[Mesa-dev] [PATCH V3 17/22] i965/gen9: Add XY_FAST_COPY_BLT support to intelEmitCopyBlit()
Ben Widawsky
ben at bwidawsk.net
Wed Jun 3 15:25:50 PDT 2015
On Tue, Jun 02, 2015 at 04:04:07PM -0700, Anuj Phogat 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().
> Use XY_FAST prefix for the macros.
>
> 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 | 306 +++++++++++++++++++++++----
> 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 | 36 ++++
> 4 files changed, 299 insertions(+), 47 deletions(-)
>
> diff --git a/src/mesa/drivers/dri/i965/intel_blit.c b/src/mesa/drivers/dri/i965/intel_blit.c
> index cd89f9d..8f0b48b 100644
> --- a/src/mesa/drivers/dri/i965/intel_blit.c
> +++ b/src/mesa/drivers/dri/i965/intel_blit.c
> @@ -43,6 +43,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 +92,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;
> case 2:
> @@ -86,6 +107,81 @@ 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};
> + const uint32_t bpp = cpp * 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;
> +
> + if (tr_mode == INTEL_MIPTREE_TRMODE_YF)
> + align = align_2d_yf[i];
> + else
> + align = align_2d_ys[i];
> +
> + switch(align) {
> + case 512:
> + return is_src ? XY_FAST_SRC_H_ALIGN_512 : XY_FAST_DST_H_ALIGN_512;
> + case 256:
> + return is_src ? XY_FAST_SRC_H_ALIGN_256 : XY_FAST_DST_H_ALIGN_256;
> + case 128:
> + return is_src ? XY_FAST_SRC_H_ALIGN_128 : XY_FAST_DST_H_ALIGN_128;
> + case 64:
> + return is_src ? XY_FAST_SRC_H_ALIGN_64 : XY_FAST_DST_H_ALIGN_64;
> + case 32:
> + /* XY_FAST_COPY_BLT doesn't support horizontal alignment of 16. */
> + case 16:
> + return is_src ? XY_FAST_SRC_H_ALIGN_32 : XY_FAST_DST_H_ALIGN_32;
> + default:
> + unreachable("not reached");
> + }
> +}
I'd make this smaller, but I think my brain works differently than most. I don't
see anything wrong with this code though, so it's up to you.
int shift = is_src ? 17 : 10
Then either use your table, or:
/* 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;
> + 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;
> +
> + if (tr_mode == INTEL_MIPTREE_TRMODE_YF)
> + align = align_2d_yf[i];
> + else
> + align = align_2d_ys[i];
> +
> + switch(align) {
> + case 256:
> + return is_src ? XY_FAST_SRC_V_ALIGN_256 : XY_FAST_DST_V_ALIGN_256;
> + case 128:
> + return is_src ? XY_FAST_SRC_V_ALIGN_128 : XY_FAST_DST_V_ALIGN_128;
> + case 64:
> + /* XY_FAST_COPY_BLT doesn't support vertical alignments of 16 and 32. */
> + case 32:
> + case 16:
> + return is_src ? XY_FAST_SRC_V_ALIGN_64 : XY_FAST_DST_V_ALIGN_64;
> + default:
> + unreachable("not reached");
> + }
> +}
> +
> /**
> * Emits the packet for switching the blitter from X to Y tiled or back.
> *
> @@ -248,9 +344,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,
> @@ -282,6 +380,63 @@ 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, uintptr_t src_offset, uint32_t src_pitch,
> + uint32_t src_tiling, uint32_t src_tr_mode,
> + int16_t dst_x, uintptr_t dst_offset, uint32_t dst_pitch,
> + uint32_t dst_tiling, uint32_t dst_tr_mode,
> + int16_t w, 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;
> +
> + /* Check for an overlap. */
> + if ((src_x < dst_x && (src_x + w) > dst_x) ||
> + (src_x > dst_x && (dst_x + w) > src_x))
> + return false;
Can you remind me why Y isn't a factor in determining overlap?
> +
> + /* 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;
> +
> + /* 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
> @@ -291,10 +446,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,
> @@ -306,11 +463,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;
> @@ -342,52 +495,107 @@ 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_offset, src_pitch,
> + src_tiling, src_tr_mode,
> + dst_x, dst_offset, dst_pitch,
> + dst_tiling, dst_tr_mode,
> + w, 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) {
> @@ -545,7 +753,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 */
> @@ -564,7 +774,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 f563939..4f4bbc5 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..c8ec56b 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,44 @@
> #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)
> +
> +#define XY_FAST_SRC_H_ALIGN_512 (4 << 17)
> +#define XY_FAST_SRC_H_ALIGN_256 (3 << 17)
> +#define XY_FAST_SRC_H_ALIGN_128 (2 << 17)
> +#define XY_FAST_SRC_H_ALIGN_64 (1 << 17)
> +#define XY_FAST_SRC_H_ALIGN_32 (0 << 17)
> +
> +#define XY_FAST_SRC_V_ALIGN_256 (2 << 15)
> +#define XY_FAST_SRC_V_ALIGN_128 (1 << 15)
> +#define XY_FAST_SRC_V_ALIGN_64 (0 << 15)
> +
> +#define XY_FAST_DST_H_ALIGN_512 (4 << 10)
> +#define XY_FAST_DST_H_ALIGN_256 (3 << 10)
> +#define XY_FAST_DST_H_ALIGN_128 (2 << 10)
> +#define XY_FAST_DST_H_ALIGN_64 (1 << 10)
> +#define XY_FAST_DST_H_ALIGN_32 (0 << 10)
> +
> +#define XY_FAST_DST_V_ALIGN_256 (2 << 8)
> +#define XY_FAST_DST_V_ALIGN_128 (1 << 8)
> +#define XY_FAST_DST_V_ALIGN_64 (0 << 8)
> +
> /* 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
More information about the mesa-dev
mailing list