]> git.tdb.fi Git - libs/gl.git/blobdiff - source/glsl/finalize.cpp
Check the flat qualifier from the correct member
[libs/gl.git] / source / glsl / finalize.cpp
index 52cf95804245767ec1e487619313e87d66ee17dc..469cb92daba088493168f82f55e47a4b5938dccd 100644 (file)
@@ -72,10 +72,15 @@ void LocationAllocator::apply(Module &module, const Features &f, bool a)
        if(features.target_api!=VULKAN)
                allocate_locations("uniform");
 
-       for(InterfaceBlock *b: unbound_blocks)
-               bind_uniform(b->layout, b->block_name, features.uniform_binding_range);
+       for(VariableDeclaration *b: unbound_blocks)
+               bind_uniform(b->layout, b->block_declaration->block_name, features.uniform_binding_range);
        for(VariableDeclaration *t: unbound_textures)
-               bind_uniform(t->layout, t->name, features.texture_binding_range);
+       {
+               const TypeDeclaration *base_type = get_ultimate_base_type(t->type_declaration);
+               unsigned range = (static_cast<const ImageTypeDeclaration *>(base_type)->sampled ?
+                       features.texture_binding_range : features.storage_texture_binding_range);
+               bind_uniform(t->layout, t->name, range);
+       }
 }
 
 void LocationAllocator::apply(Stage &stage)
@@ -86,6 +91,8 @@ void LocationAllocator::apply(Stage &stage)
        stage.content.visit(*this);
 
        allocate_locations("in");
+       if(stage.type==Stage::VERTEX)
+               swap(used_locations["in"], used_vertex_attribs);
        allocate_locations("out");
 }
 
@@ -116,6 +123,8 @@ void LocationAllocator::allocate_locations(const string &iface)
                if(!alloc_new)
                        continue;
 
+               bool flat = ((*i)->interpolation=="flat" || ((*i)->linked_declaration && (*i)->linked_declaration->interpolation=="flat"));
+
                set<unsigned> &used = used_locations[(*i)->interface];
 
                unsigned size = LocationCounter().apply(**i);
@@ -123,7 +132,7 @@ void LocationAllocator::allocate_locations(const string &iface)
                {
                        int blocking = -1;
                        for(unsigned j=0; j<size; ++j)
-                               if(used.count(next+j))
+                               if(used.count(next+j) || (flat && used_vertex_attribs.count(next+j)))
                                        blocking = next+j;
                        if(blocking<0)
                                break;
@@ -168,12 +177,11 @@ void LocationAllocator::bind_uniform(RefPtr<Layout> &layout, const string &name,
 
 bool LocationAllocator::visit_uniform(const string &name, RefPtr<Layout> &layout)
 {
-       int desc_set = 0;
+       int desc_set = get_layout_value(layout.get(), "set");
        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;
@@ -183,6 +191,11 @@ bool LocationAllocator::visit_uniform(const string &name, RefPtr<Layout> &layout
                if(desc_set>=0)
                        uniforms[name].desc_set = desc_set;
        }
+       else if(desc_set>=0 && bind_point<0)
+       {
+               auto i = find_member(layout->qualifiers, string("set"), &Layout::Qualifier::name);
+               layout->qualifiers.erase(i);
+       }
 
        if(bind_point>=0)
        {
@@ -198,7 +211,7 @@ void LocationAllocator::visit(VariableDeclaration &var)
        if(!var.name.compare(0, 3, "gl_"))
                return;
 
-       if(!var.interface.empty())
+       if(!var.interface.empty() && !var.block_declaration)
        {
                int location = get_layout_value(var.layout.get(), "location");
 
@@ -223,22 +236,101 @@ void LocationAllocator::visit(VariableDeclaration &var)
 
        if(var.interface=="uniform")
        {
-               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(var.block_declaration)
+               {
+                       bool push_constant = has_layout_qualifier(var.layout.get(), "push_constant");
+                       if(!push_constant && !visit_uniform(var.block_declaration->block_name, var.layout))
+                               unbound_blocks.push_back(&var);
+               }
+               else
+               {
+                       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);
+               }
        }
 }
 
-void LocationAllocator::visit(InterfaceBlock &iface)
+
+void DepthRangeConverter::apply(Stage &stage, const Features &features)
 {
-       if(!iface.instance_name.compare(0, 3, "gl_"))
+       if(stage.type!=Stage::VERTEX || features.target_api==VULKAN)
                return;
 
-       if(iface.interface=="uniform")
+       stage.content.visit(*this);
+}
+
+void DepthRangeConverter::visit(VariableReference &var)
+{
+       const StructDeclaration *strct = dynamic_cast<const StructDeclaration *>(var.type);
+       r_gl_pervertex = (strct && strct->block_name=="gl_PerVertex");
+}
+
+void DepthRangeConverter::visit(MemberAccess &memacc)
+{
+       r_gl_pervertex = false;
+       memacc.left->visit(*this);
+       r_gl_position = (r_gl_pervertex && memacc.member=="gl_Position");
+}
+
+void DepthRangeConverter::visit(Swizzle &swiz)
+{
+       r_gl_position = false;
+       swiz.left->visit(*this);
+       if(assignment_target && r_gl_position && swiz.count==1 && swiz.components[0]==2)
+               r_position_z_assigned = true;
+}
+
+void DepthRangeConverter::visit(Assignment &assign)
+{
        {
-               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);
+               SetFlag set_target(assignment_target);
+               assign.left->visit(*this);
+       }
+       assign.right->visit(*this);
+}
+
+void DepthRangeConverter::visit(FunctionDeclaration &func)
+{
+       r_position_z_assigned = false;
+       TraversingVisitor::visit(func);
+
+       if(func.definition==&func && func.name=="main" && !r_position_z_assigned)
+       {
+               VariableReference *position = new VariableReference;
+               position->name = "gl_Position";
+
+               MemberAccess *z = new MemberAccess;
+               z->left = position;
+               z->member = "z";
+
+               Literal *scale = new Literal;
+               scale->token = "2.0";
+               scale->value = 2.0f;
+
+               BinaryExpression *multiply = new BinaryExpression;
+               multiply->oper = &Operator::get_operator("*", Operator::BINARY);
+               multiply->left = z;
+               multiply->right = scale;
+
+               MemberAccess *w = new MemberAccess;
+               w->left = position->clone();
+               w->member = "w";
+
+               BinaryExpression *subtract = new BinaryExpression;
+               subtract->oper = &Operator::get_operator("-", Operator::BINARY);
+               subtract->left = multiply;
+               subtract->right = w;
+
+               Assignment *assign = new Assignment;
+               assign->oper = &Operator::get_operator("=", Operator::BINARY);
+               assign->left = z->clone();
+               assign->right = subtract;
+
+               ExpressionStatement *statement = new ExpressionStatement;
+               statement->expression = assign;
+
+               func.body.body.push_back(statement);
        }
 }
 
@@ -383,24 +475,34 @@ void StructuralFeatureConverter::visit(RefPtr<Expression> &expr)
 
 bool StructuralFeatureConverter::supports_stage(Stage::Type st) const
 {
-       if(st==Stage::GEOMETRY)
+       if(st==Stage::TESS_CONTROL || st==Stage::TESS_EVAL)
+       {
+               if(features.target_api==OPENGL_ES)
+                       return check_version(Version(3, 20));
+               else
+                       return check_version(Version(4, 0));
+       }
+       else if(st==Stage::GEOMETRY)
        {
-               if(features.target_api==VULKAN)
-                       return true;
-               else if(features.target_api==OPENGL_ES)
+               if(features.target_api==OPENGL_ES)
                        return check_version(Version(3, 20));
                else
                        return check_version(Version(1, 50));
        }
+       else if(st==Stage::COMPUTE)
+       {
+               if(features.target_api==OPENGL_ES)
+                       return check_version(Version(3, 10));
+               else
+                       return check_version(Version(4, 30));
+       }
        else
                return true;
 }
 
 bool StructuralFeatureConverter::supports_unified_interface_syntax() const
 {
-       if(features.target_api==VULKAN)
-               return true;
-       else if(features.target_api==OPENGL_ES)
+       if(features.target_api==OPENGL_ES)
                return check_version(Version(3, 0));
        else
                return check_version(Version(1, 30));
@@ -413,11 +515,8 @@ void StructuralFeatureConverter::visit(VariableReference &var)
                var.name = "gl_FragColor";
                var.declaration = 0;
        }
-}
 
-void StructuralFeatureConverter::visit(InterfaceBlockReference &iface)
-{
-       r_flattened_interface = nodes_to_remove.count(iface.declaration);
+       r_flattened_interface = nodes_to_remove.count(var.declaration);
 }
 
 void StructuralFeatureConverter::visit(MemberAccess &memacc)
@@ -441,9 +540,7 @@ void StructuralFeatureConverter::visit(Assignment &assign)
 
 bool StructuralFeatureConverter::supports_unified_sampling_functions() const
 {
-       if(features.target_api==VULKAN)
-               return true;
-       else if(features.target_api==OPENGL_ES)
+       if(features.target_api==OPENGL_ES)
                return check_version(Version(3, 0));
        else
                return check_version(Version(1, 30));
@@ -486,23 +583,9 @@ void StructuralFeatureConverter::visit(FunctionCall &call)
        TraversingVisitor::visit(call);
 }
 
-void StructuralFeatureConverter::visit(VariableDeclaration &var)
-{
-       if((var.interface=="in" || var.interface=="out") && !supports_unified_interface_syntax())
-               if(stage->type==Stage::FRAGMENT && var.interface=="out")
-               {
-                       frag_out = &var;
-                       nodes_to_remove.insert(&var);
-               }
-
-       TraversingVisitor::visit(var);
-}
-
 bool StructuralFeatureConverter::supports_interface_blocks(const string &iface) const
 {
-       if(features.target_api==VULKAN)
-               return true;
-       else if(features.target_api==OPENGL_ES)
+       if(features.target_api==OPENGL_ES)
        {
                if(iface=="uniform")
                        return check_version(Version(3, 0));
@@ -517,27 +600,35 @@ bool StructuralFeatureConverter::supports_interface_blocks(const string &iface)
                return false;
 }
 
-void StructuralFeatureConverter::visit(InterfaceBlock &iface)
+void StructuralFeatureConverter::visit(VariableDeclaration &var)
 {
-       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(var.block_declaration)
        {
-               if(!iface.instance_name.empty())
-                       unsupported("ARB_uniform_buffer_object required for interface block instances");
-               else if(iface.struct_declaration)
+               bool push_constant = has_layout_qualifier(var.layout.get(), "push_constant");
+               if(!supports_interface_blocks(var.interface) || (push_constant && features.target_api!=VULKAN))
                {
-                       for(const RefPtr<Statement> &s: iface.struct_declaration->members.body)
-                               if(VariableDeclaration *var = dynamic_cast<VariableDeclaration *>(s.get()))
-                                       var->interface = iface.interface;
-                       stage->content.body.splice(uniform_insert_point, iface.struct_declaration->members.body);
-                       nodes_to_remove.insert(&iface);
-                       nodes_to_remove.insert(iface.struct_declaration);
+                       if(var.name.find(' ')==string::npos)
+                               unsupported("ARB_uniform_buffer_object required for interface block instances");
+                       else
+                       {
+                               for(const RefPtr<Statement> &s: var.block_declaration->members.body)
+                                       if(VariableDeclaration *mem = dynamic_cast<VariableDeclaration *>(s.get()))
+                                               mem->interface = var.interface;
+                               stage->content.body.splice(uniform_insert_point, var.block_declaration->members.body);
+                               nodes_to_remove.insert(&var);
+                               nodes_to_remove.insert(var.block_declaration);
+                       }
                }
-               else
-                       /* If the interface block is an array, it should have an instance
-                       name too, so this should never be reached */
-                       throw logic_error("Unexpected interface block configuration");
        }
+
+       if((var.interface=="in" || var.interface=="out") && !supports_unified_interface_syntax())
+               if(stage->type==Stage::FRAGMENT && var.interface=="out")
+               {
+                       frag_out = &var;
+                       nodes_to_remove.insert(&var);
+               }
+
+       TraversingVisitor::visit(var);
 }
 
 
@@ -548,9 +639,7 @@ void QualifierConverter::apply()
 
 bool QualifierConverter::supports_interface_layouts() const
 {
-       if(features.target_api==VULKAN)
-               return true;
-       else if(features.target_api==OPENGL_ES)
+       if(features.target_api==OPENGL_ES)
                return check_version(Version(3, 0));
        else if(check_version(Version(3, 30)))
                return true;
@@ -562,9 +651,7 @@ bool QualifierConverter::supports_interface_layouts() const
 
 bool QualifierConverter::supports_stage_interface_layouts() const
 {
-       if(features.target_api==VULKAN)
-               return true;
-       else if(features.target_api==OPENGL_ES)
+       if(features.target_api==OPENGL_ES)
                return check_version(Version(3, 10));
        else if(check_version(Version(4, 10)))
                return true;
@@ -574,9 +661,7 @@ bool QualifierConverter::supports_stage_interface_layouts() const
 
 bool QualifierConverter::supports_centroid_sampling() const
 {
-       if(features.target_api==VULKAN)
-               return true;
-       else if(features.target_api==OPENGL_ES)
+       if(features.target_api==OPENGL_ES)
                return check_version(Version(3, 0));
        else if(check_version(Version(1, 20)))
                return true;
@@ -586,9 +671,7 @@ bool QualifierConverter::supports_centroid_sampling() const
 
 bool QualifierConverter::supports_sample_sampling() const
 {
-       if(features.target_api==VULKAN)
-               return true;
-       else if(features.target_api==OPENGL_ES)
+       if(features.target_api==OPENGL_ES)
                return check_version(Version(3, 20));
        else if(check_version(Version(4, 0)))
                return true;
@@ -598,9 +681,7 @@ bool QualifierConverter::supports_sample_sampling() const
 
 bool QualifierConverter::supports_uniform_location() const
 {
-       if(features.target_api==VULKAN)
-               return true;
-       else if(features.target_api==OPENGL_ES)
+       if(features.target_api==OPENGL_ES)
                return check_version(Version(3, 10));
        else if(check_version(Version(4, 30)))
                return true;
@@ -610,14 +691,22 @@ bool QualifierConverter::supports_uniform_location() const
 
 bool QualifierConverter::supports_binding() const
 {
-       if(features.target_api==VULKAN)
-               return true;
-       else if(features.target_api==OPENGL_ES)
+       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)
+               return check_version(Version(3, 20));
+       else if(check_version(Version(4, 40)))
+               return true;
+       else
+               return check_extension(&Features::arb_enhanced_layouts);
+}
+
 void QualifierConverter::visit(VariableDeclaration &var)
 {
        if(var.layout)
@@ -628,7 +717,9 @@ void QualifierConverter::visit(VariableDeclaration &var)
                        {
                                bool supported = true;
                                bool external = false;
-                               if(var.interface=="in")
+                               if(var.block_declaration)
+                                       supported = supports_interface_block_location();
+                               else if(var.interface=="in")
                                {
                                        external = (stage->type==Stage::VERTEX);
                                        supported = (external ? supports_interface_layouts() : supports_stage_interface_layouts());
@@ -658,7 +749,9 @@ void QualifierConverter::visit(VariableDeclaration &var)
                        }
                        else if(i->name=="binding" && !supports_binding())
                        {
-                               if(dynamic_cast<const ImageTypeDeclaration *>(get_ultimate_base_type(var.type_declaration)))
+                               if(var.block_declaration)
+                                       stage->uniform_block_bindings[var.block_declaration->block_name] = i->value;
+                               else 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);
@@ -689,40 +782,6 @@ void QualifierConverter::visit(VariableDeclaration &var)
        TraversingVisitor::visit(var);
 }
 
-bool QualifierConverter::supports_interface_block_location() const
-{
-       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;
-       else
-               return check_extension(&Features::arb_enhanced_layouts);
-}
-
-void QualifierConverter::visit(InterfaceBlock &iface)
-{
-       if(iface.layout)
-       {
-               for(auto i=iface.layout->qualifiers.begin(); i!=iface.layout->qualifiers.end(); )
-               {
-                       if(i->name=="location" && !supports_interface_block_location())
-                               i = iface.layout->qualifiers.erase(i);
-                       else if(i->name=="binding" && !supports_binding())
-                       {
-                               stage->uniform_block_bindings[iface.block_name] = i->value;
-                               i = iface.layout->qualifiers.erase(i);
-                       }
-                       else
-                               ++i;
-               }
-
-               if(iface.layout->qualifiers.empty())
-                       iface.layout = 0;
-       }
-}
-
 } // namespace SL
 } // namespace GL
 } // namespace Msp