void Compiler::validate(Stage &stage)
{
- DeclarationValidator().apply(stage);
+ DeclarationValidator().apply(stage, features);
IdentifierValidator().apply(stage);
ReferenceValidator().apply(stage);
ExpressionValidator().apply(stage);
features.texture_binding_range = (ver>=Version(3, 20) ? 96 : ver>=Version(3, 10) ? 48 :
ver>=Version(3, 0) ? 32 : 8);
break;
+ case VULKAN:
+ features.uniform_binding_range = 72;
+ features.texture_binding_range = 96;
+ break;
default:
throw invalid_argument("Features::from_api_version");
}
return from_api_version(api, Version(4, 60));
case OPENGL_ES:
return from_api_version(api, Version(3, 20));
+ case VULKAN:
+ return from_api_version(api, Version(1, 2));
default:
throw invalid_argument("Features::latest");
}
{
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);
{
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));
push_constant = (i!=iface.layout->qualifiers.end());
}
- if((!supports_interface_blocks(iface.interface) || push_constant) && iface.type_declaration)
+ 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));
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;
void SpirVGenerator::visit(InterfaceBlock &iface)
{
- StorageClass storage = get_interface_storage(iface.interface, true);
+ const vector<Layout::Qualifier> *layout_ql = (iface.layout ? &iface.layout->qualifiers : 0);
+
+ bool push_const = false;
+ if(layout_ql)
+ {
+ auto i = find_member(*layout_ql, string("push_constant"), &Layout::Qualifier::name);
+ push_const = (i!=layout_ql->end());
+ }
+
+ StorageClass storage = (push_const ? STORAGE_PUSH_CONSTANT : get_interface_storage(iface.interface, true));
Id type_id;
if(iface.array)
type_id = get_array_type_id(*iface.struct_declaration, 0);
writer.write_op(content.globals, OP_VARIABLE, ptr_type_id, block_id, storage);
- if(iface.layout)
+ if(layout_ql)
{
- auto i = find_member(iface.layout->qualifiers, string("binding"), &Layout::Qualifier::name);
- if(i!=iface.layout->qualifiers.end())
+ auto i = find_member(*layout_ql, string("binding"), &Layout::Qualifier::name);
+ if(i!=layout_ql->end())
writer.write_op_decorate(block_id, DECO_BINDING, i->value);
}
}
STORAGE_UNIFORM = 2,
STORAGE_OUTPUT = 3,
STORAGE_PRIVATE = 6,
- STORAGE_FUNCTION = 7
+ STORAGE_FUNCTION = 7,
+ STORAGE_PUSH_CONSTANT = 9
};
enum SpirVDecoration
}
+void DeclarationValidator::apply(Stage &s, const Features &f)
+{
+ stage = &s;
+ features = f;
+ s.content.visit(*this);
+}
+
const char *DeclarationValidator::describe_variable(ScopeType scope)
{
switch(scope)
{
binding = true;
- if(q.name=="set")
+ if(q.name=="set" && features.target_api!=VULKAN)
{
error(layout, "Layout qualifier 'set' not allowed when targeting OpenGL");
continue;
error(var, format("Mismatched interface qualifier '%s' inside '%s' block", var.interface, iface_block->interface));
else if(scope==STRUCT || scope==FUNCTION)
error(var, format("Interface qualifier not allowed on %s", descr));
+ else if(scope==GLOBAL && variable->interface=="uniform" && features.target_api==VULKAN)
+ {
+ TypeDeclaration *type = variable->type_declaration;
+ while(BasicTypeDeclaration *basic = dynamic_cast<BasicTypeDeclaration *>(type))
+ type = basic->base_type;
+ if(!dynamic_cast<ImageTypeDeclaration *>(type))
+ error(var, "Interface qualifier 'uniform' not allowed on non-opaque variable in global scope");
+ }
}
TypeDeclaration *type = var.type_declaration;
FUNCTION
};
+ Features features;
ScopeType scope = GLOBAL;
InterfaceLayout *iface_layout = 0;
InterfaceBlock *iface_block = 0;
VariableDeclaration *variable = 0;
public:
- void apply(Stage &s) { stage = &s; s.content.visit(*this); }
+ void apply(Stage &, const Features &);
private:
static const char *describe_variable(ScopeType);
vector<string> spec_values_in;
unsigned as_module = 0;
string module_type = "glsl";
+ bool vulkan = false;
unsigned target_version = 0;
GetOpt getopt;
getopt.add_option('e', "specialize", spec_values_in, GetOpt::REQUIRED_ARG).set_help("Set specialization constant", "NAME:VALUE");
getopt.add_option('s', "stage", stage_str, GetOpt::REQUIRED_ARG).set_help("Output GLSL for STAGE", "STAGE");
getopt.add_option('m', "module", module_type, GetOpt::OPTIONAL_ARG).bind_seen_count(as_module).set_help("Compile as unspecialized module");
+ getopt.add_option("vulkan", vulkan, GetOpt::NO_ARG).set_help("Compile for Vulkan target");
getopt.add_option('t', "target-version", target_version, GetOpt::REQUIRED_ARG).set_help("Specify target GLSL version", "VER");
getopt.add_option('o', "out-file", out_filename, GetOpt::REQUIRED_ARG).set_help("Write output to file instead of stdout", "FILE");
getopt.add_option('I', "include", include_paths, GetOpt::REQUIRED_ARG).set_help("Add a directory to look for imported files", "DIR");
getopt.add_argument("source", source_fn, GetOpt::REQUIRED_ARG).set_help("GLSL file to compile");
getopt(argc, argv);
- if(target_version)
+ if(vulkan)
+ {
+ features = GL::SL::Features::latest(GL::VULKAN);
+ as_module = 1;
+ module_type = "spirv";
+ }
+ else if(target_version)
features = GL::SL::Features::from_api_version(GL::OPENGL, GL::Version(target_version/100, target_version%100));
if(as_module)