i965: Fix textureGather with RG32I/UI on Gen7.
authorKenneth Graunke <kenneth@whitecape.org>
Thu, 5 Jan 2017 10:51:38 +0000 (02:51 -0800)
committerKenneth Graunke <kenneth@whitecape.org>
Fri, 13 Jan 2017 19:57:06 +0000 (11:57 -0800)
According to the "Gather4 R32G32_FLOAT Bug" internal documentation
page, the R32G32_UINT and R32G32_SINT formats are affected by the
same bug as R32G32_FLOAT.  Applying the same workarounds should be
viable - apparently the R32G32_FLOAT_LD format shouldn't corrupt
integer data which is NaN or other sketchy floating point values.

One irritating caveat is that, because it's a FLOAT format, the
alpha channel or any set to SCS_ONE return 0x3f8 (1.0) rather than
integer 1.  So we need shader code to whack those channels to 1.

Fixes GL45-CTS.texture_gather.plain-gather-int-cube-rg on Haswell.

v2: Fix swizzle component zeroing (caught by Jordan Justen).

Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
src/mesa/drivers/dri/i965/brw_wm.c
src/mesa/drivers/dri/i965/brw_wm_surface_state.c

index 56b60b87ffb6c8f6b514071a439a6d5893d79817..bd2b24a3bfab0d0c9a8f07a00d9328d8db58971d 100644 (file)
@@ -347,13 +347,40 @@ brw_populate_sampler_prog_key_data(struct gl_context *ctx,
                key->gl_clamp_mask[2] |= 1 << s;
          }
 
-         /* gather4's channel select for green from RG32F is broken; requires
-          * a shader w/a on IVB; fixable with just SCS on HSW.
-          */
-         if (brw->gen == 7 && !brw->is_haswell &&
-             prog->nir->info->uses_texture_gather) {
-            if (img->InternalFormat == GL_RG32F)
-               key->gather_channel_quirk_mask |= 1 << s;
+         /* gather4 for RG32* is broken in multiple ways on Gen7. */
+         if (brw->gen == 7 && prog->nir->info->uses_texture_gather) {
+            switch (img->InternalFormat) {
+            case GL_RG32I:
+            case GL_RG32UI: {
+               /* We have to override the format to R32G32_FLOAT_LD.
+                * This means that SCS_ALPHA and SCS_ONE will return 0x3f8
+                * (1.0) rather than integer 1.  This needs shader hacks.
+                *
+                * On Ivybridge, we whack W (alpha) to ONE in our key's
+                * swizzle.  On Haswell, we look at the original texture
+                * swizzle, and use XYZW with channels overridden to ONE,
+                * leaving normal texture swizzling to SCS.
+                */
+               unsigned src_swizzle =
+                  brw->is_haswell ? t->_Swizzle : key->swizzles[s];
+               for (int i = 0; i < 4; i++) {
+                  unsigned src_comp = GET_SWZ(src_swizzle, i);
+                  if (src_comp == SWIZZLE_ONE || src_comp == SWIZZLE_W) {
+                     key->swizzles[i] &= ~(0x7 << (3 * i));
+                     key->swizzles[i] |= SWIZZLE_ONE << (3 * i);
+                  }
+               }
+               /* fallthrough */
+            }
+            case GL_RG32F:
+               /* The channel select for green doesn't work - we have to
+                * request blue.  Haswell can use SCS for this, but Ivybridge
+                * needs a shader workaround.
+                */
+               if (!brw->is_haswell)
+                  key->gather_channel_quirk_mask |= 1 << s;
+               break;
+            }
          }
 
          /* Gen6's gather4 is broken for UINT/SINT; we treat them as
index 4566696fa98dafda8da740770422174476b03ad6..02aea78e7265b492fc8e3a32f501e028a65088fe 100644 (file)
@@ -565,7 +565,9 @@ brw_update_texture_surface(struct gl_context *ctx,
       /* Implement gen6 and gen7 gather work-around */
       bool need_green_to_blue = false;
       if (for_gather) {
-         if (brw->gen == 7 && format == BRW_SURFACEFORMAT_R32G32_FLOAT) {
+         if (brw->gen == 7 && (format == BRW_SURFACEFORMAT_R32G32_FLOAT ||
+                               format == BRW_SURFACEFORMAT_R32G32_SINT ||
+                               format == BRW_SURFACEFORMAT_R32G32_UINT)) {
             format = BRW_SURFACEFORMAT_R32G32_FLOAT_LD;
             need_green_to_blue = brw->is_haswell;
          } else if (brw->gen == 6) {