From b7f46931a9878b2fd7ec863d520dc22ac89c0baf Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Sun, 26 Sep 2021 16:41:03 +0300 Subject: [PATCH] Restructure Program to remove linking from the public interface It doesn't map to Vulkan at all. Doing it from add_stages also simplifies handling some temporary data. --- source/core/program.cpp | 136 ++++++++++++++------------------- source/core/program.h | 22 ++---- source/resources/resources.cpp | 1 - 3 files changed, 65 insertions(+), 94 deletions(-) diff --git a/source/core/program.cpp b/source/core/program.cpp index 82f438cd..4e090380 100644 --- a/source/core/program.cpp +++ b/source/core/program.cpp @@ -35,7 +35,6 @@ Program::Program(const Module &mod, const map &spec_values) { init(); add_stages(mod, spec_values); - link(); } void Program::init() @@ -44,8 +43,6 @@ void Program::init() id = glCreateProgram(); fill(stage_ids, stage_ids+MAX_STAGES, 0); - module = 0; - transient = 0; linked = false; } @@ -62,12 +59,20 @@ void Program::add_stages(const Module &mod, const map &spec_values) if(has_stages()) throw invalid_operation("Program::add_stages"); + TransientData transient; switch(mod.get_format()) { - case Module::GLSL: return add_glsl_stages(static_cast(mod), spec_values); - case Module::SPIR_V: return add_spirv_stages(static_cast(mod), spec_values); - default: throw invalid_argument("Program::add_stages"); + case Module::GLSL: + add_glsl_stages(static_cast(mod), spec_values, transient); + break; + case Module::SPIR_V: + add_spirv_stages(static_cast(mod), spec_values, transient); + break; + default: + throw invalid_argument("Program::add_stages"); } + + finalize(mod, transient); } bool Program::has_stages() const @@ -104,10 +109,8 @@ unsigned Program::add_stage(Stage type) return stage_id; } -void Program::add_glsl_stages(const GlslModule &mod, const map &spec_values) +void Program::add_glsl_stages(const GlslModule &mod, const map &spec_values, TransientData &transient) { - module = &mod; - SL::Compiler compiler; compiler.set_source(mod.get_prepared_source(), ""); compiler.specialize(spec_values); @@ -119,6 +122,9 @@ void Program::add_glsl_stages(const GlslModule &mod, const map &spe #endif vector stages = compiler.get_stages(); + if(stages.empty()) + throw invalid_argument("Program::add_glsl_stages"); + for(SL::Stage::Type st: stages) { unsigned stage_id = 0; @@ -147,16 +153,14 @@ void Program::add_glsl_stages(const GlslModule &mod, const map &spe glBindFragDataLocation(id, kvp.second, kvp.first.c_str()); } - compile_glsl_stage(stage_id); + compile_glsl_stage(mod, stage_id); } - if(!transient) - transient = new TransientData; - transient->textures = compiler.get_texture_bindings(); - transient->blocks = compiler.get_uniform_block_bindings(); + transient.textures = compiler.get_texture_bindings(); + transient.blocks = compiler.get_uniform_block_bindings(); } -void Program::compile_glsl_stage(unsigned stage_id) +void Program::compile_glsl_stage(const GlslModule &mod, unsigned stage_id) { glCompileShader(stage_id); int status = 0; @@ -167,8 +171,7 @@ void Program::compile_glsl_stage(unsigned stage_id) string info_log(info_log_len+1, 0); glGetShaderInfoLog(stage_id, info_log_len+1, &info_log_len, &info_log[0]); info_log.erase(info_log_len); - if(module && module->get_format()==Module::GLSL) - info_log = static_cast(module)->get_source_map().translate_errors(info_log); + info_log = mod.get_source_map().translate_errors(info_log); if(!status) throw compile_error(info_log); @@ -178,13 +181,11 @@ void Program::compile_glsl_stage(unsigned stage_id) #endif } -void Program::add_spirv_stages(const SpirVModule &mod, const map &spec_values) +void Program::add_spirv_stages(const SpirVModule &mod, const map &spec_values, TransientData &transient) { static Require _req(ARB_gl_spirv); static Require _req2(ARB_ES2_compatibility); - module = &mod; - unsigned n_stages = 0; unsigned used_stage_ids[MAX_STAGES]; for(const SpirVModule::EntryPoint &e: mod.get_entry_points()) @@ -201,12 +202,12 @@ void Program::add_spirv_stages(const SpirVModule &mod, const map &s used_stage_ids[n_stages++] = stage_id; } + if(!n_stages) + throw invalid_argument("Program::add_spirv_stages"); + const vector &code = mod.get_code(); glShaderBinary(n_stages, used_stage_ids, GL_SHADER_BINARY_FORMAT_SPIR_V, &code[0], code.size()*4); - if(!spec_values.empty() && !transient) - transient = new TransientData; - const vector &spec_consts = mod.get_spec_constants(); vector spec_id_array; vector spec_value_array; @@ -219,7 +220,7 @@ void Program::add_spirv_stages(const SpirVModule &mod, const map &s { spec_id_array.push_back(c.constant_id); spec_value_array.push_back(i->second); - transient->spec_values[c.constant_id] = i->second; + transient.spec_values[c.constant_id] = i->second; } } @@ -229,11 +230,8 @@ void Program::add_spirv_stages(const SpirVModule &mod, const map &s glSpecializeShader(stage_ids[i], j->name.c_str(), spec_id_array.size(), &spec_id_array[0], &spec_value_array[0]); } -void Program::link() +void Program::finalize(const Module &mod, const TransientData &transient) { - if(!has_stages()) - throw invalid_operation("Program::link"); - reflect_data = ReflectData(); glLinkProgram(id); @@ -246,8 +244,8 @@ void Program::link() string info_log(info_log_len+1, 0); glGetProgramInfoLog(id, info_log_len+1, &info_log_len, &info_log[0]); info_log.erase(info_log_len); - if(module && module->get_format()==Module::GLSL) - info_log = static_cast(module)->get_source_map().translate_errors(info_log); + if(mod.get_format()==Module::GLSL) + info_log = static_cast(mod).get_source_map().translate_errors(info_log); if(!linked) throw compile_error(info_log); @@ -256,46 +254,40 @@ void Program::link() IO::print("Program link info log:\n%s", info_log); #endif - if(module->get_format()==Module::GLSL) + if(mod.get_format()==Module::GLSL) { query_uniforms(); query_attributes(); - if(transient) + for(unsigned i=0; iblocks.find(reflect_data.uniform_blocks[i].name); - if(j!=transient->blocks.end()) - { - glUniformBlockBinding(id, i, j->second); - reflect_data.uniform_blocks[i].bind_point = j->second; - } + glUniformBlockBinding(id, i, j->second); + reflect_data.uniform_blocks[i].bind_point = j->second; } + } - if(!ARB_separate_shader_objects) - glUseProgram(id); - for(const auto &kvp: transient->textures) + if(!ARB_separate_shader_objects) + glUseProgram(id); + for(const auto &kvp: transient.textures) + { + int location = get_uniform_location(kvp.first); + if(location>=0) { - int location = get_uniform_location(kvp.first); - if(location>=0) - { - if(ARB_separate_shader_objects) - glProgramUniform1i(id, location, kvp.second); - else - glUniform1i(location, kvp.second); - } + if(ARB_separate_shader_objects) + glProgramUniform1i(id, location, kvp.second); + else + glUniform1i(location, kvp.second); } } } - else if(module->get_format()==Module::SPIR_V) + else if(mod.get_format()==Module::SPIR_V) { - collect_uniforms(); - collect_attributes(); + collect_uniforms(static_cast(mod), transient.spec_values); + collect_attributes(static_cast(mod)); } - delete transient; - transient = 0; - for(const ReflectData::UniformInfo &u: reflect_data.uniforms) require_type(u.type); for(const ReflectData::AttributeInfo &a: reflect_data.attributes) @@ -458,10 +450,8 @@ void Program::query_attributes() } } -void Program::collect_uniforms() +void Program::collect_uniforms(const SpirVModule &mod, const map &spec_values) { - const SpirVModule &mod = static_cast(*module); - // Prepare the default block reflect_data.uniform_blocks.push_back(ReflectData::UniformBlockInfo()); vector > block_uniform_names(1); @@ -480,7 +470,7 @@ void Program::collect_uniforms() if(!v.name.empty()) prefix = v.struct_type->name+"."; block_uniform_names.push_back(vector()); - collect_block_uniforms(*v.struct_type, prefix, 0, block_uniform_names.back()); + collect_block_uniforms(*v.struct_type, prefix, 0, spec_values, block_uniform_names.back()); } else if(v.storage==SpirVModule::UNIFORM_CONSTANT && v.location>=0) { @@ -515,7 +505,7 @@ void Program::collect_uniforms() reflect_data.update_layout_hash(); } -void Program::collect_block_uniforms(const SpirVModule::Structure &strct, const string &prefix, unsigned base_offset, vector &uniform_names) +void Program::collect_block_uniforms(const SpirVModule::Structure &strct, const string &prefix, unsigned base_offset, const map &spec_values, vector &uniform_names) { for(const SpirVModule::StructMember &m: strct.members) { @@ -526,21 +516,18 @@ void Program::collect_block_uniforms(const SpirVModule::Structure &strct, const if(m.array_size_spec) { array_size = m.array_size_spec->i_value; - if(transient) - { - auto j = transient->spec_values.find(m.array_size_spec->constant_id); - if(j!=transient->spec_values.end()) - array_size = j->second; - } + auto j = spec_values.find(m.array_size_spec->constant_id); + if(j!=spec_values.end()) + array_size = j->second; } if(array_size) { for(unsigned j=0; j(*module); - for(const SpirVModule::EntryPoint &e: mod.get_entry_points()) if(e.stage==SpirVModule::VERTEX && e.name=="main") { @@ -672,12 +657,7 @@ void Program::set_stage_debug_name(unsigned stage_id, Stage type) Program::Loader::Loader(Program &p, Collection &c): DataFile::CollectionObjectLoader(p, &c) { - add("module", &Loader::module); -} - -void Program::Loader::finish() -{ - obj.link(); + add("module", &Loader::module); } void Program::Loader::module(const string &n) diff --git a/source/core/program.h b/source/core/program.h index b7f46ee4..6301edbe 100644 --- a/source/core/program.h +++ b/source/core/program.h @@ -27,8 +27,6 @@ public: Loader(Program &, Collection &); private: - virtual void finish(); - void module(const std::string &); }; @@ -67,8 +65,6 @@ private: unsigned id; unsigned stage_ids[MAX_STAGES]; - const Module *module; - TransientData *transient; bool linked; ReflectData reflect_data; std::string debug_name; @@ -89,23 +85,19 @@ public: private: bool has_stages() const; unsigned add_stage(Stage); - void add_glsl_stages(const GlslModule &, const std::map &); - void compile_glsl_stage(unsigned); - void add_spirv_stages(const SpirVModule &, const std::map &); + void add_glsl_stages(const GlslModule &, const std::map &, TransientData &); + void compile_glsl_stage(const GlslModule &, unsigned); + void add_spirv_stages(const SpirVModule &, const std::map &, TransientData &); -public: - void link(); -private: + void finalize(const Module &, const TransientData &); void query_uniforms(); void query_uniform_blocks(const std::vector &); void query_attributes(); - void collect_uniforms(); - void collect_block_uniforms(const SpirVModule::Structure &, const std::string &, unsigned, std::vector &); - void collect_attributes(); + void collect_uniforms(const SpirVModule &, const std::map &); + void collect_block_uniforms(const SpirVModule::Structure &, const std::string &, unsigned, const std::map &, std::vector &); + void collect_attributes(const SpirVModule &); public: - bool is_linked() const { return linked; } - ReflectData::LayoutHash get_uniform_layout_hash() const { return reflect_data.layout_hash; } const std::vector &get_uniform_blocks() const { return reflect_data.uniform_blocks; } const ReflectData::UniformBlockInfo &get_uniform_block_info(const std::string &) const; diff --git a/source/resources/resources.cpp b/source/resources/resources.cpp index 8a7780cd..62bdabf6 100644 --- a/source/resources/resources.cpp +++ b/source/resources/resources.cpp @@ -244,7 +244,6 @@ Program *Resources::create_program(const string &name) Module &module = get(base); RefPtr shprog = new Program; shprog->add_stages(module); - shprog->link(); return shprog.release(); } -- 2.43.0