]> git.tdb.fi Git - libs/gl.git/blobdiff - source/program.cpp
Store information about attributes in Program
[libs/gl.git] / source / program.cpp
index a4358acb4d6d74e048c1c416107540f4fb9bdce9..d8827ab5d0f5f095fed0d53424571aff7147f472 100644 (file)
@@ -7,11 +7,15 @@
 #include <msp/gl/extensions/arb_uniform_buffer_object.h>
 #include <msp/gl/extensions/arb_vertex_shader.h>
 #include <msp/gl/extensions/ext_gpu_shader4.h>
+#include <msp/gl/extensions/nv_non_square_matrices.h>
+#include <msp/io/print.h>
 #include <msp/strings/format.h>
 #include "buffer.h"
 #include "error.h"
 #include "misc.h"
 #include "program.h"
+#include "programcompiler.h"
+#include "resources.h"
 #include "shader.h"
 
 using namespace std;
@@ -33,6 +37,24 @@ Program::Program(const ProgramBuilder::StandardFeatures &features)
        link();
 }
 
+Program::Program(const std::string &source)
+{
+       init();
+
+       ProgramCompiler compiler;
+       if(source.find(';')==string::npos && source.size()>5 && !source.compare(source.size()-5, 5, ".glsl"))
+       {
+               if(RefPtr<IO::Seekable> io = Resources::get_builtins().open(source))
+                       compiler.compile(*io, source);
+               else
+                       throw IO::file_not_found(source);
+       }
+       else
+               compiler.compile(source);
+       compiler.add_shaders(*this);
+       link();
+}
+
 Program::Program(const string &vert, const string &frag)
 {
        init();
@@ -114,6 +136,18 @@ void Program::link()
        if(!linked)
                throw compile_error(get_info_log());
 
+#ifdef DEBUG
+       std::string info_log = get_info_log();
+       if(!info_log.empty())
+               IO::print("Program link info log:\n%s", info_log);
+#endif
+
+       query_uniforms();
+       query_attributes();
+}
+
+void Program::query_uniforms()
+{
        unsigned count = get_program_i(id, GL_ACTIVE_UNIFORMS);
        vector<UniformInfo *> uniforms_by_index(count);
        for(unsigned i=0; i<count; ++i)
@@ -143,90 +177,8 @@ void Program::link()
                        legacy_vars = true;
        }
 
-       count = get_program_i(id, GL_ACTIVE_ATTRIBUTES);
-       for(unsigned i=0; i<count; ++i)
-       {
-               char name[128];
-               int len = 0;
-               int size;
-               GLenum type;
-               glGetActiveAttrib(id, i, sizeof(name), &len, &size, &type, name);
-               if(len && !strncmp(name, "gl_", 3))
-                       legacy_vars = true;
-       }
-
        if(ARB_uniform_buffer_object)
-       {
-               uniform_blocks.clear();
-
-               std::set<unsigned> used_bind_points;
-               count = get_program_i(id, GL_ACTIVE_UNIFORM_BLOCKS);
-               for(unsigned i=0; i<count; ++i)
-               {
-                       char name[128];
-                       int len;
-                       glGetActiveUniformBlockName(id, i, sizeof(name), &len, name);
-                       UniformBlockInfo &info = uniform_blocks[name];
-                       info.name = name;
-
-                       int value;
-                       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_by_index[*j]->block = &info;
-                       }
-
-                       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);
-                       if(!indices2.empty())
-                       {
-                               glGetActiveUniformsiv(id, indices2.size(), &indices2[0], GL_UNIFORM_ARRAY_STRIDE, &values[0]);
-                               for(unsigned j=0; j<indices2.size(); ++j)
-                                       uniforms_by_index[indices2[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);
-                       }
-                       if(!indices2.empty())
-                       {
-                               glGetActiveUniformsiv(id, indices2.size(), &indices2[0], GL_UNIFORM_MATRIX_STRIDE, &values[0]);
-                               for(unsigned j=0; j<indices2.size(); ++j)
-                                       uniforms_by_index[indices2[j]]->matrix_stride = values[j];
-                       }
-
-                       sort(info.uniforms.begin(), info.uniforms.end(), uniform_location_compare);
-                       info.layout_hash = compute_layout_hash(info.uniforms);
-                       unsigned n_bindings = BufferRange::get_n_uniform_buffer_bindings();
-                       info.bind_point = info.layout_hash%n_bindings;
-                       while(used_bind_points.count(info.bind_point))
-                               info.bind_point = (info.bind_point+1)%n_bindings;
-                       glUniformBlockBinding(id, i, info.bind_point);
-                       used_bind_points.insert(info.bind_point);
-               }
-       }
+               query_uniform_blocks(uniforms_by_index);
 
        UniformBlockInfo &default_block = uniform_blocks[string()];
        default_block.data_size = 0;
@@ -248,6 +200,105 @@ void Program::link()
        uniform_layout_hash = hash32(layout_descriptor);
 }
 
+void Program::query_uniform_blocks(const vector<UniformInfo *> &uniforms_by_index)
+{
+       uniform_blocks.clear();
+
+       std::set<unsigned> used_bind_points;
+       unsigned count = get_program_i(id, GL_ACTIVE_UNIFORM_BLOCKS);
+       for(unsigned i=0; i<count; ++i)
+       {
+               char name[128];
+               int len;
+               glGetActiveUniformBlockName(id, i, sizeof(name), &len, name);
+               UniformBlockInfo &info = uniform_blocks[name];
+               info.name = name;
+
+               int value;
+               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_by_index[*j]->block = &info;
+               }
+
+               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);
+               if(!indices2.empty())
+               {
+                       glGetActiveUniformsiv(id, indices2.size(), &indices2[0], GL_UNIFORM_ARRAY_STRIDE, &values[0]);
+                       for(unsigned j=0; j<indices2.size(); ++j)
+                               uniforms_by_index[indices2[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);
+               }
+               if(!indices2.empty())
+               {
+                       glGetActiveUniformsiv(id, indices2.size(), &indices2[0], GL_UNIFORM_MATRIX_STRIDE, &values[0]);
+                       for(unsigned j=0; j<indices2.size(); ++j)
+                               uniforms_by_index[indices2[j]]->matrix_stride = values[j];
+               }
+
+               sort(info.uniforms.begin(), info.uniforms.end(), uniform_location_compare);
+               info.layout_hash = compute_layout_hash(info.uniforms);
+               unsigned n_bindings = BufferRange::get_n_uniform_buffer_bindings();
+               info.bind_point = info.layout_hash%n_bindings;
+               while(used_bind_points.count(info.bind_point))
+                       info.bind_point = (info.bind_point+1)%n_bindings;
+               glUniformBlockBinding(id, i, info.bind_point);
+               used_bind_points.insert(info.bind_point);
+       }
+}
+
+void Program::query_attributes()
+{
+       unsigned count = get_program_i(id, GL_ACTIVE_ATTRIBUTES);
+       for(unsigned i=0; i<count; ++i)
+       {
+               char name[128];
+               int len = 0;
+               int size;
+               GLenum type;
+               glGetActiveAttrib(id, i, sizeof(name), &len, &size, &type, name);
+               if(len && strncmp(name, "gl_", 3))
+               {
+                       if(len>3 && !strcmp(name+len-3, "[0]"))
+                               name[len-3] = 0;
+
+                       AttributeInfo &info = attributes[name];
+                       info.name = name;
+                       info.location = glGetAttribLocation(id, name);
+                       info.size = size;
+                       info.type = type;
+               }
+               else
+                       legacy_vars = true;
+       }
+}
+
 Program::LayoutHash Program::compute_layout_hash(const vector<const UniformInfo *> &uniforms)
 {
        string layout_descriptor;
@@ -283,29 +334,30 @@ const Program::UniformInfo &Program::get_uniform_info(const string &name) const
 
 int Program::get_uniform_location(const string &n) const
 {
+       if(n[n.size()-1]==']')
+               throw invalid_argument("Program::get_uniform_location");
+
        UniformMap::const_iterator i = uniforms.find(n);
        if(i==uniforms.end())
-       {
-               if(n[n.size()-1]==']')
-               {
-                       string::size_type open_bracket = n.rfind('[');
-                       if(open_bracket!=string::npos)
-                       {
-                               /* 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. */
-                               unsigned offset = lexical_cast<unsigned>(n.substr(open_bracket+1, n.size()-2-open_bracket));
-                               i = uniforms.find(n.substr(0, open_bracket));
-                               if(i!=uniforms.end() && i->second.block->bind_point<0 && offset<i->second.size)
-                                       return i->second.location+offset;
-                       }
-               }
                return -1;
-       }
 
        return i->second.block->bind_point<0 ? i->second.location : -1;
 }
 
+const Program::AttributeInfo &Program::get_attribute_info(const string &name) const
+{
+       return get_item(attributes, name);
+}
+
+int Program::get_attribute_location(const string &n) const
+{
+       if(n[n.size()-1]==']')
+               throw invalid_argument("Program::get_attribute_location");
+
+       AttributeMap::const_iterator i = attributes.find(n);
+       return i!=attributes.end() ? i->second.location : -1;
+}
+
 void Program::bind() const
 {
        if(!linked)
@@ -331,6 +383,7 @@ Program::Loader::Loader(Program &p):
 {
        add("attribute",       &Loader::attribute);
        add("fragment_shader", &Loader::fragment_shader);
+       add("geometry_shader", &Loader::geometry_shader);
        add("standard",        &Loader::standard);
        add("vertex_shader",   &Loader::vertex_shader);
 }
@@ -350,6 +403,11 @@ void Program::Loader::fragment_shader(const string &src)
        obj.attach_shader_owned(new FragmentShader(src));
 }
 
+void Program::Loader::geometry_shader(const string &src)
+{
+       obj.attach_shader_owned(new GeometryShader(src));
+}
+
 void Program::Loader::standard()
 {
        ProgramBuilder::StandardFeatures feat;