]> git.tdb.fi Git - libs/gl.git/blobdiff - source/programcompiler.cpp
Basic OpenGL ES support in ProgramCompiler
[libs/gl.git] / source / programcompiler.cpp
index 5f8c6f9b91f612c218992ff8553620803b1f269a..6b8eb6e6135ddb68702537cbc4d3c9b626a341c1 100644 (file)
@@ -160,6 +160,7 @@ void ProgramCompiler::generate(Stage &stage)
 {
        inject_block(stage.content, module->shared.content);
 
+       apply<DeclarationReorderer>(stage);
        apply<FunctionResolver>(stage);
        apply<VariableResolver>(stage);
        apply<InterfaceGenerator>(stage);
@@ -227,9 +228,23 @@ 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);
+       {
+               formatted += format("#version %d%d", ver.major, ver.minor);
+               if(api==OPENGL_ES2 && ver>=Version(3, 0))
+                       formatted += " es";
+               formatted += '\n';
+       }
+
+       if(api==OPENGL_ES2)
+       {
+               if(s.type==FRAGMENT)
+                       formatted += "precision mediump float;\n";
+       }
+
        Visitor::apply(s);
 }
 
@@ -367,7 +382,17 @@ void ProgramCompiler::Formatter::visit(VariableDeclaration &var)
        if(!var.sampling.empty())
                formatted += format("%s ", var.sampling);
        if(!var.interface.empty() && var.interface!=block_interface)
-               formatted += format("%s ", var.interface);
+       {
+               string interface = var.interface;
+               if(stage->required_version<Version(1, 30))
+               {
+                       if(stage->type==VERTEX && var.interface=="in")
+                               interface = "attribute";
+                       else if((stage->type==VERTEX && var.interface=="out") || (stage->type==FRAGMENT && var.interface=="in"))
+                               interface = "varying";
+               }
+               formatted += format("%s ", interface);
+       }
        formatted += format("%s %s", var.type, var.name);
        if(var.array)
        {
@@ -1228,8 +1253,7 @@ void ProgramCompiler::UnusedVariableLocator::apply(Stage &s)
                if(!i->second.referenced)
                {
                        unused_nodes.insert(i->first);
-                       for(vector<Node *>::iterator j=i->second.assignments.begin(); j!=i->second.assignments.end(); ++j)
-                               unused_nodes.insert(*j);
+                       clear_assignments(i->second, true);
                }
        }
        variables.pop_back();
@@ -1281,11 +1305,21 @@ void ProgramCompiler::UnusedVariableLocator::record_assignment(VariableDeclarati
 {
        VariableInfo &var_info = variables.back()[&var];
        if(!self_ref)
-               var_info.assignments.clear();
+               clear_assignments(var_info, true);
        var_info.assignments.push_back(&node);
        var_info.conditionally_assigned = false;
 }
 
+void ProgramCompiler::UnusedVariableLocator::clear_assignments(VariableInfo &var_info, bool mark_unused)
+{
+       if(mark_unused)
+       {
+               for(vector<Node *>::iterator i=var_info.assignments.begin(); i!=var_info.assignments.end(); ++i)
+                       unused_nodes.insert(*i);
+       }
+       var_info.assignments.clear();
+}
+
 void ProgramCompiler::UnusedVariableLocator::visit(ExpressionStatement &expr)
 {
        assignment = 0;
@@ -1336,6 +1370,8 @@ void ProgramCompiler::UnusedVariableLocator::visit(FunctionDeclaration &func)
        BlockVariableMap &block_variables = variables.back();
        for(BlockVariableMap::iterator i=block_variables.begin(); i!=block_variables.end(); ++i)
                i->second.conditionally_assigned = true;
+       for(vector<RefPtr<VariableDeclaration> >::iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i)
+               block_variables[i->get()].referenced = true;
        merge_down_variables();
 }
 
@@ -1349,8 +1385,7 @@ void ProgramCompiler::UnusedVariableLocator::merge_down_variables()
                {
                        if(!i->second.referenced)
                                unused_nodes.insert(i->first);
-                       for(vector<Node *>::iterator j=i->second.assignments.begin(); j!=i->second.assignments.end(); ++j)
-                               unused_nodes.insert(*j);
+                       clear_assignments(i->second, true);
                        continue;
                }
 
@@ -1359,11 +1394,9 @@ void ProgramCompiler::UnusedVariableLocator::merge_down_variables()
                        parent_variables.insert(*i);
                else
                {
-                       if(!i->second.conditionally_assigned)
-                       {
-                               j->second.assignments.clear();
-                               j->second.conditionally_assigned = true;
-                       }
+                       if(i->second.referenced || !i->second.conditionally_assigned)
+                               clear_assignments(j->second, !i->second.referenced);
+                       j->second.conditionally_assigned = i->second.conditionally_assigned;
                        j->second.referenced |= i->second.referenced;
                        j->second.assignments.insert(j->second.assignments.end(), i->second.assignments.begin(), i->second.assignments.end());
                }
@@ -1438,7 +1471,7 @@ void ProgramCompiler::UnusedFunctionLocator::visit(FunctionDeclaration &func)
 {
        TraversingVisitor::visit(func);
 
-       if(func.name!="main" && !used_definitions.count(&func))
+       if((func.name!="main" || func.body.body.empty()) && !used_definitions.count(&func))
                unused_nodes.insert(&func);
 }
 
@@ -1475,14 +1508,18 @@ void ProgramCompiler::NodeRemover::visit(VariableDeclaration &var)
 
 
 ProgramCompiler::LegacyConverter::LegacyConverter():
-       target_version(get_glsl_version())
+       target_api(get_gl_api()),
+       target_version(get_glsl_version()),
+       frag_out(0)
 { }
 
 ProgramCompiler::LegacyConverter::LegacyConverter(const Version &v):
-       target_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;
@@ -1492,9 +1529,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.name==frag_out_name && !check_version(Version(1, 30)))
+       if(var.declaration==frag_out && !supports_unified_interface_syntax())
        {
                var.name = "gl_FragColor";
                var.declaration = 0;
@@ -1506,9 +1551,24 @@ void ProgramCompiler::LegacyConverter::visit(VariableReference &var)
                type = string();
 }
 
+void ProgramCompiler::LegacyConverter::visit(Assignment &assign)
+{
+       TraversingVisitor::visit(assign);
+       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())
@@ -1533,9 +1593,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) ;
@@ -1558,15 +1626,11 @@ 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==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")
+               if(stage->type==FRAGMENT && var.interface=="out")
                {
-                       frag_out_name = var.name;
+                       frag_out = &var;
                        remove_node = true;
                }
        }
@@ -1574,9 +1638,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);
 }