glsl/linker: refactor link-time validation of output locations
authorIago Toral Quiroga <itoral@igalia.com>
Thu, 19 Oct 2017 08:57:30 +0000 (10:57 +0200)
committerIago Toral Quiroga <itoral@igalia.com>
Thu, 26 Oct 2017 06:40:14 +0000 (08:40 +0200)
Move the checks for explicit locations to a separate function. We
will use this in a follow-up patch to validate locations for interface
variables where we need to validate each interface member rather than
the interface variable itself.

Reviewed-by: Timothy Arceri <tarceri@itsqueeze.com>
src/compiler/glsl/link_varyings.cpp

index cb9091d86b451769d8c4ffe63b7fd4a1ca14c498..d394488ab91a05c5fd6f774e687451410ffe4e22 100644 (file)
@@ -403,6 +403,75 @@ compute_variable_location_slot(ir_variable *var, gl_shader_stage stage)
    return var->data.location - location_start;
 }
 
+static bool
+check_location_aliasing(ir_variable *explicit_locations[][4],
+                        ir_variable *var,
+                        unsigned location,
+                        unsigned component,
+                        unsigned location_limit,
+                        const glsl_type *type,
+                        gl_shader_program *prog,
+                        gl_shader_stage stage)
+{
+   unsigned last_comp;
+   if (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 = type->without_array()->is_64bit() ? 2 : 1;
+      last_comp = component + type->without_array()->vector_elements * dmul;
+   }
+
+   while (location < location_limit) {
+      unsigned i = component;
+      while (i < last_comp) {
+         if (explicit_locations[location][i] != NULL) {
+            linker_error(prog,
+                         "%s shader has multiple outputs explicitly "
+                         "assigned to location %d and component %d\n",
+                         _mesa_shader_stage_to_string(stage),
+                         location, component);
+            return false;
+         }
+
+         /* Make sure all component at this location have the same type.
+          */
+         for (unsigned j = 0; j < 4; j++) {
+            if (explicit_locations[location][j] &&
+                (explicit_locations[location][j]->type->without_array()
+                 ->base_type != 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", location, component);
+               return false;
+            }
+         }
+
+         explicit_locations[location][i] = var;
+         i++;
+
+         /* 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 == 4 && last_comp > 4) {
+            last_comp = last_comp - 4;
+            /* Bump location index and reset the component index */
+            location++;
+            i = 0;
+         }
+      }
+
+      location++;
+   }
+
+   return true;
+}
+
 /**
  * Validate that outputs from one stage match inputs of another
  */
@@ -435,7 +504,6 @@ cross_validate_outputs_to_inputs(struct gl_context *ctx,
          unsigned num_elements = type->count_attribute_slots(false);
          unsigned idx = compute_variable_location_slot(var, producer->Stage);
          unsigned slot_limit = idx + num_elements;
-         unsigned last_comp;
 
          unsigned slot_max =
             ctx->Const.Program[producer->Stage].MaxOutputComponents / 4;
@@ -446,60 +514,10 @@ cross_validate_outputs_to_inputs(struct gl_context *ctx,
             return;
          }
 
-         if (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 = type->without_array()->is_64bit() ? 2 : 1;
-            last_comp = var->data.location_frac +
-               type->without_array()->vector_elements * dmul;
-         }
-
-         while (idx < slot_limit) {
-            unsigned i = var->data.location_frac;
-            while (i < last_comp) {
-               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;
-               }
-
-               /* 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 != 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;
-               i++;
-
-               /* 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 == 4 && last_comp > 4) {
-                  last_comp = last_comp - 4;
-                  /* Bump location index and reset the component index */
-                  idx++;
-                  i = 0;
-               }
-            }
-            idx++;
+         if (!check_location_aliasing(explicit_locations, var, idx,
+                                      var->data.location_frac, slot_limit,
+                                      type, prog, producer->Stage)) {
+            return;
          }
       }
    }