]> git.tdb.fi Git - libs/gl.git/blob - source/glsl/compatibility.cpp
Split SL::Compiler into several files
[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==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" && !call.declaration && !supports_unified_sampling_functions())
149         {
150                 NodeArray<Expression>::iterator i = call.arguments.begin();
151                 if(i!=call.arguments.end())
152                 {
153                         (*i)->visit(*this);
154                         if(type=="sampler1D")
155                                 call.name = "texture1D";
156                         else if(type=="sampler2D")
157                                 call.name = "texture2D";
158                         else if(type=="sampler3D")
159                                 call.name = "texture3D";
160                         else if(type=="samplerCube")
161                                 call.name = "textureCube";
162                         else if(type=="sampler1DShadow")
163                                 call.name = "shadow1D";
164                         else if(type=="sampler2DShadow")
165                                 call.name = "shadow2D";
166                         else if(type=="sampler1DArray")
167                         {
168                                 check_extension(EXT_texture_array);
169                                 call.name = "texture1DArray";
170                         }
171                         else if(type=="sampler2DArray")
172                         {
173                                 check_extension(EXT_texture_array);
174                                 call.name = "texture2DArray";
175                         }
176                         else if(type=="sampler1DArrayShadow")
177                         {
178                                 check_extension(EXT_texture_array);
179                                 call.name = "shadow1DArray";
180                         }
181                         else if(type=="sampler2DArrayShadow")
182                         {
183                                 check_extension(EXT_texture_array);
184                                 call.name = "shadow2DArray";
185                         }
186
187                         for(; i!=call.arguments.end(); ++i)
188                                 (*i)->visit(*this);
189                 }
190         }
191         else
192                 TraversingVisitor::visit(call);
193 }
194
195 bool LegacyConverter::supports_interface_layouts() const
196 {
197         if(target_api==OPENGL_ES2)
198                 return check_version(Version(3, 0));
199         else if(check_version(Version(3, 30)))
200                 return true;
201         else
202                 return check_extension(ARB_explicit_attrib_location);
203 }
204
205 bool LegacyConverter::supports_centroid_sampling() const
206 {
207         if(target_api==OPENGL_ES2)
208                 return check_version(Version(3, 0));
209         else if(check_version(Version(1, 20)))
210                 return true;
211         else
212                 return check_extension(EXT_gpu_shader4);
213 }
214
215 bool LegacyConverter::supports_sample_sampling() const
216 {
217         if(target_api==OPENGL_ES2)
218                 return check_version(Version(3, 20));
219         else if(check_version(Version(4, 0)))
220                 return true;
221         else
222                 return check_extension(ARB_gpu_shader5);
223 }
224
225 void LegacyConverter::visit(VariableDeclaration &var)
226 {
227         if(var.layout && !supports_interface_layouts())
228         {
229                 vector<Layout::Qualifier>::iterator i;
230                 for(i=var.layout->qualifiers.begin(); (i!=var.layout->qualifiers.end() && i->identifier!="location"); ++i) ;
231                 if(i!=var.layout->qualifiers.end())
232                 {
233                         unsigned location = lexical_cast<unsigned>(i->value);
234                         if(stage->type==VERTEX && var.interface=="in")
235                         {
236                                 stage->locations[var.name] = location;
237                                 var.layout->qualifiers.erase(i);
238                         }
239                         else if(stage->type==FRAGMENT && var.interface=="out")
240                         {
241                                 if(location!=0)
242                                         static Require _req(EXT_gpu_shader4);
243                                 stage->locations[var.name] = location;
244                                 var.layout->qualifiers.erase(i);
245                         }
246
247                         if(var.layout->qualifiers.empty())
248                                 var.layout = 0;
249                 }
250         }
251
252         if(var.sampling=="centroid")
253         {
254                 if(!supports_centroid_sampling())
255                         var.sampling = string();
256         }
257         else if(var.sampling=="sample")
258         {
259                 if(!supports_sample_sampling())
260                         var.sampling = string();
261         }
262
263         if((var.interface=="in" || var.interface=="out") && !supports_unified_interface_syntax())
264         {
265                 if(stage->type==FRAGMENT && var.interface=="out")
266                 {
267                         frag_out = &var;
268                         remove_node = true;
269                 }
270         }
271
272         TraversingVisitor::visit(var);
273 }
274
275 bool LegacyConverter::supports_interface_blocks(const string &iface) const
276 {
277         if(target_api==OPENGL_ES2)
278         {
279                 if(iface=="uniform")
280                         return check_version(Version(3, 0));
281                 else
282                         return check_version(Version(3, 20));
283         }
284         else if(check_version(Version(1, 50)))
285                 return true;
286         else if(iface=="uniform")
287                 return check_extension(ARB_uniform_buffer_object);
288         else
289                 return false;
290 }
291
292 void LegacyConverter::visit(InterfaceBlock &iface)
293 {
294         if(!supports_interface_blocks(iface.interface))
295                 flatten_block(iface.members);
296 }
297
298 } // namespace SL
299 } // namespace GL
300 } // namespace Msp