]> git.tdb.fi Git - libs/gl.git/blobdiff - source/glsl/spirv.cpp
Use extended alignment in SPIR-V struct layout when necessary
[libs/gl.git] / source / glsl / spirv.cpp
index 2dcc285c624a2806dab80d3a6e487783138f732f..07d4eb072c0989eb1745405aae0c85ea2ae59fc7 100644 (file)
@@ -135,8 +135,9 @@ SpirVGenerator::SpirVGenerator():
        writer(content)
 { }
 
-void SpirVGenerator::apply(Module &module)
+void SpirVGenerator::apply(Module &module, const Features &f)
 {
+       features = f;
        use_capability(CAP_SHADER);
 
        for(Stage &s: module.stages)
@@ -337,10 +338,10 @@ bool SpirVGenerator::is_scalar_type(Id type_id, BasicTypeDeclaration::Kind kind)
        return (i!=standard_type_ids.end() && i->second==type_id);
 }
 
-SpirVGenerator::Id SpirVGenerator::get_array_type_id(TypeDeclaration &base_type, Id size_id)
+SpirVGenerator::Id SpirVGenerator::get_array_type_id(TypeDeclaration &base_type, Id size_id, bool extended_align)
 {
        Id base_type_id = get_id(base_type);
-       Id &array_type_id = array_type_ids[TypeKey(base_type_id, size_id)];
+       Id &array_type_id = array_type_ids[TypeKey(base_type_id, extended_align*0x400000 | size_id)];
        if(!array_type_id)
        {
                array_type_id = next_id++;
@@ -350,6 +351,8 @@ SpirVGenerator::Id SpirVGenerator::get_array_type_id(TypeDeclaration &base_type,
                        writer.write_op(content.globals, OP_TYPE_RUNTIME_ARRAY, array_type_id, base_type_id);
 
                unsigned stride = MemoryRequirementsCalculator().apply(base_type).stride;
+               if(extended_align)
+                       stride = (stride+15)&~15U;
                writer.write_op_decorate(array_type_id, DECO_ARRAY_STRIDE, stride);
        }
 
@@ -382,7 +385,7 @@ SpirVGenerator::Id SpirVGenerator::get_variable_type_id(const VariableDeclaratio
                        }
                        else
                                size_id = get_constant_id(get_standard_type_id(BasicTypeDeclaration::INT, 1), 1);
-                       return get_array_type_id(*basic->base_type, size_id);
+                       return get_array_type_id(*basic->base_type, size_id, true);
                }
 
        return get_id(*var.type_declaration);
@@ -690,6 +693,9 @@ void SpirVGenerator::visit(Swizzle &swizzle)
 
 void SpirVGenerator::visit(UnaryExpression &unary)
 {
+       if(composite_access)
+               return visit_isolated(unary);
+
        unary.expression->visit(*this);
 
        char oper = unary.oper->token[0];
@@ -774,6 +780,8 @@ void SpirVGenerator::visit(BinaryExpression &binary)
                visit_isolated(*binary.right);
                return visit_composite(*binary.left, 0x400000|r_expression_result_id, *binary.type);
        }
+       else if(composite_access)
+               return visit_isolated(binary);
 
        if(assignment_source_id)
                throw internal_error("invalid binary expression in assignment target");
@@ -998,6 +1006,8 @@ void SpirVGenerator::visit(Assignment &assign)
 
 void SpirVGenerator::visit(TernaryExpression &ternary)
 {
+       if(composite_access)
+               return visit_isolated(ternary);
        if(constant_expression)
        {
                ternary.condition->visit(*this);
@@ -1575,16 +1585,6 @@ void SpirVGenerator::visit(StructDeclaration &strct)
 
 void SpirVGenerator::visit(VariableDeclaration &var)
 {
-       const vector<Layout::Qualifier> *layout_ql = (var.layout ? &var.layout->qualifiers : 0);
-
-       int spec_id = -1;
-       if(layout_ql)
-       {
-               auto i = find_member(*layout_ql, string("constant_id"), &Layout::Qualifier::name);
-               if(i!=layout_ql->end())
-                       spec_id = i->value;
-       }
-
        Id type_id = get_variable_type_id(var);
        Id var_id;
 
@@ -1593,18 +1593,25 @@ void SpirVGenerator::visit(VariableDeclaration &var)
                if(!var.init_expression)
                        throw internal_error("const variable without initializer");
 
+               int spec_id = get_layout_value(var.layout.get(), "constant_id");
+               Id *spec_var_id = (spec_id>=0 ? &declared_spec_ids[spec_id] : 0);
+               if(spec_id>=0 && *spec_var_id)
+               {
+                       insert_unique(declared_ids, &var, Declaration(*spec_var_id, type_id));
+                       return;
+               }
+
                SetFlag set_const(constant_expression);
                SetFlag set_spec(spec_constant, spec_id>=0);
                r_expression_result_id = 0;
                var.init_expression->visit(*this);
                var_id = r_expression_result_id;
                insert_unique(declared_ids, &var, Declaration(var_id, type_id));
-               writer.write_op_decorate(var_id, DECO_SPEC_ID, spec_id);
-
-               /* It's unclear what should be done if a specialization constant is
-               initialized with anything other than a literal.  GLSL doesn't seem to
-               prohibit that but SPIR-V says OpSpecConstantOp can't be updated via
-               specialization. */
+               if(spec_id>=0)
+               {
+                       writer.write_op_decorate(var_id, DECO_SPEC_ID, spec_id);
+                       *spec_var_id = var_id;
+               }
        }
        else
        {
@@ -1643,9 +1650,9 @@ void SpirVGenerator::visit(VariableDeclaration &var)
                        writer.write(init_id);
                writer.end_op(OP_VARIABLE);
 
-               if(layout_ql)
+               if(var.layout)
                {
-                       for(const Layout::Qualifier &q: *layout_ql)
+                       for(const Layout::Qualifier &q: var.layout->qualifiers)
                        {
                                if(q.name=="location")
                                        writer.write_op_decorate(var_id, DECO_LOCATION, q.value);
@@ -1673,10 +1680,12 @@ void SpirVGenerator::visit(VariableDeclaration &var)
 
 void SpirVGenerator::visit(InterfaceBlock &iface)
 {
-       StorageClass storage = get_interface_storage(iface.interface, true);
+       bool push_const = has_layout_qualifier(iface.layout.get(), "push_constant");
+
+       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);
+               type_id = get_array_type_id(*iface.struct_declaration, 0, true);
        else
                type_id = get_id(*iface.struct_declaration);
        Id ptr_type_id = get_pointer_type_id(type_id, storage);
@@ -1701,9 +1710,13 @@ void SpirVGenerator::visit(InterfaceBlock &iface)
 
        if(iface.layout)
        {
-               auto i = find_member(iface.layout->qualifiers, string("binding"), &Layout::Qualifier::name);
-               if(i!=iface.layout->qualifiers.end())
-                       writer.write_op_decorate(block_id, DECO_BINDING, i->value);
+               for(const Layout::Qualifier &q: iface.layout->qualifiers)
+               {
+                       if(q.name=="set")
+                               writer.write_op_decorate(block_id, DECO_DESCRIPTOR_SET, q.value);
+                       else if(q.name=="binding")
+                               writer.write_op_decorate(block_id, DECO_BINDING, q.value);
+               }
        }
 }
 
@@ -1735,7 +1748,10 @@ void SpirVGenerator::visit_entry_point(FunctionDeclaration &func, Id func_id)
        writer.end_op(OP_ENTRY_POINT);
 
        if(stage->type==Stage::FRAGMENT)
-               writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_ORIGIN_LOWER_LEFT);
+       {
+               SpirVExecutionMode origin = (features.target_api==VULKAN ? EXEC_ORIGIN_UPPER_LEFT : EXEC_ORIGIN_LOWER_LEFT);
+               writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, origin);
+       }
        else if(stage->type==Stage::GEOMETRY)
                use_capability(CAP_GEOMETRY);
 
@@ -1849,6 +1865,8 @@ void SpirVGenerator::visit(Conditional &cond)
        writer.write_op(content.function_body, OP_SELECTION_MERGE, merge_block_id, 0);  // Selection control (none)
        writer.write_op(content.function_body, OP_BRANCH_CONDITIONAL, r_expression_result_id, true_label_id, false_label_id);
 
+       std::map<const VariableDeclaration *, Id> saved_load_ids = variable_load_ids;
+
        writer.write_op_label(true_label_id);
        cond.body.visit(*this);
        if(writer.get_current_block())
@@ -1859,6 +1877,7 @@ void SpirVGenerator::visit(Conditional &cond)
        reachable = true;
        if(!cond.else_body.body.empty())
        {
+               swap(saved_load_ids, variable_load_ids);
                writer.write_op_label(false_label_id);
                cond.else_body.visit(*this);
                reachable |= reachable_if_true;