]> git.tdb.fi Git - libs/gl.git/commitdiff
Construct uniform buffers for named uniform blocks
authorMikko Rasa <tdb@tdb.fi>
Fri, 24 Aug 2012 21:55:06 +0000 (00:55 +0300)
committerMikko Rasa <tdb@tdb.fi>
Fri, 24 Aug 2012 21:56:44 +0000 (00:56 +0300)
source/buffer.h
source/programdata.cpp
source/programdata.h
source/uniform.h
source/uniformblock.cpp
source/uniformblock.h

index bd3a999eeab0d19da7aea2f94b90abae390f4a74..6f0a9708e18069485460587d3295b63aaf6055b1 100644 (file)
@@ -33,8 +33,8 @@ class BufferRange;
 
 /**
 A buffer for storing data in GL memory.  Putting vertex and index data in
-buffers can improve rendering performance.  The VertexArray and Mesh classes
-contain built-in support for buffers.
+buffers can improve rendering performance.  The VertexArray, Mesh and
+UniformBlock classes contain built-in support for buffers.
 */
 class Buffer
 {
index 5bfbd68fe25ece5ef5a016cf61de253b6c31c790..04fdd6b865053073435069696b968c5c90c48785 100644 (file)
@@ -1,3 +1,4 @@
+#include "buffer.h"
 #include "color.h"
 #include "error.h"
 #include "extension.h"
@@ -14,6 +15,8 @@ namespace Msp {
 namespace GL {
 
 ProgramData::ProgramData():
+       last_block(0),
+       buffer(0),
        modified(false)
 {
        static RequireExtension _ext("GL_ARB_shader_objects");
@@ -22,6 +25,8 @@ ProgramData::ProgramData():
 // Blocks are intentionally left uncopied
 ProgramData::ProgramData(const ProgramData &other):
        uniforms(other.uniforms),
+       last_block(0),
+       buffer(0),
        modified(false)
 {
        for(UniformMap::iterator i=uniforms.begin(); i!=uniforms.end(); ++i)
@@ -145,7 +150,7 @@ void ProgramData::uniform_matrix4_array(const string &name, unsigned n, const fl
        uniform(name, new UniformArray<UniformMatrix4x4f>(n, v));
 }
 
-const UniformBlock &ProgramData::get_block(const Program &prog) const
+const UniformBlock &ProgramData::get_block(const Program &prog, const string &name) const
 {
        if(modified)
        {
@@ -154,23 +159,54 @@ const UniformBlock &ProgramData::get_block(const Program &prog) const
                modified = false;
        }
 
-       unsigned layout_hash = prog.get_uniform_layout_hash();
+       const Program::UniformBlockInfo *info = 0;
+       unsigned layout_hash;
+       if(!name.empty())
+       {
+               info = &prog.get_uniform_block_info(name);
+               layout_hash = info->layout_hash;
+       }
+       else
+               layout_hash = prog.get_uniform_layout_hash();
+
        map<unsigned, Block>::iterator i = blocks.find(layout_hash);
        if(i==blocks.end())
        {
                i = blocks.insert(BlockMap::value_type(layout_hash, Block())).first;
                i->second.dirty = true;
-               i->second.block = new UniformBlock;
+               if(info)
+               {
+                       i->second.block = new UniformBlock(info->data_size);
+                       if(!buffer)
+                               buffer = new Buffer(UNIFORM_BUFFER);
+                       i->second.block->use_buffer(buffer, last_block);
+                       last_block = i->second.block;
+               }
+               else
+                       i->second.block = new UniformBlock;
        }
 
        UniformBlock &block = *i->second.block;
        if(i->second.dirty)
        {
-               for(UniformMap::const_iterator j=uniforms.begin(); j!=uniforms.end(); ++j)
+               if(info)
                {
-                       int loc = prog.get_uniform_location(j->first);
-                       if(loc>=0)
-                               block.attach(loc, *j->second);
+                       for(vector<const Program::UniformInfo *>::const_iterator j=info->uniforms.begin(); j!=info->uniforms.end(); ++j)
+                       {
+                               // XXX individual array elements
+                               UniformMap::const_iterator k = uniforms.find((*j)->name);
+                               if(k!=uniforms.end())
+                                       block.attach(**j, *k->second);
+                       }
+               }
+               else
+               {
+                       for(UniformMap::const_iterator j=uniforms.begin(); j!=uniforms.end(); ++j)
+                       {
+                               int loc = prog.get_uniform_location(j->first);
+                               if(loc>=0)
+                                       block.attach(loc, *j->second);
+                       }
                }
                i->second.dirty = false;
        }
@@ -184,7 +220,14 @@ void ProgramData::apply() const
        if(!prog)
                throw invalid_operation("ProgramData::apply");
 
-       const UniformBlock &block = get_block(*prog);
+       const Program::UniformBlockMap &prog_blocks = prog->get_uniform_blocks();
+       for(Program::UniformBlockMap::const_iterator i=prog_blocks.begin(); i!=prog_blocks.end(); ++i)
+       {
+               const UniformBlock &block = get_block(*prog, i->second.name);
+               block.apply(i->second.bind_point);
+       }
+
+       const UniformBlock &block = get_block(*prog, string());
        block.apply(-1);
 }
 
index d74017b50ba237965f4aea15e9a8f295ca7e29f7..885804f010e16d868e7ab551caccb1b144824395 100644 (file)
@@ -7,6 +7,7 @@
 namespace Msp {
 namespace GL {
 
+class Buffer;
 class Color;
 class Matrix;
 class Program;
@@ -45,8 +46,11 @@ private:
        typedef std::map<std::string, Uniform *> UniformMap;
        typedef std::map<unsigned, Block> BlockMap;
 
+       // XXX All these mutables are a bit silly, but I'm out of better ideas
        UniformMap uniforms;
        mutable BlockMap blocks;
+       mutable UniformBlock *last_block;
+       mutable Buffer *buffer;
        mutable bool modified;
 
        ProgramData &operator=(const ProgramData &);
@@ -77,7 +81,7 @@ public:
        void uniform4_array(const std::string &, unsigned, const float *);
        void uniform_matrix4_array(const std::string &, unsigned, const float *);
 
-       const UniformBlock &get_block(const Program &) const;
+       const UniformBlock &get_block(const Program &, const std::string &) const;
 
        void apply() const;
 };
index 216d3be6a65c37cf5b2694a004363bf98a306a18..f8a59f2a441e5fd2b3ec2ba55cdd604b50ab0477 100644 (file)
@@ -2,6 +2,7 @@
 #define MSP_GL_UNIFORM_H_
 
 #include <algorithm>
+#include "program.h"
 
 namespace Msp {
 namespace GL {
@@ -17,6 +18,7 @@ public:
        virtual ~Uniform() { }
 
        virtual void apply(int) const = 0;
+       virtual void store(const Program::UniformInfo &, void *) const = 0;
        virtual Uniform *clone() const = 0;
 };
 
@@ -39,6 +41,12 @@ public:
 
        static void apply(int, unsigned, const T *);
 
+       virtual void store(const Program::UniformInfo &info, void *buffer) const
+       { store(info, buffer, &value); }
+
+       static void store(const Program::UniformInfo &, void *buffer, const T *value)
+       { *reinterpret_cast<T *>(buffer) = *value; }
+
        virtual UniformScalar *clone() const
        { return new UniformScalar(value); }
 };
@@ -66,6 +74,12 @@ public:
 
        static void apply(int index, unsigned size, const T *value);
 
+       virtual void store(const Program::UniformInfo &info, void *buffer) const
+       { store(info, buffer, value); }
+
+       static void store(const Program::UniformInfo &, void *buffer, const T *value)
+       { std::copy(value, value+vecsize, reinterpret_cast<T *>(buffer)); }
+
        virtual UniformVector *clone() const
        { return new UniformVector(value); }
 };
@@ -94,6 +108,15 @@ public:
 
        static void apply(int index, unsigned size, const T *value);
 
+       virtual void store(const Program::UniformInfo &info, void *buffer) const
+       { store(info, buffer, value); }
+
+       static void store(const Program::UniformInfo &info, void *buffer, const T *value)
+       {
+               for(unsigned i=0; i<cols; ++i)
+                       UniformVector<T, rows>::store(info, reinterpret_cast<char *>(buffer)+i*info.matrix_stride, value+i*rows);
+       }
+
        virtual UniformMatrix *clone() const
        { return new UniformMatrix(value); }
 };
@@ -106,6 +129,7 @@ class UniformArray: public Uniform
 {
 private:
        typedef typename T::BaseType BaseType;
+       enum { elemsize = sizeof(typename T::Type)/sizeof(typename T::BaseType) };
 
        BaseType *values;
        unsigned size;
@@ -114,7 +138,6 @@ public:
        UniformArray(unsigned n, const BaseType *vp):
                size(n)
        {
-               unsigned elemsize = sizeof(typename T::Type)/sizeof(typename T::BaseType);
                values = new BaseType[elemsize*size];
                std::copy(vp, vp+elemsize*size, values);
        }
@@ -122,6 +145,12 @@ public:
        virtual void apply(int index) const
        { T::apply(index, size, values); }
 
+       virtual void store(const Program::UniformInfo &info, void *buffer) const
+       {
+               for(unsigned i=0; i<size; ++i)
+                       T::store(info, reinterpret_cast<char *>(buffer)+i*info.array_stride, values+i*elemsize);
+       }
+
        virtual UniformArray *clone() const
        { return new UniformArray(size, values); }
 };
index 2ff00fa221295ada6f8578cc89649b6936c70afe..2b9a135c0d8b61d9dd545c4aefeccd603f39fbf7 100644 (file)
@@ -1,5 +1,7 @@
 #include <stdexcept>
+#include "buffer.h"
 #include "color.h"
+#include "error.h"
 #include "matrix.h"
 #include "uniform.h"
 #include "uniformblock.h"
@@ -10,18 +12,49 @@ using namespace std;
 namespace Msp {
 namespace GL {
 
+UniformBlock::UniformBlock()
+{ }
+
+UniformBlock::UniformBlock(unsigned s):
+       size(s),
+       data(size)
+{ }
+
 void UniformBlock::attach(int index, const Uniform &uni)
 {
        uniforms[index] = &uni;
 }
 
+void UniformBlock::attach(const Program::UniformInfo &info, const Uniform &uni)
+{
+       uniforms[info.location] = &uni;
+       if(buffer)
+       {
+               uni.store(info, &data[info.location]);
+               dirty = true;
+       }
+}
+
 void UniformBlock::apply(int index) const
 {
-       if(index>=0)
-               throw logic_error("GL_ARB_uniform_buffer_object support not implemented yet");
+       if((index>=0) != (buffer!=0))
+               throw invalid_operation("UniformBlock::apply");
 
-       for(map<int, const Uniform *>::const_iterator i=uniforms.begin(); i!=uniforms.end(); ++i)
-               i->second->apply(i->first);
+       if(buffer)
+       {
+               if(dirty)
+               {
+                       update_buffer_data();
+                       if(!buf_range)
+                               buf_range = new BufferRange(*buffer, buffer_offset, size);
+               }
+               buf_range->bind_to(UNIFORM_BUFFER, index);
+       }
+       else
+       {
+               for(map<int, const Uniform *>::const_iterator i=uniforms.begin(); i!=uniforms.end(); ++i)
+                       i->second->apply(i->first);
+       }
 }
 
 } // namespace GL
index 3a1cdb959d06e77106024aa1f264f648836664bb..fbc9c7047b3fdd57acb162338c9369dbdb442cf0 100644 (file)
@@ -2,27 +2,41 @@
 #define MSP_GL_UNIFORMBLOCK_H_
 
 #include <map>
+#include <vector>
+#include "bufferable.h"
+#include "program.h"
 
 namespace Msp {
 namespace GL {
 
+class BufferRange;
 class Color;
 class Matrix;
 class Uniform;
 class Vector3;
 class Vector4;
 
-class UniformBlock
+class UniformBlock: public Bufferable
 {
 private:
        std::map<int, const Uniform *> uniforms;
+       unsigned size;
+       std::vector<char> data;
+       mutable BufferRange *buf_range;
 
        UniformBlock(const UniformBlock &);
        UniformBlock &operator=(const UniformBlock &);
 public:
-       UniformBlock() { }
+       UniformBlock();
+       UniformBlock(unsigned);
 
+private:
+       virtual const void *get_data() const { return &data[0]; }
+       virtual unsigned get_data_size() const { return size; }
+
+public:
        void attach(int, const Uniform &);
+       void attach(const Program::UniformInfo &, const Uniform &);
 
        void apply(int) const;
 };