]> git.tdb.fi Git - libs/gl.git/blobdiff - source/programcompiler.cpp
Derive ProgramCompiler::DeclarationCombiner from BlockModifier
[libs/gl.git] / source / programcompiler.cpp
index fd27839da25e1f7cb377a7fdf46079bfb1e862f3..c35fa275c2b1bbadbcfbfb8f113cf68d165d4a8a 100644 (file)
@@ -122,6 +122,8 @@ void ProgramCompiler::process()
                else
                        ++i;
        }
+       for(list<Stage>::iterator i=module->stages.begin(); i!=module->stages.end(); ++i)
+               finalize(*i);
 }
 
 void ProgramCompiler::import(const string &name)
@@ -185,6 +187,14 @@ bool ProgramCompiler::optimize(Stage &stage)
        return !unused.empty();
 }
 
+void ProgramCompiler::finalize(Stage &stage)
+{
+       if(get_gl_api()==OPENGL_ES2)
+               apply<DefaultPrecisionGenerator>(stage);
+       else
+               apply<PrecisionRemover>(stage);
+}
+
 void ProgramCompiler::inject_block(Block &target, const Block &source)
 {
        list<RefPtr<Node> >::iterator insert_point = target.body.begin();
@@ -220,6 +230,38 @@ void ProgramCompiler::Visitor::apply(Stage &s)
 }
 
 
+ProgramCompiler::BlockModifier::BlockModifier():
+       remove_node(false)
+{ }
+
+void ProgramCompiler::BlockModifier::flatten_block(Block &block)
+{
+       insert_nodes.insert(insert_nodes.end(), block.body.begin(), block.body.end());
+       remove_node = true;
+}
+
+void ProgramCompiler::BlockModifier::apply_and_increment(Block &block, list<RefPtr<Node> >::iterator &i)
+{
+       block.body.insert(i, insert_nodes.begin(), insert_nodes.end());
+       insert_nodes.clear();
+
+       if(remove_node)
+               block.body.erase(i++);
+       else
+               ++i;
+       remove_node = false;
+}
+
+void ProgramCompiler::BlockModifier::visit(Block &block)
+{
+       for(list<RefPtr<Node> >::iterator i=block.body.begin(); i!=block.body.end(); )
+       {
+               (*i)->visit(*this);
+               apply_and_increment(block, i);
+       }
+}
+
+
 ProgramCompiler::Formatter::Formatter():
        indent(0),
        parameter_list(false),
@@ -228,9 +270,17 @@ ProgramCompiler::Formatter::Formatter():
 
 void ProgramCompiler::Formatter::apply(ProgramSyntax::Stage &s)
 {
+       GLApi api = get_gl_api();
        const Version &ver = s.required_version;
-       if(ver.major)
-               formatted += format("#version %d%d\n", ver.major, ver.minor);
+
+       if(ver)
+       {
+               formatted += format("#version %d%02d", ver.major, ver.minor);
+               if(api==OPENGL_ES2 && ver>=Version(3, 0))
+                       formatted += " es";
+               formatted += '\n';
+       }
+
        Visitor::apply(s);
 }
 
@@ -329,6 +379,11 @@ void ProgramCompiler::Formatter::visit(Import &import)
        formatted += format("import %s;", import.module);
 }
 
+void ProgramCompiler::Formatter::visit(Precision &prec)
+{
+       formatted += format("precision %s %s;", prec.precision, prec.type);
+}
+
 void ProgramCompiler::Formatter::visit(Layout &layout)
 {
        formatted += "layout(";
@@ -379,6 +434,8 @@ void ProgramCompiler::Formatter::visit(VariableDeclaration &var)
                }
                formatted += format("%s ", interface);
        }
+       if(!var.precision.empty())
+               formatted += format("%s ", var.precision);
        formatted += format("%s %s", var.type, var.name);
        if(var.array)
        {
@@ -471,8 +528,7 @@ void ProgramCompiler::Formatter::visit(Jump &jump)
 
 
 ProgramCompiler::DeclarationCombiner::DeclarationCombiner():
-       toplevel(true),
-       remove_node(false)
+       toplevel(true)
 { }
 
 void ProgramCompiler::DeclarationCombiner::visit(Block &block)
@@ -481,15 +537,7 @@ void ProgramCompiler::DeclarationCombiner::visit(Block &block)
                return;
 
        SetForScope<bool> set(toplevel, false);
-       for(list<RefPtr<Node> >::iterator i=block.body.begin(); i!=block.body.end(); )
-       {
-               remove_node = false;
-               (*i)->visit(*this);
-               if(remove_node)
-                       block.body.erase(i++);
-               else
-                       ++i;
-       }
+       BlockModifier::visit(block);
 }
 
 void ProgramCompiler::DeclarationCombiner::visit(FunctionDeclaration &func)
@@ -689,38 +737,6 @@ void ProgramCompiler::FunctionResolver::visit(FunctionDeclaration &func)
 }
 
 
-ProgramCompiler::BlockModifier::BlockModifier():
-       remove_node(false)
-{ }
-
-void ProgramCompiler::BlockModifier::flatten_block(Block &block)
-{
-       insert_nodes.insert(insert_nodes.end(), block.body.begin(), block.body.end());
-       remove_node = true;
-}
-
-void ProgramCompiler::BlockModifier::apply_and_increment(Block &block, list<RefPtr<Node> >::iterator &i)
-{
-       block.body.insert(i, insert_nodes.begin(), insert_nodes.end());
-       insert_nodes.clear();
-
-       if(remove_node)
-               block.body.erase(i++);
-       else
-               ++i;
-       remove_node = false;
-}
-
-void ProgramCompiler::BlockModifier::visit(Block &block)
-{
-       for(list<RefPtr<Node> >::iterator i=block.body.begin(); i!=block.body.end(); )
-       {
-               (*i)->visit(*this);
-               apply_and_increment(block, i);
-       }
-}
-
-
 ProgramCompiler::InterfaceGenerator::InterfaceGenerator():
        scope_level(0)
 { }
@@ -1493,17 +1509,78 @@ void ProgramCompiler::NodeRemover::visit(VariableDeclaration &var)
 }
 
 
+void ProgramCompiler::PrecisionRemover::visit(Precision &)
+{
+       remove_node = true;
+}
+
+void ProgramCompiler::PrecisionRemover::visit(VariableDeclaration &var)
+{
+       var.precision.clear();
+}
+
+
+ProgramCompiler::DefaultPrecisionGenerator::DefaultPrecisionGenerator():
+       toplevel(true)
+{ }
+
+void ProgramCompiler::DefaultPrecisionGenerator::visit(Block &block)
+{
+       if(toplevel)
+       {
+               SetForScope<bool> set(toplevel, false);
+               BlockModifier::visit(block);
+       }
+       else
+               Visitor::visit(block);
+}
+
+void ProgramCompiler::DefaultPrecisionGenerator::visit(Precision &prec)
+{
+       have_default.insert(prec.type);
+}
+
+void ProgramCompiler::DefaultPrecisionGenerator::visit(VariableDeclaration &var)
+{
+       if(var.type_declaration)
+               return;
+
+       string type = var.type;
+       if(!type.compare(0, 3, "vec") || !type.compare(0, 3, "mat"))
+               type = "float";
+       else if(!type.compare(0, 3, "ivec") || type=="uint")
+               type = "int";
+
+       if(!have_default.count(type))
+       {
+               Precision *prec = new Precision;
+               if(!type.compare(0, 7, "sampler"))
+                       prec->precision = "lowp";
+               else if(stage->type==FRAGMENT)
+                       prec->precision = "mediump";
+               else
+                       prec->precision = "highp";
+               prec->type = type;
+               insert_nodes.push_back(prec);
+
+               have_default.insert(type);
+       }
+}
+
+
 ProgramCompiler::LegacyConverter::LegacyConverter():
+       target_api(get_gl_api()),
        target_version(get_glsl_version()),
        frag_out(0)
 { }
 
 ProgramCompiler::LegacyConverter::LegacyConverter(const Version &v):
+       target_api(get_gl_api()),
        target_version(v),
        frag_out(0)
 { }
 
-bool ProgramCompiler::LegacyConverter::check_version(const Version &feature_version)
+bool ProgramCompiler::LegacyConverter::check_version(const Version &feature_version) const
 {
        if(target_version<feature_version)
                return false;
@@ -1513,9 +1590,17 @@ bool ProgramCompiler::LegacyConverter::check_version(const Version &feature_vers
        return true;
 }
 
+bool ProgramCompiler::LegacyConverter::supports_unified_interface_syntax() const
+{
+       if(target_api==OPENGL_ES2)
+               return check_version(Version(3, 0));
+       else
+               return check_version(Version(1, 30));
+}
+
 void ProgramCompiler::LegacyConverter::visit(VariableReference &var)
 {
-       if(var.declaration==frag_out && !check_version(Version(1, 30)))
+       if(var.declaration==frag_out && !supports_unified_interface_syntax())
        {
                var.name = "gl_FragColor";
                var.declaration = 0;
@@ -1530,13 +1615,21 @@ void ProgramCompiler::LegacyConverter::visit(VariableReference &var)
 void ProgramCompiler::LegacyConverter::visit(Assignment &assign)
 {
        TraversingVisitor::visit(assign);
-       if(assign.target_declaration==frag_out && !check_version(Version(1, 30)))
+       if(assign.target_declaration==frag_out && !supports_unified_interface_syntax())
                assign.target_declaration = 0;
 }
 
+bool ProgramCompiler::LegacyConverter::supports_unified_sampling_functions() const
+{
+       if(target_api==OPENGL_ES2)
+               return check_version(Version(3, 0));
+       else
+               return check_version(Version(1, 30));
+}
+
 void ProgramCompiler::LegacyConverter::visit(FunctionCall &call)
 {
-       if(call.name=="texture" && !call.declaration && !check_version(Version(1, 30)))
+       if(call.name=="texture" && !call.declaration && !supports_unified_sampling_functions())
        {
                vector<RefPtr<Expression> >::iterator i = call.arguments.begin();
                if(i!=call.arguments.end())
@@ -1561,9 +1654,17 @@ void ProgramCompiler::LegacyConverter::visit(FunctionCall &call)
                TraversingVisitor::visit(call);
 }
 
+bool ProgramCompiler::LegacyConverter::supports_interface_layouts() const
+{
+       if(target_api==OPENGL_ES2)
+               return check_version(Version(3, 0));
+       else
+               return check_version(Version(3, 30));
+}
+
 void ProgramCompiler::LegacyConverter::visit(VariableDeclaration &var)
 {
-       if(var.layout && !check_version(Version(3, 30)))
+       if(var.layout && !supports_interface_layouts())
        {
                vector<Layout::Qualifier>::iterator i;
                for(i=var.layout->qualifiers.begin(); (i!=var.layout->qualifiers.end() && i->identifier!="location"); ++i) ;
@@ -1586,7 +1687,7 @@ void ProgramCompiler::LegacyConverter::visit(VariableDeclaration &var)
                }
        }
 
-       if((var.interface=="in" || var.interface=="out") && !check_version(Version(1, 30)))
+       if((var.interface=="in" || var.interface=="out") && !supports_unified_interface_syntax())
        {
                if(stage->type==FRAGMENT && var.interface=="out")
                {
@@ -1598,9 +1699,22 @@ void ProgramCompiler::LegacyConverter::visit(VariableDeclaration &var)
        TraversingVisitor::visit(var);
 }
 
+bool ProgramCompiler::LegacyConverter::supports_interface_blocks(const string &iface) const
+{
+       if(target_api==OPENGL_ES2)
+       {
+               if(iface=="uniform")
+                       return check_version(Version(3, 0));
+               else
+                       return check_version(Version(3, 20));
+       }
+       else
+               return check_version(Version(1, 50));
+}
+
 void ProgramCompiler::LegacyConverter::visit(InterfaceBlock &iface)
 {
-       if(!check_version(Version(1, 50)))
+       if(!supports_interface_blocks(iface.interface))
                flatten_block(iface.members);
 }