From eb94bf33cc1b37231063703c691c4b460481df7a Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Sat, 9 Nov 2019 14:12:42 +0100 Subject: [PATCH 051/101] drv:media: cedrus: h264: Improve buffer management Signed-off-by: Jernej Skrabec --- drivers/staging/media/sunxi/cedrus/cedrus.h | 3 + .../staging/media/sunxi/cedrus/cedrus_h264.c | 95 ++++++++----------- 2 files changed, 44 insertions(+), 54 deletions(-) diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.h b/drivers/staging/media/sunxi/cedrus/cedrus.h index 54a860ec7..25079901a 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.h +++ b/drivers/staging/media/sunxi/cedrus/cedrus.h @@ -105,6 +105,9 @@ struct cedrus_buffer { struct { unsigned int position; enum cedrus_h264_pic_type pic_type; + void *mv_col_buf; + dma_addr_t mv_col_buf_dma; + ssize_t mv_col_buf_size; } h264; struct { void *mv_col_buf; diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c index b4173a892..787c1575c 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c @@ -55,16 +55,14 @@ static void cedrus_h264_write_sram(struct cedrus_dev *dev, } static dma_addr_t cedrus_h264_mv_col_buf_addr(struct cedrus_ctx *ctx, - unsigned int position, + struct cedrus_buffer *buf, unsigned int field) { - dma_addr_t addr = ctx->codec.h264.mv_col_buf_dma; - - /* Adjust for the position */ - addr += position * ctx->codec.h264.mv_col_buf_field_size * 2; + dma_addr_t addr = buf->codec.h264.mv_col_buf_dma; /* Adjust for the field */ - addr += field * ctx->codec.h264.mv_col_buf_field_size; + if (field) + addr += buf->codec.h264.mv_col_buf_size / 2; return addr; } @@ -76,7 +74,6 @@ static void cedrus_fill_ref_pic(struct cedrus_ctx *ctx, struct cedrus_h264_sram_ref_pic *pic) { struct vb2_buffer *vbuf = &buf->m2m_buf.vb.vb2_buf; - unsigned int position = buf->codec.h264.position; pic->top_field_order_cnt = cpu_to_le32(top_field_order_cnt); pic->bottom_field_order_cnt = cpu_to_le32(bottom_field_order_cnt); @@ -85,9 +82,9 @@ static void cedrus_fill_ref_pic(struct cedrus_ctx *ctx, pic->luma_ptr = cpu_to_le32(cedrus_buf_addr(vbuf, &ctx->dst_fmt, 0)); pic->chroma_ptr = cpu_to_le32(cedrus_buf_addr(vbuf, &ctx->dst_fmt, 1)); pic->mv_col_top_ptr = - cpu_to_le32(cedrus_h264_mv_col_buf_addr(ctx, position, 0)); + cpu_to_le32(cedrus_h264_mv_col_buf_addr(ctx, buf, 0)); pic->mv_col_bot_ptr = - cpu_to_le32(cedrus_h264_mv_col_buf_addr(ctx, position, 1)); + cpu_to_le32(cedrus_h264_mv_col_buf_addr(ctx, buf, 1)); } static void cedrus_write_frame_list(struct cedrus_ctx *ctx, @@ -146,6 +143,28 @@ static void cedrus_write_frame_list(struct cedrus_ctx *ctx, output_buf = vb2_to_cedrus_buffer(&run->dst->vb2_buf); output_buf->codec.h264.position = position; + if (!output_buf->codec.h264.mv_col_buf_size) { + const struct v4l2_ctrl_h264_sps *sps = run->h264.sps; + unsigned int field_size; + + field_size = DIV_ROUND_UP(ctx->src_fmt.width, 16) * + DIV_ROUND_UP(ctx->src_fmt.height, 16) * 16; + if (!(sps->flags & V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE)) + field_size = field_size * 2; + if (!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY)) + field_size = field_size * 2; + + output_buf->codec.h264.mv_col_buf_size = field_size * 2; + output_buf->codec.h264.mv_col_buf = + dma_alloc_attrs(dev->dev, + output_buf->codec.h264.mv_col_buf_size, + &output_buf->codec.h264.mv_col_buf_dma, + GFP_KERNEL, DMA_ATTR_NO_KERNEL_MAPPING); + + if (!output_buf->codec.h264.mv_col_buf) + output_buf->codec.h264.mv_col_buf_size = 0; + } + if (decode->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC) output_buf->codec.h264.pic_type = CEDRUS_H264_PIC_TYPE_FIELD; else if (sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD) @@ -516,8 +535,6 @@ static int cedrus_h264_start(struct cedrus_ctx *ctx) { struct cedrus_dev *dev = ctx->dev; unsigned int pic_info_size; - unsigned int field_size; - unsigned int mv_col_size; int ret; /* @@ -565,38 +582,6 @@ static int cedrus_h264_start(struct cedrus_ctx *ctx) goto err_pic_buf; } - field_size = DIV_ROUND_UP(ctx->src_fmt.width, 16) * - DIV_ROUND_UP(ctx->src_fmt.height, 16) * 16; - - /* - * FIXME: This is actually conditional to - * V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE not being set, we - * might have to rework this if memory efficiency ever is - * something we need to work on. - */ - field_size = field_size * 2; - - /* - * FIXME: This is actually conditional to - * V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY not being set, we might - * have to rework this if memory efficiency ever is something - * we need to work on. - */ - field_size = field_size * 2; - ctx->codec.h264.mv_col_buf_field_size = field_size; - - mv_col_size = field_size * 2 * CEDRUS_H264_FRAME_NUM; - ctx->codec.h264.mv_col_buf_size = mv_col_size; - ctx->codec.h264.mv_col_buf = - dma_alloc_attrs(dev->dev, - ctx->codec.h264.mv_col_buf_size, - &ctx->codec.h264.mv_col_buf_dma, - GFP_KERNEL, DMA_ATTR_NO_KERNEL_MAPPING); - if (!ctx->codec.h264.mv_col_buf) { - ret = -ENOMEM; - goto err_neighbor_buf; - } - if (ctx->src_fmt.width > 2048) { /* * Formulas for deblock and intra prediction buffer sizes @@ -612,7 +597,7 @@ static int cedrus_h264_start(struct cedrus_ctx *ctx) GFP_KERNEL, DMA_ATTR_NO_KERNEL_MAPPING); if (!ctx->codec.h264.deblk_buf) { ret = -ENOMEM; - goto err_mv_col_buf; + goto err_neighbor_buf; } /* @@ -640,12 +625,6 @@ static int cedrus_h264_start(struct cedrus_ctx *ctx) ctx->codec.h264.deblk_buf_dma, DMA_ATTR_NO_KERNEL_MAPPING); -err_mv_col_buf: - dma_free_attrs(dev->dev, ctx->codec.h264.mv_col_buf_size, - ctx->codec.h264.mv_col_buf, - ctx->codec.h264.mv_col_buf_dma, - DMA_ATTR_NO_KERNEL_MAPPING); - err_neighbor_buf: dma_free_attrs(dev->dev, CEDRUS_NEIGHBOR_INFO_BUF_SIZE, ctx->codec.h264.neighbor_info_buf, @@ -664,10 +643,6 @@ static void cedrus_h264_stop(struct cedrus_ctx *ctx) { struct cedrus_dev *dev = ctx->dev; - dma_free_attrs(dev->dev, ctx->codec.h264.mv_col_buf_size, - ctx->codec.h264.mv_col_buf, - ctx->codec.h264.mv_col_buf_dma, - DMA_ATTR_NO_KERNEL_MAPPING); dma_free_attrs(dev->dev, CEDRUS_NEIGHBOR_INFO_BUF_SIZE, ctx->codec.h264.neighbor_info_buf, ctx->codec.h264.neighbor_info_buf_dma, @@ -696,6 +671,17 @@ static void cedrus_h264_trigger(struct cedrus_ctx *ctx) VE_H264_TRIGGER_TYPE_AVC_SLICE_DECODE); } +static void cedrus_h264_buf_cleanup(struct cedrus_ctx *ctx, + struct cedrus_buffer *buf) +{ + if (buf->codec.h264.mv_col_buf_size) + dma_free_attrs(ctx->dev->dev, + buf->codec.h264.mv_col_buf_size, + buf->codec.h264.mv_col_buf, + buf->codec.h264.mv_col_buf_dma, + DMA_ATTR_NO_KERNEL_MAPPING); +} + struct cedrus_dec_ops cedrus_dec_ops_h264 = { .irq_clear = cedrus_h264_irq_clear, .irq_disable = cedrus_h264_irq_disable, @@ -704,4 +690,5 @@ struct cedrus_dec_ops cedrus_dec_ops_h264 = { .start = cedrus_h264_start, .stop = cedrus_h264_stop, .trigger = cedrus_h264_trigger, + .buf_cleanup = cedrus_h264_buf_cleanup, }; -- 2.31.1