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"
16 DefaultPrecisionGenerator::DefaultPrecisionGenerator():
20 void DefaultPrecisionGenerator::apply(Stage &s)
26 void DefaultPrecisionGenerator::visit(Block &block)
28 for(NodeList<Statement>::iterator i=block.body.begin(); i!=block.body.end(); ++i)
30 if(&block==&stage->content)
36 void DefaultPrecisionGenerator::visit(Precision &prec)
38 have_default.insert(prec.type);
41 void DefaultPrecisionGenerator::visit(VariableDeclaration &var)
43 if(var.type_declaration)
46 string type = var.type;
47 if(!type.compare(0, 3, "vec") || !type.compare(0, 3, "mat"))
49 else if(!type.compare(0, 3, "ivec") || type=="uint")
52 if(!have_default.count(type))
54 Precision *prec = new Precision;
55 if(!type.compare(0, 7, "sampler"))
56 prec->precision = "lowp";
57 else if(stage->type==Stage::FRAGMENT)
58 prec->precision = "mediump";
60 prec->precision = "highp";
62 stage->content.body.insert(insert_point, prec);
64 have_default.insert(type);
69 void PrecisionRemover::apply(Stage &stage)
72 NodeRemover().apply(stage, nodes_to_remove);
75 void PrecisionRemover::visit(Precision &prec)
77 nodes_to_remove.insert(&prec);
80 void PrecisionRemover::visit(VariableDeclaration &var)
82 var.precision.clear();
86 LegacyConverter::LegacyConverter():
87 target_api(get_gl_api()),
88 target_version(get_glsl_version()),
92 void LegacyConverter::apply(Stage &s)
98 void LegacyConverter::visit(Block &block)
100 for(NodeList<Statement>::iterator i=block.body.begin(); i!=block.body.end(); ++i)
102 if(&block==&stage->content)
103 uniform_insert_point = i;
108 bool LegacyConverter::check_version(const Version &feature_version) const
110 if(target_version<feature_version)
112 else if(stage->required_version<feature_version)
113 stage->required_version = feature_version;
118 bool LegacyConverter::check_extension(const Extension &extension) const
123 vector<const Extension *>::iterator i = find(stage->required_extensions, &extension);
124 if(i==stage->required_extensions.end())
125 stage->required_extensions.push_back(&extension);
130 bool LegacyConverter::supports_unified_interface_syntax() const
132 if(target_api==OPENGL_ES2)
133 return check_version(Version(3, 0));
135 return check_version(Version(1, 30));
138 void LegacyConverter::visit(VariableReference &var)
140 if(var.declaration==frag_out && !supports_unified_interface_syntax())
142 var.name = "gl_FragColor";
146 else if(var.declaration)
147 type = var.declaration->type;
152 void LegacyConverter::visit(Assignment &assign)
154 TraversingVisitor::visit(assign);
155 if(assign.target_declaration==frag_out && !supports_unified_interface_syntax())
156 assign.target_declaration = 0;
159 bool LegacyConverter::supports_unified_sampling_functions() const
161 if(target_api==OPENGL_ES2)
162 return check_version(Version(3, 0));
164 return check_version(Version(1, 30));
167 void LegacyConverter::visit(FunctionCall &call)
169 if(call.name=="texture")
173 NodeArray<Expression>::iterator i = call.arguments.begin();
174 if(i!=call.arguments.end())
179 for(; i!=call.arguments.end(); ++i)
183 if(!supports_unified_sampling_functions())
185 if(sampler_type=="sampler1D")
186 call.name = "texture1D";
187 else if(sampler_type=="sampler2D")
188 call.name = "texture2D";
189 else if(sampler_type=="sampler3D")
190 call.name = "texture3D";
191 else if(sampler_type=="samplerCube")
192 call.name = "textureCube";
193 else if(sampler_type=="sampler1DShadow")
194 call.name = "shadow1D";
195 else if(sampler_type=="sampler2DShadow")
196 call.name = "shadow2D";
197 else if(sampler_type=="sampler1DArray")
199 check_extension(EXT_texture_array);
200 call.name = "texture1DArray";
202 else if(sampler_type=="sampler2DArray")
204 check_extension(EXT_texture_array);
205 call.name = "texture2DArray";
207 else if(sampler_type=="sampler1DArrayShadow")
209 check_extension(EXT_texture_array);
210 call.name = "shadow1DArray";
212 else if(sampler_type=="sampler2DArrayShadow")
214 check_extension(EXT_texture_array);
215 call.name = "shadow2DArray";
220 TraversingVisitor::visit(call);
223 bool LegacyConverter::supports_interface_layouts() const
225 if(target_api==OPENGL_ES2)
226 return check_version(Version(3, 0));
227 else if(check_version(Version(3, 30)))
230 return check_extension(ARB_explicit_attrib_location);
233 bool LegacyConverter::supports_centroid_sampling() const
235 if(target_api==OPENGL_ES2)
236 return check_version(Version(3, 0));
237 else if(check_version(Version(1, 20)))
240 return check_extension(EXT_gpu_shader4);
243 bool LegacyConverter::supports_sample_sampling() const
245 if(target_api==OPENGL_ES2)
246 return check_version(Version(3, 20));
247 else if(check_version(Version(4, 0)))
250 return check_extension(ARB_gpu_shader5);
253 void LegacyConverter::visit(VariableDeclaration &var)
255 if(var.layout && !supports_interface_layouts())
257 vector<Layout::Qualifier>::iterator i;
258 for(i=var.layout->qualifiers.begin(); (i!=var.layout->qualifiers.end() && i->identifier!="location"); ++i) ;
259 if(i!=var.layout->qualifiers.end())
261 unsigned location = lexical_cast<unsigned>(i->value);
262 if(stage->type==Stage::VERTEX && var.interface=="in")
264 stage->locations[var.name] = location;
265 var.layout->qualifiers.erase(i);
267 else if(stage->type==Stage::FRAGMENT && var.interface=="out")
270 static Require _req(EXT_gpu_shader4);
271 stage->locations[var.name] = location;
272 var.layout->qualifiers.erase(i);
275 if(var.layout->qualifiers.empty())
280 if(var.sampling=="centroid")
282 if(!supports_centroid_sampling())
283 var.sampling = string();
285 else if(var.sampling=="sample")
287 if(!supports_sample_sampling())
288 var.sampling = string();
291 if((var.interface=="in" || var.interface=="out") && !supports_unified_interface_syntax())
293 if(stage->type==Stage::FRAGMENT && var.interface=="out")
296 nodes_to_remove.insert(&var);
300 TraversingVisitor::visit(var);
303 bool LegacyConverter::supports_interface_blocks(const string &iface) const
305 if(target_api==OPENGL_ES2)
308 return check_version(Version(3, 0));
310 return check_version(Version(3, 20));
312 else if(check_version(Version(1, 50)))
314 else if(iface=="uniform")
315 return check_extension(ARB_uniform_buffer_object);
320 void LegacyConverter::visit(InterfaceBlock &iface)
322 if(!supports_interface_blocks(iface.interface))
324 stage->content.body.splice(uniform_insert_point, iface.members.body);
325 nodes_to_remove.insert(&iface);