]> git.tdb.fi Git - libs/gl.git/blobdiff - source/program.cpp
Remove useless using declarations
[libs/gl.git] / source / program.cpp
index ffdd3b6380e03180a6e3790ea730d57fcd6d8832..270dbdc3e5675163017349d0cef901fcffaccdf8 100644 (file)
@@ -1,14 +1,21 @@
 #include <algorithm>
 #include <cstring>
+#include <set>
 #include <msp/core/hash.h>
 #include <msp/core/maputils.h>
 #include <msp/gl/extensions/arb_shader_objects.h>
 #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;
@@ -27,8 +34,25 @@ Program::Program(const ProgramBuilder::StandardFeatures &features)
 
        ProgramBuilder builder(features);
        builder.add_shaders(*this);
-       if(!features.transform)
-               link();
+       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)
@@ -87,6 +111,17 @@ void Program::bind_attribute(unsigned index, const string &name)
        glBindAttribLocation(id, index, name.c_str());
 }
 
+void Program::bind_attribute(VertexComponent comp, const string &name)
+{
+       bind_attribute(get_component_type(comp), name);
+}
+
+void Program::bind_fragment_data(unsigned index, const string &name)
+{
+       static Require _req(EXT_gpu_shader4);
+       glBindFragDataLocation(id, index, name.c_str());
+}
+
 void Program::link()
 {
        for(ShaderList::iterator i=shaders.begin(); i!=shaders.end(); ++i)
@@ -97,15 +132,19 @@ void Program::link()
        legacy_vars = false;
 
        glLinkProgram(id);
-       int value;
-       glGetProgramiv(id, GL_LINK_STATUS, &value);
-       if(!(linked = value))
+       linked = get_program_i(id, GL_LINK_STATUS);
+       if(!linked)
                throw compile_error(get_info_log());
 
-       int count;
-       glGetProgramiv(id, GL_ACTIVE_UNIFORMS, &count);
+#ifdef DEBUG
+       std::string info_log = get_info_log();
+       if(!info_log.empty())
+               IO::print("Program link info log:\n%s", info_log);
+#endif
+
+       unsigned count = get_program_i(id, GL_ACTIVE_UNIFORMS);
        vector<UniformInfo *> uniforms_by_index(count);
-       for(int i=0; i<count; ++i)
+       for(unsigned i=0; i<count; ++i)
        {
                char name[128];
                int len = 0;
@@ -115,7 +154,7 @@ void Program::link()
                if(len && strncmp(name, "gl_", 3))
                {
                        /* Some implementations report the first element of a uniform array,
-                       others report just the name of an array. */
+                       others report just the name of the array itself. */
                        if(len>3 && !strcmp(name+len-3, "[0]"))
                                name[len-3] = 0;
 
@@ -132,8 +171,8 @@ void Program::link()
                        legacy_vars = true;
        }
 
-       glGetProgramiv(id, GL_ACTIVE_ATTRIBUTES, &count);
-       for(int i=0; i<count; ++i)
+       count = get_program_i(id, GL_ACTIVE_ATTRIBUTES);
+       for(unsigned i=0; i<count; ++i)
        {
                char name[128];
                int len = 0;
@@ -146,8 +185,11 @@ void Program::link()
 
        if(ARB_uniform_buffer_object)
        {
-               glGetProgramiv(id, GL_ACTIVE_UNIFORM_BLOCKS, &count);
-               for(int i=0; i<count; ++i)
+               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;
@@ -155,6 +197,7 @@ void Program::link()
                        UniformBlockInfo &info = uniform_blocks[name];
                        info.name = name;
 
+                       int value;
                        glGetActiveUniformBlockiv(id, i, GL_UNIFORM_BLOCK_DATA_SIZE, &value);
                        info.data_size = value;
 
@@ -183,7 +226,7 @@ void Program::link()
                        {
                                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];
+                                       uniforms_by_index[indices2[j]]->array_stride = values[j];
                        }
 
                        indices2.clear();
@@ -199,28 +242,41 @@ void Program::link()
                        {
                                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];
+                                       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);
-                       info.bind_point = info.layout_hash%BufferRange::get_n_uniform_buffer_bindings();
+                       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);
                }
        }
 
-       vector<const UniformInfo *> blockless_uniforms;
+       UniformBlockInfo &default_block = uniform_blocks[string()];
+       default_block.data_size = 0;
+       default_block.bind_point = -1;
+
        for(UniformMap::iterator i=uniforms.begin(); i!=uniforms.end(); ++i)
                if(!i->second.block)
                {
                        i->second.location = glGetUniformLocation(id, i->second.name.c_str());
-                       blockless_uniforms.push_back(&i->second);
+                       i->second.block = &default_block;
+                       default_block.uniforms.push_back(&i->second);
                }
 
-       uniform_layout_hash = compute_layout_hash(blockless_uniforms);
+       default_block.layout_hash = compute_layout_hash(default_block.uniforms);
+
+       string layout_descriptor;
+       for(UniformBlockMap::const_iterator i=uniform_blocks.begin(); i!=uniform_blocks.end(); ++i)
+               layout_descriptor += format("%d:%x\n", i->second.bind_point, i->second.layout_hash);
+       uniform_layout_hash = hash32(layout_descriptor);
 }
 
-unsigned Program::compute_layout_hash(const vector<const UniformInfo *> &uniforms)
+Program::LayoutHash 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)
@@ -235,8 +291,7 @@ bool Program::uniform_location_compare(const UniformInfo *uni1, const UniformInf
 
 string Program::get_info_log() const
 {
-       GLsizei len = 0;
-       glGetProgramiv(id, GL_INFO_LOG_LENGTH, &len);
+       GLsizei len = get_program_i(id, GL_INFO_LOG_LENGTH);
        char *buf = new char[len+1];
        glGetProgramInfoLog(id, len+1, &len, buf);
        string log(buf, len);
@@ -256,27 +311,14 @@ 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 && offset<i->second.size)
-                                       return i->second.location+offset;
-                       }
-               }
                return -1;
-       }
 
-       return i->second.block ? -1 : i->second.location;
+       return i->second.block->bind_point<0 ? i->second.location : -1;
 }
 
 void Program::bind() const
@@ -304,6 +346,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);
 }
@@ -323,6 +366,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;