linker: Allow consumer stage or producer stage to be NULL

When linking a separable program that contains only a fragment shader,
the producer will be NULL.  Similar cases will exist with geometry
shaders and, eventually, tessellation shaders.

Signed-off-by: Ian Romanick <ian.d.romanick@intel.com>
Reviewed-by: Eric Anholt <eric@anholt.net>
This commit is contained in:
Ian Romanick
2014-02-14 12:08:53 -08:00
parent fe37cb0ac6
commit 7d73c3e99e

View File

@@ -746,7 +746,10 @@ varying_matches::~varying_matches()
void void
varying_matches::record(ir_variable *producer_var, ir_variable *consumer_var) varying_matches::record(ir_variable *producer_var, ir_variable *consumer_var)
{ {
if (!producer_var->data.is_unmatched_generic_inout) { assert(producer_var != NULL || consumer_var != NULL);
if ((producer_var && !producer_var->data.is_unmatched_generic_inout)
|| (consumer_var && !consumer_var->data.is_unmatched_generic_inout)) {
/* 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.
@@ -781,23 +784,27 @@ varying_matches::record(ir_variable *producer_var, ir_variable *consumer_var)
realloc(this->matches, realloc(this->matches,
sizeof(*this->matches) * this->matches_capacity); sizeof(*this->matches) * this->matches_capacity);
} }
const ir_variable *const var = (producer_var != NULL)
? producer_var : consumer_var;
this->matches[this->num_matches].packing_class this->matches[this->num_matches].packing_class
= this->compute_packing_class(producer_var); = this->compute_packing_class(var);
this->matches[this->num_matches].packing_order this->matches[this->num_matches].packing_order
= this->compute_packing_order(producer_var); = this->compute_packing_order(var);
if (this->disable_varying_packing) { if (this->disable_varying_packing) {
unsigned slots = producer_var->type->is_array() unsigned slots = var->type->is_array()
? (producer_var->type->length ? (var->type->length * var->type->fields.array->matrix_columns)
* producer_var->type->fields.array->matrix_columns) : var->type->matrix_columns;
: producer_var->type->matrix_columns;
this->matches[this->num_matches].num_components = 4 * slots; this->matches[this->num_matches].num_components = 4 * slots;
} else { } else {
this->matches[this->num_matches].num_components this->matches[this->num_matches].num_components
= producer_var->type->component_slots(); = var->type->component_slots();
} }
this->matches[this->num_matches].producer_var = producer_var; this->matches[this->num_matches].producer_var = producer_var;
this->matches[this->num_matches].consumer_var = consumer_var; this->matches[this->num_matches].consumer_var = consumer_var;
this->num_matches++; this->num_matches++;
if (producer_var)
producer_var->data.is_unmatched_generic_inout = 0; producer_var->data.is_unmatched_generic_inout = 0;
if (consumer_var) if (consumer_var)
consumer_var->data.is_unmatched_generic_inout = 0; consumer_var->data.is_unmatched_generic_inout = 0;
@@ -851,8 +858,11 @@ varying_matches::store_locations() const
unsigned slot = generic_location / 4; unsigned slot = generic_location / 4;
unsigned offset = generic_location % 4; unsigned offset = generic_location % 4;
if (producer_var) {
producer_var->data.location = VARYING_SLOT_VAR0 + slot; producer_var->data.location = VARYING_SLOT_VAR0 + slot;
producer_var->data.location_frac = offset; producer_var->data.location_frac = offset;
}
if (consumer_var) { if (consumer_var) {
assert(consumer_var->data.location == -1); assert(consumer_var->data.location == -1);
consumer_var->data.location = VARYING_SLOT_VAR0 + slot; consumer_var->data.location = VARYING_SLOT_VAR0 + slot;
@@ -1164,10 +1174,13 @@ assign_varying_locations(struct gl_context *ctx,
return false; return false;
} }
if (producer) {
foreach_list(node, producer->ir) { foreach_list(node, producer->ir) {
ir_variable *const output_var = ((ir_instruction *) node)->as_variable(); ir_variable *const output_var =
((ir_instruction *) node)->as_variable();
if ((output_var == NULL) || (output_var->data.mode != ir_var_shader_out)) if ((output_var == NULL) ||
(output_var->data.mode != ir_var_shader_out))
continue; continue;
tfeedback_candidate_generator g(mem_ctx, tfeedback_candidates); tfeedback_candidate_generator g(mem_ctx, tfeedback_candidates);
@@ -1176,10 +1189,16 @@ assign_varying_locations(struct gl_context *ctx,
ir_variable *const input_var = ir_variable *const input_var =
linker::get_matching_input(mem_ctx, output_var, consumer_inputs, linker::get_matching_input(mem_ctx, output_var, consumer_inputs,
consumer_interface_inputs); consumer_interface_inputs);
if (input_var) {
/* If a matching input variable was found, add this ouptut (and the
* input) to the set. If this is a separable program and there is no
* consumer stage, add the output.
*/
if (input_var || (prog->SeparateShader && consumer == NULL)) {
matches.record(output_var, input_var); matches.record(output_var, input_var);
} }
} }
}
for (unsigned i = 0; i < num_tfeedback_decls; ++i) { for (unsigned i = 0; i < num_tfeedback_decls; ++i) {
if (!tfeedback_decls[i].is_varying()) if (!tfeedback_decls[i].is_varying())
@@ -1225,15 +1244,17 @@ assign_varying_locations(struct gl_context *ctx,
*/ */
assert(!ctx->Extensions.EXT_transform_feedback); assert(!ctx->Extensions.EXT_transform_feedback);
} else { } else {
if (producer) {
lower_packed_varyings(mem_ctx, slots_used, ir_var_shader_out, lower_packed_varyings(mem_ctx, slots_used, ir_var_shader_out,
0, producer); 0, producer);
}
if (consumer) { if (consumer) {
lower_packed_varyings(mem_ctx, slots_used, ir_var_shader_in, lower_packed_varyings(mem_ctx, slots_used, ir_var_shader_in,
gs_input_vertices, consumer); gs_input_vertices, consumer);
} }
} }
if (consumer) { if (consumer && producer) {
foreach_list(node, consumer->ir) { foreach_list(node, consumer->ir) {
ir_variable *const var = ((ir_instruction *) node)->as_variable(); ir_variable *const var = ((ir_instruction *) node)->as_variable();