]> git.tdb.fi Git - libs/gl.git/blob - source/glsl/compiler.cpp
21060cb4b783975f72da2a039de2f6a07b86888f
[libs/gl.git] / source / glsl / compiler.cpp
1 #include <msp/core/algorithm.h>
2 #include <msp/gl/extensions/ext_gpu_shader4.h>
3 #include <msp/strings/format.h>
4 #include <msp/strings/regex.h>
5 #include <msp/strings/utils.h>
6 #include "compatibility.h"
7 #include "compiler.h"
8 #include "error.h"
9 #include "generate.h"
10 #include "optimize.h"
11 #include "output.h"
12 #include "shader.h"
13
14 #undef interface
15
16 using namespace std;
17
18 namespace Msp {
19 namespace GL {
20 namespace SL {
21
22 Compiler::Compiler():
23         resources(0),
24         module(0)
25 { }
26
27 Compiler::~Compiler()
28 {
29         delete module;
30 }
31
32 void Compiler::compile(const string &source, const string &src_name)
33 {
34         resources = 0;
35         delete module;
36         module = new Module();
37         Parser parser;
38         imported_names.push_back(src_name);
39         append_module(parser.parse(source, src_name, 1));
40         process();
41 }
42
43 void Compiler::compile(IO::Base &io, Resources *res, const string &src_name)
44 {
45         resources = res;
46         delete module;
47         module = new Module();
48         Parser parser;
49         imported_names.push_back(src_name);
50         append_module(parser.parse(io, src_name, 1));
51         process();
52 }
53
54 void Compiler::compile(IO::Base &io, const string &src_name)
55 {
56         compile(io, 0, src_name);
57 }
58
59 void Compiler::add_shaders(Program &program)
60 {
61         if(!module)
62                 throw invalid_operation("Compiler::add_shaders");
63
64         try
65         {
66                 for(list<Stage>::iterator i=module->stages.begin(); i!=module->stages.end(); ++i)
67                 {
68                         string stage_src = Formatter().apply(*i);
69
70                         if(i->type==Stage::VERTEX)
71                         {
72                                 program.attach_shader_owned(new VertexShader(stage_src));
73                                 for(map<string, unsigned>::iterator j=i->locations.begin(); j!=i->locations.end(); ++j)
74                                         program.bind_attribute(j->second, j->first);
75                         }
76                         else if(i->type==Stage::GEOMETRY)
77                                 program.attach_shader_owned(new GeometryShader(stage_src));
78                         else if(i->type==Stage::FRAGMENT)
79                         {
80                                 program.attach_shader_owned(new FragmentShader(stage_src));
81                                 if(EXT_gpu_shader4)
82                                 {
83                                         for(map<string, unsigned>::iterator j=i->locations.begin(); j!=i->locations.end(); ++j)
84                                                 program.bind_fragment_data(j->second, j->first);
85                                 }
86                         }
87                 }
88         }
89         catch(const compile_error &e)
90         {
91                 static const Regex r_message("^(([0-9]+)\\(([0-9]+)\\) :|ERROR: ([0-9]+):([0-9]+):) (.*)$");
92                 vector<string> lines = split(e.what(), '\n');
93                 string translated;
94                 for(vector<string>::const_iterator i=lines.begin(); i!=lines.end(); ++i)
95                 {
96                         RegMatch m = r_message.match(*i);
97                         if(m)
98                         {
99                                 unsigned index = 0;
100                                 unsigned line = 0;
101                                 if(m[2])
102                                 {
103                                         index = lexical_cast<unsigned>(m[2].str);
104                                         line = lexical_cast<unsigned>(m[3].str);
105                                 }
106                                 else if(m[4])
107                                 {
108                                         index = lexical_cast<unsigned>(m[4].str);
109                                         line = lexical_cast<unsigned>(m[5].str);
110                                 }
111                                 const char *src = "<unknown>";
112                                 if(index==0)
113                                         src = "<generated>";
114                                 else if(index-1<imported_names.size())
115                                         src = imported_names[index-1].c_str();
116                                 translated += format("%s:%d: %s", src, line, m[6].str);
117                         }
118                         else
119                                 translated += *i;
120                         translated += '\n';
121                 }
122
123                 throw compile_error(translated);
124         }
125 }
126
127 void Compiler::append_module(Module &mod)
128 {
129         vector<Import *> imports = NodeGatherer<Import>().apply(mod.shared);
130         for(vector<Import *>::iterator i=imports.begin(); i!=imports.end(); ++i)
131                 import((*i)->module);
132         NodeRemover(set<Node *>(imports.begin(), imports.end())).apply(mod.shared);
133
134         append_stage(mod.shared);
135         for(list<Stage>::iterator i=mod.stages.begin(); i!=mod.stages.end(); ++i)
136                 append_stage(*i);
137 }
138
139 void Compiler::append_stage(Stage &stage)
140 {
141         Stage *target = 0;
142         if(stage.type==Stage::SHARED)
143                 target = &module->shared;
144         else
145         {
146                 list<Stage>::iterator i;
147                 for(i=module->stages.begin(); (i!=module->stages.end() && i->type<stage.type); ++i) ;
148                 if(i==module->stages.end() || i->type>stage.type)
149                 {
150                         list<Stage>::iterator j = module->stages.insert(i, stage.type);
151                         if(i!=module->stages.end())
152                                 i->previous = &*j;
153                         i = j;
154                         if(i!=module->stages.begin())
155                                 i->previous = &*--j;
156                 }
157
158                 target = &*i;
159         }
160
161         if(stage.required_version>target->required_version)
162                 target->required_version = stage.required_version;
163         for(NodeList<Statement>::iterator i=stage.content.body.begin(); i!=stage.content.body.end(); ++i)
164                 target->content.body.push_back(*i);
165         DeclarationCombiner().apply(*target);
166 }
167
168 void Compiler::process()
169 {
170         for(list<Stage>::iterator i=module->stages.begin(); i!=module->stages.end(); ++i)
171                 generate(*i);
172         for(list<Stage>::iterator i=module->stages.begin(); i!=module->stages.end(); )
173         {
174                 if(optimize(*i))
175                         i = module->stages.begin();
176                 else
177                         ++i;
178         }
179         for(list<Stage>::iterator i=module->stages.begin(); i!=module->stages.end(); ++i)
180                 finalize(*i);
181 }
182
183 void Compiler::import(const string &name)
184 {
185         string fn = name+".glsl";
186         if(find(imported_names, fn)!=imported_names.end())
187                 return;
188         imported_names.push_back(fn);
189
190         RefPtr<IO::Seekable> io = (resources ? resources->open_raw(fn) : Resources::get_builtins().open(fn));
191         if(!io)
192                 throw runtime_error(format("module %s not found", name));
193         Parser import_parser;
194         append_module(import_parser.parse(*io, fn, imported_names.size()));
195 }
196
197 void Compiler::generate(Stage &stage)
198 {
199         if(module->shared.required_version>stage.required_version)
200                 stage.required_version = module->shared.required_version;
201         inject_block(stage.content, module->shared.content);
202
203         DeclarationReorderer().apply(stage);
204         FunctionResolver().apply(stage);
205         VariableResolver().apply(stage);
206         InterfaceGenerator().apply(stage);
207         VariableResolver().apply(stage);
208         DeclarationReorderer().apply(stage);
209         FunctionResolver().apply(stage);
210         LegacyConverter().apply(stage);
211 }
212
213 bool Compiler::optimize(Stage &stage)
214 {
215         ConstantConditionEliminator().apply(stage);
216
217         set<FunctionDeclaration *> inlineable = InlineableFunctionLocator().apply(stage);
218         FunctionInliner(inlineable).apply(stage);
219
220         set<Node *> unused = UnusedVariableLocator().apply(stage);
221         set<Node *> unused2 = UnusedFunctionLocator().apply(stage);
222         unused.insert(unused2.begin(), unused2.end());
223         NodeRemover(unused).apply(stage);
224
225         return !unused.empty();
226 }
227
228 void Compiler::finalize(Stage &stage)
229 {
230         if(get_gl_api()==OPENGL_ES2)
231                 DefaultPrecisionGenerator().apply(stage);
232         else
233                 PrecisionRemover().apply(stage);
234 }
235
236 void Compiler::inject_block(Block &target, const Block &source)
237 {
238         NodeList<Statement>::iterator insert_point = target.body.begin();
239         for(NodeList<Statement>::const_iterator i=source.body.begin(); i!=source.body.end(); ++i)
240                 target.body.insert(insert_point, (*i)->clone());
241 }
242
243 } // namespace SL
244 } // namespace GL
245 } // namespace Msp