From 5feb8adb0fa472aaeb7f7c5a75f0de5ac71a4ae7 Mon Sep 17 00:00:00 2001 From: Jonathan Marek Date: Mon, 1 Jul 2019 18:41:20 -0400 Subject: [PATCH] etnaviv: implement buffer compression Vivante GPUs have lossless buffer compression using the tile-status bits, which can reduce memory access and thus improve performance. This patch only enables compression for "V4" compression GPUs, but the implementation is tested on GC2000(V1) and GC3000(V2). V1/V2 compresssion looks absolutely useless, so it is not enabled. I couldn't test if this patch breaks MSAA, because it looks like MSAA is already broken. Signed-off-by: Jonathan Marek Reviewed-by: Christian Gmeiner --- src/gallium/drivers/etnaviv/etnaviv_blt.c | 30 +++++++++--------- src/gallium/drivers/etnaviv/etnaviv_blt.h | 3 +- .../drivers/etnaviv/etnaviv_resource.c | 15 +++++++++ .../drivers/etnaviv/etnaviv_resource.h | 1 + src/gallium/drivers/etnaviv/etnaviv_rs.c | 31 +++++++++---------- src/gallium/drivers/etnaviv/etnaviv_rs.h | 1 + src/gallium/drivers/etnaviv/etnaviv_state.c | 28 ++++++++++------- src/gallium/drivers/etnaviv/etnaviv_texture.c | 5 +-- 8 files changed, 65 insertions(+), 49 deletions(-) diff --git a/src/gallium/drivers/etnaviv/etnaviv_blt.c b/src/gallium/drivers/etnaviv/etnaviv_blt.c index e0274a5b599..471ed90d3ee 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_blt.c +++ b/src/gallium/drivers/etnaviv/etnaviv_blt.c @@ -70,8 +70,8 @@ blt_compute_img_config_bits(const struct blt_imginfo *img, bool for_dest) return BLT_IMAGE_CONFIG_TS_MODE(img->ts_mode) | COND(img->use_ts, BLT_IMAGE_CONFIG_TS) | - COND(img->compressed, BLT_IMAGE_CONFIG_COMPRESSION) | - BLT_IMAGE_CONFIG_COMPRESSION_FORMAT(img->compress_fmt) | + COND(img->use_ts && img->ts_compress_fmt >= 0, BLT_IMAGE_CONFIG_COMPRESSION) | + BLT_IMAGE_CONFIG_COMPRESSION_FORMAT(img->ts_compress_fmt) | COND(for_dest, BLT_IMAGE_CONFIG_UNK22) | BLT_IMAGE_CONFIG_SWIZ_R(0) | /* not used? */ BLT_IMAGE_CONFIG_SWIZ_G(1) | @@ -211,10 +211,6 @@ etna_blit_clear_color_blt(struct pipe_context *pctx, struct pipe_surface *dst, clr.dest.addr.flags = ETNA_RELOC_WRITE; clr.dest.bpp = util_format_get_blocksize(surf->base.format); clr.dest.stride = surf->surf.stride; - /* TODO: color compression - clr.dest.compressed = 1; - clr.dest.compress_fmt = 3; - */ clr.dest.tiling = res->layout; if (surf->surf.ts_size) { @@ -225,6 +221,7 @@ etna_blit_clear_color_blt(struct pipe_context *pctx, struct pipe_surface *dst, clr.dest.ts_clear_value[0] = new_clear_value; clr.dest.ts_clear_value[1] = new_clear_value; clr.dest.ts_mode = surf->level->ts_mode; + clr.dest.ts_compress_fmt = surf->level->ts_compress_fmt; } clr.clear_value[0] = new_clear_value; @@ -287,10 +284,6 @@ etna_blit_clear_zs_blt(struct pipe_context *pctx, struct pipe_surface *dst, clr.dest.addr.flags = ETNA_RELOC_WRITE; clr.dest.bpp = util_format_get_blocksize(surf->base.format); clr.dest.stride = surf->surf.stride; -#if 0 /* TODO depth compression */ - clr.dest.compressed = 1; - clr.dest.compress_fmt = COLOR_COMPRESSION_FORMAT_D24S8; -#endif clr.dest.tiling = res->layout; if (surf->surf.ts_size) { @@ -301,6 +294,7 @@ etna_blit_clear_zs_blt(struct pipe_context *pctx, struct pipe_surface *dst, clr.dest.ts_clear_value[0] = new_clear_value; clr.dest.ts_clear_value[1] = new_clear_value; clr.dest.ts_mode = surf->level->ts_mode; + clr.dest.ts_compress_fmt = surf->level->ts_compress_fmt; } clr.clear_value[0] = new_clear_value; @@ -418,12 +412,19 @@ etna_try_blt_blit(struct pipe_context *pctx, struct etna_resource_level *src_lev = &src->levels[blit_info->src.level]; struct etna_resource_level *dst_lev = &dst->levels[blit_info->dst.level]; - /* Kick off BLT here */ + /* if we asked for in-place resolve, return immediately if ts isn't valid + * do this check separately because it applies when compression is used, but + * we can't use inplace resolve path with compression + */ if (src == dst) { - /* Resolve-in-place */ assert(!memcmp(&blit_info->src, &blit_info->dst, sizeof(blit_info->src))); if (!src_lev->ts_size || !src_lev->ts_valid) /* No TS, no worries */ return true; + } + + /* Kick off BLT here */ + if (src == dst && src_lev->ts_compress_fmt < 0) { + /* Resolve-in-place */ struct blt_inplace_op op = {}; op.addr.bo = src->bo; @@ -464,6 +465,7 @@ etna_try_blt_blit(struct pipe_context *pctx, op.src.ts_clear_value[0] = src_lev->clear_value; op.src.ts_clear_value[1] = src_lev->clear_value; op.src.ts_mode = src_lev->ts_mode; + op.src.ts_compress_fmt = src_lev->ts_compress_fmt; } op.dest.addr.bo = dst->bo; @@ -471,10 +473,6 @@ etna_try_blt_blit(struct pipe_context *pctx, op.dest.addr.flags = ETNA_RELOC_WRITE; op.dest.format = translate_blt_format(dst_format); op.dest.stride = dst_lev->stride; - /* TODO color compression - op.dest.compressed = 1; - op.dest.compress_fmt = 3; - */ op.dest.tiling = dst->layout; const struct util_format_description *dst_format_desc = util_format_description(dst_format); diff --git a/src/gallium/drivers/etnaviv/etnaviv_blt.h b/src/gallium/drivers/etnaviv/etnaviv_blt.h index 8bbc6c5e875..7370d1dbf87 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_blt.h +++ b/src/gallium/drivers/etnaviv/etnaviv_blt.h @@ -37,17 +37,16 @@ struct pipe_context; /* src/dest info for image operations */ struct blt_imginfo { - unsigned compressed:1; unsigned use_ts:1; struct etna_reloc addr; struct etna_reloc ts_addr; uint32_t format; /* BLT_FORMAT_* */ uint32_t stride; - uint32_t compress_fmt; /* COLOR_COMPRESSION_FORMAT_* */ enum etna_surface_layout tiling; /* ETNA_LAYOUT_* */ uint32_t ts_clear_value[2]; uint8_t swizzle[4]; /* TEXTURE_SWIZZLE_* */ uint8_t ts_mode; /* TS_MODE_* */ + int8_t ts_compress_fmt; /* COLOR_COMPRESSION_FORMAT_* */ uint8_t endian_mode; /* ENDIAN_MODE_* */ uint8_t bpp; /* # bytes per pixel 1/2/4/8 - only used for CLEAR_IMAGE */ }; diff --git a/src/gallium/drivers/etnaviv/etnaviv_resource.c b/src/gallium/drivers/etnaviv/etnaviv_resource.c index 996232c94cd..44da60a22b1 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_resource.c +++ b/src/gallium/drivers/etnaviv/etnaviv_resource.c @@ -87,10 +87,24 @@ etna_screen_resource_alloc_ts(struct pipe_screen *pscreen, size_t rt_ts_size, ts_layer_stride; size_t ts_bits_per_tile, bytes_per_tile; uint8_t ts_mode = TS_MODE_128B; /* only used by halti5 */ + int8_t ts_compress_fmt; assert(!rsc->ts_bo); + /* pre-v4 compression is largely useless, so disable it when not wanted for MSAA + * v4 compression can be enabled everywhere without any known drawback, + * except that in-place resolve must go through a slower path + */ + ts_compress_fmt = (screen->specs.v4_compression || rsc->base.nr_samples > 1) ? + translate_ts_format(rsc->base.format) : -1; + if (screen->specs.halti >= 5) { + /* enable 256B ts mode with compression, as it improves performance + * the size of the resource might also determine if we want to use it or not + */ + if (ts_compress_fmt >= 0) + ts_mode = TS_MODE_256B; + ts_bits_per_tile = 4; bytes_per_tile = ts_mode == TS_MODE_256B ? 256 : 128; } else { @@ -121,6 +135,7 @@ etna_screen_resource_alloc_ts(struct pipe_screen *pscreen, rsc->levels[0].ts_layer_stride = ts_layer_stride; rsc->levels[0].ts_size = rt_ts_size; rsc->levels[0].ts_mode = ts_mode; + rsc->levels[0].ts_compress_fmt = ts_compress_fmt; return true; } diff --git a/src/gallium/drivers/etnaviv/etnaviv_resource.h b/src/gallium/drivers/etnaviv/etnaviv_resource.h index c2ad10fddc9..e86639b7f4d 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_resource.h +++ b/src/gallium/drivers/etnaviv/etnaviv_resource.h @@ -52,6 +52,7 @@ struct etna_resource_level { uint32_t clear_value; /* clear value of resource level (mainly for TS) */ bool ts_valid; uint8_t ts_mode; + int8_t ts_compress_fmt; /* COLOR_COMPRESSION_FORMAT_* (-1 = disable) */ /* keep track if we have done some per block patching */ bool patched; diff --git a/src/gallium/drivers/etnaviv/etnaviv_rs.c b/src/gallium/drivers/etnaviv/etnaviv_rs.c index 3ac4c5d5316..2653fc21335 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_rs.c +++ b/src/gallium/drivers/etnaviv/etnaviv_rs.c @@ -145,7 +145,8 @@ etna_compile_rs_state(struct etna_context *ctx, struct compiled_rs_state *cs, rs->source_stride == rs->dest_stride && !rs->downsample_x && !rs->downsample_y && !rs->swap_rb && !rs->flip && - !rs->clear_mode && rs->source_padded_width) { + !rs->clear_mode && rs->source_padded_width && + !rs->source_ts_compressed) { /* Total number of tiles (same as for autodisable) */ cs->RS_KICKER_INPLACE = rs->tile_count; } @@ -545,7 +546,6 @@ etna_try_rs_blit(struct pipe_context *pctx, struct etna_resource *src = etna_resource(blit_info->src.resource); struct etna_resource *dst = etna_resource(blit_info->dst.resource); struct compiled_rs_state copy_to_screen; - uint32_t ts_mem_config = 0; int msaa_xscale = 1, msaa_yscale = 1; /* Ensure that the level is valid */ @@ -661,13 +661,6 @@ etna_try_rs_blit(struct pipe_context *pctx, width & (w_align - 1) || height & (h_align - 1)) goto manual; - if (src->base.nr_samples > 1) { - uint32_t ts_format = translate_ts_format(src_format); - assert(ts_format != ETNA_NO_MATCH); - ts_mem_config |= VIVS_TS_MEM_CONFIG_COLOR_COMPRESSION | - VIVS_TS_MEM_CONFIG_COLOR_COMPRESSION_FORMAT(ts_format); - } - /* Always flush color and depth cache together before resolving. This works * around artifacts that appear in some cases when scanning out a texture * directly after it has been rendered to, such as rendering an animated web @@ -683,18 +676,22 @@ etna_try_rs_blit(struct pipe_context *pctx, VIVS_GL_FLUSH_CACHE_COLOR | VIVS_GL_FLUSH_CACHE_DEPTH); etna_stall(ctx->stream, SYNC_RECIPIENT_RA, SYNC_RECIPIENT_PE); - if (src->levels[blit_info->src.level].ts_size && - src->levels[blit_info->src.level].ts_valid) + if (src_lev->ts_size && src_lev->ts_valid) etna_set_state(ctx->stream, VIVS_TS_FLUSH_CACHE, VIVS_TS_FLUSH_CACHE_FLUSH); } /* Set up color TS to source surface before blit, if needed */ bool source_ts_valid = false; - if (src->levels[blit_info->src.level].ts_size && - src->levels[blit_info->src.level].ts_valid) { + if (src_lev->ts_size && src_lev->ts_valid) { struct etna_reloc reloc; unsigned ts_offset = src_lev->ts_offset + blit_info->src.box.z * src_lev->ts_layer_stride; + uint32_t ts_mem_config = 0; + + if (src_lev->ts_compress_fmt >= 0) { + ts_mem_config |= VIVS_TS_MEM_CONFIG_COLOR_COMPRESSION | + VIVS_TS_MEM_CONFIG_COLOR_COMPRESSION_FORMAT(src_lev->ts_compress_fmt); + } etna_set_state(ctx->stream, VIVS_TS_MEM_CONFIG, VIVS_TS_MEM_CONFIG_COLOR_FAST_CLEAR | ts_mem_config); @@ -712,12 +709,11 @@ etna_try_rs_blit(struct pipe_context *pctx, reloc.flags = ETNA_RELOC_READ; etna_set_state_reloc(ctx->stream, VIVS_TS_COLOR_SURFACE_BASE, &reloc); - etna_set_state(ctx->stream, VIVS_TS_COLOR_CLEAR_VALUE, - src->levels[blit_info->src.level].clear_value); + etna_set_state(ctx->stream, VIVS_TS_COLOR_CLEAR_VALUE, src_lev->clear_value); source_ts_valid = true; } else { - etna_set_state(ctx->stream, VIVS_TS_MEM_CONFIG, ts_mem_config); + etna_set_state(ctx->stream, VIVS_TS_MEM_CONFIG, 0); } ctx->dirty |= ETNA_DIRTY_TS; @@ -731,6 +727,7 @@ etna_try_rs_blit(struct pipe_context *pctx, .source_padded_width = src_lev->padded_width, .source_padded_height = src_lev->padded_height, .source_ts_valid = source_ts_valid, + .source_ts_compressed = src_lev->ts_compress_fmt >= 0, .dest_format = translate_rs_format(dst_format), .dest_tiling = dst->layout, .dest = dst->bo, @@ -751,7 +748,7 @@ etna_try_rs_blit(struct pipe_context *pctx, resource_read(ctx, &src->base); resource_written(ctx, &dst->base); dst->seqno++; - dst->levels[blit_info->dst.level].ts_valid = false; + dst_lev->ts_valid = false; ctx->dirty |= ETNA_DIRTY_DERIVE_TS; return true; diff --git a/src/gallium/drivers/etnaviv/etnaviv_rs.h b/src/gallium/drivers/etnaviv/etnaviv_rs.h index 125a13a9ad3..748de00e16f 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_rs.h +++ b/src/gallium/drivers/etnaviv/etnaviv_rs.h @@ -34,6 +34,7 @@ struct rs_state { uint8_t downsample_x : 1; /* Downsample in x direction */ uint8_t downsample_y : 1; /* Downsample in y direction */ uint8_t source_ts_valid : 1; + uint8_t source_ts_compressed : 1; uint8_t source_format; /* RS_FORMAT_XXX */ uint8_t source_tiling; /* ETNA_LAYOUT_XXX */ diff --git a/src/gallium/drivers/etnaviv/etnaviv_state.c b/src/gallium/drivers/etnaviv/etnaviv_state.c index 1cefed0a130..8df00ab1db2 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_state.c +++ b/src/gallium/drivers/etnaviv/etnaviv_state.c @@ -176,13 +176,16 @@ etna_set_framebuffer_state(struct pipe_context *pctx, cs->TS_COLOR_SURFACE_BASE.flags = ETNA_RELOC_READ | ETNA_RELOC_WRITE; pe_mem_config |= VIVS_PE_MEM_CONFIG_COLOR_TS_MODE(cbuf->level->ts_mode); - } - /* MSAA */ - if (cbuf->base.texture->nr_samples > 1) { - ts_mem_config |= - VIVS_TS_MEM_CONFIG_COLOR_COMPRESSION | - VIVS_TS_MEM_CONFIG_COLOR_COMPRESSION_FORMAT(translate_ts_format(cbuf->base.format)); + if (cbuf->level->ts_compress_fmt >= 0) { + /* overwrite bit breaks v1/v2 compression */ + if (!ctx->specs.v4_compression) + cs->PE_COLOR_FORMAT &= ~VIVS_PE_COLOR_FORMAT_OVERWRITE; + + ts_mem_config |= + VIVS_TS_MEM_CONFIG_COLOR_COMPRESSION | + VIVS_TS_MEM_CONFIG_COLOR_COMPRESSION_FORMAT(cbuf->level->ts_compress_fmt); + } } nr_samples_color = cbuf->base.texture->nr_samples; @@ -246,16 +249,17 @@ etna_set_framebuffer_state(struct pipe_context *pctx, cs->TS_DEPTH_SURFACE_BASE.flags = ETNA_RELOC_READ | ETNA_RELOC_WRITE; pe_mem_config |= VIVS_PE_MEM_CONFIG_DEPTH_TS_MODE(zsbuf->level->ts_mode); + + if (zsbuf->level->ts_compress_fmt >= 0) { + ts_mem_config |= + VIVS_TS_MEM_CONFIG_DEPTH_COMPRESSION | + COND(zsbuf->level->ts_compress_fmt == COMPRESSION_FORMAT_D24S8, + VIVS_TS_MEM_CONFIG_STENCIL_ENABLE); + } } ts_mem_config |= COND(depth_bits == 16, VIVS_TS_MEM_CONFIG_DEPTH_16BPP); - /* MSAA */ - if (zsbuf->base.texture->nr_samples > 1) - /* XXX VIVS_TS_MEM_CONFIG_DEPTH_COMPRESSION; - * Disable without MSAA for now, as it causes corruption in glquake. */ - ts_mem_config |= VIVS_TS_MEM_CONFIG_DEPTH_COMPRESSION; - nr_samples_depth = zsbuf->base.texture->nr_samples; } else { cs->PE_DEPTH_CONFIG = VIVS_PE_DEPTH_CONFIG_DEPTH_MODE_NONE; diff --git a/src/gallium/drivers/etnaviv/etnaviv_texture.c b/src/gallium/drivers/etnaviv/etnaviv_texture.c index 9bf63ec34c4..59a0d122d59 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_texture.c +++ b/src/gallium/drivers/etnaviv/etnaviv_texture.c @@ -86,7 +86,8 @@ etna_configure_sampler_ts(struct etna_sampler_ts *sts, struct pipe_sampler_view sts->mode = lev->ts_mode; sts->TS_SAMPLER_CONFIG = VIVS_TS_SAMPLER_CONFIG_ENABLE | - VIVS_TS_SAMPLER_CONFIG_COMPRESSION_FORMAT(translate_ts_format(rsc->base.format)); + COND(lev->ts_compress_fmt >= 0, VIVS_TS_SAMPLER_CONFIG_COMPRESSION) | + VIVS_TS_SAMPLER_CONFIG_COMPRESSION_FORMAT(lev->ts_compress_fmt); sts->TS_SAMPLER_CLEAR_VALUE = lev->clear_value; sts->TS_SAMPLER_CLEAR_VALUE2 = lev->clear_value; /* To handle 64-bit formats this needs a different value */ sts->TS_SAMPLER_STATUS_BASE.bo = rsc->ts_bo; @@ -123,7 +124,7 @@ etna_can_use_sampler_ts(struct pipe_sampler_view *view, int num) return VIV_FEATURE(screen, chipMinorFeatures2, TEXTURE_TILED_READ) && num < VIVS_TS_SAMPLER__LEN && rsc->base.target != PIPE_BUFFER && - translate_ts_format(rsc->base.format) != ETNA_NO_MATCH && + (rsc->levels[0].ts_compress_fmt < 0 || screen->specs.v4_compression) && view->u.tex.first_level == 0 && MIN2(view->u.tex.last_level, rsc->base.last_level) == 0 && rsc->levels[0].ts_valid; } -- 2.30.2