]> git.tdb.fi Git - libs/gl.git/blob - source/glsl/compatibility.cpp
Adjust member access of the various visitors in the GLSL compiler
[libs/gl.git] / source / glsl / compatibility.cpp
1 #include <msp/core/algorithm.h>
2 #include <msp/core/raii.h>
3 #include <msp/gl/extensions/arb_explicit_attrib_location.h>
4 #include <msp/gl/extensions/arb_gpu_shader5.h>
5 #include <msp/gl/extensions/arb_uniform_buffer_object.h>
6 #include <msp/gl/extensions/ext_gpu_shader4.h>
7 #include <msp/gl/extensions/ext_texture_array.h>
8 #include "compatibility.h"
9
10 using namespace std;
11
12 namespace Msp {
13 namespace GL {
14 namespace SL {
15
16 DefaultPrecisionGenerator::DefaultPrecisionGenerator():
17         stage_type(Stage::SHARED),
18         toplevel(true)
19 { }
20
21 void DefaultPrecisionGenerator::apply(Stage &stage)
22 {
23         SetForScope<Stage::Type> set_stage(stage_type, stage.type);
24         visit(stage.content);
25 }
26
27 void DefaultPrecisionGenerator::visit(Block &block)
28 {
29         if(toplevel)
30         {
31                 SetForScope<bool> set(toplevel, false);
32                 BlockModifier::visit(block);
33         }
34         else
35                 TraversingVisitor::visit(block);
36 }
37
38 void DefaultPrecisionGenerator::visit(Precision &prec)
39 {
40         have_default.insert(prec.type);
41 }
42
43 void DefaultPrecisionGenerator::visit(VariableDeclaration &var)
44 {
45         if(var.type_declaration)
46                 return;
47
48         string type = var.type;
49         if(!type.compare(0, 3, "vec") || !type.compare(0, 3, "mat"))
50                 type = "float";
51         else if(!type.compare(0, 3, "ivec") || type=="uint")
52                 type = "int";
53
54         if(!have_default.count(type))
55         {
56                 Precision *prec = new Precision;
57                 if(!type.compare(0, 7, "sampler"))
58                         prec->precision = "lowp";
59                 else if(stage_type==Stage::FRAGMENT)
60                         prec->precision = "mediump";
61                 else
62                         prec->precision = "highp";
63                 prec->type = type;
64                 insert_nodes.push_back(prec);
65
66                 have_default.insert(type);
67         }
68 }
69
70
71 void PrecisionRemover::visit(Precision &)
72 {
73         remove_node = true;
74 }
75
76 void PrecisionRemover::visit(VariableDeclaration &var)
77 {
78         var.precision.clear();
79 }
80
81
82 LegacyConverter::LegacyConverter():
83         target_api(get_gl_api()),
84         target_version(get_glsl_version()),
85         frag_out(0)
86 { }
87
88 LegacyConverter::LegacyConverter(const Version &v):
89         target_api(get_gl_api()),
90         target_version(v),
91         frag_out(0)
92 { }
93
94 void LegacyConverter::apply(Stage &s)
95 {
96         SetForScope<Stage *> set_stage(stage, &s);
97         visit(s.content);
98 }
99
100 bool LegacyConverter::check_version(const Version &feature_version) const
101 {
102         if(target_version<feature_version)
103                 return false;
104         else if(stage->required_version<feature_version)
105                 stage->required_version = feature_version;
106
107         return true;
108 }
109
110 bool LegacyConverter::check_extension(const Extension &extension) const
111 {
112         if(!extension)
113                 return false;
114
115         vector<const Extension *>::iterator i = find(stage->required_extensions, &extension);
116         if(i==stage->required_extensions.end())
117                 stage->required_extensions.push_back(&extension);
118
119         return true;
120 }
121
122 bool LegacyConverter::supports_unified_interface_syntax() const
123 {
124         if(target_api==OPENGL_ES2)
125                 return check_version(Version(3, 0));
126         else
127                 return check_version(Version(1, 30));
128 }
129
130 void LegacyConverter::visit(VariableReference &var)
131 {
132         if(var.declaration==frag_out && !supports_unified_interface_syntax())
133         {
134                 var.name = "gl_FragColor";
135                 var.declaration = 0;
136                 type = "vec4";
137         }
138         else if(var.declaration)
139                 type = var.declaration->type;
140         else
141                 type = string();
142 }
143
144 void LegacyConverter::visit(Assignment &assign)
145 {
146         TraversingVisitor::visit(assign);
147         if(assign.target_declaration==frag_out && !supports_unified_interface_syntax())
148                 assign.target_declaration = 0;
149 }
150
151 bool LegacyConverter::supports_unified_sampling_functions() const
152 {
153         if(target_api==OPENGL_ES2)
154                 return check_version(Version(3, 0));
155         else
156                 return check_version(Version(1, 30));
157 }
158
159 void LegacyConverter::visit(FunctionCall &call)
160 {
161         if(call.name=="texture")
162         {
163                 string sampler_type;
164                 type = string();
165                 NodeArray<Expression>::iterator i = call.arguments.begin();
166                 if(i!=call.arguments.end())
167                 {
168                         (*i)->visit(*this);
169                         sampler_type = type;
170
171                         for(; i!=call.arguments.end(); ++i)
172                                 (*i)->visit(*this);
173                 }
174
175                 if(!supports_unified_sampling_functions())
176                 {
177                         if(sampler_type=="sampler1D")
178                                 call.name = "texture1D";
179                         else if(sampler_type=="sampler2D")
180                                 call.name = "texture2D";
181                         else if(sampler_type=="sampler3D")
182                                 call.name = "texture3D";
183                         else if(sampler_type=="samplerCube")
184                                 call.name = "textureCube";
185                         else if(sampler_type=="sampler1DShadow")
186                                 call.name = "shadow1D";
187                         else if(sampler_type=="sampler2DShadow")
188                                 call.name = "shadow2D";
189                         else if(sampler_type=="sampler1DArray")
190                         {
191                                 check_extension(EXT_texture_array);
192                                 call.name = "texture1DArray";
193                         }
194                         else if(sampler_type=="sampler2DArray")
195                         {
196                                 check_extension(EXT_texture_array);
197                                 call.name = "texture2DArray";
198                         }
199                         else if(sampler_type=="sampler1DArrayShadow")
200                         {
201                                 check_extension(EXT_texture_array);
202                                 call.name = "shadow1DArray";
203                         }
204                         else if(sampler_type=="sampler2DArrayShadow")
205                         {
206                                 check_extension(EXT_texture_array);
207                                 call.name = "shadow2DArray";
208                         }
209                 }
210         }
211         else
212                 TraversingVisitor::visit(call);
213 }
214
215 bool LegacyConverter::supports_interface_layouts() const
216 {
217         if(target_api==OPENGL_ES2)
218                 return check_version(Version(3, 0));
219         else if(check_version(Version(3, 30)))
220                 return true;
221         else
222                 return check_extension(ARB_explicit_attrib_location);
223 }
224
225 bool LegacyConverter::supports_centroid_sampling() const
226 {
227         if(target_api==OPENGL_ES2)
228                 return check_version(Version(3, 0));
229         else if(check_version(Version(1, 20)))
230                 return true;
231         else
232                 return check_extension(EXT_gpu_shader4);
233 }
234
235 bool LegacyConverter::supports_sample_sampling() const
236 {
237         if(target_api==OPENGL_ES2)
238                 return check_version(Version(3, 20));
239         else if(check_version(Version(4, 0)))
240                 return true;
241         else
242                 return check_extension(ARB_gpu_shader5);
243 }
244
245 void LegacyConverter::visit(VariableDeclaration &var)
246 {
247         if(var.layout && !supports_interface_layouts())
248         {
249                 vector<Layout::Qualifier>::iterator i;
250                 for(i=var.layout->qualifiers.begin(); (i!=var.layout->qualifiers.end() && i->identifier!="location"); ++i) ;
251                 if(i!=var.layout->qualifiers.end())
252                 {
253                         unsigned location = lexical_cast<unsigned>(i->value);
254                         if(stage->type==Stage::VERTEX && var.interface=="in")
255                         {
256                                 stage->locations[var.name] = location;
257                                 var.layout->qualifiers.erase(i);
258                         }
259                         else if(stage->type==Stage::FRAGMENT && var.interface=="out")
260                         {
261                                 if(location!=0)
262                                         static Require _req(EXT_gpu_shader4);
263                                 stage->locations[var.name] = location;
264                                 var.layout->qualifiers.erase(i);
265                         }
266
267                         if(var.layout->qualifiers.empty())
268                                 var.layout = 0;
269                 }
270         }
271
272         if(var.sampling=="centroid")
273         {
274                 if(!supports_centroid_sampling())
275                         var.sampling = string();
276         }
277         else if(var.sampling=="sample")
278         {
279                 if(!supports_sample_sampling())
280                         var.sampling = string();
281         }
282
283         if((var.interface=="in" || var.interface=="out") && !supports_unified_interface_syntax())
284         {
285                 if(stage->type==Stage::FRAGMENT && var.interface=="out")
286                 {
287                         frag_out = &var;
288                         remove_node = true;
289                 }
290         }
291
292         TraversingVisitor::visit(var);
293 }
294
295 bool LegacyConverter::supports_interface_blocks(const string &iface) const
296 {
297         if(target_api==OPENGL_ES2)
298         {
299                 if(iface=="uniform")
300                         return check_version(Version(3, 0));
301                 else
302                         return check_version(Version(3, 20));
303         }
304         else if(check_version(Version(1, 50)))
305                 return true;
306         else if(iface=="uniform")
307                 return check_extension(ARB_uniform_buffer_object);
308         else
309                 return false;
310 }
311
312 void LegacyConverter::visit(InterfaceBlock &iface)
313 {
314         if(!supports_interface_blocks(iface.interface))
315                 flatten_block(iface.members);
316 }
317
318 } // namespace SL
319 } // namespace GL
320 } // namespace Msp