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::visit(Block &block)
24 SetForScope<bool> set(toplevel, false);
25 BlockModifier::visit(block);
28 StageVisitor::visit(block);
31 void DefaultPrecisionGenerator::visit(Precision &prec)
33 have_default.insert(prec.type);
36 void DefaultPrecisionGenerator::visit(VariableDeclaration &var)
38 if(var.type_declaration)
41 string type = var.type;
42 if(!type.compare(0, 3, "vec") || !type.compare(0, 3, "mat"))
44 else if(!type.compare(0, 3, "ivec") || type=="uint")
47 if(!have_default.count(type))
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";
55 prec->precision = "highp";
57 insert_nodes.push_back(prec);
59 have_default.insert(type);
64 void PrecisionRemover::visit(Precision &)
69 void PrecisionRemover::visit(VariableDeclaration &var)
71 var.precision.clear();
75 LegacyConverter::LegacyConverter():
76 target_api(get_gl_api()),
77 target_version(get_glsl_version()),
81 LegacyConverter::LegacyConverter(const Version &v):
82 target_api(get_gl_api()),
87 bool LegacyConverter::check_version(const Version &feature_version) const
89 if(target_version<feature_version)
91 else if(stage->required_version<feature_version)
92 stage->required_version = feature_version;
97 bool LegacyConverter::check_extension(const Extension &extension) const
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);
109 bool LegacyConverter::supports_unified_interface_syntax() const
111 if(target_api==OPENGL_ES2)
112 return check_version(Version(3, 0));
114 return check_version(Version(1, 30));
117 void LegacyConverter::visit(VariableReference &var)
119 if(var.declaration==frag_out && !supports_unified_interface_syntax())
121 var.name = "gl_FragColor";
125 else if(var.declaration)
126 type = var.declaration->type;
131 void LegacyConverter::visit(Assignment &assign)
133 TraversingVisitor::visit(assign);
134 if(assign.target_declaration==frag_out && !supports_unified_interface_syntax())
135 assign.target_declaration = 0;
138 bool LegacyConverter::supports_unified_sampling_functions() const
140 if(target_api==OPENGL_ES2)
141 return check_version(Version(3, 0));
143 return check_version(Version(1, 30));
146 void LegacyConverter::visit(FunctionCall &call)
148 if(call.name=="texture")
152 NodeArray<Expression>::iterator i = call.arguments.begin();
153 if(i!=call.arguments.end())
158 for(; i!=call.arguments.end(); ++i)
162 if(!supports_unified_sampling_functions())
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")
178 check_extension(EXT_texture_array);
179 call.name = "texture1DArray";
181 else if(sampler_type=="sampler2DArray")
183 check_extension(EXT_texture_array);
184 call.name = "texture2DArray";
186 else if(sampler_type=="sampler1DArrayShadow")
188 check_extension(EXT_texture_array);
189 call.name = "shadow1DArray";
191 else if(sampler_type=="sampler2DArrayShadow")
193 check_extension(EXT_texture_array);
194 call.name = "shadow2DArray";
199 TraversingVisitor::visit(call);
202 bool LegacyConverter::supports_interface_layouts() const
204 if(target_api==OPENGL_ES2)
205 return check_version(Version(3, 0));
206 else if(check_version(Version(3, 30)))
209 return check_extension(ARB_explicit_attrib_location);
212 bool LegacyConverter::supports_centroid_sampling() const
214 if(target_api==OPENGL_ES2)
215 return check_version(Version(3, 0));
216 else if(check_version(Version(1, 20)))
219 return check_extension(EXT_gpu_shader4);
222 bool LegacyConverter::supports_sample_sampling() const
224 if(target_api==OPENGL_ES2)
225 return check_version(Version(3, 20));
226 else if(check_version(Version(4, 0)))
229 return check_extension(ARB_gpu_shader5);
232 void LegacyConverter::visit(VariableDeclaration &var)
234 if(var.layout && !supports_interface_layouts())
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())
240 unsigned location = lexical_cast<unsigned>(i->value);
241 if(stage->type==Stage::VERTEX && var.interface=="in")
243 stage->locations[var.name] = location;
244 var.layout->qualifiers.erase(i);
246 else if(stage->type==Stage::FRAGMENT && var.interface=="out")
249 static Require _req(EXT_gpu_shader4);
250 stage->locations[var.name] = location;
251 var.layout->qualifiers.erase(i);
254 if(var.layout->qualifiers.empty())
259 if(var.sampling=="centroid")
261 if(!supports_centroid_sampling())
262 var.sampling = string();
264 else if(var.sampling=="sample")
266 if(!supports_sample_sampling())
267 var.sampling = string();
270 if((var.interface=="in" || var.interface=="out") && !supports_unified_interface_syntax())
272 if(stage->type==Stage::FRAGMENT && var.interface=="out")
279 TraversingVisitor::visit(var);
282 bool LegacyConverter::supports_interface_blocks(const string &iface) const
284 if(target_api==OPENGL_ES2)
287 return check_version(Version(3, 0));
289 return check_version(Version(3, 20));
291 else if(check_version(Version(1, 50)))
293 else if(iface=="uniform")
294 return check_extension(ARB_uniform_buffer_object);
299 void LegacyConverter::visit(InterfaceBlock &iface)
301 if(!supports_interface_blocks(iface.interface))
302 flatten_block(iface.members);