intel/blorp: Handle SINT/UINT clamping on blits.
authorKenneth Graunke <kenneth@whitecape.org>
Wed, 5 Jun 2019 06:18:45 +0000 (23:18 -0700)
committerKenneth Graunke <kenneth@whitecape.org>
Wed, 5 Jun 2019 23:58:07 +0000 (16:58 -0700)
This patch makes blorp_blit handle SINT<->UINT blit value clamping.
After reading the source's integer data (which is expanded to 32-bit),
we either IMAX with 0 (for SINT -> UINT, to clamp negative numbers) or
UMIN with (1 << 31) - 1 (for UINT -> SINT, to clamp positive numbers
outside of the representable range).

Such blits are not allowed by the OpenGL or Vulkan APIs directly:

   The Vulkan 1.1 spec for vkCmdBlitImage says:

   "Integer formats can only be converted to other integer formats with
    the same signedness."

   The GL 4.5 spec for glBlitFramebuffer says:

   "An INVALID_OPERATION error is generated if format conversions are
    not supported, which occurs under any of the following conditions:
    [...]
    * The read buffer contains unsigned integer values and any draw
      buffer does not contain unsigned integer values.
    * The read buffer contains signed integer values and any draw buffer
      does not contain signed integer values."

However, they are useful for other operations, such as texture upload
and download, which typically are implemented via blorp_blit().  i965
has code to fall back in this case (which the next commit will delete),
and Gallium expects blit() to handle this case for texture upload.

Fixes the following tests on iris:
- GTF-GL46.gtf32.GL3Tests.packed_pixels.packed_pixels
- GTF-GL46.gtf32.GL3Tests.packed_pixels.packed_pixels_pbo
- GTF-GL46.gtf32.GL3Tests.packed_pixels.packed_pixels_pixelstore

Reviewed-by: Jason Ekstrand <jason@jlekstrand.net>
src/intel/blorp/blorp_blit.c
src/intel/blorp/blorp_priv.h

index 9e964d02f36e9e1f04107f47fa14faaf315fe0fc..c0b2b5e6533e61a9a78110210e344299b6604580 100644 (file)
@@ -1426,6 +1426,29 @@ brw_blorp_build_nir_shader(struct blorp_context *blorp, void *mem_ctx,
       color = bit_cast_color(&b, color, key);
    } else if (key->dst_format) {
       color = convert_color(&b, color, key);
+   } else if (key->uint32_to_sint) {
+      /* Normally the hardware will take care of converting values from/to
+       * the source and destination formats.  But a few cases need help.
+       *
+       * The Skylake PRM, volume 07, page 658 has a programming note:
+       *
+       *    "When using SINT or UINT rendertarget surface formats, Blending
+       *     must be DISABLED. The Pre-Blend Color Clamp Enable and Color
+       *     Clamp Range fields are ignored, and an implied clamp to the
+       *     rendertarget surface format is performed."
+       *
+       * For UINT to SINT blits, our sample operation gives us a uint32_t,
+       * but our render target write expects a signed int32_t number.  If we
+       * simply passed the value along, the hardware would interpret a value
+       * with bit 31 set as a negative value, clamping it to the largest
+       * negative number the destination format could represent.  But the
+       * actual source value is a positive number, so we want to clamp it
+       * to INT_MAX.  To fix this, we explicitly take min(color, INT_MAX).
+       */
+      color = nir_umin(&b, color, nir_imm_int(&b, INT32_MAX));
+   } else if (key->sint32_to_uint) {
+      /* Similar to above, but clamping negative numbers to zero. */
+      color = nir_imax(&b, color, nir_imm_int(&b, 0));
    }
 
    if (key->dst_rgb) {
@@ -2300,9 +2323,18 @@ blorp_blit(struct blorp_batch *batch,
    params.src.view.swizzle = src_swizzle;
    params.dst.view.swizzle = dst_swizzle;
 
+   const struct isl_format_layout *src_fmtl =
+      isl_format_get_layout(params.src.view.format);
+
    struct brw_blorp_blit_prog_key wm_prog_key = {
       .shader_type = BLORP_SHADER_TYPE_BLIT,
       .filter = filter,
+      .sint32_to_uint = src_fmtl->channels.r.bits == 32 &&
+                        isl_format_has_sint_channel(params.src.view.format) &&
+                        isl_format_has_uint_channel(params.dst.view.format),
+      .uint32_to_sint = src_fmtl->channels.r.bits == 32 &&
+                        isl_format_has_uint_channel(params.src.view.format) &&
+                        isl_format_has_sint_channel(params.dst.view.format),
    };
 
    /* Scaling factors used for bilinear filtering in multisample scaled
index b351e6bf5845dc8b7866373a5ee8ad11b51719e0..02c33c6bac56a95c8ffac9943b503bf7823a7a0b 100644 (file)
@@ -284,6 +284,12 @@ struct brw_blorp_blit_prog_key
    /* Whether or not the format workarounds are a bitcast operation */
    bool format_bit_cast;
 
+   /** True if we need to perform SINT -> UINT clamping. */
+   bool sint32_to_uint;
+
+   /** True if we need to perform UINT -> SINT clamping. */
+   bool uint32_to_sint;
+
    /* Type of the data to be read from the texture (one of
     * nir_type_(int|uint|float)).
     */