From ff008db792551cd56ebf9960b899fbf3a467f7e6 Mon Sep 17 00:00:00 2001 From: Christian Gmeiner Date: Mon, 7 Jul 2025 15:53:55 +0200 Subject: [PATCH] etnaviv: blt: Add hardware based mipmap generation This provides a hardware-accelerated path for mipmap generation on supported formats. Signed-off-by: Christian Gmeiner Part-of: --- src/gallium/drivers/etnaviv/etnaviv_blt.c | 123 +++++++++++++++++++ src/gallium/drivers/etnaviv/etnaviv_blt.h | 11 ++ src/gallium/drivers/etnaviv/etnaviv_screen.c | 1 + 3 files changed, 135 insertions(+) diff --git a/src/gallium/drivers/etnaviv/etnaviv_blt.c b/src/gallium/drivers/etnaviv/etnaviv_blt.c index ab913f6755b..6916eaec3d2 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_blt.c +++ b/src/gallium/drivers/etnaviv/etnaviv_blt.c @@ -34,6 +34,7 @@ #include "etnaviv_resource.h" #include "etnaviv_translate.h" +#include "util/format/u_format.h" #include "util/u_math.h" #include "pipe/p_defines.h" #include "pipe/p_state.h" @@ -219,6 +220,51 @@ emit_blt_inplace(struct etna_cmd_stream *stream, const struct blt_inplace_op *op etna_stall(stream, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_PE); } +/* Emit genmipamp using BLT. */ +static void +emit_blt_genmipmap(struct etna_cmd_stream *stream, const struct blt_genmipmap_op *op) +{ + etna_cmd_stream_reserve(stream, 64*2); /* Never allow BLT sequences to be broken up */ + + etna_set_state(stream, VIVS_GL_FLUSH_CACHE, 0x00000c23); + etna_set_state(stream, VIVS_TS_FLUSH_CACHE, VIVS_TS_FLUSH_CACHE_FLUSH); + + etna_set_state(stream, VIVS_BLT_ENABLE, 0x00000001); + + etna_set_state(stream, VIVS_BLT_SRC_STRIDE, blt_compute_stride_bits(&op->src)); + etna_set_state(stream, VIVS_BLT_SRC_CONFIG, blt_compute_img_config_bits(&op->src, false)); + etna_set_state_reloc(stream, VIVS_BLT_SRC_ADDR, &op->src.addr); + + etna_set_state(stream, VIVS_BLT_DEST_CONFIG, blt_compute_img_config_bits(&op->src, true)); + etna_set_state(stream, VIVS_BLT_DEST_STRIDE, blt_compute_stride_bits(&op->src)); + + etna_set_state(stream, VIVS_BLT_IMAGE_SIZE, + VIVS_BLT_IMAGE_SIZE_HEIGHT(op->height) | + VIVS_BLT_IMAGE_SIZE_WIDTH(op->width)); + + etna_set_state(stream, VIVS_BLT_SWIZZLE, + blt_compute_swizzle_bits(&op->src, false) | + blt_compute_swizzle_bits(&op->src, true)); + + for (unsigned i = 0; i < op->num_levels; i++) { + etna_set_state_reloc(stream, VIVS_BLT_MIP_ADDR(i), &op->level[i]); + etna_set_state(stream, VIVS_BLT_MIP_STRIDE(i), op->stride[i]); + } + + etna_set_state(stream, VIVS_BLT_MIPMAP_CONFIG, + VIVS_BLT_MIPMAP_CONFIG_NUM(op->num_levels + 1) | + VIVS_BLT_MIPMAP_CONFIG_UNK5); + etna_set_state(stream, VIVS_BLT_CONFIG, 0x0); + + etna_set_state(stream, VIVS_BLT_SET_COMMAND, 0x00000003); + etna_set_state(stream, VIVS_BLT_COMMAND, VIVS_BLT_COMMAND_COMMAND_GEN_MIPMAPS); + etna_set_state(stream, VIVS_BLT_SET_COMMAND, 0x00000003); + etna_set_state(stream, VIVS_BLT_ENABLE, 0x00000000); + + if (DBG_ENABLED(ETNA_DBG_DRAW_STALL)) + etna_stall(stream, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_PE); +} + static void etna_blit_clear_color_blt(struct pipe_context *pctx, unsigned idx, const union pipe_color_union *color) @@ -410,6 +456,82 @@ etna_clear_blt(struct pipe_context *pctx, unsigned buffers, const struct pipe_sc etna_set_state(ctx->stream, VIVS_GL_FLUSH_CACHE, 0x00000002); } +static bool +etna_generate_mipmap_blt(struct pipe_context *pctx, + struct pipe_resource *prsc, + enum pipe_format format, + unsigned base_level, + unsigned last_level, + unsigned first_layer, + unsigned last_layer) +{ + struct etna_resource *rsc = etna_resource(prsc); + struct etna_context *ctx = etna_context(pctx); + struct etna_resource_level *src_lev = &rsc->levels[base_level]; + + if (format != prsc->format) + return false; + + if (first_layer != last_layer) + return false; + + uint32_t fmt = translate_blt_format(format); + if (fmt == ETNA_NO_MATCH) { + perf_debug_ctx(ctx, "BLT mipmap generation not possible due to unsupported format: %s\n", + util_format_short_name(format)); + return false; + } + + struct blt_genmipmap_op op = {}; + + op.num_levels = last_level - base_level; + op.width = prsc->width0; + op.height = prsc->height0; + op.src.addr.bo = rsc->bo; + op.src.addr.offset = src_lev->offset + (first_layer * src_lev->layer_stride); + op.src.addr.flags = ETNA_RELOC_READ; + op.src.stride = src_lev->stride; + op.src.tiling = rsc->layout; + op.src.format = fmt; + op.src.swizzle[0] = 0; + op.src.swizzle[1] = 1; + op.src.swizzle[2] = 2; + op.src.swizzle[3] = 3; + + if (etna_resource_level_ts_valid(src_lev)) { + assert(first_layer == 0); + + op.src.use_ts = 1; + op.src.ts_addr.bo = rsc->ts_bo; + op.src.ts_addr.offset = src_lev->ts_offset; + op.src.ts_addr.flags = ETNA_RELOC_READ; + op.src.ts_mode = src_lev->ts_mode; + op.src.ts_compress_fmt = src_lev->ts_compress_fmt; + } + + for (unsigned i = 0; i < op.num_levels; i++) { + struct etna_resource_level *dst_lev = &rsc->levels[i + 1]; + + op.level[i].bo = rsc->bo; + op.level[i].offset = dst_lev->offset + (first_layer * dst_lev->layer_stride); + op.level[i].flags = ETNA_RELOC_WRITE; + op.stride[i] = dst_lev->stride; + + etna_resource_level_ts_mark_invalid(dst_lev); + } + + emit_blt_genmipmap(ctx->stream, &op); + + etna_stall(ctx->stream, SYNC_RECIPIENT_RA, SYNC_RECIPIENT_BLT); + + resource_read(ctx, prsc); + resource_written(ctx, prsc); + + ctx->dirty |= ETNA_DIRTY_TEXTURE_CACHES; + + return true; +} + static bool etna_try_blt_blit(struct pipe_context *pctx, const struct pipe_blit_info *blit_info) @@ -657,6 +779,7 @@ etna_clear_blit_blt_init(struct pipe_context *pctx) DBG("etnaviv: Using BLT blit engine"); pctx->clear = etna_clear_blt; + pctx->generate_mipmap = etna_generate_mipmap_blt; ctx->blit = etna_try_blt_blit; ctx->emit_yuv_tiler_state = etna_emit_yuv_tiler_state_blt; } diff --git a/src/gallium/drivers/etnaviv/etnaviv_blt.h b/src/gallium/drivers/etnaviv/etnaviv_blt.h index fdc14090ed5..28a02d0ba7d 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_blt.h +++ b/src/gallium/drivers/etnaviv/etnaviv_blt.h @@ -27,6 +27,7 @@ #ifndef H_ETNAVIV_BLT #define H_ETNAVIV_BLT +#include "etnaviv_internal.h" #include "etnaviv_tiling.h" #include @@ -94,6 +95,16 @@ struct blt_inplace_op uint8_t bpp; }; +struct blt_genmipmap_op { + struct blt_imginfo src; + uint16_t width; + uint16_t height; + + uint8_t num_levels; + uint32_t stride[ETNA_NUM_LOD - 1]; + struct etna_reloc level[ETNA_NUM_LOD - 1]; +}; + /* Context initialization for BLT clear_blit functions. */ void etna_clear_blit_blt_init(struct pipe_context *pctx); diff --git a/src/gallium/drivers/etnaviv/etnaviv_screen.c b/src/gallium/drivers/etnaviv/etnaviv_screen.c index b267fc11e83..9f736b25c43 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_screen.c +++ b/src/gallium/drivers/etnaviv/etnaviv_screen.c @@ -232,6 +232,7 @@ etna_init_screen_caps(struct etna_screen *screen) caps->fs_position_is_sysval = true; caps->fs_face_is_integer_sysval = true; /* note: not integer */ caps->fs_point_is_sysval = false; + caps->generate_mipmap = screen->specs.use_blt; /* Memory */ caps->constant_buffer_offset_alignment = 256;