From: Mikko Rasa Date: Wed, 10 Nov 2021 20:09:17 +0000 (+0200) Subject: Add basic Vulkan support to the shader compiler X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=commitdiff_plain;h=25629675e83449d986ef8896e830db562a8ae64e Add basic Vulkan support to the shader compiler --- diff --git a/source/glsl/compiler.cpp b/source/glsl/compiler.cpp index 00efbd94..e676fcc8 100644 --- a/source/glsl/compiler.cpp +++ b/source/glsl/compiler.cpp @@ -329,7 +329,7 @@ void Compiler::resolve(Stage &stage, unsigned flags) void Compiler::validate(Stage &stage) { - DeclarationValidator().apply(stage); + DeclarationValidator().apply(stage, features); IdentifierValidator().apply(stage); ReferenceValidator().apply(stage); ExpressionValidator().apply(stage); diff --git a/source/glsl/features.cpp b/source/glsl/features.cpp index a174f644..c67cf2dc 100644 --- a/source/glsl/features.cpp +++ b/source/glsl/features.cpp @@ -41,6 +41,10 @@ Features Features::from_api_version(GraphicsApi api, const Version &ver) 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"); } @@ -55,6 +59,8 @@ Features Features::latest(GraphicsApi api) 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"); } diff --git a/source/glsl/finalize.cpp b/source/glsl/finalize.cpp index 1a8f7542..e89aa494 100644 --- a/source/glsl/finalize.cpp +++ b/source/glsl/finalize.cpp @@ -71,7 +71,9 @@ void LocationAllocator::apply(Module &module, const Features &features) { 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); @@ -386,7 +388,9 @@ bool StructuralFeatureConverter::supports_stage(Stage::Type st) const { 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)); @@ -397,7 +401,9 @@ bool StructuralFeatureConverter::supports_stage(Stage::Type st) const 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)); @@ -438,7 +444,9 @@ void StructuralFeatureConverter::visit(Assignment &assign) 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)); @@ -495,7 +503,9 @@ void StructuralFeatureConverter::visit(VariableDeclaration &var) 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)); @@ -519,7 +529,7 @@ void StructuralFeatureConverter::visit(InterfaceBlock &iface) 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"); @@ -547,7 +557,9 @@ void QualifierConverter::apply() 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; @@ -559,7 +571,9 @@ bool QualifierConverter::supports_interface_layouts() const 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; @@ -569,7 +583,9 @@ bool QualifierConverter::supports_stage_interface_layouts() const 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; @@ -579,7 +595,9 @@ bool QualifierConverter::supports_centroid_sampling() const 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; @@ -589,7 +607,9 @@ bool QualifierConverter::supports_sample_sampling() const 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; @@ -599,7 +619,9 @@ bool QualifierConverter::supports_uniform_location() const 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)); @@ -681,7 +703,9 @@ void QualifierConverter::visit(VariableDeclaration &var) 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; diff --git a/source/glsl/spirv.cpp b/source/glsl/spirv.cpp index 609cdb19..c9062efa 100644 --- a/source/glsl/spirv.cpp +++ b/source/glsl/spirv.cpp @@ -1680,7 +1680,16 @@ void SpirVGenerator::visit(VariableDeclaration &var) void SpirVGenerator::visit(InterfaceBlock &iface) { - StorageClass storage = get_interface_storage(iface.interface, true); + const vector *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); @@ -1706,10 +1715,10 @@ void SpirVGenerator::visit(InterfaceBlock &iface) 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); } } diff --git a/source/glsl/spirvconstants.h b/source/glsl/spirvconstants.h index 66183905..33d705e2 100644 --- a/source/glsl/spirvconstants.h +++ b/source/glsl/spirvconstants.h @@ -188,7 +188,8 @@ enum SpirVStorageClass STORAGE_UNIFORM = 2, STORAGE_OUTPUT = 3, STORAGE_PRIVATE = 6, - STORAGE_FUNCTION = 7 + STORAGE_FUNCTION = 7, + STORAGE_PUSH_CONSTANT = 9 }; enum SpirVDecoration diff --git a/source/glsl/validate.cpp b/source/glsl/validate.cpp index 2da8345d..e11f181e 100644 --- a/source/glsl/validate.cpp +++ b/source/glsl/validate.cpp @@ -34,6 +34,13 @@ void Validator::add_info(Node &node, const string &message) } +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) @@ -62,7 +69,7 @@ void DeclarationValidator::visit(Layout &layout) { 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; @@ -249,6 +256,14 @@ void DeclarationValidator::visit(VariableDeclaration &var) 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(type)) + type = basic->base_type; + if(!dynamic_cast(type)) + error(var, "Interface qualifier 'uniform' not allowed on non-opaque variable in global scope"); + } } TypeDeclaration *type = var.type_declaration; diff --git a/source/glsl/validate.h b/source/glsl/validate.h index b47a9911..558803ff 100644 --- a/source/glsl/validate.h +++ b/source/glsl/validate.h @@ -39,13 +39,14 @@ private: 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); diff --git a/tools/glslcompiler.cpp b/tools/glslcompiler.cpp index bcc787eb..ee9c2d3c 100644 --- a/tools/glslcompiler.cpp +++ b/tools/glslcompiler.cpp @@ -55,6 +55,7 @@ GlslCompiler::GlslCompiler(int argc, char **argv): vector spec_values_in; unsigned as_module = 0; string module_type = "glsl"; + bool vulkan = false; unsigned target_version = 0; GetOpt getopt; @@ -64,13 +65,20 @@ GlslCompiler::GlslCompiler(int argc, char **argv): 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)