From 6288c42adde9ee7d39a47de51fa2856cf965dccc Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Fri, 26 Feb 2021 23:10:17 +0200 Subject: [PATCH] Support specialization constants in the GLSL compiler --- source/glsl/compiler.cpp | 13 ++++++++-- source/glsl/compiler.h | 3 +++ source/glsl/generate.cpp | 55 ++++++++++++++++++++++++++++++++++++++++ source/glsl/generate.h | 14 ++++++++++ source/glsl/optimize.cpp | 8 +++++- source/glsl/parser.cpp | 10 +++++++- tools/glslcompiler.cpp | 20 +++++++++++++++ 7 files changed, 119 insertions(+), 4 deletions(-) diff --git a/source/glsl/compiler.cpp b/source/glsl/compiler.cpp index ca6c5805..a18b8e8c 100644 --- a/source/glsl/compiler.cpp +++ b/source/glsl/compiler.cpp @@ -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 &sv) +{ + specialized = true; + spec_values = sv; +} + void Compiler::compile(Mode mode) { for(list::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); } diff --git a/source/glsl/compiler.h b/source/glsl/compiler.h index 4eaff213..69ac7427 100644 --- a/source/glsl/compiler.h +++ b/source/glsl/compiler.h @@ -24,6 +24,8 @@ private: Features features; Module *module; std::vector imported_names; + bool specialized; + std::map spec_values; public: Compiler(); @@ -36,6 +38,7 @@ public: void set_source(const std::string &, const std::string & = ""); void load_source(IO::Base &, DataFile::Collection * = 0, const std::string & = ""); void load_source(IO::Base &, const std::string &); + void specialize(const std::map &); void compile(Mode); std::string get_combined_glsl() const; diff --git a/source/glsl/generate.cpp b/source/glsl/generate.cpp index 42226a91..2ac37a6f 100644 --- a/source/glsl/generate.cpp +++ b/source/glsl/generate.cpp @@ -1,4 +1,6 @@ +#include #include +#include #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 *v) +{ + values = v; + stage.content.visit(*this); +} + +void ConstantSpecializer::visit(VariableDeclaration &var) +{ + bool specializable = false; + if(var.layout) + { + vector &qualifiers = var.layout->qualifiers; + for(vector::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::const_iterator i = values->find(var.name); + if(i!=values->end()) + { + RefPtr literal = new Literal; + if(var.type=="bool") + { + literal->token = (i->second ? "true" : "false"); + literal->value = static_cast(i->second); + } + else if(var.type=="int") + { + literal->token = lexical_cast(i->second); + literal->value = i->second; + } + var.init_expression = literal; + } + } +} + + void BlockResolver::enter(Block &block) { block.parent = current_block; diff --git a/source/glsl/generate.h b/source/glsl/generate.h index f1f10b89..68816b8b 100644 --- a/source/glsl/generate.h +++ b/source/glsl/generate.h @@ -27,6 +27,20 @@ private: virtual void visit(VariableDeclaration &); }; +class ConstantSpecializer: private TraversingVisitor +{ +private: + const std::map *values; + +public: + ConstantSpecializer(); + + void apply(Stage &, const std::map *); + +private: + virtual void visit(VariableDeclaration &); +}; + class BlockResolver: private TraversingVisitor { public: diff --git a/source/glsl/optimize.cpp b/source/glsl/optimize.cpp index 3f63dd8a..2215f833 100644 --- a/source/glsl/optimize.cpp +++ b/source/glsl/optimize.cpp @@ -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::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(); } diff --git a/source/glsl/parser.cpp b/source/glsl/parser.cpp index b493c677..5ffc2a9b 100644 --- a/source/glsl/parser.cpp +++ b/source/glsl/parser.cpp @@ -327,7 +327,15 @@ RefPtr 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; diff --git a/tools/glslcompiler.cpp b/tools/glslcompiler.cpp index 74b37ef6..0ce5f01d 100644 --- a/tools/glslcompiler.cpp +++ b/tools/glslcompiler.cpp @@ -2,11 +2,13 @@ #include #include #include +#include class GlslCompiler: public Msp::RegisteredApplication { private: std::string source_fn; + std::map 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 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::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(value_str); + else + value = lexical_cast(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); -- 2.43.0