From 74bd3813b9744550c9ac5980588e561835b616d9 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Fri, 18 Nov 2016 19:40:16 +0200 Subject: [PATCH] Automatically backport shaders to earlier GLSL versions if necessary Fragment shader output replacement is a bit crude and will just replace any output with gl_FragColor. It will be made better later. --- source/programcompiler.cpp | 104 +++++++++++++++++++++++++++++++++++-- source/programcompiler.h | 17 ++++++ source/programsyntax.h | 2 + 3 files changed, 118 insertions(+), 5 deletions(-) diff --git a/source/programcompiler.cpp b/source/programcompiler.cpp index 3cb8611c..d6586931 100644 --- a/source/programcompiler.cpp +++ b/source/programcompiler.cpp @@ -58,15 +58,14 @@ void ProgramCompiler::add_shaders(Program &program) if(!module) throw invalid_operation("ProgramCompiler::add_shaders"); - string head = "#version 150\n"; for(list::iterator i=module->stages.begin(); i!=module->stages.end(); ++i) { if(i->type==VERTEX) - program.attach_shader_owned(new VertexShader(head+apply(*i))); + program.attach_shader_owned(new VertexShader(apply(*i))); else if(i->type==GEOMETRY) - program.attach_shader_owned(new GeometryShader(head+apply(*i))); + program.attach_shader_owned(new GeometryShader(apply(*i))); else if(i->type==FRAGMENT) - program.attach_shader_owned(new FragmentShader(head+apply(*i))); + program.attach_shader_owned(new FragmentShader(apply(*i))); } program.bind_attribute(VERTEX4, "vertex"); @@ -164,6 +163,8 @@ void ProgramCompiler::generate(Stage &stage) apply(stage); apply(stage); apply(stage); + apply(stage); + apply(stage); } bool ProgramCompiler::optimize(Stage &stage) @@ -220,6 +221,14 @@ ProgramCompiler::Formatter::Formatter(): else_if(0) { } +void ProgramCompiler::Formatter::apply(ProgramSyntax::Stage &s) +{ + const Version &ver = s.required_version; + if(ver.major) + formatted += format("#version %d%d\n", ver.major, ver.minor); + Visitor::apply(s); +} + void ProgramCompiler::Formatter::visit(Literal &literal) { formatted += literal.token; @@ -295,7 +304,7 @@ void ProgramCompiler::Formatter::visit(Block &block) if(use_braces) formatted += format("%s{\n", string(brace_indent*2, ' ')); - SetForScope set(indent, indent+!formatted.empty()); + SetForScope set(indent, indent+(indent>0 || use_braces)); string spaces(indent*2, ' '); for(list >::iterator i=block.body.begin(); i!=block.body.end(); ++i) { @@ -1281,5 +1290,90 @@ void ProgramCompiler::NodeRemover::visit(VariableDeclaration &var) var.init_expression = 0; } + +ProgramCompiler::LegacyConverter::LegacyConverter(): + target_version(get_glsl_version()) +{ } + +ProgramCompiler::LegacyConverter::LegacyConverter(const Version &v): + target_version(v) +{ } + +bool ProgramCompiler::LegacyConverter::check_version(const Version &feature_version) +{ + if(target_versionrequired_versionrequired_version = feature_version; + + return true; +} + +void ProgramCompiler::LegacyConverter::visit(VariableReference &var) +{ + if(var.name==frag_out_name && !check_version(Version(1, 30))) + { + var.name = "gl_FragColor"; + var.declaration = 0; + type = "vec4"; + } + else if(var.declaration) + type = var.declaration->type; + else + type = string(); +} + +void ProgramCompiler::LegacyConverter::visit(FunctionCall &call) +{ + if(call.name=="texture" && !call.declaration && !check_version(Version(1, 30))) + { + vector >::iterator i = call.arguments.begin(); + if(i!=call.arguments.end()) + { + (*i)->visit(*this); + if(type=="sampler1D") + call.name = "texture1D"; + else if(type=="sampler2D") + call.name = "texture2D"; + else if(type=="sampler3D") + call.name = "texture3D"; + else if(type=="sampler1DShadow") + call.name = "shadow1D"; + else if(type=="sampler2DShadow") + call.name = "shadow2D"; + + for(; i!=call.arguments.end(); ++i) + (*i)->visit(*this); + } + } + else + TraversingVisitor::visit(call); +} + +void ProgramCompiler::LegacyConverter::visit(VariableDeclaration &var) +{ + if(var.interface=="in" || var.interface=="out") + if(!check_version(Version(1, 30))) + { + if(stage->type==VERTEX && var.interface=="in") + var.interface = "attribute"; + else if((stage->type==VERTEX && var.interface=="out") || (stage->type==FRAGMENT && var.interface=="in")) + var.interface = "varying"; + else if(stage->type==FRAGMENT && var.interface=="out") + { + frag_out_name = var.name; + remove_node = true; + } + } + + TraversingVisitor::visit(var); +} + +void ProgramCompiler::LegacyConverter::visit(InterfaceBlock &iface) +{ + if(!check_version(Version(1, 50))) + flatten_block(iface.members); +} + } // namespace GL } // namespace Msp diff --git a/source/programcompiler.h b/source/programcompiler.h index 96fee471..8ae22901 100644 --- a/source/programcompiler.h +++ b/source/programcompiler.h @@ -38,6 +38,7 @@ private: Formatter(); + virtual void apply(ProgramSyntax::Stage &); const std::string &get_result() const { return formatted; } virtual void visit(ProgramSyntax::Block &); virtual void visit(ProgramSyntax::Literal &); @@ -246,6 +247,22 @@ private: virtual void visit(ProgramSyntax::VariableDeclaration &); }; + struct LegacyConverter: BlockModifier + { + Version target_version; + std::string type; + std::string frag_out_name; + + LegacyConverter(); + LegacyConverter(const Version &); + + bool check_version(const Version &); + virtual void visit(ProgramSyntax::VariableReference &); + virtual void visit(ProgramSyntax::FunctionCall &); + virtual void visit(ProgramSyntax::VariableDeclaration &); + virtual void visit(ProgramSyntax::InterfaceBlock &); + }; + Resources *resources; ProgramParser parser; ProgramSyntax::Module *module; diff --git a/source/programsyntax.h b/source/programsyntax.h index 08968332..2f9f1fc0 100644 --- a/source/programsyntax.h +++ b/source/programsyntax.h @@ -5,6 +5,7 @@ #include #include #include +#include "extension.h" namespace Msp { namespace GL { @@ -343,6 +344,7 @@ struct Stage ProgramSyntax::Block content; std::map in_variables; std::map out_variables; + Version required_version; Stage(StageType); }; -- 2.43.0