i965: Fix cube array coordinate normalization
authorChris Forbes <chrisf@ijw.co.nz>
Sun, 15 Sep 2013 10:25:45 +0000 (22:25 +1200)
committerChris Forbes <chrisf@ijw.co.nz>
Thu, 26 Sep 2013 06:24:22 +0000 (18:24 +1200)
Hardware requires the magnitude of the largest component to not exceed
1; brw_cubemap_normalize ensures that this is the case.

Unfortunately, we would previously multiply the array index for cube
arrays by the normalization factor. The incorrect array index would then
cause the sampler to attempt to access either the wrong cube, or memory
outside the cube surface entirely, resulting in garbage rendering or in
the worst case, hangs.

Alter the normalization pass to only multiply the .xyz components.

Fixes broken rendering in the arb_texture_cube_map_array-cubemap piglit,
which was recently adjusted to provoke this behavior.

V2: Fix indent.

Signed-off-by: Chris Forbes <chrisf@ijw.co.nz>
Cc: "9.2" mesa-stable@lists.freedesktop.org
Reviewed-by: Eric Anholt <eric@anholt.net>
src/mesa/drivers/dri/i965/brw_cubemap_normalize.cpp

index 9e149f96f5382178db42024bde876821e0bb0ccc..46155fb43af9688521050d3b48550abf8754b2e9 100644 (file)
@@ -32,6 +32,7 @@
 
 #include "glsl/glsl_types.h"
 #include "glsl/ir.h"
+#include "program/prog_instruction.h" /* For WRITEMASK_* */
 
 class brw_cubemap_normalize_visitor : public ir_hierarchical_visitor {
 public:
@@ -88,11 +89,16 @@ brw_cubemap_normalize_visitor::visit_leave(ir_texture *ir)
                                     glsl_type::float_type,
                                     expr, NULL);
 
-   deref = new(mem_ctx) ir_dereference_variable(var);
-   ir->coordinate = new(mem_ctx) ir_expression(ir_binop_mul,
-                                              ir->coordinate->type,
-                                              deref,
-                                              expr);
+   /* coordinate.xyz *= expr */
+   assign = new(mem_ctx) ir_assignment(
+      new(mem_ctx) ir_dereference_variable(var),
+      new(mem_ctx) ir_expression(ir_binop_mul,
+                                 ir->coordinate->type,
+                                 new(mem_ctx) ir_dereference_variable(var),
+                                 expr));
+   assign->write_mask = WRITEMASK_XYZ;
+   base_ir->insert_before(assign);
+   ir->coordinate = new(mem_ctx) ir_dereference_variable(var);
 
    progress = true;
    return visit_continue;