From a5772e203cc30ce3b449614d03a293fd5b5985ad Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Tue, 14 Nov 2017 12:57:34 +0200 Subject: [PATCH] Support precision qualifiers in shaders --- source/programcompiler.cpp | 82 +++++++++++++++++++++++++++++++++++--- source/programcompiler.h | 22 ++++++++++ source/programparser.cpp | 38 ++++++++++++++++-- source/programparser.h | 2 + source/programsyntax.cpp | 6 +++ source/programsyntax.h | 11 +++++ 6 files changed, 151 insertions(+), 10 deletions(-) diff --git a/source/programcompiler.cpp b/source/programcompiler.cpp index 697ec219..c54a33d6 100644 --- a/source/programcompiler.cpp +++ b/source/programcompiler.cpp @@ -122,6 +122,8 @@ void ProgramCompiler::process() else ++i; } + for(list::iterator i=module->stages.begin(); i!=module->stages.end(); ++i) + finalize(*i); } void ProgramCompiler::import(const string &name) @@ -185,6 +187,14 @@ bool ProgramCompiler::optimize(Stage &stage) return !unused.empty(); } +void ProgramCompiler::finalize(Stage &stage) +{ + if(get_gl_api()==OPENGL_ES2) + apply(stage); + else + apply(stage); +} + void ProgramCompiler::inject_block(Block &target, const Block &source) { list >::iterator insert_point = target.body.begin(); @@ -239,12 +249,6 @@ void ProgramCompiler::Formatter::apply(ProgramSyntax::Stage &s) formatted += '\n'; } - if(api==OPENGL_ES2) - { - if(s.type==FRAGMENT) - formatted += "precision mediump float;\n"; - } - Visitor::apply(s); } @@ -343,6 +347,11 @@ void ProgramCompiler::Formatter::visit(Import &import) 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("; @@ -393,6 +402,8 @@ void ProgramCompiler::Formatter::visit(VariableDeclaration &var) } formatted += format("%s ", interface); } + if(!var.precision.empty()) + formatted += format("%s ", var.precision); formatted += format("%s %s", var.type, var.name); if(var.array) { @@ -1507,6 +1518,65 @@ void ProgramCompiler::NodeRemover::visit(VariableDeclaration &var) } +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 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()), diff --git a/source/programcompiler.h b/source/programcompiler.h index a84ccb8a..daf2a5db 100644 --- a/source/programcompiler.h +++ b/source/programcompiler.h @@ -52,6 +52,7 @@ private: 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 &); @@ -326,6 +327,26 @@ private: 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 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; @@ -368,6 +389,7 @@ private: 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 static typename T::ResultType apply(ProgramSyntax::Stage &); diff --git a/source/programparser.cpp b/source/programparser.cpp index bf5d5dff..453eb18d 100644 --- a/source/programparser.cpp +++ b/source/programparser.cpp @@ -307,9 +307,14 @@ bool ProgramParser::is_sampling_qualifier(const string &token) 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) @@ -334,6 +339,8 @@ RefPtr ProgramParser::parse_global_declaration() string token = peek_token(); if(token=="import") return parse_import(); + else if(token=="precision") + return parse_precision(); else if(token=="layout") { RefPtr layout = parse_layout(); @@ -355,15 +362,16 @@ RefPtr ProgramParser::parse_global_declaration() } 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)=="(") @@ -422,6 +430,25 @@ RefPtr ProgramParser::parse_import() return import; } +RefPtr ProgramParser::parse_precision() +{ + expect("precision"); + RefPtr 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 ProgramParser::parse_layout() { expect("layout"); @@ -623,6 +650,9 @@ RefPtr ProgramParser::parse_variable_declaration() parse_token(); } + if(is_precision_qualifier(token)) + var->precision = parse_token(); + var->type = expect_type(); var->name = expect_identifier(); diff --git a/source/programparser.h b/source/programparser.h index 0a46c09e..927c0204 100644 --- a/source/programparser.h +++ b/source/programparser.h @@ -69,6 +69,7 @@ private: 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 &); @@ -77,6 +78,7 @@ private: RefPtr parse_global_declaration(); RefPtr parse_statement(); RefPtr parse_import(); + RefPtr parse_precision(); RefPtr parse_layout(); void parse_block(ProgramSyntax::Block &, bool); RefPtr parse_expression(unsigned = 0); diff --git a/source/programsyntax.cpp b/source/programsyntax.cpp index 18545395..8cb276d9 100644 --- a/source/programsyntax.cpp +++ b/source/programsyntax.cpp @@ -103,6 +103,12 @@ void Import::visit(NodeVisitor &visitor) } +void Precision::visit(NodeVisitor &visitor) +{ + visitor.visit(*this); +} + + void Layout::visit(NodeVisitor &visitor) { visitor.visit(*this); diff --git a/source/programsyntax.h b/source/programsyntax.h index b72d401d..9e64c4c7 100644 --- a/source/programsyntax.h +++ b/source/programsyntax.h @@ -178,6 +178,15 @@ struct Import: Node 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 @@ -217,6 +226,7 @@ struct VariableDeclaration: Node bool constant; std::string sampling; std::string interface; + std::string precision; std::string type; StructDeclaration *type_declaration; std::string name; @@ -321,6 +331,7 @@ struct NodeVisitor 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 &) { } -- 2.43.0