X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=blobdiff_plain;f=source%2Fprogramcompiler.cpp;h=f30ccfa6233ad6b6dc8115488210c7f1dbd4c7a5;hp=f7d231615618178cecbcaf68ecf49caa2ae5835b;hb=HEAD;hpb=02c1541c20adf36ea09825dc7bc745f8487c4bc8 diff --git a/source/programcompiler.cpp b/source/programcompiler.cpp deleted file mode 100644 index f7d23161..00000000 --- a/source/programcompiler.cpp +++ /dev/null @@ -1,776 +0,0 @@ -#include -#include -#include -#include "error.h" -#include "program.h" -#include "programcompiler.h" -#include "shader.h" - -using namespace std; - -namespace Msp { -namespace GL { - -using namespace ProgramSyntax; - -ProgramCompiler::ProgramCompiler(): - module(0) -{ } - -void ProgramCompiler::compile(const string &source) -{ - module = &parser.parse(source); - process(); -} - -void ProgramCompiler::compile(IO::Base &io) -{ - module = &parser.parse(io); - process(); -} - -void ProgramCompiler::add_shaders(Program &program) -{ - if(!module) - throw invalid_operation("ProgramCompiler::add_shaders"); - - string head = "#version 150\n"; - for(list::iterator i=module->stages.begin(); i!=module->stages.end(); ++i) - { - if(i->type==VERTEX) - program.attach_shader_owned(new VertexShader(head+create_source(*i))); - else if(i->type==GEOMETRY) - program.attach_shader_owned(new GeometryShader(head+create_source(*i))); - else if(i->type==FRAGMENT) - program.attach_shader_owned(new FragmentShader(head+create_source(*i))); - } - - program.bind_attribute(VERTEX4, "vertex"); - program.bind_attribute(NORMAL3, "normal"); - program.bind_attribute(COLOR4_FLOAT, "color"); - program.bind_attribute(TEXCOORD4, "texcoord"); -} - -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; - } -} - -void ProgramCompiler::generate(Stage &stage) -{ - inject_block(stage.content, module->shared.content); - - apply(stage); - apply(stage); - apply(stage); - apply(stage); -} - -bool ProgramCompiler::optimize(Stage &stage) -{ - UnusedVariableLocator unused_locator; - unused_locator.apply(stage); - - NodeRemover remover; - remover.to_remove = unused_locator.unused_nodes; - remover.apply(stage); - - return !unused_locator.unused_nodes.empty(); -} - -void ProgramCompiler::inject_block(Block &target, const Block &source) -{ - list >::iterator insert_point = target.body.begin(); - for(list >::const_iterator i=source.body.begin(); i!=source.body.end(); ++i) - target.body.insert(insert_point, (*i)->clone()); -} - -template -void ProgramCompiler::apply(Stage &stage) -{ - T visitor; - visitor.apply(stage); -} - -string ProgramCompiler::create_source(Stage &stage) -{ - Formatter formatter; - formatter.apply(stage); - return formatter.formatted; -} - - -ProgramCompiler::Visitor::Visitor(): - stage(0) -{ } - -void ProgramCompiler::Visitor::apply(Stage &s) -{ - SetForScope set(stage, &s); - stage->content.visit(*this); -} - - -ProgramCompiler::Formatter::Formatter(): - indent(0), - parameter_list(false), - else_if(false) -{ } - -void ProgramCompiler::Formatter::visit(Literal &literal) -{ - formatted += literal.token; -} - -void ProgramCompiler::Formatter::visit(ParenthesizedExpression &parexpr) -{ - formatted += '('; - parexpr.expression->visit(*this); - formatted += ')'; -} - -void ProgramCompiler::Formatter::visit(VariableReference &var) -{ - formatted += var.name; -} - -void ProgramCompiler::Formatter::visit(MemberAccess &memacc) -{ - memacc.left->visit(*this); - formatted += format(".%s", memacc.member); -} - -void ProgramCompiler::Formatter::visit(UnaryExpression &unary) -{ - if(unary.prefix) - formatted += unary.oper; - unary.expression->visit(*this); - if(!unary.prefix) - formatted += unary.oper; -} - -void ProgramCompiler::Formatter::visit(BinaryExpression &binary) -{ - binary.left->visit(*this); - if(binary.assignment) - formatted += format(" %s ", binary.oper); - else - formatted += binary.oper; - binary.right->visit(*this); - formatted += binary.after; -} - -void ProgramCompiler::Formatter::visit(FunctionCall &call) -{ - formatted += format("%s(", call.name); - for(vector >::iterator i=call.arguments.begin(); i!=call.arguments.end(); ++i) - { - if(i!=call.arguments.begin()) - formatted += ", "; - (*i)->visit(*this); - } - formatted += ')'; -} - -void ProgramCompiler::Formatter::visit(ExpressionStatement &expr) -{ - expr.expression->visit(*this); - formatted += ';'; -} - -void ProgramCompiler::Formatter::visit(Block &block) -{ - if(block.use_braces) - { - if(else_if) - { - formatted += '\n'; - else_if = false; - } - formatted += format("%s{\n", string(indent*2, ' ')); - } - - bool change_indent = (!formatted.empty() && !else_if); - indent += change_indent; - string spaces(indent*2, ' '); - for(list >::iterator i=block.body.begin(); i!=block.body.end(); ++i) - { - if(i!=block.body.begin()) - formatted += '\n'; - if(!else_if) - formatted += spaces; - (*i)->visit(*this); - } - indent -= change_indent; - - if(block.use_braces) - formatted += format("\n%s}", string(indent*2, ' ')); -} - -void ProgramCompiler::Formatter::visit(Layout &layout) -{ - formatted += "layout("; - for(vector::const_iterator i=layout.qualifiers.begin(); i!=layout.qualifiers.end(); ++i) - { - if(i!=layout.qualifiers.begin()) - formatted += ", "; - formatted += i->identifier; - if(!i->value.empty()) - formatted += format("=%s", i->value); - } - formatted += format(") %s;", layout.interface); -} - -void ProgramCompiler::Formatter::visit(StructDeclaration &strct) -{ - formatted += format("struct %s\n", strct.name); - strct.members.visit(*this); - formatted += ';'; -} - -void ProgramCompiler::Formatter::visit(VariableDeclaration &var) -{ - if(var.constant) - formatted += "const "; - if(!var.sampling.empty()) - formatted += format("%s ", var.sampling); - if(!var.interface.empty()) - formatted += format("%s ", var.interface); - formatted += format("%s %s", var.type, var.name); - if(var.array) - { - formatted += '['; - if(var.array_size) - var.array_size->visit(*this); - formatted += ']'; - } - if(var.init_expression) - { - formatted += " = "; - var.init_expression->visit(*this); - } - if(!parameter_list) - formatted += ';'; -} - -void ProgramCompiler::Formatter::visit(InterfaceBlock &iface) -{ - formatted += format("%s %s\n", iface.interface, iface.name); - iface.members.visit(*this); - formatted += ';'; -} - -void ProgramCompiler::Formatter::visit(FunctionDeclaration &func) -{ - formatted += format("%s %s(", func.return_type, func.name); - for(vector >::iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i) - { - if(i!=func.parameters.begin()) - formatted += ", "; - SetFlag set(parameter_list); - (*i)->visit(*this); - } - formatted += ')'; - if(func.definition) - { - formatted += '\n'; - func.body.visit(*this); - } - else - formatted += ';'; -} - -void ProgramCompiler::Formatter::visit(Conditional &cond) -{ - if(else_if) - { - formatted += ' '; - else_if = false; - } - - formatted += "if("; - cond.condition->visit(*this); - formatted += ")\n"; - - cond.body.visit(*this); - if(!cond.else_body.body.empty()) - { - formatted += format("\n%selse", string(indent*2, ' ')); - SetFlag set(else_if); - cond.else_body.visit(*this); - } -} - -void ProgramCompiler::Formatter::visit(Iteration &iter) -{ - formatted += "for("; - iter.init_statement->visit(*this); - formatted += ' '; - iter.condition->visit(*this); - formatted += "; "; - iter.loop_expression->visit(*this); - formatted += ")\n"; - iter.body.visit(*this); -} - -void ProgramCompiler::Formatter::visit(Return &ret) -{ - formatted += "return "; - ret.expression->visit(*this); - formatted += ';'; -} - - -ProgramCompiler::VariableResolver::VariableResolver(): - anonymous(false) -{ } - -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; - } - } -} - -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=="[") - { - binary.right->visit(*this); - type = 0; - binary.left->visit(*this); - } - else - { - TraversingVisitor::visit(binary); - type = 0; - } -} - -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; - } - - 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); - TraversingVisitor::visit(iface); -} - - -ProgramCompiler::InterfaceGenerator::InterfaceGenerator(): - scope_level(0), - remove_node(false) -{ } - -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(list >::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) - { - list >::iterator k = block.body.insert(i, j->second); - (*k)->visit(*this); - } - iface_declarations.clear(); - } - - for(list::iterator j=insert_nodes.begin(); j!=insert_nodes.end(); ++j) - block.body.insert(i, *j); - insert_nodes.clear(); - - if(remove_node) - block.body.erase(i++); - else - ++i; - remove_node = false; - } -} - -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; - iface_var->array = (var.array || (stage->type==GEOMETRY && iface=="in")); - iface_var->array_size = var.array_size; - if(iface=="in") - iface_var->linked_declaration = &var; - iface_declarations[name] = iface_var; - - return true; -} - -void ProgramCompiler::InterfaceGenerator::insert_assignment(const string &left, ProgramSyntax::Expression *right) -{ - BinaryExpression *assign = new BinaryExpression; - VariableReference *ref = new VariableReference; - ref->name = left; - assign->left = ref; - assign->oper = "="; - assign->right = right; - assign->assignment = true; - - ExpressionStatement *stmt = new ExpressionStatement; - stmt->expression = assign; - insert_nodes.push_back(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", var.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) - insert_assignment(var.name, var.init_expression->clone()); - } - } - 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); - - 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); - } - } - - 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; -} - - -void ProgramCompiler::VariableRenamer::visit(VariableReference &var) -{ - if(var.declaration) - var.name = var.declaration->name; -} - -void ProgramCompiler::VariableRenamer::visit(VariableDeclaration &var) -{ - if(var.linked_declaration) - var.name = var.linked_declaration->name; - TraversingVisitor::visit(var); -} - - -ProgramCompiler::UnusedVariableLocator::UnusedVariableLocator(): - aggregate(0), - assignment(false), - record_target(false), - assignment_target(0), - indeterminate_target(false), - self_referencing(false) -{ } - -void ProgramCompiler::UnusedVariableLocator::visit(VariableReference &var) -{ - if(record_target) - { - if(assignment_target) - indeterminate_target = true; - else - assignment_target = var.declaration; - } - else - { - unused_nodes.erase(var.declaration); - - map::iterator i = assignments.find(var.declaration); - if(i!=assignments.end()) - { - unused_nodes.erase(i->second); - assignments.erase(i); - } - - if(assignment && var.declaration==assignment_target) - self_referencing = true; - } - - map::iterator i = aggregates.find(var.declaration); - if(i!=aggregates.end()) - unused_nodes.erase(i->second); -} - -void ProgramCompiler::UnusedVariableLocator::visit(MemberAccess &memacc) -{ - TraversingVisitor::visit(memacc); - unused_nodes.erase(memacc.declaration); -} - -void ProgramCompiler::UnusedVariableLocator::visit(BinaryExpression &binary) -{ - if(binary.assignment) - { - assignment = true; - { - SetFlag set(record_target); - binary.left->visit(*this); - } - if(binary.oper!="=") - self_referencing = true; - binary.right->visit(*this); - } - else if(record_target && binary.oper=="[") - { - binary.left->visit(*this); - SetForScope set(record_target, false); - binary.right->visit(*this); - } - else - TraversingVisitor::visit(binary); -} - -void ProgramCompiler::UnusedVariableLocator::visit(ExpressionStatement &expr) -{ - assignment = false; - assignment_target = 0; - indeterminate_target = false; - self_referencing = false; - TraversingVisitor::visit(expr); - if(assignment && assignment_target && !indeterminate_target) - { - Node *&assign = assignments[assignment_target]; - if(self_referencing) - unused_nodes.erase(assign); - else if(assign) - unused_nodes.insert(assign); - assign = &expr; - if(assignment_target->interface=="out" && (stage->type==FRAGMENT || assignment_target->linked_declaration)) - unused_nodes.erase(assignment_target); - else - unused_nodes.insert(&expr); - } - assignment = false; -} - -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 - { - unused_nodes.insert(&var); - if(var.init_expression) - { - unused_nodes.insert(&*var.init_expression); - assignments[&var] = &*var.init_expression; - } - } - 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::NodeRemover::visit(Block &block) -{ - for(list >::iterator i=block.body.begin(); i!=block.body.end(); ) - { - (*i)->visit(*this); - if(to_remove.count(&**i)) - 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); - if(var.linked_declaration) - var.linked_declaration->linked_declaration = 0; - } - else if(var.init_expression && to_remove.count(&*var.init_expression)) - var.init_expression = 0; -} - -} // namespace GL -} // namespace Msp