glsl: allow any l-value of an input variable as interpolant in interpolateAt*
authorNicolai Hähnle <nicolai.haehnle@amd.com>
Wed, 14 Jun 2017 10:43:10 +0000 (12:43 +0200)
committerNicolai Hähnle <nicolai.haehnle@amd.com>
Fri, 3 Nov 2017 13:30:08 +0000 (14:30 +0100)
The intended rule has been clarified in GLSL 4.60, Section 8.13.2
(Interpolation Functions):

   "For all of the interpolation functions, interpolant must be an l-value
    from an in declaration; this can include a variable, a block or
    structure member, an array element, or some combination of these.
    Component selection operators (e.g., .xy) may be used when specifying
    interpolant."

For members of interface blocks, var->data.must_be_shader_input must be
determined on-the-fly after lowering interface blocks, since we don't want
to disable varying packing for an entire block just because one input in it
is used in interpolateAt*.

v2: keep setting must_be_shader_input in ast_function (Ian)
v3: follow the relaxed rule of GLSL 4.60
v4: only apply the relaxed rules to desktop GL
    (the ES WG decided that the relaxed rules may apply in a future version
     but not retroactively; see also
     dEQP-GLES31.functional.shaders.multisample_interpolation.interpolate_at_centroid.negative.*)

Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=101378
Reviewed-by: Ian Romanick <ian.d.romanick@intel.com> (v1)
Reviewed-by: Timothy Arceri <tarceri@itsqueeze.com>
src/compiler/glsl/ast_function.cpp
src/compiler/glsl/lower_named_interface_blocks.cpp

index 46a61e4..d1596c2 100644 (file)
@@ -227,19 +227,28 @@ verify_parameter_modes(_mesa_glsl_parse_state *state,
             val = ((ir_swizzle *)val)->val;
          }
 
-         while (val->ir_type == ir_type_dereference_array) {
-            val = ((ir_dereference_array *)val)->array;
+         for (;;) {
+            if (val->ir_type == ir_type_dereference_array) {
+               val = ((ir_dereference_array *)val)->array;
+            } else if (val->ir_type == ir_type_dereference_record &&
+                       !state->es_shader) {
+               val = ((ir_dereference_record *)val)->record;
+            } else
+               break;
          }
 
-         if (!val->as_dereference_variable() ||
-             val->variable_referenced()->data.mode != ir_var_shader_in) {
+         ir_variable *var = NULL;
+         if (const ir_dereference_variable *deref_var = val->as_dereference_variable())
+            var = deref_var->variable_referenced();
+
+         if (!var || var->data.mode != ir_var_shader_in) {
             _mesa_glsl_error(&loc, state,
                              "parameter `%s` must be a shader input",
                              formal->name);
             return false;
          }
 
-         val->variable_referenced()->data.must_be_shader_input = 1;
+         var->data.must_be_shader_input = 1;
       }
 
       /* Verify that 'out' and 'inout' actual parameters are lvalues. */
index 0646941..136352a 100644 (file)
@@ -115,6 +115,7 @@ public:
    void run(exec_list *instructions);
 
    virtual ir_visitor_status visit_leave(ir_assignment *);
+   virtual ir_visitor_status visit_leave(ir_expression *);
    virtual void handle_rvalue(ir_rvalue **rvalue);
 };
 
@@ -238,6 +239,23 @@ flatten_named_interface_blocks_declarations::visit_leave(ir_assignment *ir)
    return rvalue_visit(ir);
 }
 
+ir_visitor_status
+flatten_named_interface_blocks_declarations::visit_leave(ir_expression *ir)
+{
+   ir_visitor_status status = rvalue_visit(ir);
+
+   if (ir->operation == ir_unop_interpolate_at_centroid ||
+       ir->operation == ir_binop_interpolate_at_offset ||
+       ir->operation == ir_binop_interpolate_at_sample) {
+      const ir_rvalue *val = ir->operands[0];
+
+      /* This disables varying packing for this input. */
+      val->variable_referenced()->data.must_be_shader_input = 1;
+   }
+
+   return status;
+}
+
 void
 flatten_named_interface_blocks_declarations::handle_rvalue(ir_rvalue **rvalue)
 {