0
0
mirror of https://github.com/libretro/Lakka-LibreELEC.git synced 2024-12-16 07:58:51 +00:00
Lakka-LibreELEC/projects/Allwinner/patches/linux/0063-media-cedrus-Implement-AFBC-YUV420-formats-for-H265.patch
2023-10-09 22:11:20 +02:00

170 lines
6.2 KiB
Diff

From eaa6dd41f9c4c9a12d7f81a6ead80cc5d7146afa Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@gmail.com>
Date: Sun, 8 Oct 2023 12:44:59 +0200
Subject: [PATCH 17/23] media: cedrus: Implement AFBC YUV420 formats for H265
AFBC output formats are more performant, since they are optimized for
more efficient memory operations and transfers.
Add support for them.
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
---
drivers/staging/media/sunxi/cedrus/cedrus.h | 11 ++++++
.../staging/media/sunxi/cedrus/cedrus_h265.c | 3 +-
.../staging/media/sunxi/cedrus/cedrus_hw.c | 16 +++++++++
.../staging/media/sunxi/cedrus/cedrus_regs.h | 6 ++++
.../staging/media/sunxi/cedrus/cedrus_video.c | 36 +++++++++++++++++++
5 files changed, 71 insertions(+), 1 deletion(-)
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.h b/drivers/staging/media/sunxi/cedrus/cedrus.h
index 522c184e2afc..c7ec4dee8630 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus.h
+++ b/drivers/staging/media/sunxi/cedrus/cedrus.h
@@ -268,6 +268,17 @@ cedrus_is_capable(struct cedrus_ctx *ctx, unsigned int capabilities)
return (ctx->dev->capabilities & capabilities) == capabilities;
}
+static inline bool is_afbc_format(u32 format)
+{
+ switch (format) {
+ case V4L2_PIX_FMT_YUV420_8_AFBC_16X16_SPLIT:
+ case V4L2_PIX_FMT_YUV420_10_AFBC_16X16_SPLIT:
+ return true;
+ default:
+ return false;
+ }
+}
+
void *cedrus_find_control_data(struct cedrus_ctx *ctx, u32 id);
u32 cedrus_get_num_of_controls(struct cedrus_ctx *ctx, u32 id);
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c
index 16c822637dc6..2372fafab475 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c
@@ -120,7 +120,8 @@ static void cedrus_h265_frame_info_write_single(struct cedrus_ctx *ctx,
{
struct cedrus_dev *dev = ctx->dev;
dma_addr_t dst_luma_addr = cedrus_dst_buf_addr(ctx, buf, 0);
- dma_addr_t dst_chroma_addr = cedrus_dst_buf_addr(ctx, buf, 1);
+ dma_addr_t dst_chroma_addr = is_afbc_format(ctx->dst_fmt.pixelformat) ?
+ 0 : cedrus_dst_buf_addr(ctx, buf, 1);
dma_addr_t mv_col_buf_addr[2] = {
cedrus_h265_frame_info_mv_col_buf_addr(buf, 0),
cedrus_h265_frame_info_mv_col_buf_addr(buf, field_pic ? 1 : 0)
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_hw.c b/drivers/staging/media/sunxi/cedrus/cedrus_hw.c
index b696bf884cbd..ac0a88d47e10 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_hw.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_hw.c
@@ -65,6 +65,18 @@ int cedrus_engine_enable(struct cedrus_ctx *ctx)
reg |= VE_MODE_PIC_WIDTH_IS_4096;
if (ctx->src_fmt.width > 2048)
reg |= VE_MODE_PIC_WIDTH_MORE_2048;
+ /*
+ * NOTE: Not sure if RGB default color feature is part of official
+ * AFBC standard or not and if it is, which feature that is. However,
+ * in order to render it properly with display engine, default color
+ * has to be set to white there.
+ */
+ if (is_afbc_format(ctx->dst_fmt.pixelformat))
+ reg |= VE_MODE_COMPRESS_EN |
+ VE_MODE_MIN_VAL_WRAP_EN |
+ VE_MODE_RGB_DEF_COLOR_EN |
+ VE_MODE_BODYBUF_1K_ALIGNED |
+ VE_MODE_COMPRESS_MODE_AFBC;
cedrus_write(ctx->dev, VE_MODE, reg);
@@ -85,6 +97,10 @@ void cedrus_dst_format_set(struct cedrus_dev *dev,
u32 reg;
switch (fmt->pixelformat) {
+ case V4L2_PIX_FMT_YUV420_8_AFBC_16X16_SPLIT:
+ case V4L2_PIX_FMT_YUV420_10_AFBC_16X16_SPLIT:
+ /* format is already set in cedrus_engine_enable() */
+ break;
case V4L2_PIX_FMT_NV12:
chroma_size = ALIGN(width, 16) * ALIGN(height, 16) / 2;
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_regs.h b/drivers/staging/media/sunxi/cedrus/cedrus_regs.h
index 05e6cbc548ab..c3dcd93a29eb 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_regs.h
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_regs.h
@@ -35,12 +35,18 @@
#define VE_MODE 0x00
+#define VE_MODE_COMPRESS_EN BIT(29)
+#define VE_MODE_MIN_VAL_WRAP_EN BIT(27)
+#define VE_MODE_RGB_DEF_COLOR_EN BIT(26)
#define VE_MODE_PIC_WIDTH_IS_4096 BIT(22)
#define VE_MODE_PIC_WIDTH_MORE_2048 BIT(21)
#define VE_MODE_REC_WR_MODE_2MB (0x01 << 20)
#define VE_MODE_REC_WR_MODE_1MB (0x00 << 20)
#define VE_MODE_DDR_MODE_BW_128 (0x03 << 16)
#define VE_MODE_DDR_MODE_BW_256 (0x02 << 16)
+#define VE_MODE_BODYBUF_1K_ALIGNED BIT(12)
+#define VE_MODE_COMPRESS_MODE_LOSSLESS (0x00 << 4)
+#define VE_MODE_COMPRESS_MODE_AFBC (0x01 << 4)
#define VE_MODE_DISABLED (0x07 << 0)
#define VE_MODE_DEC_H265 (0x04 << 0)
#define VE_MODE_DEC_H264 (0x01 << 0)
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_video.c b/drivers/staging/media/sunxi/cedrus/cedrus_video.c
index 75b6f2e85a5f..a61b30946204 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_video.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_video.c
@@ -55,6 +55,22 @@ static struct cedrus_format cedrus_formats[] = {
.directions = CEDRUS_DECODE_SRC,
.capabilities = CEDRUS_CAPABILITY_VP8_DEC,
},
+ {
+ .pixelformat = V4L2_PIX_FMT_YUV420_10_AFBC_16X16_SPLIT,
+ .directions = CEDRUS_DECODE_DST,
+ .capabilities = CEDRUS_CAPABILITY_UNTILED |
+ CEDRUS_CAPABILITY_H265_10_DEC,
+ .depth = 10,
+ .src_format = V4L2_PIX_FMT_HEVC_SLICE,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_YUV420_8_AFBC_16X16_SPLIT,
+ .directions = CEDRUS_DECODE_DST,
+ .capabilities = CEDRUS_CAPABILITY_UNTILED |
+ CEDRUS_CAPABILITY_H265_10_DEC,
+ .depth = 8,
+ .src_format = V4L2_PIX_FMT_HEVC_SLICE,
+ },
{
.pixelformat = V4L2_PIX_FMT_NV12,
.directions = CEDRUS_DECODE_DST,
@@ -160,6 +176,26 @@ void cedrus_prepare_format(struct v4l2_pix_format *pix_fmt)
sizeimage += bytesperline * height / 2;
break;
+
+ case V4L2_PIX_FMT_YUV420_10_AFBC_16X16_SPLIT:
+ /* Zero bytes per line for compressed destination. */
+ bytesperline = 0;
+
+ sizeimage = DIV_ROUND_UP(width, 16) *
+ DIV_ROUND_UP(height + 4, 16) * (512 + 16) +
+ 32 + SZ_1K;
+
+ break;
+
+ case V4L2_PIX_FMT_YUV420_8_AFBC_16X16_SPLIT:
+ /* Zero bytes per line for compressed destination. */
+ bytesperline = 0;
+
+ sizeimage = DIV_ROUND_UP(width, 16) *
+ DIV_ROUND_UP(height + 4, 16) * (384 + 16) +
+ 32 + SZ_1K;
+
+ break;
}
pix_fmt->width = width;
--
2.42.0