glsl: cross validate varyings with a component qualifier
authorTimothy Arceri <timothy.arceri@collabora.com>
Thu, 17 Dec 2015 00:34:09 +0000 (11:34 +1100)
committerTimothy Arceri <timothy.arceri@collabora.com>
Sun, 1 May 2016 13:13:10 +0000 (23:13 +1000)
This change checks for component overlap, including handling overlap of
locations and components by doubles. Previously there was no validation
for assigning explicit locations to a location used by the second half
of a double.

V3: simplify handling of doubles and fix double component aliasing
detection

V2: fix component matching for matricies

Reviewed-by: Anuj Phogat <anuj.phogat@gmail.com>
Reviewed-by: Edward O'Callaghan <eocallaghan@alterapraxis.com>
Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
src/compiler/glsl/link_varyings.cpp

index c222ede9291b6b5bbe849cfb8f49592a55c4b996..34e82c71d5678eb5b7ad731b3d382decd805999a 100644 (file)
@@ -350,7 +350,7 @@ cross_validate_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, };
+   ir_variable *explicit_locations[MAX_VARYING][4] = { {NULL, NULL} };
 
    /* Find all shader outputs in the "producer" stage.
     */
@@ -371,18 +371,59 @@ cross_validate_outputs_to_inputs(struct gl_shader_program *prog,
          unsigned num_elements = type->count_attribute_slots(false);
          unsigned idx = var->data.location - VARYING_SLOT_VAR0;
          unsigned slot_limit = idx + num_elements;
+         unsigned last_comp;
+
+         if (var->type->without_array()->is_record()) {
+            /* The component qualifier can't be used on structs so just treat
+             * all component slots as used.
+             */
+            last_comp = 4;
+         } else {
+            unsigned dmul = var->type->is_double() ? 2 : 1;
+            last_comp = var->data.location_frac +
+               var->type->without_array()->vector_elements * dmul;
+         }
 
          while (idx < slot_limit) {
-            if (explicit_locations[idx] != NULL) {
-               linker_error(prog,
-                         "%s shader has multiple outputs explicitly "
-                         "assigned to location %d\n",
-                         _mesa_shader_stage_to_string(producer->Stage),
-                         idx);
-               return;
-            }
+            for (unsigned i = var->data.location_frac; i < last_comp; i++) {
+               if (explicit_locations[idx][i] != NULL) {
+                  linker_error(prog,
+                               "%s shader has multiple outputs explicitly "
+                               "assigned to location %d and component %d\n",
+                               _mesa_shader_stage_to_string(producer->Stage),
+                               idx, var->data.location_frac);
+                  return;
+               }
 
-            explicit_locations[idx] = var;
+               /* Make sure all component at this location have the same type.
+                */
+               for (unsigned j = 0; j < 4; j++) {
+                  if (explicit_locations[idx][j] &&
+                      (explicit_locations[idx][j]->type->without_array()
+                       ->base_type != var->type->without_array()->base_type)) {
+                     linker_error(prog,
+                                  "Varyings sharing the same location must "
+                                  "have the same underlying numerical type. "
+                                  "Location %u component %u\n", idx,
+                                  var->data.location_frac);
+                     return;
+                  }
+               }
+
+               explicit_locations[idx][i] = var;
+
+               /* We need to do some special handling for doubles as dvec3 and
+                * dvec4 consume two consecutive locations. We don't need to
+                * worry about components beginning at anything other than 0 as
+                * the spec does not allow this for dvec3 and dvec4.
+                */
+               if (i == 3 && last_comp > 4) {
+                  last_comp = last_comp - 4;
+                  /* Bump location index and reset the component index */
+                  idx++;
+                  i = 0;
+               }
+            }
             idx++;
          }
       }
@@ -439,7 +480,7 @@ cross_validate_outputs_to_inputs(struct gl_shader_program *prog,
             unsigned slot_limit = idx + num_elements;
 
             while (idx < slot_limit) {
-               output = explicit_locations[idx];
+               output = explicit_locations[idx][input->data.location_frac];
 
                if (output == NULL ||
                    input->data.location != output->data.location) {