glsl: fix array assignments of a swizzled vector
authorIlia Mirkin <imirkin@alum.mit.edu>
Fri, 5 Oct 2018 06:18:20 +0000 (02:18 -0400)
committerIlia Mirkin <imirkin@alum.mit.edu>
Mon, 8 Oct 2018 18:29:14 +0000 (14:29 -0400)
This happens in situations where we might do

  vec.wzyx[i] = ...

The swizzle would get effectively ignored because of the interaction
between how ir_assignment->set_lhs works and overwriting the write_mask.
There are two cases, one where i is a constant, and another where i is
variable. We have to be extra-careful in both cases.

Fixes the following WebGL test:

  https://www.khronos.org/registry/webgl/sdk/tests/conformance2/glsl3/vector-dynamic-indexing-swizzled-lvalue.html

And the new piglit tests:

  swizzled-writemask-indexing-nonconst.shader_test
  swizzled-writemask-indexing.shader_test

Signed-off-by: Ilia Mirkin <imirkin@alum.mit.edu>
Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
Cc: mesa-stable@lists.freedesktop.org
src/compiler/glsl/lower_vector_derefs.cpp

index 7583d1fdd3ee266b04fca2001844a1f5ef79a7ae..6cd9a2d819a3728497abd49bc59bc30e5040a73e 100644 (file)
@@ -59,8 +59,7 @@ vector_deref_visitor::visit_enter(ir_assignment *ir)
    if (!deref->array->type->is_vector())
       return ir_rvalue_enter_visitor::visit_enter(ir);
 
-   ir_dereference *const new_lhs = (ir_dereference *) deref->array;
-   ir->set_lhs(new_lhs);
+   ir_rvalue *const new_lhs = deref->array;
 
    void *mem_ctx = ralloc_parent(ir);
    ir_constant *old_index_constant =
@@ -72,8 +71,16 @@ vector_deref_visitor::visit_enter(ir_assignment *ir)
                                            ir->rhs,
                                            deref->array_index);
       ir->write_mask = (1 << new_lhs->type->vector_elements) - 1;
+      ir->set_lhs(new_lhs);
+   } else if (new_lhs->ir_type != ir_type_swizzle) {
+      ir->set_lhs(new_lhs);
+      ir->write_mask = 1 << old_index_constant->get_uint_component(0);
    } else {
-      ir->write_mask = 1 << old_index_constant->get_int_component(0);
+      /* If the "new" LHS is a swizzle, use the set_lhs helper to instead
+       * swizzle the RHS.
+       */
+      unsigned component[1] = { old_index_constant->get_uint_component(0) };
+      ir->set_lhs(new(mem_ctx) ir_swizzle(new_lhs, component, 1));
    }
 
    return ir_rvalue_enter_visitor::visit_enter(ir);