etnaviv: Add multi-planar YUV support
Some checks are pending
macOS-CI / macOS-CI (dri) (push) Waiting to run
macOS-CI / macOS-CI (xlib) (push) Waiting to run

This enables support for NV12, which are really useful when
dealing with hardware video decoders. This patch makes use
of the integrated YUV tiler to convert multi-planar to YUYV.
The binary blob uses the same method to deal with multi-planar
YUV formats. Other formarts will be added in a follow-up patch.

Tested with kmscube (nv12-1img) and the following gstreamer pipeline:

gst-launch-1.0 filesrc location=/tmp/test.mp4 ! qtdemux ! v4l2slh264dec ! video/x-raw,format=NV12 ! glimagesink

Signed-off-by: Christian Gmeiner <cgmeiner@igalia.com>
Signed-off-by: Peter Frühberger
Signed-off-by: Marek Vasut <marex@denx.de>
Acked-by: Daniel Stone <daniels@collabora.com>
Reviewed-by: Lucas Stach <l.stach@pengutronix.de>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/3418>
This commit is contained in:
Christian Gmeiner 2020-01-15 21:04:37 +01:00 committed by Marge Bot
parent 58f8143da3
commit 042138093f
13 changed files with 199 additions and 1 deletions

View file

@ -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,
};

View file

@ -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);

View file

@ -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);

View file

@ -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;
}

View file

@ -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);

View file

@ -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;

View file

@ -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

View file

@ -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;
}

View file

@ -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;

View file

@ -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);

View file

@ -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;
}

View file

@ -0,0 +1,36 @@
/*
* Copyright 2024 Igalia, S.L.
* SPDX-License-Identifier: MIT
*/
#ifndef H_ETNA_YUV
#define H_ETNA_YUV
#include <stdbool.h>
#include <stdint.h>
#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

View file

@ -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',
)