]> git.tdb.fi Git - libs/gl.git/commitdiff
Support specialization constants in the GLSL compiler
authorMikko Rasa <tdb@tdb.fi>
Fri, 26 Feb 2021 21:10:17 +0000 (23:10 +0200)
committerMikko Rasa <tdb@tdb.fi>
Fri, 26 Feb 2021 21:10:17 +0000 (23:10 +0200)
source/glsl/compiler.cpp
source/glsl/compiler.h
source/glsl/generate.cpp
source/glsl/generate.h
source/glsl/optimize.cpp
source/glsl/parser.cpp
tools/glslcompiler.cpp

index ca6c58057022b8b3a9f69373433c0f6c54a2e35d..a18b8e8c2c3df57e0f26c2d126719edbaced8fb5 100644 (file)
@@ -21,12 +21,14 @@ namespace SL {
 
 Compiler::Compiler():
        features(Features::from_context()),
-       module(0)
+       module(0),
+       specialized(false)
 { }
 
 Compiler::Compiler(const Features &f):
        features(f),
-       module(0)
+       module(0),
+       specialized(false)
 { }
 
 Compiler::~Compiler()
@@ -63,6 +65,12 @@ void Compiler::load_source(IO::Base &io, const string &src_name)
        load_source(io, 0, src_name);
 }
 
+void Compiler::specialize(const map<string, int> &sv)
+{
+       specialized = true;
+       spec_values = sv;
+}
+
 void Compiler::compile(Mode mode)
 {
        for(list<Stage>::iterator i=module->stages.begin(); i!=module->stages.end(); ++i)
@@ -213,6 +221,7 @@ void Compiler::generate(Stage &stage, Mode mode)
        VariableResolver().apply(stage);
        DeclarationReorderer().apply(stage);
        FunctionResolver().apply(stage);
+       ConstantSpecializer().apply(stage, (mode==PROGRAM && specialized ? &spec_values : 0));
        if(mode==PROGRAM)
                LegacyConverter().apply(stage, features);
 }
index 4eaff213076ea07131528b03810b1c51b961369e..69ac7427d80fc97188fa2bcbb0c2c600ef6cf67a 100644 (file)
@@ -24,6 +24,8 @@ private:
        Features features;
        Module *module;
        std::vector<std::string> imported_names;
+       bool specialized;
+       std::map<std::string, int> spec_values;
 
 public:
        Compiler();
@@ -36,6 +38,7 @@ public:
        void set_source(const std::string &, const std::string & = "<string>");
        void load_source(IO::Base &, DataFile::Collection * = 0, const std::string & = "<file>");
        void load_source(IO::Base &, const std::string &);
+       void specialize(const std::map<std::string, int> &);
        void compile(Mode);
 
        std::string get_combined_glsl() const;
index 42226a912396171faf0287b4062cbee19fbe5a40..2ac37a6ffae788a16c6cc367dbcf53b9fdb61dcb 100644 (file)
@@ -1,4 +1,6 @@
+#include <msp/core/hash.h>
 #include <msp/core/raii.h>
+#include <msp/strings/lexicalcast.h>
 #include "builtin.h"
 #include "generate.h"
 
@@ -73,6 +75,59 @@ void DeclarationCombiner::visit(VariableDeclaration &var)
 }
 
 
+ConstantSpecializer::ConstantSpecializer():
+       values(0)
+{ }
+
+void ConstantSpecializer::apply(Stage &stage, const map<string, int> *v)
+{
+       values = v;
+       stage.content.visit(*this);
+}
+
+void ConstantSpecializer::visit(VariableDeclaration &var)
+{
+       bool specializable = false;
+       if(var.layout)
+       {
+               vector<Layout::Qualifier> &qualifiers = var.layout->qualifiers;
+               for(vector<Layout::Qualifier>::iterator i=qualifiers.begin(); i!=qualifiers.end(); ++i)
+                       if(i->name=="constant_id")
+                       {
+                               specializable = true;
+                               if(values)
+                                       qualifiers.erase(i);
+                               else if(i->value==-1)
+                                       i->value = hash32(var.name)&0x7FFFFFFF;
+                               break;
+                       }
+
+               if(qualifiers.empty())
+                       var.layout = 0;
+       }
+
+       if(specializable && values)
+       {
+               map<string, int>::const_iterator i = values->find(var.name);
+               if(i!=values->end())
+               {
+                       RefPtr<Literal> literal = new Literal;
+                       if(var.type=="bool")
+                       {
+                               literal->token = (i->second ? "true" : "false");
+                               literal->value = static_cast<bool>(i->second);
+                       }
+                       else if(var.type=="int")
+                       {
+                               literal->token = lexical_cast<string>(i->second);
+                               literal->value = i->second;
+                       }
+                       var.init_expression = literal;
+               }
+       }
+}
+
+
 void BlockResolver::enter(Block &block)
 {
        block.parent = current_block;
index f1f10b897c281e9ec4a39ff032a167963b936b8a..68816b8b50acec9411ec331e8b866749412bb3d2 100644 (file)
@@ -27,6 +27,20 @@ private:
        virtual void visit(VariableDeclaration &);
 };
 
+class ConstantSpecializer: private TraversingVisitor
+{
+private:
+       const std::map<std::string, int> *values;
+
+public:
+       ConstantSpecializer();
+
+       void apply(Stage &, const std::map<std::string, int> *);
+
+private:
+       virtual void visit(VariableDeclaration &);
+};
+
 class BlockResolver: private TraversingVisitor
 {
 public:
index 3f63dd8a7debaac0c492c0f3f5a2e9491d989ebf..2215f8335cd06a23ea71e2c381cb1776362b81cd 100644 (file)
@@ -160,7 +160,13 @@ void ConstantConditionEliminator::visit(Assignment &assign)
 
 void ConstantConditionEliminator::visit(VariableDeclaration &var)
 {
-       if((var.constant || current_block->parent) && var.init_expression)
+       bool constant = var.constant;
+       if(constant && var.layout)
+       {
+               for(vector<Layout::Qualifier>::const_iterator i=var.layout->qualifiers.begin(); (constant && i!=var.layout->qualifiers.end()); ++i)
+                       constant = (i->name!="constant_id");
+       }
+       if((constant || current_block->parent) && var.init_expression)
                variable_values[&var] = var.init_expression.get();
 }
 
index b493c677d3d4007a4c9d8c285ba6d8c4b99fc9f3..5ffc2a9b023f284b2837990e06f7a8533955d5fc 100644 (file)
@@ -327,7 +327,15 @@ RefPtr<Layout> Parser::parse_layout()
                qual.name = token;
 
                if((qual.has_value = check("=")))
-                       qual.value = expect_integer();
+               {
+                       if(qual.name=="constant_id" && tokenizer.peek_token()=="auto")
+                       {
+                               qual.value = -1;
+                               tokenizer.parse_token();
+                       }
+                       else
+                               qual.value = expect_integer();
+               }
 
                if(tokenizer.peek_token()==")")
                        break;
index 74b37ef6b20a2fb5a46e0d19142c460fed346c98..0ce5f01d722ac424c064d7a7f64d862f72b16390 100644 (file)
@@ -2,11 +2,13 @@
 #include <msp/core/getopt.h>
 #include <msp/gl/glsl/compiler.h>
 #include <msp/io/print.h>
+#include <msp/strings/utils.h>
 
 class GlslCompiler: public Msp::RegisteredApplication<GlslCompiler>
 {
 private:
        std::string source_fn;
+       std::map<std::string, int> spec_values;
        bool parse_only;
        bool combined;
        Msp::GL::SL::Stage::Type stage;
@@ -28,11 +30,13 @@ GlslCompiler::GlslCompiler(int argc, char **argv):
        dump_ast(false)
 {
        string stage_str;
+       vector<string> spec_values_in;
 
        GetOpt getopt;
        getopt.add_option('c', "combined", combined, GetOpt::NO_ARG).set_help("Output combined GLSL");
        getopt.add_option('a', "dump-ast", dump_ast, GetOpt::NO_ARG).set_help("Dump AST for debugging");
        getopt.add_option('p', "parse_only", parse_only, GetOpt::NO_ARG).set_help("Only parse the loaded source, don't compile");
+       getopt.add_option('e', "specialize", spec_values_in, GetOpt::REQUIRED_ARG).set_help("Set specialization constant", "NAME:VALUE");
        getopt.add_option('s', "stage", stage_str, GetOpt::REQUIRED_ARG).set_help("Output GLSL for STAGE", "STAGE");
        getopt.add_argument("source", source_fn, GetOpt::REQUIRED_ARG).set_help("GLSL file to compile");
        getopt(argc, argv);
@@ -45,6 +49,21 @@ GlslCompiler::GlslCompiler(int argc, char **argv):
                stage = GL::SL::Stage::FRAGMENT;
        else if(!dump_ast)
                combined = true;
+
+       for(vector<string>::const_iterator i=spec_values_in.begin(); i!=spec_values_in.end(); ++i)
+       {
+               unsigned colon = i->find(':');
+               if(colon==string::npos || colon==0 || colon+1>=i->size())
+                       throw usage_error("Invalid specialization value");
+
+               string value_str = i->substr(colon+1);
+               int value;
+               if(isnumrc(value_str))
+                       value = lexical_cast<int>(value_str);
+               else
+                       value = lexical_cast<bool>(value_str);
+               spec_values[i->substr(0, colon)] = value;
+       }
 }
 
 int GlslCompiler::main()
@@ -52,6 +71,7 @@ int GlslCompiler::main()
        GL::SL::Compiler compiler(GL::SL::Features::all());
        IO::File file(source_fn);
        compiler.load_source(file, source_fn);
+       compiler.specialize(spec_values);
        if(!parse_only)
                compiler.compile(GL::SL::Compiler::PROGRAM);