]> git.tdb.fi Git - libs/gl.git/blob - source/glsl/compiler.cpp
Redesign the way shader programs are loaded
[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(Mode mode)
60 {
61         for(list<Stage>::iterator i=module->stages.begin(); i!=module->stages.end(); ++i)
62                 generate(*i, mode);
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, mode);
72 }
73
74 string Compiler::get_combined_glsl() const
75 {
76         string glsl;
77
78         unsigned source_count = module->source_map.get_count();
79         for(unsigned i=1; i<source_count; ++i)
80                 glsl += format("#pragma MSP source(%d, \"%s\")\n", i, module->source_map.get_name(i));
81         for(list<Stage>::iterator i=module->stages.begin(); i!=module->stages.end(); ++i)
82         {
83                 glsl += format("#pragma MSP stage(%s)\n", Stage::get_stage_name(i->type));
84                 glsl += Formatter().apply(*i, MODULE);
85                 glsl += '\n';
86         }
87
88         return glsl;
89 }
90
91 vector<Stage::Type> Compiler::get_stages() const
92 {
93         vector<Stage::Type> stage_types;
94         stage_types.reserve(module->stages.size());
95         for(list<Stage>::const_iterator i=module->stages.begin(); i!=module->stages.end(); ++i)
96                 stage_types.push_back(i->type);
97         return stage_types;
98 }
99
100 string Compiler::get_stage_glsl(Stage::Type stage_type) const
101 {
102         for(list<Stage>::iterator i=module->stages.begin(); i!=module->stages.end(); ++i)
103                 if(i->type==stage_type)
104                         return Formatter().apply(*i, PROGRAM);
105         throw key_error(Stage::get_stage_name(stage_type));
106 }
107
108 const map<string, unsigned> &Compiler::get_vertex_attributes() const
109 {
110         for(list<Stage>::const_iterator i=module->stages.begin(); i!=module->stages.end(); ++i)
111                 if(i->type==Stage::VERTEX)
112                         return i->locations;
113         throw invalid_operation("Compiler::get_vertex_attributes");
114 }
115
116 const map<string, unsigned> &Compiler::get_fragment_outputs() const
117 {
118         for(list<Stage>::const_iterator i=module->stages.begin(); i!=module->stages.end(); ++i)
119                 if(i->type==Stage::FRAGMENT)
120                         return i->locations;
121         throw invalid_operation("Compiler::get_fragment_outputs");
122 }
123
124 const SourceMap &Compiler::get_source_map() const
125 {
126         return module->source_map;
127 }
128
129 void Compiler::append_module(Module &mod, DataFile::Collection *res)
130 {
131         module->source_map.merge_from(mod.source_map);
132
133         vector<Import *> imports = NodeGatherer<Import>().apply(mod.shared);
134         for(vector<Import *>::iterator i=imports.begin(); i!=imports.end(); ++i)
135                 import(res, (*i)->module);
136         NodeRemover().apply(mod.shared, set<Node *>(imports.begin(), imports.end()));
137
138         append_stage(mod.shared);
139         for(list<Stage>::iterator i=mod.stages.begin(); i!=mod.stages.end(); ++i)
140                 append_stage(*i);
141 }
142
143 void Compiler::append_stage(Stage &stage)
144 {
145         Stage *target = 0;
146         if(stage.type==Stage::SHARED)
147                 target = &module->shared;
148         else
149         {
150                 list<Stage>::iterator i;
151                 for(i=module->stages.begin(); (i!=module->stages.end() && i->type<stage.type); ++i) ;
152                 if(i==module->stages.end() || i->type>stage.type)
153                 {
154                         list<Stage>::iterator j = module->stages.insert(i, stage.type);
155                         if(i!=module->stages.end())
156                                 i->previous = &*j;
157                         i = j;
158                         if(i!=module->stages.begin())
159                                 i->previous = &*--j;
160                 }
161
162                 target = &*i;
163         }
164
165         if(stage.required_version>target->required_version)
166                 target->required_version = stage.required_version;
167         for(NodeList<Statement>::iterator i=stage.content.body.begin(); i!=stage.content.body.end(); ++i)
168                 target->content.body.push_back(*i);
169         DeclarationCombiner().apply(*target);
170 }
171
172 void Compiler::import(DataFile::Collection *resources, const string &name)
173 {
174         string fn = name+".glsl";
175         if(find(imported_names, fn)!=imported_names.end())
176                 return;
177         imported_names.push_back(fn);
178
179         RefPtr<IO::Seekable> io = (resources ? resources->open_raw(fn) : Resources::get_builtins().open(fn));
180         if(!io)
181                 throw runtime_error(format("module %s not found", name));
182         Parser import_parser;
183         append_module(import_parser.parse(*io, fn, module->source_map.get_count()), resources);
184 }
185
186 void Compiler::generate(Stage &stage, Mode mode)
187 {
188         if(module->shared.required_version>stage.required_version)
189                 stage.required_version = module->shared.required_version;
190         inject_block(stage.content, module->shared.content);
191
192         DeclarationReorderer().apply(stage);
193         BlockResolver().apply(stage);
194         FunctionResolver().apply(stage);
195         VariableResolver().apply(stage);
196         InterfaceGenerator().apply(stage);
197         VariableResolver().apply(stage);
198         DeclarationReorderer().apply(stage);
199         FunctionResolver().apply(stage);
200         if(mode==PROGRAM)
201                 LegacyConverter().apply(stage);
202 }
203
204 bool Compiler::optimize(Stage &stage)
205 {
206         ConstantConditionEliminator().apply(stage);
207
208         FunctionInliner().apply(stage);
209         BlockResolver().apply(stage);
210         VariableResolver().apply(stage);
211
212         bool result = UnusedVariableRemover().apply(stage);
213         result |= UnusedFunctionRemover().apply(stage);
214
215         return result;
216 }
217
218 void Compiler::finalize(Stage &stage, Mode mode)
219 {
220         if(get_gl_api()==OPENGL_ES2 && mode==PROGRAM)
221                 DefaultPrecisionGenerator().apply(stage);
222         else if(mode==MODULE)
223                 PrecisionRemover().apply(stage);
224 }
225
226 void Compiler::inject_block(Block &target, const Block &source)
227 {
228         NodeList<Statement>::iterator insert_point = target.body.begin();
229         for(NodeList<Statement>::const_iterator i=source.body.begin(); i!=source.body.end(); ++i)
230                 target.body.insert(insert_point, (*i)->clone());
231 }
232
233 } // namespace SL
234 } // namespace GL
235 } // namespace Msp