mesa: fix interface matching done in validate_io
authorTapani Pälli <tapani.palli@intel.com>
Wed, 16 Dec 2015 06:24:52 +0000 (08:24 +0200)
committerTapani Pälli <tapani.palli@intel.com>
Tue, 22 Dec 2015 12:50:25 +0000 (14:50 +0200)
Patch makes following changes for interface matching:

   - do not try to match builtin variables
   - handle swizzle in input name, as example 'a.z' should
     match with 'a'
   - add matching by location
   - check that amount of inputs and outputs matches

These changes make interface matching tests to work in:
   ES31-CTS.sepshaderobjs.StateInteraction

The test still does not pass completely due to errors in rendering
output. IMO this is unrelated to interface matching.

Note that type matching is not done due to varying packing which
changes type of variable, this can be added later on. Preferably
when we have quicker way to iterate resources and have a complete
list of all existed varyings (before packing) available.

v2: add spec reference, return true on desktop since we do not
    have failing cases for it, inputs and outputs amount do not
    need to match on desktop.

v3: add some more spec reference, remove desktop specifics since
    not used for now on desktop, add match by location qualifier,
    rename input_stage and output_stage as producer and consumer
    as suggested by Timothy.

Signed-off-by: Tapani Pälli <tapani.palli@intel.com>
Reviewed-by: Timothy Arceri <timothy.arceri@collabora.com>
src/mesa/main/shader_query.cpp

index ced10a93b1da4e6f4a19c0cd9689a312b1b23342..e526119db1928969b5cc81b8699bad1e1868a1c1 100644 (file)
@@ -1373,46 +1373,107 @@ _mesa_get_program_resourceiv(struct gl_shader_program *shProg,
 }
 
 static bool
-validate_io(const struct gl_shader *input_stage,
-            const struct gl_shader *output_stage, bool isES)
+validate_io(const struct gl_shader *producer,
+            const struct gl_shader *consumer, bool isES)
 {
-   assert(input_stage && output_stage);
+   assert(producer && consumer);
+   unsigned inputs = 0, outputs = 0;
+
+   /* From OpenGL ES 3.1 spec (Interface matching):
+    *
+    *    "An output variable is considered to match an input variable in the
+    *    subsequent shader if:
+    *
+    *    - the two variables match in name, type, and qualification; or
+    *    - the two variables are declared with the same location qualifier and
+    *      match in type and qualification.
+    *
+    *    ...
+    *
+    *    At an interface between program objects, the set of inputs and outputs
+    *    are considered to match exactly if and only if:
+    *
+    *    - Every declared input variable has a matching output, as described
+    *    above.
+    *
+    *    - There are no user-defined output variables declared without a
+    *    matching input variable declaration.
+    *
+    *    - All matched input and output variables have identical precision
+    *    qualification.
+    *
+    *    When the set of inputs and outputs on an interface between programs
+    *    matches exactly, all inputs are well-defined except when the
+    *    corresponding outputs were not written in the previous shader. However,
+    *    any mismatch between inputs and outputs will result in a validation
+    *    failure."
+    *
+    * OpenGL Core 4.5 spec includes same paragraph as above but without check
+    * for precision and the last 'validation failure' clause. Therefore
+    * behaviour is more relaxed, input and output amount is not required by the
+    * spec to be validated.
+    *
+    * FIXME: Update once Khronos spec bug #15331 is resolved.
+    * FIXME: Add validation by type, currently information loss during varying
+    * packing makes this challenging.
+    */
+
+   /* Currently no matching done for desktop. */
+   if (!isES)
+      return true;
 
    /* For each output in a, find input in b and do any required checks. */
-   foreach_in_list(ir_instruction, out, input_stage->ir) {
+   foreach_in_list(ir_instruction, out, producer->ir) {
       ir_variable *out_var = out->as_variable();
-      if (!out_var || out_var->data.mode != ir_var_shader_out)
+      if (!out_var || out_var->data.mode != ir_var_shader_out ||
+          is_gl_identifier(out_var->name))
          continue;
 
-      foreach_in_list(ir_instruction, in, output_stage->ir) {
+      outputs++;
+
+      inputs = 0;
+      foreach_in_list(ir_instruction, in, consumer->ir) {
          ir_variable *in_var = in->as_variable();
-         if (!in_var || in_var->data.mode != ir_var_shader_in)
+         if (!in_var || in_var->data.mode != ir_var_shader_in ||
+             is_gl_identifier(in_var->name))
+            continue;
+
+         inputs++;
+
+         /* Match by location qualifier and precision.
+          *
+          * FIXME: Add explicit location matching validation here. Be careful
+          * not to match varyings with explicit locations to varyings without
+          * explicit locations.
+          */
+         if ((in_var->data.explicit_location &&
+             out_var->data.explicit_location) &&
+             in_var->data.location == out_var->data.location &&
+             in_var->data.precision == out_var->data.precision)
             continue;
 
-         if (strcmp(in_var->name, out_var->name) == 0) {
-            /* Since we now only validate precision, we can skip this step for
-             * desktop GLSL shaders, there precision qualifier is ignored.
-             *
-             * From OpenGL 4.50 Shading Language spec, section 4.7:
-             *     "For the purposes of determining if an output from one
-             *     shader stage matches an input of the next stage, the
-             *     precision qualifier need not match."
+         unsigned len = strlen(in_var->name);
+
+         /* Handle input swizzle in variable name. */
+         const char *dot = strchr(in_var->name, '.');
+         if (dot)
+            len = dot - in_var->name;
+
+         /* Match by name and precision. */
+         if (strncmp(in_var->name, out_var->name, len) == 0) {
+            /* From OpenGL ES 3.1 spec:
+             *     "When both shaders are in separate programs, mismatched
+             *     precision qualifiers will result in a program interface
+             *     mismatch that will result in program pipeline validation
+             *     failures, as described in section 7.4.1 (“Shader Interface
+             *     Matching”) of the OpenGL ES 3.1 Specification."
              */
-            if (isES) {
-               /* From OpenGL ES 3.1 spec:
-                *     "When both shaders are in separate programs, mismatched
-                *     precision qualifiers will result in a program interface
-                *     mismatch that will result in program pipeline validation
-                *     failures, as described in section 7.4.1 (“Shader Interface
-                *     Matching”) of the OpenGL ES 3.1 Specification."
-                */
-               if (in_var->data.precision != out_var->data.precision)
-                  return false;
-            }
+            if (in_var->data.precision != out_var->data.precision)
+               return false;
          }
       }
    }
-   return true;
+   return inputs == outputs;
 }
 
 /**