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 <msp/strings/lexicalcast.h>
9 #include "compatibility.h"
17 DefaultPrecisionGenerator::DefaultPrecisionGenerator():
21 void DefaultPrecisionGenerator::apply(Stage &s)
27 void DefaultPrecisionGenerator::visit(Block &block)
29 for(NodeList<Statement>::iterator i=block.body.begin(); i!=block.body.end(); ++i)
31 if(&block==&stage->content)
37 void DefaultPrecisionGenerator::visit(Precision &prec)
39 have_default.insert(prec.type);
42 void DefaultPrecisionGenerator::visit(VariableDeclaration &var)
44 if(var.type_declaration)
47 string type = var.type;
48 if(!type.compare(0, 3, "vec") || !type.compare(0, 3, "mat"))
50 else if(!type.compare(0, 3, "ivec") || type=="uint")
53 if(!have_default.count(type))
55 Precision *prec = new Precision;
56 if(!type.compare(0, 7, "sampler"))
57 prec->precision = "lowp";
58 else if(stage->type==Stage::FRAGMENT)
59 prec->precision = "mediump";
61 prec->precision = "highp";
63 stage->content.body.insert(insert_point, prec);
65 have_default.insert(type);
70 void PrecisionRemover::apply(Stage &stage)
73 NodeRemover().apply(stage, nodes_to_remove);
76 void PrecisionRemover::visit(Precision &prec)
78 nodes_to_remove.insert(&prec);
81 void PrecisionRemover::visit(VariableDeclaration &var)
83 var.precision.clear();
87 LegacyConverter::LegacyConverter():
88 target_api(get_gl_api()),
89 target_version(get_glsl_version()),
93 void LegacyConverter::apply(Stage &s)
99 void LegacyConverter::visit(Block &block)
101 for(NodeList<Statement>::iterator i=block.body.begin(); i!=block.body.end(); ++i)
103 if(&block==&stage->content)
104 uniform_insert_point = i;
109 bool LegacyConverter::check_version(const Version &feature_version) const
111 if(target_version<feature_version)
113 else if(stage->required_version<feature_version)
114 stage->required_version = feature_version;
119 bool LegacyConverter::check_extension(const Extension &extension) const
124 vector<const Extension *>::iterator i = find(stage->required_extensions, &extension);
125 if(i==stage->required_extensions.end())
126 stage->required_extensions.push_back(&extension);
131 bool LegacyConverter::supports_unified_interface_syntax() const
133 if(target_api==OPENGL_ES2)
134 return check_version(Version(3, 0));
136 return check_version(Version(1, 30));
139 void LegacyConverter::visit(VariableReference &var)
141 if(var.declaration==frag_out && !supports_unified_interface_syntax())
143 var.name = "gl_FragColor";
147 else if(var.declaration)
148 type = var.declaration->type;
153 void LegacyConverter::visit(Assignment &assign)
155 TraversingVisitor::visit(assign);
156 if(assign.target_declaration==frag_out && !supports_unified_interface_syntax())
157 assign.target_declaration = 0;
160 bool LegacyConverter::supports_unified_sampling_functions() const
162 if(target_api==OPENGL_ES2)
163 return check_version(Version(3, 0));
165 return check_version(Version(1, 30));
168 void LegacyConverter::visit(FunctionCall &call)
170 if(call.name=="texture")
174 NodeArray<Expression>::iterator i = call.arguments.begin();
175 if(i!=call.arguments.end())
180 for(; i!=call.arguments.end(); ++i)
184 if(!supports_unified_sampling_functions())
186 if(sampler_type=="sampler1D")
187 call.name = "texture1D";
188 else if(sampler_type=="sampler2D")
189 call.name = "texture2D";
190 else if(sampler_type=="sampler3D")
191 call.name = "texture3D";
192 else if(sampler_type=="samplerCube")
193 call.name = "textureCube";
194 else if(sampler_type=="sampler1DShadow")
195 call.name = "shadow1D";
196 else if(sampler_type=="sampler2DShadow")
197 call.name = "shadow2D";
198 else if(sampler_type=="sampler1DArray")
200 check_extension(EXT_texture_array);
201 call.name = "texture1DArray";
203 else if(sampler_type=="sampler2DArray")
205 check_extension(EXT_texture_array);
206 call.name = "texture2DArray";
208 else if(sampler_type=="sampler1DArrayShadow")
210 check_extension(EXT_texture_array);
211 call.name = "shadow1DArray";
213 else if(sampler_type=="sampler2DArrayShadow")
215 check_extension(EXT_texture_array);
216 call.name = "shadow2DArray";
221 TraversingVisitor::visit(call);
224 bool LegacyConverter::supports_interface_layouts() const
226 if(target_api==OPENGL_ES2)
227 return check_version(Version(3, 0));
228 else if(check_version(Version(3, 30)))
231 return check_extension(ARB_explicit_attrib_location);
234 bool LegacyConverter::supports_centroid_sampling() const
236 if(target_api==OPENGL_ES2)
237 return check_version(Version(3, 0));
238 else if(check_version(Version(1, 20)))
241 return check_extension(EXT_gpu_shader4);
244 bool LegacyConverter::supports_sample_sampling() const
246 if(target_api==OPENGL_ES2)
247 return check_version(Version(3, 20));
248 else if(check_version(Version(4, 0)))
251 return check_extension(ARB_gpu_shader5);
254 void LegacyConverter::visit(VariableDeclaration &var)
256 if(var.layout && !supports_interface_layouts())
258 vector<Layout::Qualifier>::iterator i;
259 for(i=var.layout->qualifiers.begin(); (i!=var.layout->qualifiers.end() && i->identifier!="location"); ++i) ;
260 if(i!=var.layout->qualifiers.end())
262 unsigned location = lexical_cast<unsigned>(i->value);
263 if(stage->type==Stage::VERTEX && var.interface=="in")
265 stage->locations[var.name] = location;
266 var.layout->qualifiers.erase(i);
268 else if(stage->type==Stage::FRAGMENT && var.interface=="out")
271 static Require _req(EXT_gpu_shader4);
272 stage->locations[var.name] = location;
273 var.layout->qualifiers.erase(i);
276 if(var.layout->qualifiers.empty())
281 if(var.sampling=="centroid")
283 if(!supports_centroid_sampling())
284 var.sampling = string();
286 else if(var.sampling=="sample")
288 if(!supports_sample_sampling())
289 var.sampling = string();
292 if((var.interface=="in" || var.interface=="out") && !supports_unified_interface_syntax())
294 if(stage->type==Stage::FRAGMENT && var.interface=="out")
297 nodes_to_remove.insert(&var);
301 TraversingVisitor::visit(var);
304 bool LegacyConverter::supports_interface_blocks(const string &iface) const
306 if(target_api==OPENGL_ES2)
309 return check_version(Version(3, 0));
311 return check_version(Version(3, 20));
313 else if(check_version(Version(1, 50)))
315 else if(iface=="uniform")
316 return check_extension(ARB_uniform_buffer_object);
321 void LegacyConverter::visit(InterfaceBlock &iface)
323 if(!supports_interface_blocks(iface.interface))
325 stage->content.body.splice(uniform_insert_point, iface.members.body);
326 nodes_to_remove.insert(&iface);