]> git.tdb.fi Git - libs/gl.git/blobdiff - source/programcompiler.cpp
Remove the deprecated ProgramBuilder class
[libs/gl.git] / source / programcompiler.cpp
index 50e4f5851df3cb11aecb1277763f622bb3a8d6f1..d021ab4f75732769855e9370fe0c8eec990aca20 100644 (file)
@@ -4,7 +4,9 @@
 #include <msp/gl/extensions/arb_gpu_shader5.h>
 #include <msp/gl/extensions/arb_uniform_buffer_object.h>
 #include <msp/gl/extensions/ext_gpu_shader4.h>
+#include <msp/gl/extensions/ext_texture_array.h>
 #include <msp/strings/format.h>
+#include <msp/strings/regex.h>
 #include <msp/strings/utils.h>
 #include "error.h"
 #include "program.h"
@@ -57,8 +59,8 @@ void ProgramCompiler::compile(const string &source, const string &src_name)
        delete module;
        module = new Module();
        ProgramParser parser;
-       imported_names.insert(src_name);
-       append_module(parser.parse(source, src_name));
+       imported_names.push_back(src_name);
+       append_module(parser.parse(source, src_name, 1));
        process();
 }
 
@@ -68,8 +70,8 @@ void ProgramCompiler::compile(IO::Base &io, Resources *res, const string &src_na
        delete module;
        module = new Module();
        ProgramParser parser;
-       imported_names.insert(src_name);
-       append_module(parser.parse(io, src_name));
+       imported_names.push_back(src_name);
+       append_module(parser.parse(io, src_name, 1));
        process();
 }
 
@@ -83,25 +85,64 @@ void ProgramCompiler::add_shaders(Program &program)
        if(!module)
                throw invalid_operation("ProgramCompiler::add_shaders");
 
-       for(list<Stage>::iterator i=module->stages.begin(); i!=module->stages.end(); ++i)
+       try
        {
-               if(i->type==VERTEX)
+               for(list<Stage>::iterator i=module->stages.begin(); i!=module->stages.end(); ++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);
+                       if(i->type==VERTEX)
+                       {
+                               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(apply<Formatter>(*i)));
+                       else if(i->type==FRAGMENT)
+                       {
+                               program.attach_shader_owned(new FragmentShader(apply<Formatter>(*i)));
+                               if(EXT_gpu_shader4)
+                               {
+                                       for(map<string, unsigned>::iterator j=i->locations.begin(); j!=i->locations.end(); ++j)
+                                               program.bind_fragment_data(j->second, j->first);
+                               }
+                       }
                }
-               else if(i->type==GEOMETRY)
-                       program.attach_shader_owned(new GeometryShader(apply<Formatter>(*i)));
-               else if(i->type==FRAGMENT)
+       }
+       catch(const compile_error &e)
+       {
+               static const Regex r_message("^(([0-9]+)\\(([0-9]+)\\) :|ERROR: ([0-9]+):([0-9]+):) (.*)$");
+               vector<string> lines = split(e.what(), '\n');
+               string translated;
+               for(vector<string>::const_iterator i=lines.begin(); i!=lines.end(); ++i)
                {
-                       program.attach_shader_owned(new FragmentShader(apply<Formatter>(*i)));
-                       if(EXT_gpu_shader4)
+                       RegMatch m = r_message.match(*i);
+                       if(m)
                        {
-                               for(map<string, unsigned>::iterator j=i->locations.begin(); j!=i->locations.end(); ++j)
-                                       program.bind_fragment_data(j->second, j->first);
+                               unsigned index = 0;
+                               unsigned line = 0;
+                               if(m[2])
+                               {
+                                       index = lexical_cast<unsigned>(m[2].str);
+                                       line = lexical_cast<unsigned>(m[3].str);
+                               }
+                               else if(m[4])
+                               {
+                                       index = lexical_cast<unsigned>(m[4].str);
+                                       line = lexical_cast<unsigned>(m[5].str);
+                               }
+                               const char *src = "<unknown>";
+                               if(index==0)
+                                       src = "<generated>";
+                               else if(index-1<imported_names.size())
+                                       src = imported_names[index-1].c_str();
+                               translated += format("%s:%d: %s", src, line, m[6].str);
                        }
+                       else
+                               translated += *i;
+                       translated += '\n';
                }
+
+               throw compile_error(translated);
        }
 }
 
@@ -168,6 +209,8 @@ void ProgramCompiler::append_stage(Stage &stage)
                target = &*i;
        }
 
+       if(stage.required_version>target->required_version)
+               target->required_version = stage.required_version;
        for(NodeList<Statement>::iterator i=stage.content.body.begin(); i!=stage.content.body.end(); ++i)
                target->content.body.push_back(*i);
        apply<DeclarationCombiner>(*target);
@@ -191,19 +234,21 @@ void ProgramCompiler::process()
 void ProgramCompiler::import(const string &name)
 {
        string fn = name+".glsl";
-       if(imported_names.count(fn))
+       if(find(imported_names, fn)!=imported_names.end())
                return;
-       imported_names.insert(fn);
+       imported_names.push_back(fn);
 
        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;
-       append_module(import_parser.parse(*io, fn));
+       append_module(import_parser.parse(*io, fn, imported_names.size()));
 }
 
 void ProgramCompiler::generate(Stage &stage)
 {
+       if(module->shared.required_version>stage.required_version)
+               stage.required_version = module->shared.required_version;
        inject_block(stage.content, module->shared.content);
 
        apply<DeclarationReorderer>(stage);
@@ -307,6 +352,8 @@ void ProgramCompiler::BlockModifier::visit(Block &block)
 
 
 ProgramCompiler::Formatter::Formatter():
+       source_index(0),
+       source_line(1),
        indent(0),
        parameter_list(false)
 { }
@@ -335,11 +382,34 @@ void ProgramCompiler::Formatter::apply(ProgramSyntax::Stage &s)
 void ProgramCompiler::Formatter::append(const string &text)
 {
        formatted += text;
+       for(string::const_iterator i=text.begin(); i!=text.end(); ++i)
+               if(*i=='\n')
+                       ++source_line;
 }
 
 void ProgramCompiler::Formatter::append(char c)
 {
        formatted += c;
+       if(c=='\n')
+               ++source_line;
+}
+
+void ProgramCompiler::Formatter::set_source(unsigned index, unsigned line)
+{
+       if(index!=source_index || (index && line!=source_line))
+       {
+               if(index==source_index && line==source_line+1)
+                       formatted += '\n';
+               else
+               {
+                       unsigned l = line;
+                       if(stage->required_version<Version(3, 30))
+                               --l;
+                       formatted += format("#line %d %d\n", l, index);
+               }
+       }
+       source_index = index;
+       source_line = line;
 }
 
 void ProgramCompiler::Formatter::visit(Literal &literal)
@@ -420,6 +490,7 @@ void ProgramCompiler::Formatter::visit(Block &block)
        {
                if(i!=block.body.begin())
                        append('\n');
+               set_source((*i)->source, (*i)->line);
                append(spaces);
                (*i)->visit(*this);
        }
@@ -549,7 +620,9 @@ void ProgramCompiler::Formatter::visit(Conditional &cond)
                Conditional *else_cond = dynamic_cast<Conditional *>(cond.else_body.body.front().get());
                if(cond.else_body.body.size()==1 && else_cond)
                {
-                       append(format("\n%selse ", string(indent*2, ' ')));
+                       append('\n');
+                       set_source(else_cond->source, else_cond->line);
+                       append(format("%selse ", string(indent*2, ' ')));
                        else_cond->visit(*this);
                }
                else
@@ -922,7 +995,7 @@ bool ProgramCompiler::InterfaceGenerator::generate_interface(VariableDeclaration
        return true;
 }
 
-void ProgramCompiler::InterfaceGenerator::insert_assignment(const string &left, ProgramSyntax::Expression *right)
+ExpressionStatement &ProgramCompiler::InterfaceGenerator::insert_assignment(const string &left, ProgramSyntax::Expression *right)
 {
        Assignment *assign = new Assignment;
        VariableReference *ref = new VariableReference;
@@ -935,6 +1008,8 @@ void ProgramCompiler::InterfaceGenerator::insert_assignment(const string &left,
        stmt->expression = assign;
        stmt->visit(*this);
        insert_nodes.push_back(stmt);
+
+       return *stmt;
 }
 
 void ProgramCompiler::InterfaceGenerator::visit(VariableReference &var)
@@ -966,7 +1041,9 @@ void ProgramCompiler::InterfaceGenerator::visit(VariableDeclaration &var)
                        remove_node = true;
                        if(var.init_expression)
                        {
-                               insert_assignment(var.name, var.init_expression->clone());
+                               ExpressionStatement &stmt = insert_assignment(var.name, var.init_expression->clone());
+                               stmt.source = var.source;
+                               stmt.line = var.line;
                                return;
                        }
                }
@@ -1604,7 +1681,7 @@ void ProgramCompiler::UnusedVariableLocator::merge_down_variables()
                {
                        if(!i->second.referenced)
                                unused_nodes.insert(i->first);
-                       clear_assignments(i->second, true);
+                       clear_assignments(i->second, i->first->interface!="out");
                        continue;
                }
 
@@ -1877,10 +1954,32 @@ void ProgramCompiler::LegacyConverter::visit(FunctionCall &call)
                                call.name = "texture2D";
                        else if(type=="sampler3D")
                                call.name = "texture3D";
+                       else if(type=="samplerCube")
+                               call.name = "textureCube";
                        else if(type=="sampler1DShadow")
                                call.name = "shadow1D";
                        else if(type=="sampler2DShadow")
                                call.name = "shadow2D";
+                       else if(type=="sampler1DArray")
+                       {
+                               check_extension(EXT_texture_array);
+                               call.name = "texture1DArray";
+                       }
+                       else if(type=="sampler2DArray")
+                       {
+                               check_extension(EXT_texture_array);
+                               call.name = "texture2DArray";
+                       }
+                       else if(type=="sampler1DArrayShadow")
+                       {
+                               check_extension(EXT_texture_array);
+                               call.name = "shadow1DArray";
+                       }
+                       else if(type=="sampler2DArrayShadow")
+                       {
+                               check_extension(EXT_texture_array);
+                               call.name = "shadow2DArray";
+                       }
 
                        for(; i!=call.arguments.end(); ++i)
                                (*i)->visit(*this);