]> git.tdb.fi Git - libs/gl.git/commitdiff
Query information about uniform blocks when linking a Program
authorMikko Rasa <tdb@tdb.fi>
Fri, 24 Aug 2012 16:05:43 +0000 (19:05 +0300)
committerMikko Rasa <tdb@tdb.fi>
Fri, 24 Aug 2012 16:49:42 +0000 (19:49 +0300)
source/program.cpp
source/program.h

index 8ca8e336c0d18dc3f0efb08b31914824570f36c4..40a388191e650ef83cb71bc7f3d976027b6b7e80 100644 (file)
@@ -1,8 +1,12 @@
 #include <algorithm>
+#include <cstring>
 #include <msp/core/hash.h>
+#include <msp/core/maputils.h>
 #include <msp/strings/format.h>
 #include "arb_shader_objects.h"
+#include "arb_uniform_buffer_object.h"
 #include "arb_vertex_shader.h"
+#include "buffer.h"
 #include "error.h"
 #include "extension.h"
 #include "program.h"
@@ -235,29 +239,112 @@ void Program::link()
                throw compile_error(get_info_log());
 
        glGetObjectParameterivARB(id, GL_OBJECT_ACTIVE_UNIFORMS_ARB, &value);
-       for(int i=0; i<value; ++i)
+       unsigned count = value;
+       vector<UniformInfo *> uniforms_by_index(count);
+       for(unsigned i=0; i<count; ++i)
        {
-               UniformInfo info;
                char name[128];
                int len = 0;
-               glGetActiveUniformARB(id, i, 128, &len, &info.size, &info.type, name);
-               if(len)
+               int size;
+               GLenum type;
+               glGetActiveUniformARB(id, i, 128, &len, &size, &type, name);
+               if(len && strncmp(name, "gl_", 3))
                {
+                       UniformInfo &info = uniforms[name];
                        info.name = name;
-                       info.location = glGetUniformLocationARB(id, name);
-                       uniforms[name] = info;
+                       info.size = size;
+                       info.type = type;
+                       uniforms_by_index[i] = &info;
                }
        }
 
-       string layout_descriptor;
-       for(map<string, UniformInfo>::const_iterator i = uniforms.begin(); i!=uniforms.end(); ++i)
-               if(i->second.location>=0)
+       vector<const UniformInfo *> blockless_uniforms;
+
+       if(is_supported("GL_ARB_uniform_buffer_object"))
+       {
+               glGetObjectParameterivARB(id, GL_ACTIVE_UNIFORM_BLOCKS, &value);
+               count = value;
+               vector<bool> uniforms_in_blocks(uniforms_by_index.size());
+               for(unsigned i=0; i<count; ++i)
                {
-                       if(!layout_descriptor.empty())
-                               layout_descriptor += '\n';
-                       layout_descriptor += format("%d:%s:%x", i->second.location, i->second.name, i->second.type);
+                       char name[128];
+                       int len;
+                       glGetActiveUniformBlockName(id, i, 128, &len, name);
+                       UniformBlockInfo &info = uniform_blocks[name];
+                       info.name = name;
+
+                       glGetActiveUniformBlockiv(id, i, GL_UNIFORM_BLOCK_DATA_SIZE, &value);
+                       info.data_size = value;
+
+                       glGetActiveUniformBlockiv(id, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &value);
+                       vector<int> indices(value);
+                       glGetActiveUniformBlockiv(id, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, &indices[0]);
+                       for(vector<int>::iterator j=indices.begin(); j!=indices.end(); ++j)
+                       {
+                               if(!uniforms_by_index[*j])
+                                       throw logic_error("Program::link");
+                               info.uniforms.push_back(uniforms_by_index[*j]);
+                               uniforms_in_blocks[*j] = true;
+                       }
+
+                       vector<unsigned> indices2(indices.begin(), indices.end());
+                       vector<int> values(indices.size());
+                       glGetActiveUniformsiv(id, indices.size(), &indices2[0], GL_UNIFORM_OFFSET, &values[0]);
+                       for(unsigned j=0; j<indices.size(); ++j)
+                               uniforms_by_index[indices[j]]->location = values[j];
+
+                       indices2.clear();
+                       for(vector<int>::iterator j=indices.begin(); j!=indices.end(); ++j)
+                               if(uniforms_by_index[*j]->size>1)
+                                       indices2.push_back(*j);
+                       glGetActiveUniformsiv(id, indices2.size(), &indices2[0], GL_UNIFORM_ARRAY_STRIDE, &values[0]);
+                       for(unsigned j=0; j<indices2.size(); ++j)
+                               uniforms_by_index[indices[j]]->array_stride = values[j];
+
+                       indices2.clear();
+                       for(vector<int>::iterator j=indices.begin(); j!=indices.end(); ++j)
+                       {
+                               GLenum t = uniforms_by_index[*j]->type;
+                               if(t==GL_FLOAT_MAT4 || t==GL_FLOAT_MAT3 || t==GL_FLOAT_MAT2 ||
+                                       t==GL_FLOAT_MAT2x3 || t==GL_FLOAT_MAT2x4 || t==GL_FLOAT_MAT3x2 ||
+                                       t==GL_FLOAT_MAT3x4 || t==GL_FLOAT_MAT4x2 || t==GL_FLOAT_MAT4x3)
+                                       indices2.push_back(*j);
+                       }
+                       glGetActiveUniformsiv(id, indices2.size(), &indices2[0], GL_UNIFORM_MATRIX_STRIDE, &values[0]);
+                       for(unsigned j=0; j<indices2.size(); ++j)
+                               uniforms_by_index[indices[j]]->matrix_stride = values[j];
+
+                       info.layout_hash = compute_layout_hash(info.uniforms);
+                       info.bind_point = info.layout_hash%BufferRange::get_n_uniform_buffer_bindings();
+                       glUniformBlockBinding(id, i, info.bind_point);
                }
-       uniform_layout_hash = hash32(layout_descriptor);
+
+               for(unsigned i=0; i<uniforms_by_index.size(); ++i)
+                       if(uniforms_by_index[i] && !uniforms_in_blocks[i])
+                       {
+                               UniformInfo *info = uniforms_by_index[i];
+                               info->location = glGetUniformLocationARB(id, info->name.c_str());
+                               blockless_uniforms.push_back(info);
+                       }
+       }
+       else
+       {
+               for(UniformMap::iterator i=uniforms.begin(); i!=uniforms.end(); ++i)
+               {
+                       i->second.location = glGetUniformLocationARB(id, i->second.name.c_str());
+                       blockless_uniforms.push_back(&i->second);
+               }
+       }
+
+       uniform_layout_hash = compute_layout_hash(blockless_uniforms);
+}
+
+unsigned Program::compute_layout_hash(const vector<const UniformInfo *> &uniforms)
+{
+       string layout_descriptor;
+       for(vector<const UniformInfo *>::const_iterator i = uniforms.begin(); i!=uniforms.end(); ++i)
+               layout_descriptor += format("%d:%s:%x:%d\n", (*i)->location, (*i)->name, (*i)->type, (*i)->size);
+       return hash32(layout_descriptor);
 }
 
 string Program::get_info_log() const
@@ -271,6 +358,16 @@ string Program::get_info_log() const
        return log;
 }
 
+const Program::UniformBlockInfo &Program::get_uniform_block_info(const string &name) const
+{
+       return get_item(uniform_blocks, name);
+}
+
+const Program::UniformInfo &Program::get_uniform_info(const string &name) const
+{
+       return get_item(uniforms, name);
+}
+
 int Program::get_uniform_location(const string &n) const
 {
        UniformMap::const_iterator i = uniforms.find(n);
@@ -284,7 +381,7 @@ int Program::get_uniform_location(const string &n) const
                                /* The requested name looks like an array.  glGetActiveUniform only
                                gives us the first element of the array, so try to look that up and
                                add an offset. */
-                               int offset = lexical_cast<unsigned>(n.substr(open_bracket+1, n.size()-2-open_bracket));
+                               unsigned offset = lexical_cast<unsigned>(n.substr(open_bracket+1, n.size()-2-open_bracket));
                                i = uniforms.find(n.substr(0, open_bracket)+"[0]");
                                if(i!=uniforms.end() && offset<i->second.size)
                                        return i->second.location+offset;
index 7e9676d36548972c2c30f10d143843f45666d6db..40a7a33b143a39aa98f779b6e1d68a8285d54a7c 100644 (file)
@@ -54,19 +54,32 @@ public:
        struct UniformInfo
        {
                std::string name;
-               int location;
-               int size;
+               unsigned location;
+               unsigned size;
+               unsigned array_stride;
+               unsigned matrix_stride;
                GLenum type;
        };
 
+       struct UniformBlockInfo
+       {
+               std::string name;
+               unsigned data_size;
+               unsigned bind_point;
+               std::vector<const UniformInfo *> uniforms;
+               unsigned layout_hash;
+       };
+
        typedef std::list<Shader *> ShaderList;
        typedef std::map<std::string, UniformInfo> UniformMap;
+       typedef std::map<std::string, UniformBlockInfo> UniformBlockMap;
 
 private:
        unsigned id;
        ShaderList shaders;
        ShaderList owned_data;
        bool linked;
+       UniformBlockMap uniform_blocks;
        UniformMap uniforms;
        unsigned uniform_layout_hash;
 
@@ -91,10 +104,17 @@ public:
        void bind_attribute(unsigned, const std::string &);
 
        void link();
+private:
+       static unsigned compute_layout_hash(const std::vector<const UniformInfo *> &);
+public:
        bool is_linked() const { return linked; }
        std::string get_info_log() const;
 
        unsigned get_uniform_layout_hash() const { return uniform_layout_hash; }
+       const UniformBlockMap &get_uniform_blocks() const { return uniform_blocks; }
+       const UniformBlockInfo &get_uniform_block_info(const std::string &) const;
+       const UniformMap &get_uniforms() const { return uniforms; }
+       const UniformInfo &get_uniform_info(const std::string &) const;
        int get_uniform_location(const std::string &) const;
 
        void bind() const;