]> git.tdb.fi Git - libs/gl.git/blobdiff - source/backends/opengl/program_backend.cpp
Use emplace_back when a new object is being constructed
[libs/gl.git] / source / backends / opengl / program_backend.cpp
index 4dbf38a7197e5bd40e58f1f5c4151bbfafe2a594..a9328488cedc9bc12b5399bf55d2b032771dd52a 100644 (file)
@@ -12,6 +12,7 @@
 #include <msp/gl/extensions/khr_debug.h>
 #include <msp/gl/extensions/nv_non_square_matrices.h>
 #include <msp/io/print.h>
+#include "device.h"
 #include "error.h"
 #include "program.h"
 #include "program_backend.h"
@@ -45,6 +46,17 @@ OpenGLProgram::OpenGLProgram()
        id = glCreateProgram();
 }
 
+OpenGLProgram::OpenGLProgram(OpenGLProgram &&other):
+       id(other.id),
+       linked(other.linked),
+       uniform_calls(move(other.uniform_calls)),
+       debug_name(move(other.debug_name))
+{
+       move(other.stage_ids, other.stage_ids+MAX_STAGES, stage_ids);
+       other.id = 0;
+       fill(other.stage_ids, other.stage_ids+MAX_STAGES, 0);
+}
+
 OpenGLProgram::~OpenGLProgram()
 {
        for(unsigned i=0; i<MAX_STAGES; ++i)
@@ -69,11 +81,11 @@ unsigned OpenGLProgram::add_stage(Stage type)
        case VERTEX: { static Require _req(ARB_vertex_shader); gl_type = GL_VERTEX_SHADER; } break;
        case GEOMETRY: { static Require _req(ARB_geometry_shader4); gl_type = GL_GEOMETRY_SHADER; } break;
        case FRAGMENT: { static Require _req(ARB_fragment_shader); gl_type = GL_FRAGMENT_SHADER; } break;
-       default: throw invalid_argument("Program::add_stage");
+       default: throw invalid_argument("OpenGLProgram::add_stage");
        }
 
        if(stage_ids[type])
-               throw invalid_operation("Program::add_stage");
+               throw invalid_operation("OpenGLProgram::add_stage");
 
        unsigned stage_id = glCreateShader(gl_type);
        stage_ids[type] = stage_id;
@@ -89,7 +101,7 @@ unsigned OpenGLProgram::add_stage(Stage type)
 
 void OpenGLProgram::add_glsl_stages(const GlslModule &mod, const map<string, int> &spec_values, TransientData &transient)
 {
-       SL::Compiler compiler;
+       SL::Compiler compiler(Device::get_current().get_info().glsl_features);
        compiler.set_source(mod.get_prepared_source(), "<module>");
        compiler.specialize(spec_values);
        compiler.compile(SL::Compiler::PROGRAM);
@@ -101,7 +113,7 @@ void OpenGLProgram::add_glsl_stages(const GlslModule &mod, const map<string, int
 
        vector<SL::Stage::Type> stages = compiler.get_stages();
        if(stages.empty())
-               throw invalid_argument("Program::add_glsl_stages");
+               throw invalid_argument("OpenGLProgram::add_glsl_stages");
 
        for(SL::Stage::Type st: stages)
        {
@@ -111,7 +123,7 @@ void OpenGLProgram::add_glsl_stages(const GlslModule &mod, const map<string, int
                case SL::Stage::VERTEX: stage_id = add_stage(VERTEX); break;
                case SL::Stage::GEOMETRY: stage_id = add_stage(GEOMETRY); break;
                case SL::Stage::FRAGMENT: stage_id = add_stage(FRAGMENT); break;
-               default: throw invalid_operation("Program::add_glsl_stages");
+               default: throw invalid_operation("OpenGLProgram::add_glsl_stages");
                }
 
                string stage_src = compiler.get_stage_glsl(st);
@@ -136,6 +148,9 @@ void OpenGLProgram::add_glsl_stages(const GlslModule &mod, const map<string, int
 
        transient.textures = compiler.get_texture_bindings();
        transient.blocks = compiler.get_uniform_block_bindings();
+
+       ReflectData &rd = static_cast<Program *>(this)->reflect_data;
+       rd.n_clip_distances = compiler.get_n_clip_distances();
 }
 
 void OpenGLProgram::compile_glsl_stage(const GlslModule &mod, unsigned stage_id)
@@ -159,7 +174,7 @@ void OpenGLProgram::compile_glsl_stage(const GlslModule &mod, unsigned stage_id)
 #endif
 }
 
-void OpenGLProgram::add_spirv_stages(const SpirVModule &mod, const map<string, int> &spec_values, TransientData &transient)
+void OpenGLProgram::add_spirv_stages(const SpirVModule &mod, const map<string, int> &spec_values)
 {
        static Require _req(ARB_gl_spirv);
        static Require _req2(ARB_ES2_compatibility);
@@ -174,14 +189,14 @@ void OpenGLProgram::add_spirv_stages(const SpirVModule &mod, const map<string, i
                case SpirVModule::VERTEX: stage_id = add_stage(VERTEX); break;
                case SpirVModule::GEOMETRY: stage_id = add_stage(GEOMETRY); break;
                case SpirVModule::FRAGMENT: stage_id = add_stage(FRAGMENT); break;
-               default: throw invalid_operation("Program::add_spirv_stages");
+               default: throw invalid_operation("OpenGLProgram::add_spirv_stages");
                }
 
                used_stage_ids[n_stages++] = stage_id;
        }
 
        if(!n_stages)
-               throw invalid_argument("Program::add_spirv_stages");
+               throw invalid_argument("OpenGLProgram::add_spirv_stages");
 
        const vector<uint32_t> &code = mod.get_code();
        glShaderBinary(n_stages, used_stage_ids, GL_SHADER_BINARY_FORMAT_SPIR_V, &code[0], code.size()*4);
@@ -198,7 +213,6 @@ void OpenGLProgram::add_spirv_stages(const SpirVModule &mod, const map<string, i
                {
                        spec_id_array.push_back(c.constant_id);
                        spec_value_array.push_back(i->second);
-                       transient.spec_values[c.constant_id] = i->second;
                }
        }
 
@@ -208,7 +222,7 @@ void OpenGLProgram::add_spirv_stages(const SpirVModule &mod, const map<string, i
                        glSpecializeShader(stage_ids[i], j->name.c_str(), spec_id_array.size(), &spec_id_array[0], &spec_value_array[0]);
 }
 
-void OpenGLProgram::finalize(const Module &mod)
+void OpenGLProgram::finalize(const Module &mod, TransientData &transient)
 {
        glLinkProgram(id);
        int status = 0;
@@ -229,6 +243,13 @@ void OpenGLProgram::finalize(const Module &mod)
        if(!info_log.empty())
                IO::print("Program link info log:\n%s", info_log);
 #endif
+
+       if(mod.get_format()==Module::GLSL)
+       {
+               query_uniforms();
+               query_attributes();
+               apply_bindings(transient);
+       }
 }
 
 void OpenGLProgram::query_uniforms()
@@ -253,7 +274,7 @@ void OpenGLProgram::query_uniforms()
                        if(len>3 && !strcmp(name+len-3, "[0]"))
                                name[len-3] = 0;
 
-                       rd.uniforms.push_back(ReflectData::UniformInfo());
+                       rd.uniforms.emplace_back();
                        ReflectData::UniformInfo &info = rd.uniforms.back();
                        info.name = name;
                        info.tag = name;
@@ -275,7 +296,7 @@ void OpenGLProgram::query_uniforms()
                query_uniform_blocks(uniforms_by_index);
        }
 
-       rd.uniform_blocks.push_back(ReflectData::UniformBlockInfo());
+       rd.uniform_blocks.emplace_back();
        ReflectData::UniformBlockInfo &default_block = rd.uniform_blocks.back();
 
        for(ReflectData::UniformInfo &u: rd.uniforms)
@@ -288,57 +309,11 @@ void OpenGLProgram::query_uniforms()
                                u.matrix_stride = get_type_size(get_matrix_column_type(u.type));
                        default_block.uniforms.push_back(&u);
 
-                       if(u.location>=0)
-                       {
-                               UniformCall::FuncPtr func = 0;
-                               if(is_image(u.type))
-                                       glGetUniformiv(id, u.location, &u.binding);
-                               else if(u.type==FLOAT)
-                                       func = &uniform_wrapper<float, glUniform1fv>;
-                               else if(u.type==FLOAT_VEC2)
-                                       func = &uniform_wrapper<float, glUniform2fv>;
-                               else if(u.type==FLOAT_VEC3)
-                                       func = &uniform_wrapper<float, glUniform3fv>;
-                               else if(u.type==FLOAT_VEC4)
-                                       func = &uniform_wrapper<float, glUniform4fv>;
-                               else if(u.type==INT)
-                                       func = &uniform_wrapper<int, glUniform1iv>;
-                               else if(u.type==INT_VEC2)
-                                       func = &uniform_wrapper<int, glUniform2iv>;
-                               else if(u.type==INT_VEC3)
-                                       func = &uniform_wrapper<int, glUniform3iv>;
-                               else if(u.type==INT_VEC4)
-                                       func = &uniform_wrapper<int, glUniform4iv>;
-                               else if(u.type==FLOAT_MAT2)
-                                       func = &uniform_matrix_wrapper<float, glUniformMatrix2fv>;
-                               else if(u.type==FLOAT_MAT3)
-                                       func = &uniform_matrix_wrapper<float, glUniformMatrix3fv>;
-                               else if(u.type==FLOAT_MAT4)
-                                       func = &uniform_matrix_wrapper<float, glUniformMatrix4fv>;
-                               else if(u.type==FLOAT_MAT2x3)
-                                       func = &uniform_matrix_wrapper<float, glUniformMatrix2x3fv>;
-                               else if(u.type==FLOAT_MAT3x2)
-                                       func = &uniform_matrix_wrapper<float, glUniformMatrix3x2fv>;
-                               else if(u.type==FLOAT_MAT2x4)
-                                       func = &uniform_matrix_wrapper<float, glUniformMatrix2x4fv>;
-                               else if(u.type==FLOAT_MAT4x2)
-                                       func = &uniform_matrix_wrapper<float, glUniformMatrix4x2fv>;
-                               else if(u.type==FLOAT_MAT3x4)
-                                       func = &uniform_matrix_wrapper<float, glUniformMatrix3x4fv>;
-                               else if(u.type==FLOAT_MAT4x3)
-                                       func = &uniform_matrix_wrapper<float, glUniformMatrix4x3fv>;
-
-                               if(func)
-                                       uniform_calls.push_back(UniformCall(u.location, u.array_size, func));
-                       }
+                       if(is_image(u.type) && u.location>=0)
+                               glGetUniformiv(id, u.location, &u.binding);
                }
 
        default_block.sort_uniforms();
-       if(!default_block.uniforms.empty())
-       {
-               const ReflectData::UniformInfo &uni = *default_block.uniforms.back();
-               default_block.data_size = uni.location*16+uni.array_size*get_type_size(uni.type);
-       }
        default_block.update_layout_hash();
        rd.update_layout_hash();
 }
@@ -356,7 +331,7 @@ void OpenGLProgram::query_uniform_blocks(const vector<ReflectData::UniformInfo *
                char name[128];
                int len;
                glGetActiveUniformBlockName(id, i, sizeof(name), &len, name);
-               rd.uniform_blocks.push_back(ReflectData::UniformBlockInfo());
+               rd.uniform_blocks.emplace_back();
                ReflectData::UniformBlockInfo &info = rd.uniform_blocks.back();
                info.name = name;
 
@@ -373,7 +348,7 @@ void OpenGLProgram::query_uniform_blocks(const vector<ReflectData::UniformInfo *
                for(int j: indices)
                {
                        if(!uniforms_by_index[j])
-                               throw logic_error("Program::link");
+                               throw logic_error("OpenGLProgram::query_uniform_blocks");
                        info.uniforms.push_back(uniforms_by_index[j]);
                        uniforms_by_index[j]->block = &info;
                }
@@ -433,7 +408,7 @@ void OpenGLProgram::query_attributes()
                        if(len>3 && !strcmp(name+len-3, "[0]"))
                                name[len-3] = 0;
 
-                       rd.attributes.push_back(ReflectData::AttributeInfo());
+                       rd.attributes.emplace_back();
                        ReflectData::AttributeInfo &info = rd.attributes.back();
                        info.name = name;
                        info.location = glGetAttribLocation(id, name);
@@ -472,6 +447,72 @@ void OpenGLProgram::apply_bindings(const TransientData &transient)
        }
 }
 
+void OpenGLProgram::finalize_uniforms()
+{
+       ReflectData &rd = static_cast<Program *>(this)->reflect_data;
+
+       auto i = find_if(rd.uniform_blocks, [](const ReflectData::UniformBlockInfo &b){ return b.bind_point<0; });
+       if(i!=rd.uniform_blocks.end() && !i->uniforms.empty())
+       {
+               for(const ReflectData::UniformInfo *u: i->uniforms)
+                       if(u->location>=0)
+                       {
+                               UniformCall::FuncPtr func = 0;
+                               if(u->type==FLOAT)
+                                       func = &uniform_wrapper<float, glUniform1fv>;
+                               else if(u->type==FLOAT_VEC2)
+                                       func = &uniform_wrapper<float, glUniform2fv>;
+                               else if(u->type==FLOAT_VEC3)
+                                       func = &uniform_wrapper<float, glUniform3fv>;
+                               else if(u->type==FLOAT_VEC4)
+                                       func = &uniform_wrapper<float, glUniform4fv>;
+                               else if(u->type==INT)
+                                       func = &uniform_wrapper<int, glUniform1iv>;
+                               else if(u->type==INT_VEC2)
+                                       func = &uniform_wrapper<int, glUniform2iv>;
+                               else if(u->type==INT_VEC3)
+                                       func = &uniform_wrapper<int, glUniform3iv>;
+                               else if(u->type==INT_VEC4)
+                                       func = &uniform_wrapper<int, glUniform4iv>;
+                               else if(u->type==UNSIGNED_INT)
+                                       func = &uniform_wrapper<unsigned, glUniform1uiv>;
+                               else if(u->type==UINT_VEC2)
+                                       func = &uniform_wrapper<unsigned, glUniform2uiv>;
+                               else if(u->type==UINT_VEC3)
+                                       func = &uniform_wrapper<unsigned, glUniform3uiv>;
+                               else if(u->type==UINT_VEC4)
+                                       func = &uniform_wrapper<unsigned, glUniform4uiv>;
+                               else if(u->type==FLOAT_MAT2)
+                                       func = &uniform_matrix_wrapper<float, glUniformMatrix2fv>;
+                               else if(u->type==FLOAT_MAT3)
+                                       func = &uniform_matrix_wrapper<float, glUniformMatrix3fv>;
+                               else if(u->type==FLOAT_MAT4)
+                                       func = &uniform_matrix_wrapper<float, glUniformMatrix4fv>;
+                               else if(u->type==FLOAT_MAT2x3)
+                                       func = &uniform_matrix_wrapper<float, glUniformMatrix2x3fv>;
+                               else if(u->type==FLOAT_MAT3x2)
+                                       func = &uniform_matrix_wrapper<float, glUniformMatrix3x2fv>;
+                               else if(u->type==FLOAT_MAT2x4)
+                                       func = &uniform_matrix_wrapper<float, glUniformMatrix2x4fv>;
+                               else if(u->type==FLOAT_MAT4x2)
+                                       func = &uniform_matrix_wrapper<float, glUniformMatrix4x2fv>;
+                               else if(u->type==FLOAT_MAT3x4)
+                                       func = &uniform_matrix_wrapper<float, glUniformMatrix3x4fv>;
+                               else if(u->type==FLOAT_MAT4x3)
+                                       func = &uniform_matrix_wrapper<float, glUniformMatrix4x3fv>;
+
+                               if(func)
+                                       uniform_calls.push_back(UniformCall(u->location, u->array_size, func));
+                       }
+
+               if(i->data_size<=0)
+               {
+                       const ReflectData::UniformInfo &last = *i->uniforms.back();
+                       i->data_size = last.location*16+last.array_size*get_type_size(last.type);
+               }
+       }
+}
+
 void OpenGLProgram::set_debug_name(const string &name)
 {
 #ifdef DEBUG