if(layout_offset)
*layout_offset = offset;
else
- {
- if(!var.layout)
- var.layout = new Layout;
-
- var.layout->qualifiers.push_back(Layout::Qualifier("offset", offset));
- }
+ add_layout_qualifier(var.layout, Layout::Qualifier("offset", offset));
if(!has_matrix_order)
{
while(basic && basic->kind==BasicTypeDeclaration::ARRAY)
basic = dynamic_cast<const BasicTypeDeclaration *>(basic->base_type);
if(basic && basic->kind==BasicTypeDeclaration::MATRIX)
- var.layout->qualifiers.push_back(Layout::Qualifier("column_major"));
+ add_layout_qualifier(var.layout, Layout::Qualifier("column_major"));
}
offset += mem_reqs.size;
}
-void LocationAllocator::apply(Module &module, const Features &features)
+void LocationAllocator::apply(Module &module, const Features &f, bool a)
{
+ features = f;
+ alloc_new = a;
for(Stage &s: module.stages)
apply(s);
- allocate_locations("uniform");
+
+ if(features.target_api!=VULKAN)
+ allocate_locations("uniform");
for(InterfaceBlock *b: unbound_blocks)
bind_uniform(b->layout, b->block_name, features.uniform_binding_range);
auto j = uniforms.find((*i)->name);
if(j!=uniforms.end() && j->second.location>=0)
{
- add_layout_value((*i)->layout, "location", j->second.location);
+ add_layout_qualifier((*i)->layout, Layout::Qualifier("location", j->second.location));
continue;
}
}
+ if(!alloc_new)
+ continue;
+
set<unsigned> &used = used_locations[(*i)->interface];
unsigned size = LocationCounter().apply(**i);
next = blocking+1;
}
- add_layout_value((*i)->layout, "location", next);
+ add_layout_qualifier((*i)->layout, Layout::Qualifier("location", next));
if((*i)->interface=="uniform")
uniforms[(*i)->name].location = next;
void LocationAllocator::bind_uniform(RefPtr<Layout> &layout, const string &name, unsigned range)
{
auto i = uniforms.find(name);
+
+ int desc_set = (i!=uniforms.end() ? i->second.desc_set : 0);
+ if(features.target_api==VULKAN && get_layout_value(layout.get(), "set")<0)
+ add_layout_qualifier(layout, Layout::Qualifier("set", desc_set));
+
if(i!=uniforms.end() && i->second.bind_point>=0)
- add_layout_value(layout, "binding", i->second.bind_point);
- else
+ add_layout_qualifier(layout, Layout::Qualifier("binding", i->second.bind_point));
+ else if(alloc_new)
{
- set<unsigned> &used = used_bindings[0];
+ set<unsigned> &used = used_bindings[desc_set];
- unsigned bind_point = fold32(hash64(name))%range;
+ unsigned bind_point = hash_fold<32>(hash<64>(name))%range;
while(used.count(bind_point))
bind_point = (bind_point+1)%range;
- add_layout_value(layout, "binding", bind_point);
+ add_layout_qualifier(layout, Layout::Qualifier("binding", bind_point));
uniforms[name].bind_point = bind_point;
used.insert(bind_point);
}
}
-void LocationAllocator::add_layout_value(RefPtr<Layout> &layout, const string &name, unsigned value)
+bool LocationAllocator::visit_uniform(const string &name, RefPtr<Layout> &layout)
{
- if(!layout)
- layout = new Layout;
+ int desc_set = 0;
+ int bind_point = get_layout_value(layout.get(), "binding");
+
+ if(features.target_api==VULKAN)
+ {
+ desc_set = get_layout_value(layout.get(), "set");
+ if(desc_set<0 && bind_point>=0)
+ {
+ desc_set = 0;
+ add_layout_qualifier(layout, Layout::Qualifier("set", desc_set));
+ }
- layout->qualifiers.push_back(Layout::Qualifier(name, value));
+ if(desc_set>=0)
+ uniforms[name].desc_set = desc_set;
+ }
+
+ 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.interface.empty())
{
- int location = (var.layout ? get_layout_value(*var.layout, "location") : -1);
+ 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, "location");
+ location = get_layout_value(var.linked_declaration->layout.get(), "location");
if(location>=0)
- add_layout_value(var.layout, "location", location);
+ add_layout_qualifier(var.layout, Layout::Qualifier("location", location));
}
if(location>=0)
if(var.interface=="uniform")
{
- const TypeDeclaration *type = var.type_declaration;
- while(const BasicTypeDeclaration *basic = dynamic_cast<const BasicTypeDeclaration *>(type))
- type = basic->base_type;
- if(dynamic_cast<const ImageTypeDeclaration *>(type))
- {
- int bind_point = (var.layout ? get_layout_value(*var.layout, "binding") : -1);
- if(bind_point>=0)
- {
- used_bindings[0].insert(bind_point);
- uniforms[var.name].bind_point = bind_point;
- }
- else
- unbound_textures.push_back(&var);
- }
+ const TypeDeclaration *base_type = get_ultimate_base_type(var.type_declaration);
+ if(dynamic_cast<const ImageTypeDeclaration *>(base_type) && !visit_uniform(var.name, var.layout))
+ unbound_textures.push_back(&var);
}
}
if(iface.interface=="uniform")
{
- bool push_constant = false;
- if(iface.layout)
- {
- auto i = find_member(iface.layout->qualifiers, string("push_constant"), &Layout::Qualifier::name);
- push_constant = (i!=iface.layout->qualifiers.end());
- }
-
- if(!push_constant)
- {
- int bind_point = (iface.layout ? get_layout_value(*iface.layout, "binding") : -1);
-
- if(bind_point>=0)
- {
- used_bindings[0].insert(bind_point);
- uniforms[iface.block_name].bind_point = bind_point;
- }
- else
- unbound_blocks.push_back(&iface);
- }
+ bool push_constant = has_layout_qualifier(iface.layout.get(), "push_constant");
+ if(!push_constant && !visit_uniform(iface.block_name, iface.layout))
+ unbound_blocks.push_back(&iface);
}
}
{
if(st==Stage::GEOMETRY)
{
- if(features.target_api==OPENGL_ES)
+ if(features.target_api==VULKAN)
+ return true;
+ else if(features.target_api==OPENGL_ES)
return check_version(Version(3, 20));
else
return check_version(Version(1, 50));
bool StructuralFeatureConverter::supports_unified_interface_syntax() const
{
- if(features.target_api==OPENGL_ES)
+ if(features.target_api==VULKAN)
+ return true;
+ else if(features.target_api==OPENGL_ES)
return check_version(Version(3, 0));
else
return check_version(Version(1, 30));
bool StructuralFeatureConverter::supports_unified_sampling_functions() const
{
- if(features.target_api==OPENGL_ES)
+ if(features.target_api==VULKAN)
+ return true;
+ else if(features.target_api==OPENGL_ES)
return check_version(Version(3, 0));
else
return check_version(Version(1, 30));
bool StructuralFeatureConverter::supports_interface_blocks(const string &iface) const
{
- if(features.target_api==OPENGL_ES)
+ if(features.target_api==VULKAN)
+ return true;
+ else if(features.target_api==OPENGL_ES)
{
if(iface=="uniform")
return check_version(Version(3, 0));
void StructuralFeatureConverter::visit(InterfaceBlock &iface)
{
- bool push_constant = false;
- if(iface.layout)
- {
- auto i = find_member(iface.layout->qualifiers, string("push_constant"), &Layout::Qualifier::name);
- push_constant = (i!=iface.layout->qualifiers.end());
- }
-
- if((!supports_interface_blocks(iface.interface) || push_constant) && iface.type_declaration)
+ bool push_constant = has_layout_qualifier(iface.layout.get(), "push_constant");
+ if((!supports_interface_blocks(iface.interface) || (push_constant && features.target_api!=VULKAN)) && iface.type_declaration)
{
if(!iface.instance_name.empty())
unsupported("ARB_uniform_buffer_object required for interface block instances");
bool QualifierConverter::supports_interface_layouts() const
{
- if(features.target_api==OPENGL_ES)
+ if(features.target_api==VULKAN)
+ return true;
+ else if(features.target_api==OPENGL_ES)
return check_version(Version(3, 0));
else if(check_version(Version(3, 30)))
return true;
bool QualifierConverter::supports_stage_interface_layouts() const
{
- if(features.target_api==OPENGL_ES)
+ if(features.target_api==VULKAN)
+ return true;
+ else if(features.target_api==OPENGL_ES)
return check_version(Version(3, 10));
else if(check_version(Version(4, 10)))
return true;
bool QualifierConverter::supports_centroid_sampling() const
{
- if(features.target_api==OPENGL_ES)
+ if(features.target_api==VULKAN)
+ return true;
+ else if(features.target_api==OPENGL_ES)
return check_version(Version(3, 0));
else if(check_version(Version(1, 20)))
return true;
bool QualifierConverter::supports_sample_sampling() const
{
- if(features.target_api==OPENGL_ES)
+ if(features.target_api==VULKAN)
+ return true;
+ else if(features.target_api==OPENGL_ES)
return check_version(Version(3, 20));
else if(check_version(Version(4, 0)))
return true;
bool QualifierConverter::supports_uniform_location() const
{
- if(features.target_api==OPENGL_ES)
+ if(features.target_api==VULKAN)
+ return true;
+ else if(features.target_api==OPENGL_ES)
return check_version(Version(3, 10));
else if(check_version(Version(4, 30)))
return true;
bool QualifierConverter::supports_binding() const
{
- if(features.target_api==OPENGL_ES)
+ if(features.target_api==VULKAN)
+ return true;
+ else if(features.target_api==OPENGL_ES)
return check_version(Version(3, 10));
else
return check_version(Version(4, 20));
}
else if(i->name=="binding" && !supports_binding())
{
- const TypeDeclaration *type = var.type_declaration;
- while(const BasicTypeDeclaration *basic = dynamic_cast<const BasicTypeDeclaration *>(type))
- type = basic->base_type;
- if(dynamic_cast<const ImageTypeDeclaration *>(type))
+ if(dynamic_cast<const ImageTypeDeclaration *>(get_ultimate_base_type(var.type_declaration)))
stage->texture_bindings[var.name] = i->value;
i = var.layout->qualifiers.erase(i);
bool QualifierConverter::supports_interface_block_location() const
{
- if(features.target_api==OPENGL_ES)
+ if(features.target_api==VULKAN)
+ return true;
+ else if(features.target_api==OPENGL_ES)
return check_version(Version(3, 20));
else if(check_version(Version(4, 40)))
return true;