From 83bfb4bc26cf20cada1fcda47064b75d8e49fa08 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Thu, 30 Aug 2012 22:01:55 +0300 Subject: [PATCH] Shader optimization ProgramBuilder can now collapse variables with only one reference into the expression using it. Fragment color expressions were tuned as well. --- source/programbuilder.cpp | 81 ++++++++++++++++++++++++++++++++------- source/programbuilder.h | 5 +++ 2 files changed, 72 insertions(+), 14 deletions(-) diff --git a/source/programbuilder.cpp b/source/programbuilder.cpp index 1e07c1e5..05e801c7 100644 --- a/source/programbuilder.cpp +++ b/source/programbuilder.cpp @@ -38,16 +38,17 @@ anything that might need them. */ const ProgramBuilder::StandardVariable ProgramBuilder::standard_variables[] = { { FRAGMENT, "gl_FragColor", 0, "color_base", "!t" }, - { FRAGMENT, "gl_FragColor", 0, "tex_sample*color_base", "t" }, - { FRAGMENT, "color_base", "vec4", "color_unlit", "!l!s" }, - { FRAGMENT, "color_base", "vec4", "color_unlit*vec4(vec3(l_shadow), 1.0)", "!ls" }, + { FRAGMENT, "gl_FragColor", 0, "tex_sample", "!l!s!mt" }, + { FRAGMENT, "gl_FragColor", 0, "tex_sample*color_base", "l|s|mt" }, + { FRAGMENT, "color_base", "vec4", "vec4(1.0)", "!l!s!m" }, + { FRAGMENT, "color_base", "vec4", "color", "!l!sm" }, + { FRAGMENT, "color_base", "vec4", "vec4(vec3(l_shadow), 1.0)", "!ls!m" }, + { FRAGMENT, "color_base", "vec4", "color*vec4(vec3(l_shadow), 1.0)", "!lsm" }, { FRAGMENT, "color_base", "vec4", "vec4(rgb_light_full, 1.0)", "l!m" }, { FRAGMENT, "color_base", "vec4", "vec4(rgb_light_full, gl_FrontMaterial.diffuse.a)", "lm" }, - { FRAGMENT, "color_unlit", "vec4", "vec4(1.0)", "!m" }, - { FRAGMENT, "color_unlit", "vec4", "color", "m" }, { FRAGMENT, "rgb_light_full", "vec3", "rgb_light_shadow+gl_FrontLightModelProduct.sceneColor.rgb", "m" }, { FRAGMENT, "rgb_light_full", "vec3", "rgb_light_shadow", "!m" }, - { FRAGMENT, "rgb_light_shadow", "vec3", "(rgb_light)*l_shadow", "s" }, + { FRAGMENT, "rgb_light_shadow", "vec3", "rgb_light*l_shadow", "s" }, { FRAGMENT, "rgb_light_shadow", "vec3", "rgb_light", "!s" }, { FRAGMENT, "rgb_light", "vec3", "vec3(l_diffuse)", "!m!p" }, { FRAGMENT, "rgb_light", "vec3", "vec3(l_diffuse+l_specular)", "!mp" }, @@ -97,9 +98,15 @@ const ProgramBuilder::StandardVariable ProgramBuilder::standard_variables[] = ProgramBuilder::ProgramBuilder(const StandardFeatures &f): features(f), - feature_flags(features.create_flags()) + feature_flags(features.create_flags()), + optimize(true) { } +void ProgramBuilder::set_optimize(bool o) +{ + optimize = o; +} + Program *ProgramBuilder::create_program() const { Program *prog = new Program; @@ -167,6 +174,12 @@ void ProgramBuilder::add_shaders(Program &prog) const } } + if(optimize) + { + for(list::const_iterator i=resolved_vars.begin(); i!=resolved_vars.end(); ++i) + (*i)->check_inline(); + } + prog.attach_shader_owned(new VertexShader(create_source(resolved_vars, VERTEX))); prog.attach_shader_owned(new FragmentShader(create_source(resolved_vars, FRAGMENT))); } @@ -206,7 +219,7 @@ string ProgramBuilder::create_source(const list &variables, Va source += "void main()\n{\n"; for(list::const_iterator i=variables.begin(); i!=variables.end(); ++i) - if((*i)->variable->scope==scope) + if((*i)->variable->scope==scope && !(*i)->inlined) { source += '\t'; if((*i)->variable->type) @@ -220,7 +233,12 @@ string ProgramBuilder::create_source(const list &variables, Va if(scope==VERTEX) { for(list::const_iterator i=varyings.begin(); i!=varyings.end(); ++i) - source += format("\tv_%s = %s;\n", (*i)->resolved_name, (*i)->resolved_name); + { + if((*i)->inlined) + source += format("\tv_%s = %s;\n", (*i)->resolved_name, (*i)->get_expression()); + else + source += format("\tv_%s = %s;\n", (*i)->resolved_name, (*i)->resolved_name); + } } source += '}'; @@ -401,7 +419,9 @@ ProgramBuilder::ShaderVariable::ShaderVariable(const std::string &n): name(n), variable(0), resolved_name(n), - fuzzy_space(name.find("zzz")!=string::npos) + fuzzy_space(name.find("zzz")!=string::npos), + inlined(false), + inline_parens(false) { } void ProgramBuilder::ShaderVariable::resolve(const StandardVariable &var) @@ -416,6 +436,7 @@ void ProgramBuilder::ShaderVariable::resolve(ShaderVariable &var) { for(list::iterator i=referenced_by.begin(); i!=referenced_by.end(); ++i) (*i)->update_reference(*this, var); + var.referenced_by.insert(var.referenced_by.end(), referenced_by.begin(), referenced_by.end()); } void ProgramBuilder::ShaderVariable::resolve_space(const string &space) @@ -454,6 +475,32 @@ void ProgramBuilder::ShaderVariable::update_reference(ShaderVariable &from, Shad resolve_space(to.resolved_space); } +void ProgramBuilder::ShaderVariable::check_inline() +{ + if(variable->expression) + { + unsigned total_refs = referenced_by.size(); + unsigned in_scope_refs = 0; + for(list::const_iterator i=referenced_by.begin(); i!=referenced_by.end(); ++i) + if((*i)->variable->scope==variable->scope) + ++in_scope_refs; + if(total_refs==1 || (total_refs>0 && in_scope_refs==0)) + { + inlined = true; + unsigned level = 0; + for(const char *c=variable->expression; (!inline_parens && *c); ++c) + { + if(*c=='(') + ++level; + else if(*c==')') + --level; + else if(level==0 && !isalnum(*c) && *c!='_' && *c!='.') + inline_parens = true; + } + } + } +} + bool ProgramBuilder::ShaderVariable::is_referenced_from(VariableScope scope) const { for(list::const_iterator i=referenced_by.begin(); i!=referenced_by.end(); ++i) @@ -468,11 +515,17 @@ string ProgramBuilder::ShaderVariable::get_expression() const for(list::const_iterator i=referenced_vars.begin(); i!=referenced_vars.end(); ++i) if((*i)->variable) { - string var_name = (*i)->resolved_name; + string replacement = (*i)->resolved_name; if(variable->scope==FRAGMENT && (*i)->variable->scope==VERTEX) - var_name = "v_"+var_name; - if(var_name!=(*i)->name) - replace_map[(*i)->name] = var_name; + replacement = "v_"+replacement; + else if((*i)->inlined) + { + replacement = (*i)->get_expression(); + if((*i)->inline_parens) + replacement = "("+replacement+")"; + } + if(replacement!=(*i)->name) + replace_map[(*i)->name] = replacement; } if(replace_map.empty()) diff --git a/source/programbuilder.h b/source/programbuilder.h index 30f1ef15..82a954b5 100644 --- a/source/programbuilder.h +++ b/source/programbuilder.h @@ -64,6 +64,8 @@ private: std::string resolved_space; std::list referenced_vars; std::list referenced_by; + bool inlined; + bool inline_parens; ShaderVariable(const std::string &); @@ -72,6 +74,7 @@ private: void resolve_space(const std::string &); void add_reference(ShaderVariable &); void update_reference(ShaderVariable &, ShaderVariable &); + void check_inline(); bool is_referenced_from(VariableScope) const; std::string get_expression() const; }; @@ -85,12 +88,14 @@ private: StandardFeatures features; std::string feature_flags; + bool optimize; static const StandardVariable standard_variables[]; public: ProgramBuilder(const StandardFeatures &); + void set_optimize(bool); Program *create_program() const; void add_shaders(Program &) const; private: -- 2.43.0