[Mesa-dev] [PATCH v2] glsl: disallow mixed varying types within a location

Ilia Mirkin imirkin at alum.mit.edu
Sat Sep 9 17:09:25 UTC 2017


The enhanced layouts spec has all kinds of restrictions about what can
and cannot be mixed in a location. Integer/float(/presumably double)
can't occupy a single location, interpolation has to be the same, as
well as auxiliary storage (including patch!).

The implication of this is ... don't specify explicit locations/components
if you want better packing, since the auto-packer doesn't care at all
about most of these restrictions. Sad. (Auto-packer, of course, also
can't always do its magic, e.g. SSO.)

This fixes:

KHR-GL45.enhanced_layouts.varying_location_aliasing_with_mixed_types
KHR-GL45.enhanced_layouts.varying_location_aliasing_with_mixed_interpolation
KHR-GL45.enhanced_layouts.varying_location_aliasing_with_mixed_auxiliary_storage

See https://github.com/KhronosGroup/OpenGL-API/issues/13 for some more
info, where I asked about patch vs non-patch locations.

Signed-off-by: Ilia Mirkin <imirkin at alum.mit.edu>
---

v1 -> v2: move to link_varyings.cpp, per tarceri

 src/compiler/glsl/link_varyings.cpp | 90 +++++++++++++++++++++++++++++++++++++
 1 file changed, 90 insertions(+)

diff --git a/src/compiler/glsl/link_varyings.cpp b/src/compiler/glsl/link_varyings.cpp
index 528506fd0eb..0aab083010e 100644
--- a/src/compiler/glsl/link_varyings.cpp
+++ b/src/compiler/glsl/link_varyings.cpp
@@ -2438,6 +2438,87 @@ check_against_input_limit(struct gl_context *ctx,
    return true;
 }
 
+static void
+check_location_mixing(struct gl_shader_program *prog,
+                      struct gl_linked_shader *shader)
+{
+   struct data_type {
+      // 0: unused, 1: float, 2: int, 3: 64-bit
+      unsigned var_type:2;
+      unsigned interpolation:2;
+      bool centroid:1;
+      bool sample:1;
+      bool patch:1;
+   } data_types[2][MAX_VARYING] = {};
+
+   foreach_in_list(ir_instruction, node, shader->ir) {
+      ir_variable *var = node->as_variable();
+      if (!var || !var->data.explicit_location)
+         continue;
+
+      if (var->data.mode != ir_var_shader_in &&
+          var->data.mode != ir_var_shader_out)
+         continue;
+
+      bool output = var->data.mode == ir_var_shader_out;
+      int var_slot;
+      if (!output && shader->Stage == MESA_SHADER_VERTEX) {
+         var_slot = var->data.location - VERT_ATTRIB_GENERIC0;
+         if (var_slot >= VERT_ATTRIB_GENERIC_MAX)
+            continue;
+      } else if (var->data.patch) {
+         var_slot = var->data.location - VARYING_SLOT_PATCH0;
+         if (var_slot >= MAX_VARYING)
+            continue;
+      } else {
+         var_slot = var->data.location - VARYING_SLOT_VAR0;
+         if (var_slot >= MAX_VARYING)
+            continue;
+      }
+
+      if (var_slot < 0)
+         continue;
+
+      const glsl_type *type = get_varying_type(var, shader->Stage);
+      const glsl_type *type_without_array = type->without_array();
+      unsigned num_elements = type->count_attribute_slots(false);
+      unsigned var_type;
+      if (glsl_base_type_is_64bit(type_without_array->base_type))
+         var_type = 3;
+      else if (glsl_base_type_is_integer(type_without_array->base_type))
+         var_type = 2;
+      else
+         var_type = 1;
+
+      const char *var_dir = output ? "out" : "in";
+
+      for (unsigned i = 0; i < num_elements; i++, var_slot++) {
+         data_type& existing = data_types[output][var_slot];
+
+         if (existing.var_type) {
+            if (existing.var_type != var_type)
+               linker_error(prog, "Mismatching %s varying types at location=%d",
+                            var_dir, var_slot);
+            if (existing.interpolation != var->data.interpolation)
+               linker_error(prog, "Mismatching %s varying interpolation at location=%d",
+                            var_dir, var_slot);
+            if (existing.centroid != var->data.centroid ||
+                existing.sample != var->data.sample ||
+                existing.patch != var->data.patch)
+               linker_error(prog, "Mismatching %s varying auxiliary storage at location=%d",
+                            var_dir, var_slot);
+         } else {
+            existing.var_type = var_type;
+            existing.interpolation = var->data.interpolation;
+            existing.centroid = var->data.centroid;
+            existing.sample = var->data.sample;
+            existing.patch = var->data.patch;
+         }
+      }
+   }
+}
+
+
 bool
 link_varyings(struct gl_shader_program *prog, unsigned first, unsigned last,
               struct gl_context *ctx, void *mem_ctx)
@@ -2447,6 +2528,15 @@ link_varyings(struct gl_shader_program *prog, unsigned first, unsigned last,
    char **varying_names = NULL;
    tfeedback_decl *tfeedback_decls = NULL;
 
+   /* Ensure that no illegal type/interp/storage mixing exists within
+    * explicitly-specified varying/attribute locations.
+    */
+   for (int i = MESA_SHADER_FRAGMENT - 1; i >= 0; i--)
+      if (prog->_LinkedShaders[i] != NULL)
+         check_location_mixing(prog, prog->_LinkedShaders[i]);
+   if (!prog->data->LinkStatus)
+      return false;
+
    /* From the ARB_enhanced_layouts spec:
     *
     *    "If the shader used to record output variables for transform feedback
-- 
2.13.5



More information about the mesa-dev mailing list