]> git.tdb.fi Git - libs/gl.git/commitdiff
Support inlining GLSL functions with parameters
authorMikko Rasa <tdb@tdb.fi>
Tue, 16 Mar 2021 16:51:34 +0000 (18:51 +0200)
committerMikko Rasa <tdb@tdb.fi>
Tue, 16 Mar 2021 16:58:04 +0000 (18:58 +0200)
source/glsl/optimize.cpp
source/glsl/optimize.h
tests/glsl/function_arguments_inline.glsl [new file with mode: 0644]
tests/glsl/function_overloading.glsl

index 0d428149dcc667ca6a7990c5d760a9ca22ea9aee..7d605f1f12bc755812a3252172828a84d3720777 100644 (file)
@@ -34,8 +34,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 +73,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;
@@ -89,7 +93,22 @@ const string &InlineContentInjector::apply(Stage &stage, FunctionDeclaration &ta
        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(0);
+               staging_block.body.back() = 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);
@@ -117,6 +136,10 @@ const string &InlineContentInjector::apply(Stage &stage, FunctionDeclaration &ta
        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);
@@ -258,7 +281,7 @@ void FunctionInliner::visit(FunctionCall &call)
 
        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())
index f6604743810ff1e275198ee554badcd53a75ffa2..6d4b1bcb5d2c2e5d883d7ab640390481c8c7e84e 100644 (file)
@@ -10,8 +10,8 @@ namespace GL {
 namespace SL {
 
 /** Finds functions which are candidates for inlining.  Currently this means
-functions which have no parameters, contain no more than one return statement,
-and are only called once. */
+functions which have no flow control statements, no more than one return
+statement, and are only called once. */
 class InlineableFunctionLocator: private TraversingVisitor
 {
 private:
@@ -59,7 +59,7 @@ private:
 public:
        InlineContentInjector();
 
-       const std::string &apply(Stage &, FunctionDeclaration &, Block &, const NodeList<Statement>::iterator &, FunctionDeclaration &);
+       const std::string &apply(Stage &, FunctionDeclaration &, Block &, const NodeList<Statement>::iterator &, FunctionCall &);
 
 private:
        virtual void visit(VariableReference &);
diff --git a/tests/glsl/function_arguments_inline.glsl b/tests/glsl/function_arguments_inline.glsl
new file mode 100644 (file)
index 0000000..f9946c9
--- /dev/null
@@ -0,0 +1,21 @@
+uniform mat4 mvp;
+
+#pragma MSP stage(vertex)
+layout(location=0) in vec4 position;
+vec4 transform_position(vec4 p)
+{
+       return mvp*p;
+}
+void main()
+{
+       gl_Position = transform_position(position);
+}
+
+/* Expected output: vertex
+uniform mat4 mvp;
+layout(location=0) in vec4 position;
+void main()
+{
+       gl_Position = mvp*position;
+}
+*/
index 636db5112c6fde119672e6e9c3d321e2be40b986..f74a793ba47ab0821180f0ee779d4d2a77daf984 100644 (file)
@@ -43,18 +43,12 @@ void main()
 
 /* Expected output: fragment
 uniform sampler2D tex;
-vec3 srgb_to_linear(vec3 color)
-{
-  return mix(color.rgb/12.92, pow((color.rgb+0.055)/1.055, vec3(2.4)), lessThan(color, vec3(0.04045)));
-}
-vec4 srgb_to_linear(vec4 color)
-{
-  return vec4(srgb_to_linear(color.rgb), color.a);
-}
 layout(location=0) out vec4 frag_color;
 in vec2 _vs_out_texcoord;
 void main()
 {
-  frag_color = srgb_to_linear(texture(tex, _vs_out_texcoord));
+       vec4 color = texture(tex, _vs_out_texcoord);
+       vec3 _srgb_to_linear_color = color.rgb;
+       frag_color = vec4(mix(_srgb_to_linear_color.rgb/12.92, pow((_srgb_to_linear_color.rgb+0.055)/1.055, vec3(2.4)), lessThan(_srgb_to_linear_color, vec3(0.04045))), color.a);
 }
 */