linker: Allow consumer stage or producer stage to be NULL
authorIan Romanick <ian.d.romanick@intel.com>
Fri, 14 Feb 2014 20:08:53 +0000 (12:08 -0800)
committerIan Romanick <ian.d.romanick@intel.com>
Fri, 2 May 2014 14:19:40 +0000 (07:19 -0700)
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>
src/glsl/link_varyings.cpp

index 9b5ae3e941095a658b1d7b037fb65a2c7e78ccff..898233205eb580e99292975149d474cc409fc877 100644 (file)
@@ -746,7 +746,10 @@ varying_matches::~varying_matches()
 void
 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
        * of fixed functionality), or it has already been recorded as part of a
        * previous match.
@@ -781,24 +784,28 @@ varying_matches::record(ir_variable *producer_var, ir_variable *consumer_var)
          realloc(this->matches,
                  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->compute_packing_class(producer_var);
+      = this->compute_packing_class(var);
    this->matches[this->num_matches].packing_order
-      = this->compute_packing_order(producer_var);
+      = this->compute_packing_order(var);
    if (this->disable_varying_packing) {
-      unsigned slots = producer_var->type->is_array()
-         ? (producer_var->type->length
-            * producer_var->type->fields.array->matrix_columns)
-         : producer_var->type->matrix_columns;
+      unsigned slots = var->type->is_array()
+         ? (var->type->length * var->type->fields.array->matrix_columns)
+         : var->type->matrix_columns;
       this->matches[this->num_matches].num_components = 4 * slots;
    } else {
       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].consumer_var = consumer_var;
    this->num_matches++;
-   producer_var->data.is_unmatched_generic_inout = 0;
+   if (producer_var)
+      producer_var->data.is_unmatched_generic_inout = 0;
    if (consumer_var)
       consumer_var->data.is_unmatched_generic_inout = 0;
 }
@@ -851,8 +858,11 @@ varying_matches::store_locations() const
       unsigned slot = generic_location / 4;
       unsigned offset = generic_location % 4;
 
-      producer_var->data.location = VARYING_SLOT_VAR0 + slot;
-      producer_var->data.location_frac = offset;
+      if (producer_var) {
+         producer_var->data.location = VARYING_SLOT_VAR0 + slot;
+         producer_var->data.location_frac = offset;
+      }
+
       if (consumer_var) {
          assert(consumer_var->data.location == -1);
          consumer_var->data.location = VARYING_SLOT_VAR0 + slot;
@@ -1164,20 +1174,29 @@ assign_varying_locations(struct gl_context *ctx,
       return false;
    }
 
-   foreach_list(node, producer->ir) {
-      ir_variable *const output_var = ((ir_instruction *) node)->as_variable();
+   if (producer) {
+      foreach_list(node, producer->ir) {
+         ir_variable *const output_var =
+            ((ir_instruction *) node)->as_variable();
 
-      if ((output_var == NULL) || (output_var->data.mode != ir_var_shader_out))
-        continue;
+         if ((output_var == NULL) ||
+             (output_var->data.mode != ir_var_shader_out))
+            continue;
+
+         tfeedback_candidate_generator g(mem_ctx, tfeedback_candidates);
+         g.process(output_var);
 
-      tfeedback_candidate_generator g(mem_ctx, tfeedback_candidates);
-      g.process(output_var);
+         ir_variable *const input_var =
+            linker::get_matching_input(mem_ctx, output_var, consumer_inputs,
+                                       consumer_interface_inputs);
 
-      ir_variable *const input_var =
-         linker::get_matching_input(mem_ctx, output_var, consumer_inputs,
-                                    consumer_interface_inputs);
-      if (input_var) {
-         matches.record(output_var, 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);
+         }
       }
    }
 
@@ -1225,15 +1244,17 @@ assign_varying_locations(struct gl_context *ctx,
        */
       assert(!ctx->Extensions.EXT_transform_feedback);
    } else {
-      lower_packed_varyings(mem_ctx, slots_used, ir_var_shader_out,
-                            0, producer);
+      if (producer) {
+         lower_packed_varyings(mem_ctx, slots_used, ir_var_shader_out,
+                               0, producer);
+      }
       if (consumer) {
          lower_packed_varyings(mem_ctx, slots_used, ir_var_shader_in,
                                gs_input_vertices, consumer);
       }
    }
 
-   if (consumer) {
+   if (consumer && producer) {
       foreach_list(node, consumer->ir) {
          ir_variable *const var = ((ir_instruction *) node)->as_variable();