diff --git a/src/etnaviv/common/etna_core_info.h b/src/etnaviv/common/etna_core_info.h index 275ebbc5913..6cd3d1d2d72 100644 --- a/src/etnaviv/common/etna_core_info.h +++ b/src/etnaviv/common/etna_core_info.h @@ -65,6 +65,7 @@ enum etna_feature { ETNA_FEATURE_DEC400, ETNA_FEATURE_VIP_V7, ETNA_FEATURE_NN_XYDP0, + ETNA_FEATURE_YUV420_TILER, ETNA_FEATURE_NUM, }; diff --git a/src/etnaviv/drm/etnaviv_gpu.c b/src/etnaviv/drm/etnaviv_gpu.c index 11739257519..ea4e25de571 100644 --- a/src/etnaviv/drm/etnaviv_gpu.c +++ b/src/etnaviv/drm/etnaviv_gpu.c @@ -92,6 +92,7 @@ query_features_from_kernel(struct etna_gpu *gpu) ETNA_FEATURE(chipFeatures, DXT_TEXTURE_COMPRESSION); ETNA_FEATURE(chipFeatures, ETC1_TEXTURE_COMPRESSION); ETNA_FEATURE(chipFeatures, NO_EARLY_Z); + ETNA_FEATURE(chipFeatures, YUV420_TILER); ETNA_FEATURE(chipMinorFeatures0, MC20); ETNA_FEATURE(chipMinorFeatures0, RENDERTARGET_8K); diff --git a/src/etnaviv/hwdb/etna_hwdb.c b/src/etnaviv/hwdb/etna_hwdb.c index 3d7e50b5475..bdf42e7af40 100644 --- a/src/etnaviv/hwdb/etna_hwdb.c +++ b/src/etnaviv/hwdb/etna_hwdb.c @@ -90,6 +90,8 @@ etna_query_feature_db(struct etna_core_info *info) ETNA_FEATURE(REG_Halti5, HALTI5); ETNA_FEATURE(REG_RAWriteDepth, RA_WRITE_DEPTH); + ETNA_FEATURE(REG_YUV420Tiler, YUV420_TILER); + ETNA_FEATURE(CACHE128B256BPERLINE, CACHE128B256BPERLINE); ETNA_FEATURE(NEW_GPIPE, NEW_GPIPE); ETNA_FEATURE(NO_ASTC, NO_ASTC); diff --git a/src/gallium/drivers/etnaviv/etnaviv_blt.c b/src/gallium/drivers/etnaviv/etnaviv_blt.c index 31ed591d50f..f1854ab656a 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_blt.c +++ b/src/gallium/drivers/etnaviv/etnaviv_blt.c @@ -622,6 +622,32 @@ etna_try_blt_blit(struct pipe_context *pctx, return true; } +static void +etna_emit_yuv_tiler_state_blt(struct etna_context *ctx, struct etna_yuv_config *config) +{ + struct etna_cmd_stream *stream = ctx->stream; + + etna_set_state(stream, VIVS_BLT_ENABLE, 0x00000001); + etna_set_state(stream, VIVS_BLT_YUV_CONFIG, + VIVS_BLT_YUV_CONFIG_SOURCE_FORMAT(config->format) | VIVS_BLT_YUV_CONFIG_ENABLE); + etna_set_state(stream, VIVS_BLT_YUV_WINDOW_SIZE, + VIVS_BLT_YUV_WINDOW_SIZE_HEIGHT(config->height) | + VIVS_BLT_YUV_WINDOW_SIZE_WIDTH(config->width)); + + etna_yuv_emit_plane(ctx, config->planes[0], ETNA_PENDING_READ, VIVS_BLT_YUV_SRC_YADDR, VIVS_BLT_YUV_SRC_YSTRIDE); + etna_yuv_emit_plane(ctx, config->planes[1], ETNA_PENDING_READ, VIVS_BLT_YUV_SRC_UADDR, VIVS_BLT_YUV_SRC_USTRIDE); + etna_yuv_emit_plane(ctx, config->planes[2], ETNA_PENDING_READ, VIVS_BLT_YUV_SRC_VADDR, VIVS_BLT_YUV_SRC_VSTRIDE); + etna_yuv_emit_plane(ctx, config->dst, ETNA_PENDING_WRITE, VIVS_BLT_YUV_DEST_ADDR, VIVS_BLT_YUV_DEST_STRIDE); + + /* trigger resolve */ + etna_set_state(stream, VIVS_BLT_SET_COMMAND, 0x00000003); + etna_set_state(stream, VIVS_BLT_COMMAND, VIVS_BLT_COMMAND_COMMAND_YUV_TILE); + etna_set_state(stream, VIVS_BLT_SET_COMMAND, 0x00000003); + etna_set_state(stream, VIVS_BLT_ENABLE, 0x00000000); + + etna_stall(stream, SYNC_RECIPIENT_RA, SYNC_RECIPIENT_BLT); +} + void etna_clear_blit_blt_init(struct pipe_context *pctx) { @@ -630,4 +656,5 @@ etna_clear_blit_blt_init(struct pipe_context *pctx) DBG("etnaviv: Using BLT blit engine"); pctx->clear = etna_clear_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_clear_blit.c b/src/gallium/drivers/etnaviv/etnaviv_clear_blit.c index c06053fab2e..559003ca2f5 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_clear_blit.c +++ b/src/gallium/drivers/etnaviv/etnaviv_clear_blit.c @@ -36,6 +36,7 @@ #include "etnaviv_rs.h" #include "etnaviv_surface.h" #include "etnaviv_translate.h" +#include "etnaviv_yuv.h" #include "pipe/p_defines.h" #include "pipe/p_state.h" @@ -111,6 +112,10 @@ etna_blit(struct pipe_context *pctx, const struct pipe_blit_info *blit_info) if (ctx->blit(pctx, &info)) goto success; + if (etna_format_needs_yuv_tiler(blit_info->src.format) && + etna_try_yuv_blit(pctx, blit_info)) + goto success; + if (util_try_blit_via_copy_region(pctx, &info, false)) goto success; @@ -210,7 +215,7 @@ etna_copy_resource(struct pipe_context *pctx, struct pipe_resource *dst, struct etna_resource *src_priv = etna_resource(src); struct etna_resource *dst_priv = etna_resource(dst); - assert(src->format == dst->format); + assert(src->format == dst->format || util_format_is_yuv(src->format)); assert(src->array_size == dst->array_size); assert(last_level <= dst->last_level && last_level <= src->last_level); diff --git a/src/gallium/drivers/etnaviv/etnaviv_context.h b/src/gallium/drivers/etnaviv/etnaviv_context.h index 84442baafd3..82d750d366d 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_context.h +++ b/src/gallium/drivers/etnaviv/etnaviv_context.h @@ -32,6 +32,7 @@ #include "etnaviv_resource.h" #include "etnaviv_tiling.h" +#include "etnaviv_yuv.h" #include "pipe/p_context.h" #include "pipe/p_defines.h" #include "util/format/u_formats.h" @@ -117,6 +118,8 @@ struct etna_context { struct etna_sampler_ts *(*ts_for_sampler_view)(struct pipe_sampler_view *pview); /* GPU-specific blit implementation */ bool (*blit)(struct pipe_context *pipe, const struct pipe_blit_info *info); + /* GPU-specific implementation to emit yuv tiler state */ + void (*emit_yuv_tiler_state)(struct etna_context *ctx, struct etna_yuv_config *config); struct etna_screen *screen; struct etna_cmd_stream *stream; diff --git a/src/gallium/drivers/etnaviv/etnaviv_format.c b/src/gallium/drivers/etnaviv/etnaviv_format.c index f18d66662c3..cf35bda345a 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_format.c +++ b/src/gallium/drivers/etnaviv/etnaviv_format.c @@ -255,6 +255,9 @@ static struct etna_format formats[PIPE_FORMAT_COUNT] = { /* YUV */ _T(YUYV, YUY2, YUY2), _T(UYVY, UYVY, NONE), + + /* multi-planar YUV */ + _T(NV12, YUY2, NONE), }; uint32_t diff --git a/src/gallium/drivers/etnaviv/etnaviv_rs.c b/src/gallium/drivers/etnaviv/etnaviv_rs.c index 82bf16d2c98..f659952f688 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_rs.c +++ b/src/gallium/drivers/etnaviv/etnaviv_rs.c @@ -904,6 +904,33 @@ manual: return false; } +static void +etna_emit_yuv_tiler_state_rs(struct etna_context *ctx, struct etna_yuv_config *config) +{ + struct etna_cmd_stream *stream = ctx->stream; + + etna_set_state(stream, VIVS_YUV_CONFIG, + VIVS_YUV_CONFIG_SOURCE_FORMAT(config->format) | VIVS_YUV_CONFIG_ENABLE); + etna_set_state(stream, VIVS_YUV_WINDOW_SIZE, + VIVS_YUV_WINDOW_SIZE_HEIGHT(config->height) | + VIVS_YUV_WINDOW_SIZE_WIDTH(config->width)); + + etna_yuv_emit_plane(ctx, config->planes[0], ETNA_PENDING_READ, VIVS_YUV_Y_BASE, VIVS_YUV_Y_STRIDE); + etna_yuv_emit_plane(ctx, config->planes[1], ETNA_PENDING_READ, VIVS_YUV_U_BASE, VIVS_YUV_U_STRIDE); + etna_yuv_emit_plane(ctx, config->planes[2], ETNA_PENDING_READ, VIVS_YUV_V_BASE, VIVS_YUV_V_STRIDE); + etna_yuv_emit_plane(ctx, config->dst, ETNA_PENDING_WRITE, VIVS_YUV_DEST_BASE, VIVS_YUV_DEST_STRIDE); + + /* configure RS */ + etna_set_state(stream, VIVS_RS_SOURCE_STRIDE, 0); + etna_set_state(stream, VIVS_RS_CLEAR_CONTROL, 0); + + /* trigger resolve */ + etna_set_state(stream, VIVS_RS_KICKER, 0xbadabeeb); + + /* disable yuv tiller */ + etna_set_state(stream, VIVS_YUV_CONFIG, 0x0); +} + void etna_align_box_for_rs(const struct etna_screen *screen, const struct etna_resource *rsc, @@ -929,4 +956,5 @@ etna_clear_blit_rs_init(struct pipe_context *pctx) DBG("etnaviv: Using RS blit engine"); pctx->clear = etna_clear_rs; ctx->blit = etna_try_rs_blit; + ctx->emit_yuv_tiler_state = etna_emit_yuv_tiler_state_rs; } diff --git a/src/gallium/drivers/etnaviv/etnaviv_screen.c b/src/gallium/drivers/etnaviv/etnaviv_screen.c index 98e4575e06a..6a503f704b2 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_screen.c +++ b/src/gallium/drivers/etnaviv/etnaviv_screen.c @@ -37,6 +37,7 @@ #include "etnaviv_query.h" #include "etnaviv_resource.h" #include "etnaviv_translate.h" +#include "etnaviv_yuv.h" #include "util/hash_table.h" #include "util/os_time.h" @@ -407,6 +408,9 @@ gpu_supports_texture_format(struct etna_screen *screen, uint32_t fmt, supported = VIV_FEATURE(screen, ETNA_FEATURE_HALTI2); + if (etna_format_needs_yuv_tiler(format)) + supported = VIV_FEATURE(screen, ETNA_FEATURE_YUV420_TILER); + if (!supported) return false; diff --git a/src/gallium/drivers/etnaviv/etnaviv_texture.c b/src/gallium/drivers/etnaviv/etnaviv_texture.c index 73504e8eb91..e41e1d17719 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_texture.c +++ b/src/gallium/drivers/etnaviv/etnaviv_texture.c @@ -33,6 +33,7 @@ #include "etnaviv_texture_desc.h" #include "etnaviv_texture_state.h" #include "etnaviv_translate.h" +#include "etnaviv_yuv.h" #include "util/u_inlines.h" #include "util/u_memory.h" @@ -203,6 +204,9 @@ etna_update_sampler_source(struct pipe_sampler_view *view, int num) static bool etna_resource_sampler_compatible(struct etna_resource *res) { + if (etna_format_needs_yuv_tiler(res->base.format)) + return false; + if (util_format_is_compressed(res->base.format)) return true; @@ -243,6 +247,12 @@ etna_texture_handle_incompatible(struct pipe_context *pctx, struct pipe_resource templat.bind &= ~(PIPE_BIND_DEPTH_STENCIL | PIPE_BIND_RENDER_TARGET | PIPE_BIND_BLENDABLE); + + if (util_format_is_yuv(prsc->format)) { + templat.format = PIPE_FORMAT_YUYV; + templat.next = NULL; + } + res->texture = etna_resource_alloc(pctx->screen, ETNA_LAYOUT_TILED, DRM_FORMAT_MOD_LINEAR, &templat); diff --git a/src/gallium/drivers/etnaviv/etnaviv_yuv.c b/src/gallium/drivers/etnaviv/etnaviv_yuv.c new file mode 100644 index 00000000000..5ad04c5a3be --- /dev/null +++ b/src/gallium/drivers/etnaviv/etnaviv_yuv.c @@ -0,0 +1,76 @@ +/* + * Copyright 2024 Igalia, S.L. + * SPDX-License-Identifier: MIT + */ + +#include "etnaviv_context.h" +#include "etnaviv_emit.h" +#include "etnaviv_yuv.h" + +void +etna_yuv_emit_plane(struct etna_context *ctx, struct etna_resource *plane, + enum etna_resource_status status, uint32_t base, uint32_t stride) +{ + if (!plane) + return; + + uint32_t flags = (status == ETNA_PENDING_WRITE) ? ETNA_RELOC_WRITE : ETNA_RELOC_READ; + + etna_resource_used(ctx, &plane->base, status); + etna_set_state_reloc(ctx->stream, base, &(struct etna_reloc) { + .bo = plane->bo, + .offset = plane->levels[0].offset, + .flags = flags, + }); + etna_set_state(ctx->stream, stride, plane->levels[0].stride); +} + +bool +etna_try_yuv_blit(struct pipe_context *pctx, + const struct pipe_blit_info *blit_info) +{ + struct etna_context *ctx = etna_context(pctx); + struct etna_cmd_stream *stream = ctx->stream; + struct pipe_resource *src = blit_info->src.resource; + struct etna_yuv_config config = { 0 }; + ASSERTED unsigned num_planes; + int idx = 0; + + assert(util_format_is_yuv(blit_info->src.format)); + assert(blit_info->dst.format == PIPE_FORMAT_YUYV); + assert(blit_info->src.level == 0); + assert(blit_info->dst.level == 0); + + config.dst = etna_resource(blit_info->dst.resource); + config.height = blit_info->dst.box.height; + config.width = blit_info->dst.box.width; + + switch (blit_info->src.format) { + case PIPE_FORMAT_NV12: + config.format = 0x1; + num_planes = 2; + break; + default: + return false; + } + + while (src) { + config.planes[idx++] = etna_resource(src); + src = src->next; + } + + assert(idx == num_planes); + + etna_set_state(stream, VIVS_GL_FLUSH_CACHE, + VIVS_GL_FLUSH_CACHE_COLOR | VIVS_GL_FLUSH_CACHE_DEPTH); + etna_stall(stream, SYNC_RECIPIENT_RA, SYNC_RECIPIENT_PE); + + etna_set_state(stream, VIVS_TS_FLUSH_CACHE, VIVS_TS_FLUSH_CACHE_FLUSH); + etna_set_state(stream, VIVS_TS_MEM_CONFIG, 0); + + ctx->emit_yuv_tiler_state(ctx, &config); + + ctx->dirty |= ETNA_DIRTY_TS; + + return true; +} diff --git a/src/gallium/drivers/etnaviv/etnaviv_yuv.h b/src/gallium/drivers/etnaviv/etnaviv_yuv.h new file mode 100644 index 00000000000..bce3ab6eafb --- /dev/null +++ b/src/gallium/drivers/etnaviv/etnaviv_yuv.h @@ -0,0 +1,36 @@ +/* + * Copyright 2024 Igalia, S.L. + * SPDX-License-Identifier: MIT + */ + +#ifndef H_ETNA_YUV +#define H_ETNA_YUV + +#include +#include + +#include "etnaviv_context.h" + +struct etna_yuv_config { + struct etna_resource *planes[3]; + struct etna_resource *dst; + uint32_t width; + uint32_t height; + uint32_t format; +}; + +static inline bool +etna_format_needs_yuv_tiler(enum pipe_format format) +{ + return format == PIPE_FORMAT_NV12; +} + +void +etna_yuv_emit_plane(struct etna_context *ctx, struct etna_resource *plane, + enum etna_resource_status status, uint32_t base, uint32_t stride); + +bool +etna_try_yuv_blit(struct pipe_context *pctx, + const struct pipe_blit_info *blit_info); + +#endif diff --git a/src/gallium/drivers/etnaviv/meson.build b/src/gallium/drivers/etnaviv/meson.build index e44eaef16ce..8cc971a36e4 100644 --- a/src/gallium/drivers/etnaviv/meson.build +++ b/src/gallium/drivers/etnaviv/meson.build @@ -83,6 +83,8 @@ files_etnaviv = files( 'etnaviv_uniforms.c', 'etnaviv_uniforms.h', 'etnaviv_util.h', + 'etnaviv_yuv.c', + 'etnaviv_yuv.h', 'etnaviv_zsa.c', 'etnaviv_zsa.h', )