glsl/linker: produce error when invalid explicit locations are used
authorIago Toral Quiroga <itoral@igalia.com>
Mon, 16 Oct 2017 10:43:52 +0000 (12:43 +0200)
committerIago Toral Quiroga <itoral@igalia.com>
Thu, 19 Oct 2017 09:27:12 +0000 (11:27 +0200)
We only need to add a check to validate output locations here. For
inputs with invalid locations we will fail to link when we can't
find a matching output in the same (invalid) location.

v2: compute location slots properly depending on shader stage and
    variable type / direction

Fixes:
KHR-GL45.enhanced_layouts.varying_location_limit

Reviewed-by: Nicolai Hähnle <nicolai.haehnle@amd.com>
src/compiler/glsl/link_varyings.cpp
src/compiler/glsl/link_varyings.h
src/compiler/glsl/linker.cpp

index 29842ecacda4e7fa1974495728241b4e0c2077a6..69c92bf53b05022bddcbcf0ef4bb780798e3d97e 100644 (file)
@@ -377,11 +377,38 @@ cross_validate_front_and_back_color(struct gl_shader_program *prog,
                                           consumer_stage, producer_stage);
 }
 
+static unsigned
+compute_variable_location_slot(ir_variable *var, gl_shader_stage stage)
+{
+   unsigned location_start = VARYING_SLOT_VAR0;
+
+   switch (stage) {
+      case MESA_SHADER_VERTEX:
+         if (var->data.mode == ir_var_shader_in)
+            location_start = VERT_ATTRIB_GENERIC0;
+         break;
+      case MESA_SHADER_TESS_CTRL:
+      case MESA_SHADER_TESS_EVAL:
+         if (var->data.patch)
+            location_start = VARYING_SLOT_PATCH0;
+         break;
+      case MESA_SHADER_FRAGMENT:
+         if (var->data.mode == ir_var_shader_out)
+            location_start = FRAG_RESULT_DATA0;
+         break;
+      default:
+         break;
+   }
+
+   return var->data.location - location_start;
+}
+
 /**
  * Validate that outputs from one stage match inputs of another
  */
 void
-cross_validate_outputs_to_inputs(struct gl_shader_program *prog,
+cross_validate_outputs_to_inputs(struct gl_context *ctx,
+                                 struct gl_shader_program *prog,
                                  gl_linked_shader *producer,
                                  gl_linked_shader *consumer)
 {
@@ -406,10 +433,19 @@ cross_validate_outputs_to_inputs(struct gl_shader_program *prog,
           */
          const glsl_type *type = get_varying_type(var, producer->Stage);
          unsigned num_elements = type->count_attribute_slots(false);
-         unsigned idx = var->data.location - VARYING_SLOT_VAR0;
+         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;
+         if (slot_limit > slot_max) {
+            linker_error(prog,
+                         "Invalid location %u in %s shader\n",
+                         idx, _mesa_shader_stage_to_string(producer->Stage));
+            return;
+         }
+
          if (type->without_array()->is_record()) {
             /* The component qualifier can't be used on structs so just treat
              * all component slots as used.
@@ -515,7 +551,8 @@ cross_validate_outputs_to_inputs(struct gl_shader_program *prog,
 
             const glsl_type *type = get_varying_type(input, consumer->Stage);
             unsigned num_elements = type->count_attribute_slots(false);
-            unsigned idx = input->data.location - VARYING_SLOT_VAR0;
+            unsigned idx =
+               compute_variable_location_slot(input, consumer->Stage);
             unsigned slot_limit = idx + num_elements;
 
             while (idx < slot_limit) {
index 4e1f6d2e42adf9f57c94a59b0618d6fe4ed6eb08..081b04ea38fc7604bcd20d86a4bc999e4d9f5c88 100644 (file)
@@ -300,7 +300,8 @@ link_varyings(struct gl_shader_program *prog, unsigned first, unsigned last,
               struct gl_context *ctx, void *mem_ctx);
 
 void
-cross_validate_outputs_to_inputs(struct gl_shader_program *prog,
+cross_validate_outputs_to_inputs(struct gl_context *ctx,
+                                 struct gl_shader_program *prog,
                                  gl_linked_shader *producer,
                                  gl_linked_shader *consumer);
 
index 03eb05bf637651aed1d0a7f44b1e027d28a61110..37983096784cb69f813642a6f7b701d6d68006d6 100644 (file)
@@ -4929,7 +4929,7 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
       if (!prog->data->LinkStatus)
          goto done;
 
-      cross_validate_outputs_to_inputs(prog,
+      cross_validate_outputs_to_inputs(ctx, prog,
                                        prog->_LinkedShaders[prev],
                                        prog->_LinkedShaders[i]);
       if (!prog->data->LinkStatus)