]> git.tdb.fi Git - libs/gl.git/blob - source/glsl/compatibility.cpp
Tweaks to visitor classes 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         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 void LegacyConverter::apply(Stage &s)
89 {
90         stage = &s;
91         visit(s.content);
92 }
93
94 bool LegacyConverter::check_version(const Version &feature_version) const
95 {
96         if(target_version<feature_version)
97                 return false;
98         else if(stage->required_version<feature_version)
99                 stage->required_version = feature_version;
100
101         return true;
102 }
103
104 bool LegacyConverter::check_extension(const Extension &extension) const
105 {
106         if(!extension)
107                 return false;
108
109         vector<const Extension *>::iterator i = find(stage->required_extensions, &extension);
110         if(i==stage->required_extensions.end())
111                 stage->required_extensions.push_back(&extension);
112
113         return true;
114 }
115
116 bool LegacyConverter::supports_unified_interface_syntax() const
117 {
118         if(target_api==OPENGL_ES2)
119                 return check_version(Version(3, 0));
120         else
121                 return check_version(Version(1, 30));
122 }
123
124 void LegacyConverter::visit(VariableReference &var)
125 {
126         if(var.declaration==frag_out && !supports_unified_interface_syntax())
127         {
128                 var.name = "gl_FragColor";
129                 var.declaration = 0;
130                 type = "vec4";
131         }
132         else if(var.declaration)
133                 type = var.declaration->type;
134         else
135                 type = string();
136 }
137
138 void LegacyConverter::visit(Assignment &assign)
139 {
140         TraversingVisitor::visit(assign);
141         if(assign.target_declaration==frag_out && !supports_unified_interface_syntax())
142                 assign.target_declaration = 0;
143 }
144
145 bool LegacyConverter::supports_unified_sampling_functions() const
146 {
147         if(target_api==OPENGL_ES2)
148                 return check_version(Version(3, 0));
149         else
150                 return check_version(Version(1, 30));
151 }
152
153 void LegacyConverter::visit(FunctionCall &call)
154 {
155         if(call.name=="texture")
156         {
157                 string sampler_type;
158                 type = string();
159                 NodeArray<Expression>::iterator i = call.arguments.begin();
160                 if(i!=call.arguments.end())
161                 {
162                         (*i)->visit(*this);
163                         sampler_type = type;
164
165                         for(; i!=call.arguments.end(); ++i)
166                                 (*i)->visit(*this);
167                 }
168
169                 if(!supports_unified_sampling_functions())
170                 {
171                         if(sampler_type=="sampler1D")
172                                 call.name = "texture1D";
173                         else if(sampler_type=="sampler2D")
174                                 call.name = "texture2D";
175                         else if(sampler_type=="sampler3D")
176                                 call.name = "texture3D";
177                         else if(sampler_type=="samplerCube")
178                                 call.name = "textureCube";
179                         else if(sampler_type=="sampler1DShadow")
180                                 call.name = "shadow1D";
181                         else if(sampler_type=="sampler2DShadow")
182                                 call.name = "shadow2D";
183                         else if(sampler_type=="sampler1DArray")
184                         {
185                                 check_extension(EXT_texture_array);
186                                 call.name = "texture1DArray";
187                         }
188                         else if(sampler_type=="sampler2DArray")
189                         {
190                                 check_extension(EXT_texture_array);
191                                 call.name = "texture2DArray";
192                         }
193                         else if(sampler_type=="sampler1DArrayShadow")
194                         {
195                                 check_extension(EXT_texture_array);
196                                 call.name = "shadow1DArray";
197                         }
198                         else if(sampler_type=="sampler2DArrayShadow")
199                         {
200                                 check_extension(EXT_texture_array);
201                                 call.name = "shadow2DArray";
202                         }
203                 }
204         }
205         else
206                 TraversingVisitor::visit(call);
207 }
208
209 bool LegacyConverter::supports_interface_layouts() const
210 {
211         if(target_api==OPENGL_ES2)
212                 return check_version(Version(3, 0));
213         else if(check_version(Version(3, 30)))
214                 return true;
215         else
216                 return check_extension(ARB_explicit_attrib_location);
217 }
218
219 bool LegacyConverter::supports_centroid_sampling() const
220 {
221         if(target_api==OPENGL_ES2)
222                 return check_version(Version(3, 0));
223         else if(check_version(Version(1, 20)))
224                 return true;
225         else
226                 return check_extension(EXT_gpu_shader4);
227 }
228
229 bool LegacyConverter::supports_sample_sampling() const
230 {
231         if(target_api==OPENGL_ES2)
232                 return check_version(Version(3, 20));
233         else if(check_version(Version(4, 0)))
234                 return true;
235         else
236                 return check_extension(ARB_gpu_shader5);
237 }
238
239 void LegacyConverter::visit(VariableDeclaration &var)
240 {
241         if(var.layout && !supports_interface_layouts())
242         {
243                 vector<Layout::Qualifier>::iterator i;
244                 for(i=var.layout->qualifiers.begin(); (i!=var.layout->qualifiers.end() && i->identifier!="location"); ++i) ;
245                 if(i!=var.layout->qualifiers.end())
246                 {
247                         unsigned location = lexical_cast<unsigned>(i->value);
248                         if(stage->type==Stage::VERTEX && var.interface=="in")
249                         {
250                                 stage->locations[var.name] = location;
251                                 var.layout->qualifiers.erase(i);
252                         }
253                         else if(stage->type==Stage::FRAGMENT && var.interface=="out")
254                         {
255                                 if(location!=0)
256                                         static Require _req(EXT_gpu_shader4);
257                                 stage->locations[var.name] = location;
258                                 var.layout->qualifiers.erase(i);
259                         }
260
261                         if(var.layout->qualifiers.empty())
262                                 var.layout = 0;
263                 }
264         }
265
266         if(var.sampling=="centroid")
267         {
268                 if(!supports_centroid_sampling())
269                         var.sampling = string();
270         }
271         else if(var.sampling=="sample")
272         {
273                 if(!supports_sample_sampling())
274                         var.sampling = string();
275         }
276
277         if((var.interface=="in" || var.interface=="out") && !supports_unified_interface_syntax())
278         {
279                 if(stage->type==Stage::FRAGMENT && var.interface=="out")
280                 {
281                         frag_out = &var;
282                         remove_node = true;
283                 }
284         }
285
286         TraversingVisitor::visit(var);
287 }
288
289 bool LegacyConverter::supports_interface_blocks(const string &iface) const
290 {
291         if(target_api==OPENGL_ES2)
292         {
293                 if(iface=="uniform")
294                         return check_version(Version(3, 0));
295                 else
296                         return check_version(Version(3, 20));
297         }
298         else if(check_version(Version(1, 50)))
299                 return true;
300         else if(iface=="uniform")
301                 return check_extension(ARB_uniform_buffer_object);
302         else
303                 return false;
304 }
305
306 void LegacyConverter::visit(InterfaceBlock &iface)
307 {
308         if(!supports_interface_blocks(iface.interface))
309                 flatten_block(iface.members);
310 }
311
312 } // namespace SL
313 } // namespace GL
314 } // namespace Msp