{ NO_SCOPE, 0, 0, 0, 0 }
};
+const char ProgramBuilder::interfaces[] = { 0, 0, 0, 'v', 0 };
+
ProgramBuilder::ProgramBuilder(const StandardFeatures &f):
features(f),
feature_flags(features.create_flags()),
if((*i)->variable->scope==UNIFORM && (*i)->is_referenced_from(scope) && !(*i)->inlined)
source += format("uniform %s;\n", (*i)->create_declaration());
- if(scope==VERTEX)
+ /* Interface variables need to have global declarations. */
+ for(list<ShaderVariable *>::const_iterator i=variables.begin(); i!=variables.end(); ++i)
{
- const char *qualifier = (features.legacy ? "attribute" : "in");
- for(list<ShaderVariable *>::const_iterator i=variables.begin(); i!=variables.end(); ++i)
- if((*i)->variable->scope==ATTRIBUTE && !(*i)->inlined)
- source += format("%s %s;\n", qualifier, (*i)->create_declaration());
- }
+ if(!(*i)->resolved_name.compare(0, 3, "gl_"))
+ continue;
- /* Any variables defined in vertex scope but referenced from fragment scope
- should be exported as varyings over the interface. */
- list<ShaderVariable *> varyings;
- for(list<ShaderVariable *>::const_iterator i=variables.begin(); i!=variables.end(); ++i)
- if(((*i)->variable->scope==VERTEX || (*i)->variable->scope==ATTRIBUTE) && (*i)->is_referenced_from(FRAGMENT))
+ InterfaceFlags interface = (*i)->get_interface_flags(scope);
+
+ if(interface&INPUT)
{
- varyings.push_back(*i);
- const char *qualifier;
- if(!features.legacy)
- qualifier = (scope==VERTEX ? "out" : "in");
- else
- qualifier = "varying";
- source += format("%s %s;\n", qualifier, (*i)->create_declaration('v'));
+ const char *qualifier = (features.legacy ? scope==VERTEX ? "attribute" : "varying" : "in");
+ source += format("%s %s;\n", qualifier, (*i)->create_declaration(interfaces[scope-1]));
}
- for(list<ShaderVariable *>::const_iterator i=variables.begin(); i!=variables.end(); ++i)
- if((*i)->referenced_by.empty() && (*i)->resolved_name.compare(0, 3, "gl_"))
- source += format("out %s;\n", (*i)->create_declaration());
+ if(interface&OUTPUT)
+ {
+ const char *qualifier = (features.legacy ? "varying" : "out");
+ source += format("%s %s;\n", qualifier, (*i)->create_declaration(interfaces[scope]));
+ }
+ }
source += "void main()\n{\n";
for(list<ShaderVariable *>::const_iterator i=variables.begin(); i!=variables.end(); ++i)
+ {
+ InterfaceFlags interface = (*i)->get_interface_flags(scope);
+
if((*i)->variable->scope==scope && !(*i)->inlined)
{
- source += '\t';
- if((*i)->referenced_by.empty())
- source += (*i)->resolved_name;
- else
- source += (*i)->create_declaration();
- source += format(" = %s;\n", (*i)->create_expression());
+ string decl = ((interface&GOAL) ? (*i)->resolved_name : (*i)->create_declaration());
+ source += format("\t%s = %s;\n", decl, (*i)->create_expression());
}
- if(scope==VERTEX)
- {
- for(list<ShaderVariable *>::const_iterator i=varyings.begin(); i!=varyings.end(); ++i)
+ if((interface&(OUTPUT|GOAL))==OUTPUT)
{
- if((*i)->inlined)
- source += format("\tv_%s = %s;\n", (*i)->resolved_name, (*i)->create_expression());
- else
- source += format("\tv_%s = %s;\n", (*i)->resolved_name, (*i)->resolved_name);
+ string expr = ((*i)->inlined ? (*i)->create_expression() : (*i)->resolved_name);
+ source += format("\t%c_%s = %s;\n", interfaces[scope], (*i)->resolved_name, expr);
}
}
return false;
}
+ProgramBuilder::InterfaceFlags ProgramBuilder::ShaderVariable::get_interface_flags(VariableScope scope) const
+{
+ /* Uniforms are available to all stages and are not passed through
+ interfaces */
+ if(variable->scope==UNIFORM)
+ return NO_INTERFACE;
+
+ int flags = NO_INTERFACE;
+
+ for(list<ShaderVariable *>::const_iterator i=referenced_by.begin(); i!=referenced_by.end(); ++i)
+ {
+ /* Variables used in a later scope than they are declared in need to go
+ through the interface */
+ if((*i)->variable->scope>scope && variable->scope<=scope)
+ flags |= OUTPUT;
+ if((*i)->variable->scope>=scope && variable->scope<scope)
+ if(!inlined || variable->scope!=ATTRIBUTE || scope!=VERTEX)
+ flags |= INPUT;
+ }
+
+ // Variables without any references are goals and also outputs.
+ if(referenced_by.empty() && variable->scope==scope)
+ flags |= OUTPUT|GOAL;
+
+ return static_cast<InterfaceFlags>(flags);
+}
+
string ProgramBuilder::ShaderVariable::create_declaration(char interface) const
{
if(variable->scope==UNIFORM)
string replacement = resolved_name;
if(variable)
{
- if(from_scope==FRAGMENT && (variable->scope==VERTEX || variable->scope==ATTRIBUTE))
- replacement = "v_"+replacement;
+ InterfaceFlags interface = get_interface_flags(from_scope);
+ if((interface&INPUT) && interfaces[from_scope-1])
+ replacement = format("%c_%s", interfaces[from_scope-1], replacement);
else if(inlined)
{
replacement = create_expression();