]> git.tdb.fi Git - libs/gl.git/blob - source/glsl/finalize.cpp
Fill in the required version if empty
[libs/gl.git] / source / glsl / finalize.cpp
1 #include <msp/core/algorithm.h>
2 #include <msp/core/raii.h>
3 #include <msp/strings/lexicalcast.h>
4 #include "finalize.h"
5 #include "glsl_error.h"
6
7 using namespace std;
8
9 namespace Msp {
10 namespace GL {
11 namespace SL {
12
13 PrecisionConverter::PrecisionConverter():
14         stage(0)
15 { }
16
17 void PrecisionConverter::apply(Stage &s)
18 {
19         stage = &s;
20         s.content.visit(*this);
21         NodeRemover().apply(s, nodes_to_remove);
22 }
23
24 void PrecisionConverter::visit(Block &block)
25 {
26         for(NodeList<Statement>::iterator i=block.body.begin(); i!=block.body.end(); ++i)
27         {
28                 if(&block==&stage->content)
29                         insert_point = i;
30                 (*i)->visit(*this);
31         }
32 }
33
34 void PrecisionConverter::visit(Precision &prec)
35 {
36         if(stage->required_features.gl_api==OPENGL_ES2)
37                 have_default.insert(prec.type);
38         else
39                 nodes_to_remove.insert(&prec);
40 }
41
42 void PrecisionConverter::visit(VariableDeclaration &var)
43 {
44         if(stage->required_features.gl_api!=OPENGL_ES2)
45         {
46                 var.precision.clear();
47                 return;
48         }
49
50         const char *default_prec = (stage->type==Stage::FRAGMENT ? "mediump" : "highp");
51         const TypeDeclaration *type = var.type_declaration;
52         while(type)
53         {
54                 if(dynamic_cast<const ImageTypeDeclaration *>(type))
55                 {
56                         default_prec = "lowp";
57                         break;
58                 }
59                 else if(const BasicTypeDeclaration *basic = dynamic_cast<const BasicTypeDeclaration *>(type))
60                 {
61                         if(basic->kind==BasicTypeDeclaration::INT || basic->kind==BasicTypeDeclaration::FLOAT)
62                                 break;
63                         type = basic->base_type;
64                 }
65                 else
66                         return;
67         }
68         if(!type)
69                 return;
70
71         if(!have_default.count(type->name))
72         {
73                 Precision *prec = new Precision;
74                 prec->precision = default_prec;
75                 prec->type = type->name;
76                 stage->content.body.insert(insert_point, prec);
77
78                 have_default.insert(type->name);
79         }
80 }
81
82
83 LegacyConverter::LegacyConverter():
84         frag_out(0)
85 { }
86
87 void LegacyConverter::apply(Stage &s, const Features &feat)
88 {
89         stage = &s;
90         features = feat;
91         if(supports_stage(s.type))
92         {
93                 s.content.visit(*this);
94
95                 if(!stage->required_features.glsl_version)
96                         stage->required_features.glsl_version = Version(1, (stage->required_features.gl_api==OPENGL_ES2 ? 0 : 10));
97         }
98         else
99                 unsupported(format("Stage %s is not supported", Stage::get_stage_name(s.type)));
100 }
101
102 void LegacyConverter::unsupported(const string &reason)
103 {
104         Diagnostic diagnostic;
105         diagnostic.severity = Diagnostic::ERR;
106         diagnostic.source = GENERATED_SOURCE;
107         diagnostic.line = 0;
108         diagnostic.message = reason;
109         stage->diagnostics.push_back(diagnostic);
110 }
111
112 void LegacyConverter::visit(Block &block)
113 {
114         for(NodeList<Statement>::iterator i=block.body.begin(); i!=block.body.end(); ++i)
115         {
116                 if(&block==&stage->content)
117                         uniform_insert_point = i;
118                 (*i)->visit(*this);
119         }
120 }
121
122 bool LegacyConverter::check_version(const Version &feature_version) const
123 {
124         if(features.glsl_version<feature_version)
125                 return false;
126         else if(stage->required_features.glsl_version<feature_version)
127                 stage->required_features.glsl_version = feature_version;
128
129         return true;
130 }
131
132 bool LegacyConverter::check_extension(bool Features::*extension) const
133 {
134         if(!(features.*extension))
135                 return false;
136
137         stage->required_features.*extension = true;
138
139         return true;
140 }
141
142 bool LegacyConverter::supports_stage(Stage::Type st) const
143 {
144         if(st==Stage::GEOMETRY)
145         {
146                 if(features.gl_api==OPENGL_ES2)
147                         return check_version(Version(3, 20));
148                 else
149                         return check_version(Version(1, 50));
150         }
151         else
152                 return true;
153 }
154
155 bool LegacyConverter::supports_unified_interface_syntax() const
156 {
157         if(features.gl_api==OPENGL_ES2)
158                 return check_version(Version(3, 0));
159         else
160                 return check_version(Version(1, 30));
161 }
162
163 void LegacyConverter::visit(VariableReference &var)
164 {
165         if(var.declaration==frag_out && !supports_unified_interface_syntax())
166         {
167                 var.name = "gl_FragColor";
168                 var.declaration = 0;
169                 r_type = "vec4";
170         }
171         else if(var.declaration)
172                 r_type = var.declaration->type;
173         else
174                 r_type.clear();
175 }
176
177 void LegacyConverter::visit(Assignment &assign)
178 {
179         TraversingVisitor::visit(assign);
180         if(assign.target.declaration==frag_out && !supports_unified_interface_syntax())
181                 assign.target.declaration = 0;
182 }
183
184 bool LegacyConverter::supports_unified_sampling_functions() const
185 {
186         if(features.gl_api==OPENGL_ES2)
187                 return check_version(Version(3, 0));
188         else
189                 return check_version(Version(1, 30));
190 }
191
192 void LegacyConverter::visit(FunctionCall &call)
193 {
194         if(call.name=="texture")
195         {
196                 string sampler_type;
197                 r_type.clear();
198                 NodeArray<Expression>::iterator i = call.arguments.begin();
199                 if(i!=call.arguments.end())
200                 {
201                         (*i)->visit(*this);
202                         sampler_type = r_type;
203
204                         for(; i!=call.arguments.end(); ++i)
205                                 (*i)->visit(*this);
206                 }
207
208                 if(!supports_unified_sampling_functions())
209                 {
210                         if(sampler_type=="sampler1D")
211                                 call.name = "texture1D";
212                         else if(sampler_type=="sampler2D")
213                                 call.name = "texture2D";
214                         else if(sampler_type=="sampler3D")
215                                 call.name = "texture3D";
216                         else if(sampler_type=="samplerCube")
217                                 call.name = "textureCube";
218                         else if(sampler_type=="sampler1DShadow")
219                                 call.name = "shadow1D";
220                         else if(sampler_type=="sampler2DShadow")
221                                 call.name = "shadow2D";
222                         else if(sampler_type=="sampler1DArray")
223                         {
224                                 check_extension(&Features::ext_texture_array);
225                                 call.name = "texture1DArray";
226                         }
227                         else if(sampler_type=="sampler2DArray")
228                         {
229                                 check_extension(&Features::ext_texture_array);
230                                 call.name = "texture2DArray";
231                         }
232                         else if(sampler_type=="sampler1DArrayShadow")
233                         {
234                                 check_extension(&Features::ext_texture_array);
235                                 call.name = "shadow1DArray";
236                         }
237                         else if(sampler_type=="sampler2DArrayShadow")
238                         {
239                                 check_extension(&Features::ext_texture_array);
240                                 call.name = "shadow2DArray";
241                         }
242                 }
243         }
244         else
245                 TraversingVisitor::visit(call);
246 }
247
248 bool LegacyConverter::supports_interface_layouts() const
249 {
250         if(features.gl_api==OPENGL_ES2)
251                 return check_version(Version(3, 0));
252         else if(check_version(Version(3, 30)))
253                 return true;
254         else
255                 return check_extension(&Features::arb_explicit_attrib_location);
256 }
257
258 bool LegacyConverter::supports_centroid_sampling() const
259 {
260         if(features.gl_api==OPENGL_ES2)
261                 return check_version(Version(3, 0));
262         else if(check_version(Version(1, 20)))
263                 return true;
264         else
265                 return check_extension(&Features::ext_gpu_shader4);
266 }
267
268 bool LegacyConverter::supports_sample_sampling() const
269 {
270         if(features.gl_api==OPENGL_ES2)
271                 return check_version(Version(3, 20));
272         else if(check_version(Version(4, 0)))
273                 return true;
274         else
275                 return check_extension(&Features::arb_gpu_shader5);
276 }
277
278 void LegacyConverter::visit(VariableDeclaration &var)
279 {
280         if(var.layout && !supports_interface_layouts())
281         {
282                 vector<Layout::Qualifier>::iterator i;
283                 for(i=var.layout->qualifiers.begin(); (i!=var.layout->qualifiers.end() && i->name!="location"); ++i) ;
284                 if(i!=var.layout->qualifiers.end())
285                 {
286                         if(stage->type==Stage::VERTEX && var.interface=="in")
287                         {
288                                 stage->locations[var.name] = i->value;
289                                 var.layout->qualifiers.erase(i);
290                         }
291                         else if(stage->type==Stage::FRAGMENT && var.interface=="out")
292                         {
293                                 if(check_extension(&Features::ext_gpu_shader4))
294                                         stage->locations[var.name] = i->value;
295                                 else if(i->value!=0)
296                                         unsupported("EXT_gpu_shader4 required for multiple fragment shader outputs");
297                                 var.layout->qualifiers.erase(i);
298                         }
299
300                         if(var.layout->qualifiers.empty())
301                                 var.layout = 0;
302                 }
303         }
304
305         if(var.sampling=="centroid")
306         {
307                 if(!supports_centroid_sampling())
308                         var.sampling = string();
309         }
310         else if(var.sampling=="sample")
311         {
312                 if(!supports_sample_sampling())
313                         var.sampling = string();
314         }
315
316         if((var.interface=="in" || var.interface=="out") && !supports_unified_interface_syntax())
317         {
318                 if(stage->type==Stage::FRAGMENT && var.interface=="out")
319                 {
320                         frag_out = &var;
321                         nodes_to_remove.insert(&var);
322                 }
323         }
324
325         TraversingVisitor::visit(var);
326 }
327
328 bool LegacyConverter::supports_interface_blocks(const string &iface) const
329 {
330         if(features.gl_api==OPENGL_ES2)
331         {
332                 if(iface=="uniform")
333                         return check_version(Version(3, 0));
334                 else
335                         return check_version(Version(3, 20));
336         }
337         else if(check_version(Version(1, 50)))
338                 return true;
339         else if(iface=="uniform")
340                 return check_extension(&Features::arb_uniform_buffer_object);
341         else
342                 return false;
343 }
344
345 void LegacyConverter::visit(InterfaceBlock &iface)
346 {
347         if(!supports_interface_blocks(iface.interface) && iface.type_declaration)
348         {
349                 if(!iface.instance_name.empty())
350                         unsupported("ARB_uniform_buffer_object required for interface block instances");
351                 else if(iface.struct_declaration)
352                 {
353                         stage->content.body.splice(uniform_insert_point, iface.struct_declaration->members.body);
354                         nodes_to_remove.insert(&iface);
355                         nodes_to_remove.insert(iface.struct_declaration);
356                 }
357                 else
358                         /* If the interface block is an array, it should have an instance
359                         name too, so this should never be reached */
360                         throw logic_error("Unexpected interface block configuration");
361         }
362 }
363
364 } // namespace SL
365 } // namespace GL
366 } // namespace Msp