X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fgallium%2Fdrivers%2Ffreedreno%2Fa6xx%2Ffd6_blitter.c;h=4e4153ec718d59b0ea8e9c1e7e7cd0dca3c817bd;hb=d5c82c3c5f2f5e7a49630687173ff4f2debb3016;hp=97e015d19eb258c014eb233b8e9e4c0265206d44;hpb=0ac5acaeaaa651d850d77ebab094fa851a7ee06d;p=mesa.git diff --git a/src/gallium/drivers/freedreno/a6xx/fd6_blitter.c b/src/gallium/drivers/freedreno/a6xx/fd6_blitter.c index 97e015d19eb..4e4153ec718 100644 --- a/src/gallium/drivers/freedreno/a6xx/fd6_blitter.c +++ b/src/gallium/drivers/freedreno/a6xx/fd6_blitter.c @@ -26,14 +26,86 @@ */ #include "util/u_dump.h" +#include "util/half_float.h" #include "freedreno_blitter.h" #include "freedreno_fence.h" +#include "freedreno_log.h" #include "freedreno_resource.h" #include "fd6_blitter.h" #include "fd6_format.h" #include "fd6_emit.h" +#include "fd6_resource.h" +#include "fd6_pack.h" + +static inline enum a6xx_2d_ifmt +fd6_ifmt(enum a6xx_format fmt) +{ + switch (fmt) { + case FMT6_A8_UNORM: + case FMT6_8_UNORM: + case FMT6_8_SNORM: + case FMT6_8_8_UNORM: + case FMT6_8_8_SNORM: + case FMT6_8_8_8_8_UNORM: + case FMT6_8_8_8_X8_UNORM: + case FMT6_8_8_8_8_SNORM: + case FMT6_4_4_4_4_UNORM: + case FMT6_5_5_5_1_UNORM: + case FMT6_5_6_5_UNORM: + return R2D_UNORM8; + + case FMT6_32_UINT: + case FMT6_32_SINT: + case FMT6_32_32_UINT: + case FMT6_32_32_SINT: + case FMT6_32_32_32_32_UINT: + case FMT6_32_32_32_32_SINT: + return R2D_INT32; + + case FMT6_16_UINT: + case FMT6_16_SINT: + case FMT6_16_16_UINT: + case FMT6_16_16_SINT: + case FMT6_16_16_16_16_UINT: + case FMT6_16_16_16_16_SINT: + case FMT6_10_10_10_2_UINT: + return R2D_INT16; + + case FMT6_8_UINT: + case FMT6_8_SINT: + case FMT6_8_8_UINT: + case FMT6_8_8_SINT: + case FMT6_8_8_8_8_UINT: + case FMT6_8_8_8_8_SINT: + case FMT6_Z24_UNORM_S8_UINT: + case FMT6_Z24_UNORM_S8_UINT_AS_R8G8B8A8: + return R2D_INT8; + + case FMT6_16_UNORM: + case FMT6_16_SNORM: + case FMT6_16_16_UNORM: + case FMT6_16_16_SNORM: + case FMT6_16_16_16_16_UNORM: + case FMT6_16_16_16_16_SNORM: + case FMT6_32_FLOAT: + case FMT6_32_32_FLOAT: + case FMT6_32_32_32_32_FLOAT: + return R2D_FLOAT32; + + case FMT6_16_FLOAT: + case FMT6_16_16_FLOAT: + case FMT6_16_16_16_16_FLOAT: + case FMT6_11_11_10_FLOAT: + case FMT6_10_10_10_2_UNORM_DEST: + return R2D_FLOAT16; + + default: + unreachable("bad format"); + return 0; + } +} /* Make sure none of the requested dimensions extend beyond the size of the * resource. Not entirely sure why this happens, but sometimes it does, and @@ -55,17 +127,33 @@ ok_dims(const struct pipe_resource *r, const struct pipe_box *b, int lvl) static bool ok_format(enum pipe_format pfmt) { - enum a6xx_color_fmt fmt = fd6_pipe2color(pfmt); - if (fmt == ~0) - return false; + enum a6xx_format fmt = fd6_pipe2color(pfmt); + + if (util_format_is_compressed(pfmt)) + return true; + + switch (pfmt) { + case PIPE_FORMAT_Z24_UNORM_S8_UINT: + case PIPE_FORMAT_Z24X8_UNORM: + case PIPE_FORMAT_Z16_UNORM: + case PIPE_FORMAT_Z32_UNORM: + case PIPE_FORMAT_Z32_FLOAT: + case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT: + case PIPE_FORMAT_S8_UINT: + return true; + default: + break; + } - if (fd6_ifmt(fmt) == 0) + if (fmt == FMT6_NONE) return false; return true; } +#define DEBUG_BLIT 0 #define DEBUG_BLIT_FALLBACK 0 + #define fail_if(cond) \ do { \ if (cond) { \ @@ -90,29 +178,12 @@ can_do_blit(const struct pipe_blit_info *info) */ fail_if(info->dst.box.depth != info->src.box.depth); - /* We can blit if both or neither formats are compressed formats... */ - fail_if(util_format_is_compressed(info->src.format) != - util_format_is_compressed(info->src.format)); - /* Fail if unsupported format: */ fail_if(!ok_format(info->src.format)); fail_if(!ok_format(info->dst.format)); - /* ... but only if they're the same compression format. */ - fail_if(util_format_is_compressed(info->src.format) && - info->src.format != info->dst.format); - - /* hw ignores {SRC,DST}_INFO.COLOR_SWAP if {SRC,DST}_INFO.TILE_MODE - * is set (not linear). We can kind of get around that when tiling/ - * untiling by setting both src and dst COLOR_SWAP=WZYX, but that - * means the formats must match: - */ - fail_if((fd_resource(info->dst.resource)->tile_mode || - fd_resource(info->src.resource)->tile_mode) && - info->dst.format != info->src.format); - - /* src box can be inverted, which we don't support.. dst box cannot: */ - fail_if((info->src.box.width < 0) || (info->src.box.height < 0)); + debug_assert(!util_format_is_compressed(info->src.format)); + debug_assert(!util_format_is_compressed(info->dst.format)); fail_if(!ok_dims(info->src.resource, &info->src.box, info->src.level)); @@ -122,60 +193,113 @@ can_do_blit(const struct pipe_blit_info *info) debug_assert(info->dst.box.height >= 0); debug_assert(info->dst.box.depth >= 0); - fail_if(info->dst.resource->nr_samples + info->src.resource->nr_samples > 2); + fail_if(info->dst.resource->nr_samples > 1); fail_if(info->window_rectangle_include); - fail_if(info->render_condition_enable); + const struct util_format_description *src_desc = + util_format_description(info->src.format); + const struct util_format_description *dst_desc = + util_format_description(info->dst.format); + const int common_channels = MIN2(src_desc->nr_channels, dst_desc->nr_channels); + + if (info->mask & PIPE_MASK_RGBA) { + for (int i = 0; i < common_channels; i++) { + fail_if(memcmp(&src_desc->channel[i], + &dst_desc->channel[i], + sizeof(src_desc->channel[0]))); + } + } fail_if(info->alpha_blend); - fail_if(info->mask != util_format_get_mask(info->src.format)); - - fail_if(info->mask != util_format_get_mask(info->dst.format)); - return true; } static void -emit_setup(struct fd_ringbuffer *ring) +emit_setup(struct fd_batch *batch) { - OUT_PKT7(ring, CP_EVENT_WRITE, 1); - OUT_RING(ring, PC_CCU_INVALIDATE_COLOR); - - OUT_PKT7(ring, CP_EVENT_WRITE, 1); - OUT_RING(ring, LRZ_FLUSH); + struct fd_ringbuffer *ring = batch->draw; - OUT_PKT7(ring, CP_SKIP_IB2_ENABLE_GLOBAL, 1); - OUT_RING(ring, 0x0); + fd6_event_write(batch, ring, PC_CCU_FLUSH_COLOR_TS, true); + fd6_event_write(batch, ring, PC_CCU_FLUSH_DEPTH_TS, true); + fd6_event_write(batch, ring, PC_CCU_INVALIDATE_COLOR, false); + fd6_event_write(batch, ring, PC_CCU_INVALIDATE_DEPTH, false); + /* normal BLIT_OP_SCALE operation needs bypass RB_CCU_CNTL */ OUT_WFI5(ring); - OUT_PKT4(ring, REG_A6XX_RB_CCU_CNTL, 1); - OUT_RING(ring, 0x10000000); + OUT_RING(ring, fd6_context(batch->ctx)->magic.RB_CCU_CNTL_bypass); } -static uint32_t -blit_control(enum a6xx_color_fmt fmt) +static void +emit_blit_setup(struct fd_ringbuffer *ring, + enum pipe_format pfmt, bool scissor_enable, union pipe_color_union *color) { - unsigned blit_cntl = 0xf00000; - blit_cntl |= A6XX_RB_2D_BLIT_CNTL_COLOR_FORMAT(fmt); - blit_cntl |= A6XX_RB_2D_BLIT_CNTL_IFMT(fd6_ifmt(fmt)); - return blit_cntl; + enum a6xx_format fmt = fd6_pipe2color(pfmt); + bool is_srgb = util_format_is_srgb(pfmt); + enum a6xx_2d_ifmt ifmt = fd6_ifmt(fmt); + + OUT_PKT7(ring, CP_SET_MARKER, 1); + OUT_RING(ring, A6XX_CP_SET_MARKER_0_MODE(RM6_BLIT2DSCALE)); + + if (is_srgb) { + assert(ifmt == R2D_UNORM8); + ifmt = R2D_UNORM8_SRGB; + } + + uint32_t blit_cntl = A6XX_RB_2D_BLIT_CNTL_MASK(0xf) | + A6XX_RB_2D_BLIT_CNTL_COLOR_FORMAT(fmt) | + A6XX_RB_2D_BLIT_CNTL_IFMT(ifmt) | + COND(color, A6XX_RB_2D_BLIT_CNTL_SOLID_COLOR) | + COND(scissor_enable, A6XX_RB_2D_BLIT_CNTL_SCISSOR); + + OUT_PKT4(ring, REG_A6XX_RB_2D_BLIT_CNTL, 1); + OUT_RING(ring, blit_cntl); + + OUT_PKT4(ring, REG_A6XX_GRAS_2D_BLIT_CNTL, 1); + OUT_RING(ring, blit_cntl); + + if (fmt == FMT6_10_10_10_2_UNORM_DEST) + fmt = FMT6_16_16_16_16_FLOAT; + + /* This register is probably badly named... it seems that it's + * controlling the internal/accumulator format or something like + * that. It's certainly not tied to only the src format. + */ + OUT_PKT4(ring, REG_A6XX_SP_2D_SRC_FORMAT, 1); + OUT_RING(ring, A6XX_SP_2D_SRC_FORMAT_COLOR_FORMAT(fmt) | + COND(util_format_is_pure_sint(pfmt), + A6XX_SP_2D_SRC_FORMAT_SINT) | + COND(util_format_is_pure_uint(pfmt), + A6XX_SP_2D_SRC_FORMAT_UINT) | + COND(util_format_is_snorm(pfmt), + A6XX_SP_2D_SRC_FORMAT_SINT | + A6XX_SP_2D_SRC_FORMAT_NORM) | + COND(util_format_is_unorm(pfmt), +// TODO sometimes blob uses UINT+NORM but dEQP seems unhappy about that +// A6XX_SP_2D_SRC_FORMAT_UINT | + A6XX_SP_2D_SRC_FORMAT_NORM) | + COND(is_srgb, A6XX_SP_2D_SRC_FORMAT_SRGB) | + A6XX_SP_2D_SRC_FORMAT_MASK(0xf)); + + OUT_PKT4(ring, REG_A6XX_RB_UNKNOWN_8C01, 1); + OUT_RING(ring, 0); } /* buffers need to be handled specially since x/width can exceed the bounds * supported by hw.. if necessary decompose into (potentially) two 2D blits */ static void -emit_blit_buffer(struct fd_ringbuffer *ring, const struct pipe_blit_info *info) +emit_blit_buffer(struct fd_context *ctx, struct fd_ringbuffer *ring, + const struct pipe_blit_info *info) { const struct pipe_box *sbox = &info->src.box; const struct pipe_box *dbox = &info->dst.box; struct fd_resource *src, *dst; unsigned sshift, dshift; - if (DEBUG_BLIT_FALLBACK) { + if (DEBUG_BLIT) { fprintf(stderr, "buffer blit: "); util_dump_blit_info(stderr, info); fprintf(stderr, "\ndst resource: "); @@ -188,8 +312,8 @@ emit_blit_buffer(struct fd_ringbuffer *ring, const struct pipe_blit_info *info) src = fd_resource(info->src.resource); dst = fd_resource(info->dst.resource); - debug_assert(src->cpp == 1); - debug_assert(dst->cpp == 1); + debug_assert(src->layout.cpp == 1); + debug_assert(dst->layout.cpp == 1); debug_assert(info->src.resource->format == info->dst.resource->format); debug_assert((sbox->y == 0) && (sbox->height == 1)); debug_assert((dbox->y == 0) && (dbox->height == 1)); @@ -220,15 +344,7 @@ emit_blit_buffer(struct fd_ringbuffer *ring, const struct pipe_blit_info *info) sshift = sbox->x & 0x3f; dshift = dbox->x & 0x3f; - OUT_PKT7(ring, CP_SET_MARKER, 1); - OUT_RING(ring, A2XX_CP_SET_MARKER_0_MODE(RM6_BLIT2DSCALE)); - - uint32_t blit_cntl = blit_control(RB6_R8_UNORM) | 0x20000000; - OUT_PKT4(ring, REG_A6XX_RB_2D_BLIT_CNTL, 1); - OUT_RING(ring, blit_cntl); - - OUT_PKT4(ring, REG_A6XX_GRAS_2D_BLIT_CNTL, 1); - OUT_RING(ring, blit_cntl); + emit_blit_setup(ring, PIPE_FORMAT_R8_UNORM, false, NULL); for (unsigned off = 0; off < sbox->width; off += (0x4000 - 0x40)) { unsigned soff, doff, w, p; @@ -245,10 +361,11 @@ emit_blit_buffer(struct fd_ringbuffer *ring, const struct pipe_blit_info *info) /* * Emit source: */ - OUT_PKT4(ring, REG_A6XX_SP_PS_2D_SRC_INFO, 13); - OUT_RING(ring, A6XX_SP_PS_2D_SRC_INFO_COLOR_FORMAT(RB6_R8_UNORM) | + OUT_PKT4(ring, REG_A6XX_SP_PS_2D_SRC_INFO, 10); + OUT_RING(ring, A6XX_SP_PS_2D_SRC_INFO_COLOR_FORMAT(FMT6_8_UNORM) | A6XX_SP_PS_2D_SRC_INFO_TILE_MODE(TILE6_LINEAR) | - A6XX_SP_PS_2D_SRC_INFO_COLOR_SWAP(WZYX) | 0x500000); + A6XX_SP_PS_2D_SRC_INFO_COLOR_SWAP(WZYX) | + 0x500000); OUT_RING(ring, A6XX_SP_PS_2D_SRC_SIZE_WIDTH(sshift + w) | A6XX_SP_PS_2D_SRC_SIZE_HEIGHT(1)); /* SP_PS_2D_SRC_SIZE */ OUT_RELOC(ring, src->bo, soff, 0, 0); /* SP_PS_2D_SRC_LO/HI */ @@ -260,15 +377,11 @@ emit_blit_buffer(struct fd_ringbuffer *ring, const struct pipe_blit_info *info) OUT_RING(ring, 0x00000000); OUT_RING(ring, 0x00000000); - OUT_RING(ring, 0x00000000); - OUT_RING(ring, 0x00000000); - OUT_RING(ring, 0x00000000); - /* * Emit destination: */ OUT_PKT4(ring, REG_A6XX_RB_2D_DST_INFO, 9); - OUT_RING(ring, A6XX_RB_2D_DST_INFO_COLOR_FORMAT(RB6_R8_UNORM) | + OUT_RING(ring, A6XX_RB_2D_DST_INFO_COLOR_FORMAT(FMT6_8_UNORM) | A6XX_RB_2D_DST_INFO_TILE_MODE(TILE6_LINEAR) | A6XX_RB_2D_DST_INFO_COLOR_SWAP(WZYX)); OUT_RELOC(ring, dst->bo, doff, 0, 0); /* RB_2D_DST_LO/HI */ @@ -296,14 +409,8 @@ emit_blit_buffer(struct fd_ringbuffer *ring, const struct pipe_blit_info *info) OUT_RING(ring, 0x3f); OUT_WFI5(ring); - OUT_PKT4(ring, REG_A6XX_RB_UNKNOWN_8C01, 1); - OUT_RING(ring, 0); - - OUT_PKT4(ring, REG_A6XX_SP_2D_SRC_FORMAT, 1); - OUT_RING(ring, 0xf180); - OUT_PKT4(ring, REG_A6XX_RB_UNKNOWN_8E04, 1); - OUT_RING(ring, 0x01000000); + OUT_RING(ring, fd6_context(ctx)->magic.RB_UNKNOWN_8E04_blit); OUT_PKT7(ring, CP_BLIT, 1); OUT_RING(ring, CP_BLIT_0_OP(BLIT_OP_SCALE)); @@ -311,25 +418,110 @@ emit_blit_buffer(struct fd_ringbuffer *ring, const struct pipe_blit_info *info) OUT_WFI5(ring); OUT_PKT4(ring, REG_A6XX_RB_UNKNOWN_8E04, 1); - OUT_RING(ring, 0); + OUT_RING(ring, 0); /* RB_UNKNOWN_8E04 */ + } +} + +static void +emit_blit_dst(struct fd_ringbuffer *ring, struct pipe_resource *prsc, enum pipe_format pfmt, unsigned level, unsigned layer) +{ + struct fd_resource *dst = fd_resource(prsc); + enum a6xx_format fmt = fd6_pipe2color(pfmt); + enum a6xx_tile_mode tile = fd_resource_tile_mode(prsc, level); + enum a3xx_color_swap swap = fd6_resource_swap(dst, pfmt); + uint32_t pitch = fd_resource_pitch(dst, level); + bool ubwc_enabled = fd_resource_ubwc_enabled(dst, level); + unsigned off = fd_resource_offset(dst, level, layer); + + if (fmt == FMT6_Z24_UNORM_S8_UINT) + fmt = FMT6_Z24_UNORM_S8_UINT_AS_R8G8B8A8; + + OUT_PKT4(ring, REG_A6XX_RB_2D_DST_INFO, 9); + OUT_RING(ring, A6XX_RB_2D_DST_INFO_COLOR_FORMAT(fmt) | + A6XX_RB_2D_DST_INFO_TILE_MODE(tile) | + A6XX_RB_2D_DST_INFO_COLOR_SWAP(swap) | + COND(util_format_is_srgb(pfmt), A6XX_RB_2D_DST_INFO_SRGB) | + COND(ubwc_enabled, A6XX_RB_2D_DST_INFO_FLAGS)); + OUT_RELOC(ring, dst->bo, off, 0, 0); /* RB_2D_DST_LO/HI */ + OUT_RING(ring, A6XX_RB_2D_DST_SIZE_PITCH(pitch)); + OUT_RING(ring, 0x00000000); + OUT_RING(ring, 0x00000000); + OUT_RING(ring, 0x00000000); + OUT_RING(ring, 0x00000000); + OUT_RING(ring, 0x00000000); + + if (ubwc_enabled) { + OUT_PKT4(ring, REG_A6XX_RB_2D_DST_FLAGS_LO, 6); + fd6_emit_flag_reference(ring, dst, level, layer); + OUT_RING(ring, 0x00000000); + OUT_RING(ring, 0x00000000); + OUT_RING(ring, 0x00000000); } } static void -emit_blit_texture(struct fd_ringbuffer *ring, const struct pipe_blit_info *info) +emit_blit_src(struct fd_ringbuffer *ring, const struct pipe_blit_info *info, unsigned layer, unsigned nr_samples) +{ + struct fd_resource *src = fd_resource(info->src.resource); + enum a6xx_format sfmt = fd6_pipe2color(info->src.format); + enum a6xx_tile_mode stile = fd_resource_tile_mode(info->src.resource, info->src.level); + enum a3xx_color_swap sswap = fd6_resource_swap(src, info->src.format); + uint32_t pitch = fd_resource_pitch(src, info->src.level); + bool subwc_enabled = fd_resource_ubwc_enabled(src, info->src.level); + unsigned soff = fd_resource_offset(src, info->src.level, layer); + uint32_t width = u_minify(src->base.width0, info->src.level) * nr_samples; + uint32_t height = u_minify(src->base.height0, info->src.level); + uint32_t filter = 0; + + if (info->filter == PIPE_TEX_FILTER_LINEAR) + filter = A6XX_SP_PS_2D_SRC_INFO_FILTER; + + enum a3xx_msaa_samples samples = fd_msaa_samples(src->base.nr_samples); + + if (sfmt == FMT6_10_10_10_2_UNORM_DEST) + sfmt = FMT6_10_10_10_2_UNORM; + + OUT_PKT4(ring, REG_A6XX_SP_PS_2D_SRC_INFO, 10); + OUT_RING(ring, A6XX_SP_PS_2D_SRC_INFO_COLOR_FORMAT(sfmt) | + A6XX_SP_PS_2D_SRC_INFO_TILE_MODE(stile) | + A6XX_SP_PS_2D_SRC_INFO_COLOR_SWAP(sswap) | + A6XX_SP_PS_2D_SRC_INFO_SAMPLES(samples) | + COND(samples > MSAA_ONE && (info->mask & PIPE_MASK_RGBA), + A6XX_SP_PS_2D_SRC_INFO_SAMPLES_AVERAGE) | + COND(subwc_enabled, A6XX_SP_PS_2D_SRC_INFO_FLAGS) | + COND(util_format_is_srgb(info->src.format), A6XX_SP_PS_2D_SRC_INFO_SRGB) | + 0x500000 | filter); + OUT_RING(ring, A6XX_SP_PS_2D_SRC_SIZE_WIDTH(width) | + A6XX_SP_PS_2D_SRC_SIZE_HEIGHT(height)); /* SP_PS_2D_SRC_SIZE */ + OUT_RELOC(ring, src->bo, soff, 0, 0); /* SP_PS_2D_SRC_LO/HI */ + OUT_RING(ring, A6XX_SP_PS_2D_SRC_PITCH_PITCH(pitch)); + + OUT_RING(ring, 0x00000000); + OUT_RING(ring, 0x00000000); + OUT_RING(ring, 0x00000000); + OUT_RING(ring, 0x00000000); + OUT_RING(ring, 0x00000000); + + if (subwc_enabled) { + OUT_PKT4(ring, REG_A6XX_SP_PS_2D_SRC_FLAGS_LO, 6); + fd6_emit_flag_reference(ring, src, info->src.level, layer); + OUT_RING(ring, 0x00000000); + OUT_RING(ring, 0x00000000); + OUT_RING(ring, 0x00000000); + } +} + +static void +emit_blit_texture(struct fd_context *ctx, + struct fd_ringbuffer *ring, const struct pipe_blit_info *info) { const struct pipe_box *sbox = &info->src.box; const struct pipe_box *dbox = &info->dst.box; - struct fd_resource *src, *dst; - struct fd_resource_slice *sslice, *dslice; - enum a6xx_color_fmt sfmt, dfmt; - enum a6xx_tile_mode stile, dtile; - enum a3xx_color_swap sswap, dswap; - unsigned spitch, dpitch; - unsigned sx1, sy1, sx2, sy2; - unsigned dx1, dy1, dx2, dy2; - - if (DEBUG_BLIT_FALLBACK) { + struct fd_resource *dst; + int sx1, sy1, sx2, sy2; + int dx1, dy1, dx2, dy2; + + if (DEBUG_BLIT) { fprintf(stderr, "texture blit: "); util_dump_blit_info(stderr, info); fprintf(stderr, "\ndst resource: "); @@ -339,167 +531,145 @@ emit_blit_texture(struct fd_ringbuffer *ring, const struct pipe_blit_info *info) fprintf(stderr, "\n"); } - src = fd_resource(info->src.resource); dst = fd_resource(info->dst.resource); - sslice = fd_resource_slice(src, info->src.level); - dslice = fd_resource_slice(dst, info->dst.level); + uint32_t nr_samples = fd_resource_nr_samples(&dst->base); - sfmt = fd6_pipe2color(info->src.format); - dfmt = fd6_pipe2color(info->dst.format); + sx1 = sbox->x * nr_samples; + sy1 = sbox->y; + sx2 = (sbox->x + sbox->width) * nr_samples - 1; + sy2 = sbox->y + sbox->height - 1; - int blocksize = util_format_get_blocksize(info->src.format); - int blockwidth = util_format_get_blockwidth(info->src.format); - int blockheight = util_format_get_blockheight(info->src.format); - int nelements; + OUT_PKT4(ring, REG_A6XX_GRAS_2D_SRC_TL_X, 4); + OUT_RING(ring, A6XX_GRAS_2D_SRC_TL_X_X(sx1)); + OUT_RING(ring, A6XX_GRAS_2D_SRC_BR_X_X(sx2)); + OUT_RING(ring, A6XX_GRAS_2D_SRC_TL_Y_Y(sy1)); + OUT_RING(ring, A6XX_GRAS_2D_SRC_BR_Y_Y(sy2)); - stile = fd_resource_level_linear(info->src.resource, info->src.level) ? - TILE6_LINEAR : src->tile_mode; - dtile = fd_resource_level_linear(info->dst.resource, info->dst.level) ? - TILE6_LINEAR : dst->tile_mode; + dx1 = dbox->x * nr_samples; + dy1 = dbox->y; + dx2 = (dbox->x + dbox->width) * nr_samples - 1; + dy2 = dbox->y + dbox->height - 1; - sswap = fd6_pipe2swap(info->src.format); - dswap = fd6_pipe2swap(info->dst.format); + OUT_PKT4(ring, REG_A6XX_GRAS_2D_DST_TL, 2); + OUT_RING(ring, A6XX_GRAS_2D_DST_TL_X(dx1) | A6XX_GRAS_2D_DST_TL_Y(dy1)); + OUT_RING(ring, A6XX_GRAS_2D_DST_BR_X(dx2) | A6XX_GRAS_2D_DST_BR_Y(dy2)); - if (util_format_is_compressed(info->src.format)) { - debug_assert(info->src.format == info->dst.format); - sfmt = dfmt = RB6_R8_UNORM; - nelements = blocksize; - } else { - debug_assert(!util_format_is_compressed(info->dst.format)); - nelements = 1; + if (info->scissor_enable) { + OUT_PKT4(ring, REG_A6XX_GRAS_RESOLVE_CNTL_1, 2); + OUT_RING(ring, A6XX_GRAS_RESOLVE_CNTL_1_X(info->scissor.minx) | + A6XX_GRAS_RESOLVE_CNTL_1_Y(info->scissor.miny)); + OUT_RING(ring, A6XX_GRAS_RESOLVE_CNTL_1_X(info->scissor.maxx - 1) | + A6XX_GRAS_RESOLVE_CNTL_1_Y(info->scissor.maxy - 1)); } - spitch = DIV_ROUND_UP(sslice->pitch, blockwidth) * src->cpp; - dpitch = DIV_ROUND_UP(dslice->pitch, blockwidth) * dst->cpp; - - sx1 = sbox->x / blockwidth * nelements; - sy1 = sbox->y / blockheight; - sx2 = DIV_ROUND_UP(sbox->x + sbox->width, blockwidth) * nelements - 1; - sy2 = DIV_ROUND_UP(sbox->y + sbox->height, blockheight) - 1; + emit_blit_setup(ring, info->dst.format, info->scissor_enable, NULL); - dx1 = dbox->x / blockwidth * nelements; - dy1 = dbox->y / blockheight; - dx2 = DIV_ROUND_UP(dbox->x + dbox->width, blockwidth) * nelements - 1; - dy2 = DIV_ROUND_UP(dbox->y + dbox->height, blockheight) - 1; + for (unsigned i = 0; i < info->dst.box.depth; i++) { - uint32_t width = DIV_ROUND_UP(u_minify(src->base.width0, info->src.level), blockwidth) * nelements; - uint32_t height = DIV_ROUND_UP(u_minify(src->base.height0, info->src.level), blockheight); + emit_blit_src(ring, info, sbox->z + i, nr_samples); + emit_blit_dst(ring, info->dst.resource, info->dst.format, info->dst.level, dbox->z + i); - /* if dtile, then dswap ignored by hw, and likewise if stile then sswap - * ignored by hw.. but in this case we have already rejected the blit - * if src and dst formats differ, so juse use WZYX for both src and - * dst swap mode (so we don't change component order) - */ - if (stile || dtile) { - debug_assert(info->src.format == info->dst.format); - sswap = dswap = WZYX; - } + /* + * Blit command: + */ + OUT_PKT7(ring, CP_EVENT_WRITE, 1); + OUT_RING(ring, 0x3f); + OUT_WFI5(ring); - OUT_PKT7(ring, CP_SET_MARKER, 1); - OUT_RING(ring, A2XX_CP_SET_MARKER_0_MODE(RM6_BLIT2DSCALE)); + OUT_PKT4(ring, REG_A6XX_RB_UNKNOWN_8E04, 1); + OUT_RING(ring, fd6_context(ctx)->magic.RB_UNKNOWN_8E04_blit); - uint32_t blit_cntl = blit_control(dfmt); + OUT_PKT7(ring, CP_BLIT, 1); + OUT_RING(ring, CP_BLIT_0_OP(BLIT_OP_SCALE)); - if (dtile != stile) - blit_cntl |= 0x20000000; + OUT_WFI5(ring); - if (info->scissor_enable) { - OUT_PKT4(ring, REG_A6XX_GRAS_RESOLVE_CNTL_1, 2); - OUT_RING(ring, A6XX_GRAS_RESOLVE_CNTL_1_X(info->scissor.minx) | - A6XX_GRAS_RESOLVE_CNTL_1_Y(info->scissor.miny)); - OUT_RING(ring, A6XX_GRAS_RESOLVE_CNTL_1_X(info->scissor.maxx - 1) | - A6XX_GRAS_RESOLVE_CNTL_1_Y(info->scissor.maxy - 1)); - blit_cntl |= A6XX_RB_2D_BLIT_CNTL_SCISSOR; + OUT_PKT4(ring, REG_A6XX_RB_UNKNOWN_8E04, 1); + OUT_RING(ring, 0); /* RB_UNKNOWN_8E04 */ } +} - OUT_PKT4(ring, REG_A6XX_RB_2D_BLIT_CNTL, 1); - OUT_RING(ring, blit_cntl); +static void +emit_clear_color(struct fd_ringbuffer *ring, + enum pipe_format pfmt, union pipe_color_union *color) +{ + switch (pfmt) { + case PIPE_FORMAT_Z24X8_UNORM: + case PIPE_FORMAT_Z24_UNORM_S8_UINT: + case PIPE_FORMAT_X24S8_UINT: { + uint32_t depth_unorm24 = color->f[0] * ((1u << 24) - 1); + uint8_t stencil = color->ui[1]; + color->ui[0] = depth_unorm24 & 0xff; + color->ui[1] = (depth_unorm24 >> 8) & 0xff; + color->ui[2] = (depth_unorm24 >> 16) & 0xff; + color->ui[3] = stencil; + break; + } + default: + break; + } - OUT_PKT4(ring, REG_A6XX_GRAS_2D_BLIT_CNTL, 1); - OUT_RING(ring, blit_cntl); + OUT_PKT4(ring, REG_A6XX_RB_2D_SRC_SOLID_C0, 4); + switch (fd6_ifmt(fd6_pipe2color(pfmt))) { + case R2D_UNORM8: + case R2D_UNORM8_SRGB: + OUT_RING(ring, float_to_ubyte(color->f[0])); + OUT_RING(ring, float_to_ubyte(color->f[1])); + OUT_RING(ring, float_to_ubyte(color->f[2])); + OUT_RING(ring, float_to_ubyte(color->f[3])); + break; + case R2D_FLOAT16: + OUT_RING(ring, _mesa_float_to_half(color->f[0])); + OUT_RING(ring, _mesa_float_to_half(color->f[1])); + OUT_RING(ring, _mesa_float_to_half(color->f[2])); + OUT_RING(ring, _mesa_float_to_half(color->f[3])); + break; + case R2D_FLOAT32: + case R2D_INT32: + case R2D_INT16: + case R2D_INT8: + default: + OUT_RING(ring, color->ui[0]); + OUT_RING(ring, color->ui[1]); + OUT_RING(ring, color->ui[2]); + OUT_RING(ring, color->ui[3]); + break; + } +} - for (unsigned i = 0; i < info->dst.box.depth; i++) { - unsigned soff = fd_resource_offset(src, info->src.level, sbox->z + i); - unsigned doff = fd_resource_offset(dst, info->dst.level, dbox->z + i); +void +fd6_clear_surface(struct fd_context *ctx, + struct fd_ringbuffer *ring, struct pipe_surface *psurf, + uint32_t width, uint32_t height, union pipe_color_union *color) +{ + if (DEBUG_BLIT) { + fprintf(stderr, "surface clear:\ndst resource: "); + util_dump_resource(stderr, psurf->texture); + fprintf(stderr, "\n"); + } - /* - * Emit source: - */ - uint32_t filter = 0; - if (info->filter == PIPE_TEX_FILTER_LINEAR) - filter = A6XX_SP_PS_2D_SRC_INFO_FILTER; - - OUT_PKT4(ring, REG_A6XX_SP_PS_2D_SRC_INFO, 13); - OUT_RING(ring, A6XX_SP_PS_2D_SRC_INFO_COLOR_FORMAT(sfmt) | - A6XX_SP_PS_2D_SRC_INFO_TILE_MODE(stile) | - A6XX_SP_PS_2D_SRC_INFO_COLOR_SWAP(sswap) | 0x500000 | filter); - OUT_RING(ring, A6XX_SP_PS_2D_SRC_SIZE_WIDTH(width) | - A6XX_SP_PS_2D_SRC_SIZE_HEIGHT(height)); /* SP_PS_2D_SRC_SIZE */ - OUT_RELOC(ring, src->bo, soff, 0, 0); /* SP_PS_2D_SRC_LO/HI */ - OUT_RING(ring, A6XX_SP_PS_2D_SRC_PITCH_PITCH(spitch)); - OUT_RING(ring, 0x00000000); - OUT_RING(ring, 0x00000000); - OUT_RING(ring, 0x00000000); - OUT_RING(ring, 0x00000000); - OUT_RING(ring, 0x00000000); + uint32_t nr_samples = fd_resource_nr_samples(psurf->texture); + OUT_PKT4(ring, REG_A6XX_GRAS_2D_DST_TL, 2); + OUT_RING(ring, A6XX_GRAS_2D_DST_TL_X(0) | A6XX_GRAS_2D_DST_TL_Y(0)); + OUT_RING(ring, A6XX_GRAS_2D_DST_BR_X(width * nr_samples - 1) | + A6XX_GRAS_2D_DST_BR_Y(height - 1)); - OUT_RING(ring, 0x00000000); - OUT_RING(ring, 0x00000000); - OUT_RING(ring, 0x00000000); + emit_clear_color(ring, psurf->format, color); + emit_blit_setup(ring, psurf->format, false, color); - /* - * Emit destination: - */ - OUT_PKT4(ring, REG_A6XX_RB_2D_DST_INFO, 9); - OUT_RING(ring, A6XX_RB_2D_DST_INFO_COLOR_FORMAT(dfmt) | - A6XX_RB_2D_DST_INFO_TILE_MODE(dtile) | - A6XX_RB_2D_DST_INFO_COLOR_SWAP(dswap)); - OUT_RELOC(ring, dst->bo, doff, 0, 0); /* RB_2D_DST_LO/HI */ - OUT_RING(ring, A6XX_RB_2D_DST_SIZE_PITCH(dpitch)); - OUT_RING(ring, 0x00000000); - OUT_RING(ring, 0x00000000); - OUT_RING(ring, 0x00000000); - OUT_RING(ring, 0x00000000); - OUT_RING(ring, 0x00000000); + for (unsigned i = psurf->u.tex.first_layer; i <= psurf->u.tex.last_layer; i++) { + emit_blit_dst(ring, psurf->texture, psurf->format, psurf->u.tex.level, i); /* * Blit command: */ - OUT_PKT4(ring, REG_A6XX_GRAS_2D_SRC_TL_X, 4); - OUT_RING(ring, A6XX_GRAS_2D_SRC_TL_X_X(sx1)); - OUT_RING(ring, A6XX_GRAS_2D_SRC_BR_X_X(sx2)); - OUT_RING(ring, A6XX_GRAS_2D_SRC_TL_Y_Y(sy1)); - OUT_RING(ring, A6XX_GRAS_2D_SRC_BR_Y_Y(sy2)); - - OUT_PKT4(ring, REG_A6XX_GRAS_2D_DST_TL, 2); - OUT_RING(ring, A6XX_GRAS_2D_DST_TL_X(dx1) | A6XX_GRAS_2D_DST_TL_Y(dy1)); - OUT_RING(ring, A6XX_GRAS_2D_DST_BR_X(dx2) | A6XX_GRAS_2D_DST_BR_Y(dy2)); - OUT_PKT7(ring, CP_EVENT_WRITE, 1); OUT_RING(ring, 0x3f); OUT_WFI5(ring); - OUT_PKT4(ring, REG_A6XX_RB_UNKNOWN_8C01, 1); - OUT_RING(ring, 0); - - OUT_PKT4(ring, REG_A6XX_SP_2D_SRC_FORMAT, 1); - OUT_RING(ring, A6XX_SP_2D_SRC_FORMAT_COLOR_FORMAT(sfmt) | - COND(util_format_is_pure_sint(info->src.format), - A6XX_SP_2D_SRC_FORMAT_SINT) | - COND(util_format_is_pure_uint(info->src.format), - A6XX_SP_2D_SRC_FORMAT_UINT) | - COND(util_format_is_snorm(info->src.format), - A6XX_SP_2D_SRC_FORMAT_SINT | - A6XX_SP_2D_SRC_FORMAT_NORM) | - COND(util_format_is_unorm(info->src.format), -// TODO sometimes blob uses UINT+NORM but dEQP seems unhappy about that -// A6XX_SP_2D_SRC_FORMAT_UINT | - A6XX_SP_2D_SRC_FORMAT_NORM) | - 0xf000); - OUT_PKT4(ring, REG_A6XX_RB_UNKNOWN_8E04, 1); - OUT_RING(ring, 0x01000000); + OUT_RING(ring, fd6_context(ctx)->magic.RB_UNKNOWN_8E04_blit); OUT_PKT7(ring, CP_BLIT, 1); OUT_RING(ring, CP_BLIT_0_OP(BLIT_OP_SCALE)); @@ -507,111 +677,228 @@ emit_blit_texture(struct fd_ringbuffer *ring, const struct pipe_blit_info *info) OUT_WFI5(ring); OUT_PKT4(ring, REG_A6XX_RB_UNKNOWN_8E04, 1); - OUT_RING(ring, 0); + OUT_RING(ring, 0); /* RB_UNKNOWN_8E04 */ } } -static void -emit_blit(struct pipe_context *pctx, const struct pipe_blit_info *info) +static bool +handle_rgba_blit(struct fd_context *ctx, const struct pipe_blit_info *info) { - struct fd_context *ctx = fd_context(pctx); struct fd_batch *batch; - fd_fence_ref(pctx->screen, &ctx->last_fence, NULL); + debug_assert(!(info->mask & PIPE_MASK_ZS)); + + if (!can_do_blit(info)) + return false; batch = fd_bc_alloc_batch(&ctx->screen->batch_cache, ctx, true); fd6_emit_restore(batch, batch->draw); fd6_emit_lrz_flush(batch->draw); - mtx_lock(&ctx->screen->lock); + fd_screen_lock(ctx->screen); - fd_batch_resource_used(batch, fd_resource(info->src.resource), false); - fd_batch_resource_used(batch, fd_resource(info->dst.resource), true); + fd_batch_resource_read(batch, fd_resource(info->src.resource)); + fd_batch_resource_write(batch, fd_resource(info->dst.resource)); + + fd_screen_unlock(ctx->screen); + + /* Clearing last_fence must come after the batch dependency tracking + * (resource_read()/resource_write()), as that can trigger a flush, + * re-populating last_fence + */ + fd_fence_ref(&ctx->last_fence, NULL); - mtx_unlock(&ctx->screen->lock); + fd_batch_set_stage(batch, FD_STAGE_BLIT); - emit_setup(batch->draw); + fd_log_stream(batch, stream, util_dump_blit_info(stream, info)); + + emit_setup(batch); if ((info->src.resource->target == PIPE_BUFFER) && (info->dst.resource->target == PIPE_BUFFER)) { - assert(fd_resource(info->src.resource)->tile_mode == TILE6_LINEAR); - assert(fd_resource(info->dst.resource)->tile_mode == TILE6_LINEAR); - emit_blit_buffer(batch->draw, info); + assert(fd_resource(info->src.resource)->layout.tile_mode == TILE6_LINEAR); + assert(fd_resource(info->dst.resource)->layout.tile_mode == TILE6_LINEAR); + fd_log(batch, "START BLIT (BUFFER)"); + emit_blit_buffer(ctx, batch->draw, info); + fd_log(batch, "END BLIT (BUFFER)"); } else { /* I don't *think* we need to handle blits between buffer <-> !buffer */ debug_assert(info->src.resource->target != PIPE_BUFFER); debug_assert(info->dst.resource->target != PIPE_BUFFER); - emit_blit_texture(batch->draw, info); + fd_log(batch, "START BLIT (TEXTURE)"); + emit_blit_texture(ctx, batch->draw, info); + fd_log(batch, "END BLIT (TEXTURE)"); } - fd6_event_write(batch, batch->draw, 0x1d, true); - fd6_event_write(batch, batch->draw, FACENESS_FLUSH, true); + fd6_event_write(batch, batch->draw, PC_CCU_FLUSH_COLOR_TS, true); + fd6_event_write(batch, batch->draw, PC_CCU_FLUSH_DEPTH_TS, true); fd6_event_write(batch, batch->draw, CACHE_FLUSH_TS, true); + fd6_cache_inv(batch, batch->draw); fd_resource(info->dst.resource)->valid = true; batch->needs_flush = true; - fd_batch_flush(batch, false, false); + fd_batch_flush(batch); fd_batch_reference(&batch, NULL); + + return true; } -static void -fd6_blit(struct pipe_context *pctx, const struct pipe_blit_info *info) +/** + * Re-written z/s blits can still fail for various reasons (for example MSAA). + * But we want to do the fallback blit with the re-written pipe_blit_info, + * in particular as u_blitter cannot blit stencil. So handle the fallback + * ourself and never "fail". + */ +static bool +do_rewritten_blit(struct fd_context *ctx, const struct pipe_blit_info *info) { - struct fd_context *ctx = fd_context(pctx); + bool success = handle_rgba_blit(ctx, info); + if (!success) + success = fd_blitter_blit(ctx, info); + debug_assert(success); /* fallback should never fail! */ + return success; +} - if (!can_do_blit(info)) { - fd_blitter_pipe_begin(ctx, info->render_condition_enable, false, FD_STAGE_BLIT); - fd_blitter_blit(ctx, info); - fd_blitter_pipe_end(ctx); - return; +/** + * Handle depth/stencil blits either via u_blitter and/or re-writing the + * blit into an equivilant format that we can handle + */ +static bool +handle_zs_blit(struct fd_context *ctx, const struct pipe_blit_info *info) +{ + struct pipe_blit_info blit = *info; + + if (DEBUG_BLIT) { + fprintf(stderr, "---- handle_zs_blit: "); + util_dump_blit_info(stderr, info); + fprintf(stderr, "\ndst resource: "); + util_dump_resource(stderr, info->dst.resource); + fprintf(stderr, "\nsrc resource: "); + util_dump_resource(stderr, info->src.resource); + fprintf(stderr, "\n"); } - emit_blit(pctx, info); + switch (info->dst.format) { + case PIPE_FORMAT_S8_UINT: + debug_assert(info->mask == PIPE_MASK_S); + blit.mask = PIPE_MASK_R; + blit.src.format = PIPE_FORMAT_R8_UINT; + blit.dst.format = PIPE_FORMAT_R8_UINT; + return do_rewritten_blit(ctx, &blit); + + case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT: + if (info->mask & PIPE_MASK_Z) { + blit.mask = PIPE_MASK_R; + blit.src.format = PIPE_FORMAT_R32_FLOAT; + blit.dst.format = PIPE_FORMAT_R32_FLOAT; + do_rewritten_blit(ctx, &blit); + } + + if (info->mask & PIPE_MASK_S) { + blit.mask = PIPE_MASK_R; + blit.src.format = PIPE_FORMAT_R8_UINT; + blit.dst.format = PIPE_FORMAT_R8_UINT; + blit.src.resource = &fd_resource(info->src.resource)->stencil->base; + blit.dst.resource = &fd_resource(info->dst.resource)->stencil->base; + do_rewritten_blit(ctx, &blit); + } + + return true; + + case PIPE_FORMAT_Z16_UNORM: + blit.mask = PIPE_MASK_R; + blit.src.format = PIPE_FORMAT_R16_UNORM; + blit.dst.format = PIPE_FORMAT_R16_UNORM; + return do_rewritten_blit(ctx, &blit); + + case PIPE_FORMAT_Z32_UNORM: + case PIPE_FORMAT_Z32_FLOAT: + debug_assert(info->mask == PIPE_MASK_Z); + blit.mask = PIPE_MASK_R; + blit.src.format = PIPE_FORMAT_R32_UINT; + blit.dst.format = PIPE_FORMAT_R32_UINT; + return do_rewritten_blit(ctx, &blit); + + case PIPE_FORMAT_Z24X8_UNORM: + case PIPE_FORMAT_Z24_UNORM_S8_UINT: + blit.mask = 0; + if (info->mask & PIPE_MASK_Z) + blit.mask |= PIPE_MASK_R | PIPE_MASK_G | PIPE_MASK_B; + if (info->mask & PIPE_MASK_S) + blit.mask |= PIPE_MASK_A; + blit.src.format = PIPE_FORMAT_Z24_UNORM_S8_UINT_AS_R8G8B8A8; + blit.dst.format = PIPE_FORMAT_Z24_UNORM_S8_UINT_AS_R8G8B8A8; + return fd_blitter_blit(ctx, &blit); + + default: + return false; + } } -static void -fd6_resource_copy_region(struct pipe_context *pctx, - struct pipe_resource *dst, - unsigned dst_level, - unsigned dstx, unsigned dsty, unsigned dstz, - struct pipe_resource *src, - unsigned src_level, - const struct pipe_box *src_box) +static bool +handle_compressed_blit(struct fd_context *ctx, const struct pipe_blit_info *info) { - struct pipe_blit_info info; - - debug_assert(src->format == dst->format); - - memset(&info, 0, sizeof info); - info.dst.resource = dst; - info.dst.level = dst_level; - info.dst.box.x = dstx; - info.dst.box.y = dsty; - info.dst.box.z = dstz; - info.dst.box.width = src_box->width; - info.dst.box.height = src_box->height; - assert(info.dst.box.width >= 0); - assert(info.dst.box.height >= 0); - info.dst.box.depth = 1; - info.dst.format = dst->format; - info.src.resource = src; - info.src.level = src_level; - info.src.box = *src_box; - info.src.format = src->format; - info.mask = util_format_get_mask(src->format); - info.filter = PIPE_TEX_FILTER_NEAREST; - info.scissor_enable = 0; - - if (!can_do_blit(&info)) { - fd_resource_copy_region(pctx, - dst, dst_level, dstx, dsty, dstz, - src, src_level, src_box); - return; + struct pipe_blit_info blit = *info; + + if (DEBUG_BLIT) { + fprintf(stderr, "---- handle_compressed_blit: "); + util_dump_blit_info(stderr, info); + fprintf(stderr, "\ndst resource: "); + util_dump_resource(stderr, info->dst.resource); + fprintf(stderr, "\nsrc resource: "); + util_dump_resource(stderr, info->src.resource); + fprintf(stderr, "\n"); + } + + if (info->src.format != info->dst.format) + return fd_blitter_blit(ctx, info); + + if (util_format_get_blocksize(info->src.format) == 8) { + blit.src.format = blit.dst.format = PIPE_FORMAT_R16G16B16A16_UINT; + } else { + debug_assert(util_format_get_blocksize(info->src.format) == 16); + blit.src.format = blit.dst.format = PIPE_FORMAT_R32G32B32A32_UINT; } - emit_blit(pctx, &info); + int bw = util_format_get_blockwidth(info->src.format); + int bh = util_format_get_blockheight(info->src.format); + + /* NOTE: x/y *must* be aligned to block boundary (ie. in + * glCompressedTexSubImage2D()) but width/height may not + * be: + */ + + debug_assert((blit.src.box.x % bw) == 0); + debug_assert((blit.src.box.y % bh) == 0); + + blit.src.box.x /= bw; + blit.src.box.y /= bh; + blit.src.box.width = DIV_ROUND_UP(blit.src.box.width, bw); + blit.src.box.height = DIV_ROUND_UP(blit.src.box.height, bh); + + debug_assert((blit.dst.box.x % bw) == 0); + debug_assert((blit.dst.box.y % bh) == 0); + + blit.dst.box.x /= bw; + blit.dst.box.y /= bh; + blit.dst.box.width = DIV_ROUND_UP(blit.dst.box.width, bw); + blit.dst.box.height = DIV_ROUND_UP(blit.dst.box.height, bh); + + return do_rewritten_blit(ctx, &blit); +} + +static bool +fd6_blit(struct fd_context *ctx, const struct pipe_blit_info *info) +{ + if (info->mask & PIPE_MASK_ZS) + return handle_zs_blit(ctx, info); + if (util_format_is_compressed(info->src.format) || + util_format_is_compressed(info->dst.format)) + return handle_compressed_blit(ctx, info); + + return handle_rgba_blit(ctx, info); } void @@ -620,15 +907,23 @@ fd6_blitter_init(struct pipe_context *pctx) if (fd_mesa_debug & FD_DBG_NOBLIT) return; - pctx->resource_copy_region = fd6_resource_copy_region; - pctx->blit = fd6_blit; + fd_context(pctx)->blit = fd6_blit; } unsigned fd6_tile_mode(const struct pipe_resource *tmpl) { + /* if the mipmap level 0 is still too small to be tiled, then don't + * bother pretending: + */ + if (fd_resource_level_linear(tmpl, 0)) + return TILE6_LINEAR; + /* basically just has to be a format we can blit, so uploads/downloads * via linear staging buffer works: */ - return TILE6_3; + if (ok_format(tmpl->format)) + return TILE6_3; + + return TILE6_LINEAR; }