]> git.tdb.fi Git - libs/gl.git/blobdiff - source/programcompiler.cpp
Use layout declarations to set attribute and fragment data locations
[libs/gl.git] / source / programcompiler.cpp
index 9b3266755b0b4f36c7bdc1ebe3471ebba48e8d40..fd756de0e00cbbca4c5aa18587b251afc4e94ccb 100644 (file)
@@ -58,21 +58,23 @@ void ProgramCompiler::add_shaders(Program &program)
        if(!module)
                throw invalid_operation("ProgramCompiler::add_shaders");
 
-       string head = "#version 150\n";
        for(list<Stage>::iterator i=module->stages.begin(); i!=module->stages.end(); ++i)
        {
                if(i->type==VERTEX)
-                       program.attach_shader_owned(new VertexShader(head+apply<Formatter>(*i)));
+               {
+                       program.attach_shader_owned(new VertexShader(apply<Formatter>(*i)));
+                       for(map<string, unsigned>::iterator j=i->locations.begin(); j!=i->locations.end(); ++j)
+                               program.bind_attribute(j->second, j->first);
+               }
                else if(i->type==GEOMETRY)
-                       program.attach_shader_owned(new GeometryShader(head+apply<Formatter>(*i)));
+                       program.attach_shader_owned(new GeometryShader(apply<Formatter>(*i)));
                else if(i->type==FRAGMENT)
-                       program.attach_shader_owned(new FragmentShader(head+apply<Formatter>(*i)));
+               {
+                       program.attach_shader_owned(new FragmentShader(apply<Formatter>(*i)));
+                       for(map<string, unsigned>::iterator j=i->locations.begin(); j!=i->locations.end(); ++j)
+                               program.bind_fragment_data(j->second, j->first);
+               }
        }
-
-       program.bind_attribute(VERTEX4, "vertex");
-       program.bind_attribute(NORMAL3, "normal");
-       program.bind_attribute(COLOR4_FLOAT, "color");
-       program.bind_attribute(TEXCOORD4, "texcoord");
 }
 
 Module *ProgramCompiler::create_builtins_module()
@@ -124,9 +126,8 @@ void ProgramCompiler::process()
 
 void ProgramCompiler::import(const string &name)
 {
-       if(!resources)
-               throw runtime_error("no resources");
-       RefPtr<IO::Seekable> io = resources->open_raw(name+".glsl");
+       string fn = name+".glsl";
+       RefPtr<IO::Seekable> io = (resources ? resources->open_raw(fn) : Resources::get_builtins().open(fn));
        if(!io)
                throw runtime_error(format("module %s not found", name));
        ProgramParser import_parser;
@@ -159,10 +160,13 @@ void ProgramCompiler::generate(Stage &stage)
 {
        inject_block(stage.content, module->shared.content);
 
+       apply<FunctionResolver>(stage);
        apply<VariableResolver>(stage);
        apply<InterfaceGenerator>(stage);
        apply<VariableResolver>(stage);
        apply<VariableRenamer>(stage);
+       apply<LegacyConverter>(stage);
+       apply<VariableResolver>(stage);
 }
 
 bool ProgramCompiler::optimize(Stage &stage)
@@ -171,6 +175,8 @@ bool ProgramCompiler::optimize(Stage &stage)
        apply<VariableResolver>(stage);
 
        set<Node *> unused = apply<UnusedVariableLocator>(stage);
+       set<Node *> unused2 = apply<UnusedFunctionLocator>(stage);
+       unused.insert(unused2.begin(), unused2.end());
        apply<NodeRemover>(stage, unused);
 
        return !unused.empty();
@@ -217,6 +223,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;
@@ -292,7 +306,7 @@ void ProgramCompiler::Formatter::visit(Block &block)
        if(use_braces)
                formatted += format("%s{\n", string(brace_indent*2, ' '));
 
-       SetForScope<unsigned> set(indent, indent+!formatted.empty());
+       SetForScope<unsigned> set(indent, indent+(indent>0 || use_braces));
        string spaces(indent*2, ' ');
        for(list<NodePtr<Node> >::iterator i=block.body.begin(); i!=block.body.end(); ++i)
        {
@@ -323,7 +337,13 @@ void ProgramCompiler::Formatter::visit(Layout &layout)
                if(!i->value.empty())
                        formatted += format("=%s", i->value);
        }
-       formatted += format(") %s;", layout.interface);
+       formatted += ')';
+}
+
+void ProgramCompiler::Formatter::visit(InterfaceLayout &layout)
+{
+       layout.layout.visit(*this);
+       formatted += format(" %s;", layout.interface);
 }
 
 void ProgramCompiler::Formatter::visit(StructDeclaration &strct)
@@ -335,6 +355,11 @@ void ProgramCompiler::Formatter::visit(StructDeclaration &strct)
 
 void ProgramCompiler::Formatter::visit(VariableDeclaration &var)
 {
+       if(var.layout)
+       {
+               var.layout->visit(*this);
+               formatted += ' ';
+       }
        if(var.constant)
                formatted += "const ";
        if(!var.sampling.empty())
@@ -467,6 +492,7 @@ void ProgramCompiler::DeclarationCombiner::visit(VariableDeclaration &var)
        VariableDeclaration *&ptr = variables[var.name];
        if(ptr)
        {
+               ptr->type = var.type;
                if(var.init_expression)
                        ptr->init_expression = var.init_expression;
                remove_node = true;
@@ -616,11 +642,72 @@ void ProgramCompiler::VariableResolver::visit(InterfaceBlock &iface)
 }
 
 
-ProgramCompiler::InterfaceGenerator::InterfaceGenerator():
-       scope_level(0),
+void ProgramCompiler::FunctionResolver::visit(FunctionCall &call)
+{
+       map<string, vector<FunctionDeclaration *> >::iterator i = functions.find(call.name);
+       if(i!=functions.end())
+               call.declaration = i->second.back();
+
+       TraversingVisitor::visit(call);
+}
+
+void ProgramCompiler::FunctionResolver::visit(FunctionDeclaration &func)
+{
+       vector<FunctionDeclaration *> &decls = functions[func.name];
+       if(func.definition)
+       {
+               for(vector<FunctionDeclaration *>::iterator i=decls.begin(); i!=decls.end(); ++i)
+                       (*i)->definition = func.definition;
+               decls.clear();
+               decls.push_back(&func);
+       }
+       else if(!decls.empty() && decls.back()->definition)
+               func.definition = decls.back()->definition;
+       else
+               decls.push_back(&func);
+
+       TraversingVisitor::visit(func);
+}
+
+
+ProgramCompiler::BlockModifier::BlockModifier():
        remove_node(false)
 { }
 
+void ProgramCompiler::BlockModifier::flatten_block(Block &block)
+{
+       for(list<NodePtr<Node> >::iterator i=block.body.begin(); i!=block.body.end(); ++i)
+               insert_nodes.push_back((*i)->clone());
+       remove_node = true;
+}
+
+void ProgramCompiler::BlockModifier::apply_and_increment(Block &block, list<NodePtr<Node> >::iterator &i)
+{
+       for(list<Node *>::iterator j=insert_nodes.begin(); j!=insert_nodes.end(); ++j)
+               block.body.insert(i, *j);
+       insert_nodes.clear();
+
+       if(remove_node)
+               block.body.erase(i++);
+       else
+               ++i;
+       remove_node = false;
+}
+
+void ProgramCompiler::BlockModifier::visit(Block &block)
+{
+       for(list<NodePtr<Node> >::iterator i=block.body.begin(); i!=block.body.end(); )
+       {
+               (*i)->visit(*this);
+               apply_and_increment(block, i);
+       }
+}
+
+
+ProgramCompiler::InterfaceGenerator::InterfaceGenerator():
+       scope_level(0)
+{ }
+
 string ProgramCompiler::InterfaceGenerator::get_out_prefix(StageType type)
 {
        if(type==VERTEX)
@@ -657,15 +744,7 @@ void ProgramCompiler::InterfaceGenerator::visit(Block &block)
                        iface_declarations.clear();
                }
 
-               for(list<Node *>::iterator j=insert_nodes.begin(); j!=insert_nodes.end(); ++j)
-                       block.body.insert(i, *j);
-               insert_nodes.clear();
-
-               if(remove_node)
-                       block.body.erase(i++);
-               else
-                       ++i;
-               remove_node = false;
+               apply_and_increment(block, i);
        }
 }
 
@@ -928,30 +1007,13 @@ void ProgramCompiler::ExpressionEvaluator::visit(BinaryExpression &binary)
 
 
 ProgramCompiler::ConstantConditionEliminator::ConstantConditionEliminator():
-       scope_level(0),
-       remove_node(false),
-       replacement_block(0)
+       scope_level(0)
 { }
 
 void ProgramCompiler::ConstantConditionEliminator::visit(Block &block)
 {
        SetForScope<unsigned> set(scope_level, scope_level+1);
-       for(list<NodePtr<Node> >::iterator i=block.body.begin(); i!=block.body.end(); )
-       {
-               (*i)->visit(*this);
-               if(replacement_block)
-               {
-                       for(list<NodePtr<Node> >::iterator j=replacement_block->body.begin(); j!=replacement_block->body.end(); ++j)
-                               block.body.insert(i, *j);
-                       replacement_block = 0;
-               }
-
-               if(remove_node)
-                       block.body.erase(i++);
-               else
-                       ++i;
-               remove_node = false;
-       }
+       BlockModifier::visit(block);
 
        for(map<string, VariableDeclaration *>::const_iterator i=block.variables.begin(); i!=block.variables.end(); ++i)
                variable_values.erase(i->second);
@@ -973,10 +1035,7 @@ void ProgramCompiler::ConstantConditionEliminator::visit(Conditional &cond)
        ExpressionEvaluator eval(variable_values);
        cond.condition->visit(eval);
        if(eval.result_valid)
-       {
-               remove_node = true;
-               replacement_block = (eval.result ? &cond.body : &cond.else_body);
-       }
+               flatten_block(eval.result ? cond.body : cond.else_body);
        else
                TraversingVisitor::visit(cond);
 }
@@ -1198,6 +1257,24 @@ void ProgramCompiler::UnusedVariableLocator::visit(Iteration &iter)
 }
 
 
+void ProgramCompiler::UnusedFunctionLocator::visit(FunctionCall &call)
+{
+       TraversingVisitor::visit(call);
+
+       unused_nodes.erase(call.declaration);
+       if(call.declaration && call.declaration->definition!=call.declaration)
+               used_definitions.insert(call.declaration->definition);
+}
+
+void ProgramCompiler::UnusedFunctionLocator::visit(FunctionDeclaration &func)
+{
+       TraversingVisitor::visit(func);
+
+       if(func.name!="main" && !used_definitions.count(&func))
+               unused_nodes.insert(&func);
+}
+
+
 ProgramCompiler::NodeRemover::NodeRemover(const set<Node *> &r):
        to_remove(r)
 { }
@@ -1220,6 +1297,7 @@ void ProgramCompiler::NodeRemover::visit(VariableDeclaration &var)
        {
                stage->in_variables.erase(var.name);
                stage->out_variables.erase(var.name);
+               stage->locations.erase(var.name);
                if(var.linked_declaration)
                        var.linked_declaration->linked_declaration = 0;
        }
@@ -1227,5 +1305,112 @@ 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_version<feature_version)
+               return false;
+       else if(stage->required_version<feature_version)
+               stage->required_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<NodePtr<Expression> >::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.layout && !check_version(Version(3, 30)))
+       {
+               vector<Layout::Qualifier>::iterator i;
+               for(i=var.layout->qualifiers.begin(); (i!=var.layout->qualifiers.end() && i->identifier!="location"); ++i) ;
+               if(i!=var.layout->qualifiers.end())
+               {
+                       unsigned location = lexical_cast<unsigned>(i->value);
+                       if(stage->type==VERTEX && var.interface=="in")
+                       {
+                               stage->locations[var.name] = location;
+                               var.layout->qualifiers.erase(i);
+                       }
+                       else if(stage->type==FRAGMENT && var.interface=="out")
+                       {
+                               stage->locations[var.name] = location;
+                               var.layout->qualifiers.erase(i);
+                       }
+
+                       if(var.layout->qualifiers.empty())
+                               var.layout = 0;
+               }
+       }
+
+       if((var.interface=="in" || var.interface=="out") && !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