]> git.tdb.fi Git - libs/gl.git/commitdiff
Support precision qualifiers in shaders
authorMikko Rasa <tdb@tdb.fi>
Tue, 14 Nov 2017 10:57:34 +0000 (12:57 +0200)
committerMikko Rasa <tdb@tdb.fi>
Tue, 14 Nov 2017 10:57:34 +0000 (12:57 +0200)
source/programcompiler.cpp
source/programcompiler.h
source/programparser.cpp
source/programparser.h
source/programsyntax.cpp
source/programsyntax.h

index 697ec2193ed9e022c1bd283f4405f4188ceaf8bb..c54a33d6b6fbf0147fe21dd069db9f391d42cc16 100644 (file)
@@ -122,6 +122,8 @@ void ProgramCompiler::process()
                else
                        ++i;
        }
+       for(list<Stage>::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<DefaultPrecisionGenerator>(stage);
+       else
+               apply<PrecisionRemover>(stage);
+}
+
 void ProgramCompiler::inject_block(Block &target, const Block &source)
 {
        list<RefPtr<Node> >::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<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()),
index a84ccb8ac001d9a6fe49d93cab4f47998591ad9d..daf2a5db7904988f9e782e300b25e88ebcc47835 100644 (file)
@@ -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<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;
@@ -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<typename T>
        static typename T::ResultType apply(ProgramSyntax::Stage &);
index bf5d5dffb103fea9b554afa0940f607d12b21ac4..453eb18d31db554f0dd1fc47241a5c770db858dd 100644 (file)
@@ -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<Node> 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> layout = parse_layout();
@@ -355,15 +362,16 @@ RefPtr<Node> 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<Import> ProgramParser::parse_import()
        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");
@@ -623,6 +650,9 @@ RefPtr<VariableDeclaration> ProgramParser::parse_variable_declaration()
                parse_token();
        }
 
+       if(is_precision_qualifier(token))
+               var->precision = parse_token();
+
        var->type = expect_type();
        var->name = expect_identifier();
 
index 0a46c09ece6202e18c71625afd916b8680f4806a..927c02046fb822d17e67dcc0b8ecdfbe03bafc9f 100644 (file)
@@ -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<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);
index 185453952a006fdf591b9bf64b6306d37efe0989..8cb276d9b6dcdef94e2afaccc7ba907ab580f675 100644 (file)
@@ -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);
index b72d401d1ffc1b81ccf2f70affc7e39250e8c147..9e64c4c7e86896192748cefb24e29b2333ca1787 100644 (file)
@@ -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 &) { }