[Mesa-dev] [PATCH 2/7] intel/blorp: Handle more exotic destination formats

Jason Ekstrand jason at jlekstrand.net
Tue Jan 24 23:45:49 UTC 2017


This commit adds support for using both R24_UNORM_X8_TYPELESS and
R9G9B9E5_SHAREDEXP as destination formats even though the hardware does
not support rendering to them.  This is done by using a different format
and emitting shader code to fake it the rest of the way.
---
 src/intel/blorp/blorp_blit.c | 92 ++++++++++++++++++++++++++++++++++++++++++++
 src/intel/blorp/blorp_priv.h |  6 +++
 2 files changed, 98 insertions(+)

diff --git a/src/intel/blorp/blorp_blit.c b/src/intel/blorp/blorp_blit.c
index fc76fd4..b964224 100644
--- a/src/intel/blorp/blorp_blit.c
+++ b/src/intel/blorp/blorp_blit.c
@@ -26,6 +26,7 @@
 #include "blorp_priv.h"
 #include "brw_meta_util.h"
 
+#include "util/format_rgb9e5.h"
 /* header-only include needed for _mesa_unorm_to_float and friends. */
 #include "mesa/main/format_utils.h"
 
@@ -916,6 +917,88 @@ bit_cast_color(struct nir_builder *b, nir_ssa_def *color,
    }
 }
 
+static nir_ssa_def *
+convert_color(struct nir_builder *b, nir_ssa_def *color,
+              const struct brw_blorp_blit_prog_key *key)
+{
+   /* All of our color conversions end up generating a single-channel color
+    * value that we need to write out.
+    */
+   nir_ssa_def *value;
+
+   if (key->dst_format == ISL_FORMAT_R24_UNORM_X8_TYPELESS) {
+      /* The destination image is bound as R32_UNORM but the data needs to be
+       * in R24_UNORM_X8_TYPELESS.  The bottom 24 are the actual data and the
+       * top 8 need to be zero.  We can accomplish this by simply multiplying
+       * by a factor to scale things down.
+       */
+      float factor = (float)((1 << 24) - 1) / (float)UINT32_MAX;
+      value = nir_fmul(b, nir_fsat(b, nir_channel(b, color, 0)),
+                          nir_imm_float(b, factor));
+   } else if (key->dst_format == ISL_FORMAT_R9G9B9E5_SHAREDEXP) {
+      /* See also float3_to_rgb9e5 */
+
+      /* First, we need to clamp it to range. */
+      nir_ssa_def *clamped = nir_fmin(b, color, nir_imm_float(b, MAX_RGB9E5));
+
+      /* Get rid of negatives and NaN */
+      clamped = nir_bcsel(b, nir_ult(b, nir_imm_int(b, 0x7f800000), color),
+                             nir_imm_float(b, 0), clamped);
+
+      /* maxrgb.u = MAX3(rc.u, gc.u, bc.u); */
+      nir_ssa_def *maxu = nir_umax(b, nir_channel(b, clamped, 0),
+                          nir_umax(b, nir_channel(b, clamped, 1),
+                                      nir_channel(b, clamped, 2)));
+
+      /* maxrgb.u += maxrgb.u & (1 << (23-9)); */
+      maxu = nir_iadd(b, maxu, nir_iand(b, maxu, nir_imm_int(b, 1 << 14)));
+
+      /* exp_shared = MAX2((maxrgb.u >> 23), -RGB9E5_EXP_BIAS - 1 + 127) +
+       *              1 + RGB9E5_EXP_BIAS - 127;
+       */
+      nir_ssa_def *exp_shared =
+         nir_iadd(b, nir_umax(b, nir_ushr(b, maxu, nir_imm_int(b, 23)),
+                                 nir_imm_int(b, -RGB9E5_EXP_BIAS - 1 + 127)),
+                     nir_imm_int(b, 1 + RGB9E5_EXP_BIAS - 127));
+
+      /* revdenom_biasedexp = 127 - (exp_shared - RGB9E5_EXP_BIAS -
+       *                             RGB9E5_MANTISSA_BITS) + 1;
+       */
+      nir_ssa_def *revdenom_biasedexp =
+         nir_isub(b, nir_imm_int(b, 127 + RGB9E5_EXP_BIAS +
+                                    RGB9E5_MANTISSA_BITS + 1),
+                     exp_shared);
+
+      /* revdenom.u = revdenom_biasedexp << 23; */
+      nir_ssa_def *revdenom =
+         nir_ishl(b, revdenom_biasedexp, nir_imm_int(b, 23));
+
+      /* rm = (int) (rc.f * revdenom.f);
+       * gm = (int) (gc.f * revdenom.f);
+       * bm = (int) (bc.f * revdenom.f);
+       */
+      nir_ssa_def *mantissa =
+         nir_f2i(b, nir_fmul(b, clamped, revdenom));
+
+      /* rm = (rm & 1) + (rm >> 1);
+       * gm = (gm & 1) + (gm >> 1);
+       * bm = (bm & 1) + (bm >> 1);
+       */
+      mantissa = nir_iadd(b, nir_iand(b, mantissa, nir_imm_int(b, 1)),
+                             nir_ushr(b, mantissa, nir_imm_int(b, 1)));
+
+      value = nir_channel(b, mantissa, 0);
+      value = nir_mask_shift_or(b, value, nir_channel(b, mantissa, 1), ~0, 9);
+      value = nir_mask_shift_or(b, value, nir_channel(b, mantissa, 2), ~0, 18);
+      value = nir_mask_shift_or(b, value, exp_shared, ~0, 27);
+   } else {
+      unreachable("Unsupported format conversion");
+   }
+
+   nir_ssa_def *u = nir_ssa_undef(b, 1, 32);
+   return nir_vec4(b, value, u, u, u);
+}
+
 /**
  * Generator for WM programs used in BLORP blits.
  *
@@ -1274,6 +1357,9 @@ brw_blorp_build_nir_shader(struct blorp_context *blorp, void *mem_ctx,
    if (key->dst_bpc != key->src_bpc)
       color = bit_cast_color(&b, color, key);
 
+   if (key->dst_format)
+      color = convert_color(&b, color, key);
+
    if (key->dst_rgb) {
       /* The destination image is bound as a red texture three times as wide
        * as the actual image.  Our shader is effectively running one color
@@ -1797,6 +1883,12 @@ try_blorp_blit(struct blorp_batch *batch,
 
       wm_prog_key->dst_rgb = true;
       wm_prog_key->need_dst_offset = true;
+   } else if (params->dst.view.format == ISL_FORMAT_R24_UNORM_X8_TYPELESS) {
+      wm_prog_key->dst_format = params->dst.view.format;
+      params->dst.view.format = ISL_FORMAT_R32_UNORM;
+   } else if (params->dst.view.format == ISL_FORMAT_R9G9B9E5_SHAREDEXP) {
+      wm_prog_key->dst_format = params->dst.view.format;
+      params->dst.view.format = ISL_FORMAT_R32_UINT;
    }
 
    if (params->src.tile_x_sa || params->src.tile_y_sa) {
diff --git a/src/intel/blorp/blorp_priv.h b/src/intel/blorp/blorp_priv.h
index d9c03b1..9c6b81e 100644
--- a/src/intel/blorp/blorp_priv.h
+++ b/src/intel/blorp/blorp_priv.h
@@ -245,6 +245,12 @@ struct brw_blorp_blit_prog_key
    /* Number of bits per channel in the destination image. */
    uint8_t dst_bpc;
 
+   /* The format of the destination if format-specific workarounds are needed
+    * and 0 (ISL_FORMAT_R32G32B32A32_FLOAT) if the destination is natively
+    * renderable.
+    */
+   enum isl_format dst_format;
+
    /* Type of the data to be read from the texture (one of
     * nir_type_(int|uint|float)).
     */
-- 
2.5.0.400.gff86faf



More information about the mesa-dev mailing list