#include <msp/core/algorithm.h>
#include <msp/core/raii.h>
-#include <msp/gl/extensions/arb_explicit_attrib_location.h>
-#include <msp/gl/extensions/arb_gpu_shader5.h>
-#include <msp/gl/extensions/arb_uniform_buffer_object.h>
-#include <msp/gl/extensions/ext_gpu_shader4.h>
-#include <msp/gl/extensions/ext_texture_array.h>
+#include <msp/strings/lexicalcast.h>
#include "compatibility.h"
+#include "glsl_error.h"
using namespace std;
namespace SL {
DefaultPrecisionGenerator::DefaultPrecisionGenerator():
- stage_type(Stage::SHARED),
- toplevel(true)
+ stage(0)
{ }
-void DefaultPrecisionGenerator::apply(Stage &stage)
+void DefaultPrecisionGenerator::apply(Stage &s)
{
- SetForScope<Stage::Type> set_stage(stage_type, stage.type);
- visit(stage.content);
+ stage = &s;
+ s.content.visit(*this);
}
void DefaultPrecisionGenerator::visit(Block &block)
{
- if(toplevel)
+ for(NodeList<Statement>::iterator i=block.body.begin(); i!=block.body.end(); ++i)
{
- SetForScope<bool> set(toplevel, false);
- BlockModifier::visit(block);
+ if(&block==&stage->content)
+ insert_point = i;
+ (*i)->visit(*this);
}
- else
- TraversingVisitor::visit(block);
}
void DefaultPrecisionGenerator::visit(Precision &prec)
Precision *prec = new Precision;
if(!type.compare(0, 7, "sampler"))
prec->precision = "lowp";
- else if(stage_type==Stage::FRAGMENT)
+ else if(stage->type==Stage::FRAGMENT)
prec->precision = "mediump";
else
prec->precision = "highp";
prec->type = type;
- insert_nodes.push_back(prec);
+ stage->content.body.insert(insert_point, prec);
have_default.insert(type);
}
}
-void PrecisionRemover::visit(Precision &)
+void PrecisionRemover::apply(Stage &stage)
+{
+ stage.content.visit(*this);
+ NodeRemover().apply(stage, nodes_to_remove);
+}
+
+void PrecisionRemover::visit(Precision &prec)
{
- remove_node = true;
+ nodes_to_remove.insert(&prec);
}
void PrecisionRemover::visit(VariableDeclaration &var)
LegacyConverter::LegacyConverter():
- target_api(get_gl_api()),
- target_version(get_glsl_version()),
frag_out(0)
{ }
-LegacyConverter::LegacyConverter(const Version &v):
- target_api(get_gl_api()),
- target_version(v),
- frag_out(0)
-{ }
+void LegacyConverter::apply(Stage &s, const Features &feat)
+{
+ stage = &s;
+ features = feat;
+ if(!supports_stage(s.type))
+ throw unsupported_shader(format("Stage %s is not supported", Stage::get_stage_name(s.type)));
+ s.content.visit(*this);
+}
-void LegacyConverter::apply(Stage &s)
+void LegacyConverter::visit(Block &block)
{
- SetForScope<Stage *> set_stage(stage, &s);
- visit(s.content);
+ for(NodeList<Statement>::iterator i=block.body.begin(); i!=block.body.end(); ++i)
+ {
+ if(&block==&stage->content)
+ uniform_insert_point = i;
+ (*i)->visit(*this);
+ }
}
bool LegacyConverter::check_version(const Version &feature_version) const
{
- if(target_version<feature_version)
+ if(features.glsl_version<feature_version)
return false;
- else if(stage->required_version<feature_version)
- stage->required_version = feature_version;
+ else if(stage->required_features.glsl_version<feature_version)
+ stage->required_features.glsl_version = feature_version;
return true;
}
-bool LegacyConverter::check_extension(const Extension &extension) const
+bool LegacyConverter::check_extension(bool Features::*extension) const
{
- if(!extension)
+ if(!(features.*extension))
return false;
- vector<const Extension *>::iterator i = find(stage->required_extensions, &extension);
- if(i==stage->required_extensions.end())
- stage->required_extensions.push_back(&extension);
+ stage->required_features.*extension = true;
return true;
}
+bool LegacyConverter::supports_stage(Stage::Type st) const
+{
+ if(st==Stage::GEOMETRY)
+ {
+ if(features.gl_api==OPENGL_ES2)
+ return check_version(Version(3, 20));
+ else
+ return check_version(Version(1, 50));
+ }
+ else
+ return true;
+}
+
bool LegacyConverter::supports_unified_interface_syntax() const
{
- if(target_api==OPENGL_ES2)
+ if(features.gl_api==OPENGL_ES2)
return check_version(Version(3, 0));
else
return check_version(Version(1, 30));
{
var.name = "gl_FragColor";
var.declaration = 0;
- type = "vec4";
+ r_type = "vec4";
}
else if(var.declaration)
- type = var.declaration->type;
+ r_type = var.declaration->type;
else
- type = string();
+ r_type.clear();
}
void LegacyConverter::visit(Assignment &assign)
bool LegacyConverter::supports_unified_sampling_functions() const
{
- if(target_api==OPENGL_ES2)
+ if(features.gl_api==OPENGL_ES2)
return check_version(Version(3, 0));
else
return check_version(Version(1, 30));
if(call.name=="texture")
{
string sampler_type;
- type = string();
+ r_type.clear();
NodeArray<Expression>::iterator i = call.arguments.begin();
if(i!=call.arguments.end())
{
(*i)->visit(*this);
- sampler_type = type;
+ sampler_type = r_type;
for(; i!=call.arguments.end(); ++i)
(*i)->visit(*this);
call.name = "shadow2D";
else if(sampler_type=="sampler1DArray")
{
- check_extension(EXT_texture_array);
+ check_extension(&Features::ext_texture_array);
call.name = "texture1DArray";
}
else if(sampler_type=="sampler2DArray")
{
- check_extension(EXT_texture_array);
+ check_extension(&Features::ext_texture_array);
call.name = "texture2DArray";
}
else if(sampler_type=="sampler1DArrayShadow")
{
- check_extension(EXT_texture_array);
+ check_extension(&Features::ext_texture_array);
call.name = "shadow1DArray";
}
else if(sampler_type=="sampler2DArrayShadow")
{
- check_extension(EXT_texture_array);
+ check_extension(&Features::ext_texture_array);
call.name = "shadow2DArray";
}
}
bool LegacyConverter::supports_interface_layouts() const
{
- if(target_api==OPENGL_ES2)
+ if(features.gl_api==OPENGL_ES2)
return check_version(Version(3, 0));
else if(check_version(Version(3, 30)))
return true;
else
- return check_extension(ARB_explicit_attrib_location);
+ return check_extension(&Features::arb_explicit_attrib_location);
}
bool LegacyConverter::supports_centroid_sampling() const
{
- if(target_api==OPENGL_ES2)
+ if(features.gl_api==OPENGL_ES2)
return check_version(Version(3, 0));
else if(check_version(Version(1, 20)))
return true;
else
- return check_extension(EXT_gpu_shader4);
+ return check_extension(&Features::ext_gpu_shader4);
}
bool LegacyConverter::supports_sample_sampling() const
{
- if(target_api==OPENGL_ES2)
+ if(features.gl_api==OPENGL_ES2)
return check_version(Version(3, 20));
else if(check_version(Version(4, 0)))
return true;
else
- return check_extension(ARB_gpu_shader5);
+ return check_extension(&Features::arb_gpu_shader5);
}
void LegacyConverter::visit(VariableDeclaration &var)
if(var.layout && !supports_interface_layouts())
{
vector<Layout::Qualifier>::iterator i;
- for(i=var.layout->qualifiers.begin(); (i!=var.layout->qualifiers.end() && i->identifier!="location"); ++i) ;
+ for(i=var.layout->qualifiers.begin(); (i!=var.layout->qualifiers.end() && i->name!="location"); ++i) ;
if(i!=var.layout->qualifiers.end())
{
- unsigned location = lexical_cast<unsigned>(i->value);
if(stage->type==Stage::VERTEX && var.interface=="in")
{
- stage->locations[var.name] = location;
+ stage->locations[var.name] = i->value;
var.layout->qualifiers.erase(i);
}
else if(stage->type==Stage::FRAGMENT && var.interface=="out")
{
- if(location!=0)
- static Require _req(EXT_gpu_shader4);
- stage->locations[var.name] = location;
+ if(i->value!=0 && !check_extension(&Features::ext_gpu_shader4))
+ throw unsupported_shader("EXT_gpu_shader4 is required");
+ stage->locations[var.name] = i->value;
var.layout->qualifiers.erase(i);
}
if(stage->type==Stage::FRAGMENT && var.interface=="out")
{
frag_out = &var;
- remove_node = true;
+ nodes_to_remove.insert(&var);
}
}
bool LegacyConverter::supports_interface_blocks(const string &iface) const
{
- if(target_api==OPENGL_ES2)
+ if(features.gl_api==OPENGL_ES2)
{
if(iface=="uniform")
return check_version(Version(3, 0));
else if(check_version(Version(1, 50)))
return true;
else if(iface=="uniform")
- return check_extension(ARB_uniform_buffer_object);
+ return check_extension(&Features::arb_uniform_buffer_object);
else
return false;
}
void LegacyConverter::visit(InterfaceBlock &iface)
{
if(!supports_interface_blocks(iface.interface))
- flatten_block(iface.members);
+ {
+ stage->content.body.splice(uniform_insert_point, iface.members.body);
+ nodes_to_remove.insert(&iface);
+ }
}
} // namespace SL