From: Mikko Rasa Date: Sun, 14 Feb 2021 12:13:56 +0000 (+0200) Subject: Move the GLSL compiler entirely in its own namespace X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=commitdiff_plain;h=c1b0303f65ee966a973197cbdbf177c571478674 Move the GLSL compiler entirely in its own namespace --- diff --git a/Build b/Build index f193a780..02f502b4 100644 --- a/Build +++ b/Build @@ -53,13 +53,13 @@ package "mspgl" source "shaderlib"; build_info { + incpath "source"; incpath "source/core"; incpath "source/materials"; incpath "source/render"; incpath "source/effects"; incpath "source/animation"; incpath "source/resources"; - incpath "source/glsl"; incpath "source/builders"; }; install true; @@ -71,7 +71,7 @@ package "mspgl" map "source/effects" "include/msp/gl"; map "source/animation" "include/msp/gl"; map "source/resources" "include/msp/gl"; - map "source/glsl" "include/msp/gl"; + map "source/glsl" "include/msp/gl/glsl"; map "source/builders" "include/msp/gl"; map "extensions" "include/msp/gl/extensions"; }; diff --git a/source/core/program.cpp b/source/core/program.cpp index 00bca834..74c1df3e 100644 --- a/source/core/program.cpp +++ b/source/core/program.cpp @@ -14,9 +14,9 @@ #include "error.h" #include "misc.h" #include "program.h" -#include "programcompiler.h" #include "resources.h" #include "shader.h" +#include "glsl/compiler.h" using namespace std; @@ -32,7 +32,7 @@ Program::Program(const std::string &source) { init(); - ProgramCompiler compiler; + SL::Compiler compiler; if(source.find(';')==string::npos && source.size()>5 && !source.compare(source.size()-5, 5, ".glsl")) { if(RefPtr io = Resources::get_builtins().open(source)) diff --git a/source/glsl/compiler.cpp b/source/glsl/compiler.cpp new file mode 100644 index 00000000..b862ef20 --- /dev/null +++ b/source/glsl/compiler.cpp @@ -0,0 +1,2094 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "error.h" +#include "compiler.h" +#include "shader.h" + +#undef interface + +using namespace std; + +namespace { + +const char builtins_src[] = + "#pragma MSP stage(vertex)\n" + "out gl_PerVertex {\n" + " vec4 gl_Position;\n" + " float gl_ClipDistance[];\n" + "};\n" + "#pragma MSP stage(geometry)\n" + "in gl_PerVertex {\n" + " vec4 gl_Position;\n" + " float gl_ClipDistance[];\n" + "} gl_in[];\n" + "out gl_PerVertex {\n" + " vec4 gl_Position;\n" + " float gl_ClipDistance[];\n" + "};\n"; + +} + +namespace Msp { +namespace GL { +namespace SL { + +Compiler::Compiler(): + resources(0), + module(0) +{ } + +Compiler::~Compiler() +{ + delete module; +} + +void Compiler::compile(const string &source, const string &src_name) +{ + resources = 0; + delete module; + module = new Module(); + Parser parser; + imported_names.push_back(src_name); + append_module(parser.parse(source, src_name, 1)); + process(); +} + +void Compiler::compile(IO::Base &io, Resources *res, const string &src_name) +{ + resources = res; + delete module; + module = new Module(); + Parser parser; + imported_names.push_back(src_name); + append_module(parser.parse(io, src_name, 1)); + process(); +} + +void Compiler::compile(IO::Base &io, const string &src_name) +{ + compile(io, 0, src_name); +} + +void Compiler::add_shaders(Program &program) +{ + if(!module) + throw invalid_operation("Compiler::add_shaders"); + + try + { + for(list::iterator i=module->stages.begin(); i!=module->stages.end(); ++i) + { + if(i->type==VERTEX) + { + program.attach_shader_owned(new VertexShader(apply(*i))); + for(map::iterator j=i->locations.begin(); j!=i->locations.end(); ++j) + program.bind_attribute(j->second, j->first); + } + else if(i->type==GEOMETRY) + program.attach_shader_owned(new GeometryShader(apply(*i))); + else if(i->type==FRAGMENT) + { + program.attach_shader_owned(new FragmentShader(apply(*i))); + if(EXT_gpu_shader4) + { + for(map::iterator j=i->locations.begin(); j!=i->locations.end(); ++j) + program.bind_fragment_data(j->second, j->first); + } + } + } + } + catch(const compile_error &e) + { + static const Regex r_message("^(([0-9]+)\\(([0-9]+)\\) :|ERROR: ([0-9]+):([0-9]+):) (.*)$"); + vector lines = split(e.what(), '\n'); + string translated; + for(vector::const_iterator i=lines.begin(); i!=lines.end(); ++i) + { + RegMatch m = r_message.match(*i); + if(m) + { + unsigned index = 0; + unsigned line = 0; + if(m[2]) + { + index = lexical_cast(m[2].str); + line = lexical_cast(m[3].str); + } + else if(m[4]) + { + index = lexical_cast(m[4].str); + line = lexical_cast(m[5].str); + } + const char *src = ""; + if(index==0) + src = ""; + else if(index-1")); + for(list::iterator i=module->stages.begin(); i!=module->stages.end(); ++i) + { + VariableResolver resolver; + i->content.visit(resolver); + for(map::iterator j=i->content.variables.begin(); j!=i->content.variables.end(); ++j) + j->second->linked_declaration = j->second; + } + return module; +} + +Module &Compiler::get_builtins_module() +{ + static RefPtr builtins_module = create_builtins_module(); + return *builtins_module; +} + +Stage *Compiler::get_builtins(StageType type) +{ + Module &module = get_builtins_module(); + for(list::iterator i=module.stages.begin(); i!=module.stages.end(); ++i) + if(i->type==type) + return &*i; + return 0; +} + +void Compiler::append_module(Module &mod) +{ + vector imports = apply >(mod.shared); + for(vector::iterator i=imports.begin(); i!=imports.end(); ++i) + import((*i)->module); + apply(mod.shared, set(imports.begin(), imports.end())); + + append_stage(mod.shared); + for(list::iterator i=mod.stages.begin(); i!=mod.stages.end(); ++i) + append_stage(*i); +} + +void Compiler::append_stage(Stage &stage) +{ + Stage *target = 0; + if(stage.type==SHARED) + target = &module->shared; + else + { + list::iterator i; + for(i=module->stages.begin(); (i!=module->stages.end() && i->typestages.end() || i->type>stage.type) + { + list::iterator j = module->stages.insert(i, stage.type); + if(i!=module->stages.end()) + i->previous = &*j; + i = j; + if(i!=module->stages.begin()) + i->previous = &*--j; + } + + target = &*i; + } + + if(stage.required_version>target->required_version) + target->required_version = stage.required_version; + for(NodeList::iterator i=stage.content.body.begin(); i!=stage.content.body.end(); ++i) + target->content.body.push_back(*i); + apply(*target); +} + +void Compiler::process() +{ + for(list::iterator i=module->stages.begin(); i!=module->stages.end(); ++i) + generate(*i); + for(list::iterator i=module->stages.begin(); i!=module->stages.end(); ) + { + if(optimize(*i)) + i = module->stages.begin(); + else + ++i; + } + for(list::iterator i=module->stages.begin(); i!=module->stages.end(); ++i) + finalize(*i); +} + +void Compiler::import(const string &name) +{ + string fn = name+".glsl"; + if(find(imported_names, fn)!=imported_names.end()) + return; + imported_names.push_back(fn); + + RefPtr io = (resources ? resources->open_raw(fn) : Resources::get_builtins().open(fn)); + if(!io) + throw runtime_error(format("module %s not found", name)); + Parser import_parser; + append_module(import_parser.parse(*io, fn, imported_names.size())); +} + +void Compiler::generate(Stage &stage) +{ + if(module->shared.required_version>stage.required_version) + stage.required_version = module->shared.required_version; + inject_block(stage.content, module->shared.content); + + apply(stage); + apply(stage); + apply(stage); + apply(stage); + apply(stage); + apply(stage); + apply(stage); + apply(stage); +} + +bool Compiler::optimize(Stage &stage) +{ + apply(stage); + + set inlineable = apply(stage); + apply(stage, inlineable); + + set unused = apply(stage); + set unused2 = apply(stage); + unused.insert(unused2.begin(), unused2.end()); + apply(stage, unused); + + return !unused.empty(); +} + +void Compiler::finalize(Stage &stage) +{ + if(get_gl_api()==OPENGL_ES2) + apply(stage); + else + apply(stage); +} + +void Compiler::inject_block(Block &target, const Block &source) +{ + NodeList::iterator insert_point = target.body.begin(); + for(NodeList::const_iterator i=source.body.begin(); i!=source.body.end(); ++i) + target.body.insert(insert_point, (*i)->clone()); +} + +template +typename T::ResultType Compiler::apply(Stage &stage) +{ + T visitor; + visitor.apply(stage); + return visitor.get_result(); +} + +template +typename T::ResultType Compiler::apply(Stage &stage, const A &arg) +{ + T visitor(arg); + visitor.apply(stage); + return visitor.get_result(); +} + + +Compiler::Visitor::Visitor(): + stage(0) +{ } + +void Compiler::Visitor::apply(Stage &s) +{ + SetForScope set(stage, &s); + stage->content.visit(*this); +} + + +Compiler::BlockModifier::BlockModifier(): + remove_node(false) +{ } + +void Compiler::BlockModifier::flatten_block(Block &block) +{ + insert_nodes.insert(insert_nodes.end(), block.body.begin(), block.body.end()); + remove_node = true; +} + +void Compiler::BlockModifier::apply_and_increment(Block &block, NodeList::iterator &i) +{ + block.body.insert(i, insert_nodes.begin(), insert_nodes.end()); + insert_nodes.clear(); + + if(remove_node) + block.body.erase(i++); + else + ++i; + remove_node = false; +} + +void Compiler::BlockModifier::visit(Block &block) +{ + for(NodeList::iterator i=block.body.begin(); i!=block.body.end(); ) + { + (*i)->visit(*this); + apply_and_increment(block, i); + } +} + + +Compiler::Formatter::Formatter(): + source_index(0), + source_line(1), + indent(0), + parameter_list(false) +{ } + +void Compiler::Formatter::apply(Stage &s) +{ + GLApi api = get_gl_api(); + const Version &ver = s.required_version; + + if(ver) + { + append(format("#version %d%02d", ver.major, ver.minor)); + if(api==OPENGL_ES2 && ver>=Version(3, 0)) + append(" es"); + formatted += '\n'; + } + + for(vector::const_iterator i=s.required_extensions.begin(); i!=s.required_extensions.end(); ++i) + append(format("#extension %s: require\n", (*i)->get_name())); + if(!s.required_extensions.empty()) + formatted += '\n'; + + Visitor::apply(s); +} + +void Compiler::Formatter::append(const string &text) +{ + formatted += text; + for(string::const_iterator i=text.begin(); i!=text.end(); ++i) + if(*i=='\n') + ++source_line; +} + +void Compiler::Formatter::append(char c) +{ + formatted += c; + if(c=='\n') + ++source_line; +} + +void Compiler::Formatter::set_source(unsigned index, unsigned line) +{ + if(index!=source_index || (index && line!=source_line)) + { + if(index==source_index && line==source_line+1) + formatted += '\n'; + else + { + unsigned l = line; + if(stage->required_versionvisit(*this); + append(')'); +} + +void Compiler::Formatter::visit(VariableReference &var) +{ + append(var.name); +} + +void Compiler::Formatter::visit(MemberAccess &memacc) +{ + memacc.left->visit(*this); + append(format(".%s", memacc.member)); +} + +void Compiler::Formatter::visit(UnaryExpression &unary) +{ + if(unary.prefix) + append(unary.oper); + unary.expression->visit(*this); + if(!unary.prefix) + append(unary.oper); +} + +void Compiler::Formatter::visit(BinaryExpression &binary) +{ + binary.left->visit(*this); + append(binary.oper); + binary.right->visit(*this); + append(binary.after); +} + +void Compiler::Formatter::visit(Assignment &assign) +{ + assign.left->visit(*this); + append(format(" %s ", assign.oper)); + assign.right->visit(*this); +} + +void Compiler::Formatter::visit(FunctionCall &call) +{ + append(format("%s(", call.name)); + for(NodeArray::iterator i=call.arguments.begin(); i!=call.arguments.end(); ++i) + { + if(i!=call.arguments.begin()) + append(", "); + (*i)->visit(*this); + } + append(')'); +} + +void Compiler::Formatter::visit(ExpressionStatement &expr) +{ + expr.expression->visit(*this); + append(';'); +} + +void Compiler::Formatter::visit(Block &block) +{ + unsigned brace_indent = indent; + bool use_braces = (block.use_braces || (indent && block.body.size()!=1)); + if(use_braces) + append(format("%s{\n", string(brace_indent*2, ' '))); + + SetForScope set(indent, indent+(indent>0 || use_braces)); + string spaces(indent*2, ' '); + for(NodeList::iterator i=block.body.begin(); i!=block.body.end(); ++i) + { + if(i!=block.body.begin()) + append('\n'); + set_source((*i)->source, (*i)->line); + append(spaces); + (*i)->visit(*this); + } + + if(use_braces) + append(format("\n%s}", string(brace_indent*2, ' '))); +} + +void Compiler::Formatter::visit(Import &import) +{ + append(format("import %s;", import.module)); +} + +void Compiler::Formatter::visit(Precision &prec) +{ + append(format("precision %s %s;", prec.precision, prec.type)); +} + +void Compiler::Formatter::visit(Layout &layout) +{ + append("layout("); + for(vector::const_iterator i=layout.qualifiers.begin(); i!=layout.qualifiers.end(); ++i) + { + if(i!=layout.qualifiers.begin()) + append(", "); + append(i->identifier); + if(!i->value.empty()) + append(format("=%s", i->value)); + } + append(')'); +} + +void Compiler::Formatter::visit(InterfaceLayout &layout) +{ + layout.layout.visit(*this); + append(format(" %s;", layout.interface)); +} + +void Compiler::Formatter::visit(StructDeclaration &strct) +{ + append(format("struct %s\n", strct.name)); + strct.members.visit(*this); + append(';'); +} + +void Compiler::Formatter::visit(VariableDeclaration &var) +{ + if(var.layout) + { + var.layout->visit(*this); + append(' '); + } + if(var.constant) + append("const "); + if(!var.interpolation.empty()) + append(format("%s ", var.interpolation)); + if(!var.sampling.empty()) + append(format("%s ", var.sampling)); + if(!var.interface.empty() && var.interface!=block_interface) + { + string interface = var.interface; + if(stage->required_versiontype==VERTEX && var.interface=="in") + interface = "attribute"; + else if((stage->type==VERTEX && var.interface=="out") || (stage->type==FRAGMENT && var.interface=="in")) + interface = "varying"; + } + append(format("%s ", interface)); + } + if(!var.precision.empty()) + append(format("%s ", var.precision)); + append(format("%s %s", var.type, var.name)); + if(var.array) + { + append('['); + if(var.array_size) + var.array_size->visit(*this); + append(']'); + } + if(var.init_expression) + { + append(" = "); + var.init_expression->visit(*this); + } + if(!parameter_list) + append(';'); +} + +void Compiler::Formatter::visit(InterfaceBlock &iface) +{ + SetForScope set(block_interface, iface.interface); + append(format("%s %s\n", iface.interface, iface.name)); + iface.members.visit(*this); + append(';'); +} + +void Compiler::Formatter::visit(FunctionDeclaration &func) +{ + append(format("%s %s(", func.return_type, func.name)); + for(NodeArray::iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i) + { + if(i!=func.parameters.begin()) + append(", "); + SetFlag set(parameter_list); + (*i)->visit(*this); + } + append(')'); + if(func.definition==&func) + { + append('\n'); + func.body.visit(*this); + } + else + append(';'); +} + +void Compiler::Formatter::visit(Conditional &cond) +{ + append("if("); + cond.condition->visit(*this); + append(")\n"); + + cond.body.visit(*this); + if(!cond.else_body.body.empty()) + { + Conditional *else_cond = dynamic_cast(cond.else_body.body.front().get()); + if(cond.else_body.body.size()==1 && else_cond) + { + append('\n'); + set_source(else_cond->source, else_cond->line); + append(format("%selse ", string(indent*2, ' '))); + else_cond->visit(*this); + } + else + { + append(format("\n%selse\n", string(indent*2, ' '))); + cond.else_body.visit(*this); + } + } +} + +void Compiler::Formatter::visit(Iteration &iter) +{ + if(!iter.init_statement && iter.condition && !iter.loop_expression) + { + append("while("); + iter.condition->visit(*this); + append(')'); + } + else + { + append("for("); + if(iter.init_statement) + iter.init_statement->visit(*this); + else + append(';'); + if(iter.condition) + { + append(' '); + iter.condition->visit(*this); + } + append(';'); + if(iter.loop_expression) + { + append(' '); + iter.loop_expression->visit(*this); + } + append(')'); + } + + if(iter.body.body.empty()) + append(" { }"); + else + { + append('\n'); + iter.body.visit(*this); + } +} + +void Compiler::Formatter::visit(Return &ret) +{ + append("return"); + if(ret.expression) + { + append(' '); + ret.expression->visit(*this); + } + append(';'); +} + +void Compiler::Formatter::visit(Jump &jump) +{ + append(jump.keyword); + append(';'); +} + + +Compiler::DeclarationCombiner::DeclarationCombiner(): + toplevel(true) +{ } + +void Compiler::DeclarationCombiner::visit(Block &block) +{ + if(!toplevel) + return; + + SetForScope set(toplevel, false); + BlockModifier::visit(block); +} + +void Compiler::DeclarationCombiner::visit(FunctionDeclaration &func) +{ + vector &decls = functions[func.name]; + if(func.definition) + { + for(vector::iterator i=decls.begin(); i!=decls.end(); ++i) + { + (*i)->definition = func.definition; + (*i)->body.body.clear(); + } + } + decls.push_back(&func); +} + +void Compiler::DeclarationCombiner::visit(VariableDeclaration &var) +{ + VariableDeclaration *&ptr = variables[var.name]; + if(ptr) + { + ptr->type = var.type; + if(var.init_expression) + ptr->init_expression = var.init_expression; + if(var.layout) + { + if(ptr->layout) + { + for(vector::iterator i=var.layout->qualifiers.begin(); i!=var.layout->qualifiers.end(); ++i) + { + bool found = false; + for(vector::iterator j=ptr->layout->qualifiers.begin(); (!found && j!=ptr->layout->qualifiers.end()); ++j) + if(j->identifier==i->identifier) + { + j->value = i->value; + found = true; + } + + if(!found) + ptr->layout->qualifiers.push_back(*i); + } + } + else + ptr->layout = var.layout; + } + remove_node = true; + } + else + ptr = &var; +} + + +Compiler::VariableResolver::VariableResolver(): + anonymous(false), + record_target(false), + assignment_target(0), + self_referencing(false) +{ } + +void Compiler::VariableResolver::apply(Stage &s) +{ + SetForScope set(stage, &s); + Stage *builtins = get_builtins(stage->type); + if(builtins) + blocks.push_back(&builtins->content); + stage->content.visit(*this); + if(builtins) + blocks.pop_back(); +} + +void Compiler::VariableResolver::visit(Block &block) +{ + blocks.push_back(&block); + block.variables.clear(); + TraversingVisitor::visit(block); + blocks.pop_back(); +} + +void Compiler::VariableResolver::visit(VariableReference &var) +{ + var.declaration = 0; + type = 0; + for(vector::iterator i=blocks.end(); i!=blocks.begin(); ) + { + --i; + map::iterator j = (*i)->variables.find(var.name); + if(j!=(*i)->variables.end()) + { + var.declaration = j->second; + type = j->second->type_declaration; + break; + } + } + + if(record_target) + { + if(assignment_target) + { + record_target = false; + assignment_target = 0; + } + else + assignment_target = var.declaration; + } + else if(var.declaration && var.declaration==assignment_target) + self_referencing = true; +} + +void Compiler::VariableResolver::visit(MemberAccess &memacc) +{ + type = 0; + TraversingVisitor::visit(memacc); + memacc.declaration = 0; + if(type) + { + map::iterator i = type->members.variables.find(memacc.member); + if(i!=type->members.variables.end()) + { + memacc.declaration = i->second; + type = i->second->type_declaration; + } + else + type = 0; + } +} + +void Compiler::VariableResolver::visit(BinaryExpression &binary) +{ + if(binary.oper=="[") + { + { + SetForScope set(record_target, false); + binary.right->visit(*this); + } + type = 0; + binary.left->visit(*this); + } + else + { + TraversingVisitor::visit(binary); + type = 0; + } +} + +void Compiler::VariableResolver::visit(Assignment &assign) +{ + { + SetFlag set(record_target); + assignment_target = 0; + assign.left->visit(*this); + } + + self_referencing = false; + assign.right->visit(*this); + + assign.self_referencing = (self_referencing || assign.oper!="="); + assign.target_declaration = assignment_target; +} + +void Compiler::VariableResolver::visit(StructDeclaration &strct) +{ + TraversingVisitor::visit(strct); + blocks.back()->types[strct.name] = &strct; +} + +void Compiler::VariableResolver::visit(VariableDeclaration &var) +{ + for(vector::iterator i=blocks.end(); i!=blocks.begin(); ) + { + --i; + map::iterator j = (*i)->types.find(var.type); + if(j!=(*i)->types.end()) + var.type_declaration = j->second; + } + + if(!block_interface.empty() && var.interface.empty()) + var.interface = block_interface; + + TraversingVisitor::visit(var); + blocks.back()->variables[var.name] = &var; + if(anonymous && blocks.size()>1) + blocks[blocks.size()-2]->variables[var.name] = &var; +} + +void Compiler::VariableResolver::visit(InterfaceBlock &iface) +{ + SetFlag set(anonymous); + SetForScope set2(block_interface, iface.interface); + TraversingVisitor::visit(iface); +} + + +void Compiler::FunctionResolver::visit(FunctionCall &call) +{ + map >::iterator i = functions.find(call.name); + if(i!=functions.end()) + call.declaration = i->second.back(); + + TraversingVisitor::visit(call); +} + +void Compiler::FunctionResolver::visit(FunctionDeclaration &func) +{ + vector &decls = functions[func.name]; + if(func.definition) + { + for(vector::iterator i=decls.begin(); i!=decls.end(); ++i) + (*i)->definition = func.definition; + decls.clear(); + decls.push_back(&func); + } + else if(!decls.empty() && decls.back()->definition) + func.definition = decls.back()->definition; + else + decls.push_back(&func); + + TraversingVisitor::visit(func); +} + + +Compiler::InterfaceGenerator::InterfaceGenerator(): + scope_level(0) +{ } + +string Compiler::InterfaceGenerator::get_out_prefix(StageType type) +{ + if(type==VERTEX) + return "_vs_out_"; + else if(type==GEOMETRY) + return "_gs_out_"; + else + return string(); +} + +void Compiler::InterfaceGenerator::apply(Stage &s) +{ + SetForScope set(stage, &s); + if(stage->previous) + in_prefix = get_out_prefix(stage->previous->type); + out_prefix = get_out_prefix(stage->type); + stage->content.visit(*this); +} + +void Compiler::InterfaceGenerator::visit(Block &block) +{ + SetForScope set(scope_level, scope_level+1); + for(NodeList::iterator i=block.body.begin(); i!=block.body.end(); ) + { + (*i)->visit(*this); + + if(scope_level==1) + { + for(map >::iterator j=iface_declarations.begin(); j!=iface_declarations.end(); ++j) + { + NodeList::iterator k = block.body.insert(i, j->second); + (*k)->visit(*this); + } + iface_declarations.clear(); + } + + apply_and_increment(block, i); + } +} + +string Compiler::InterfaceGenerator::change_prefix(const string &name, const string &prefix) const +{ + unsigned offset = (name.compare(0, in_prefix.size(), in_prefix) ? 0 : in_prefix.size()); + return prefix+name.substr(offset); +} + +bool Compiler::InterfaceGenerator::generate_interface(VariableDeclaration &var, const string &iface, const string &name) +{ + const map &stage_vars = (iface=="in" ? stage->in_variables : stage->out_variables); + if(stage_vars.count(name) || iface_declarations.count(name)) + return false; + + VariableDeclaration* iface_var = new VariableDeclaration; + iface_var->sampling = var.sampling; + iface_var->interface = iface; + iface_var->type = var.type; + iface_var->type_declaration = var.type_declaration; + iface_var->name = name; + if(stage->type==GEOMETRY) + iface_var->array = ((var.array && var.interface!="in") || iface=="in"); + else + iface_var->array = var.array; + if(iface_var->array) + iface_var->array_size = var.array_size; + if(iface=="in") + iface_var->linked_declaration = &var; + iface_declarations[name] = iface_var; + + return true; +} + +ExpressionStatement &Compiler::InterfaceGenerator::insert_assignment(const string &left, Expression *right) +{ + Assignment *assign = new Assignment; + VariableReference *ref = new VariableReference; + ref->name = left; + assign->left = ref; + assign->oper = "="; + assign->right = right; + + ExpressionStatement *stmt = new ExpressionStatement; + stmt->expression = assign; + stmt->visit(*this); + insert_nodes.push_back(stmt); + + return *stmt; +} + +void Compiler::InterfaceGenerator::visit(VariableReference &var) +{ + if(var.declaration || !stage->previous) + return; + if(iface_declarations.count(var.name)) + return; + + const map &prev_out = stage->previous->out_variables; + map::const_iterator i = prev_out.find(var.name); + if(i==prev_out.end()) + i = prev_out.find(in_prefix+var.name); + if(i!=prev_out.end()) + { + generate_interface(*i->second, "in", i->second->name); + var.name = i->second->name; + } +} + +void Compiler::InterfaceGenerator::visit(VariableDeclaration &var) +{ + if(var.interface=="out") + { + if(scope_level==1) + stage->out_variables[var.name] = &var; + else if(generate_interface(var, "out", change_prefix(var.name, string()))) + { + remove_node = true; + if(var.init_expression) + { + ExpressionStatement &stmt = insert_assignment(var.name, var.init_expression->clone()); + stmt.source = var.source; + stmt.line = var.line; + return; + } + } + } + else if(var.interface=="in") + { + stage->in_variables[var.name] = &var; + if(var.linked_declaration) + var.linked_declaration->linked_declaration = &var; + else if(stage->previous) + { + const map &prev_out = stage->previous->out_variables; + map::const_iterator i = prev_out.find(var.name); + if(i!=prev_out.end()) + { + var.linked_declaration = i->second; + i->second->linked_declaration = &var; + } + } + } + + TraversingVisitor::visit(var); +} + +void Compiler::InterfaceGenerator::visit(Passthrough &pass) +{ + vector pass_vars; + + for(map::const_iterator i=stage->in_variables.begin(); i!=stage->in_variables.end(); ++i) + pass_vars.push_back(i->second); + for(map >::const_iterator i=iface_declarations.begin(); i!=iface_declarations.end(); ++i) + if(i->second->interface=="in") + pass_vars.push_back(i->second.get()); + + if(stage->previous) + { + const map &prev_out = stage->previous->out_variables; + for(map::const_iterator i=prev_out.begin(); i!=prev_out.end(); ++i) + { + bool linked = false; + for(vector::const_iterator j=pass_vars.begin(); (!linked && j!=pass_vars.end()); ++j) + linked = ((*j)->linked_declaration==i->second); + + if(!linked && generate_interface(*i->second, "in", i->second->name)) + pass_vars.push_back(i->second); + } + } + + if(stage->type==GEOMETRY) + { + VariableReference *ref = new VariableReference; + ref->name = "gl_in"; + + BinaryExpression *subscript = new BinaryExpression; + subscript->left = ref; + subscript->oper = "["; + subscript->right = pass.subscript; + subscript->after = "]"; + + MemberAccess *memacc = new MemberAccess; + memacc->left = subscript; + memacc->member = "gl_Position"; + + insert_assignment("gl_Position", memacc); + } + + for(vector::const_iterator i=pass_vars.begin(); i!=pass_vars.end(); ++i) + { + string out_name = change_prefix((*i)->name, out_prefix); + generate_interface(**i, "out", out_name); + + VariableReference *ref = new VariableReference; + ref->name = (*i)->name; + if(pass.subscript) + { + BinaryExpression *subscript = new BinaryExpression; + subscript->left = ref; + subscript->oper = "["; + subscript->right = pass.subscript; + subscript->after = "]"; + insert_assignment(out_name, subscript); + } + else + insert_assignment(out_name, ref); + } + + remove_node = true; +} + + +Compiler::DeclarationReorderer::DeclarationReorderer(): + scope_level(0), + kind(NO_DECLARATION) +{ } + +void Compiler::DeclarationReorderer::visit(FunctionCall &call) +{ + FunctionDeclaration *def = call.declaration; + if(def) + def = def->definition; + if(def && !ordered_funcs.count(def)) + needed_funcs.insert(def); +} + +void Compiler::DeclarationReorderer::visit(Block &block) +{ + SetForScope set(scope_level, scope_level+1); + if(scope_level>1) + return Visitor::visit(block); + + NodeList::iterator struct_insert_point = block.body.end(); + NodeList::iterator variable_insert_point = block.body.end(); + NodeList::iterator function_insert_point = block.body.end(); + unsigned unordered_func_count = 0; + bool ordered_any_funcs = false; + + for(NodeList::iterator i=block.body.begin(); i!=block.body.end(); ) + { + kind = NO_DECLARATION; + (*i)->visit(*this); + + bool moved = false; + if(kind==STRUCT && struct_insert_point!=block.body.end()) + { + block.body.insert(struct_insert_point, *i); + moved = true; + } + else if(kind>STRUCT && struct_insert_point==block.body.end()) + struct_insert_point = i; + + if(kind==VARIABLE && variable_insert_point!=block.body.end()) + { + block.body.insert(variable_insert_point, *i); + moved = true; + } + else if(kind>VARIABLE && variable_insert_point==block.body.end()) + variable_insert_point = i; + + if(kind==FUNCTION) + { + if(function_insert_point==block.body.end()) + function_insert_point = i; + + if(needed_funcs.empty()) + { + ordered_funcs.insert(i->get()); + if(i!=function_insert_point) + { + block.body.insert(function_insert_point, *i); + moved = true; + } + else + ++function_insert_point; + ordered_any_funcs = true; + } + else + ++unordered_func_count; + } + + if(moved) + { + if(function_insert_point==i) + ++function_insert_point; + block.body.erase(i++); + } + else + ++i; + + if(i==block.body.end() && unordered_func_count) + { + if(!ordered_any_funcs) + // A subset of the remaining functions forms a recursive loop + /* TODO pick a function and move it up, adding any necessary + declarations */ + break; + + i = function_insert_point; + unordered_func_count = 0; + } + } +} + +void Compiler::DeclarationReorderer::visit(VariableDeclaration &var) +{ + Visitor::visit(var); + kind = VARIABLE; +} + +void Compiler::DeclarationReorderer::visit(FunctionDeclaration &func) +{ + needed_funcs.clear(); + func.body.visit(*this); + needed_funcs.erase(&func); + kind = FUNCTION; +} + + +Compiler::InlineableFunctionLocator::InlineableFunctionLocator(): + in_function(0) +{ } + +void Compiler::InlineableFunctionLocator::visit(FunctionCall &call) +{ + FunctionDeclaration *def = call.declaration; + if(def && def->definition!=def) + def = def->definition; + + if(def) + { + unsigned &count = refcounts[def]; + ++count; + if(count>1 || def==in_function) + inlineable.erase(def); + } + + TraversingVisitor::visit(call); +} + +void Compiler::InlineableFunctionLocator::visit(FunctionDeclaration &func) +{ + unsigned &count = refcounts[func.definition]; + if(!count && func.parameters.empty()) + inlineable.insert(func.definition); + + SetForScope set(in_function, &func); + TraversingVisitor::visit(func); +} + + +Compiler::FunctionInliner::FunctionInliner(): + extract_result(0) +{ } + +Compiler::FunctionInliner::FunctionInliner(const set &in): + inlineable(in), + extract_result(0) +{ } + +void Compiler::FunctionInliner::visit_and_inline(RefPtr &ptr) +{ + inline_result = 0; + ptr->visit(*this); + if(inline_result) + ptr = inline_result; +} + +void Compiler::FunctionInliner::visit(Block &block) +{ + if(extract_result) + --extract_result; + + for(NodeList::iterator i=block.body.begin(); i!=block.body.end(); ++i) + { + (*i)->visit(*this); + if(extract_result) + --extract_result; + } +} + +void Compiler::FunctionInliner::visit(UnaryExpression &unary) +{ + visit_and_inline(unary.expression); + inline_result = 0; +} + +void Compiler::FunctionInliner::visit(BinaryExpression &binary) +{ + visit_and_inline(binary.left); + visit_and_inline(binary.right); + inline_result = 0; +} + +void Compiler::FunctionInliner::visit(MemberAccess &memacc) +{ + visit_and_inline(memacc.left); + inline_result = 0; +} + +void Compiler::FunctionInliner::visit(FunctionCall &call) +{ + for(NodeArray::iterator i=call.arguments.begin(); i!=call.arguments.end(); ++i) + visit_and_inline(*i); + + FunctionDeclaration *def = call.declaration; + if(def && def->definition!=def) + def = def->definition; + + if(def && inlineable.count(def)) + { + extract_result = 2; + def->visit(*this); + } + else + inline_result = 0; +} + +void Compiler::FunctionInliner::visit(VariableDeclaration &var) +{ + if(var.init_expression) + visit_and_inline(var.init_expression); + inline_result = 0; +} + +void Compiler::FunctionInliner::visit(Return &ret) +{ + TraversingVisitor::visit(ret); + + if(extract_result) + inline_result = ret.expression->clone(); +} + + +Compiler::ExpressionEvaluator::ExpressionEvaluator(): + variable_values(0), + result(0.0f), + result_valid(false) +{ } + +Compiler::ExpressionEvaluator::ExpressionEvaluator(const ValueMap &v): + variable_values(&v), + result(0.0f), + result_valid(false) +{ } + +void Compiler::ExpressionEvaluator::visit(Literal &literal) +{ + if(literal.token=="true") + result = 1.0f; + else if(literal.token=="false") + result = 0.0f; + else + result = lexical_cast(literal.token); + result_valid = true; +} + +void Compiler::ExpressionEvaluator::visit(ParenthesizedExpression &parexp) +{ + parexp.expression->visit(*this); +} + +void Compiler::ExpressionEvaluator::visit(VariableReference &var) +{ + if(!var.declaration) + return; + + if(variable_values) + { + ValueMap::const_iterator i = variable_values->find(var.declaration); + if(i!=variable_values->end()) + i->second->visit(*this); + } + else if(var.declaration->init_expression) + var.declaration->init_expression->visit(*this); +} + +void Compiler::ExpressionEvaluator::visit(UnaryExpression &unary) +{ + result_valid = false; + unary.expression->visit(*this); + if(!result_valid) + return; + + if(unary.oper=="!") + result = !result; + else + result_valid = false; +} + +void Compiler::ExpressionEvaluator::visit(BinaryExpression &binary) +{ + result_valid = false; + binary.left->visit(*this); + if(!result_valid) + return; + + float left_result = result; + result_valid = false; + binary.right->visit(*this); + if(!result_valid) + return; + + if(binary.oper=="<") + result = (left_result") + result = (left_result>result); + else if(binary.oper==">=") + result = (left_result>=result); + else if(binary.oper=="==") + result = (left_result==result); + else if(binary.oper=="!=") + result = (left_result!=result); + else if(binary.oper=="&&") + result = (left_result && result); + else if(binary.oper=="||") + result = (left_result || result); + else + result_valid = false; +} + + +Compiler::ConstantConditionEliminator::ConstantConditionEliminator(): + scope_level(0), + record_only(false) +{ } + +void Compiler::ConstantConditionEliminator::visit(Block &block) +{ + SetForScope set(scope_level, scope_level+1); + BlockModifier::visit(block); + + for(map::const_iterator i=block.variables.begin(); i!=block.variables.end(); ++i) + variable_values.erase(i->second); +} + +void Compiler::ConstantConditionEliminator::visit(UnaryExpression &unary) +{ + if(VariableReference *var = dynamic_cast(unary.expression.get())) + if(unary.oper=="++" || unary.oper=="--") + variable_values.erase(var->declaration); +} + +void Compiler::ConstantConditionEliminator::visit(Assignment &assign) +{ + variable_values.erase(assign.target_declaration); +} + +void Compiler::ConstantConditionEliminator::visit(VariableDeclaration &var) +{ + if(var.constant || scope_level>1) + variable_values[&var] = var.init_expression.get(); +} + +void Compiler::ConstantConditionEliminator::visit(Conditional &cond) +{ + if(!record_only) + { + ExpressionEvaluator eval(variable_values); + cond.condition->visit(eval); + if(eval.result_valid) + { + flatten_block(eval.result ? cond.body : cond.else_body); + return; + } + } + + TraversingVisitor::visit(cond); +} + +void Compiler::ConstantConditionEliminator::visit(Iteration &iter) +{ + if(!record_only) + { + if(iter.condition) + { + /* If the loop condition is always false on the first iteration, the + entire loop can be removed */ + if(iter.init_statement) + iter.init_statement->visit(*this); + ExpressionEvaluator eval(variable_values); + iter.condition->visit(eval); + if(eval.result_valid && !eval.result) + { + remove_node = true; + return; + } + } + + /* Record all assignments that occur inside the loop body so those + variables won't be considered as constant */ + SetFlag set_record(record_only); + TraversingVisitor::visit(iter); + } + + TraversingVisitor::visit(iter); + + if(VariableDeclaration *init_decl = dynamic_cast(iter.init_statement.get())) + variable_values.erase(init_decl); +} + + +Compiler::UnusedVariableLocator::UnusedVariableLocator(): + aggregate(0), + assignment(0), + assignment_target(false), + assign_to_subscript(false), + global_scope(true) +{ } + +void Compiler::UnusedVariableLocator::apply(Stage &s) +{ + variables.push_back(BlockVariableMap()); + Visitor::apply(s); + BlockVariableMap &global_variables = variables.back(); + for(BlockVariableMap::iterator i=global_variables.begin(); i!=global_variables.end(); ++i) + { + if(i->first->interface=="out" && (s.type==FRAGMENT || i->first->linked_declaration || !i->first->name.compare(0, 3, "gl_"))) + continue; + if(!i->second.referenced) + { + unused_nodes.insert(i->first); + clear_assignments(i->second, true); + } + } + variables.pop_back(); +} + +void Compiler::UnusedVariableLocator::visit(VariableReference &var) +{ + map::iterator i = aggregates.find(var.declaration); + if(i!=aggregates.end()) + unused_nodes.erase(i->second); + + if(var.declaration && !assignment_target) + { + VariableInfo &var_info = variables.back()[var.declaration]; + var_info.assignments.clear(); + var_info.referenced = true; + } +} + +void Compiler::UnusedVariableLocator::visit(MemberAccess &memacc) +{ + TraversingVisitor::visit(memacc); + unused_nodes.erase(memacc.declaration); +} + +void Compiler::UnusedVariableLocator::visit(BinaryExpression &binary) +{ + if(binary.oper=="[") + { + if(assignment_target) + assign_to_subscript = true; + binary.left->visit(*this); + SetForScope set(assignment_target, false); + binary.right->visit(*this); + } + else + TraversingVisitor::visit(binary); +} + +void Compiler::UnusedVariableLocator::visit(Assignment &assign) +{ + { + assign_to_subscript = false; + SetForScope set(assignment_target, !assign.self_referencing); + assign.left->visit(*this); + } + assign.right->visit(*this); + assignment = &assign; +} + +void Compiler::UnusedVariableLocator::record_assignment(VariableDeclaration &var, Node &node, bool chained) +{ + VariableInfo &var_info = variables.back()[&var]; + if(!chained) + clear_assignments(var_info, true); + var_info.assignments.push_back(&node); + var_info.conditionally_assigned = false; +} + +void Compiler::UnusedVariableLocator::clear_assignments(VariableInfo &var_info, bool mark_unused) +{ + if(mark_unused) + { + for(vector::iterator i=var_info.assignments.begin(); i!=var_info.assignments.end(); ++i) + unused_nodes.insert(*i); + } + var_info.assignments.clear(); +} + +void Compiler::UnusedVariableLocator::visit(ExpressionStatement &expr) +{ + assignment = 0; + TraversingVisitor::visit(expr); + if(assignment && assignment->target_declaration) + record_assignment(*assignment->target_declaration, expr, (assignment->self_referencing || assign_to_subscript)); +} + +void Compiler::UnusedVariableLocator::visit(StructDeclaration &strct) +{ + SetForScope set(aggregate, &strct); + unused_nodes.insert(&strct); + TraversingVisitor::visit(strct); +} + +void Compiler::UnusedVariableLocator::visit(VariableDeclaration &var) +{ + if(aggregate) + aggregates[&var] = aggregate; + else + { + variables.back()[&var].local = true; + if(var.init_expression) + record_assignment(var, *var.init_expression, false); + } + unused_nodes.erase(var.type_declaration); + TraversingVisitor::visit(var); +} + +void Compiler::UnusedVariableLocator::visit(InterfaceBlock &iface) +{ + SetForScope set(aggregate, &iface); + unused_nodes.insert(&iface); + TraversingVisitor::visit(iface); +} + +void Compiler::UnusedVariableLocator::visit(FunctionDeclaration &func) +{ + variables.push_back(BlockVariableMap()); + + { + SetForScope set(global_scope, false); + for(NodeArray::iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i) + (*i)->visit(*this); + func.body.visit(*this); + } + + BlockVariableMap &block_variables = variables.back(); + for(BlockVariableMap::iterator i=block_variables.begin(); i!=block_variables.end(); ++i) + i->second.conditionally_assigned = true; + for(NodeArray::iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i) + block_variables[i->get()].referenced = true; + merge_down_variables(); +} + +void Compiler::UnusedVariableLocator::merge_down_variables() +{ + BlockVariableMap &parent_variables = variables[variables.size()-2]; + BlockVariableMap &block_variables = variables.back(); + for(BlockVariableMap::iterator i=block_variables.begin(); i!=block_variables.end(); ++i) + { + if(i->second.local) + { + if(!i->second.referenced) + unused_nodes.insert(i->first); + clear_assignments(i->second, i->first->interface!="out"); + continue; + } + + BlockVariableMap::iterator j = parent_variables.find(i->first); + if(j==parent_variables.end()) + parent_variables.insert(*i); + else + { + if(i->second.referenced || !i->second.conditionally_assigned) + clear_assignments(j->second, !i->second.referenced); + j->second.conditionally_assigned = i->second.conditionally_assigned; + j->second.referenced |= i->second.referenced; + j->second.assignments.insert(j->second.assignments.end(), i->second.assignments.begin(), i->second.assignments.end()); + } + } + variables.pop_back(); +} + +void Compiler::UnusedVariableLocator::visit(Conditional &cond) +{ + cond.condition->visit(*this); + variables.push_back(BlockVariableMap()); + cond.body.visit(*this); + + BlockVariableMap if_variables; + swap(variables.back(), if_variables); + cond.else_body.visit(*this); + + BlockVariableMap &else_variables = variables.back(); + for(BlockVariableMap::iterator i=else_variables.begin(); i!=else_variables.end(); ++i) + { + BlockVariableMap::iterator j = if_variables.find(i->first); + if(j!=if_variables.end()) + { + i->second.assignments.insert(i->second.assignments.end(), j->second.assignments.begin(), j->second.assignments.end()); + i->second.conditionally_assigned |= j->second.conditionally_assigned; + if_variables.erase(j); + } + else + i->second.conditionally_assigned = true; + } + + for(BlockVariableMap::iterator i=if_variables.begin(); i!=if_variables.end(); ++i) + { + i->second.conditionally_assigned = true; + else_variables.insert(*i); + } + + merge_down_variables(); +} + +void Compiler::UnusedVariableLocator::visit(Iteration &iter) +{ + variables.push_back(BlockVariableMap()); + TraversingVisitor::visit(iter); + + BlockVariableMap &block_variables = variables.back(); + for(BlockVariableMap::iterator i=block_variables.begin(); i!=block_variables.end(); ++i) + if(!i->second.local && i->second.referenced) + i->second.assignments.clear(); + + merge_down_variables(); +} + + +Compiler::UnusedVariableLocator::VariableInfo::VariableInfo(): + local(false), + conditionally_assigned(false), + referenced(false) +{ } + + +void Compiler::UnusedFunctionLocator::visit(FunctionCall &call) +{ + TraversingVisitor::visit(call); + + unused_nodes.erase(call.declaration); + if(call.declaration && call.declaration->definition!=call.declaration) + used_definitions.insert(call.declaration->definition); +} + +void Compiler::UnusedFunctionLocator::visit(FunctionDeclaration &func) +{ + TraversingVisitor::visit(func); + + if((func.name!="main" || func.body.body.empty()) && !used_definitions.count(&func)) + unused_nodes.insert(&func); +} + + +Compiler::NodeRemover::NodeRemover(const set &r): + to_remove(r) +{ } + +void Compiler::NodeRemover::visit(Block &block) +{ + for(NodeList::iterator i=block.body.begin(); i!=block.body.end(); ) + { + (*i)->visit(*this); + if(to_remove.count(i->get())) + block.body.erase(i++); + else + ++i; + } +} + +void Compiler::NodeRemover::visit(VariableDeclaration &var) +{ + if(to_remove.count(&var)) + { + stage->in_variables.erase(var.name); + stage->out_variables.erase(var.name); + stage->locations.erase(var.name); + if(var.linked_declaration) + var.linked_declaration->linked_declaration = 0; + } + else if(var.init_expression && to_remove.count(var.init_expression.get())) + var.init_expression = 0; +} + +void Compiler::NodeRemover::visit(Iteration &iter) +{ + if(to_remove.count(iter.init_statement.get())) + iter.init_statement = 0; + TraversingVisitor::visit(iter); +} + + +void Compiler::PrecisionRemover::visit(Precision &) +{ + remove_node = true; +} + +void Compiler::PrecisionRemover::visit(VariableDeclaration &var) +{ + var.precision.clear(); +} + + +Compiler::DefaultPrecisionGenerator::DefaultPrecisionGenerator(): + toplevel(true) +{ } + +void Compiler::DefaultPrecisionGenerator::visit(Block &block) +{ + if(toplevel) + { + SetForScope set(toplevel, false); + BlockModifier::visit(block); + } + else + Visitor::visit(block); +} + +void Compiler::DefaultPrecisionGenerator::visit(Precision &prec) +{ + have_default.insert(prec.type); +} + +void Compiler::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); + } +} + + +Compiler::LegacyConverter::LegacyConverter(): + target_api(get_gl_api()), + target_version(get_glsl_version()), + frag_out(0) +{ } + +Compiler::LegacyConverter::LegacyConverter(const Version &v): + target_api(get_gl_api()), + target_version(v), + frag_out(0) +{ } + +bool Compiler::LegacyConverter::check_version(const Version &feature_version) const +{ + if(target_versionrequired_versionrequired_version = feature_version; + + return true; +} + +bool Compiler::LegacyConverter::check_extension(const Extension &extension) const +{ + if(!extension) + return false; + + vector::iterator i = find(stage->required_extensions, &extension); + if(i==stage->required_extensions.end()) + stage->required_extensions.push_back(&extension); + + return true; +} + +bool Compiler::LegacyConverter::supports_unified_interface_syntax() const +{ + if(target_api==OPENGL_ES2) + return check_version(Version(3, 0)); + else + return check_version(Version(1, 30)); +} + +void Compiler::LegacyConverter::visit(VariableReference &var) +{ + if(var.declaration==frag_out && !supports_unified_interface_syntax()) + { + var.name = "gl_FragColor"; + var.declaration = 0; + type = "vec4"; + } + else if(var.declaration) + type = var.declaration->type; + else + type = string(); +} + +void Compiler::LegacyConverter::visit(Assignment &assign) +{ + TraversingVisitor::visit(assign); + if(assign.target_declaration==frag_out && !supports_unified_interface_syntax()) + assign.target_declaration = 0; +} + +bool Compiler::LegacyConverter::supports_unified_sampling_functions() const +{ + if(target_api==OPENGL_ES2) + return check_version(Version(3, 0)); + else + return check_version(Version(1, 30)); +} + +void Compiler::LegacyConverter::visit(FunctionCall &call) +{ + if(call.name=="texture" && !call.declaration && !supports_unified_sampling_functions()) + { + NodeArray::iterator i = call.arguments.begin(); + if(i!=call.arguments.end()) + { + (*i)->visit(*this); + if(type=="sampler1D") + call.name = "texture1D"; + else if(type=="sampler2D") + call.name = "texture2D"; + else if(type=="sampler3D") + call.name = "texture3D"; + else if(type=="samplerCube") + call.name = "textureCube"; + else if(type=="sampler1DShadow") + call.name = "shadow1D"; + else if(type=="sampler2DShadow") + call.name = "shadow2D"; + else if(type=="sampler1DArray") + { + check_extension(EXT_texture_array); + call.name = "texture1DArray"; + } + else if(type=="sampler2DArray") + { + check_extension(EXT_texture_array); + call.name = "texture2DArray"; + } + else if(type=="sampler1DArrayShadow") + { + check_extension(EXT_texture_array); + call.name = "shadow1DArray"; + } + else if(type=="sampler2DArrayShadow") + { + check_extension(EXT_texture_array); + call.name = "shadow2DArray"; + } + + for(; i!=call.arguments.end(); ++i) + (*i)->visit(*this); + } + } + else + TraversingVisitor::visit(call); +} + +bool Compiler::LegacyConverter::supports_interface_layouts() const +{ + if(target_api==OPENGL_ES2) + return check_version(Version(3, 0)); + else if(check_version(Version(3, 30))) + return true; + else + return check_extension(ARB_explicit_attrib_location); +} + +bool Compiler::LegacyConverter::supports_centroid_sampling() const +{ + if(target_api==OPENGL_ES2) + return check_version(Version(3, 0)); + else if(check_version(Version(1, 20))) + return true; + else + return check_extension(EXT_gpu_shader4); +} + +bool Compiler::LegacyConverter::supports_sample_sampling() const +{ + if(target_api==OPENGL_ES2) + return check_version(Version(3, 20)); + else if(check_version(Version(4, 0))) + return true; + else + return check_extension(ARB_gpu_shader5); +} + +void Compiler::LegacyConverter::visit(VariableDeclaration &var) +{ + if(var.layout && !supports_interface_layouts()) + { + vector::iterator i; + for(i=var.layout->qualifiers.begin(); (i!=var.layout->qualifiers.end() && i->identifier!="location"); ++i) ; + if(i!=var.layout->qualifiers.end()) + { + unsigned location = lexical_cast(i->value); + if(stage->type==VERTEX && var.interface=="in") + { + stage->locations[var.name] = location; + var.layout->qualifiers.erase(i); + } + else if(stage->type==FRAGMENT && var.interface=="out") + { + if(location!=0) + static Require _req(EXT_gpu_shader4); + stage->locations[var.name] = location; + var.layout->qualifiers.erase(i); + } + + if(var.layout->qualifiers.empty()) + var.layout = 0; + } + } + + if(var.sampling=="centroid") + { + if(!supports_centroid_sampling()) + var.sampling = string(); + } + else if(var.sampling=="sample") + { + if(!supports_sample_sampling()) + var.sampling = string(); + } + + if((var.interface=="in" || var.interface=="out") && !supports_unified_interface_syntax()) + { + if(stage->type==FRAGMENT && var.interface=="out") + { + frag_out = &var; + remove_node = true; + } + } + + TraversingVisitor::visit(var); +} + +bool Compiler::LegacyConverter::supports_interface_blocks(const string &iface) const +{ + if(target_api==OPENGL_ES2) + { + if(iface=="uniform") + return check_version(Version(3, 0)); + else + return check_version(Version(3, 20)); + } + else if(check_version(Version(1, 50))) + return true; + else if(iface=="uniform") + return check_extension(ARB_uniform_buffer_object); + else + return false; +} + +void Compiler::LegacyConverter::visit(InterfaceBlock &iface) +{ + if(!supports_interface_blocks(iface.interface)) + flatten_block(iface.members); +} + +} // namespace SL +} // namespace GL +} // namespace Msp diff --git a/source/glsl/compiler.h b/source/glsl/compiler.h new file mode 100644 index 00000000..853a399a --- /dev/null +++ b/source/glsl/compiler.h @@ -0,0 +1,417 @@ +#ifndef MSP_GL_SL_COMPILER_H_ +#define MSP_GL_SL_COMPILER_H_ + +#include +#include "parser.h" +#include "program.h" +#include "resources.h" +#include "syntax.h" + +namespace Msp { +namespace GL { +namespace SL { + +class Compiler +{ +private: + struct Visitor: TraversingVisitor + { + typedef void ResultType; + + Stage *stage; + + Visitor(); + + virtual void apply(Stage &); + void get_result() const { } + }; + + struct BlockModifier: Visitor + { + bool remove_node; + std::vector > insert_nodes; + + BlockModifier(); + + void flatten_block(Block &); + void apply_and_increment(Block &, NodeList::iterator &); + using Visitor::visit; + virtual void visit(Block &); + }; + + struct Formatter: Visitor + { + typedef std::string ResultType; + + std::string formatted; + unsigned source_index; + unsigned source_line; + unsigned indent; + bool parameter_list; + std::string block_interface; + + Formatter(); + + virtual void apply(Stage &); + const std::string &get_result() const { return formatted; } + using Visitor::visit; + void append(const std::string &); + void append(char); + void set_source(unsigned, unsigned); + virtual void visit(Block &); + virtual void visit(Literal &); + virtual void visit(ParenthesizedExpression &); + virtual void visit(VariableReference &); + virtual void visit(MemberAccess &); + virtual void visit(UnaryExpression &); + virtual void visit(BinaryExpression &); + virtual void visit(Assignment &); + 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 &); + virtual void visit(VariableDeclaration &); + virtual void visit(InterfaceBlock &); + virtual void visit(FunctionDeclaration &); + virtual void visit(Conditional &); + virtual void visit(Iteration &); + virtual void visit(Return &); + virtual void visit(Jump &); + }; + + template + struct NodeGatherer: Visitor + { + typedef std::vector ResultType; + + std::vector nodes; + + const ResultType &get_result() const { return nodes; } + using Visitor::visit; + virtual void visit(T &n) { nodes.push_back(&n); } + }; + + struct DeclarationCombiner: BlockModifier + { + bool toplevel; + std::map > functions; + std::map variables; + + DeclarationCombiner(); + + using Visitor::visit; + virtual void visit(Block &); + virtual void visit(FunctionDeclaration &); + virtual void visit(VariableDeclaration &); + }; + + struct VariableResolver: Visitor + { + std::vector blocks; + StructDeclaration *type; + bool anonymous; + std::string block_interface; + bool record_target; + VariableDeclaration *assignment_target; + bool self_referencing; + + VariableResolver(); + + virtual void apply(Stage &); + using Visitor::visit; + virtual void visit(Block &); + virtual void visit(VariableReference &); + virtual void visit(MemberAccess &); + virtual void visit(BinaryExpression &); + virtual void visit(Assignment &); + virtual void visit(StructDeclaration &); + virtual void visit(VariableDeclaration &); + virtual void visit(InterfaceBlock &); + }; + + struct FunctionResolver: Visitor + { + std::map > functions; + + using Visitor::visit; + virtual void visit(FunctionCall &); + virtual void visit(FunctionDeclaration &); + }; + + struct InterfaceGenerator: BlockModifier + { + std::string in_prefix; + std::string out_prefix; + unsigned scope_level; + std::map > iface_declarations; + + InterfaceGenerator(); + + static std::string get_out_prefix(StageType); + virtual void apply(Stage &); + using Visitor::visit; + virtual void visit(Block &); + std::string change_prefix(const std::string &, const std::string &) const; + bool generate_interface(VariableDeclaration &, const std::string &, const std::string &); + ExpressionStatement &insert_assignment(const std::string &, Expression *); + virtual void visit(VariableReference &); + virtual void visit(VariableDeclaration &); + virtual void visit(Passthrough &); + }; + + struct DeclarationReorderer: Visitor + { + enum DeclarationKind + { + NO_DECLARATION, + LAYOUT, + STRUCT, + VARIABLE, + FUNCTION + }; + + unsigned scope_level; + DeclarationKind kind; + std::set ordered_funcs; + std::set needed_funcs; + + DeclarationReorderer(); + + using Visitor::visit; + virtual void visit(Block &); + virtual void visit(FunctionCall &); + virtual void visit(InterfaceLayout &) { kind = LAYOUT; } + virtual void visit(StructDeclaration &) { kind = STRUCT; } + virtual void visit(VariableDeclaration &); + virtual void visit(InterfaceBlock &) { kind = VARIABLE; } + virtual void visit(FunctionDeclaration &); + }; + + struct InlineableFunctionLocator: Visitor + { + typedef std::set ResultType; + + std::map refcounts; + std::set inlineable; + FunctionDeclaration *in_function; + + InlineableFunctionLocator(); + + const ResultType &get_result() const { return inlineable; } + using Visitor::visit; + virtual void visit(FunctionCall &); + virtual void visit(FunctionDeclaration &); + }; + + struct FunctionInliner: Visitor + { + std::set inlineable; + unsigned extract_result; + RefPtr inline_result; + + FunctionInliner(); + FunctionInliner(const std::set &); + + void visit_and_inline(RefPtr &); + using Visitor::visit; + virtual void visit(Block &); + virtual void visit(UnaryExpression &); + virtual void visit(BinaryExpression &); + virtual void visit(MemberAccess &); + virtual void visit(FunctionCall &); + virtual void visit(VariableDeclaration &); + virtual void visit(Return &); + }; + + struct ExpressionEvaluator: NodeVisitor + { + typedef std::map ValueMap; + + const ValueMap *variable_values; + float result; + bool result_valid; + + ExpressionEvaluator(); + ExpressionEvaluator(const ValueMap &); + + using NodeVisitor::visit; + virtual void visit(Literal &); + virtual void visit(ParenthesizedExpression &); + virtual void visit(VariableReference &); + virtual void visit(UnaryExpression &); + virtual void visit(BinaryExpression &); + }; + + struct ConstantConditionEliminator: BlockModifier + { + unsigned scope_level; + bool record_only; + ExpressionEvaluator::ValueMap variable_values; + + ConstantConditionEliminator(); + + using Visitor::visit; + virtual void visit(Block &); + virtual void visit(UnaryExpression &); + virtual void visit(Assignment &); + virtual void visit(VariableDeclaration &); + virtual void visit(Conditional &); + virtual void visit(Iteration &); + }; + + struct UnusedVariableLocator: Visitor + { + struct VariableInfo + { + bool local; + std::vector assignments; + bool conditionally_assigned; + bool referenced; + + VariableInfo(); + }; + + typedef std::set ResultType; + typedef std::map BlockVariableMap; + + std::set unused_nodes; + std::map aggregates; + Node *aggregate; + std::vector variables; + Assignment *assignment; + bool assignment_target; + bool assign_to_subscript; + bool global_scope; + + UnusedVariableLocator(); + + virtual void apply(Stage &); + const ResultType &get_result() const { return unused_nodes; } + using Visitor::visit; + virtual void visit(VariableReference &); + virtual void visit(MemberAccess &); + virtual void visit(BinaryExpression &); + virtual void visit(Assignment &); + void record_assignment(VariableDeclaration &, Node &, bool); + void clear_assignments(VariableInfo &, bool); + virtual void visit(ExpressionStatement &); + virtual void visit(StructDeclaration &); + virtual void visit(VariableDeclaration &); + virtual void visit(InterfaceBlock &); + virtual void visit(FunctionDeclaration &); + void merge_down_variables(); + virtual void visit(Conditional &); + virtual void visit(Iteration &); + }; + + struct UnusedFunctionLocator: Visitor + { + typedef std::set ResultType; + + std::set unused_nodes; + std::set used_definitions; + + const ResultType &get_result() const { return unused_nodes; } + using Visitor::visit; + virtual void visit(FunctionCall &); + virtual void visit(FunctionDeclaration &); + }; + + struct NodeRemover: Visitor + { + std::set to_remove; + + NodeRemover() { } + NodeRemover(const std::set &); + + using Visitor::visit; + virtual void visit(Block &); + virtual void visit(VariableDeclaration &); + virtual void visit(Iteration &); + }; + + struct PrecisionRemover: BlockModifier + { + using Visitor::visit; + virtual void visit(Precision &); + virtual void visit(VariableDeclaration &); + }; + + struct DefaultPrecisionGenerator: BlockModifier + { + bool toplevel; + std::set have_default; + + DefaultPrecisionGenerator(); + + using Visitor::visit; + virtual void visit(Block &); + virtual void visit(Precision &); + virtual void visit(VariableDeclaration &); + }; + + struct LegacyConverter: BlockModifier + { + GLApi target_api; + Version target_version; + std::string type; + VariableDeclaration *frag_out; + + LegacyConverter(); + LegacyConverter(const Version &); + + bool check_version(const Version &) const; + bool check_extension(const Extension &) const; + using Visitor::visit; + bool supports_unified_interface_syntax() const; + virtual void visit(VariableReference &); + virtual void visit(Assignment &); + bool supports_unified_sampling_functions() const; + virtual void visit(FunctionCall &); + bool supports_interface_layouts() const; + bool supports_centroid_sampling() const; + bool supports_sample_sampling() const; + virtual void visit(VariableDeclaration &); + bool supports_interface_blocks(const std::string &) const; + virtual void visit(InterfaceBlock &); + }; + + Resources *resources; + Module *module; + std::vector imported_names; + +public: + Compiler(); + ~Compiler(); + + void compile(const std::string &, const std::string & = ""); + void compile(IO::Base &, Resources * = 0, const std::string & = ""); + void compile(IO::Base &, const std::string &); + void add_shaders(Program &); + +private: + static Module *create_builtins_module(); + static Module &get_builtins_module(); + static Stage *get_builtins(StageType); + void append_module(Module &); + void append_stage(Stage &); + void process(); + void import(const std::string &); + void generate(Stage &); + bool optimize(Stage &); + void finalize(Stage &); + static void inject_block(Block &, const Block &); + template + static typename T::ResultType apply(Stage &); + template + static typename T::ResultType apply(Stage &, const A &); +}; + +} // namespace SL +} // namespace GL +} // namespace Msp + +#endif diff --git a/source/glsl/parser.cpp b/source/glsl/parser.cpp new file mode 100644 index 00000000..d55cdab3 --- /dev/null +++ b/source/glsl/parser.cpp @@ -0,0 +1,962 @@ +#include +#include +#include +#include "parser.h" + +#undef interface + +using namespace std; + +namespace Msp { +namespace GL { +namespace SL { + +Parser::Operator Parser::operators[] = +{ + { "[", 2, BINARY, LEFT_TO_RIGHT }, + { "(", 2, BINARY, LEFT_TO_RIGHT }, + { ".", 2, BINARY, LEFT_TO_RIGHT }, + { "++", 2, POSTFIX, LEFT_TO_RIGHT }, + { "--", 2, POSTFIX, LEFT_TO_RIGHT }, + { "++", 3, PREFIX, RIGHT_TO_LEFT }, + { "--", 3, PREFIX, RIGHT_TO_LEFT }, + { "+", 3, PREFIX, RIGHT_TO_LEFT }, + { "-", 3, PREFIX, RIGHT_TO_LEFT }, + { "~", 3, PREFIX, RIGHT_TO_LEFT }, + { "!", 3, PREFIX, RIGHT_TO_LEFT }, + { "*", 4, BINARY, LEFT_TO_RIGHT }, + { "/", 4, BINARY, LEFT_TO_RIGHT }, + { "%", 4, BINARY, LEFT_TO_RIGHT }, + { "+", 5, BINARY, LEFT_TO_RIGHT }, + { "-", 5, BINARY, LEFT_TO_RIGHT }, + { "<<", 6, BINARY, LEFT_TO_RIGHT }, + { ">>", 6, BINARY, LEFT_TO_RIGHT }, + { "<", 7, BINARY, LEFT_TO_RIGHT }, + { ">", 7, BINARY, LEFT_TO_RIGHT }, + { "<=", 7, BINARY, LEFT_TO_RIGHT }, + { ">=", 7, BINARY, LEFT_TO_RIGHT }, + { "==", 8, BINARY, LEFT_TO_RIGHT }, + { "!=", 8, BINARY, LEFT_TO_RIGHT }, + { "&", 9, BINARY, LEFT_TO_RIGHT }, + { "^", 10, BINARY, LEFT_TO_RIGHT }, + { "|", 11, BINARY, LEFT_TO_RIGHT }, + { "&&", 12, BINARY, LEFT_TO_RIGHT }, + { "^^", 13, BINARY, LEFT_TO_RIGHT }, + { "||", 14, BINARY, LEFT_TO_RIGHT }, + { "?", 15, BINARY, RIGHT_TO_LEFT }, + { ":", 15, BINARY, RIGHT_TO_LEFT }, + { "=", 16, BINARY, RIGHT_TO_LEFT }, + { "+=", 16, BINARY, RIGHT_TO_LEFT }, + { "-=", 16, BINARY, RIGHT_TO_LEFT }, + { "*=", 16, BINARY, RIGHT_TO_LEFT }, + { "/=", 16, BINARY, RIGHT_TO_LEFT }, + { "%=", 16, BINARY, RIGHT_TO_LEFT }, + { "<<=", 16, BINARY, RIGHT_TO_LEFT }, + { ">>=", 16, BINARY, RIGHT_TO_LEFT }, + { "&=", 16, BINARY, RIGHT_TO_LEFT }, + { "^=", 16, BINARY, RIGHT_TO_LEFT }, + { "|=", 16, BINARY, RIGHT_TO_LEFT }, + { ",", 17, BINARY, LEFT_TO_RIGHT }, + { { 0 }, 18, NO_OPERATOR, LEFT_TO_RIGHT } +}; + +Parser::Parser(): + module(0) +{ } + +Parser::~Parser() +{ + delete module; +} + +Module &Parser::parse(const string &s, const string &n, unsigned i) +{ + source = s; + source_name = n; + source_index = i; + parse_source(); + return *module; +} + +Module &Parser::parse(IO::Base &io, const string &n, unsigned i) +{ + source = string(); + source_name = n; + source_index = i; + while(!io.eof()) + { + char buffer[4096]; + unsigned len = io.read(buffer, sizeof(buffer)); + source.append(buffer, len); + } + parse_source(); + return *module; +} + +void Parser::parse_source() +{ + while(1) + { + string::size_type slashes = source.find("//////"); + if(slashes==string::npos) + break; + + string::size_type newline = source.find('\n', slashes); + string pragma = format("#pragma MSP stage(%s)", source.substr(slashes+6, newline-slashes-6)); + source.replace(slashes, newline-slashes, pragma); + } + + delete module; + module = new Module; + cur_stage = &module->shared; + iter = source.begin(); + source_end = source.end(); + current_line = 1; + allow_preprocess = true; + while(RefPtr statement = parse_global_declaration()) + cur_stage->content.body.push_back(statement); +} + +string Parser::format_error(const std::string &message) +{ + string location = format("%s:%d: ", source_name, current_line); + return location+message; +} + +string Parser::format_syntax_error(const std::string &expected) +{ + return format_error(format("Syntax error at '%s': expected %s", last_token, expected)); +} + +const string &Parser::peek_token(unsigned index) +{ + while(next_tokens.size()<=index) + next_tokens.push_back(parse_token_()); + return (last_token = next_tokens[index]); +} + +const string &Parser::parse_token() +{ + if(!next_tokens.empty()) + { + last_token = next_tokens.front(); + next_tokens.pop_front(); + return last_token; + } + + return (last_token = parse_token_()); +} + +string Parser::parse_token_() +{ + while(1) + { + skip_comment_and_whitespace(); + if(iter==source_end) + return string(); + else if(allow_preprocess && *iter=='#') + { + allow_preprocess = false; + SetForScope > clear_tokens(next_tokens, deque()); + preprocess(); + } + else if(isalpha(*iter) || *iter=='_') + return parse_identifier(); + else if(isdigit(*iter)) + return parse_number(); + else + return parse_other(); + } +} + +string Parser::parse_identifier() +{ + string ident; + while(iter!=source_end) + { + if(isalnum(*iter) || *iter=='_') + ident += *iter++; + else + break; + } + + return ident; +} + +string Parser::parse_number() +{ + bool accept_sign = false; + string number; + while(iter!=source_end) + { + if(isdigit(*iter) || *iter=='.') + number += *iter++; + else if(*iter=='e' || *iter=='E') + { + number += *iter++; + accept_sign = true; + } + else if(accept_sign && (*iter=='+' || *iter=='-')) + number += *iter++; + else + break; + } + + return number; +} + +string Parser::parse_other() +{ + if(iter==source_end) + return string(); + + string token(1, *iter++); + for(unsigned i=1; (i<3 && iter!=source_end); ++i) + { + bool matched = false; + for(const Operator *j=operators; (!matched && j->type); ++j) + { + matched = (j->token[i]==*iter); + for(unsigned k=0; (matched && ktoken[k]); ++k) + matched = (j->token[k]==token[k]); + } + + if(!matched) + break; + + token += *iter++; + } + + return token; +} + +void Parser::skip_comment_and_whitespace() +{ + unsigned comment = 0; + while(iter!=source_end) + { + if(comment==0) + { + if(*iter=='/') + comment = 1; + else if(!isspace(*iter)) + break; + } + else if(comment==1) + { + if(*iter=='/') + comment = 2; + else if(*iter=='*') + comment = 3; + else + { + comment = 0; + --iter; + break; + } + } + else if(comment==2) + { + if(*iter=='\n') + comment = 0; + } + else if(comment==3 && *iter=='*') + comment = 4; + else if(comment==4) + { + if(*iter=='/') + comment = 0; + else if(*iter!='*') + comment = 3; + } + + if(*iter=='\n') + { + ++current_line; + allow_preprocess = (comment<3); + } + + ++iter; + } +} + +void Parser::expect(const string &token) +{ + string parsed = parse_token(); + if(parsed!=token) + throw runtime_error(format_syntax_error(format("'%s'", token))); +} + +string Parser::expect_type() +{ + string token = parse_token(); + if(!is_type(token)) + throw runtime_error(format_syntax_error("a type")); + return token; +} + +string Parser::expect_identifier() +{ + string token = parse_token(); + if(!is_identifier(token)) + throw runtime_error(format_syntax_error("an identifier")); + return token; +} + +bool Parser::check(const string &token) +{ + bool result = (peek_token()==token); + if(result) + parse_token(); + return result; +} + +bool Parser::is_interface_qualifier(const string &token) +{ + return (token=="uniform" || token=="in" || token=="out"); +} + +bool Parser::is_sampling_qualifier(const string &token) +{ + return (token=="centroid" || token=="sample"); +} + +bool Parser::is_interpolation_qualifier(const string &token) +{ + return (token=="smooth" || token=="flat" || token=="noperspective"); +} + +bool Parser::is_precision_qualifier(const string &token) +{ + return (token=="highp" || token=="mediump" || token=="lowp"); +} + +bool Parser::is_qualifier(const string &token) +{ + return (token=="const" || + is_interface_qualifier(token) || + is_sampling_qualifier(token) || + is_interpolation_qualifier(token) || + is_precision_qualifier(token)); +} + +bool Parser::is_builtin_type(const string &token) +{ + static Regex re("^(void|float|int|bool|[ib]?vec[234]|mat[234](x[234])?|sampler((1D|2D|Cube)(Array)?(Shadow)?|3D))$"); + return re.match(token); +} + +bool Parser::is_type(const string &token) +{ + return is_builtin_type(token) || declared_types.count(token); +} + +bool Parser::is_identifier(const string &token) +{ + static Regex re("^[a-zA-Z_][a-zA-Z0-9_]*$"); + return re.match(token); +} + +void Parser::preprocess() +{ + expect("#"); + + string::const_iterator line_end = iter; + for(; (line_end!=source_end && *line_end!='\n'); ++line_end) ; + SetForScope stop_at_line_end(source_end, line_end); + + string token = peek_token(); + if(token=="pragma") + preprocess_pragma(); + else if(token=="version") + preprocess_version(); + else if(token=="define" || token=="undef" || token=="if" || token=="ifdef" || token=="ifndef" || token=="else" || + token=="elif" || token=="endif" || token=="error" || token=="extension" || token=="line") + throw runtime_error(format_error(format("Unsupported preprocessor directive '%s'", token))); + else if(!token.empty()) + throw runtime_error(format_syntax_error("a preprocessor directive")); + + iter = line_end; +} + +void Parser::preprocess_version() +{ + expect("version"); + string token = parse_token(); + unsigned version = lexical_cast(token); + cur_stage->required_version = Version(version/100, version%100); + + token = parse_token(); + if(!token.empty()) + throw runtime_error(format_syntax_error("end of line")); +} + +void Parser::preprocess_pragma() +{ + expect("pragma"); + string token = parse_token(); + if(token=="MSP") + preprocess_pragma_msp(); +} + +void Parser::preprocess_pragma_msp() +{ + string token = peek_token(); + if(token=="stage") + preprocess_stage(); + else + throw runtime_error(format_error(format("Unrecognized MSP pragma '%s'", token))); + + token = parse_token(); + if(!token.empty()) + throw runtime_error(format_syntax_error("end of line")); +} + +void Parser::preprocess_stage() +{ + if(!allow_stage_change) + throw runtime_error(format_error("Changing stage not allowed here")); + + expect("stage"); + expect("("); + string token = expect_identifier(); + StageType stage = SHARED; + if(token=="vertex") + stage = VERTEX; + else if(token=="geometry") + stage = GEOMETRY; + else if(token=="fragment") + stage = FRAGMENT; + else + throw runtime_error(format_syntax_error("stage identifier")); + expect(")"); + + if(stage<=cur_stage->type) + throw runtime_error(format_error(format("Stage '%s' not allowed here", token))); + + module->stages.push_back(stage); + + if(cur_stage->type!=SHARED) + module->stages.back().previous = cur_stage; + cur_stage = &module->stages.back(); +} + +RefPtr Parser::parse_global_declaration() +{ + allow_stage_change = true; + string token = peek_token(); + allow_stage_change = false; + + if(token=="import") + return parse_import(); + else if(token=="precision") + return parse_precision(); + else if(token=="layout") + { + RefPtr layout = parse_layout(); + token = peek_token(); + if(is_interface_qualifier(token) && peek_token(1)==";") + { + RefPtr iface_lo = new InterfaceLayout; + iface_lo->source = source_index; + iface_lo->line = current_line; + iface_lo->layout.qualifiers = layout->qualifiers; + iface_lo->interface = parse_token(); + expect(";"); + return iface_lo; + } + else + { + RefPtr var = parse_variable_declaration(); + var->layout = layout; + return var; + } + } + else if(token=="struct") + return parse_struct_declaration(); + else if(is_interface_qualifier(token)) + { + string next = peek_token(1); + if(is_type(next) || is_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)=="(") + return parse_function_declaration(); + else + return parse_variable_declaration(); + } + else if(token.empty()) + return 0; + else + throw runtime_error(format_syntax_error("a global declaration")); +} + +RefPtr Parser::parse_statement() +{ + string token = peek_token(); + if(token=="if") + return parse_conditional(); + else if(token=="for") + return parse_for(); + else if(token=="while") + return parse_while(); + else if(token=="passthrough") + return parse_passthrough(); + else if(token=="return") + return parse_return(); + else if(token=="break" || token=="continue" || token=="discard") + { + RefPtr jump = new Jump; + jump->source = source_index; + jump->line = current_line; + jump->keyword = parse_token(); + expect(";"); + + return jump; + } + else if(is_qualifier(token) || is_type(token)) + return parse_variable_declaration(); + else if(!token.empty()) + { + RefPtr expr = new ExpressionStatement; + expr->source = source_index; + expr->line = current_line; + expr->expression = parse_expression(); + expect(";"); + + return expr; + } + else + throw runtime_error(format_syntax_error("a statement")); +} + +RefPtr Parser::parse_import() +{ + if(cur_stage->type!=SHARED) + throw runtime_error(format_error("Imports are only allowed in the shared section")); + + expect("import"); + RefPtr import = new Import; + import->source = source_index; + import->line = current_line; + import->module = expect_identifier(); + expect(";"); + return import; +} + +RefPtr Parser::parse_precision() +{ + expect("precision"); + RefPtr precision = new Precision; + precision->source = source_index; + precision->line = current_line; + + precision->precision = parse_token(); + if(!is_precision_qualifier(precision->precision)) + throw runtime_error(format_syntax_error("a precision qualifier")); + + 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_syntax_error("a builtin type")); + + expect(";"); + + return precision; +} + +RefPtr Parser::parse_layout() +{ + expect("layout"); + expect("("); + RefPtr layout = new Layout; + while(1) + { + string token = parse_token(); + if(token==")") + throw runtime_error(format_syntax_error("a layout qualifier name")); + + layout->qualifiers.push_back(Layout::Qualifier()); + Layout::Qualifier &qual = layout->qualifiers.back(); + qual.identifier = token; + + if(check("=")) + qual.value = parse_token(); + + if(peek_token()==")") + break; + + expect(","); + } + expect(")"); + + return layout; +} + +void Parser::parse_block(Block &block, bool require_braces) +{ + bool have_braces = (require_braces || peek_token()=="{"); + if(have_braces) + expect("{"); + + if(have_braces) + { + while(peek_token()!="}") + block.body.push_back(parse_statement()); + } + else + block.body.push_back(parse_statement()); + + block.use_braces = (require_braces || block.body.size()!=1); + + if(have_braces) + expect("}"); +} + +RefPtr Parser::parse_expression(unsigned precedence) +{ + RefPtr left; + VariableReference *left_var = 0; + while(1) + { + string token = peek_token(); + + const Operator *oper = 0; + for(Operator *i=operators; (!oper && i->type); ++i) + if(token==i->token && (!left || i->type!=PREFIX) && (left || i->type!=POSTFIX)) + oper = i; + + if(token==";" || token==")" || token=="]" || token=="," || (oper && precedence && oper->precedence>=precedence)) + { + if(left) + return left; + else + throw runtime_error(format_syntax_error("an expression")); + } + else if(left) + { + if(token=="(") + { + if(!left_var) + throw runtime_error(format_error("Syntax error before '(': function name must be an identifier")); + left = parse_function_call(*left_var); + } + else if(token==".") + { + RefPtr memacc = new MemberAccess; + memacc->left = left; + parse_token(); + memacc->member = expect_identifier(); + left = memacc; + } + else if(oper && oper->type==POSTFIX) + { + RefPtr unary = new UnaryExpression; + unary->oper = parse_token(); + unary->prefix = false; + unary->expression = left; + left = unary; + } + else if(oper && oper->type==BINARY) + left = parse_binary(left, oper); + else + throw runtime_error(format_syntax_error("an operator")); + left_var = 0; + } + else + { + if(token=="(") + { + parse_token(); + RefPtr parexpr = new ParenthesizedExpression; + parexpr->expression = parse_expression(); + expect(")"); + left = parexpr; + } + else if(isdigit(token[0]) || token=="true" || token=="false") + { + RefPtr literal = new Literal; + literal->token = parse_token(); + left = literal; + } + else if(is_identifier(token)) + { + RefPtr var = new VariableReference; + var->name = expect_identifier(); + left = var; + left_var = var.get(); + } + else if(oper && oper->type==PREFIX) + { + RefPtr unary = new UnaryExpression; + unary->oper = parse_token(); + unary->prefix = true; + unary->expression = parse_expression(oper->precedence); + left = unary; + } + else + throw runtime_error(format_syntax_error("an expression")); + } + } +} + +RefPtr Parser::parse_binary(const RefPtr &left, const Operator *oper) +{ + RefPtr binary = (oper->precedence==16 ? new Assignment : new BinaryExpression); + binary->left = left; + binary->oper = parse_token(); + if(binary->oper=="[") + { + binary->right = parse_expression(); + expect("]"); + binary->after = "]"; + } + else + binary->right = parse_expression(oper->precedence+(oper->assoc==RIGHT_TO_LEFT)); + return binary; +} + +RefPtr Parser::parse_function_call(const VariableReference &var) +{ + RefPtr call = new FunctionCall; + call->name = var.name; + call->constructor = is_type(call->name); + expect("("); + while(peek_token()!=")") + { + if(!call->arguments.empty()) + expect(","); + call->arguments.push_back(parse_expression()); + } + expect(")"); + return call; +} + +RefPtr Parser::parse_struct_declaration() +{ + expect("struct"); + RefPtr strct = new StructDeclaration; + strct->source = source_index; + strct->line = current_line; + + strct->name = expect_identifier(); + parse_block(strct->members, true); + expect(";"); + + declared_types.insert(strct->name); + return strct; +} + +RefPtr Parser::parse_variable_declaration() +{ + RefPtr var = new VariableDeclaration; + var->source = source_index; + var->line = current_line; + + string token = peek_token(); + while(is_qualifier(token)) + { + parse_token(); + if(is_interface_qualifier(token)) + var->interface = token; + else if(is_sampling_qualifier(token)) + var->sampling = token; + else if(is_interpolation_qualifier(token)) + var->interpolation = token; + else if(is_precision_qualifier(token)) + var->precision = token; + else if(token=="const") + var->constant = true; + token = peek_token(); + } + + var->type = expect_type(); + var->name = expect_identifier(); + + if(check("[")) + { + var->array = true; + if(!check("]")) + { + var->array_size = parse_expression(); + expect("]"); + } + } + + if(check("=")) + var->init_expression = parse_expression(); + + expect(";"); + return var; +} + +RefPtr Parser::parse_function_declaration() +{ + RefPtr func = new FunctionDeclaration; + func->source = source_index; + func->line = current_line; + + func->return_type = expect_type(); + func->name = expect_identifier(); + expect("("); + while(peek_token()!=")") + { + if(!func->parameters.empty()) + expect(","); + + RefPtr var = new VariableDeclaration; + string token = peek_token(); + if(token=="in" || token=="out" || token=="inout") + var->interface = parse_token(); + var->type = expect_type(); + var->name = expect_identifier(); + func->parameters.push_back(var); + } + expect(")"); + + string token = peek_token(); + if(token=="{") + { + func->definition = func.get(); + parse_block(func->body, true); + } + else if(token==";") + parse_token(); + else + throw runtime_error(format_syntax_error("'{' or ';'")); + + return func; +} + +RefPtr Parser::parse_interface_block() +{ + RefPtr iface = new InterfaceBlock; + iface->source = source_index; + iface->line = current_line; + + iface->interface = parse_token(); + if(!is_interface_qualifier(iface->interface)) + throw runtime_error(format_syntax_error("an interface qualifier")); + + iface->name = expect_identifier(); + parse_block(iface->members, true); + if(!check(";")) + { + iface->instance_name = expect_identifier(); + if(check("[")) + { + iface->array = true; + expect("]"); + } + expect(";"); + } + + return iface; +} + +RefPtr Parser::parse_conditional() +{ + expect("if"); + RefPtr cond = new Conditional; + cond->source = source_index; + cond->line = current_line; + expect("("); + cond->condition = parse_expression(); + expect(")"); + + parse_block(cond->body, false); + + string token = peek_token(); + if(token=="else") + { + parse_token(); + parse_block(cond->else_body, false); + } + + return cond; +} + +RefPtr Parser::parse_for() +{ + expect("for"); + RefPtr loop = new Iteration; + loop->source = source_index; + loop->line = current_line; + expect("("); + string token = peek_token(); + if(is_type(token)) + loop->init_statement = parse_statement(); + else + { + if(token!=";") + { + RefPtr expr = new ExpressionStatement; + expr->expression = parse_expression(); + loop->init_statement = expr; + } + expect(";"); + } + if(peek_token()!=";") + loop->condition = parse_expression(); + expect(";"); + if(peek_token()!=")") + loop->loop_expression = parse_expression(); + expect(")"); + + parse_block(loop->body, false); + + return loop; +} + +RefPtr Parser::parse_while() +{ + expect("while"); + RefPtr loop = new Iteration; + loop->source = source_index; + loop->line = current_line; + expect("("); + loop->condition = parse_expression(); + expect(")"); + + parse_block(loop->body, false); + + return loop; +} + +RefPtr Parser::parse_passthrough() +{ + expect("passthrough"); + RefPtr pass = new Passthrough; + pass->source = source_index; + pass->line = current_line; + if(cur_stage->type==GEOMETRY) + { + expect("["); + pass->subscript = parse_expression(); + expect("]"); + } + expect(";"); + return pass; +} + +RefPtr Parser::parse_return() +{ + expect("return"); + RefPtr ret = new Return; + ret->source = source_index; + ret->line = current_line; + if(peek_token()!=";") + ret->expression = parse_expression(); + expect(";"); + return ret; +} + +} // namespace SL +} // namespace GL +} // namespace Msp diff --git a/source/glsl/parser.h b/source/glsl/parser.h new file mode 100644 index 00000000..c9588bfb --- /dev/null +++ b/source/glsl/parser.h @@ -0,0 +1,120 @@ +#ifndef MSP_GL_SL_PARSER_H_ +#define MSP_GL_SL_PARSER_H_ + +#include +#include +#include +#include +#include +#include "syntax.h" + +namespace Msp { +namespace GL { +namespace SL { + +class Parser +{ +private: + enum OperatorType + { + NO_OPERATOR, + BINARY, + PREFIX, + POSTFIX + }; + + enum Associativity + { + LEFT_TO_RIGHT, + RIGHT_TO_LEFT + }; + + struct Operator + { + const char token[4]; + unsigned precedence; + OperatorType type; + Associativity assoc; + }; + + std::string source; + std::string source_name; + unsigned source_index; + unsigned current_line; + std::string::const_iterator iter; + std::string::const_iterator source_end; + bool allow_preprocess; + bool allow_stage_change; + std::string last_token; + std::deque next_tokens; + Module *module; + Stage *cur_stage; + std::set declared_types; + + static Operator operators[]; + +public: + Parser(); + ~Parser(); + + Module &parse(const std::string &, const std::string &, unsigned = 0); + Module &parse(IO::Base &, const std::string &, unsigned = 0); + +private: + void parse_source(); + + std::string format_error(const std::string &); + std::string format_syntax_error(const std::string &); + + const std::string &peek_token(unsigned = 0); + const std::string &parse_token(); + std::string parse_token_(); + std::string parse_identifier(); + std::string parse_number(); + std::string parse_other(); + void skip_comment_and_whitespace(); + void expect(const std::string &); + std::string expect_type(); + std::string expect_identifier(); + bool check(const std::string &); + + static bool is_interface_qualifier(const std::string &); + static bool is_sampling_qualifier(const std::string &); + static bool is_interpolation_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 &); + bool is_identifier(const std::string &); + + void preprocess(); + void preprocess_version(); + void preprocess_pragma(); + void preprocess_pragma_msp(); + void preprocess_stage(); + + RefPtr parse_global_declaration(); + RefPtr parse_statement(); + RefPtr parse_import(); + RefPtr parse_precision(); + RefPtr parse_layout(); + void parse_block(Block &, bool); + RefPtr parse_expression(unsigned = 0); + RefPtr parse_binary(const RefPtr &, const Operator *); + RefPtr parse_function_call(const VariableReference &); + RefPtr parse_struct_declaration(); + RefPtr parse_variable_declaration(); + RefPtr parse_function_declaration(); + RefPtr parse_interface_block(); + RefPtr parse_conditional(); + RefPtr parse_for(); + RefPtr parse_while(); + RefPtr parse_passthrough(); + RefPtr parse_return(); +}; + +} // namespace SL +} // namespace GL +} // namespace Msp + +#endif diff --git a/source/glsl/programcompiler.cpp b/source/glsl/programcompiler.cpp deleted file mode 100644 index d021ab4f..00000000 --- a/source/glsl/programcompiler.cpp +++ /dev/null @@ -1,2096 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "error.h" -#include "program.h" -#include "programcompiler.h" -#include "resources.h" -#include "shader.h" - -#undef interface - -using namespace std; - -namespace { - -const char builtins_src[] = - "#pragma MSP stage(vertex)\n" - "out gl_PerVertex {\n" - " vec4 gl_Position;\n" - " float gl_ClipDistance[];\n" - "};\n" - "#pragma MSP stage(geometry)\n" - "in gl_PerVertex {\n" - " vec4 gl_Position;\n" - " float gl_ClipDistance[];\n" - "} gl_in[];\n" - "out gl_PerVertex {\n" - " vec4 gl_Position;\n" - " float gl_ClipDistance[];\n" - "};\n"; - -} - -namespace Msp { -namespace GL { - -using namespace ProgramSyntax; - -ProgramCompiler::ProgramCompiler(): - resources(0), - module(0) -{ } - -ProgramCompiler::~ProgramCompiler() -{ - delete module; -} - -void ProgramCompiler::compile(const string &source, const string &src_name) -{ - resources = 0; - delete module; - module = new Module(); - ProgramParser parser; - imported_names.push_back(src_name); - append_module(parser.parse(source, src_name, 1)); - process(); -} - -void ProgramCompiler::compile(IO::Base &io, Resources *res, const string &src_name) -{ - resources = res; - delete module; - module = new Module(); - ProgramParser parser; - imported_names.push_back(src_name); - append_module(parser.parse(io, src_name, 1)); - process(); -} - -void ProgramCompiler::compile(IO::Base &io, const string &src_name) -{ - compile(io, 0, src_name); -} - -void ProgramCompiler::add_shaders(Program &program) -{ - if(!module) - throw invalid_operation("ProgramCompiler::add_shaders"); - - try - { - for(list::iterator i=module->stages.begin(); i!=module->stages.end(); ++i) - { - if(i->type==VERTEX) - { - program.attach_shader_owned(new VertexShader(apply(*i))); - for(map::iterator j=i->locations.begin(); j!=i->locations.end(); ++j) - program.bind_attribute(j->second, j->first); - } - else if(i->type==GEOMETRY) - program.attach_shader_owned(new GeometryShader(apply(*i))); - else if(i->type==FRAGMENT) - { - program.attach_shader_owned(new FragmentShader(apply(*i))); - if(EXT_gpu_shader4) - { - for(map::iterator j=i->locations.begin(); j!=i->locations.end(); ++j) - program.bind_fragment_data(j->second, j->first); - } - } - } - } - catch(const compile_error &e) - { - static const Regex r_message("^(([0-9]+)\\(([0-9]+)\\) :|ERROR: ([0-9]+):([0-9]+):) (.*)$"); - vector lines = split(e.what(), '\n'); - string translated; - for(vector::const_iterator i=lines.begin(); i!=lines.end(); ++i) - { - RegMatch m = r_message.match(*i); - if(m) - { - unsigned index = 0; - unsigned line = 0; - if(m[2]) - { - index = lexical_cast(m[2].str); - line = lexical_cast(m[3].str); - } - else if(m[4]) - { - index = lexical_cast(m[4].str); - line = lexical_cast(m[5].str); - } - const char *src = ""; - if(index==0) - src = ""; - else if(index-1")); - for(list::iterator i=module->stages.begin(); i!=module->stages.end(); ++i) - { - VariableResolver resolver; - i->content.visit(resolver); - for(map::iterator j=i->content.variables.begin(); j!=i->content.variables.end(); ++j) - j->second->linked_declaration = j->second; - } - return module; -} - -Module &ProgramCompiler::get_builtins_module() -{ - static RefPtr builtins_module = create_builtins_module(); - return *builtins_module; -} - -Stage *ProgramCompiler::get_builtins(StageType type) -{ - Module &module = get_builtins_module(); - for(list::iterator i=module.stages.begin(); i!=module.stages.end(); ++i) - if(i->type==type) - return &*i; - return 0; -} - -void ProgramCompiler::append_module(ProgramSyntax::Module &mod) -{ - vector imports = apply >(mod.shared); - for(vector::iterator i=imports.begin(); i!=imports.end(); ++i) - import((*i)->module); - apply(mod.shared, set(imports.begin(), imports.end())); - - append_stage(mod.shared); - for(list::iterator i=mod.stages.begin(); i!=mod.stages.end(); ++i) - append_stage(*i); -} - -void ProgramCompiler::append_stage(Stage &stage) -{ - Stage *target = 0; - if(stage.type==SHARED) - target = &module->shared; - else - { - list::iterator i; - for(i=module->stages.begin(); (i!=module->stages.end() && i->typestages.end() || i->type>stage.type) - { - list::iterator j = module->stages.insert(i, stage.type); - if(i!=module->stages.end()) - i->previous = &*j; - i = j; - if(i!=module->stages.begin()) - i->previous = &*--j; - } - - target = &*i; - } - - if(stage.required_version>target->required_version) - target->required_version = stage.required_version; - for(NodeList::iterator i=stage.content.body.begin(); i!=stage.content.body.end(); ++i) - target->content.body.push_back(*i); - apply(*target); -} - -void ProgramCompiler::process() -{ - for(list::iterator i=module->stages.begin(); i!=module->stages.end(); ++i) - generate(*i); - for(list::iterator i=module->stages.begin(); i!=module->stages.end(); ) - { - if(optimize(*i)) - i = module->stages.begin(); - else - ++i; - } - for(list::iterator i=module->stages.begin(); i!=module->stages.end(); ++i) - finalize(*i); -} - -void ProgramCompiler::import(const string &name) -{ - string fn = name+".glsl"; - if(find(imported_names, fn)!=imported_names.end()) - return; - imported_names.push_back(fn); - - RefPtr io = (resources ? resources->open_raw(fn) : Resources::get_builtins().open(fn)); - if(!io) - throw runtime_error(format("module %s not found", name)); - ProgramParser import_parser; - append_module(import_parser.parse(*io, fn, imported_names.size())); -} - -void ProgramCompiler::generate(Stage &stage) -{ - if(module->shared.required_version>stage.required_version) - stage.required_version = module->shared.required_version; - inject_block(stage.content, module->shared.content); - - apply(stage); - apply(stage); - apply(stage); - apply(stage); - apply(stage); - apply(stage); - apply(stage); - apply(stage); -} - -bool ProgramCompiler::optimize(Stage &stage) -{ - apply(stage); - - set inlineable = apply(stage); - apply(stage, inlineable); - - set unused = apply(stage); - set unused2 = apply(stage); - unused.insert(unused2.begin(), unused2.end()); - apply(stage, unused); - - 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) -{ - NodeList::iterator insert_point = target.body.begin(); - for(NodeList::const_iterator i=source.body.begin(); i!=source.body.end(); ++i) - target.body.insert(insert_point, (*i)->clone()); -} - -template -typename T::ResultType ProgramCompiler::apply(Stage &stage) -{ - T visitor; - visitor.apply(stage); - return visitor.get_result(); -} - -template -typename T::ResultType ProgramCompiler::apply(Stage &stage, const A &arg) -{ - T visitor(arg); - visitor.apply(stage); - return visitor.get_result(); -} - - -ProgramCompiler::Visitor::Visitor(): - stage(0) -{ } - -void ProgramCompiler::Visitor::apply(Stage &s) -{ - SetForScope set(stage, &s); - stage->content.visit(*this); -} - - -ProgramCompiler::BlockModifier::BlockModifier(): - remove_node(false) -{ } - -void ProgramCompiler::BlockModifier::flatten_block(Block &block) -{ - insert_nodes.insert(insert_nodes.end(), block.body.begin(), block.body.end()); - remove_node = true; -} - -void ProgramCompiler::BlockModifier::apply_and_increment(Block &block, NodeList::iterator &i) -{ - block.body.insert(i, insert_nodes.begin(), insert_nodes.end()); - insert_nodes.clear(); - - if(remove_node) - block.body.erase(i++); - else - ++i; - remove_node = false; -} - -void ProgramCompiler::BlockModifier::visit(Block &block) -{ - for(NodeList::iterator i=block.body.begin(); i!=block.body.end(); ) - { - (*i)->visit(*this); - apply_and_increment(block, i); - } -} - - -ProgramCompiler::Formatter::Formatter(): - source_index(0), - source_line(1), - indent(0), - parameter_list(false) -{ } - -void ProgramCompiler::Formatter::apply(ProgramSyntax::Stage &s) -{ - GLApi api = get_gl_api(); - const Version &ver = s.required_version; - - if(ver) - { - append(format("#version %d%02d", ver.major, ver.minor)); - if(api==OPENGL_ES2 && ver>=Version(3, 0)) - append(" es"); - formatted += '\n'; - } - - for(vector::const_iterator i=s.required_extensions.begin(); i!=s.required_extensions.end(); ++i) - append(format("#extension %s: require\n", (*i)->get_name())); - if(!s.required_extensions.empty()) - formatted += '\n'; - - Visitor::apply(s); -} - -void ProgramCompiler::Formatter::append(const string &text) -{ - formatted += text; - for(string::const_iterator i=text.begin(); i!=text.end(); ++i) - if(*i=='\n') - ++source_line; -} - -void ProgramCompiler::Formatter::append(char c) -{ - formatted += c; - if(c=='\n') - ++source_line; -} - -void ProgramCompiler::Formatter::set_source(unsigned index, unsigned line) -{ - if(index!=source_index || (index && line!=source_line)) - { - if(index==source_index && line==source_line+1) - formatted += '\n'; - else - { - unsigned l = line; - if(stage->required_versionvisit(*this); - append(')'); -} - -void ProgramCompiler::Formatter::visit(VariableReference &var) -{ - append(var.name); -} - -void ProgramCompiler::Formatter::visit(MemberAccess &memacc) -{ - memacc.left->visit(*this); - append(format(".%s", memacc.member)); -} - -void ProgramCompiler::Formatter::visit(UnaryExpression &unary) -{ - if(unary.prefix) - append(unary.oper); - unary.expression->visit(*this); - if(!unary.prefix) - append(unary.oper); -} - -void ProgramCompiler::Formatter::visit(BinaryExpression &binary) -{ - binary.left->visit(*this); - append(binary.oper); - binary.right->visit(*this); - append(binary.after); -} - -void ProgramCompiler::Formatter::visit(Assignment &assign) -{ - assign.left->visit(*this); - append(format(" %s ", assign.oper)); - assign.right->visit(*this); -} - -void ProgramCompiler::Formatter::visit(FunctionCall &call) -{ - append(format("%s(", call.name)); - for(NodeArray::iterator i=call.arguments.begin(); i!=call.arguments.end(); ++i) - { - if(i!=call.arguments.begin()) - append(", "); - (*i)->visit(*this); - } - append(')'); -} - -void ProgramCompiler::Formatter::visit(ExpressionStatement &expr) -{ - expr.expression->visit(*this); - append(';'); -} - -void ProgramCompiler::Formatter::visit(Block &block) -{ - unsigned brace_indent = indent; - bool use_braces = (block.use_braces || (indent && block.body.size()!=1)); - if(use_braces) - append(format("%s{\n", string(brace_indent*2, ' '))); - - SetForScope set(indent, indent+(indent>0 || use_braces)); - string spaces(indent*2, ' '); - for(NodeList::iterator i=block.body.begin(); i!=block.body.end(); ++i) - { - if(i!=block.body.begin()) - append('\n'); - set_source((*i)->source, (*i)->line); - append(spaces); - (*i)->visit(*this); - } - - if(use_braces) - append(format("\n%s}", string(brace_indent*2, ' '))); -} - -void ProgramCompiler::Formatter::visit(Import &import) -{ - append(format("import %s;", import.module)); -} - -void ProgramCompiler::Formatter::visit(Precision &prec) -{ - append(format("precision %s %s;", prec.precision, prec.type)); -} - -void ProgramCompiler::Formatter::visit(Layout &layout) -{ - append("layout("); - for(vector::const_iterator i=layout.qualifiers.begin(); i!=layout.qualifiers.end(); ++i) - { - if(i!=layout.qualifiers.begin()) - append(", "); - append(i->identifier); - if(!i->value.empty()) - append(format("=%s", i->value)); - } - append(')'); -} - -void ProgramCompiler::Formatter::visit(InterfaceLayout &layout) -{ - layout.layout.visit(*this); - append(format(" %s;", layout.interface)); -} - -void ProgramCompiler::Formatter::visit(StructDeclaration &strct) -{ - append(format("struct %s\n", strct.name)); - strct.members.visit(*this); - append(';'); -} - -void ProgramCompiler::Formatter::visit(VariableDeclaration &var) -{ - if(var.layout) - { - var.layout->visit(*this); - append(' '); - } - if(var.constant) - append("const "); - if(!var.interpolation.empty()) - append(format("%s ", var.interpolation)); - if(!var.sampling.empty()) - append(format("%s ", var.sampling)); - if(!var.interface.empty() && var.interface!=block_interface) - { - string interface = var.interface; - if(stage->required_versiontype==VERTEX && var.interface=="in") - interface = "attribute"; - else if((stage->type==VERTEX && var.interface=="out") || (stage->type==FRAGMENT && var.interface=="in")) - interface = "varying"; - } - append(format("%s ", interface)); - } - if(!var.precision.empty()) - append(format("%s ", var.precision)); - append(format("%s %s", var.type, var.name)); - if(var.array) - { - append('['); - if(var.array_size) - var.array_size->visit(*this); - append(']'); - } - if(var.init_expression) - { - append(" = "); - var.init_expression->visit(*this); - } - if(!parameter_list) - append(';'); -} - -void ProgramCompiler::Formatter::visit(InterfaceBlock &iface) -{ - SetForScope set(block_interface, iface.interface); - append(format("%s %s\n", iface.interface, iface.name)); - iface.members.visit(*this); - append(';'); -} - -void ProgramCompiler::Formatter::visit(FunctionDeclaration &func) -{ - append(format("%s %s(", func.return_type, func.name)); - for(NodeArray::iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i) - { - if(i!=func.parameters.begin()) - append(", "); - SetFlag set(parameter_list); - (*i)->visit(*this); - } - append(')'); - if(func.definition==&func) - { - append('\n'); - func.body.visit(*this); - } - else - append(';'); -} - -void ProgramCompiler::Formatter::visit(Conditional &cond) -{ - append("if("); - cond.condition->visit(*this); - append(")\n"); - - cond.body.visit(*this); - if(!cond.else_body.body.empty()) - { - Conditional *else_cond = dynamic_cast(cond.else_body.body.front().get()); - if(cond.else_body.body.size()==1 && else_cond) - { - append('\n'); - set_source(else_cond->source, else_cond->line); - append(format("%selse ", string(indent*2, ' '))); - else_cond->visit(*this); - } - else - { - append(format("\n%selse\n", string(indent*2, ' '))); - cond.else_body.visit(*this); - } - } -} - -void ProgramCompiler::Formatter::visit(Iteration &iter) -{ - if(!iter.init_statement && iter.condition && !iter.loop_expression) - { - append("while("); - iter.condition->visit(*this); - append(')'); - } - else - { - append("for("); - if(iter.init_statement) - iter.init_statement->visit(*this); - else - append(';'); - if(iter.condition) - { - append(' '); - iter.condition->visit(*this); - } - append(';'); - if(iter.loop_expression) - { - append(' '); - iter.loop_expression->visit(*this); - } - append(')'); - } - - if(iter.body.body.empty()) - append(" { }"); - else - { - append('\n'); - iter.body.visit(*this); - } -} - -void ProgramCompiler::Formatter::visit(Return &ret) -{ - append("return"); - if(ret.expression) - { - append(' '); - ret.expression->visit(*this); - } - append(';'); -} - -void ProgramCompiler::Formatter::visit(Jump &jump) -{ - append(jump.keyword); - append(';'); -} - - -ProgramCompiler::DeclarationCombiner::DeclarationCombiner(): - toplevel(true) -{ } - -void ProgramCompiler::DeclarationCombiner::visit(Block &block) -{ - if(!toplevel) - return; - - SetForScope set(toplevel, false); - BlockModifier::visit(block); -} - -void ProgramCompiler::DeclarationCombiner::visit(FunctionDeclaration &func) -{ - vector &decls = functions[func.name]; - if(func.definition) - { - for(vector::iterator i=decls.begin(); i!=decls.end(); ++i) - { - (*i)->definition = func.definition; - (*i)->body.body.clear(); - } - } - decls.push_back(&func); -} - -void ProgramCompiler::DeclarationCombiner::visit(VariableDeclaration &var) -{ - VariableDeclaration *&ptr = variables[var.name]; - if(ptr) - { - ptr->type = var.type; - if(var.init_expression) - ptr->init_expression = var.init_expression; - if(var.layout) - { - if(ptr->layout) - { - for(vector::iterator i=var.layout->qualifiers.begin(); i!=var.layout->qualifiers.end(); ++i) - { - bool found = false; - for(vector::iterator j=ptr->layout->qualifiers.begin(); (!found && j!=ptr->layout->qualifiers.end()); ++j) - if(j->identifier==i->identifier) - { - j->value = i->value; - found = true; - } - - if(!found) - ptr->layout->qualifiers.push_back(*i); - } - } - else - ptr->layout = var.layout; - } - remove_node = true; - } - else - ptr = &var; -} - - -ProgramCompiler::VariableResolver::VariableResolver(): - anonymous(false), - record_target(false), - assignment_target(0), - self_referencing(false) -{ } - -void ProgramCompiler::VariableResolver::apply(Stage &s) -{ - SetForScope set(stage, &s); - Stage *builtins = get_builtins(stage->type); - if(builtins) - blocks.push_back(&builtins->content); - stage->content.visit(*this); - if(builtins) - blocks.pop_back(); -} - -void ProgramCompiler::VariableResolver::visit(Block &block) -{ - blocks.push_back(&block); - block.variables.clear(); - TraversingVisitor::visit(block); - blocks.pop_back(); -} - -void ProgramCompiler::VariableResolver::visit(VariableReference &var) -{ - var.declaration = 0; - type = 0; - for(vector::iterator i=blocks.end(); i!=blocks.begin(); ) - { - --i; - map::iterator j = (*i)->variables.find(var.name); - if(j!=(*i)->variables.end()) - { - var.declaration = j->second; - type = j->second->type_declaration; - break; - } - } - - if(record_target) - { - if(assignment_target) - { - record_target = false; - assignment_target = 0; - } - else - assignment_target = var.declaration; - } - else if(var.declaration && var.declaration==assignment_target) - self_referencing = true; -} - -void ProgramCompiler::VariableResolver::visit(MemberAccess &memacc) -{ - type = 0; - TraversingVisitor::visit(memacc); - memacc.declaration = 0; - if(type) - { - map::iterator i = type->members.variables.find(memacc.member); - if(i!=type->members.variables.end()) - { - memacc.declaration = i->second; - type = i->second->type_declaration; - } - else - type = 0; - } -} - -void ProgramCompiler::VariableResolver::visit(BinaryExpression &binary) -{ - if(binary.oper=="[") - { - { - SetForScope set(record_target, false); - binary.right->visit(*this); - } - type = 0; - binary.left->visit(*this); - } - else - { - TraversingVisitor::visit(binary); - type = 0; - } -} - -void ProgramCompiler::VariableResolver::visit(Assignment &assign) -{ - { - SetFlag set(record_target); - assignment_target = 0; - assign.left->visit(*this); - } - - self_referencing = false; - assign.right->visit(*this); - - assign.self_referencing = (self_referencing || assign.oper!="="); - assign.target_declaration = assignment_target; -} - -void ProgramCompiler::VariableResolver::visit(StructDeclaration &strct) -{ - TraversingVisitor::visit(strct); - blocks.back()->types[strct.name] = &strct; -} - -void ProgramCompiler::VariableResolver::visit(VariableDeclaration &var) -{ - for(vector::iterator i=blocks.end(); i!=blocks.begin(); ) - { - --i; - map::iterator j = (*i)->types.find(var.type); - if(j!=(*i)->types.end()) - var.type_declaration = j->second; - } - - if(!block_interface.empty() && var.interface.empty()) - var.interface = block_interface; - - TraversingVisitor::visit(var); - blocks.back()->variables[var.name] = &var; - if(anonymous && blocks.size()>1) - blocks[blocks.size()-2]->variables[var.name] = &var; -} - -void ProgramCompiler::VariableResolver::visit(InterfaceBlock &iface) -{ - SetFlag set(anonymous); - SetForScope set2(block_interface, iface.interface); - TraversingVisitor::visit(iface); -} - - -void ProgramCompiler::FunctionResolver::visit(FunctionCall &call) -{ - map >::iterator i = functions.find(call.name); - if(i!=functions.end()) - call.declaration = i->second.back(); - - TraversingVisitor::visit(call); -} - -void ProgramCompiler::FunctionResolver::visit(FunctionDeclaration &func) -{ - vector &decls = functions[func.name]; - if(func.definition) - { - for(vector::iterator i=decls.begin(); i!=decls.end(); ++i) - (*i)->definition = func.definition; - decls.clear(); - decls.push_back(&func); - } - else if(!decls.empty() && decls.back()->definition) - func.definition = decls.back()->definition; - else - decls.push_back(&func); - - TraversingVisitor::visit(func); -} - - -ProgramCompiler::InterfaceGenerator::InterfaceGenerator(): - scope_level(0) -{ } - -string ProgramCompiler::InterfaceGenerator::get_out_prefix(StageType type) -{ - if(type==VERTEX) - return "_vs_out_"; - else if(type==GEOMETRY) - return "_gs_out_"; - else - return string(); -} - -void ProgramCompiler::InterfaceGenerator::apply(Stage &s) -{ - SetForScope set(stage, &s); - if(stage->previous) - in_prefix = get_out_prefix(stage->previous->type); - out_prefix = get_out_prefix(stage->type); - stage->content.visit(*this); -} - -void ProgramCompiler::InterfaceGenerator::visit(Block &block) -{ - SetForScope set(scope_level, scope_level+1); - for(NodeList::iterator i=block.body.begin(); i!=block.body.end(); ) - { - (*i)->visit(*this); - - if(scope_level==1) - { - for(map >::iterator j=iface_declarations.begin(); j!=iface_declarations.end(); ++j) - { - NodeList::iterator k = block.body.insert(i, j->second); - (*k)->visit(*this); - } - iface_declarations.clear(); - } - - apply_and_increment(block, i); - } -} - -string ProgramCompiler::InterfaceGenerator::change_prefix(const string &name, const string &prefix) const -{ - unsigned offset = (name.compare(0, in_prefix.size(), in_prefix) ? 0 : in_prefix.size()); - return prefix+name.substr(offset); -} - -bool ProgramCompiler::InterfaceGenerator::generate_interface(VariableDeclaration &var, const string &iface, const string &name) -{ - const map &stage_vars = (iface=="in" ? stage->in_variables : stage->out_variables); - if(stage_vars.count(name) || iface_declarations.count(name)) - return false; - - VariableDeclaration* iface_var = new VariableDeclaration; - iface_var->sampling = var.sampling; - iface_var->interface = iface; - iface_var->type = var.type; - iface_var->type_declaration = var.type_declaration; - iface_var->name = name; - if(stage->type==GEOMETRY) - iface_var->array = ((var.array && var.interface!="in") || iface=="in"); - else - iface_var->array = var.array; - if(iface_var->array) - iface_var->array_size = var.array_size; - if(iface=="in") - iface_var->linked_declaration = &var; - iface_declarations[name] = iface_var; - - return true; -} - -ExpressionStatement &ProgramCompiler::InterfaceGenerator::insert_assignment(const string &left, ProgramSyntax::Expression *right) -{ - Assignment *assign = new Assignment; - VariableReference *ref = new VariableReference; - ref->name = left; - assign->left = ref; - assign->oper = "="; - assign->right = right; - - ExpressionStatement *stmt = new ExpressionStatement; - stmt->expression = assign; - stmt->visit(*this); - insert_nodes.push_back(stmt); - - return *stmt; -} - -void ProgramCompiler::InterfaceGenerator::visit(VariableReference &var) -{ - if(var.declaration || !stage->previous) - return; - if(iface_declarations.count(var.name)) - return; - - const map &prev_out = stage->previous->out_variables; - map::const_iterator i = prev_out.find(var.name); - if(i==prev_out.end()) - i = prev_out.find(in_prefix+var.name); - if(i!=prev_out.end()) - { - generate_interface(*i->second, "in", i->second->name); - var.name = i->second->name; - } -} - -void ProgramCompiler::InterfaceGenerator::visit(VariableDeclaration &var) -{ - if(var.interface=="out") - { - if(scope_level==1) - stage->out_variables[var.name] = &var; - else if(generate_interface(var, "out", change_prefix(var.name, string()))) - { - remove_node = true; - if(var.init_expression) - { - ExpressionStatement &stmt = insert_assignment(var.name, var.init_expression->clone()); - stmt.source = var.source; - stmt.line = var.line; - return; - } - } - } - else if(var.interface=="in") - { - stage->in_variables[var.name] = &var; - if(var.linked_declaration) - var.linked_declaration->linked_declaration = &var; - else if(stage->previous) - { - const map &prev_out = stage->previous->out_variables; - map::const_iterator i = prev_out.find(var.name); - if(i!=prev_out.end()) - { - var.linked_declaration = i->second; - i->second->linked_declaration = &var; - } - } - } - - TraversingVisitor::visit(var); -} - -void ProgramCompiler::InterfaceGenerator::visit(Passthrough &pass) -{ - vector pass_vars; - - for(map::const_iterator i=stage->in_variables.begin(); i!=stage->in_variables.end(); ++i) - pass_vars.push_back(i->second); - for(map >::const_iterator i=iface_declarations.begin(); i!=iface_declarations.end(); ++i) - if(i->second->interface=="in") - pass_vars.push_back(i->second.get()); - - if(stage->previous) - { - const map &prev_out = stage->previous->out_variables; - for(map::const_iterator i=prev_out.begin(); i!=prev_out.end(); ++i) - { - bool linked = false; - for(vector::const_iterator j=pass_vars.begin(); (!linked && j!=pass_vars.end()); ++j) - linked = ((*j)->linked_declaration==i->second); - - if(!linked && generate_interface(*i->second, "in", i->second->name)) - pass_vars.push_back(i->second); - } - } - - if(stage->type==GEOMETRY) - { - VariableReference *ref = new VariableReference; - ref->name = "gl_in"; - - BinaryExpression *subscript = new BinaryExpression; - subscript->left = ref; - subscript->oper = "["; - subscript->right = pass.subscript; - subscript->after = "]"; - - MemberAccess *memacc = new MemberAccess; - memacc->left = subscript; - memacc->member = "gl_Position"; - - insert_assignment("gl_Position", memacc); - } - - for(vector::const_iterator i=pass_vars.begin(); i!=pass_vars.end(); ++i) - { - string out_name = change_prefix((*i)->name, out_prefix); - generate_interface(**i, "out", out_name); - - VariableReference *ref = new VariableReference; - ref->name = (*i)->name; - if(pass.subscript) - { - BinaryExpression *subscript = new BinaryExpression; - subscript->left = ref; - subscript->oper = "["; - subscript->right = pass.subscript; - subscript->after = "]"; - insert_assignment(out_name, subscript); - } - else - insert_assignment(out_name, ref); - } - - remove_node = true; -} - - -ProgramCompiler::DeclarationReorderer::DeclarationReorderer(): - scope_level(0), - kind(NO_DECLARATION) -{ } - -void ProgramCompiler::DeclarationReorderer::visit(FunctionCall &call) -{ - FunctionDeclaration *def = call.declaration; - if(def) - def = def->definition; - if(def && !ordered_funcs.count(def)) - needed_funcs.insert(def); -} - -void ProgramCompiler::DeclarationReorderer::visit(Block &block) -{ - SetForScope set(scope_level, scope_level+1); - if(scope_level>1) - return Visitor::visit(block); - - NodeList::iterator struct_insert_point = block.body.end(); - NodeList::iterator variable_insert_point = block.body.end(); - NodeList::iterator function_insert_point = block.body.end(); - unsigned unordered_func_count = 0; - bool ordered_any_funcs = false; - - for(NodeList::iterator i=block.body.begin(); i!=block.body.end(); ) - { - kind = NO_DECLARATION; - (*i)->visit(*this); - - bool moved = false; - if(kind==STRUCT && struct_insert_point!=block.body.end()) - { - block.body.insert(struct_insert_point, *i); - moved = true; - } - else if(kind>STRUCT && struct_insert_point==block.body.end()) - struct_insert_point = i; - - if(kind==VARIABLE && variable_insert_point!=block.body.end()) - { - block.body.insert(variable_insert_point, *i); - moved = true; - } - else if(kind>VARIABLE && variable_insert_point==block.body.end()) - variable_insert_point = i; - - if(kind==FUNCTION) - { - if(function_insert_point==block.body.end()) - function_insert_point = i; - - if(needed_funcs.empty()) - { - ordered_funcs.insert(i->get()); - if(i!=function_insert_point) - { - block.body.insert(function_insert_point, *i); - moved = true; - } - else - ++function_insert_point; - ordered_any_funcs = true; - } - else - ++unordered_func_count; - } - - if(moved) - { - if(function_insert_point==i) - ++function_insert_point; - block.body.erase(i++); - } - else - ++i; - - if(i==block.body.end() && unordered_func_count) - { - if(!ordered_any_funcs) - // A subset of the remaining functions forms a recursive loop - /* TODO pick a function and move it up, adding any necessary - declarations */ - break; - - i = function_insert_point; - unordered_func_count = 0; - } - } -} - -void ProgramCompiler::DeclarationReorderer::visit(ProgramSyntax::VariableDeclaration &var) -{ - Visitor::visit(var); - kind = VARIABLE; -} - -void ProgramCompiler::DeclarationReorderer::visit(FunctionDeclaration &func) -{ - needed_funcs.clear(); - func.body.visit(*this); - needed_funcs.erase(&func); - kind = FUNCTION; -} - - -ProgramCompiler::InlineableFunctionLocator::InlineableFunctionLocator(): - in_function(0) -{ } - -void ProgramCompiler::InlineableFunctionLocator::visit(FunctionCall &call) -{ - FunctionDeclaration *def = call.declaration; - if(def && def->definition!=def) - def = def->definition; - - if(def) - { - unsigned &count = refcounts[def]; - ++count; - if(count>1 || def==in_function) - inlineable.erase(def); - } - - TraversingVisitor::visit(call); -} - -void ProgramCompiler::InlineableFunctionLocator::visit(FunctionDeclaration &func) -{ - unsigned &count = refcounts[func.definition]; - if(!count && func.parameters.empty()) - inlineable.insert(func.definition); - - SetForScope set(in_function, &func); - TraversingVisitor::visit(func); -} - - -ProgramCompiler::FunctionInliner::FunctionInliner(): - extract_result(0) -{ } - -ProgramCompiler::FunctionInliner::FunctionInliner(const set &in): - inlineable(in), - extract_result(0) -{ } - -void ProgramCompiler::FunctionInliner::visit_and_inline(RefPtr &ptr) -{ - inline_result = 0; - ptr->visit(*this); - if(inline_result) - ptr = inline_result; -} - -void ProgramCompiler::FunctionInliner::visit(Block &block) -{ - if(extract_result) - --extract_result; - - for(NodeList::iterator i=block.body.begin(); i!=block.body.end(); ++i) - { - (*i)->visit(*this); - if(extract_result) - --extract_result; - } -} - -void ProgramCompiler::FunctionInliner::visit(UnaryExpression &unary) -{ - visit_and_inline(unary.expression); - inline_result = 0; -} - -void ProgramCompiler::FunctionInliner::visit(BinaryExpression &binary) -{ - visit_and_inline(binary.left); - visit_and_inline(binary.right); - inline_result = 0; -} - -void ProgramCompiler::FunctionInliner::visit(MemberAccess &memacc) -{ - visit_and_inline(memacc.left); - inline_result = 0; -} - -void ProgramCompiler::FunctionInliner::visit(FunctionCall &call) -{ - for(NodeArray::iterator i=call.arguments.begin(); i!=call.arguments.end(); ++i) - visit_and_inline(*i); - - FunctionDeclaration *def = call.declaration; - if(def && def->definition!=def) - def = def->definition; - - if(def && inlineable.count(def)) - { - extract_result = 2; - def->visit(*this); - } - else - inline_result = 0; -} - -void ProgramCompiler::FunctionInliner::visit(VariableDeclaration &var) -{ - if(var.init_expression) - visit_and_inline(var.init_expression); - inline_result = 0; -} - -void ProgramCompiler::FunctionInliner::visit(Return &ret) -{ - TraversingVisitor::visit(ret); - - if(extract_result) - inline_result = ret.expression->clone(); -} - - -ProgramCompiler::ExpressionEvaluator::ExpressionEvaluator(): - variable_values(0), - result(0.0f), - result_valid(false) -{ } - -ProgramCompiler::ExpressionEvaluator::ExpressionEvaluator(const ValueMap &v): - variable_values(&v), - result(0.0f), - result_valid(false) -{ } - -void ProgramCompiler::ExpressionEvaluator::visit(Literal &literal) -{ - if(literal.token=="true") - result = 1.0f; - else if(literal.token=="false") - result = 0.0f; - else - result = lexical_cast(literal.token); - result_valid = true; -} - -void ProgramCompiler::ExpressionEvaluator::visit(ParenthesizedExpression &parexp) -{ - parexp.expression->visit(*this); -} - -void ProgramCompiler::ExpressionEvaluator::visit(VariableReference &var) -{ - if(!var.declaration) - return; - - if(variable_values) - { - ValueMap::const_iterator i = variable_values->find(var.declaration); - if(i!=variable_values->end()) - i->second->visit(*this); - } - else if(var.declaration->init_expression) - var.declaration->init_expression->visit(*this); -} - -void ProgramCompiler::ExpressionEvaluator::visit(UnaryExpression &unary) -{ - result_valid = false; - unary.expression->visit(*this); - if(!result_valid) - return; - - if(unary.oper=="!") - result = !result; - else - result_valid = false; -} - -void ProgramCompiler::ExpressionEvaluator::visit(BinaryExpression &binary) -{ - result_valid = false; - binary.left->visit(*this); - if(!result_valid) - return; - - float left_result = result; - result_valid = false; - binary.right->visit(*this); - if(!result_valid) - return; - - if(binary.oper=="<") - result = (left_result") - result = (left_result>result); - else if(binary.oper==">=") - result = (left_result>=result); - else if(binary.oper=="==") - result = (left_result==result); - else if(binary.oper=="!=") - result = (left_result!=result); - else if(binary.oper=="&&") - result = (left_result && result); - else if(binary.oper=="||") - result = (left_result || result); - else - result_valid = false; -} - - -ProgramCompiler::ConstantConditionEliminator::ConstantConditionEliminator(): - scope_level(0), - record_only(false) -{ } - -void ProgramCompiler::ConstantConditionEliminator::visit(Block &block) -{ - SetForScope set(scope_level, scope_level+1); - BlockModifier::visit(block); - - for(map::const_iterator i=block.variables.begin(); i!=block.variables.end(); ++i) - variable_values.erase(i->second); -} - -void ProgramCompiler::ConstantConditionEliminator::visit(UnaryExpression &unary) -{ - if(VariableReference *var = dynamic_cast(unary.expression.get())) - if(unary.oper=="++" || unary.oper=="--") - variable_values.erase(var->declaration); -} - -void ProgramCompiler::ConstantConditionEliminator::visit(Assignment &assign) -{ - variable_values.erase(assign.target_declaration); -} - -void ProgramCompiler::ConstantConditionEliminator::visit(VariableDeclaration &var) -{ - if(var.constant || scope_level>1) - variable_values[&var] = var.init_expression.get(); -} - -void ProgramCompiler::ConstantConditionEliminator::visit(Conditional &cond) -{ - if(!record_only) - { - ExpressionEvaluator eval(variable_values); - cond.condition->visit(eval); - if(eval.result_valid) - { - flatten_block(eval.result ? cond.body : cond.else_body); - return; - } - } - - TraversingVisitor::visit(cond); -} - -void ProgramCompiler::ConstantConditionEliminator::visit(Iteration &iter) -{ - if(!record_only) - { - if(iter.condition) - { - /* If the loop condition is always false on the first iteration, the - entire loop can be removed */ - if(iter.init_statement) - iter.init_statement->visit(*this); - ExpressionEvaluator eval(variable_values); - iter.condition->visit(eval); - if(eval.result_valid && !eval.result) - { - remove_node = true; - return; - } - } - - /* Record all assignments that occur inside the loop body so those - variables won't be considered as constant */ - SetFlag set_record(record_only); - TraversingVisitor::visit(iter); - } - - TraversingVisitor::visit(iter); - - if(VariableDeclaration *init_decl = dynamic_cast(iter.init_statement.get())) - variable_values.erase(init_decl); -} - - -ProgramCompiler::UnusedVariableLocator::UnusedVariableLocator(): - aggregate(0), - assignment(0), - assignment_target(false), - assign_to_subscript(false), - global_scope(true) -{ } - -void ProgramCompiler::UnusedVariableLocator::apply(Stage &s) -{ - variables.push_back(BlockVariableMap()); - Visitor::apply(s); - BlockVariableMap &global_variables = variables.back(); - for(BlockVariableMap::iterator i=global_variables.begin(); i!=global_variables.end(); ++i) - { - if(i->first->interface=="out" && (s.type==FRAGMENT || i->first->linked_declaration || !i->first->name.compare(0, 3, "gl_"))) - continue; - if(!i->second.referenced) - { - unused_nodes.insert(i->first); - clear_assignments(i->second, true); - } - } - variables.pop_back(); -} - -void ProgramCompiler::UnusedVariableLocator::visit(VariableReference &var) -{ - map::iterator i = aggregates.find(var.declaration); - if(i!=aggregates.end()) - unused_nodes.erase(i->second); - - if(var.declaration && !assignment_target) - { - VariableInfo &var_info = variables.back()[var.declaration]; - var_info.assignments.clear(); - var_info.referenced = true; - } -} - -void ProgramCompiler::UnusedVariableLocator::visit(MemberAccess &memacc) -{ - TraversingVisitor::visit(memacc); - unused_nodes.erase(memacc.declaration); -} - -void ProgramCompiler::UnusedVariableLocator::visit(BinaryExpression &binary) -{ - if(binary.oper=="[") - { - if(assignment_target) - assign_to_subscript = true; - binary.left->visit(*this); - SetForScope set(assignment_target, false); - binary.right->visit(*this); - } - else - TraversingVisitor::visit(binary); -} - -void ProgramCompiler::UnusedVariableLocator::visit(Assignment &assign) -{ - { - assign_to_subscript = false; - SetForScope set(assignment_target, !assign.self_referencing); - assign.left->visit(*this); - } - assign.right->visit(*this); - assignment = &assign; -} - -void ProgramCompiler::UnusedVariableLocator::record_assignment(VariableDeclaration &var, Node &node, bool chained) -{ - VariableInfo &var_info = variables.back()[&var]; - if(!chained) - clear_assignments(var_info, true); - var_info.assignments.push_back(&node); - var_info.conditionally_assigned = false; -} - -void ProgramCompiler::UnusedVariableLocator::clear_assignments(VariableInfo &var_info, bool mark_unused) -{ - if(mark_unused) - { - for(vector::iterator i=var_info.assignments.begin(); i!=var_info.assignments.end(); ++i) - unused_nodes.insert(*i); - } - var_info.assignments.clear(); -} - -void ProgramCompiler::UnusedVariableLocator::visit(ExpressionStatement &expr) -{ - assignment = 0; - TraversingVisitor::visit(expr); - if(assignment && assignment->target_declaration) - record_assignment(*assignment->target_declaration, expr, (assignment->self_referencing || assign_to_subscript)); -} - -void ProgramCompiler::UnusedVariableLocator::visit(StructDeclaration &strct) -{ - SetForScope set(aggregate, &strct); - unused_nodes.insert(&strct); - TraversingVisitor::visit(strct); -} - -void ProgramCompiler::UnusedVariableLocator::visit(VariableDeclaration &var) -{ - if(aggregate) - aggregates[&var] = aggregate; - else - { - variables.back()[&var].local = true; - if(var.init_expression) - record_assignment(var, *var.init_expression, false); - } - unused_nodes.erase(var.type_declaration); - TraversingVisitor::visit(var); -} - -void ProgramCompiler::UnusedVariableLocator::visit(InterfaceBlock &iface) -{ - SetForScope set(aggregate, &iface); - unused_nodes.insert(&iface); - TraversingVisitor::visit(iface); -} - -void ProgramCompiler::UnusedVariableLocator::visit(FunctionDeclaration &func) -{ - variables.push_back(BlockVariableMap()); - - { - SetForScope set(global_scope, false); - for(NodeArray::iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i) - (*i)->visit(*this); - func.body.visit(*this); - } - - BlockVariableMap &block_variables = variables.back(); - for(BlockVariableMap::iterator i=block_variables.begin(); i!=block_variables.end(); ++i) - i->second.conditionally_assigned = true; - for(NodeArray::iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i) - block_variables[i->get()].referenced = true; - merge_down_variables(); -} - -void ProgramCompiler::UnusedVariableLocator::merge_down_variables() -{ - BlockVariableMap &parent_variables = variables[variables.size()-2]; - BlockVariableMap &block_variables = variables.back(); - for(BlockVariableMap::iterator i=block_variables.begin(); i!=block_variables.end(); ++i) - { - if(i->second.local) - { - if(!i->second.referenced) - unused_nodes.insert(i->first); - clear_assignments(i->second, i->first->interface!="out"); - continue; - } - - BlockVariableMap::iterator j = parent_variables.find(i->first); - if(j==parent_variables.end()) - parent_variables.insert(*i); - else - { - if(i->second.referenced || !i->second.conditionally_assigned) - clear_assignments(j->second, !i->second.referenced); - j->second.conditionally_assigned = i->second.conditionally_assigned; - j->second.referenced |= i->second.referenced; - j->second.assignments.insert(j->second.assignments.end(), i->second.assignments.begin(), i->second.assignments.end()); - } - } - variables.pop_back(); -} - -void ProgramCompiler::UnusedVariableLocator::visit(Conditional &cond) -{ - cond.condition->visit(*this); - variables.push_back(BlockVariableMap()); - cond.body.visit(*this); - - BlockVariableMap if_variables; - swap(variables.back(), if_variables); - cond.else_body.visit(*this); - - BlockVariableMap &else_variables = variables.back(); - for(BlockVariableMap::iterator i=else_variables.begin(); i!=else_variables.end(); ++i) - { - BlockVariableMap::iterator j = if_variables.find(i->first); - if(j!=if_variables.end()) - { - i->second.assignments.insert(i->second.assignments.end(), j->second.assignments.begin(), j->second.assignments.end()); - i->second.conditionally_assigned |= j->second.conditionally_assigned; - if_variables.erase(j); - } - else - i->second.conditionally_assigned = true; - } - - for(BlockVariableMap::iterator i=if_variables.begin(); i!=if_variables.end(); ++i) - { - i->second.conditionally_assigned = true; - else_variables.insert(*i); - } - - merge_down_variables(); -} - -void ProgramCompiler::UnusedVariableLocator::visit(Iteration &iter) -{ - variables.push_back(BlockVariableMap()); - TraversingVisitor::visit(iter); - - BlockVariableMap &block_variables = variables.back(); - for(BlockVariableMap::iterator i=block_variables.begin(); i!=block_variables.end(); ++i) - if(!i->second.local && i->second.referenced) - i->second.assignments.clear(); - - merge_down_variables(); -} - - -ProgramCompiler::UnusedVariableLocator::VariableInfo::VariableInfo(): - local(false), - conditionally_assigned(false), - referenced(false) -{ } - - -void ProgramCompiler::UnusedFunctionLocator::visit(FunctionCall &call) -{ - TraversingVisitor::visit(call); - - unused_nodes.erase(call.declaration); - if(call.declaration && call.declaration->definition!=call.declaration) - used_definitions.insert(call.declaration->definition); -} - -void ProgramCompiler::UnusedFunctionLocator::visit(FunctionDeclaration &func) -{ - TraversingVisitor::visit(func); - - if((func.name!="main" || func.body.body.empty()) && !used_definitions.count(&func)) - unused_nodes.insert(&func); -} - - -ProgramCompiler::NodeRemover::NodeRemover(const set &r): - to_remove(r) -{ } - -void ProgramCompiler::NodeRemover::visit(Block &block) -{ - for(NodeList::iterator i=block.body.begin(); i!=block.body.end(); ) - { - (*i)->visit(*this); - if(to_remove.count(i->get())) - block.body.erase(i++); - else - ++i; - } -} - -void ProgramCompiler::NodeRemover::visit(VariableDeclaration &var) -{ - if(to_remove.count(&var)) - { - stage->in_variables.erase(var.name); - stage->out_variables.erase(var.name); - stage->locations.erase(var.name); - if(var.linked_declaration) - var.linked_declaration->linked_declaration = 0; - } - else if(var.init_expression && to_remove.count(var.init_expression.get())) - var.init_expression = 0; -} - -void ProgramCompiler::NodeRemover::visit(Iteration &iter) -{ - if(to_remove.count(iter.init_statement.get())) - iter.init_statement = 0; - TraversingVisitor::visit(iter); -} - - -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()), - frag_out(0) -{ } - -ProgramCompiler::LegacyConverter::LegacyConverter(const Version &v): - target_api(get_gl_api()), - target_version(v), - frag_out(0) -{ } - -bool ProgramCompiler::LegacyConverter::check_version(const Version &feature_version) const -{ - if(target_versionrequired_versionrequired_version = feature_version; - - return true; -} - -bool ProgramCompiler::LegacyConverter::check_extension(const Extension &extension) const -{ - if(!extension) - return false; - - vector::iterator i = find(stage->required_extensions, &extension); - if(i==stage->required_extensions.end()) - stage->required_extensions.push_back(&extension); - - return true; -} - -bool ProgramCompiler::LegacyConverter::supports_unified_interface_syntax() const -{ - if(target_api==OPENGL_ES2) - return check_version(Version(3, 0)); - else - return check_version(Version(1, 30)); -} - -void ProgramCompiler::LegacyConverter::visit(VariableReference &var) -{ - if(var.declaration==frag_out && !supports_unified_interface_syntax()) - { - var.name = "gl_FragColor"; - var.declaration = 0; - type = "vec4"; - } - else if(var.declaration) - type = var.declaration->type; - else - type = string(); -} - -void ProgramCompiler::LegacyConverter::visit(Assignment &assign) -{ - TraversingVisitor::visit(assign); - if(assign.target_declaration==frag_out && !supports_unified_interface_syntax()) - assign.target_declaration = 0; -} - -bool ProgramCompiler::LegacyConverter::supports_unified_sampling_functions() const -{ - if(target_api==OPENGL_ES2) - return check_version(Version(3, 0)); - else - return check_version(Version(1, 30)); -} - -void ProgramCompiler::LegacyConverter::visit(FunctionCall &call) -{ - if(call.name=="texture" && !call.declaration && !supports_unified_sampling_functions()) - { - NodeArray::iterator i = call.arguments.begin(); - if(i!=call.arguments.end()) - { - (*i)->visit(*this); - if(type=="sampler1D") - call.name = "texture1D"; - else if(type=="sampler2D") - call.name = "texture2D"; - else if(type=="sampler3D") - call.name = "texture3D"; - else if(type=="samplerCube") - call.name = "textureCube"; - else if(type=="sampler1DShadow") - call.name = "shadow1D"; - else if(type=="sampler2DShadow") - call.name = "shadow2D"; - else if(type=="sampler1DArray") - { - check_extension(EXT_texture_array); - call.name = "texture1DArray"; - } - else if(type=="sampler2DArray") - { - check_extension(EXT_texture_array); - call.name = "texture2DArray"; - } - else if(type=="sampler1DArrayShadow") - { - check_extension(EXT_texture_array); - call.name = "shadow1DArray"; - } - else if(type=="sampler2DArrayShadow") - { - check_extension(EXT_texture_array); - call.name = "shadow2DArray"; - } - - for(; i!=call.arguments.end(); ++i) - (*i)->visit(*this); - } - } - else - TraversingVisitor::visit(call); -} - -bool ProgramCompiler::LegacyConverter::supports_interface_layouts() const -{ - if(target_api==OPENGL_ES2) - return check_version(Version(3, 0)); - else if(check_version(Version(3, 30))) - return true; - else - return check_extension(ARB_explicit_attrib_location); -} - -bool ProgramCompiler::LegacyConverter::supports_centroid_sampling() const -{ - if(target_api==OPENGL_ES2) - return check_version(Version(3, 0)); - else if(check_version(Version(1, 20))) - return true; - else - return check_extension(EXT_gpu_shader4); -} - -bool ProgramCompiler::LegacyConverter::supports_sample_sampling() const -{ - if(target_api==OPENGL_ES2) - return check_version(Version(3, 20)); - else if(check_version(Version(4, 0))) - return true; - else - return check_extension(ARB_gpu_shader5); -} - -void ProgramCompiler::LegacyConverter::visit(VariableDeclaration &var) -{ - if(var.layout && !supports_interface_layouts()) - { - vector::iterator i; - for(i=var.layout->qualifiers.begin(); (i!=var.layout->qualifiers.end() && i->identifier!="location"); ++i) ; - if(i!=var.layout->qualifiers.end()) - { - unsigned location = lexical_cast(i->value); - if(stage->type==VERTEX && var.interface=="in") - { - stage->locations[var.name] = location; - var.layout->qualifiers.erase(i); - } - else if(stage->type==FRAGMENT && var.interface=="out") - { - if(location!=0) - static Require _req(EXT_gpu_shader4); - stage->locations[var.name] = location; - var.layout->qualifiers.erase(i); - } - - if(var.layout->qualifiers.empty()) - var.layout = 0; - } - } - - if(var.sampling=="centroid") - { - if(!supports_centroid_sampling()) - var.sampling = string(); - } - else if(var.sampling=="sample") - { - if(!supports_sample_sampling()) - var.sampling = string(); - } - - if((var.interface=="in" || var.interface=="out") && !supports_unified_interface_syntax()) - { - if(stage->type==FRAGMENT && var.interface=="out") - { - frag_out = &var; - remove_node = true; - } - } - - TraversingVisitor::visit(var); -} - -bool ProgramCompiler::LegacyConverter::supports_interface_blocks(const string &iface) const -{ - if(target_api==OPENGL_ES2) - { - if(iface=="uniform") - return check_version(Version(3, 0)); - else - return check_version(Version(3, 20)); - } - else if(check_version(Version(1, 50))) - return true; - else if(iface=="uniform") - return check_extension(ARB_uniform_buffer_object); - else - return false; -} - -void ProgramCompiler::LegacyConverter::visit(InterfaceBlock &iface) -{ - if(!supports_interface_blocks(iface.interface)) - flatten_block(iface.members); -} - -} // namespace GL -} // namespace Msp diff --git a/source/glsl/programcompiler.h b/source/glsl/programcompiler.h deleted file mode 100644 index 0bff354a..00000000 --- a/source/glsl/programcompiler.h +++ /dev/null @@ -1,416 +0,0 @@ -#ifndef MSP_GL_PROGRAMCOMPILER_H_ -#define MSP_GL_PROGRAMCOMPILER_H_ - -#include -#include "programparser.h" -#include "programsyntax.h" - -namespace Msp { -namespace GL { - -class Program; -class Resources; - -class ProgramCompiler -{ -private: - struct Visitor: ProgramSyntax::TraversingVisitor - { - typedef void ResultType; - - ProgramSyntax::Stage *stage; - - Visitor(); - - virtual void apply(ProgramSyntax::Stage &); - void get_result() const { } - }; - - struct BlockModifier: Visitor - { - bool remove_node; - std::vector > insert_nodes; - - BlockModifier(); - - void flatten_block(ProgramSyntax::Block &); - void apply_and_increment(ProgramSyntax::Block &, ProgramSyntax::NodeList::iterator &); - using Visitor::visit; - virtual void visit(ProgramSyntax::Block &); - }; - - struct Formatter: Visitor - { - typedef std::string ResultType; - - std::string formatted; - unsigned source_index; - unsigned source_line; - unsigned indent; - bool parameter_list; - std::string block_interface; - - Formatter(); - - virtual void apply(ProgramSyntax::Stage &); - const std::string &get_result() const { return formatted; } - using Visitor::visit; - void append(const std::string &); - void append(char); - void set_source(unsigned, unsigned); - virtual void visit(ProgramSyntax::Block &); - virtual void visit(ProgramSyntax::Literal &); - virtual void visit(ProgramSyntax::ParenthesizedExpression &); - virtual void visit(ProgramSyntax::VariableReference &); - virtual void visit(ProgramSyntax::MemberAccess &); - virtual void visit(ProgramSyntax::UnaryExpression &); - virtual void visit(ProgramSyntax::BinaryExpression &); - virtual void visit(ProgramSyntax::Assignment &); - 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 &); - virtual void visit(ProgramSyntax::VariableDeclaration &); - virtual void visit(ProgramSyntax::InterfaceBlock &); - virtual void visit(ProgramSyntax::FunctionDeclaration &); - virtual void visit(ProgramSyntax::Conditional &); - virtual void visit(ProgramSyntax::Iteration &); - virtual void visit(ProgramSyntax::Return &); - virtual void visit(ProgramSyntax::Jump &); - }; - - template - struct NodeGatherer: Visitor - { - typedef std::vector ResultType; - - std::vector nodes; - - const ResultType &get_result() const { return nodes; } - using Visitor::visit; - virtual void visit(T &n) { nodes.push_back(&n); } - }; - - struct DeclarationCombiner: BlockModifier - { - bool toplevel; - std::map > functions; - std::map variables; - - DeclarationCombiner(); - - using Visitor::visit; - virtual void visit(ProgramSyntax::Block &); - virtual void visit(ProgramSyntax::FunctionDeclaration &); - virtual void visit(ProgramSyntax::VariableDeclaration &); - }; - - struct VariableResolver: Visitor - { - std::vector blocks; - ProgramSyntax::StructDeclaration *type; - bool anonymous; - std::string block_interface; - bool record_target; - ProgramSyntax::VariableDeclaration *assignment_target; - bool self_referencing; - - VariableResolver(); - - virtual void apply(ProgramSyntax::Stage &); - using Visitor::visit; - virtual void visit(ProgramSyntax::Block &); - virtual void visit(ProgramSyntax::VariableReference &); - virtual void visit(ProgramSyntax::MemberAccess &); - virtual void visit(ProgramSyntax::BinaryExpression &); - virtual void visit(ProgramSyntax::Assignment &); - virtual void visit(ProgramSyntax::StructDeclaration &); - virtual void visit(ProgramSyntax::VariableDeclaration &); - virtual void visit(ProgramSyntax::InterfaceBlock &); - }; - - struct FunctionResolver: Visitor - { - std::map > functions; - - using Visitor::visit; - virtual void visit(ProgramSyntax::FunctionCall &); - virtual void visit(ProgramSyntax::FunctionDeclaration &); - }; - - struct InterfaceGenerator: BlockModifier - { - std::string in_prefix; - std::string out_prefix; - unsigned scope_level; - std::map > iface_declarations; - - InterfaceGenerator(); - - static std::string get_out_prefix(ProgramSyntax::StageType); - virtual void apply(ProgramSyntax::Stage &); - using Visitor::visit; - virtual void visit(ProgramSyntax::Block &); - std::string change_prefix(const std::string &, const std::string &) const; - bool generate_interface(ProgramSyntax::VariableDeclaration &, const std::string &, const std::string &); - ProgramSyntax::ExpressionStatement &insert_assignment(const std::string &, ProgramSyntax::Expression *); - virtual void visit(ProgramSyntax::VariableReference &); - virtual void visit(ProgramSyntax::VariableDeclaration &); - virtual void visit(ProgramSyntax::Passthrough &); - }; - - struct DeclarationReorderer: Visitor - { - enum DeclarationKind - { - NO_DECLARATION, - LAYOUT, - STRUCT, - VARIABLE, - FUNCTION - }; - - unsigned scope_level; - DeclarationKind kind; - std::set ordered_funcs; - std::set needed_funcs; - - DeclarationReorderer(); - - using Visitor::visit; - virtual void visit(ProgramSyntax::Block &); - virtual void visit(ProgramSyntax::FunctionCall &); - virtual void visit(ProgramSyntax::InterfaceLayout &) { kind = LAYOUT; } - virtual void visit(ProgramSyntax::StructDeclaration &) { kind = STRUCT; } - virtual void visit(ProgramSyntax::VariableDeclaration &); - virtual void visit(ProgramSyntax::InterfaceBlock &) { kind = VARIABLE; } - virtual void visit(ProgramSyntax::FunctionDeclaration &); - }; - - struct InlineableFunctionLocator: Visitor - { - typedef std::set ResultType; - - std::map refcounts; - std::set inlineable; - ProgramSyntax::FunctionDeclaration *in_function; - - InlineableFunctionLocator(); - - const ResultType &get_result() const { return inlineable; } - using Visitor::visit; - virtual void visit(ProgramSyntax::FunctionCall &); - virtual void visit(ProgramSyntax::FunctionDeclaration &); - }; - - struct FunctionInliner: Visitor - { - std::set inlineable; - unsigned extract_result; - RefPtr inline_result; - - FunctionInliner(); - FunctionInliner(const std::set &); - - void visit_and_inline(RefPtr &); - using Visitor::visit; - virtual void visit(ProgramSyntax::Block &); - virtual void visit(ProgramSyntax::UnaryExpression &); - virtual void visit(ProgramSyntax::BinaryExpression &); - virtual void visit(ProgramSyntax::MemberAccess &); - virtual void visit(ProgramSyntax::FunctionCall &); - virtual void visit(ProgramSyntax::VariableDeclaration &); - virtual void visit(ProgramSyntax::Return &); - }; - - struct ExpressionEvaluator: ProgramSyntax::NodeVisitor - { - typedef std::map ValueMap; - - const ValueMap *variable_values; - float result; - bool result_valid; - - ExpressionEvaluator(); - ExpressionEvaluator(const ValueMap &); - - using ProgramSyntax::NodeVisitor::visit; - virtual void visit(ProgramSyntax::Literal &); - virtual void visit(ProgramSyntax::ParenthesizedExpression &); - virtual void visit(ProgramSyntax::VariableReference &); - virtual void visit(ProgramSyntax::UnaryExpression &); - virtual void visit(ProgramSyntax::BinaryExpression &); - }; - - struct ConstantConditionEliminator: BlockModifier - { - unsigned scope_level; - bool record_only; - ExpressionEvaluator::ValueMap variable_values; - - ConstantConditionEliminator(); - - using Visitor::visit; - virtual void visit(ProgramSyntax::Block &); - virtual void visit(ProgramSyntax::UnaryExpression &); - virtual void visit(ProgramSyntax::Assignment &); - virtual void visit(ProgramSyntax::VariableDeclaration &); - virtual void visit(ProgramSyntax::Conditional &); - virtual void visit(ProgramSyntax::Iteration &); - }; - - struct UnusedVariableLocator: Visitor - { - struct VariableInfo - { - bool local; - std::vector assignments; - bool conditionally_assigned; - bool referenced; - - VariableInfo(); - }; - - typedef std::set ResultType; - typedef std::map BlockVariableMap; - - std::set unused_nodes; - std::map aggregates; - ProgramSyntax::Node *aggregate; - std::vector variables; - ProgramSyntax::Assignment *assignment; - bool assignment_target; - bool assign_to_subscript; - bool global_scope; - - UnusedVariableLocator(); - - virtual void apply(ProgramSyntax::Stage &); - const ResultType &get_result() const { return unused_nodes; } - using Visitor::visit; - virtual void visit(ProgramSyntax::VariableReference &); - virtual void visit(ProgramSyntax::MemberAccess &); - virtual void visit(ProgramSyntax::BinaryExpression &); - virtual void visit(ProgramSyntax::Assignment &); - void record_assignment(ProgramSyntax::VariableDeclaration &, ProgramSyntax::Node &, bool); - void clear_assignments(VariableInfo &, bool); - virtual void visit(ProgramSyntax::ExpressionStatement &); - virtual void visit(ProgramSyntax::StructDeclaration &); - virtual void visit(ProgramSyntax::VariableDeclaration &); - virtual void visit(ProgramSyntax::InterfaceBlock &); - virtual void visit(ProgramSyntax::FunctionDeclaration &); - void merge_down_variables(); - virtual void visit(ProgramSyntax::Conditional &); - virtual void visit(ProgramSyntax::Iteration &); - }; - - struct UnusedFunctionLocator: Visitor - { - typedef std::set ResultType; - - std::set unused_nodes; - std::set used_definitions; - - const ResultType &get_result() const { return unused_nodes; } - using Visitor::visit; - virtual void visit(ProgramSyntax::FunctionCall &); - virtual void visit(ProgramSyntax::FunctionDeclaration &); - }; - - struct NodeRemover: Visitor - { - std::set to_remove; - - NodeRemover() { } - NodeRemover(const std::set &); - - using Visitor::visit; - virtual void visit(ProgramSyntax::Block &); - virtual void visit(ProgramSyntax::VariableDeclaration &); - virtual void visit(ProgramSyntax::Iteration &); - }; - - 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; - Version target_version; - std::string type; - ProgramSyntax::VariableDeclaration *frag_out; - - LegacyConverter(); - LegacyConverter(const Version &); - - bool check_version(const Version &) const; - bool check_extension(const Extension &) const; - using Visitor::visit; - bool supports_unified_interface_syntax() const; - virtual void visit(ProgramSyntax::VariableReference &); - virtual void visit(ProgramSyntax::Assignment &); - bool supports_unified_sampling_functions() const; - virtual void visit(ProgramSyntax::FunctionCall &); - bool supports_interface_layouts() const; - bool supports_centroid_sampling() const; - bool supports_sample_sampling() const; - virtual void visit(ProgramSyntax::VariableDeclaration &); - bool supports_interface_blocks(const std::string &) const; - virtual void visit(ProgramSyntax::InterfaceBlock &); - }; - - Resources *resources; - ProgramSyntax::Module *module; - std::vector imported_names; - -public: - ProgramCompiler(); - ~ProgramCompiler(); - - void compile(const std::string &, const std::string & = ""); - void compile(IO::Base &, Resources * = 0, const std::string & = ""); - void compile(IO::Base &, const std::string &); - void add_shaders(Program &); - -private: - static ProgramSyntax::Module *create_builtins_module(); - static ProgramSyntax::Module &get_builtins_module(); - static ProgramSyntax::Stage *get_builtins(ProgramSyntax::StageType); - void append_module(ProgramSyntax::Module &); - void append_stage(ProgramSyntax::Stage &); - void process(); - 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 &); - template - static typename T::ResultType apply(ProgramSyntax::Stage &, const A &); -}; - -} // namespace GL -} // namespace Msp - -#endif diff --git a/source/glsl/programparser.cpp b/source/glsl/programparser.cpp deleted file mode 100644 index 83a2879f..00000000 --- a/source/glsl/programparser.cpp +++ /dev/null @@ -1,962 +0,0 @@ -#include -#include -#include -#include "programparser.h" - -#undef interface - -using namespace std; - -namespace Msp { -namespace GL { - -using namespace ProgramSyntax; - -ProgramParser::Operator ProgramParser::operators[] = -{ - { "[", 2, BINARY, LEFT_TO_RIGHT }, - { "(", 2, BINARY, LEFT_TO_RIGHT }, - { ".", 2, BINARY, LEFT_TO_RIGHT }, - { "++", 2, POSTFIX, LEFT_TO_RIGHT }, - { "--", 2, POSTFIX, LEFT_TO_RIGHT }, - { "++", 3, PREFIX, RIGHT_TO_LEFT }, - { "--", 3, PREFIX, RIGHT_TO_LEFT }, - { "+", 3, PREFIX, RIGHT_TO_LEFT }, - { "-", 3, PREFIX, RIGHT_TO_LEFT }, - { "~", 3, PREFIX, RIGHT_TO_LEFT }, - { "!", 3, PREFIX, RIGHT_TO_LEFT }, - { "*", 4, BINARY, LEFT_TO_RIGHT }, - { "/", 4, BINARY, LEFT_TO_RIGHT }, - { "%", 4, BINARY, LEFT_TO_RIGHT }, - { "+", 5, BINARY, LEFT_TO_RIGHT }, - { "-", 5, BINARY, LEFT_TO_RIGHT }, - { "<<", 6, BINARY, LEFT_TO_RIGHT }, - { ">>", 6, BINARY, LEFT_TO_RIGHT }, - { "<", 7, BINARY, LEFT_TO_RIGHT }, - { ">", 7, BINARY, LEFT_TO_RIGHT }, - { "<=", 7, BINARY, LEFT_TO_RIGHT }, - { ">=", 7, BINARY, LEFT_TO_RIGHT }, - { "==", 8, BINARY, LEFT_TO_RIGHT }, - { "!=", 8, BINARY, LEFT_TO_RIGHT }, - { "&", 9, BINARY, LEFT_TO_RIGHT }, - { "^", 10, BINARY, LEFT_TO_RIGHT }, - { "|", 11, BINARY, LEFT_TO_RIGHT }, - { "&&", 12, BINARY, LEFT_TO_RIGHT }, - { "^^", 13, BINARY, LEFT_TO_RIGHT }, - { "||", 14, BINARY, LEFT_TO_RIGHT }, - { "?", 15, BINARY, RIGHT_TO_LEFT }, - { ":", 15, BINARY, RIGHT_TO_LEFT }, - { "=", 16, BINARY, RIGHT_TO_LEFT }, - { "+=", 16, BINARY, RIGHT_TO_LEFT }, - { "-=", 16, BINARY, RIGHT_TO_LEFT }, - { "*=", 16, BINARY, RIGHT_TO_LEFT }, - { "/=", 16, BINARY, RIGHT_TO_LEFT }, - { "%=", 16, BINARY, RIGHT_TO_LEFT }, - { "<<=", 16, BINARY, RIGHT_TO_LEFT }, - { ">>=", 16, BINARY, RIGHT_TO_LEFT }, - { "&=", 16, BINARY, RIGHT_TO_LEFT }, - { "^=", 16, BINARY, RIGHT_TO_LEFT }, - { "|=", 16, BINARY, RIGHT_TO_LEFT }, - { ",", 17, BINARY, LEFT_TO_RIGHT }, - { { 0 }, 18, NO_OPERATOR, LEFT_TO_RIGHT } -}; - -ProgramParser::ProgramParser(): - module(0) -{ } - -ProgramParser::~ProgramParser() -{ - delete module; -} - -Module &ProgramParser::parse(const string &s, const string &n, unsigned i) -{ - source = s; - source_name = n; - source_index = i; - parse_source(); - return *module; -} - -Module &ProgramParser::parse(IO::Base &io, const string &n, unsigned i) -{ - source = string(); - source_name = n; - source_index = i; - while(!io.eof()) - { - char buffer[4096]; - unsigned len = io.read(buffer, sizeof(buffer)); - source.append(buffer, len); - } - parse_source(); - return *module; -} - -void ProgramParser::parse_source() -{ - while(1) - { - string::size_type slashes = source.find("//////"); - if(slashes==string::npos) - break; - - string::size_type newline = source.find('\n', slashes); - string pragma = format("#pragma MSP stage(%s)", source.substr(slashes+6, newline-slashes-6)); - source.replace(slashes, newline-slashes, pragma); - } - - delete module; - module = new Module; - cur_stage = &module->shared; - iter = source.begin(); - source_end = source.end(); - current_line = 1; - allow_preprocess = true; - while(RefPtr statement = parse_global_declaration()) - cur_stage->content.body.push_back(statement); -} - -string ProgramParser::format_error(const std::string &message) -{ - string location = format("%s:%d: ", source_name, current_line); - return location+message; -} - -string ProgramParser::format_syntax_error(const std::string &expected) -{ - return format_error(format("Syntax error at '%s': expected %s", last_token, expected)); -} - -const string &ProgramParser::peek_token(unsigned index) -{ - while(next_tokens.size()<=index) - next_tokens.push_back(parse_token_()); - return (last_token = next_tokens[index]); -} - -const string &ProgramParser::parse_token() -{ - if(!next_tokens.empty()) - { - last_token = next_tokens.front(); - next_tokens.pop_front(); - return last_token; - } - - return (last_token = parse_token_()); -} - -string ProgramParser::parse_token_() -{ - while(1) - { - skip_comment_and_whitespace(); - if(iter==source_end) - return string(); - else if(allow_preprocess && *iter=='#') - { - allow_preprocess = false; - SetForScope > clear_tokens(next_tokens, deque()); - preprocess(); - } - else if(isalpha(*iter) || *iter=='_') - return parse_identifier(); - else if(isdigit(*iter)) - return parse_number(); - else - return parse_other(); - } -} - -string ProgramParser::parse_identifier() -{ - string ident; - while(iter!=source_end) - { - if(isalnum(*iter) || *iter=='_') - ident += *iter++; - else - break; - } - - return ident; -} - -string ProgramParser::parse_number() -{ - bool accept_sign = false; - string number; - while(iter!=source_end) - { - if(isdigit(*iter) || *iter=='.') - number += *iter++; - else if(*iter=='e' || *iter=='E') - { - number += *iter++; - accept_sign = true; - } - else if(accept_sign && (*iter=='+' || *iter=='-')) - number += *iter++; - else - break; - } - - return number; -} - -string ProgramParser::parse_other() -{ - if(iter==source_end) - return string(); - - string token(1, *iter++); - for(unsigned i=1; (i<3 && iter!=source_end); ++i) - { - bool matched = false; - for(const Operator *j=operators; (!matched && j->type); ++j) - { - matched = (j->token[i]==*iter); - for(unsigned k=0; (matched && ktoken[k]); ++k) - matched = (j->token[k]==token[k]); - } - - if(!matched) - break; - - token += *iter++; - } - - return token; -} - -void ProgramParser::skip_comment_and_whitespace() -{ - unsigned comment = 0; - while(iter!=source_end) - { - if(comment==0) - { - if(*iter=='/') - comment = 1; - else if(!isspace(*iter)) - break; - } - else if(comment==1) - { - if(*iter=='/') - comment = 2; - else if(*iter=='*') - comment = 3; - else - { - comment = 0; - --iter; - break; - } - } - else if(comment==2) - { - if(*iter=='\n') - comment = 0; - } - else if(comment==3 && *iter=='*') - comment = 4; - else if(comment==4) - { - if(*iter=='/') - comment = 0; - else if(*iter!='*') - comment = 3; - } - - if(*iter=='\n') - { - ++current_line; - allow_preprocess = (comment<3); - } - - ++iter; - } -} - -void ProgramParser::expect(const string &token) -{ - string parsed = parse_token(); - if(parsed!=token) - throw runtime_error(format_syntax_error(format("'%s'", token))); -} - -string ProgramParser::expect_type() -{ - string token = parse_token(); - if(!is_type(token)) - throw runtime_error(format_syntax_error("a type")); - return token; -} - -string ProgramParser::expect_identifier() -{ - string token = parse_token(); - if(!is_identifier(token)) - throw runtime_error(format_syntax_error("an identifier")); - return token; -} - -bool ProgramParser::check(const string &token) -{ - bool result = (peek_token()==token); - if(result) - parse_token(); - return result; -} - -bool ProgramParser::is_interface_qualifier(const string &token) -{ - return (token=="uniform" || token=="in" || token=="out"); -} - -bool ProgramParser::is_sampling_qualifier(const string &token) -{ - return (token=="centroid" || token=="sample"); -} - -bool ProgramParser::is_interpolation_qualifier(const string &token) -{ - return (token=="smooth" || token=="flat" || token=="noperspective"); -} - -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) || - is_interpolation_qualifier(token) || - is_precision_qualifier(token)); -} - -bool ProgramParser::is_builtin_type(const string &token) -{ - static Regex re("^(void|float|int|bool|[ib]?vec[234]|mat[234](x[234])?|sampler((1D|2D|Cube)(Array)?(Shadow)?|3D))$"); - return re.match(token); -} - -bool ProgramParser::is_type(const string &token) -{ - return is_builtin_type(token) || declared_types.count(token); -} - -bool ProgramParser::is_identifier(const string &token) -{ - static Regex re("^[a-zA-Z_][a-zA-Z0-9_]*$"); - return re.match(token); -} - -void ProgramParser::preprocess() -{ - expect("#"); - - string::const_iterator line_end = iter; - for(; (line_end!=source_end && *line_end!='\n'); ++line_end) ; - SetForScope stop_at_line_end(source_end, line_end); - - string token = peek_token(); - if(token=="pragma") - preprocess_pragma(); - else if(token=="version") - preprocess_version(); - else if(token=="define" || token=="undef" || token=="if" || token=="ifdef" || token=="ifndef" || token=="else" || - token=="elif" || token=="endif" || token=="error" || token=="extension" || token=="line") - throw runtime_error(format_error(format("Unsupported preprocessor directive '%s'", token))); - else if(!token.empty()) - throw runtime_error(format_syntax_error("a preprocessor directive")); - - iter = line_end; -} - -void ProgramParser::preprocess_version() -{ - expect("version"); - string token = parse_token(); - unsigned version = lexical_cast(token); - cur_stage->required_version = Version(version/100, version%100); - - token = parse_token(); - if(!token.empty()) - throw runtime_error(format_syntax_error("end of line")); -} - -void ProgramParser::preprocess_pragma() -{ - expect("pragma"); - string token = parse_token(); - if(token=="MSP") - preprocess_pragma_msp(); -} - -void ProgramParser::preprocess_pragma_msp() -{ - string token = peek_token(); - if(token=="stage") - preprocess_stage(); - else - throw runtime_error(format_error(format("Unrecognized MSP pragma '%s'", token))); - - token = parse_token(); - if(!token.empty()) - throw runtime_error(format_syntax_error("end of line")); -} - -void ProgramParser::preprocess_stage() -{ - if(!allow_stage_change) - throw runtime_error(format_error("Changing stage not allowed here")); - - expect("stage"); - expect("("); - string token = expect_identifier(); - StageType stage = SHARED; - if(token=="vertex") - stage = VERTEX; - else if(token=="geometry") - stage = GEOMETRY; - else if(token=="fragment") - stage = FRAGMENT; - else - throw runtime_error(format_syntax_error("stage identifier")); - expect(")"); - - if(stage<=cur_stage->type) - throw runtime_error(format_error(format("Stage '%s' not allowed here", token))); - - module->stages.push_back(stage); - - if(cur_stage->type!=SHARED) - module->stages.back().previous = cur_stage; - cur_stage = &module->stages.back(); -} - -RefPtr ProgramParser::parse_global_declaration() -{ - allow_stage_change = true; - string token = peek_token(); - allow_stage_change = false; - - if(token=="import") - return parse_import(); - else if(token=="precision") - return parse_precision(); - else if(token=="layout") - { - RefPtr layout = parse_layout(); - token = peek_token(); - if(is_interface_qualifier(token) && peek_token(1)==";") - { - RefPtr iface_lo = new InterfaceLayout; - iface_lo->source = source_index; - iface_lo->line = current_line; - iface_lo->layout.qualifiers = layout->qualifiers; - iface_lo->interface = parse_token(); - expect(";"); - return iface_lo; - } - else - { - RefPtr var = parse_variable_declaration(); - var->layout = layout; - return var; - } - } - else if(token=="struct") - return parse_struct_declaration(); - else if(is_interface_qualifier(token)) - { - string next = peek_token(1); - if(is_type(next) || is_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)=="(") - return parse_function_declaration(); - else - return parse_variable_declaration(); - } - else if(token.empty()) - return 0; - else - throw runtime_error(format_syntax_error("a global declaration")); -} - -RefPtr ProgramParser::parse_statement() -{ - string token = peek_token(); - if(token=="if") - return parse_conditional(); - else if(token=="for") - return parse_for(); - else if(token=="while") - return parse_while(); - else if(token=="passthrough") - return parse_passthrough(); - else if(token=="return") - return parse_return(); - else if(token=="break" || token=="continue" || token=="discard") - { - RefPtr jump = new Jump; - jump->source = source_index; - jump->line = current_line; - jump->keyword = parse_token(); - expect(";"); - - return jump; - } - else if(is_qualifier(token) || is_type(token)) - return parse_variable_declaration(); - else if(!token.empty()) - { - RefPtr expr = new ExpressionStatement; - expr->source = source_index; - expr->line = current_line; - expr->expression = parse_expression(); - expect(";"); - - return expr; - } - else - throw runtime_error(format_syntax_error("a statement")); -} - -RefPtr ProgramParser::parse_import() -{ - if(cur_stage->type!=SHARED) - throw runtime_error(format_error("Imports are only allowed in the shared section")); - - expect("import"); - RefPtr import = new Import; - import->source = source_index; - import->line = current_line; - import->module = expect_identifier(); - expect(";"); - return import; -} - -RefPtr ProgramParser::parse_precision() -{ - expect("precision"); - RefPtr precision = new Precision; - precision->source = source_index; - precision->line = current_line; - - precision->precision = parse_token(); - if(!is_precision_qualifier(precision->precision)) - throw runtime_error(format_syntax_error("a precision qualifier")); - - 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_syntax_error("a builtin type")); - - expect(";"); - - return precision; -} - -RefPtr ProgramParser::parse_layout() -{ - expect("layout"); - expect("("); - RefPtr layout = new Layout; - while(1) - { - string token = parse_token(); - if(token==")") - throw runtime_error(format_syntax_error("a layout qualifier name")); - - layout->qualifiers.push_back(Layout::Qualifier()); - Layout::Qualifier &qual = layout->qualifiers.back(); - qual.identifier = token; - - if(check("=")) - qual.value = parse_token(); - - if(peek_token()==")") - break; - - expect(","); - } - expect(")"); - - return layout; -} - -void ProgramParser::parse_block(Block &block, bool require_braces) -{ - bool have_braces = (require_braces || peek_token()=="{"); - if(have_braces) - expect("{"); - - if(have_braces) - { - while(peek_token()!="}") - block.body.push_back(parse_statement()); - } - else - block.body.push_back(parse_statement()); - - block.use_braces = (require_braces || block.body.size()!=1); - - if(have_braces) - expect("}"); -} - -RefPtr ProgramParser::parse_expression(unsigned precedence) -{ - RefPtr left; - VariableReference *left_var = 0; - while(1) - { - string token = peek_token(); - - const Operator *oper = 0; - for(Operator *i=operators; (!oper && i->type); ++i) - if(token==i->token && (!left || i->type!=PREFIX) && (left || i->type!=POSTFIX)) - oper = i; - - if(token==";" || token==")" || token=="]" || token=="," || (oper && precedence && oper->precedence>=precedence)) - { - if(left) - return left; - else - throw runtime_error(format_syntax_error("an expression")); - } - else if(left) - { - if(token=="(") - { - if(!left_var) - throw runtime_error(format_error("Syntax error before '(': function name must be an identifier")); - left = parse_function_call(*left_var); - } - else if(token==".") - { - RefPtr memacc = new MemberAccess; - memacc->left = left; - parse_token(); - memacc->member = expect_identifier(); - left = memacc; - } - else if(oper && oper->type==POSTFIX) - { - RefPtr unary = new UnaryExpression; - unary->oper = parse_token(); - unary->prefix = false; - unary->expression = left; - left = unary; - } - else if(oper && oper->type==BINARY) - left = parse_binary(left, oper); - else - throw runtime_error(format_syntax_error("an operator")); - left_var = 0; - } - else - { - if(token=="(") - { - parse_token(); - RefPtr parexpr = new ParenthesizedExpression; - parexpr->expression = parse_expression(); - expect(")"); - left = parexpr; - } - else if(isdigit(token[0]) || token=="true" || token=="false") - { - RefPtr literal = new Literal; - literal->token = parse_token(); - left = literal; - } - else if(is_identifier(token)) - { - RefPtr var = new VariableReference; - var->name = expect_identifier(); - left = var; - left_var = var.get(); - } - else if(oper && oper->type==PREFIX) - { - RefPtr unary = new UnaryExpression; - unary->oper = parse_token(); - unary->prefix = true; - unary->expression = parse_expression(oper->precedence); - left = unary; - } - else - throw runtime_error(format_syntax_error("an expression")); - } - } -} - -RefPtr ProgramParser::parse_binary(const RefPtr &left, const Operator *oper) -{ - RefPtr binary = (oper->precedence==16 ? new Assignment : new BinaryExpression); - binary->left = left; - binary->oper = parse_token(); - if(binary->oper=="[") - { - binary->right = parse_expression(); - expect("]"); - binary->after = "]"; - } - else - binary->right = parse_expression(oper->precedence+(oper->assoc==RIGHT_TO_LEFT)); - return binary; -} - -RefPtr ProgramParser::parse_function_call(const VariableReference &var) -{ - RefPtr call = new FunctionCall; - call->name = var.name; - call->constructor = is_type(call->name); - expect("("); - while(peek_token()!=")") - { - if(!call->arguments.empty()) - expect(","); - call->arguments.push_back(parse_expression()); - } - expect(")"); - return call; -} - -RefPtr ProgramParser::parse_struct_declaration() -{ - expect("struct"); - RefPtr strct = new StructDeclaration; - strct->source = source_index; - strct->line = current_line; - - strct->name = expect_identifier(); - parse_block(strct->members, true); - expect(";"); - - declared_types.insert(strct->name); - return strct; -} - -RefPtr ProgramParser::parse_variable_declaration() -{ - RefPtr var = new VariableDeclaration; - var->source = source_index; - var->line = current_line; - - string token = peek_token(); - while(is_qualifier(token)) - { - parse_token(); - if(is_interface_qualifier(token)) - var->interface = token; - else if(is_sampling_qualifier(token)) - var->sampling = token; - else if(is_interpolation_qualifier(token)) - var->interpolation = token; - else if(is_precision_qualifier(token)) - var->precision = token; - else if(token=="const") - var->constant = true; - token = peek_token(); - } - - var->type = expect_type(); - var->name = expect_identifier(); - - if(check("[")) - { - var->array = true; - if(!check("]")) - { - var->array_size = parse_expression(); - expect("]"); - } - } - - if(check("=")) - var->init_expression = parse_expression(); - - expect(";"); - return var; -} - -RefPtr ProgramParser::parse_function_declaration() -{ - RefPtr func = new FunctionDeclaration; - func->source = source_index; - func->line = current_line; - - func->return_type = expect_type(); - func->name = expect_identifier(); - expect("("); - while(peek_token()!=")") - { - if(!func->parameters.empty()) - expect(","); - - RefPtr var = new VariableDeclaration; - string token = peek_token(); - if(token=="in" || token=="out" || token=="inout") - var->interface = parse_token(); - var->type = expect_type(); - var->name = expect_identifier(); - func->parameters.push_back(var); - } - expect(")"); - - string token = peek_token(); - if(token=="{") - { - func->definition = func.get(); - parse_block(func->body, true); - } - else if(token==";") - parse_token(); - else - throw runtime_error(format_syntax_error("'{' or ';'")); - - return func; -} - -RefPtr ProgramParser::parse_interface_block() -{ - RefPtr iface = new InterfaceBlock; - iface->source = source_index; - iface->line = current_line; - - iface->interface = parse_token(); - if(!is_interface_qualifier(iface->interface)) - throw runtime_error(format_syntax_error("an interface qualifier")); - - iface->name = expect_identifier(); - parse_block(iface->members, true); - if(!check(";")) - { - iface->instance_name = expect_identifier(); - if(check("[")) - { - iface->array = true; - expect("]"); - } - expect(";"); - } - - return iface; -} - -RefPtr ProgramParser::parse_conditional() -{ - expect("if"); - RefPtr cond = new Conditional; - cond->source = source_index; - cond->line = current_line; - expect("("); - cond->condition = parse_expression(); - expect(")"); - - parse_block(cond->body, false); - - string token = peek_token(); - if(token=="else") - { - parse_token(); - parse_block(cond->else_body, false); - } - - return cond; -} - -RefPtr ProgramParser::parse_for() -{ - expect("for"); - RefPtr loop = new Iteration; - loop->source = source_index; - loop->line = current_line; - expect("("); - string token = peek_token(); - if(is_type(token)) - loop->init_statement = parse_statement(); - else - { - if(token!=";") - { - RefPtr expr = new ExpressionStatement; - expr->expression = parse_expression(); - loop->init_statement = expr; - } - expect(";"); - } - if(peek_token()!=";") - loop->condition = parse_expression(); - expect(";"); - if(peek_token()!=")") - loop->loop_expression = parse_expression(); - expect(")"); - - parse_block(loop->body, false); - - return loop; -} - -RefPtr ProgramParser::parse_while() -{ - expect("while"); - RefPtr loop = new Iteration; - loop->source = source_index; - loop->line = current_line; - expect("("); - loop->condition = parse_expression(); - expect(")"); - - parse_block(loop->body, false); - - return loop; -} - -RefPtr ProgramParser::parse_passthrough() -{ - expect("passthrough"); - RefPtr pass = new Passthrough; - pass->source = source_index; - pass->line = current_line; - if(cur_stage->type==GEOMETRY) - { - expect("["); - pass->subscript = parse_expression(); - expect("]"); - } - expect(";"); - return pass; -} - -RefPtr ProgramParser::parse_return() -{ - expect("return"); - RefPtr ret = new Return; - ret->source = source_index; - ret->line = current_line; - if(peek_token()!=";") - ret->expression = parse_expression(); - expect(";"); - return ret; -} - -} // namespace GL -} // namespace Msp diff --git a/source/glsl/programparser.h b/source/glsl/programparser.h deleted file mode 100644 index e3660473..00000000 --- a/source/glsl/programparser.h +++ /dev/null @@ -1,118 +0,0 @@ -#ifndef MSP_GL_PROGRAMPARSER_H_ -#define MSP_GL_PROGRAMPARSER_H_ - -#include -#include -#include -#include -#include -#include "programsyntax.h" - -namespace Msp { -namespace GL { - -class ProgramParser -{ -private: - enum OperatorType - { - NO_OPERATOR, - BINARY, - PREFIX, - POSTFIX - }; - - enum Associativity - { - LEFT_TO_RIGHT, - RIGHT_TO_LEFT - }; - - struct Operator - { - const char token[4]; - unsigned precedence; - OperatorType type; - Associativity assoc; - }; - - std::string source; - std::string source_name; - unsigned source_index; - unsigned current_line; - std::string::const_iterator iter; - std::string::const_iterator source_end; - bool allow_preprocess; - bool allow_stage_change; - std::string last_token; - std::deque next_tokens; - ProgramSyntax::Module *module; - ProgramSyntax::Stage *cur_stage; - std::set declared_types; - - static Operator operators[]; - -public: - ProgramParser(); - ~ProgramParser(); - - ProgramSyntax::Module &parse(const std::string &, const std::string &, unsigned = 0); - ProgramSyntax::Module &parse(IO::Base &, const std::string &, unsigned = 0); - -private: - void parse_source(); - - std::string format_error(const std::string &); - std::string format_syntax_error(const std::string &); - - const std::string &peek_token(unsigned = 0); - const std::string &parse_token(); - std::string parse_token_(); - std::string parse_identifier(); - std::string parse_number(); - std::string parse_other(); - void skip_comment_and_whitespace(); - void expect(const std::string &); - std::string expect_type(); - std::string expect_identifier(); - bool check(const std::string &); - - static bool is_interface_qualifier(const std::string &); - static bool is_sampling_qualifier(const std::string &); - static bool is_interpolation_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 &); - bool is_identifier(const std::string &); - - void preprocess(); - void preprocess_version(); - void preprocess_pragma(); - void preprocess_pragma_msp(); - void preprocess_stage(); - - 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); - RefPtr parse_binary(const RefPtr &, const Operator *); - RefPtr parse_function_call(const ProgramSyntax::VariableReference &); - RefPtr parse_struct_declaration(); - RefPtr parse_variable_declaration(); - RefPtr parse_function_declaration(); - RefPtr parse_interface_block(); - RefPtr parse_conditional(); - RefPtr parse_for(); - RefPtr parse_while(); - RefPtr parse_passthrough(); - RefPtr parse_return(); -}; - -} // namespace GL -} // namespace Msp - -#endif diff --git a/source/glsl/programsyntax.cpp b/source/glsl/programsyntax.cpp deleted file mode 100644 index 6dea029f..00000000 --- a/source/glsl/programsyntax.cpp +++ /dev/null @@ -1,333 +0,0 @@ -#include "programsyntax.h" - -using namespace std; - -namespace Msp { -namespace GL { -namespace ProgramSyntax { - -template -NodeContainer::NodeContainer(const NodeContainer &c): - C(c) -{ - for(typename C::iterator i=this->begin(); i!=this->end(); ++i) - *i = (*i)->clone(); -} - - -Statement::Statement(): - source(0), - line(1) -{ } - - -Block::Block(): - use_braces(false) -{ } - -void Block::visit(NodeVisitor &visitor) -{ - visitor.visit(*this); -} - - -void Literal::visit(NodeVisitor &visitor) -{ - visitor.visit(*this); -} - - -void ParenthesizedExpression::visit(NodeVisitor &visitor) -{ - visitor.visit(*this); -} - - -VariableReference::VariableReference(): - declaration(0) -{ } - -void VariableReference::visit(NodeVisitor &visitor) -{ - visitor.visit(*this); -} - - -void MemberAccess::visit(NodeVisitor &visitor) -{ - visitor.visit(*this); -} - - -UnaryExpression::UnaryExpression(): - prefix(true) -{ } - -void UnaryExpression::visit(NodeVisitor &visitor) -{ - visitor.visit(*this); -} - - -void BinaryExpression::visit(NodeVisitor &visitor) -{ - visitor.visit(*this); -} - - -Assignment::Assignment(): - self_referencing(false), - target_declaration(0) -{ } - -void Assignment::visit(NodeVisitor &visitor) -{ - visitor.visit(*this); -} - - -FunctionCall::FunctionCall(): - declaration(0), - constructor(false) -{ } - -void FunctionCall::visit(NodeVisitor &visitor) -{ - visitor.visit(*this); -} - - -void ExpressionStatement::visit(NodeVisitor &visitor) -{ - visitor.visit(*this); -} - - -void Import::visit(NodeVisitor &visitor) -{ - visitor.visit(*this); -} - - -void Precision::visit(NodeVisitor &visitor) -{ - visitor.visit(*this); -} - - -void Layout::visit(NodeVisitor &visitor) -{ - visitor.visit(*this); -} - - -void InterfaceLayout::visit(NodeVisitor &visitor) -{ - visitor.visit(*this); -} - - -StructDeclaration::StructDeclaration() -{ - members.use_braces = true; -} - -void StructDeclaration::visit(NodeVisitor &visitor) -{ - visitor.visit(*this); -} - - -VariableDeclaration::VariableDeclaration(): - constant(false), - type_declaration(0), - array(false), - linked_declaration(0) -{ } - -void VariableDeclaration::visit(NodeVisitor &visitor) -{ - visitor.visit(*this); -} - - -InterfaceBlock::InterfaceBlock(): - array(false) -{ - members.use_braces = true; -} - -void InterfaceBlock::visit(NodeVisitor &visitor) -{ - visitor.visit(*this); -} - - -FunctionDeclaration::FunctionDeclaration(): - definition(0) -{ } - -FunctionDeclaration::FunctionDeclaration(const FunctionDeclaration &other): - return_type(other.return_type), - name(other.name), - parameters(other.parameters), - definition(other.definition==&other ? this : other.definition), - body(other.body) -{ } - -void FunctionDeclaration::visit(NodeVisitor &visitor) -{ - visitor.visit(*this); -} - - -void Conditional::visit(NodeVisitor &visitor) -{ - visitor.visit(*this); -} - - -void Iteration::visit(NodeVisitor &visitor) -{ - visitor.visit(*this); -} - - -void Passthrough::visit(NodeVisitor &visitor) -{ - visitor.visit(*this); -} - - -void Return::visit(NodeVisitor &visitor) -{ - visitor.visit(*this); -} - - -void Jump::visit(NodeVisitor &visitor) -{ - visitor.visit(*this); -} - - -void NodeVisitor::visit(Assignment &assign) -{ - visit(static_cast(assign)); -} - - -void TraversingVisitor::visit(Block &block) -{ - for(NodeList::iterator i=block.body.begin(); i!=block.body.end(); ++i) - (*i)->visit(*this); -} - -void TraversingVisitor::visit(ParenthesizedExpression &parexpr) -{ - parexpr.expression->visit(*this); -} - -void TraversingVisitor::visit(MemberAccess &memacc) -{ - memacc.left->visit(*this); -} - -void TraversingVisitor::visit(UnaryExpression &unary) -{ - unary.expression->visit(*this); -} - -void TraversingVisitor::visit(BinaryExpression &binary) -{ - binary.left->visit(*this); - binary.right->visit(*this); -} - -void TraversingVisitor::visit(FunctionCall &call) -{ - for(NodeArray::iterator i=call.arguments.begin(); i!=call.arguments.end(); ++i) - (*i)->visit(*this); -} - -void TraversingVisitor::visit(ExpressionStatement &expr) -{ - expr.expression->visit(*this); -} - -void TraversingVisitor::visit(InterfaceLayout &layout) -{ - layout.layout.visit(*this); -} - -void TraversingVisitor::visit(StructDeclaration &strct) -{ - strct.members.visit(*this); -} - -void TraversingVisitor::visit(VariableDeclaration &var) -{ - if(var.layout) - var.layout->visit(*this); - if(var.init_expression) - var.init_expression->visit(*this); - if(var.array_size) - var.array_size->visit(*this); -} - -void TraversingVisitor::visit(InterfaceBlock &iface) -{ - iface.members.visit(*this); -} - -void TraversingVisitor::visit(FunctionDeclaration &func) -{ - for(NodeArray::iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i) - (*i)->visit(*this); - func.body.visit(*this); -} - -void TraversingVisitor::visit(Conditional &cond) -{ - cond.condition->visit(*this); - cond.body.visit(*this); - cond.else_body.visit(*this); -} - -void TraversingVisitor::visit(Iteration &iter) -{ - if(iter.init_statement) - iter.init_statement->visit(*this); - if(iter.condition) - iter.condition->visit(*this); - if(iter.loop_expression) - iter.loop_expression->visit(*this); - iter.body.visit(*this); -} - -void TraversingVisitor::visit(Passthrough &pass) -{ - if(pass.subscript) - pass.subscript->visit(*this); -} - -void TraversingVisitor::visit(Return &ret) -{ - if(ret.expression) - ret.expression->visit(*this); -} - - -Stage::Stage(StageType t): - type(t), - previous(0) -{ } - - -Module::Module(): - shared(SHARED) -{ } - -} // namespace ProgramSyntax -} // namespace GL -} // namespace Msp diff --git a/source/glsl/programsyntax.h b/source/glsl/programsyntax.h deleted file mode 100644 index e7b5111e..00000000 --- a/source/glsl/programsyntax.h +++ /dev/null @@ -1,425 +0,0 @@ -#ifndef MSP_GL_PROGRAMSYNTAX_H_ -#define MSP_GL_PROGRAMSYNTAX_H_ - -#include -#include -#include -#include -#include -#include "extension.h" -#include "uniform.h" - -#pragma push_macro("interface") -#undef interface - -namespace Msp { -namespace GL { -namespace ProgramSyntax { - -struct NodeVisitor; - -struct Node -{ -protected: - Node() { } - Node(const Node &) { } -private: - Node &operator=(const Node &); -public: - virtual ~Node() { } - - virtual Node *clone() const = 0; - virtual void visit(NodeVisitor &) = 0; -}; - -template -class NodePtr: public RefPtr -{ -public: - NodePtr() { } - NodePtr(T *p): RefPtr(p) { } - NodePtr(const NodePtr &p): RefPtr(p ? p->clone() : 0) { } - NodePtr &operator=(const NodePtr &p) { RefPtr::operator=(p); return *this; } - - template - NodePtr(const RefPtr &p): RefPtr(p) { } - - template - NodePtr(const NodePtr &p): RefPtr(p ? p->clone() : 0) { } -}; - -template -class NodeContainer: public C -{ -public: - NodeContainer() { } - NodeContainer(const NodeContainer &); -}; - -template -class NodeList: public NodeContainer > > -{ }; - -template -class NodeArray: public NodeContainer > > -{ }; - -struct StructDeclaration; -struct VariableDeclaration; -struct FunctionDeclaration; - -struct Statement: Node -{ - unsigned source; - unsigned line; - - Statement(); - - virtual Statement *clone() const = 0; -}; - -struct Block: Node -{ - NodeList body; - bool use_braces; - std::map types; - std::map variables; - - Block(); - - virtual Block *clone() const { return new Block(*this); } - virtual void visit(NodeVisitor &); -}; - -struct Expression: Node -{ - virtual Expression *clone() const = 0; -}; - -struct Literal: Expression -{ - std::string token; - - virtual Literal *clone() const { return new Literal(*this); } - virtual void visit(NodeVisitor &); -}; - -struct ParenthesizedExpression: Expression -{ - NodePtr expression; - - virtual ParenthesizedExpression *clone() const { return new ParenthesizedExpression(*this); } - virtual void visit(NodeVisitor &); -}; - -struct VariableReference: Expression -{ - std::string name; - VariableDeclaration *declaration; - - VariableReference(); - - virtual VariableReference *clone() const { return new VariableReference(*this); } - virtual void visit(NodeVisitor &); -}; - -struct MemberAccess: Expression -{ - NodePtr left; - std::string member; - VariableDeclaration *declaration; - - virtual MemberAccess *clone() const { return new MemberAccess(*this); } - virtual void visit(NodeVisitor &); -}; - -struct UnaryExpression: Expression -{ - std::string oper; - NodePtr expression; - bool prefix; - - UnaryExpression(); - - virtual UnaryExpression *clone() const { return new UnaryExpression(*this); } - virtual void visit(NodeVisitor &); -}; - -struct BinaryExpression: Expression -{ - NodePtr left; - std::string oper; - NodePtr right; - std::string after; - - virtual BinaryExpression *clone() const { return new BinaryExpression(*this); } - virtual void visit(NodeVisitor &); -}; - -struct Assignment: BinaryExpression -{ - bool self_referencing; - VariableDeclaration *target_declaration; - - Assignment(); - - virtual Assignment *clone() const { return new Assignment(*this); } - virtual void visit(NodeVisitor &); -}; - -struct FunctionCall: Expression -{ - std::string name; - FunctionDeclaration *declaration; - bool constructor; - NodeArray arguments; - - FunctionCall(); - - virtual FunctionCall *clone() const { return new FunctionCall(*this); } - virtual void visit(NodeVisitor &); -}; - -struct ExpressionStatement: Statement -{ - NodePtr expression; - - virtual ExpressionStatement *clone() const { return new ExpressionStatement(*this); } - virtual void visit(NodeVisitor &); -}; - -struct Import: Statement -{ - std::string module; - - virtual Import *clone() const { return new Import(*this); } - virtual void visit(NodeVisitor &); -}; - -struct Precision: Statement -{ - std::string precision; - std::string type; - - virtual Precision *clone() const { return new Precision(*this); } - virtual void visit(NodeVisitor &); -}; - -struct Layout: Node -{ - struct Qualifier - { - // TODO the standard calls this name, not identifier - std::string identifier; - std::string value; - }; - - std::vector qualifiers; - - virtual Layout *clone() const { return new Layout(*this); } - virtual void visit(NodeVisitor &); -}; - -struct InterfaceLayout: Statement -{ - std::string interface; - Layout layout; - - virtual InterfaceLayout *clone() const { return new InterfaceLayout(*this); } - virtual void visit(NodeVisitor &); -}; - -struct StructDeclaration: Statement -{ - std::string name; - Block members; - - StructDeclaration(); - - virtual StructDeclaration *clone() const { return new StructDeclaration(*this); } - virtual void visit(NodeVisitor &); -}; - -struct VariableDeclaration: Statement -{ - bool constant; - std::string sampling; - std::string interpolation; - std::string interface; - std::string precision; - std::string type; - StructDeclaration *type_declaration; - std::string name; - bool array; - NodePtr array_size; - NodePtr init_expression; - VariableDeclaration *linked_declaration; - NodePtr layout; - - VariableDeclaration(); - - virtual VariableDeclaration *clone() const { return new VariableDeclaration(*this); } - virtual void visit(NodeVisitor &); -}; - -struct InterfaceBlock: Statement -{ - std::string interface; - std::string name; - Block members; - std::string instance_name; - bool array; - - InterfaceBlock(); - - virtual InterfaceBlock *clone() const { return new InterfaceBlock(*this); } - virtual void visit(NodeVisitor &); -}; - -struct FunctionDeclaration: Statement -{ - std::string return_type; - std::string name; - NodeArray parameters; - FunctionDeclaration *definition; - Block body; - - FunctionDeclaration(); - FunctionDeclaration(const FunctionDeclaration &); - - virtual FunctionDeclaration *clone() const { return new FunctionDeclaration(*this); } - virtual void visit(NodeVisitor &); -}; - -struct Conditional: Statement -{ - NodePtr condition; - Block body; - Block else_body; - - virtual Conditional *clone() const { return new Conditional(*this); } - virtual void visit(NodeVisitor &); -}; - -struct Iteration: Statement -{ - NodePtr init_statement; - NodePtr condition; - NodePtr loop_expression; - Block body; - - virtual Iteration *clone() const { return new Iteration(*this); } - virtual void visit(NodeVisitor &); -}; - -struct Passthrough: Statement -{ - NodePtr subscript; - - virtual Passthrough *clone() const { return new Passthrough(*this); } - virtual void visit(NodeVisitor &); -}; - -struct Return: Statement -{ - NodePtr expression; - - virtual Return *clone() const { return new Return(*this); } - virtual void visit(NodeVisitor &); -}; - -struct Jump: Statement -{ - std::string keyword; - - virtual Jump *clone() const { return new Jump(*this); } - virtual void visit(NodeVisitor &); -}; - -struct NodeVisitor -{ - virtual ~NodeVisitor() { } - - virtual void visit(Block &) { } - virtual void visit(Literal &) { } - virtual void visit(ParenthesizedExpression &) { } - virtual void visit(VariableReference &) { } - virtual void visit(MemberAccess &) { } - virtual void visit(UnaryExpression &) { } - virtual void visit(BinaryExpression &) { } - virtual void visit(Assignment &); - 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 &) { } - virtual void visit(VariableDeclaration &) { } - virtual void visit(InterfaceBlock &) { } - virtual void visit(FunctionDeclaration &) { } - virtual void visit(Conditional &) { } - virtual void visit(Iteration &) { } - virtual void visit(Passthrough &) { } - virtual void visit(Return &) { } - virtual void visit(Jump &) { } -}; - -struct TraversingVisitor: NodeVisitor -{ - using NodeVisitor::visit; - virtual void visit(Block &); - virtual void visit(ParenthesizedExpression &); - virtual void visit(MemberAccess &); - virtual void visit(UnaryExpression &); - virtual void visit(BinaryExpression &); - virtual void visit(FunctionCall &); - virtual void visit(ExpressionStatement &); - virtual void visit(InterfaceLayout &); - virtual void visit(StructDeclaration &); - virtual void visit(VariableDeclaration &); - virtual void visit(InterfaceBlock &); - virtual void visit(FunctionDeclaration &); - virtual void visit(Conditional &); - virtual void visit(Iteration &); - virtual void visit(Passthrough &); - virtual void visit(Return &); -}; - -enum StageType -{ - SHARED, - VERTEX, - GEOMETRY, - FRAGMENT -}; - -struct Stage -{ - StageType type; - Stage *previous; - ProgramSyntax::Block content; - std::map in_variables; - std::map out_variables; - std::map locations; - Version required_version; - std::vector required_extensions; - - Stage(StageType); -}; - -struct Module -{ - Stage shared; - std::list stages; - - Module(); -}; - -} // namespace ProgramSyntax -} // namespace GL -} // namespace Msp - -#pragma pop_macro("interface") - -#endif diff --git a/source/glsl/syntax.cpp b/source/glsl/syntax.cpp new file mode 100644 index 00000000..9705c989 --- /dev/null +++ b/source/glsl/syntax.cpp @@ -0,0 +1,333 @@ +#include "syntax.h" + +using namespace std; + +namespace Msp { +namespace GL { +namespace SL { + +template +NodeContainer::NodeContainer(const NodeContainer &c): + C(c) +{ + for(typename C::iterator i=this->begin(); i!=this->end(); ++i) + *i = (*i)->clone(); +} + + +Statement::Statement(): + source(0), + line(1) +{ } + + +Block::Block(): + use_braces(false) +{ } + +void Block::visit(NodeVisitor &visitor) +{ + visitor.visit(*this); +} + + +void Literal::visit(NodeVisitor &visitor) +{ + visitor.visit(*this); +} + + +void ParenthesizedExpression::visit(NodeVisitor &visitor) +{ + visitor.visit(*this); +} + + +VariableReference::VariableReference(): + declaration(0) +{ } + +void VariableReference::visit(NodeVisitor &visitor) +{ + visitor.visit(*this); +} + + +void MemberAccess::visit(NodeVisitor &visitor) +{ + visitor.visit(*this); +} + + +UnaryExpression::UnaryExpression(): + prefix(true) +{ } + +void UnaryExpression::visit(NodeVisitor &visitor) +{ + visitor.visit(*this); +} + + +void BinaryExpression::visit(NodeVisitor &visitor) +{ + visitor.visit(*this); +} + + +Assignment::Assignment(): + self_referencing(false), + target_declaration(0) +{ } + +void Assignment::visit(NodeVisitor &visitor) +{ + visitor.visit(*this); +} + + +FunctionCall::FunctionCall(): + declaration(0), + constructor(false) +{ } + +void FunctionCall::visit(NodeVisitor &visitor) +{ + visitor.visit(*this); +} + + +void ExpressionStatement::visit(NodeVisitor &visitor) +{ + visitor.visit(*this); +} + + +void Import::visit(NodeVisitor &visitor) +{ + visitor.visit(*this); +} + + +void Precision::visit(NodeVisitor &visitor) +{ + visitor.visit(*this); +} + + +void Layout::visit(NodeVisitor &visitor) +{ + visitor.visit(*this); +} + + +void InterfaceLayout::visit(NodeVisitor &visitor) +{ + visitor.visit(*this); +} + + +StructDeclaration::StructDeclaration() +{ + members.use_braces = true; +} + +void StructDeclaration::visit(NodeVisitor &visitor) +{ + visitor.visit(*this); +} + + +VariableDeclaration::VariableDeclaration(): + constant(false), + type_declaration(0), + array(false), + linked_declaration(0) +{ } + +void VariableDeclaration::visit(NodeVisitor &visitor) +{ + visitor.visit(*this); +} + + +InterfaceBlock::InterfaceBlock(): + array(false) +{ + members.use_braces = true; +} + +void InterfaceBlock::visit(NodeVisitor &visitor) +{ + visitor.visit(*this); +} + + +FunctionDeclaration::FunctionDeclaration(): + definition(0) +{ } + +FunctionDeclaration::FunctionDeclaration(const FunctionDeclaration &other): + return_type(other.return_type), + name(other.name), + parameters(other.parameters), + definition(other.definition==&other ? this : other.definition), + body(other.body) +{ } + +void FunctionDeclaration::visit(NodeVisitor &visitor) +{ + visitor.visit(*this); +} + + +void Conditional::visit(NodeVisitor &visitor) +{ + visitor.visit(*this); +} + + +void Iteration::visit(NodeVisitor &visitor) +{ + visitor.visit(*this); +} + + +void Passthrough::visit(NodeVisitor &visitor) +{ + visitor.visit(*this); +} + + +void Return::visit(NodeVisitor &visitor) +{ + visitor.visit(*this); +} + + +void Jump::visit(NodeVisitor &visitor) +{ + visitor.visit(*this); +} + + +void NodeVisitor::visit(Assignment &assign) +{ + visit(static_cast(assign)); +} + + +void TraversingVisitor::visit(Block &block) +{ + for(NodeList::iterator i=block.body.begin(); i!=block.body.end(); ++i) + (*i)->visit(*this); +} + +void TraversingVisitor::visit(ParenthesizedExpression &parexpr) +{ + parexpr.expression->visit(*this); +} + +void TraversingVisitor::visit(MemberAccess &memacc) +{ + memacc.left->visit(*this); +} + +void TraversingVisitor::visit(UnaryExpression &unary) +{ + unary.expression->visit(*this); +} + +void TraversingVisitor::visit(BinaryExpression &binary) +{ + binary.left->visit(*this); + binary.right->visit(*this); +} + +void TraversingVisitor::visit(FunctionCall &call) +{ + for(NodeArray::iterator i=call.arguments.begin(); i!=call.arguments.end(); ++i) + (*i)->visit(*this); +} + +void TraversingVisitor::visit(ExpressionStatement &expr) +{ + expr.expression->visit(*this); +} + +void TraversingVisitor::visit(InterfaceLayout &layout) +{ + layout.layout.visit(*this); +} + +void TraversingVisitor::visit(StructDeclaration &strct) +{ + strct.members.visit(*this); +} + +void TraversingVisitor::visit(VariableDeclaration &var) +{ + if(var.layout) + var.layout->visit(*this); + if(var.init_expression) + var.init_expression->visit(*this); + if(var.array_size) + var.array_size->visit(*this); +} + +void TraversingVisitor::visit(InterfaceBlock &iface) +{ + iface.members.visit(*this); +} + +void TraversingVisitor::visit(FunctionDeclaration &func) +{ + for(NodeArray::iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i) + (*i)->visit(*this); + func.body.visit(*this); +} + +void TraversingVisitor::visit(Conditional &cond) +{ + cond.condition->visit(*this); + cond.body.visit(*this); + cond.else_body.visit(*this); +} + +void TraversingVisitor::visit(Iteration &iter) +{ + if(iter.init_statement) + iter.init_statement->visit(*this); + if(iter.condition) + iter.condition->visit(*this); + if(iter.loop_expression) + iter.loop_expression->visit(*this); + iter.body.visit(*this); +} + +void TraversingVisitor::visit(Passthrough &pass) +{ + if(pass.subscript) + pass.subscript->visit(*this); +} + +void TraversingVisitor::visit(Return &ret) +{ + if(ret.expression) + ret.expression->visit(*this); +} + + +Stage::Stage(StageType t): + type(t), + previous(0) +{ } + + +Module::Module(): + shared(SHARED) +{ } + +} // namespace SL +} // namespace GL +} // namespace Msp diff --git a/source/glsl/syntax.h b/source/glsl/syntax.h new file mode 100644 index 00000000..a2630ef0 --- /dev/null +++ b/source/glsl/syntax.h @@ -0,0 +1,425 @@ +#ifndef MSP_GL_SL_SYNTAX_H_ +#define MSP_GL_SL_SYNTAX_H_ + +#include +#include +#include +#include +#include +#include "extension.h" +#include "uniform.h" + +#pragma push_macro("interface") +#undef interface + +namespace Msp { +namespace GL { +namespace SL { + +struct NodeVisitor; + +struct Node +{ +protected: + Node() { } + Node(const Node &) { } +private: + Node &operator=(const Node &); +public: + virtual ~Node() { } + + virtual Node *clone() const = 0; + virtual void visit(NodeVisitor &) = 0; +}; + +template +class NodePtr: public RefPtr +{ +public: + NodePtr() { } + NodePtr(T *p): RefPtr(p) { } + NodePtr(const NodePtr &p): RefPtr(p ? p->clone() : 0) { } + NodePtr &operator=(const NodePtr &p) { RefPtr::operator=(p); return *this; } + + template + NodePtr(const RefPtr &p): RefPtr(p) { } + + template + NodePtr(const NodePtr &p): RefPtr(p ? p->clone() : 0) { } +}; + +template +class NodeContainer: public C +{ +public: + NodeContainer() { } + NodeContainer(const NodeContainer &); +}; + +template +class NodeList: public NodeContainer > > +{ }; + +template +class NodeArray: public NodeContainer > > +{ }; + +struct StructDeclaration; +struct VariableDeclaration; +struct FunctionDeclaration; + +struct Statement: Node +{ + unsigned source; + unsigned line; + + Statement(); + + virtual Statement *clone() const = 0; +}; + +struct Block: Node +{ + NodeList body; + bool use_braces; + std::map types; + std::map variables; + + Block(); + + virtual Block *clone() const { return new Block(*this); } + virtual void visit(NodeVisitor &); +}; + +struct Expression: Node +{ + virtual Expression *clone() const = 0; +}; + +struct Literal: Expression +{ + std::string token; + + virtual Literal *clone() const { return new Literal(*this); } + virtual void visit(NodeVisitor &); +}; + +struct ParenthesizedExpression: Expression +{ + NodePtr expression; + + virtual ParenthesizedExpression *clone() const { return new ParenthesizedExpression(*this); } + virtual void visit(NodeVisitor &); +}; + +struct VariableReference: Expression +{ + std::string name; + VariableDeclaration *declaration; + + VariableReference(); + + virtual VariableReference *clone() const { return new VariableReference(*this); } + virtual void visit(NodeVisitor &); +}; + +struct MemberAccess: Expression +{ + NodePtr left; + std::string member; + VariableDeclaration *declaration; + + virtual MemberAccess *clone() const { return new MemberAccess(*this); } + virtual void visit(NodeVisitor &); +}; + +struct UnaryExpression: Expression +{ + std::string oper; + NodePtr expression; + bool prefix; + + UnaryExpression(); + + virtual UnaryExpression *clone() const { return new UnaryExpression(*this); } + virtual void visit(NodeVisitor &); +}; + +struct BinaryExpression: Expression +{ + NodePtr left; + std::string oper; + NodePtr right; + std::string after; + + virtual BinaryExpression *clone() const { return new BinaryExpression(*this); } + virtual void visit(NodeVisitor &); +}; + +struct Assignment: BinaryExpression +{ + bool self_referencing; + VariableDeclaration *target_declaration; + + Assignment(); + + virtual Assignment *clone() const { return new Assignment(*this); } + virtual void visit(NodeVisitor &); +}; + +struct FunctionCall: Expression +{ + std::string name; + FunctionDeclaration *declaration; + bool constructor; + NodeArray arguments; + + FunctionCall(); + + virtual FunctionCall *clone() const { return new FunctionCall(*this); } + virtual void visit(NodeVisitor &); +}; + +struct ExpressionStatement: Statement +{ + NodePtr expression; + + virtual ExpressionStatement *clone() const { return new ExpressionStatement(*this); } + virtual void visit(NodeVisitor &); +}; + +struct Import: Statement +{ + std::string module; + + virtual Import *clone() const { return new Import(*this); } + virtual void visit(NodeVisitor &); +}; + +struct Precision: Statement +{ + std::string precision; + std::string type; + + virtual Precision *clone() const { return new Precision(*this); } + virtual void visit(NodeVisitor &); +}; + +struct Layout: Node +{ + struct Qualifier + { + // TODO the standard calls this name, not identifier + std::string identifier; + std::string value; + }; + + std::vector qualifiers; + + virtual Layout *clone() const { return new Layout(*this); } + virtual void visit(NodeVisitor &); +}; + +struct InterfaceLayout: Statement +{ + std::string interface; + Layout layout; + + virtual InterfaceLayout *clone() const { return new InterfaceLayout(*this); } + virtual void visit(NodeVisitor &); +}; + +struct StructDeclaration: Statement +{ + std::string name; + Block members; + + StructDeclaration(); + + virtual StructDeclaration *clone() const { return new StructDeclaration(*this); } + virtual void visit(NodeVisitor &); +}; + +struct VariableDeclaration: Statement +{ + bool constant; + std::string sampling; + std::string interpolation; + std::string interface; + std::string precision; + std::string type; + StructDeclaration *type_declaration; + std::string name; + bool array; + NodePtr array_size; + NodePtr init_expression; + VariableDeclaration *linked_declaration; + NodePtr layout; + + VariableDeclaration(); + + virtual VariableDeclaration *clone() const { return new VariableDeclaration(*this); } + virtual void visit(NodeVisitor &); +}; + +struct InterfaceBlock: Statement +{ + std::string interface; + std::string name; + Block members; + std::string instance_name; + bool array; + + InterfaceBlock(); + + virtual InterfaceBlock *clone() const { return new InterfaceBlock(*this); } + virtual void visit(NodeVisitor &); +}; + +struct FunctionDeclaration: Statement +{ + std::string return_type; + std::string name; + NodeArray parameters; + FunctionDeclaration *definition; + Block body; + + FunctionDeclaration(); + FunctionDeclaration(const FunctionDeclaration &); + + virtual FunctionDeclaration *clone() const { return new FunctionDeclaration(*this); } + virtual void visit(NodeVisitor &); +}; + +struct Conditional: Statement +{ + NodePtr condition; + Block body; + Block else_body; + + virtual Conditional *clone() const { return new Conditional(*this); } + virtual void visit(NodeVisitor &); +}; + +struct Iteration: Statement +{ + NodePtr init_statement; + NodePtr condition; + NodePtr loop_expression; + Block body; + + virtual Iteration *clone() const { return new Iteration(*this); } + virtual void visit(NodeVisitor &); +}; + +struct Passthrough: Statement +{ + NodePtr subscript; + + virtual Passthrough *clone() const { return new Passthrough(*this); } + virtual void visit(NodeVisitor &); +}; + +struct Return: Statement +{ + NodePtr expression; + + virtual Return *clone() const { return new Return(*this); } + virtual void visit(NodeVisitor &); +}; + +struct Jump: Statement +{ + std::string keyword; + + virtual Jump *clone() const { return new Jump(*this); } + virtual void visit(NodeVisitor &); +}; + +struct NodeVisitor +{ + virtual ~NodeVisitor() { } + + virtual void visit(Block &) { } + virtual void visit(Literal &) { } + virtual void visit(ParenthesizedExpression &) { } + virtual void visit(VariableReference &) { } + virtual void visit(MemberAccess &) { } + virtual void visit(UnaryExpression &) { } + virtual void visit(BinaryExpression &) { } + virtual void visit(Assignment &); + 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 &) { } + virtual void visit(VariableDeclaration &) { } + virtual void visit(InterfaceBlock &) { } + virtual void visit(FunctionDeclaration &) { } + virtual void visit(Conditional &) { } + virtual void visit(Iteration &) { } + virtual void visit(Passthrough &) { } + virtual void visit(Return &) { } + virtual void visit(Jump &) { } +}; + +struct TraversingVisitor: NodeVisitor +{ + using NodeVisitor::visit; + virtual void visit(Block &); + virtual void visit(ParenthesizedExpression &); + virtual void visit(MemberAccess &); + virtual void visit(UnaryExpression &); + virtual void visit(BinaryExpression &); + virtual void visit(FunctionCall &); + virtual void visit(ExpressionStatement &); + virtual void visit(InterfaceLayout &); + virtual void visit(StructDeclaration &); + virtual void visit(VariableDeclaration &); + virtual void visit(InterfaceBlock &); + virtual void visit(FunctionDeclaration &); + virtual void visit(Conditional &); + virtual void visit(Iteration &); + virtual void visit(Passthrough &); + virtual void visit(Return &); +}; + +enum StageType +{ + SHARED, + VERTEX, + GEOMETRY, + FRAGMENT +}; + +struct Stage +{ + StageType type; + Stage *previous; + Block content; + std::map in_variables; + std::map out_variables; + std::map locations; + Version required_version; + std::vector required_extensions; + + Stage(StageType); +}; + +struct Module +{ + Stage shared; + std::list stages; + + Module(); +}; + +} // namespace SL +} // namespace GL +} // namespace Msp + +#pragma pop_macro("interface") + +#endif diff --git a/source/resources/resources.cpp b/source/resources/resources.cpp index d52dbe34..11099ae0 100644 --- a/source/resources/resources.cpp +++ b/source/resources/resources.cpp @@ -12,7 +12,6 @@ #include "pipelinetemplate.h" #include "pose.h" #include "program.h" -#include "programcompiler.h" #include "resourcemanager.h" #include "resources.h" #include "sampler.h" @@ -21,6 +20,7 @@ #include "texture2d.h" #include "texture2darray.h" #include "texturecube.h" +#include "glsl/compiler.h" using namespace std; @@ -172,7 +172,7 @@ Program *Resources::create_program(const string &name) if(RefPtr io = open_raw(name)) { - ProgramCompiler compiler; + SL::Compiler compiler; compiler.compile(*io, this, name); RefPtr program = new Program; compiler.add_shaders(*program);