]> git.tdb.fi Git - libs/gl.git/blob - source/glsl/compiler.cpp
Rearrange secondary operations in GLSL compiler
[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 "compatibility.h"
5 #include "compiler.h"
6 #include "error.h"
7 #include "generate.h"
8 #include "optimize.h"
9 #include "output.h"
10 #include "resources.h"
11 #include "shader.h"
12
13 #undef interface
14
15 using namespace std;
16
17 namespace Msp {
18 namespace GL {
19 namespace SL {
20
21 Compiler::Compiler():
22         module(0)
23 { }
24
25 Compiler::~Compiler()
26 {
27         delete module;
28 }
29
30 void Compiler::clear()
31 {
32         delete module;
33         module = new Module();
34         imported_names.clear();
35         module->source_map.set_name(0, "<generated>");
36 }
37
38 void Compiler::set_source(const string &source, const string &src_name)
39 {
40         clear();
41         Parser parser;
42         imported_names.push_back(src_name);
43         append_module(parser.parse(source, src_name, 1), 0);
44 }
45
46 void Compiler::load_source(IO::Base &io, DataFile::Collection *res, const string &src_name)
47 {
48         clear();
49         Parser parser;
50         imported_names.push_back(src_name);
51         append_module(parser.parse(io, src_name, 1), res);
52 }
53
54 void Compiler::load_source(IO::Base &io, const string &src_name)
55 {
56         load_source(io, 0, src_name);
57 }
58
59 void Compiler::compile()
60 {
61         for(list<Stage>::iterator i=module->stages.begin(); i!=module->stages.end(); ++i)
62                 generate(*i);
63         for(list<Stage>::iterator i=module->stages.begin(); i!=module->stages.end(); )
64         {
65                 if(optimize(*i))
66                         i = module->stages.begin();
67                 else
68                         ++i;
69         }
70         for(list<Stage>::iterator i=module->stages.begin(); i!=module->stages.end(); ++i)
71                 finalize(*i);
72 }
73
74 void Compiler::add_shaders(Program &program)
75 {
76         if(!module)
77                 throw invalid_operation("Compiler::add_shaders");
78
79         try
80         {
81                 for(list<Stage>::iterator i=module->stages.begin(); i!=module->stages.end(); ++i)
82                 {
83                         string stage_src = Formatter().apply(*i);
84
85                         if(i->type==Stage::VERTEX)
86                         {
87                                 program.attach_shader_owned(new VertexShader(stage_src));
88                                 for(map<string, unsigned>::iterator j=i->locations.begin(); j!=i->locations.end(); ++j)
89                                         program.bind_attribute(j->second, j->first);
90                         }
91                         else if(i->type==Stage::GEOMETRY)
92                                 program.attach_shader_owned(new GeometryShader(stage_src));
93                         else if(i->type==Stage::FRAGMENT)
94                         {
95                                 program.attach_shader_owned(new FragmentShader(stage_src));
96                                 if(EXT_gpu_shader4)
97                                 {
98                                         for(map<string, unsigned>::iterator j=i->locations.begin(); j!=i->locations.end(); ++j)
99                                                 program.bind_fragment_data(j->second, j->first);
100                                 }
101                         }
102                 }
103         }
104         catch(const compile_error &e)
105         {
106                 throw compile_error(module->source_map.translate_errors(e.what()));
107         }
108 }
109
110 void Compiler::append_module(Module &mod, DataFile::Collection *res)
111 {
112         module->source_map.merge_from(mod.source_map);
113
114         vector<Import *> imports = NodeGatherer<Import>().apply(mod.shared);
115         for(vector<Import *>::iterator i=imports.begin(); i!=imports.end(); ++i)
116                 import(res, (*i)->module);
117         NodeRemover().apply(mod.shared, set<Node *>(imports.begin(), imports.end()));
118
119         append_stage(mod.shared);
120         for(list<Stage>::iterator i=mod.stages.begin(); i!=mod.stages.end(); ++i)
121                 append_stage(*i);
122 }
123
124 void Compiler::append_stage(Stage &stage)
125 {
126         Stage *target = 0;
127         if(stage.type==Stage::SHARED)
128                 target = &module->shared;
129         else
130         {
131                 list<Stage>::iterator i;
132                 for(i=module->stages.begin(); (i!=module->stages.end() && i->type<stage.type); ++i) ;
133                 if(i==module->stages.end() || i->type>stage.type)
134                 {
135                         list<Stage>::iterator j = module->stages.insert(i, stage.type);
136                         if(i!=module->stages.end())
137                                 i->previous = &*j;
138                         i = j;
139                         if(i!=module->stages.begin())
140                                 i->previous = &*--j;
141                 }
142
143                 target = &*i;
144         }
145
146         if(stage.required_version>target->required_version)
147                 target->required_version = stage.required_version;
148         for(NodeList<Statement>::iterator i=stage.content.body.begin(); i!=stage.content.body.end(); ++i)
149                 target->content.body.push_back(*i);
150         DeclarationCombiner().apply(*target);
151 }
152
153 void Compiler::import(DataFile::Collection *resources, const string &name)
154 {
155         string fn = name+".glsl";
156         if(find(imported_names, fn)!=imported_names.end())
157                 return;
158         imported_names.push_back(fn);
159
160         RefPtr<IO::Seekable> io = (resources ? resources->open_raw(fn) : Resources::get_builtins().open(fn));
161         if(!io)
162                 throw runtime_error(format("module %s not found", name));
163         Parser import_parser;
164         append_module(import_parser.parse(*io, fn, module->source_map.get_count()), resources);
165 }
166
167 void Compiler::generate(Stage &stage)
168 {
169         if(module->shared.required_version>stage.required_version)
170                 stage.required_version = module->shared.required_version;
171         inject_block(stage.content, module->shared.content);
172
173         DeclarationReorderer().apply(stage);
174         FunctionResolver().apply(stage);
175         VariableResolver().apply(stage);
176         InterfaceGenerator().apply(stage);
177         VariableResolver().apply(stage);
178         DeclarationReorderer().apply(stage);
179         FunctionResolver().apply(stage);
180         LegacyConverter().apply(stage);
181 }
182
183 bool Compiler::optimize(Stage &stage)
184 {
185         ConstantConditionEliminator().apply(stage);
186
187         FunctionInliner().apply(stage);
188
189         bool result = UnusedVariableRemover().apply(stage);
190         result |= UnusedFunctionRemover().apply(stage);
191
192         return result;
193 }
194
195 void Compiler::finalize(Stage &stage)
196 {
197         if(get_gl_api()==OPENGL_ES2)
198                 DefaultPrecisionGenerator().apply(stage);
199         else
200                 PrecisionRemover().apply(stage);
201 }
202
203 void Compiler::inject_block(Block &target, const Block &source)
204 {
205         NodeList<Statement>::iterator insert_point = target.body.begin();
206         for(NodeList<Statement>::const_iterator i=source.body.begin(); i!=source.body.end(); ++i)
207                 target.body.insert(insert_point, (*i)->clone());
208 }
209
210 } // namespace SL
211 } // namespace GL
212 } // namespace Msp