]> git.tdb.fi Git - libs/gl.git/blobdiff - source/glsl/optimize.cpp
Also break up arrays which are only indexed by constants
[libs/gl.git] / source / glsl / optimize.cpp
index 768cfd5dc761659f504011780e3e0cbc74f90c0d..42e4a86ec7feb3466f7e0a119b4bf1a4feb28916 100644 (file)
@@ -532,11 +532,19 @@ bool AggregateDismantler::apply(Stage &stage)
 
                for(const AggregateMember &m: kvp.second.members)
                {
+                       string name;
+                       if(m.declaration)
+                               name = format("%s_%s", kvp.second.declaration->name, m.declaration->name);
+                       else
+                               name = format("%s_%d", kvp.second.declaration->name, m.index);
+
                        VariableDeclaration *var = new VariableDeclaration;
                        var->source = kvp.first->source;
                        var->line = kvp.first->line;
-                       var->name = get_unused_variable_name(*kvp.second.decl_scope, format("%s_%s", kvp.second.declaration->name, m.declaration->name));
-                       var->type = m.declaration->type;
+                       var->name = get_unused_variable_name(*kvp.second.decl_scope, name);
+                       /* XXX This is kind of brittle and depends on the array declaration's
+                       textual type not having brackets in it. */
+                       var->type = (m.declaration ? m.declaration : kvp.second.declaration)->type;
                        if(m.initializer)
                                var->init_expression = m.initializer->clone();
 
@@ -570,10 +578,17 @@ void AggregateDismantler::visit(RefPtr<Expression> &expr)
 {
        r_aggregate_ref = 0;
        expr->visit(*this);
-       if(r_aggregate_ref && r_reference.chain_len==1 && (r_reference.chain[0]&0x3F)!=0x3F)
+       if(r_aggregate_ref && r_reference.chain_len==1)
        {
-               r_aggregate_ref->members[r_reference.chain[0]&0x3F].references.push_back(&expr);
-               r_aggregate_ref->members_referenced = true;
+               if((r_reference.chain[0]&0x3F)!=0x3F)
+               {
+                       r_aggregate_ref->members[r_reference.chain[0]&0x3F].references.push_back(&expr);
+                       r_aggregate_ref->members_referenced = true;
+               }
+               else
+                       /* If the accessed member is not known, mark the entire aggregate as
+                       referenced. */
+                       r_aggregate_ref->referenced = true;
        }
        r_aggregate_ref = 0;
 }
@@ -584,6 +599,8 @@ void AggregateDismantler::visit(VariableReference &var)
                r_reference.declaration = var.declaration;
        else
        {
+               /* If an aggregate variable is referenced as a whole, it should not be
+               dismantled. */
                auto i = aggregates.find(var.declaration);
                if(i!=aggregates.end())
                        i->second.referenced = true;
@@ -624,7 +641,19 @@ void AggregateDismantler::visit(BinaryExpression &binary)
                        visit(binary.right);
                }
 
-               add_to_chain(r_reference, Assignment::Target::ARRAY, 0x3F);
+               unsigned index = 0x3F;
+               if(Literal *literal_subscript = dynamic_cast<Literal *>(binary.right.get()))
+                       if(literal_subscript->value.check_type<int>())
+                               index = literal_subscript->value.value<int>();
+               add_to_chain(r_reference, Assignment::Target::ARRAY, index);
+
+               if(r_reference.declaration && r_reference.chain_len==1)
+               {
+                       auto i = aggregates.find(r_reference.declaration);
+                       r_aggregate_ref = (i!=aggregates.end() ? &i->second : 0);
+               }
+               else
+                       r_aggregate_ref = 0;
        }
        else
        {
@@ -638,6 +667,7 @@ void AggregateDismantler::visit(VariableDeclaration &var)
        TraversingVisitor::visit(var);
 
        if(var.interface.empty())
+       {
                if(const StructDeclaration *strct = dynamic_cast<const StructDeclaration *>(var.type_declaration))
                {
                        const FunctionCall *init_call = dynamic_cast<const FunctionCall *>(var.init_expression.get());
@@ -656,6 +686,7 @@ void AggregateDismantler::visit(VariableDeclaration &var)
                                        {
                                                AggregateMember member;
                                                member.declaration = mem_decl;
+                                               member.index = i;
                                                if(init_call)
                                                        member.initializer = init_call->arguments[i];
                                                aggre.members.push_back(member);
@@ -664,6 +695,26 @@ void AggregateDismantler::visit(VariableDeclaration &var)
                                }
                        }
                }
+               else if(const Literal *literal_size = dynamic_cast<const Literal *>(var.array_size.get()))
+               {
+                       if(literal_size->value.check_type<int>())
+                       {
+                               Aggregate &aggre = aggregates[&var];
+                               aggre.declaration = &var;
+                               aggre.decl_scope = current_block;
+                               aggre.insert_point = insert_point;
+
+                               int size = literal_size->value.value<int>();
+                               for(int i=0; i<size; ++i)
+                               {
+                                       AggregateMember member;
+                                       member.index = i;
+                                       // Array initializers are not supported yet
+                                       aggre.members.push_back(member);
+                               }
+                       }
+               }
+       }
 }