From f06c86358c2b3840d7b74514a90f83ed6fdd1991 Mon Sep 17 00:00:00 2001 From: Kenneth Graunke Date: Tue, 4 Jun 2019 23:18:45 -0700 Subject: [PATCH] intel/blorp: Handle SINT/UINT clamping on blits. 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 --- src/intel/blorp/blorp_blit.c | 32 ++++++++++++++++++++++++++++++++ src/intel/blorp/blorp_priv.h | 6 ++++++ 2 files changed, 38 insertions(+) diff --git a/src/intel/blorp/blorp_blit.c b/src/intel/blorp/blorp_blit.c index 9e964d02f36..c0b2b5e6533 100644 --- a/src/intel/blorp/blorp_blit.c +++ b/src/intel/blorp/blorp_blit.c @@ -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 diff --git a/src/intel/blorp/blorp_priv.h b/src/intel/blorp/blorp_priv.h index b351e6bf584..02c33c6bac5 100644 --- a/src/intel/blorp/blorp_priv.h +++ b/src/intel/blorp/blorp_priv.h @@ -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)). */ -- 2.30.2