mesa: Strip arrayness from interface block names in some IO validation
authorIan Romanick <ian.d.romanick@intel.com>
Fri, 10 Jun 2016 15:01:30 +0000 (08:01 -0700)
committerIan Romanick <ian.d.romanick@intel.com>
Tue, 5 Jul 2016 23:58:27 +0000 (16:58 -0700)
Outputs from the vertex shader need to be able to match
per-vertex-arrayed inputs of later stages.  Acomplish this by stripping
one level of arrayness from the names and types of outputs going to a
per-vertex-arrayed stage.

v2: Add missing checks for TESS_EVAL->GEOMETRY.  Noticed by Timothy
Arceri.

v3: Use a slightly simpler stage check suggested by Ilia.

Signed-off-by: Ian Romanick <ian.d.romanick@intel.com>
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=96358
Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
Cc: "12.0" <mesa-stable@lists.freedesktop.org>
Cc: Gregory Hainaut <gregory.hainaut@gmail.com>
Cc: Ilia Mirkin <imirkin@alum.mit.edu>
src/mesa/main/shader_query.cpp

index a2a93b16d4ef58f253f77c9fd246efde11fc800b..0eae39a3557255df1238d6ff65a751259b175569 100644 (file)
@@ -1386,13 +1386,24 @@ _mesa_get_program_resourceiv(struct gl_shader_program *shProg,
 
 static bool
 validate_io(struct gl_shader_program *producer,
-            struct gl_shader_program *consumer)
+            struct gl_shader_program *consumer,
+            gl_shader_stage producer_stage,
+            gl_shader_stage consumer_stage)
 {
    if (producer == consumer)
       return true;
 
+   const bool nonarray_stage_to_array_stage =
+      producer_stage != MESA_SHADER_TESS_CTRL &&
+      (consumer_stage == MESA_SHADER_GEOMETRY ||
+       consumer_stage == MESA_SHADER_TESS_CTRL ||
+       consumer_stage == MESA_SHADER_TESS_EVAL);
+
    bool valid = true;
 
+   void *name_buffer = NULL;
+   size_t name_buffer_size = 0;
+
    gl_shader_variable const **outputs =
       (gl_shader_variable const **) calloc(producer->NumProgramResourceList,
                                            sizeof(gl_shader_variable *));
@@ -1464,11 +1475,52 @@ validate_io(struct gl_shader_program *producer,
             }
          }
       } else {
+         char *consumer_name = consumer_var->name;
+
+         if (nonarray_stage_to_array_stage &&
+             consumer_var->interface_type != NULL &&
+             consumer_var->interface_type->is_array() &&
+             !is_gl_identifier(consumer_var->name)) {
+            const size_t name_len = strlen(consumer_var->name);
+
+            if (name_len >= name_buffer_size) {
+               free(name_buffer);
+
+               name_buffer_size = name_len + 1;
+               name_buffer = malloc(name_buffer_size);
+               if (name_buffer == NULL) {
+                  valid = false;
+                  goto out;
+               }
+            }
+
+            consumer_name = (char *) name_buffer;
+
+            char *s = strchr(consumer_var->name, '[');
+            if (s == NULL) {
+               valid = false;
+               goto out;
+            }
+
+            char *t = strchr(s, ']');
+            if (t == NULL) {
+               valid = false;
+               goto out;
+            }
+
+            assert(t[1] == '.' || t[1] == '[');
+
+            const ptrdiff_t base_name_len = s - consumer_var->name;
+
+            memcpy(consumer_name, consumer_var->name, base_name_len);
+            strcpy(consumer_name + base_name_len, t + 1);
+         }
+
          for (unsigned j = 0; j < num_outputs; j++) {
             const gl_shader_variable *const var = outputs[j];
 
             if (!var->explicit_location &&
-                strcmp(consumer_var->name, var->name) == 0) {
+                strcmp(consumer_name, var->name) == 0) {
                producer_var = var;
                match_index = j;
                break;
@@ -1530,25 +1582,53 @@ validate_io(struct gl_shader_program *producer,
        * Note that location mismatches are detected by the loops above that
        * find the producer variable that goes with the consumer variable.
        */
-      if (producer_var->type != consumer_var->type ||
-          producer_var->interpolation != consumer_var->interpolation ||
-          producer_var->precision != consumer_var->precision) {
+      if (nonarray_stage_to_array_stage) {
+         if (!consumer_var->type->is_array() ||
+             consumer_var->type->fields.array != producer_var->type) {
+            valid = false;
+            goto out;
+         }
+
+         if (consumer_var->interface_type != NULL) {
+            if (!consumer_var->interface_type->is_array() ||
+                consumer_var->interface_type->fields.array != producer_var->interface_type) {
+               valid = false;
+               goto out;
+            }
+         } else if (producer_var->interface_type != NULL) {
+            valid = false;
+            goto out;
+         }
+      } else {
+         if (producer_var->type != consumer_var->type) {
+            valid = false;
+            goto out;
+         }
+
+         if (producer_var->interface_type != consumer_var->interface_type) {
+            valid = false;
+            goto out;
+         }
+      }
+
+      if (producer_var->interpolation != consumer_var->interpolation) {
          valid = false;
          goto out;
       }
 
-      if (producer_var->outermost_struct_type != consumer_var->outermost_struct_type) {
+      if (producer_var->precision != consumer_var->precision) {
          valid = false;
          goto out;
       }
 
-      if (producer_var->interface_type != consumer_var->interface_type) {
+      if (producer_var->outermost_struct_type != consumer_var->outermost_struct_type) {
          valid = false;
          goto out;
       }
    }
 
  out:
+   free(name_buffer);
    free(outputs);
    return valid && num_outputs == 0;
 }
@@ -1580,7 +1660,9 @@ _mesa_validate_pipeline_io(struct gl_pipeline_object *pipeline)
          if (shProg[idx]->_LinkedShaders[idx]->Stage == MESA_SHADER_COMPUTE)
             break;
 
-         if (!validate_io(shProg[prev], shProg[idx]))
+         if (!validate_io(shProg[prev], shProg[idx],
+                          shProg[prev]->_LinkedShaders[prev]->Stage,
+                          shProg[idx]->_LinkedShaders[idx]->Stage))
             return false;
 
          prev = idx;