]> git.tdb.fi Git - libs/gl.git/blobdiff - source/programdata.cpp
Construct uniform buffers for named uniform blocks
[libs/gl.git] / source / programdata.cpp
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);
 }