else
++i;
}
+ for(list<Stage>::iterator i=module->stages.begin(); i!=module->stages.end(); ++i)
+ finalize(*i);
}
void ProgramCompiler::import(const string &name)
return !unused.empty();
}
+void ProgramCompiler::finalize(Stage &stage)
+{
+ if(get_gl_api()==OPENGL_ES2)
+ apply<DefaultPrecisionGenerator>(stage);
+ else
+ apply<PrecisionRemover>(stage);
+}
+
void ProgramCompiler::inject_block(Block &target, const Block &source)
{
list<RefPtr<Node> >::iterator insert_point = target.body.begin();
void ProgramCompiler::Formatter::apply(ProgramSyntax::Stage &s)
{
+ GLApi api = get_gl_api();
const Version &ver = s.required_version;
- if(ver.major)
- formatted += format("#version %d%d\n", ver.major, ver.minor);
+
+ if(ver)
+ {
+ formatted += format("#version %d%02d", ver.major, ver.minor);
+ if(api==OPENGL_ES2 && ver>=Version(3, 0))
+ formatted += " es";
+ formatted += '\n';
+ }
+
Visitor::apply(s);
}
formatted += format("import %s;", import.module);
}
+void ProgramCompiler::Formatter::visit(Precision &prec)
+{
+ formatted += format("precision %s %s;", prec.precision, prec.type);
+}
+
void ProgramCompiler::Formatter::visit(Layout &layout)
{
formatted += "layout(";
if(!var.sampling.empty())
formatted += format("%s ", var.sampling);
if(!var.interface.empty() && var.interface!=block_interface)
- formatted += format("%s ", var.interface);
+ {
+ string interface = var.interface;
+ if(stage->required_version<Version(1, 30))
+ {
+ if(stage->type==VERTEX && var.interface=="in")
+ interface = "attribute";
+ else if((stage->type==VERTEX && var.interface=="out") || (stage->type==FRAGMENT && var.interface=="in"))
+ interface = "varying";
+ }
+ formatted += format("%s ", interface);
+ }
+ if(!var.precision.empty())
+ formatted += format("%s ", var.precision);
formatted += format("%s %s", var.type, var.name);
if(var.array)
{
if(!i->second.referenced)
{
unused_nodes.insert(i->first);
- for(vector<Node *>::iterator j=i->second.assignments.begin(); j!=i->second.assignments.end(); ++j)
- unused_nodes.insert(*j);
+ clear_assignments(i->second, true);
}
}
variables.pop_back();
{
VariableInfo &var_info = variables.back()[&var];
if(!self_ref)
- var_info.assignments.clear();
+ 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<Node *>::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;
BlockVariableMap &block_variables = variables.back();
for(BlockVariableMap::iterator i=block_variables.begin(); i!=block_variables.end(); ++i)
i->second.conditionally_assigned = true;
+ for(vector<RefPtr<VariableDeclaration> >::iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i)
+ block_variables[i->get()].referenced = true;
merge_down_variables();
}
{
if(!i->second.referenced)
unused_nodes.insert(i->first);
- for(vector<Node *>::iterator j=i->second.assignments.begin(); j!=i->second.assignments.end(); ++j)
- unused_nodes.insert(*j);
+ clear_assignments(i->second, true);
continue;
}
parent_variables.insert(*i);
else
{
- if(!i->second.conditionally_assigned)
- {
- j->second.assignments.clear();
- j->second.conditionally_assigned = true;
- }
+ 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());
}
{
TraversingVisitor::visit(func);
- if(func.name!="main" && !used_definitions.count(&func))
+ if((func.name!="main" || func.body.body.empty()) && !used_definitions.count(&func))
unused_nodes.insert(&func);
}
}
+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<bool> 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_version(get_glsl_version())
+ target_api(get_gl_api()),
+ target_version(get_glsl_version()),
+ frag_out(0)
{ }
ProgramCompiler::LegacyConverter::LegacyConverter(const Version &v):
- target_version(v)
+ target_api(get_gl_api()),
+ target_version(v),
+ frag_out(0)
{ }
-bool ProgramCompiler::LegacyConverter::check_version(const Version &feature_version)
+bool ProgramCompiler::LegacyConverter::check_version(const Version &feature_version) const
{
if(target_version<feature_version)
return false;
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.name==frag_out_name && !check_version(Version(1, 30)))
+ if(var.declaration==frag_out && !supports_unified_interface_syntax())
{
var.name = "gl_FragColor";
var.declaration = 0;
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 && !check_version(Version(1, 30)))
+ if(call.name=="texture" && !call.declaration && !supports_unified_sampling_functions())
{
vector<RefPtr<Expression> >::iterator i = call.arguments.begin();
if(i!=call.arguments.end())
TraversingVisitor::visit(call);
}
+bool ProgramCompiler::LegacyConverter::supports_interface_layouts() const
+{
+ if(target_api==OPENGL_ES2)
+ return check_version(Version(3, 0));
+ else
+ return check_version(Version(3, 30));
+}
+
void ProgramCompiler::LegacyConverter::visit(VariableDeclaration &var)
{
- if(var.layout && !check_version(Version(3, 30)))
+ if(var.layout && !supports_interface_layouts())
{
vector<Layout::Qualifier>::iterator i;
for(i=var.layout->qualifiers.begin(); (i!=var.layout->qualifiers.end() && i->identifier!="location"); ++i) ;
}
}
- if((var.interface=="in" || var.interface=="out") && !check_version(Version(1, 30)))
+ if((var.interface=="in" || var.interface=="out") && !supports_unified_interface_syntax())
{
- if(stage->type==VERTEX && var.interface=="in")
- var.interface = "attribute";
- else if((stage->type==VERTEX && var.interface=="out") || (stage->type==FRAGMENT && var.interface=="in"))
- var.interface = "varying";
- else if(stage->type==FRAGMENT && var.interface=="out")
+ if(stage->type==FRAGMENT && var.interface=="out")
{
- frag_out_name = var.name;
+ 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
+ return check_version(Version(1, 50));
+}
+
void ProgramCompiler::LegacyConverter::visit(InterfaceBlock &iface)
{
- if(!check_version(Version(1, 50)))
+ if(!supports_interface_blocks(iface.interface))
flatten_block(iface.members);
}