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