X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=blobdiff_plain;f=source%2Fcore%2Fprogram.cpp;h=16b2fa79c7509a5ee38a6f912c5a2da0ebbf83ec;hp=5c8257b2fc60de50bf0e767beb90a5f8da5784e2;hb=5871764de7aa23d2c40cac03ad9d07088fb57e06;hpb=a833b47ecd5bf91a979a30d0898f768a14cf5067 diff --git a/source/core/program.cpp b/source/core/program.cpp index 5c8257b2..16b2fa79 100644 --- a/source/core/program.cpp +++ b/source/core/program.cpp @@ -17,6 +17,8 @@ void Program::add_stages(const Module &mod, const map &spec_values) if(has_stages()) throw invalid_operation("Program::add_stages"); + reflect_data = ReflectData(); + TransientData transient; switch(mod.get_format()) { @@ -24,79 +26,151 @@ void Program::add_stages(const Module &mod, const map &spec_values) add_glsl_stages(static_cast(mod), spec_values, transient); break; case Module::SPIR_V: - add_spirv_stages(static_cast(mod), spec_values, transient); + add_spirv_stages(static_cast(mod), spec_values); break; default: throw invalid_argument("Program::add_stages"); } - reflect_data = ReflectData(); + finalize(mod, transient); + + if(mod.get_format()==Module::SPIR_V) + { + const SpirVModule &spirv_mod = static_cast(mod); + vector used_variables = collect_used_variables(spirv_mod, spec_values); + collect_uniforms(spirv_mod, used_variables); + collect_attributes(spirv_mod, used_variables); + collect_builtins(spirv_mod); + } - finalize(mod); + finalize_uniforms(); + + for(const ReflectData::UniformInfo &u: reflect_data.uniforms) + require_type(u.type); + for(const ReflectData::AttributeInfo &a: reflect_data.attributes) + require_type(a.type); +} - if(mod.get_format()==Module::GLSL) +vector Program::collect_used_variables(const SpirVModule &mod, const map &spec_values) +{ + std::map spec_values_by_id; + for(const SpirVModule::Constant &c: mod.get_spec_constants()) { - query_uniforms(); - query_attributes(); - apply_bindings(transient); + auto i = spec_values.find(c.name); + if(i!=spec_values.end()) + spec_values_by_id[c.constant_id] = i->second; } - else if(mod.get_format()==Module::SPIR_V) + + const vector &blocks = mod.get_blocks(); + vector visited(blocks.size(), 4); + for(unsigned i=0; i(mod), transient.spec_values); - collect_attributes(static_cast(mod)); + const SpirVModule::InstructionBlock &b = blocks[i]; + + bool cond = true; + if(b.condition) + { + cond = b.condition->i_value; + auto j = spec_values_by_id.find(b.condition->constant_id); + if(j!=spec_values_by_id.end()) + cond = j->second; + if(b.negate_condition) + cond = !cond; + } + + visited[i] |= cond*2; + for(const SpirVModule::InstructionBlock *s: b.successors) + visited[s-blocks.data()] &= 3; } - for(ReflectData::UniformBlockInfo &b: reflect_data.uniform_blocks) - if(!b.data_size && !b.uniforms.empty()) + for(unsigned i=0; i &variables = mod.get_variables(); + vector used(variables.size()); + for(unsigned i=0; i &spec_values) +void Program::collect_visited_blocks(const vector &blocks, unsigned i, vector &visited) +{ + visited[i] |= 1; + for(const SpirVModule::InstructionBlock *s: blocks[i].successors) + { + unsigned j = s-blocks.data(); + if((visited[j]&3)==2) + collect_visited_blocks(blocks, j, visited); + } +} + +void Program::collect_uniforms(const SpirVModule &mod, const vector &used_variables) { // Prepare the default block - reflect_data.uniform_blocks.push_back(ReflectData::UniformBlockInfo()); + reflect_data.uniform_blocks.emplace_back(); vector > block_uniform_names(1); - for(const SpirVModule::Variable &v: mod.get_variables()) + const vector &variables = mod.get_variables(); + unsigned n_descriptor_sets = 0; + for(unsigned i=0; iname; - info.bind_point = v.binding; + if(v.storage==SpirVModule::PUSH_CONSTANT) + info.bind_point = ReflectData::PUSH_CONSTANT; + else + { + if(v.binding>=0) + info.bind_point = v.binding | (v.descriptor_set<<20); + else + info.bind_point = ReflectData::DEFAULT_BLOCK; + n_descriptor_sets = max(n_descriptor_sets, v.descriptor_set+1); + } info.data_size = v.struct_type->size; string prefix; if(!v.name.empty()) prefix = v.struct_type->name+"."; - block_uniform_names.push_back(vector()); - collect_block_uniforms(*v.struct_type, prefix, 0, spec_values, block_uniform_names.back()); + block_uniform_names.emplace_back(); + collect_block_uniforms(*v.struct_type, prefix, 0, block_uniform_names.back()); } - else if(v.storage==SpirVModule::UNIFORM_CONSTANT && v.location>=0) + else if(v.storage==SpirVModule::UNIFORM_CONSTANT && (v.location>=0 || v.binding>=0)) { block_uniform_names[0].push_back(v.name); - reflect_data.uniforms.push_back(ReflectData::UniformInfo()); + reflect_data.uniforms.emplace_back(); ReflectData::UniformInfo &info = reflect_data.uniforms.back(); info.name = v.name; info.tag = v.name; info.location = v.location; - info.binding = v.binding; - info.array_size = v.array_size; + if(v.binding>=0) + info.binding = v.binding | (v.descriptor_set<<20); + n_descriptor_sets = max(n_descriptor_sets, v.descriptor_set+1); + info.array_size = max(v.array_size, 1U); info.type = v.type; } } sort_member(reflect_data.uniforms, &ReflectData::UniformInfo::tag); + if(block_uniform_names.front().empty()) + { + reflect_data.uniform_blocks.erase(reflect_data.uniform_blocks.begin()); + block_uniform_names.erase(block_uniform_names.begin()); + } + for(unsigned i=0; i block.update_layout_hash(); } + reflect_data.n_descriptor_sets = n_descriptor_sets; reflect_data.update_layout_hash(); } -void Program::collect_block_uniforms(const SpirVModule::Structure &strct, const string &prefix, unsigned base_offset, const map &spec_values, vector &uniform_names) +void Program::collect_block_uniforms(const SpirVModule::Structure &strct, const string &prefix, unsigned base_offset, vector &uniform_names) { for(const SpirVModule::StructMember &m: strct.members) { unsigned offset = base_offset+m.offset; if(m.struct_type) { - unsigned array_size = m.array_size; - if(m.array_size_spec) + if(m.array_size) { - array_size = m.array_size_spec->i_value; - 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 &used_variables) { + const vector &variables = mod.get_variables(); for(const SpirVModule::EntryPoint &e: mod.get_entry_points()) if(e.stage==SpirVModule::VERTEX && e.name=="main") { for(const SpirVModule::Variable *v: e.globals) - if(v->storage==SpirVModule::INPUT) + if(v->storage==SpirVModule::INPUT && used_variables[v-variables.data()]) { - reflect_data.attributes.push_back(ReflectData::AttributeInfo()); + reflect_data.attributes.emplace_back(); ReflectData::AttributeInfo &info = reflect_data.attributes.back(); info.name = v->name; info.location = v->location; @@ -173,6 +240,20 @@ void Program::collect_attributes(const SpirVModule &mod) } } +void Program::collect_builtins(const SpirVModule &mod) +{ + for(const SpirVModule::Variable &v: mod.get_variables()) + if(v.storage==SpirVModule::OUTPUT && v.struct_type) + collect_builtins(*v.struct_type); +} + +void Program::collect_builtins(const SpirVModule::Structure &strct) +{ + for(const SpirVModule::StructMember &m: strct.members) + if(m.builtin==SpirVModule::CLIP_DISTANCE) + reflect_data.n_clip_distances = m.array_size; +} + const ReflectData::UniformBlockInfo &Program::get_uniform_block_info(const string &name) const { auto i = find_member(reflect_data.uniform_blocks, name, &ReflectData::UniformBlockInfo::name);