]> git.tdb.fi Git - libs/gl.git/blobdiff - source/glsl/optimize.cpp
Comments and cosmetic cleanups
[libs/gl.git] / source / glsl / optimize.cpp
index 0d428149dcc667ca6a7990c5d760a9ca22ea9aee..596d7e20b071365850cb8d3e894b6eb0db910c1b 100644 (file)
@@ -8,6 +8,55 @@ namespace Msp {
 namespace GL {
 namespace SL {
 
+ConstantSpecializer::ConstantSpecializer():
+       values(0)
+{ }
+
+void ConstantSpecializer::apply(Stage &stage, const map<string, int> &v)
+{
+       values = &v;
+       stage.content.visit(*this);
+}
+
+void ConstantSpecializer::visit(VariableDeclaration &var)
+{
+       bool specializable = false;
+       if(var.layout)
+       {
+               vector<Layout::Qualifier> &qualifiers = var.layout->qualifiers;
+               for(vector<Layout::Qualifier>::iterator i=qualifiers.begin(); (!specializable && i!=qualifiers.end()); ++i)
+                       if(i->name=="constant_id")
+                       {
+                               specializable = true;
+                               qualifiers.erase(i);
+                       }
+
+               if(qualifiers.empty())
+                       var.layout = 0;
+       }
+
+       if(specializable)
+       {
+               map<string, int>::const_iterator i = values->find(var.name);
+               if(i!=values->end())
+               {
+                       RefPtr<Literal> literal = new Literal;
+                       if(var.type=="bool")
+                       {
+                               literal->token = (i->second ? "true" : "false");
+                               literal->value = static_cast<bool>(i->second);
+                       }
+                       else if(var.type=="int")
+                       {
+                               literal->token = lexical_cast<string>(i->second);
+                               literal->value = i->second;
+                       }
+                       var.init_expression = literal;
+               }
+       }
+}
+
+
 InlineableFunctionLocator::InlineableFunctionLocator():
        current_function(0),
        return_count(0)
@@ -34,8 +83,12 @@ void InlineableFunctionLocator::visit(FunctionCall &call)
 
 void InlineableFunctionLocator::visit(FunctionDeclaration &func)
 {
+       bool has_out_params = false;
+       for(NodeArray<VariableDeclaration>::const_iterator i=func.parameters.begin(); (!has_out_params && i!=func.parameters.end()); ++i)
+               has_out_params = ((*i)->interface=="out");
+
        unsigned &count = refcounts[func.definition];
-       if(count<=1 && func.parameters.empty())
+       if(count<=1 && !has_out_params)
                inlineable.insert(func.definition);
 
        SetForScope<FunctionDeclaration *> set(current_function, &func);
@@ -69,9 +122,9 @@ InlineContentInjector::InlineContentInjector():
        pass(DEPENDS)
 { }
 
-const string &InlineContentInjector::apply(Stage &stage, FunctionDeclaration &target_func, Block &tgt_blk, const NodeList<Statement>::iterator &ins_pt, FunctionDeclaration &src)
+const string &InlineContentInjector::apply(Stage &stage, FunctionDeclaration &target_func, Block &tgt_blk, const NodeList<Statement>::iterator &ins_pt, FunctionCall &call)
 {
-       source_func = &src;
+       source_func = call.declaration->definition;
 
        // Collect all declarations the inlined function depends on.
        pass = DEPENDS;
@@ -87,9 +140,22 @@ const string &InlineContentInjector::apply(Stage &stage, FunctionDeclaration &ta
        pass = INLINE;
        staging_block.parent = &tgt_blk;
        staging_block.variables.clear();
-       remap_prefix = source_func->name;
 
-       for(NodeList<Statement>::iterator i=src.body.body.begin(); i!=src.body.body.end(); ++i)
+       std::vector<RefPtr<VariableDeclaration> > params;
+       params.reserve(source_func->parameters.size());
+       for(NodeArray<VariableDeclaration>::iterator i=source_func->parameters.begin(); i!=source_func->parameters.end(); ++i)
+       {
+               RefPtr<VariableDeclaration> var = (*i)->clone();
+               var->interface.clear();
+
+               SetForScope<Pass> set_pass(pass, RENAME);
+               var->visit(*this);
+
+               staging_block.body.push_back_nocopy(var);
+               params.push_back(var);
+       }
+
+       for(NodeList<Statement>::iterator i=source_func->body.body.begin(); i!=source_func->body.body.end(); ++i)
        {
                r_inlined_statement = 0;
                (*i)->visit(*this);
@@ -99,8 +165,7 @@ const string &InlineContentInjector::apply(Stage &stage, FunctionDeclaration &ta
                SetForScope<Pass> set_pass(pass, RENAME);
                r_inlined_statement->visit(*this);
 
-               staging_block.body.push_back(0);
-               staging_block.body.back() = r_inlined_statement;
+               staging_block.body.push_back_nocopy(r_inlined_statement);
        }
 
        /* Now collect names from the staging block.  Local variables that would
@@ -114,9 +179,12 @@ const string &InlineContentInjector::apply(Stage &stage, FunctionDeclaration &ta
        global identifiers used by the source function. */
        pass = RENAME;
        staging_block.parent = source_func->body.parent;
-       remap_prefix = target_func.name;
        target_func.visit(*this);
 
+       // Put the argument expressions in place after all renaming has been done.
+       for(unsigned i=0; i<source_func->parameters.size(); ++i)
+               params[i]->init_expression = call.arguments[i]->clone();
+
        tgt_blk.body.splice(ins_pt, staging_block.body);
 
        NodeReorderer().apply(stage, target_func, dependencies);
@@ -167,10 +235,13 @@ void InlineContentInjector::visit(VariableDeclaration &var)
 
        if(pass==RENAME)
        {
+               /* Check against conflicts with the other context as well as variables
+               already renamed here. */
+               bool conflict = (staging_block.variables.count(var.name) || referenced_names.count(var.name));
                staging_block.variables[var.name] = &var;
-               if(referenced_names.count(var.name))
+               if(conflict)
                {
-                       string mapped_name = get_unused_variable_name(staging_block, var.name, remap_prefix);
+                       string mapped_name = get_unused_variable_name(staging_block, var.name);
                        if(mapped_name!=var.name)
                        {
                                staging_block.variables[mapped_name] = &var;
@@ -194,7 +265,7 @@ void InlineContentInjector::visit(Return &ret)
        if(pass==INLINE && ret.expression)
        {
                // Create a new variable to hold the return value of the inlined function.
-               r_result_name = get_unused_variable_name(staging_block, "_return", source_func->name);
+               r_result_name = get_unused_variable_name(staging_block, "_return");
                RefPtr<VariableDeclaration> var = new VariableDeclaration;
                var->source = ret.source;
                var->line = ret.line;
@@ -246,23 +317,23 @@ void FunctionInliner::visit(Block &block)
 
 void FunctionInliner::visit(FunctionCall &call)
 {
+       for(NodeArray<Expression>::iterator i=call.arguments.begin(); (!r_inlined_here && i!=call.arguments.end()); ++i)
+               visit(*i);
+
        if(r_inlined_here)
                return;
 
-       for(NodeArray<Expression>::iterator i=call.arguments.begin(); i!=call.arguments.end(); ++i)
-               visit(*i);
-
        FunctionDeclaration *def = call.declaration;
        if(def)
                def = def->definition;
 
        if(def && inlineable.count(def))
        {
-               string result_name = InlineContentInjector().apply(*stage, *current_function, *current_block, insert_point, *def);
+               string result_name = InlineContentInjector().apply(*stage, *current_function, *current_block, insert_point, call);
 
                // This will later get removed by UnusedVariableRemover.
                if(result_name.empty())
-                       result_name = "msp_unused_from_inline";
+                       result_name = "_msp_unused_from_inline";
 
                RefPtr<VariableReference> ref = new VariableReference;
                ref->name = result_name;
@@ -1097,7 +1168,7 @@ void UnusedVariableRemover::visit(VariableDeclaration &var)
        /* Mark variables as output if they're used by the next stage or the
        graphics API. */
        if(interface_block)
-               var_info.output = (interface_block->interface=="out" && (interface_block->linked_block || !interface_block->name.compare(0, 3, "gl_")));
+               var_info.output = (interface_block->interface=="out" && (interface_block->linked_block || !interface_block->block_name.compare(0, 3, "gl_")));
        else
                var_info.output = (var.interface=="out" && (stage->type==Stage::FRAGMENT || var.linked_declaration || !var.name.compare(0, 3, "gl_")));
 
@@ -1119,7 +1190,7 @@ void UnusedVariableRemover::visit(InterfaceBlock &iface)
        else
        {
                VariableInfo &var_info = variables[&iface];
-               var_info.output = (iface.interface=="out" && (iface.linked_block || !iface.name.compare(0, 3, "gl_")));
+               var_info.output = (iface.interface=="out" && (iface.linked_block || !iface.block_name.compare(0, 3, "gl_")));
        }
 }