X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=blobdiff_plain;f=source%2Fprogramcompiler.cpp;h=5027dc9b79788783c0e2cc5860fa91c39b232ef2;hp=c35fa275c2b1bbadbcfbfb8f113cf68d165d4a8a;hb=8468279a03d906f79fb6158162c7970d4d7fff60;hpb=6dc2da27f0831d4172fcfeba4900616fd6c844b8 diff --git a/source/programcompiler.cpp b/source/programcompiler.cpp index c35fa275..5027dc9b 100644 --- a/source/programcompiler.cpp +++ b/source/programcompiler.cpp @@ -1,4 +1,9 @@ +#include #include +#include +#include +#include +#include #include #include #include "error.h" @@ -7,17 +12,19 @@ #include "resources.h" #include "shader.h" +#undef interface + using namespace std; namespace { const char builtins_src[] = - "////// vertex\n" + "#pragma MSP stage(vertex)\n" "out gl_PerVertex {\n" " vec4 gl_Position;\n" " float gl_ClipDistance[];\n" - "};" - "////// geometry\n" + "};\n" + "#pragma MSP stage(geometry)\n" "in gl_PerVertex {\n" " vec4 gl_Position;\n" " float gl_ClipDistance[];\n" @@ -39,20 +46,38 @@ ProgramCompiler::ProgramCompiler(): module(0) { } -void ProgramCompiler::compile(const string &source) +ProgramCompiler::~ProgramCompiler() +{ + delete module; +} + +void ProgramCompiler::compile(const string &source, const string &src_name) { resources = 0; - module = &parser.parse(source); + delete module; + module = new Module(); + ProgramParser parser; + imported_names.insert(src_name); + append_module(parser.parse(source, src_name)); process(); } -void ProgramCompiler::compile(IO::Base &io, Resources *res) +void ProgramCompiler::compile(IO::Base &io, Resources *res, const string &src_name) { resources = res; - module = &parser.parse(io); + delete module; + module = new Module(); + ProgramParser parser; + imported_names.insert(src_name); + append_module(parser.parse(io, src_name)); process(); } +void ProgramCompiler::compile(IO::Base &io, const string &src_name) +{ + compile(io, 0, src_name); +} + void ProgramCompiler::add_shaders(Program &program) { if(!module) @@ -71,8 +96,11 @@ void ProgramCompiler::add_shaders(Program &program) else if(i->type==FRAGMENT) { program.attach_shader_owned(new FragmentShader(apply(*i))); - for(map::iterator j=i->locations.begin(); j!=i->locations.end(); ++j) - program.bind_fragment_data(j->second, j->first); + if(EXT_gpu_shader4) + { + for(map::iterator j=i->locations.begin(); j!=i->locations.end(); ++j) + program.bind_fragment_data(j->second, j->first); + } } } } @@ -80,7 +108,7 @@ void ProgramCompiler::add_shaders(Program &program) Module *ProgramCompiler::create_builtins_module() { ProgramParser parser; - Module *module = new Module(parser.parse(builtins_src)); + Module *module = new Module(parser.parse(builtins_src, "")); for(list::iterator i=module->stages.begin(); i!=module->stages.end(); ++i) { VariableResolver resolver; @@ -106,13 +134,47 @@ Stage *ProgramCompiler::get_builtins(StageType type) return 0; } -void ProgramCompiler::process() +void ProgramCompiler::append_module(ProgramSyntax::Module &mod) { - list imports = apply >(module->shared); - for(list::iterator i=imports.end(); i!=imports.begin(); ) - import((*--i)->module); - apply(module->shared, set(imports.begin(), imports.end())); + 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; + } + + 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(); ) @@ -129,33 +191,15 @@ void ProgramCompiler::process() void ProgramCompiler::import(const string &name) { string fn = name+".glsl"; + if(imported_names.count(fn)) + return; + imported_names.insert(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; - Module &imported_module = import_parser.parse(*io); - - inject_block(module->shared.content, imported_module.shared.content); - apply(module->shared); - for(list::iterator i=imported_module.stages.begin(); i!=imported_module.stages.end(); ++i) - { - list::iterator j; - for(j=module->stages.begin(); (j!=module->stages.end() && j->typetype); ++j) ; - if(j==module->stages.end() || j->type>i->type) - { - j = module->stages.insert(j, *i); - list::iterator k = j; - if(++k!=module->stages.end()) - k->previous = &*j; - if(j!=module->stages.begin()) - j->previous = &*--(k=j); - } - else - { - inject_block(j->content, i->content); - apply(*j); - } - } + append_module(import_parser.parse(*io, fn)); } void ProgramCompiler::generate(Stage &stage) @@ -167,8 +211,8 @@ void ProgramCompiler::generate(Stage &stage) apply(stage); apply(stage); apply(stage); - apply(stage); apply(stage); + apply(stage); apply(stage); } @@ -197,8 +241,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()); } @@ -240,7 +284,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(); @@ -254,7 +298,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); @@ -281,6 +325,11 @@ void ProgramCompiler::Formatter::apply(ProgramSyntax::Stage &s) formatted += '\n'; } + for(vector::const_iterator i=s.required_extensions.begin(); i!=s.required_extensions.end(); ++i) + formatted += format("#extension %s: require\n", (*i)->get_name()); + if(!s.required_extensions.empty()) + formatted += '\n'; + Visitor::apply(s); } @@ -334,7 +383,7 @@ void ProgramCompiler::Formatter::visit(Assignment &assign) void ProgramCompiler::Formatter::visit(FunctionCall &call) { formatted += format("%s(", call.name); - for(vector >::iterator i=call.arguments.begin(); i!=call.arguments.end(); ++i) + for(NodeArray::iterator i=call.arguments.begin(); i!=call.arguments.end(); ++i) { if(i!=call.arguments.begin()) formatted += ", "; @@ -361,7 +410,7 @@ void ProgramCompiler::Formatter::visit(Block &block) 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'; @@ -420,6 +469,8 @@ void ProgramCompiler::Formatter::visit(VariableDeclaration &var) } if(var.constant) formatted += "const "; + if(!var.interpolation.empty()) + formatted += format("%s ", var.interpolation); if(!var.sampling.empty()) formatted += format("%s ", var.sampling); if(!var.interface.empty() && var.interface!=block_interface) @@ -464,7 +515,7 @@ void ProgramCompiler::Formatter::visit(InterfaceBlock &iface) 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) + for(NodeArray::iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i) { if(i!=func.parameters.begin()) formatted += ", "; @@ -503,20 +554,50 @@ void ProgramCompiler::Formatter::visit(Conditional &cond) 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) + { + formatted += "while("; + iter.condition->visit(*this); + formatted += ')'; + } + else + { + formatted += "for("; + if(iter.init_statement) + iter.init_statement->visit(*this); + else + formatted += ';'; + if(iter.condition) + { + formatted += ' '; + iter.condition->visit(*this); + } + formatted += ';'; + if(iter.loop_expression) + { + formatted += ' '; + iter.loop_expression->visit(*this); + } + formatted += ')'; + } + + if(iter.body.body.empty()) + formatted += " { }"; + else + { + formatted += '\n'; + iter.body.visit(*this); + } } void ProgramCompiler::Formatter::visit(Return &ret) { - formatted += "return "; - ret.expression->visit(*this); + formatted += "return"; + if(ret.expression) + { + formatted += ' '; + ret.expression->visit(*this); + } formatted += ';'; } @@ -562,6 +643,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 @@ -763,7 +865,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); @@ -771,7 +873,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(); @@ -823,6 +925,7 @@ void ProgramCompiler::InterfaceGenerator::insert_assignment(const string &left, ExpressionStatement *stmt = new ExpressionStatement; stmt->expression = assign; + stmt->visit(*this); insert_nodes.push_back(stmt); } @@ -838,7 +941,10 @@ void ProgramCompiler::InterfaceGenerator::visit(VariableReference &var) 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); + { + generate_interface(*i->second, "in", i->second->name); + var.name = i->second->name; + } } void ProgramCompiler::InterfaceGenerator::visit(VariableDeclaration &var) @@ -851,7 +957,10 @@ void ProgramCompiler::InterfaceGenerator::visit(VariableDeclaration &var) { remove_node = true; if(var.init_expression) + { insert_assignment(var.name, var.init_expression->clone()); + return; + } } } else if(var.interface=="in") @@ -940,30 +1049,33 @@ void ProgramCompiler::InterfaceGenerator::visit(Passthrough &pass) } -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::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) { - list >::iterator struct_insert_point = block.body.end(); - list >::iterator variable_insert_point = block.body.end(); + SetForScope set(scope_level, scope_level+1); + if(scope_level>1) + return Visitor::visit(block); - for(list >::iterator i=block.body.begin(); i!=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(NodeList::iterator i=block.body.begin(); i!=block.body.end(); ) { kind = NO_DECLARATION; (*i)->visit(*this); @@ -985,13 +1097,64 @@ void ProgramCompiler::DeclarationReorderer::visit(Block &block) 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) @@ -1047,7 +1210,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) @@ -1068,9 +1231,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; @@ -1086,6 +1255,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); @@ -1186,7 +1362,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) @@ -1198,6 +1375,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); @@ -1211,28 +1395,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); } @@ -1240,6 +1445,7 @@ ProgramCompiler::UnusedVariableLocator::UnusedVariableLocator(): aggregate(0), assignment(0), assignment_target(false), + assign_to_subscript(false), global_scope(true) { } @@ -1285,6 +1491,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); @@ -1296,6 +1504,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); } @@ -1303,10 +1512,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; @@ -1327,7 +1536,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) @@ -1364,7 +1573,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); } @@ -1372,7 +1581,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(); } @@ -1484,7 +1693,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())) @@ -1508,6 +1717,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 &) { @@ -1590,6 +1806,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) @@ -1631,7 +1859,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); @@ -1658,8 +1886,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_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_version(Version(3, 30)); + 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) @@ -1678,6 +1928,8 @@ void ProgramCompiler::LegacyConverter::visit(VariableDeclaration &var) } 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); } @@ -1687,6 +1939,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") @@ -1708,8 +1971,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)