else
++i;
}
+ for(list<Stage>::iterator i=module->stages.begin(); i!=module->stages.end(); ++i)
+ finalize(*i);
}
void ProgramCompiler::import(const string &name)
return !unused.empty();
}
+void ProgramCompiler::finalize(Stage &stage)
+{
+ if(get_gl_api()==OPENGL_ES2)
+ apply<DefaultPrecisionGenerator>(stage);
+ else
+ apply<PrecisionRemover>(stage);
+}
+
void ProgramCompiler::inject_block(Block &target, const Block &source)
{
list<RefPtr<Node> >::iterator insert_point = target.body.begin();
formatted += '\n';
}
- if(api==OPENGL_ES2)
- {
- if(s.type==FRAGMENT)
- formatted += "precision mediump float;\n";
- }
-
Visitor::apply(s);
}
formatted += format("import %s;", import.module);
}
+void ProgramCompiler::Formatter::visit(Precision &prec)
+{
+ formatted += format("precision %s %s;", prec.precision, prec.type);
+}
+
void ProgramCompiler::Formatter::visit(Layout &layout)
{
formatted += "layout(";
}
formatted += format("%s ", interface);
}
+ if(!var.precision.empty())
+ formatted += format("%s ", var.precision);
formatted += format("%s %s", var.type, var.name);
if(var.array)
{
}
+void ProgramCompiler::PrecisionRemover::visit(Precision &)
+{
+ remove_node = true;
+}
+
+void ProgramCompiler::PrecisionRemover::visit(VariableDeclaration &var)
+{
+ var.precision.clear();
+}
+
+
+ProgramCompiler::DefaultPrecisionGenerator::DefaultPrecisionGenerator():
+ toplevel(true)
+{ }
+
+void ProgramCompiler::DefaultPrecisionGenerator::visit(Block &block)
+{
+ if(toplevel)
+ {
+ SetForScope<bool> set(toplevel, false);
+ BlockModifier::visit(block);
+ }
+ else
+ Visitor::visit(block);
+}
+
+void ProgramCompiler::DefaultPrecisionGenerator::visit(Precision &prec)
+{
+ have_default.insert(prec.type);
+}
+
+void ProgramCompiler::DefaultPrecisionGenerator::visit(VariableDeclaration &var)
+{
+ if(var.type_declaration)
+ return;
+
+ string type = var.type;
+ if(!type.compare(0, 3, "vec") || !type.compare(0, 3, "mat"))
+ type = "float";
+ else if(!type.compare(0, 3, "ivec") || type=="uint")
+ type = "int";
+
+ if(!have_default.count(type))
+ {
+ Precision *prec = new Precision;
+ if(!type.compare(0, 7, "sampler"))
+ prec->precision = "lowp";
+ else if(stage->type==FRAGMENT)
+ prec->precision = "mediump";
+ else
+ prec->precision = "highp";
+ prec->type = type;
+ insert_nodes.push_back(prec);
+
+ have_default.insert(type);
+ }
+}
+
+
ProgramCompiler::LegacyConverter::LegacyConverter():
target_api(get_gl_api()),
target_version(get_glsl_version()),
virtual void visit(ProgramSyntax::FunctionCall &);
virtual void visit(ProgramSyntax::ExpressionStatement &);
virtual void visit(ProgramSyntax::Import &);
+ virtual void visit(ProgramSyntax::Precision &);
virtual void visit(ProgramSyntax::Layout &);
virtual void visit(ProgramSyntax::InterfaceLayout &);
virtual void visit(ProgramSyntax::StructDeclaration &);
virtual void visit(ProgramSyntax::VariableDeclaration &);
};
+ struct PrecisionRemover: BlockModifier
+ {
+ using Visitor::visit;
+ virtual void visit(ProgramSyntax::Precision &);
+ virtual void visit(ProgramSyntax::VariableDeclaration &);
+ };
+
+ struct DefaultPrecisionGenerator: BlockModifier
+ {
+ bool toplevel;
+ std::set<std::string> have_default;
+
+ DefaultPrecisionGenerator();
+
+ using Visitor::visit;
+ virtual void visit(ProgramSyntax::Block &);
+ virtual void visit(ProgramSyntax::Precision &);
+ virtual void visit(ProgramSyntax::VariableDeclaration &);
+ };
+
struct LegacyConverter: BlockModifier
{
GLApi target_api;
void import(const std::string &);
void generate(ProgramSyntax::Stage &);
bool optimize(ProgramSyntax::Stage &);
+ void finalize(ProgramSyntax::Stage &);
static void inject_block(ProgramSyntax::Block &, const ProgramSyntax::Block &);
template<typename T>
static typename T::ResultType apply(ProgramSyntax::Stage &);
return token=="centroid";
}
+bool ProgramParser::is_precision_qualifier(const string &token)
+{
+ return (token=="highp" || token=="mediump" || token=="lowp");
+}
+
bool ProgramParser::is_qualifier(const string &token)
{
- return (token=="const" || is_interface_qualifier(token) || is_sampling_qualifier(token));
+ return (token=="const" || is_interface_qualifier(token) || is_sampling_qualifier(token) || is_precision_qualifier(token));
}
bool ProgramParser::is_builtin_type(const string &token)
string token = peek_token();
if(token=="import")
return parse_import();
+ else if(token=="precision")
+ return parse_precision();
else if(token=="layout")
{
RefPtr<Layout> layout = parse_layout();
}
else if(token=="struct")
return parse_struct_declaration();
- else if(is_sampling_qualifier(token) || token=="const")
- return parse_variable_declaration();
else if(is_interface_qualifier(token))
{
- if(is_type(peek_token(1)))
+ string next = peek_token(1);
+ if(is_type(next) || is_precision_qualifier(next))
return parse_variable_declaration();
else
return parse_interface_block();
}
+ else if(is_qualifier(token))
+ return parse_variable_declaration();
else if(is_type(token))
{
if(peek_token(2)=="(")
return import;
}
+RefPtr<Precision> ProgramParser::parse_precision()
+{
+ expect("precision");
+ RefPtr<Precision> precision = new Precision;
+
+ precision->precision = parse_token();
+ if(!is_precision_qualifier(precision->precision))
+ throw runtime_error(format("Parse error at '%s': expected a precision qualifier", precision->precision));
+
+ precision->type = parse_token();
+ // Not entirely accurate; only float, int and sampler types are allowed
+ if(!is_builtin_type(precision->type))
+ throw runtime_error(format("Parse error at '%s': expected a builtin type", precision->type));
+
+ expect(";");
+
+ return precision;
+}
+
RefPtr<Layout> ProgramParser::parse_layout()
{
expect("layout");
parse_token();
}
+ if(is_precision_qualifier(token))
+ var->precision = parse_token();
+
var->type = expect_type();
var->name = expect_identifier();
static bool is_interface_qualifier(const std::string &);
static bool is_sampling_qualifier(const std::string &);
+ static bool is_precision_qualifier(const std::string &);
static bool is_qualifier(const std::string &);
static bool is_builtin_type(const std::string &);
bool is_type(const std::string &);
RefPtr<ProgramSyntax::Node> parse_global_declaration();
RefPtr<ProgramSyntax::Node> parse_statement();
RefPtr<ProgramSyntax::Import> parse_import();
+ RefPtr<ProgramSyntax::Precision> parse_precision();
RefPtr<ProgramSyntax::Layout> parse_layout();
void parse_block(ProgramSyntax::Block &, bool);
RefPtr<ProgramSyntax::Expression> parse_expression(unsigned = 0);
}
+void Precision::visit(NodeVisitor &visitor)
+{
+ visitor.visit(*this);
+}
+
+
void Layout::visit(NodeVisitor &visitor)
{
visitor.visit(*this);
virtual void visit(NodeVisitor &);
};
+struct Precision: Node
+{
+ std::string precision;
+ std::string type;
+
+ virtual Precision *clone() const { return new Precision(*this); }
+ virtual void visit(NodeVisitor &);
+};
+
struct Layout: Node
{
struct Qualifier
bool constant;
std::string sampling;
std::string interface;
+ std::string precision;
std::string type;
StructDeclaration *type_declaration;
std::string name;
virtual void visit(FunctionCall &) { }
virtual void visit(ExpressionStatement &) { }
virtual void visit(Import &) { }
+ virtual void visit(Precision &) { }
virtual void visit(Layout &) { }
virtual void visit(InterfaceLayout &) { }
virtual void visit(StructDeclaration &) { }