1 #include <msp/core/algorithm.h>
2 #include <msp/core/raii.h>
3 #include <msp/strings/lexicalcast.h>
4 #include "compatibility.h"
5 #include "glsl_error.h"
13 DefaultPrecisionGenerator::DefaultPrecisionGenerator():
17 void DefaultPrecisionGenerator::apply(Stage &s)
20 s.content.visit(*this);
23 void DefaultPrecisionGenerator::visit(Block &block)
25 for(NodeList<Statement>::iterator i=block.body.begin(); i!=block.body.end(); ++i)
27 if(&block==&stage->content)
33 void DefaultPrecisionGenerator::visit(Precision &prec)
35 have_default.insert(prec.type);
38 void DefaultPrecisionGenerator::visit(VariableDeclaration &var)
40 if(var.type_declaration)
43 string type = var.type;
44 if(!type.compare(0, 3, "vec") || !type.compare(0, 3, "mat"))
46 else if(!type.compare(0, 3, "ivec") || type=="uint")
49 if(!have_default.count(type))
51 Precision *prec = new Precision;
52 if(!type.compare(0, 7, "sampler"))
53 prec->precision = "lowp";
54 else if(stage->type==Stage::FRAGMENT)
55 prec->precision = "mediump";
57 prec->precision = "highp";
59 stage->content.body.insert(insert_point, prec);
61 have_default.insert(type);
66 void PrecisionRemover::apply(Stage &stage)
68 stage.content.visit(*this);
69 NodeRemover().apply(stage, nodes_to_remove);
72 void PrecisionRemover::visit(Precision &prec)
74 nodes_to_remove.insert(&prec);
77 void PrecisionRemover::visit(VariableDeclaration &var)
79 var.precision.clear();
83 LegacyConverter::LegacyConverter():
87 void LegacyConverter::apply(Stage &s, const Features &feat)
91 if(supports_stage(s.type))
92 s.content.visit(*this);
94 unsupported(format("Stage %s is not supported", Stage::get_stage_name(s.type)));
97 void LegacyConverter::unsupported(const string &reason)
99 Diagnostic diagnostic;
100 diagnostic.severity = Diagnostic::ERR;
101 diagnostic.source = GENERATED_SOURCE;
103 diagnostic.message = reason;
104 stage->diagnostics.push_back(diagnostic);
107 void LegacyConverter::visit(Block &block)
109 for(NodeList<Statement>::iterator i=block.body.begin(); i!=block.body.end(); ++i)
111 if(&block==&stage->content)
112 uniform_insert_point = i;
117 bool LegacyConverter::check_version(const Version &feature_version) const
119 if(features.glsl_version<feature_version)
121 else if(stage->required_features.glsl_version<feature_version)
122 stage->required_features.glsl_version = feature_version;
127 bool LegacyConverter::check_extension(bool Features::*extension) const
129 if(!(features.*extension))
132 stage->required_features.*extension = true;
137 bool LegacyConverter::supports_stage(Stage::Type st) const
139 if(st==Stage::GEOMETRY)
141 if(features.gl_api==OPENGL_ES2)
142 return check_version(Version(3, 20));
144 return check_version(Version(1, 50));
150 bool LegacyConverter::supports_unified_interface_syntax() const
152 if(features.gl_api==OPENGL_ES2)
153 return check_version(Version(3, 0));
155 return check_version(Version(1, 30));
158 void LegacyConverter::visit(VariableReference &var)
160 if(var.declaration==frag_out && !supports_unified_interface_syntax())
162 var.name = "gl_FragColor";
166 else if(var.declaration)
167 r_type = var.declaration->type;
172 void LegacyConverter::visit(Assignment &assign)
174 TraversingVisitor::visit(assign);
175 if(assign.target.declaration==frag_out && !supports_unified_interface_syntax())
176 assign.target.declaration = 0;
179 bool LegacyConverter::supports_unified_sampling_functions() const
181 if(features.gl_api==OPENGL_ES2)
182 return check_version(Version(3, 0));
184 return check_version(Version(1, 30));
187 void LegacyConverter::visit(FunctionCall &call)
189 if(call.name=="texture")
193 NodeArray<Expression>::iterator i = call.arguments.begin();
194 if(i!=call.arguments.end())
197 sampler_type = r_type;
199 for(; i!=call.arguments.end(); ++i)
203 if(!supports_unified_sampling_functions())
205 if(sampler_type=="sampler1D")
206 call.name = "texture1D";
207 else if(sampler_type=="sampler2D")
208 call.name = "texture2D";
209 else if(sampler_type=="sampler3D")
210 call.name = "texture3D";
211 else if(sampler_type=="samplerCube")
212 call.name = "textureCube";
213 else if(sampler_type=="sampler1DShadow")
214 call.name = "shadow1D";
215 else if(sampler_type=="sampler2DShadow")
216 call.name = "shadow2D";
217 else if(sampler_type=="sampler1DArray")
219 check_extension(&Features::ext_texture_array);
220 call.name = "texture1DArray";
222 else if(sampler_type=="sampler2DArray")
224 check_extension(&Features::ext_texture_array);
225 call.name = "texture2DArray";
227 else if(sampler_type=="sampler1DArrayShadow")
229 check_extension(&Features::ext_texture_array);
230 call.name = "shadow1DArray";
232 else if(sampler_type=="sampler2DArrayShadow")
234 check_extension(&Features::ext_texture_array);
235 call.name = "shadow2DArray";
240 TraversingVisitor::visit(call);
243 bool LegacyConverter::supports_interface_layouts() const
245 if(features.gl_api==OPENGL_ES2)
246 return check_version(Version(3, 0));
247 else if(check_version(Version(3, 30)))
250 return check_extension(&Features::arb_explicit_attrib_location);
253 bool LegacyConverter::supports_centroid_sampling() const
255 if(features.gl_api==OPENGL_ES2)
256 return check_version(Version(3, 0));
257 else if(check_version(Version(1, 20)))
260 return check_extension(&Features::ext_gpu_shader4);
263 bool LegacyConverter::supports_sample_sampling() const
265 if(features.gl_api==OPENGL_ES2)
266 return check_version(Version(3, 20));
267 else if(check_version(Version(4, 0)))
270 return check_extension(&Features::arb_gpu_shader5);
273 void LegacyConverter::visit(VariableDeclaration &var)
275 if(var.layout && !supports_interface_layouts())
277 vector<Layout::Qualifier>::iterator i;
278 for(i=var.layout->qualifiers.begin(); (i!=var.layout->qualifiers.end() && i->name!="location"); ++i) ;
279 if(i!=var.layout->qualifiers.end())
281 if(stage->type==Stage::VERTEX && var.interface=="in")
283 stage->locations[var.name] = i->value;
284 var.layout->qualifiers.erase(i);
286 else if(stage->type==Stage::FRAGMENT && var.interface=="out")
288 if(check_extension(&Features::ext_gpu_shader4))
289 stage->locations[var.name] = i->value;
291 unsupported("EXT_gpu_shader4 required for multiple fragment shader outputs");
292 var.layout->qualifiers.erase(i);
295 if(var.layout->qualifiers.empty())
300 if(var.sampling=="centroid")
302 if(!supports_centroid_sampling())
303 var.sampling = string();
305 else if(var.sampling=="sample")
307 if(!supports_sample_sampling())
308 var.sampling = string();
311 if((var.interface=="in" || var.interface=="out") && !supports_unified_interface_syntax())
313 if(stage->type==Stage::FRAGMENT && var.interface=="out")
316 nodes_to_remove.insert(&var);
320 TraversingVisitor::visit(var);
323 bool LegacyConverter::supports_interface_blocks(const string &iface) const
325 if(features.gl_api==OPENGL_ES2)
328 return check_version(Version(3, 0));
330 return check_version(Version(3, 20));
332 else if(check_version(Version(1, 50)))
334 else if(iface=="uniform")
335 return check_extension(&Features::arb_uniform_buffer_object);
340 void LegacyConverter::visit(InterfaceBlock &iface)
342 if(!supports_interface_blocks(iface.interface) && iface.type_declaration)
344 if(!iface.instance_name.empty())
345 unsupported("ARB_uniform_buffer_object required for interface block instances");
346 else if(iface.struct_declaration)
348 stage->content.body.splice(uniform_insert_point, iface.struct_declaration->members.body);
349 nodes_to_remove.insert(&iface);
350 nodes_to_remove.insert(iface.struct_declaration);
353 /* If the interface block is an array, it should have an instance
354 name too, so this should never be reached */
355 throw logic_error("Unexpected interface block configuration");