X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=blobdiff_plain;f=source%2Fprogramcompiler.cpp;h=d021ab4f75732769855e9370fe0c8eec990aca20;hp=0aed5936af82948eb1c040621e61b7dea83b2b18;hb=bec07999d95b76f4b47cffcc564d0cd0afc0435e;hpb=e9d5d1945f110d5307036af0d4b3f0c3ebfe3d2a diff --git a/source/programcompiler.cpp b/source/programcompiler.cpp index 0aed5936..d021ab4f 100644 --- a/source/programcompiler.cpp +++ b/source/programcompiler.cpp @@ -1,6 +1,12 @@ +#include #include +#include +#include +#include #include +#include #include +#include #include #include "error.h" #include "program.h" @@ -8,6 +14,8 @@ #include "resources.h" #include "shader.h" +#undef interface + using namespace std; namespace { @@ -35,8 +43,6 @@ namespace GL { using namespace ProgramSyntax; -// XXX For some reason global declarations are emitted for otherwise undeclared local variables - ProgramCompiler::ProgramCompiler(): resources(0), module(0) @@ -53,8 +59,8 @@ void ProgramCompiler::compile(const string &source, const string &src_name) delete module; module = new Module(); ProgramParser parser; - imported_names.insert(src_name); - append_module(parser.parse(source, src_name)); + imported_names.push_back(src_name); + append_module(parser.parse(source, src_name, 1)); process(); } @@ -64,8 +70,8 @@ void ProgramCompiler::compile(IO::Base &io, Resources *res, const string &src_na delete module; module = new Module(); ProgramParser parser; - imported_names.insert(src_name); - append_module(parser.parse(io, src_name)); + imported_names.push_back(src_name); + append_module(parser.parse(io, src_name, 1)); process(); } @@ -79,25 +85,64 @@ void ProgramCompiler::add_shaders(Program &program) if(!module) throw invalid_operation("ProgramCompiler::add_shaders"); - for(list::iterator i=module->stages.begin(); i!=module->stages.end(); ++i) + try { - if(i->type==VERTEX) + for(list::iterator i=module->stages.begin(); i!=module->stages.end(); ++i) { - 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); + 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); + } + } } - else if(i->type==GEOMETRY) - program.attach_shader_owned(new GeometryShader(apply(*i))); - else if(i->type==FRAGMENT) + } + 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) { - program.attach_shader_owned(new FragmentShader(apply(*i))); - if(EXT_gpu_shader4) + RegMatch m = r_message.match(*i); + if(m) { - for(map::iterator j=i->locations.begin(); j!=i->locations.end(); ++j) - program.bind_fragment_data(j->second, j->first); + 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::iterator i=stage.content.body.begin(); i!=stage.content.body.end(); ++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); } @@ -187,19 +234,21 @@ void ProgramCompiler::process() void ProgramCompiler::import(const string &name) { string fn = name+".glsl"; - if(imported_names.count(fn)) + if(find(imported_names, fn)!=imported_names.end()) return; - imported_names.insert(fn); + 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)); + 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); @@ -208,6 +257,7 @@ void ProgramCompiler::generate(Stage &stage) apply(stage); apply(stage); apply(stage); + apply(stage); apply(stage); } @@ -236,8 +286,8 @@ void ProgramCompiler::finalize(Stage &stage) 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) + 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()); } @@ -279,7 +329,7 @@ void ProgramCompiler::BlockModifier::flatten_block(Block &block) remove_node = true; } -void ProgramCompiler::BlockModifier::apply_and_increment(Block &block, list >::iterator &i) +void ProgramCompiler::BlockModifier::apply_and_increment(Block &block, NodeList::iterator &i) { block.body.insert(i, insert_nodes.begin(), insert_nodes.end()); insert_nodes.clear(); @@ -293,7 +343,7 @@ void ProgramCompiler::BlockModifier::apply_and_increment(Block &block, list >::iterator i=block.body.begin(); i!=block.body.end(); ) + for(NodeList::iterator i=block.body.begin(); i!=block.body.end(); ) { (*i)->visit(*this); apply_and_increment(block, i); @@ -302,9 +352,10 @@ void ProgramCompiler::BlockModifier::visit(Block &block) ProgramCompiler::Formatter::Formatter(): + source_index(0), + source_line(1), indent(0), - parameter_list(false), - else_if(0) + parameter_list(false) { } void ProgramCompiler::Formatter::apply(ProgramSyntax::Stage &s) @@ -314,140 +365,175 @@ void ProgramCompiler::Formatter::apply(ProgramSyntax::Stage &s) if(ver) { - formatted += format("#version %d%02d", ver.major, ver.minor); + append(format("#version %d%02d", ver.major, ver.minor)); if(api==OPENGL_ES2 && ver>=Version(3, 0)) - formatted += " es"; + 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); - formatted += ')'; + append(')'); } void ProgramCompiler::Formatter::visit(VariableReference &var) { - formatted += var.name; + append(var.name); } void ProgramCompiler::Formatter::visit(MemberAccess &memacc) { memacc.left->visit(*this); - formatted += format(".%s", memacc.member); + append(format(".%s", memacc.member)); } void ProgramCompiler::Formatter::visit(UnaryExpression &unary) { if(unary.prefix) - formatted += unary.oper; + append(unary.oper); unary.expression->visit(*this); if(!unary.prefix) - formatted += unary.oper; + append(unary.oper); } void ProgramCompiler::Formatter::visit(BinaryExpression &binary) { binary.left->visit(*this); - formatted += binary.oper; + append(binary.oper); binary.right->visit(*this); - formatted += binary.after; + append(binary.after); } void ProgramCompiler::Formatter::visit(Assignment &assign) { assign.left->visit(*this); - formatted += format(" %s ", assign.oper); + append(format(" %s ", assign.oper)); assign.right->visit(*this); } void ProgramCompiler::Formatter::visit(FunctionCall &call) { - formatted += format("%s(", call.name); - for(vector >::iterator i=call.arguments.begin(); i!=call.arguments.end(); ++i) + append(format("%s(", call.name)); + for(NodeArray::iterator i=call.arguments.begin(); i!=call.arguments.end(); ++i) { if(i!=call.arguments.begin()) - formatted += ", "; + append(", "); (*i)->visit(*this); } - formatted += ')'; + append(')'); } void ProgramCompiler::Formatter::visit(ExpressionStatement &expr) { expr.expression->visit(*this); - formatted += ';'; + append(';'); } void ProgramCompiler::Formatter::visit(Block &block) { - if(else_if) - --else_if; - unsigned brace_indent = indent; bool use_braces = (block.use_braces || (indent && block.body.size()!=1)); if(use_braces) - formatted += format("%s{\n", string(brace_indent*2, ' ')); + append(format("%s{\n", string(brace_indent*2, ' '))); SetForScope set(indent, indent+(indent>0 || use_braces)); string spaces(indent*2, ' '); - for(list >::iterator i=block.body.begin(); i!=block.body.end(); ++i) + for(NodeList::iterator i=block.body.begin(); i!=block.body.end(); ++i) { if(i!=block.body.begin()) - formatted += '\n'; - formatted += spaces; + append('\n'); + set_source((*i)->source, (*i)->line); + append(spaces); (*i)->visit(*this); - else_if = 0; } if(use_braces) - formatted += format("\n%s}", string(brace_indent*2, ' ')); + append(format("\n%s}", string(brace_indent*2, ' '))); } void ProgramCompiler::Formatter::visit(Import &import) { - formatted += format("import %s;", import.module); + append(format("import %s;", import.module)); } void ProgramCompiler::Formatter::visit(Precision &prec) { - formatted += format("precision %s %s;", prec.precision, prec.type); + append(format("precision %s %s;", prec.precision, prec.type)); } void ProgramCompiler::Formatter::visit(Layout &layout) { - formatted += "layout("; + append("layout("); for(vector::const_iterator i=layout.qualifiers.begin(); i!=layout.qualifiers.end(); ++i) { if(i!=layout.qualifiers.begin()) - formatted += ", "; - formatted += i->identifier; + append(", "); + append(i->identifier); if(!i->value.empty()) - formatted += format("=%s", i->value); + append(format("=%s", i->value)); } - formatted += ')'; + append(')'); } void ProgramCompiler::Formatter::visit(InterfaceLayout &layout) { layout.layout.visit(*this); - formatted += format(" %s;", layout.interface); + append(format(" %s;", layout.interface)); } void ProgramCompiler::Formatter::visit(StructDeclaration &strct) { - formatted += format("struct %s\n", strct.name); + append(format("struct %s\n", strct.name)); strct.members.visit(*this); - formatted += ';'; + append(';'); } void ProgramCompiler::Formatter::visit(VariableDeclaration &var) @@ -455,12 +541,14 @@ void ProgramCompiler::Formatter::visit(VariableDeclaration &var) if(var.layout) { var.layout->visit(*this); - formatted += ' '; + append(' '); } if(var.constant) - formatted += "const "; + append("const "); + if(!var.interpolation.empty()) + append(format("%s ", var.interpolation)); if(!var.sampling.empty()) - formatted += format("%s ", var.sampling); + append(format("%s ", var.sampling)); if(!var.interface.empty() && var.interface!=block_interface) { string interface = var.interface; @@ -471,98 +559,133 @@ void ProgramCompiler::Formatter::visit(VariableDeclaration &var) else if((stage->type==VERTEX && var.interface=="out") || (stage->type==FRAGMENT && var.interface=="in")) interface = "varying"; } - formatted += format("%s ", interface); + append(format("%s ", interface)); } if(!var.precision.empty()) - formatted += format("%s ", var.precision); - formatted += format("%s %s", var.type, var.name); + append(format("%s ", var.precision)); + append(format("%s %s", var.type, var.name)); if(var.array) { - formatted += '['; + append('['); if(var.array_size) var.array_size->visit(*this); - formatted += ']'; + append(']'); } if(var.init_expression) { - formatted += " = "; + append(" = "); var.init_expression->visit(*this); } if(!parameter_list) - formatted += ';'; + append(';'); } void ProgramCompiler::Formatter::visit(InterfaceBlock &iface) { SetForScope set(block_interface, iface.interface); - formatted += format("%s %s\n", iface.interface, iface.name); + append(format("%s %s\n", iface.interface, iface.name)); iface.members.visit(*this); - formatted += ';'; + append(';'); } 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) + 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()) - formatted += ", "; + append(", "); SetFlag set(parameter_list); (*i)->visit(*this); } - formatted += ')'; + append(')'); if(func.definition==&func) { - formatted += '\n'; + append('\n'); func.body.visit(*this); } else - formatted += ';'; + append(';'); } void ProgramCompiler::Formatter::visit(Conditional &cond) { - if(else_if) - formatted.replace(formatted.rfind('\n'), string::npos, 1, ' '); - - indent -= else_if; - - formatted += "if("; + append("if("); cond.condition->visit(*this); - formatted += ")\n"; + append(")\n"); cond.body.visit(*this); if(!cond.else_body.body.empty()) { - formatted += format("\n%selse\n", string(indent*2, ' ')); - SetForScope set(else_if, 2); - cond.else_body.visit(*this); + 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) { - formatted += "for("; - iter.init_statement->visit(*this); - formatted += ' '; - iter.condition->visit(*this); - formatted += "; "; - iter.loop_expression->visit(*this); - formatted += ")\n"; - iter.body.visit(*this); + 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) { - formatted += "return "; - ret.expression->visit(*this); - formatted += ';'; + append("return"); + if(ret.expression) + { + append(' '); + ret.expression->visit(*this); + } + append(';'); } void ProgramCompiler::Formatter::visit(Jump &jump) { - formatted += jump.keyword; - formatted += ';'; + append(jump.keyword); + append(';'); } @@ -601,6 +724,27 @@ void ProgramCompiler::DeclarationCombiner::visit(VariableDeclaration &var) 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 @@ -802,7 +946,7 @@ void ProgramCompiler::InterfaceGenerator::apply(Stage &s) void ProgramCompiler::InterfaceGenerator::visit(Block &block) { SetForScope set(scope_level, scope_level+1); - for(list >::iterator i=block.body.begin(); i!=block.body.end(); ) + for(NodeList::iterator i=block.body.begin(); i!=block.body.end(); ) { (*i)->visit(*this); @@ -810,7 +954,7 @@ void ProgramCompiler::InterfaceGenerator::visit(Block &block) { for(map >::iterator j=iface_declarations.begin(); j!=iface_declarations.end(); ++j) { - list >::iterator k = block.body.insert(i, j->second); + NodeList::iterator k = block.body.insert(i, j->second); (*k)->visit(*this); } iface_declarations.clear(); @@ -851,7 +995,7 @@ bool ProgramCompiler::InterfaceGenerator::generate_interface(VariableDeclaration return true; } -void ProgramCompiler::InterfaceGenerator::insert_assignment(const string &left, ProgramSyntax::Expression *right) +ExpressionStatement &ProgramCompiler::InterfaceGenerator::insert_assignment(const string &left, ProgramSyntax::Expression *right) { Assignment *assign = new Assignment; VariableReference *ref = new VariableReference; @@ -864,6 +1008,8 @@ void ProgramCompiler::InterfaceGenerator::insert_assignment(const string &left, stmt->expression = assign; stmt->visit(*this); insert_nodes.push_back(stmt); + + return *stmt; } void ProgramCompiler::InterfaceGenerator::visit(VariableReference &var) @@ -895,7 +1041,9 @@ void ProgramCompiler::InterfaceGenerator::visit(VariableDeclaration &var) remove_node = true; if(var.init_expression) { - insert_assignment(var.name, var.init_expression->clone()); + ExpressionStatement &stmt = insert_assignment(var.name, var.init_expression->clone()); + stmt.source = var.source; + stmt.line = var.line; return; } } @@ -1006,13 +1154,13 @@ void ProgramCompiler::DeclarationReorderer::visit(Block &block) if(scope_level>1) return Visitor::visit(block); - list >::iterator struct_insert_point = block.body.end(); - list >::iterator variable_insert_point = block.body.end(); - list >::iterator function_insert_point = block.body.end(); + 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(list >::iterator i=block.body.begin(); i!=block.body.end(); ) + for(NodeList::iterator i=block.body.begin(); i!=block.body.end(); ) { kind = NO_DECLARATION; (*i)->visit(*this); @@ -1147,7 +1295,7 @@ void ProgramCompiler::FunctionInliner::visit(Block &block) if(extract_result) --extract_result; - for(list >::iterator i=block.body.begin(); i!=block.body.end(); ++i) + for(NodeList::iterator i=block.body.begin(); i!=block.body.end(); ++i) { (*i)->visit(*this); if(extract_result) @@ -1168,9 +1316,15 @@ void ProgramCompiler::FunctionInliner::visit(BinaryExpression &binary) inline_result = 0; } +void ProgramCompiler::FunctionInliner::visit(MemberAccess &memacc) +{ + visit_and_inline(memacc.left); + inline_result = 0; +} + void ProgramCompiler::FunctionInliner::visit(FunctionCall &call) { - for(vector >::iterator i=call.arguments.begin(); i!=call.arguments.end(); ++i) + for(NodeArray::iterator i=call.arguments.begin(); i!=call.arguments.end(); ++i) visit_and_inline(*i); FunctionDeclaration *def = call.declaration; @@ -1186,6 +1340,13 @@ void ProgramCompiler::FunctionInliner::visit(FunctionCall &call) 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); @@ -1286,7 +1447,8 @@ void ProgramCompiler::ExpressionEvaluator::visit(BinaryExpression &binary) ProgramCompiler::ConstantConditionEliminator::ConstantConditionEliminator(): - scope_level(0) + scope_level(0), + record_only(false) { } void ProgramCompiler::ConstantConditionEliminator::visit(Block &block) @@ -1298,6 +1460,13 @@ void ProgramCompiler::ConstantConditionEliminator::visit(Block &block) 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); @@ -1311,28 +1480,49 @@ void ProgramCompiler::ConstantConditionEliminator::visit(VariableDeclaration &va void ProgramCompiler::ConstantConditionEliminator::visit(Conditional &cond) { - ExpressionEvaluator eval(variable_values); - cond.condition->visit(eval); - if(eval.result_valid) - flatten_block(eval.result ? cond.body : cond.else_body); - else - TraversingVisitor::visit(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(iter.condition) + if(!record_only) { - ExpressionEvaluator eval; - iter.condition->visit(eval); - if(eval.result_valid && !eval.result) + if(iter.condition) { - remove_node = true; - return; + /* 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); } @@ -1340,6 +1530,7 @@ ProgramCompiler::UnusedVariableLocator::UnusedVariableLocator(): aggregate(0), assignment(0), assignment_target(false), + assign_to_subscript(false), global_scope(true) { } @@ -1385,6 +1576,8 @@ 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); @@ -1396,6 +1589,7 @@ void ProgramCompiler::UnusedVariableLocator::visit(BinaryExpression &binary) void ProgramCompiler::UnusedVariableLocator::visit(Assignment &assign) { { + assign_to_subscript = false; SetForScope set(assignment_target, !assign.self_referencing); assign.left->visit(*this); } @@ -1403,10 +1597,10 @@ void ProgramCompiler::UnusedVariableLocator::visit(Assignment &assign) assignment = &assign; } -void ProgramCompiler::UnusedVariableLocator::record_assignment(VariableDeclaration &var, Node &node, bool self_ref) +void ProgramCompiler::UnusedVariableLocator::record_assignment(VariableDeclaration &var, Node &node, bool chained) { VariableInfo &var_info = variables.back()[&var]; - if(!self_ref) + if(!chained) clear_assignments(var_info, true); var_info.assignments.push_back(&node); var_info.conditionally_assigned = false; @@ -1427,7 +1621,7 @@ 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); + record_assignment(*assignment->target_declaration, expr, (assignment->self_referencing || assign_to_subscript)); } void ProgramCompiler::UnusedVariableLocator::visit(StructDeclaration &strct) @@ -1464,7 +1658,7 @@ void ProgramCompiler::UnusedVariableLocator::visit(FunctionDeclaration &func) { SetForScope set(global_scope, false); - for(vector >::iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i) + for(NodeArray::iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i) (*i)->visit(*this); func.body.visit(*this); } @@ -1472,7 +1666,7 @@ void ProgramCompiler::UnusedVariableLocator::visit(FunctionDeclaration &func) BlockVariableMap &block_variables = variables.back(); for(BlockVariableMap::iterator i=block_variables.begin(); i!=block_variables.end(); ++i) i->second.conditionally_assigned = true; - for(vector >::iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i) + for(NodeArray::iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i) block_variables[i->get()].referenced = true; merge_down_variables(); } @@ -1487,7 +1681,7 @@ void ProgramCompiler::UnusedVariableLocator::merge_down_variables() { if(!i->second.referenced) unused_nodes.insert(i->first); - clear_assignments(i->second, true); + clear_assignments(i->second, i->first->interface!="out"); continue; } @@ -1584,7 +1778,7 @@ ProgramCompiler::NodeRemover::NodeRemover(const set &r): void ProgramCompiler::NodeRemover::visit(Block &block) { - for(list >::iterator i=block.body.begin(); i!=block.body.end(); ) + for(NodeList::iterator i=block.body.begin(); i!=block.body.end(); ) { (*i)->visit(*this); if(to_remove.count(i->get())) @@ -1608,6 +1802,13 @@ void ProgramCompiler::NodeRemover::visit(VariableDeclaration &var) 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 &) { @@ -1690,6 +1891,18 @@ bool ProgramCompiler::LegacyConverter::check_version(const Version &feature_vers 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) @@ -1731,7 +1944,7 @@ void ProgramCompiler::LegacyConverter::visit(FunctionCall &call) { if(call.name=="texture" && !call.declaration && !supports_unified_sampling_functions()) { - vector >::iterator i = call.arguments.begin(); + NodeArray::iterator i = call.arguments.begin(); if(i!=call.arguments.end()) { (*i)->visit(*this); @@ -1741,10 +1954,32 @@ void ProgramCompiler::LegacyConverter::visit(FunctionCall &call) 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); @@ -1758,8 +1993,30 @@ 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_version(Version(3, 30)); + 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) @@ -1789,6 +2046,17 @@ void ProgramCompiler::LegacyConverter::visit(VariableDeclaration &var) } } + 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") @@ -1810,8 +2078,12 @@ bool ProgramCompiler::LegacyConverter::supports_interface_blocks(const string &i 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 check_version(Version(1, 50)); + return false; } void ProgramCompiler::LegacyConverter::visit(InterfaceBlock &iface)