[Mesa-dev] [PATCH 4/5] i965/gen9: Add XY_FAST_COPY_BLT support to intelEmitCopyBlit()

Ben Widawsky ben at bwidawsk.net
Mon Jun 22 18:06:53 PDT 2015


On Fri, Jun 19, 2015 at 02:41:50PM -0700, Anuj Phogat wrote:
> On Wed, Jun 10, 2015 at 3:34 PM, Anuj Phogat <anuj.phogat at gmail.com> wrote:
> > This patch enables using XY_FAST_COPY_BLT only for Yf/Ys tiled buffers.
> > It can be later turned on for other tiling patterns (X,Y) too.
> >
> > V3: Flush in between sequential fast copy blits.
> >     Fix src/dst alignment requirements.
> >     Make can_fast_copy_blit() helper.
> >     Use ffs(), is_power_of_two()
> >     Move overlap computation inside intel_miptree_blit().
> >
> > V4: Use _mesa_regions_overlap() function.
> >     Simplify horizontal and vertical alignment computations.
> >
> > Signed-off-by: Anuj Phogat <anuj.phogat at gmail.com>
> > Cc: Ben Widawsky <ben at bwidawsk.net>
> > ---
> >  src/mesa/drivers/dri/i965/intel_blit.c       | 295 ++++++++++++++++++++++-----
> >  src/mesa/drivers/dri/i965/intel_blit.h       |   2 +
> >  src/mesa/drivers/dri/i965/intel_copy_image.c |   2 +
> >  src/mesa/drivers/dri/i965/intel_reg.h        |  16 ++
> >  4 files changed, 268 insertions(+), 47 deletions(-)
> >
> > diff --git a/src/mesa/drivers/dri/i965/intel_blit.c b/src/mesa/drivers/dri/i965/intel_blit.c
> > index 5afc771..800ed7e 100644
> > --- a/src/mesa/drivers/dri/i965/intel_blit.c
> > +++ b/src/mesa/drivers/dri/i965/intel_blit.c
> > @@ -27,6 +27,7 @@
> >
> >
> >  #include "main/mtypes.h"
> > +#include "main/blit.h"
> >  #include "main/context.h"
> >  #include "main/enums.h"
> >  #include "main/colormac.h"
> > @@ -43,6 +44,23 @@
> >
> >  #define FILE_DEBUG_FLAG DEBUG_BLIT
> >
> > +#define SET_TILING_XY_FAST_COPY_BLT(tiling, tr_mode, type)           \
> > +({                                                                   \
> > +   switch (tiling) {                                                 \
> > +   case I915_TILING_X:                                               \
> > +      CMD |= type ## _TILED_X;                                       \
> > +      break;                                                         \
> > +   case I915_TILING_Y:                                               \
> > +      if (tr_mode == INTEL_MIPTREE_TRMODE_YS)                        \
> > +         CMD |= type ## _TILED_64K;                                  \
> > +      else                                                           \
> > +         CMD |= type ## _TILED_Y;                                    \
> > +      break;                                                         \
> > +   default:                                                          \
> > +      unreachable("not reached");                                    \
> > +   }                                                                 \
> > +})
> > +
> >  static void
> >  intel_miptree_set_alpha_to_one(struct brw_context *brw,
> >                                 struct intel_mipmap_tree *mt,
> > @@ -75,6 +93,10 @@ static uint32_t
> >  br13_for_cpp(int cpp)
> >  {
> >     switch (cpp) {
> > +   case 16:
> > +      return BR13_32323232;
> > +   case 8:
> > +      return BR13_16161616;
> >     case 4:
> >        return BR13_8888;
> >        break;
> > @@ -89,6 +111,66 @@ br13_for_cpp(int cpp)
> >     }
> >  }
> >
> > +static uint32_t
> > +get_tr_horizontal_align(uint32_t tr_mode, uint32_t cpp, bool is_src) {
> > +   /* Alignment tables for YF/YS tiled surfaces. */
> > +   const uint32_t align_2d_yf[] = {64, 64, 32, 32, 16};
> > +   const uint32_t align_2d_ys[] = {256, 256, 128, 128, 64};

If you move the alignment stuff from the other patch series to a more generic
place, you could reuse it here. Also, as you pointed out in that other patch,
ys = 4 * ys

> > +   const uint32_t bpp = cpp * 8;
> > +   const uint32_t shift = is_src ? 17 : 10;
> > +   uint32_t align;
> > +   int i = 0;
> > +
> > +   if (tr_mode == INTEL_MIPTREE_TRMODE_NONE)
> > +      return 0;
> > +
> > +   /* Compute array index. */
> > +   assert (bpp >= 8 && bpp <= 128 && is_power_of_two(bpp));
> > +   i = ffs(bpp / 8) - 1;
> > +
> > +   align = tr_mode == INTEL_MIPTREE_TRMODE_YF ?
> > +           align_2d_yf[i] :
> > +           align_2d_ys[i];
> > +
> > +   assert(is_power_of_two(align));
> > +
> > +   /* XY_FAST_COPY_BLT doesn't support horizontal alignment of 16. */
> > +   if (align == 16)
> > +      align = 32;
> > +
> > +   return (ffs(align) - 6) << shift;
> > +}
> > +
> > +static uint32_t
> > +get_tr_vertical_align(uint32_t tr_mode, uint32_t cpp, bool is_src) {
> > +   /* Vertical alignment tables for YF/YS tiled surfaces. */
> > +   const unsigned align_2d_yf[] = {64, 32, 32, 16, 16};
> > +   const unsigned align_2d_ys[] = {256, 128, 128, 64, 64};
> > +   const uint32_t bpp = cpp * 8;
> > +   const uint32_t shift = is_src ? 15 : 8;
> > +   uint32_t align;
> > +   int i = 0;
> > +
> > +   if (tr_mode == INTEL_MIPTREE_TRMODE_NONE)
> > +      return 0;
> > +
> > +   /* Compute array index. */
> > +   assert (bpp >= 8 && bpp <= 128 && is_power_of_two(bpp));
> > +   i = ffs(bpp / 8) - 1;
> > +
> > +   align = tr_mode == INTEL_MIPTREE_TRMODE_YF ?
> > +           align_2d_yf[i] :
> > +           align_2d_ys[i];
> > +
> > +   assert(is_power_of_two(align));
> > +
> > +   /* XY_FAST_COPY_BLT doesn't support vertical alignments of 16 and 32. */
> > +   if (align == 16 || align == 32)
> > +      align = 64;
> > +
> > +   return (ffs(align) - 7) << shift;
> > +}
> > +
> >  /**
> >   * Emits the packet for switching the blitter from X to Y tiled or back.
> >   *
> > @@ -281,9 +363,11 @@ intel_miptree_blit(struct brw_context *brw,
> >                            src_pitch,
> >                            src_mt->bo, src_mt->offset,
> >                            src_mt->tiling,
> > +                          src_mt->tr_mode,
> >                            dst_mt->pitch,
> >                            dst_mt->bo, dst_mt->offset,
> >                            dst_mt->tiling,
> > +                          dst_mt->tr_mode,
> >                            src_x, src_y,
> >                            dst_x, dst_y,
> >                            width, height,
> > @@ -316,6 +400,64 @@ alignment_valid(struct brw_context *brw, unsigned offset, uint32_t tiling)
> >     return true;
> >  }
> >
> > +static bool
> > +can_fast_copy_blit(struct brw_context *brw,
> > +                   int16_t src_x, int16_t src_y,
> > +                   uintptr_t src_offset, uint32_t src_pitch,\
> > +                   uint32_t src_tiling, uint32_t src_tr_mode,
> > +                   int16_t dst_x, int16_t dst_y,
> > +                   uintptr_t dst_offset, uint32_t dst_pitch,
> > +                   uint32_t dst_tiling, uint32_t dst_tr_mode,
> > +                   int16_t w, int16_t h, uint32_t cpp)
> > +{
> > +   const bool dst_tiling_none = dst_tiling == I915_TILING_NONE;
> > +   const bool src_tiling_none = src_tiling == I915_TILING_NONE;
> > +
> > +   if (brw->gen < 9)
> > +      return false;
> > +
> > +   if (_mesa_regions_overlap(src_x, src_y, src_x + w, src_y + h,
> > +                             dst_x, dst_y, dst_x + w, dst_y + h))
> Changed the condition to:
> if (src_buffer->handle == dst_buffer->handle &&
>     _mesa_regions_overlap(src_x, src_y, src_x + w, src_y + h,
>                             dst_x, dst_y, dst_x + w, dst_y + h))
> 
> See my review branch for the updated patch.
> > +      return false;
> > +
> > +   /* Enable fast copy blit only if the surfaces are Yf/Ys tiled.
> > +    * FIXME: Based on performance data, remove this condition later to
> > +    * enable for all types of surfaces.
> > +    */
> > +   if (src_tr_mode == INTEL_MIPTREE_TRMODE_NONE &&
> > +       dst_tr_mode == INTEL_MIPTREE_TRMODE_NONE)
> > +      return false;
> > +
> > +   /* For all surface types buffers must be cacheline-aligned. */
> > +   if ((dst_offset | src_offset) & 63)
> > +      return false;
> > +
> > +   /* Color depth greater than 128 bits not supported. */
> > +   if (cpp > 16)
> > +      return false;
> > +
> > +   /* For Fast Copy Blits the pitch cannot be a negative number. So, bit 15
> > +    * of the destination pitch must be zero.
> > +    */
> > +   if ((src_pitch >> 15 & 1) != 0 || (dst_pitch >> 15 & 1) != 0)
> > +      return false;

You don't need != 0, but whatever you like..

> > +
> > +   /* For Linear surfaces, the pitch has to be an OWord (16byte) multiple. */
> > +   if ((src_tiling_none && src_pitch % 16 != 0) ||
> > +       (dst_tiling_none && dst_pitch % 16 != 0))
> > +      return false;
> > +
> > +   /* For Tiled surfaces, the pitch has to be a multiple of the Tile width
> > +    * (X direction width of the Tile). This means the pitch value will
> > +    * always be Cache Line aligned (64byte multiple).
> > +    */
> > +   if ((!dst_tiling_none && dst_pitch % 64 != 0) ||
> > +       (!src_tiling_none && src_pitch % 64 != 0))
> > +      return false;
> > +
> > +   return true;
> > +}
> > +
> >  /* Copy BitBlt
> >   */
> >  bool
> > @@ -325,10 +467,12 @@ intelEmitCopyBlit(struct brw_context *brw,
> >                   drm_intel_bo *src_buffer,
> >                   GLuint src_offset,
> >                   uint32_t src_tiling,
> > +                 uint32_t src_tr_mode,
> >                   GLshort dst_pitch,
> >                   drm_intel_bo *dst_buffer,
> >                   GLuint dst_offset,
> >                   uint32_t dst_tiling,
> > +                 uint32_t dst_tr_mode,
> >                   GLshort src_x, GLshort src_y,
> >                   GLshort dst_x, GLshort dst_y,
> >                   GLshort w, GLshort h,
> > @@ -340,11 +484,7 @@ intelEmitCopyBlit(struct brw_context *brw,
> >     drm_intel_bo *aper_array[3];
> >     bool dst_y_tiled = dst_tiling == I915_TILING_Y;
> >     bool src_y_tiled = src_tiling == I915_TILING_Y;
> > -
> > -   if (!alignment_valid(brw, dst_offset, dst_tiling))
> > -      return false;
> > -   if (!alignment_valid(brw, src_offset, src_tiling))
> > -      return false;
> > +   bool use_fast_copy_blit = false;
> >
> >     if ((dst_y_tiled || src_y_tiled) && brw->gen < 6)
> >        return false;
> > @@ -376,52 +516,109 @@ intelEmitCopyBlit(struct brw_context *brw,
> >         src_buffer, src_pitch, src_offset, src_x, src_y,
> >         dst_buffer, dst_pitch, dst_offset, dst_x, dst_y, w, h);
> >
> > -   /* Blit pitch must be dword-aligned.  Otherwise, the hardware appears to drop
> > -    * the low bits.  Offsets must be naturally aligned.
> > -    */
> > -   if (src_pitch % 4 != 0 || src_offset % cpp != 0 ||
> > -       dst_pitch % 4 != 0 || dst_offset % cpp != 0)
> > -      return false;
> > -
> > -   /* For big formats (such as floating point), do the copy using 16 or 32bpp
> > -    * and multiply the coordinates.
> > -    */
> > -   if (cpp > 4) {
> > -      if (cpp % 4 == 2) {
> > -         dst_x *= cpp / 2;
> > -         dst_x2 *= cpp / 2;
> > -         src_x *= cpp / 2;
> > -         cpp = 2;
> > -      } else {
> > -         assert(cpp % 4 == 0);
> > -         dst_x *= cpp / 4;
> > -         dst_x2 *= cpp / 4;
> > -         src_x *= cpp / 4;
> > -         cpp = 4;
> > +   use_fast_copy_blit = can_fast_copy_blit(brw,
> > +                                           src_x, src_y,
> > +                                           src_offset, src_pitch,
> > +                                           src_tiling, src_tr_mode,
> > +                                           dst_x, dst_y,
> > +                                           dst_offset, dst_pitch,
> > +                                           dst_tiling, dst_tr_mode,
> > +                                           w, h, cpp);
> > +   assert(use_fast_copy_blit ||
> > +          (src_tr_mode == INTEL_MIPTREE_TRMODE_NONE &&
> > +           dst_tr_mode == INTEL_MIPTREE_TRMODE_NONE));
> > +
> > +   if (use_fast_copy_blit) {
> > +      /* When two sequential fast copy blits have different source surfaces,
> > +       * but their destinations refer to the same destination surfaces and
> > +       * therefore destinations overlap it is imperative that a flush be
> > +       * inserted between the two blits.
> > +       *
> > +       * FIXME: Figure out a way to avoid flushing when not required.
> > +       */
> > +      intel_batchbuffer_emit_mi_flush(brw);
> > +
> > +      assert(cpp <= 16);
> > +      BR13 = br13_for_cpp(cpp);
> > +
> > +      if (src_tr_mode == INTEL_MIPTREE_TRMODE_YF)
> > +         BR13 |= XY_FAST_SRC_TRMODE_YF;
> > +
> > +      if (dst_tr_mode == INTEL_MIPTREE_TRMODE_YF)
> > +         BR13 |= XY_FAST_DST_TRMODE_YF;
> > +
> > +      CMD = XY_FAST_COPY_BLT_CMD;
> > +
> > +      if (dst_tiling != I915_TILING_NONE) {
> > +         SET_TILING_XY_FAST_COPY_BLT(dst_tiling, dst_tr_mode, XY_FAST_DST);
> > +         /* Pitch value should be specified as a number of Dwords. */
> > +         dst_pitch /= 4;
> > +      }
> > +      if (src_tiling != I915_TILING_NONE) {
> > +         SET_TILING_XY_FAST_COPY_BLT(src_tiling, src_tr_mode, XY_FAST_SRC);
> > +         /* Pitch value should be specified as a number of Dwords. */
> > +         src_pitch /= 4;
> >        }
> > -   }
> >
> > -   BR13 = br13_for_cpp(cpp) | translate_raster_op(logic_op) << 16;
> > +      CMD |= get_tr_horizontal_align(src_tr_mode, cpp, true /* is_src */);
> > +      CMD |= get_tr_vertical_align(src_tr_mode, cpp, true /* is_src */);
> >
> > -   switch (cpp) {
> > -   case 1:
> > -   case 2:
> > -      CMD = XY_SRC_COPY_BLT_CMD;
> > -      break;
> > -   case 4:
> > -      CMD = XY_SRC_COPY_BLT_CMD | XY_BLT_WRITE_ALPHA | XY_BLT_WRITE_RGB;
> > -      break;
> > -   default:
> > -      return false;
> > -   }
> > +      CMD |= get_tr_horizontal_align(dst_tr_mode, cpp, false /* is_src */);
> > +      CMD |= get_tr_vertical_align(dst_tr_mode, cpp, false /* is_src */);
> >
> > -   if (dst_tiling != I915_TILING_NONE) {
> > -      CMD |= XY_DST_TILED;
> > -      dst_pitch /= 4;
> > -   }
> > -   if (src_tiling != I915_TILING_NONE) {
> > -      CMD |= XY_SRC_TILED;
> > -      src_pitch /= 4;
> > +   } else {
> > +      /* For big formats (such as floating point), do the copy using 16 or
> > +       * 32bpp and multiply the coordinates.
> > +       */
> > +      if (cpp > 4) {
> > +         if (cpp % 4 == 2) {
> > +            dst_x *= cpp / 2;
> > +            dst_x2 *= cpp / 2;
> > +            src_x *= cpp / 2;
> > +            cpp = 2;
> > +         } else {
> > +            assert(cpp % 4 == 0);
> > +            dst_x *= cpp / 4;
> > +            dst_x2 *= cpp / 4;
> > +            src_x *= cpp / 4;
> > +            cpp = 4;
> > +         }
> > +      }
> > +
> > +      if (!alignment_valid(brw, dst_offset, dst_tiling))
> > +         return false;
> > +      if (!alignment_valid(brw, src_offset, src_tiling))
> > +         return false;
> > +
> > +      /* Blit pitch must be dword-aligned.  Otherwise, the hardware appears to drop
> > +       * the low bits.  Offsets must be naturally aligned.
> > +       */
> > +      if (src_pitch % 4 != 0 || src_offset % cpp != 0 ||
> > +          dst_pitch % 4 != 0 || dst_offset % cpp != 0)
> > +         return false;
> > +
> > +      assert(cpp <= 4);
> > +      BR13 = br13_for_cpp(cpp) | translate_raster_op(logic_op) << 16;
> > +      switch (cpp) {
> > +      case 1:
> > +      case 2:
> > +         CMD = XY_SRC_COPY_BLT_CMD;
> > +         break;
> > +      case 4:
> > +         CMD = XY_SRC_COPY_BLT_CMD | XY_BLT_WRITE_ALPHA | XY_BLT_WRITE_RGB;
> > +         break;
> > +      default:
> > +         return false;
> > +      }
> > +
> > +      if (dst_tiling != I915_TILING_NONE) {
> > +         CMD |= XY_DST_TILED;
> > +         dst_pitch /= 4;
> > +      }
> > +      if (src_tiling != I915_TILING_NONE) {
> > +         CMD |= XY_SRC_TILED;
> > +         src_pitch /= 4;
> > +      }
> >     }
> >
> >     if (dst_y2 <= dst_y || dst_x2 <= dst_x) {
> > @@ -579,7 +776,9 @@ intel_emit_linear_blit(struct brw_context *brw,
> >     dst_x = dst_offset % 64;
> >     ok = intelEmitCopyBlit(brw, 1,
> >                           pitch, src_bo, src_offset - src_x, I915_TILING_NONE,
> > +                          INTEL_MIPTREE_TRMODE_NONE,
> >                           pitch, dst_bo, dst_offset - dst_x, I915_TILING_NONE,
> > +                          INTEL_MIPTREE_TRMODE_NONE,
> >                           src_x, 0, /* src x/y */
> >                           dst_x, 0, /* dst x/y */
> >                           pitch, height, /* w, h */
> > @@ -598,7 +797,9 @@ intel_emit_linear_blit(struct brw_context *brw,
> >     if (size != 0) {
> >        ok = intelEmitCopyBlit(brw, 1,
> >                              pitch, src_bo, src_offset - src_x, I915_TILING_NONE,
> > +                             INTEL_MIPTREE_TRMODE_NONE,
> >                              pitch, dst_bo, dst_offset - dst_x, I915_TILING_NONE,
> > +                             INTEL_MIPTREE_TRMODE_NONE,
> >                              src_x, 0, /* src x/y */
> >                              dst_x, 0, /* dst x/y */
> >                              size, 1, /* w, h */
> > diff --git a/src/mesa/drivers/dri/i965/intel_blit.h b/src/mesa/drivers/dri/i965/intel_blit.h
> > index 2287c37..823488b 100644
> > --- a/src/mesa/drivers/dri/i965/intel_blit.h
> > +++ b/src/mesa/drivers/dri/i965/intel_blit.h
> > @@ -37,10 +37,12 @@ intelEmitCopyBlit(struct brw_context *brw,
> >                                drm_intel_bo *src_buffer,
> >                                GLuint src_offset,
> >                               uint32_t src_tiling,
> > +                             uint32_t src_tr_mode,
> >                                GLshort dst_pitch,
> >                                drm_intel_bo *dst_buffer,
> >                                GLuint dst_offset,
> >                               uint32_t dst_tiling,
> > +                             uint32_t dst_tr_mode,
> >                                GLshort srcx, GLshort srcy,
> >                                GLshort dstx, GLshort dsty,
> >                                GLshort w, GLshort h,
> > diff --git a/src/mesa/drivers/dri/i965/intel_copy_image.c b/src/mesa/drivers/dri/i965/intel_copy_image.c
> > index f4c7eff..3706704 100644
> > --- a/src/mesa/drivers/dri/i965/intel_copy_image.c
> > +++ b/src/mesa/drivers/dri/i965/intel_copy_image.c
> > @@ -126,9 +126,11 @@ copy_image_with_blitter(struct brw_context *brw,
> >                              src_mt->pitch,
> >                              src_mt->bo, src_mt->offset,
> >                              src_mt->tiling,
> > +                            src_mt->tr_mode,
> >                              dst_mt->pitch,
> >                              dst_mt->bo, dst_mt->offset,
> >                              dst_mt->tiling,
> > +                            dst_mt->tr_mode,
> >                              src_x, src_y,
> >                              dst_x, dst_y,
> >                              src_width, src_height,
> > diff --git a/src/mesa/drivers/dri/i965/intel_reg.h b/src/mesa/drivers/dri/i965/intel_reg.h
> > index bd14e18..4223e11 100644
> > --- a/src/mesa/drivers/dri/i965/intel_reg.h
> > +++ b/src/mesa/drivers/dri/i965/intel_reg.h
> > @@ -102,6 +102,8 @@
> >
> >  #define XY_SRC_COPY_BLT_CMD             (CMD_2D | (0x53 << 22))
> >
> > +#define XY_FAST_COPY_BLT_CMD             (CMD_2D | (0x42 << 22))
> > +
> >  #define XY_TEXT_IMMEDIATE_BLIT_CMD     (CMD_2D | (0x31 << 22))
> >  # define XY_TEXT_BYTE_PACKED           (1 << 16)
> >
> > @@ -111,10 +113,24 @@
> >  #define XY_SRC_TILED           (1 << 15)
> >  #define XY_DST_TILED           (1 << 11)
> >
> > +/* BR00 */
> > +#define XY_FAST_SRC_TILED_64K        (3 << 20)
> > +#define XY_FAST_SRC_TILED_Y          (2 << 20)
> > +#define XY_FAST_SRC_TILED_X          (1 << 20)
> > +
> > +#define XY_FAST_DST_TILED_64K        (3 << 13)
> > +#define XY_FAST_DST_TILED_Y          (2 << 13)
> > +#define XY_FAST_DST_TILED_X          (1 << 13)
> > +
> >  /* BR13 */
> >  #define BR13_8                 (0x0 << 24)
> >  #define BR13_565               (0x1 << 24)
> >  #define BR13_8888              (0x3 << 24)
> > +#define BR13_16161616          (0x4 << 24)
> > +#define BR13_32323232          (0x5 << 24)
> > +
> > +#define XY_FAST_SRC_TRMODE_YF        (1 << 31)
> > +#define XY_FAST_DST_TRMODE_YF        (1 << 30)
> >
> >  /* Pipeline Statistics Counter Registers */
> >  #define IA_VERTICES_COUNT               0x2310

You have tab problems in your review branch. Looks okay to me otherwise.

Reviewed-by: Ben Widawsky <ben at bwidawsk.net>


More information about the mesa-dev mailing list