glsl: optimise inputs/outputs with explicit locations

This change allows used defined inputs/outputs with explicit locations
to be removed if they are detected to not be used between shaders
at link time.

To enable this we change the is_unmatched_generic_inout field to be
flagged when we have a user defined varying. Previously
explicit_location was assumed to be set only in builtins however SSO
allows the user to set an explicit location.

We then add a function to match explicit locations between shaders.

V2: call match_explicit_outputs_to_inputs() after
is_unmatched_generic_inout has been initialised.

Cc: Gregory Hainaut <gregory.hainaut@gmail.com>
Reviewed-by: Tapani Pälli <tapani.palli@intel.com>
This commit is contained in:
Timothy Arceri 2015-11-21 12:47:25 +11:00
parent 4d64459a92
commit 12ba6cfba7
2 changed files with 74 additions and 14 deletions

View file

@ -896,8 +896,10 @@ varying_matches::record(ir_variable *producer_var, ir_variable *consumer_var)
{ {
assert(producer_var != NULL || consumer_var != NULL); assert(producer_var != NULL || consumer_var != NULL);
if ((producer_var && !producer_var->data.is_unmatched_generic_inout) if ((producer_var && (!producer_var->data.is_unmatched_generic_inout ||
|| (consumer_var && !consumer_var->data.is_unmatched_generic_inout)) { producer_var->data.explicit_location)) ||
(consumer_var && (!consumer_var->data.is_unmatched_generic_inout ||
consumer_var->data.explicit_location))) {
/* Either a location already exists for this variable (since it is part /* Either a location already exists for this variable (since it is part
* of fixed functionality), or it has already been recorded as part of a * of fixed functionality), or it has already been recorded as part of a
* previous match. * previous match.

View file

@ -631,20 +631,12 @@ link_invalidate_variable_locations(exec_list *ir)
/* ir_variable::is_unmatched_generic_inout is used by the linker while /* ir_variable::is_unmatched_generic_inout is used by the linker while
* connecting outputs from one stage to inputs of the next stage. * connecting outputs from one stage to inputs of the next stage.
*
* There are two implicit assumptions here. First, we assume that any
* built-in variable (i.e., non-generic in or out) will have
* explicit_location set. Second, we assume that any generic in or out
* will not have explicit_location set.
*
* This second assumption will only be valid until
* GL_ARB_separate_shader_objects is supported. When that extension is
* implemented, this function will need some modifications.
*/ */
if (!var->data.explicit_location) { if (var->data.explicit_location &&
var->data.is_unmatched_generic_inout = 1; var->data.location < VARYING_SLOT_VAR0) {
} else {
var->data.is_unmatched_generic_inout = 0; var->data.is_unmatched_generic_inout = 0;
} else {
var->data.is_unmatched_generic_inout = 1;
} }
} }
} }
@ -2421,6 +2413,7 @@ assign_attribute_or_color_locations(gl_shader_program *prog,
continue; continue;
if (var->data.explicit_location) { if (var->data.explicit_location) {
var->data.is_unmatched_generic_inout = 0;
if ((var->data.location >= (int)(max_index + generic_base)) if ((var->data.location >= (int)(max_index + generic_base))
|| (var->data.location < 0)) { || (var->data.location < 0)) {
linker_error(prog, linker_error(prog,
@ -2690,6 +2683,61 @@ assign_attribute_or_color_locations(gl_shader_program *prog,
return true; return true;
} }
/**
* Match explicit locations of outputs to inputs and deactivate the
* unmatch flag if found so we don't optimise them away.
*/
void
match_explicit_outputs_to_inputs(struct gl_shader_program *prog,
gl_shader *producer,
gl_shader *consumer)
{
glsl_symbol_table parameters;
ir_variable *explicit_locations[MAX_VARYING] = { NULL };
/* Find all shader outputs in the "producer" stage.
*/
foreach_in_list(ir_instruction, node, producer->ir) {
ir_variable *const var = node->as_variable();
if ((var == NULL) || (var->data.mode != ir_var_shader_out))
continue;
/* Mark output as matched if separate shader with no linked consumer */
if (consumer == NULL)
var->data.is_unmatched_generic_inout = 0;
if (var->data.explicit_location &&
var->data.location >= VARYING_SLOT_VAR0) {
const unsigned idx = var->data.location - VARYING_SLOT_VAR0;
if (explicit_locations[idx] == NULL)
explicit_locations[idx] = var;
}
}
/* Match inputs to outputs */
foreach_in_list(ir_instruction, node, consumer->ir) {
ir_variable *const input = node->as_variable();
if ((input == NULL) || (input->data.mode != ir_var_shader_in))
continue;
/* Mark input as matched if separate shader with no linked producer */
if (producer == NULL)
input->data.is_unmatched_generic_inout = 0;
ir_variable *output = NULL;
if (input->data.explicit_location
&& input->data.location >= VARYING_SLOT_VAR0) {
output = explicit_locations[input->data.location - VARYING_SLOT_VAR0];
if (output != NULL){
input->data.is_unmatched_generic_inout = 0;
output->data.is_unmatched_generic_inout = 0;
}
}
}
}
/** /**
* Demote shader inputs and outputs that are not used in other stages * Demote shader inputs and outputs that are not used in other stages
@ -4258,6 +4306,16 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
} }
} }
prev = first;
for (unsigned i = prev + 1; i <= MESA_SHADER_FRAGMENT; i++) {
if (prog->_LinkedShaders[i] == NULL)
continue;
match_explicit_outputs_to_inputs(prog, prog->_LinkedShaders[prev],
prog->_LinkedShaders[i]);
prev = i;
}
if (!assign_attribute_or_color_locations(prog, &ctx->Const, if (!assign_attribute_or_color_locations(prog, &ctx->Const,
MESA_SHADER_VERTEX)) { MESA_SHADER_VERTEX)) {
goto done; goto done;