glsl/linker: outputs in the same location must share interpolation
authorIago Toral Quiroga <itoral@igalia.com>
Thu, 19 Oct 2017 14:13:21 +0000 (16:13 +0200)
committerIago Toral Quiroga <itoral@igalia.com>
Thu, 26 Oct 2017 06:40:14 +0000 (08:40 +0200)
From ARB_enhanced_layouts:

"[...]when location aliasing, the aliases sharing the location
 must have the same underlying numerical type (floating-point or
 integer) and the same auxiliary storage and
 interpolation qualification.[...]"

Add code to the linker to validate that aliased locations do
have the same interpolation.

Fixes:
KHR-GL45.enhanced_layouts.varying_location_aliasing_with_mixed_interpolation

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

index 1db851b7e9d4780ef7263cfcca208433cf7eef1b..954275460078842b08255645e7ccc557e4e53a2d 100644 (file)
@@ -406,6 +406,7 @@ compute_variable_location_slot(ir_variable *var, gl_shader_stage stage)
 struct explicit_location_info {
    ir_variable *var;
    unsigned base_type;
+   unsigned interpolation;
 };
 
 static bool
@@ -415,6 +416,7 @@ check_location_aliasing(struct explicit_location_info explicit_locations[][4],
                         unsigned component,
                         unsigned location_limit,
                         const glsl_type *type,
+                        unsigned interpolation,
                         gl_shader_program *prog,
                         gl_shader_stage stage)
 {
@@ -431,6 +433,38 @@ check_location_aliasing(struct explicit_location_info explicit_locations[][4],
 
    while (location < location_limit) {
       unsigned i = component;
+
+      /* If there are other outputs assigned to the same location
+       * they must have the same interpolation
+       */
+      unsigned comp = 0;
+      while (comp < 4) {
+         /* Skip the components used by this output, we only care about
+         * other outputs in the same location
+          */
+         if (comp == i) {
+            comp = last_comp;
+            continue;
+         }
+
+         struct explicit_location_info *info =
+            &explicit_locations[location][comp];
+
+         if (info->var) {
+            if (info->interpolation != interpolation) {
+               linker_error(prog,
+                            "%s shader has multiple outputs at explicit "
+                            "location %u with different interpolation "
+                            "settings\n",
+                            _mesa_shader_stage_to_string(stage), location);
+               return false;
+            }
+         }
+
+         comp++;
+      }
+
+      /* Component aliasing is not allowed */
       while (i < last_comp) {
          if (explicit_locations[location][i].var != NULL) {
             linker_error(prog,
@@ -458,6 +492,7 @@ check_location_aliasing(struct explicit_location_info explicit_locations[][4],
          explicit_locations[location][i].var = var;
          explicit_locations[location][i].base_type =
             type->without_array()->base_type;
+         explicit_locations[location][i].interpolation = interpolation;
          i++;
 
          /* We need to do some special handling for doubles as dvec3 and
@@ -526,18 +561,20 @@ cross_validate_outputs_to_inputs(struct gl_context *ctx,
                unsigned field_location = type->fields.structure[i].location -
                   (type->fields.structure[i].patch ? VARYING_SLOT_PATCH0 :
                                                      VARYING_SLOT_VAR0);
+               unsigned interpolation = type->fields.structure[i].interpolation;
                if (!check_location_aliasing(explicit_locations, var,
                                             field_location,
                                             0, field_location + 1,
-                                            field_type, prog,
-                                            producer->Stage)) {
+                                            field_type, interpolation,
+                                            prog, producer->Stage)) {
                   return;
                }
             }
          } else if (!check_location_aliasing(explicit_locations, var,
                                              idx, var->data.location_frac,
-                                             slot_limit, type, prog,
-                                             producer->Stage)) {
+                                             slot_limit, type,
+                                             var->data.interpolation,
+                                             prog, producer->Stage)) {
             return;
          }
       }