+ set<unsigned> &used = used_bindings[desc_set];
+
+ unsigned bind_point = hash_fold<32>(hash<64>(name))%range;
+ while(used.count(bind_point))
+ bind_point = (bind_point+1)%range;
+
+ add_layout_qualifier(layout, Layout::Qualifier("binding", bind_point));
+ uniforms[name].bind_point = bind_point;
+ used.insert(bind_point);
+ }
+}
+
+bool LocationAllocator::visit_uniform(const string &name, RefPtr<Layout> &layout)
+{
+ int desc_set = get_layout_value(layout.get(), "set");
+ int bind_point = get_layout_value(layout.get(), "binding");
+
+ if(features.target_api==VULKAN)
+ {
+ if(desc_set<0 && bind_point>=0)
+ {
+ desc_set = 0;
+ add_layout_qualifier(layout, Layout::Qualifier("set", desc_set));
+ }
+
+ if(desc_set>=0)
+ uniforms[name].desc_set = desc_set;
+ }
+ else if(desc_set>=0 && bind_point<0)
+ {
+ auto i = find_member(layout->qualifiers, string("set"), &Layout::Qualifier::name);
+ layout->qualifiers.erase(i);
+ }
+
+ if(bind_point>=0)
+ {
+ used_bindings[desc_set].insert(bind_point);
+ uniforms[name].bind_point = bind_point;
+ }
+
+ return bind_point>=0;
+}
+
+void LocationAllocator::visit(VariableDeclaration &var)
+{
+ if(!var.name.compare(0, 3, "gl_"))
+ return;
+
+ if(!var.interface.empty() && !var.block_declaration)
+ {
+ int location = get_layout_value(var.layout.get(), "location");
+
+ if(location<0 && var.linked_declaration && var.linked_declaration->layout)
+ {
+ location = get_layout_value(var.linked_declaration->layout.get(), "location");
+ if(location>=0)
+ add_layout_qualifier(var.layout, Layout::Qualifier("location", location));
+ }
+
+ if(location>=0)
+ {
+ unsigned size = LocationCounter().apply(var);
+ for(unsigned i=0; i<size; ++i)
+ used_locations[var.interface].insert(location+i);
+ if(var.interface=="uniform")
+ uniforms[var.name].location = location;
+ }