]> git.tdb.fi Git - libs/gl.git/commitdiff
Add basic Vulkan support to the shader compiler
authorMikko Rasa <tdb@tdb.fi>
Wed, 10 Nov 2021 20:09:17 +0000 (22:09 +0200)
committerMikko Rasa <tdb@tdb.fi>
Wed, 10 Nov 2021 23:39:40 +0000 (01:39 +0200)
source/glsl/compiler.cpp
source/glsl/features.cpp
source/glsl/finalize.cpp
source/glsl/spirv.cpp
source/glsl/spirvconstants.h
source/glsl/validate.cpp
source/glsl/validate.h
tools/glslcompiler.cpp

index 00efbd94393c4399d0dbc206551575f5bf93fc22..e676fcc87233764cc529fe98203bc5d8b666df0f 100644 (file)
@@ -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);
index a174f644fedec10c5b906cbd8a6feda19ed1dc63..c67cf2dca79943f1e39ee7254eec9b6add4ff210 100644 (file)
@@ -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");
        }
index 1a8f75422effd8368b1c9e2d2bee0b1b76cd77a6..e89aa4942ad768bb32318dad10cde682de7c78f8 100644 (file)
@@ -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;
index 609cdb1968ac896627045cf8de82c61dd9284d15..c9062efa12ae7aee7dfb54ca6638d64ca57b3da8 100644 (file)
@@ -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::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);
@@ -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);
        }
 }
index 661839053544d7e762d640fac159073cc57392da..33d705e22383971ccd273a3d8d4cc77f1b2fc9b3 100644 (file)
@@ -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
index 2da8345de4a7002e0020d98fe536443c72b8cba6..e11f181e0b42d1140b67b313cfe449ff8bad52d7 100644 (file)
@@ -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<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;
index b47a9911d95c6a147034f1937243f34bd69ebca9..558803ff8277b74902f3dcff65d2cdc454526c50 100644 (file)
@@ -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);
index bcc787ebbb252e029b83d1793e9d749a69b8b180..ee9c2d3ca6ec895574213589db91f09f70f2c447 100644 (file)
@@ -55,6 +55,7 @@ GlslCompiler::GlslCompiler(int argc, char **argv):
        vector<string> 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)