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()
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)
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);
}
Features features;
Module *module;
std::vector<std::string> imported_names;
+ bool specialized;
+ std::map<std::string, int> spec_values;
public:
Compiler();
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;
+#include <msp/core/hash.h>
#include <msp/core/raii.h>
+#include <msp/strings/lexicalcast.h>
#include "builtin.h"
#include "generate.h"
}
+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;
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:
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();
}
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;
#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;
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);
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()
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);