+
+ sort_member(uniforms, &UniformInfo::tag);
+
+ for(unsigned i=0; i<uniform_blocks.size(); ++i)
+ {
+ UniformBlockInfo &block = uniform_blocks[i];
+ for(const string &n: block_uniform_names[i])
+ {
+ // The element is already known to be present
+ UniformInfo &uni = *lower_bound_member(uniforms, Tag(n), &UniformInfo::tag);
+ block.uniforms.push_back(&uni);
+ uni.block = █
+ }
+ sort(block.uniforms, uniform_location_compare);
+ block.layout_hash = compute_layout_hash(block.uniforms);
+ }
+
+ update_layout_hash();
+}
+
+void Program::collect_block_uniforms(const SpirVModule::Structure &strct, const string &prefix, unsigned base_offset, vector<string> &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)
+ {
+ 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;
+ }
+ }
+
+ if(array_size)
+ {
+ for(unsigned j=0; j<array_size; ++j, offset+=m.array_stride)
+ collect_block_uniforms(*m.struct_type, format("%s%s[%d].", prefix, m.name, j), offset, uniform_names);
+ }
+ else
+ collect_block_uniforms(*m.struct_type, prefix+m.name+".", offset, uniform_names);
+ }
+ else
+ {
+ string name = prefix+m.name;
+ uniform_names.push_back(name);
+ uniforms.push_back(UniformInfo());
+ UniformInfo &info = uniforms.back();
+ info.name = name;
+ info.tag = name;
+ info.offset = offset;
+ info.array_size = m.array_size;
+ info.array_stride = m.array_stride;
+ info.matrix_stride = m.matrix_stride;
+ info.type = m.type;
+ }
+ }
+}
+
+void Program::collect_attributes()
+{
+ const SpirVModule &mod = static_cast<const SpirVModule &>(*module);
+
+ 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)
+ {
+ attributes.push_back(AttributeInfo());
+ AttributeInfo &info = attributes.back();
+ info.name = v->name;
+ info.location = v->location;
+ info.array_size = v->array_size;
+ info.type = v->type;
+ }
+ }
+}
+
+void Program::update_layout_hash()
+{
+ string layout_descriptor;
+ for(const UniformBlockInfo &b: uniform_blocks)
+ layout_descriptor += format("%d:%x\n", b.bind_point, b.layout_hash);
+ uniform_layout_hash = hash32(layout_descriptor);