amlvideo2: The buffer is equipped with canvas every time it is used. [1/1]

PD#SWPL-29593

Problem:
Because each buffer is equipped with canvas, the canvas is not enough.

Solution:
Only use the canvas when the buffer is used,
and allocate the canvas to the next buffer after use.

Verify:
on tm2-ab301

Change-Id: I98a5986f80471c05dfb5638c5404305c03aec867
Signed-off-by: renjiang.han <renjiang.han@amlogic.com>
This commit is contained in:
renjiang.han
2020-07-15 16:16:55 +08:00
committed by Chris
parent 907d8f7943
commit 6e07d0e713
2 changed files with 210 additions and 105 deletions

View File

@@ -521,7 +521,6 @@ static void canvas_pool_config(void)
canvas_pool_register_const_canvas(0x70, 0x77, "ppmgr");
canvas_pool_register_const_canvas(0xe4, 0xef, "encoder");
canvas_pool_register_const_canvas(0x40, 0x48, "osd");
canvas_pool_register_const_canvas(0xc0, 0xd7, "amlvideo2");
/*please add static canvas later. */
}

View File

@@ -71,8 +71,6 @@
#include <linux/sched/rt.h>
#define AVMLVIDEO2_MODULE_NAME "amlvideo2"
#define AMLVIDEO2_RES_CANVAS 0xc0
#define AMLVIDEO2_1_RES_CANVAS 0xcc
#define MULTI_NODE
/* #define USE_SEMA_QBUF */
@@ -111,9 +109,7 @@ KERNEL_VERSION(\
#define DEVICE_NAME "amlvideo2.0"
#endif
#define AMLVIDEO2_RES0_CANVAS_INDEX AMLVIDEO2_RES_CANVAS
#define AMLVIDEO2_RES1_CANVAS_INDEX AMLVIDEO2_1_RES_CANVAS
#define BUFFER_COUNT 4
#define DUR2PTS(x) ((x) - ((x) >> 4))
#define DUR2PTS_RM(x) ((x) & 0xf)
@@ -438,114 +434,162 @@ static struct v4l2_frmsize_discrete amlvideo2_prev_resolution[] = {{160, 120}, {
static struct v4l2_frmsize_discrete amlvideo2_pic_resolution[] = {{1280, 960} };
static int amlvideo2_canvas[2][2 * BUFFER_COUNT] = {
{-1, -1, -1, -1, -1, -1, -1, -1},
{-1, -1, -1, -1, -1, -1, -1, -1}
};
static int yuv420_canvas[2][BUFFER_COUNT] = {
{-1, -1, -1, -1},
{-1, -1, -1, -1}
};
static unsigned int print_cvs_idx;
module_param(print_cvs_idx, uint, 0644);
MODULE_PARM_DESC(print_cvs_idx, "print canvas index\n");
int get_amlvideo2_canvas_index(struct amlvideo2_output *output,
int start_canvas)
int inst, int buffer_id)
{
int canvas = start_canvas;
int v4l2_format = output->v4l2_format;
void *buf = (void *)output->vbuf;
int width = output->width;
int height = output->height;
int canvas_height = height;
switch (v4l2_format) {
case V4L2_PIX_FMT_RGB565X:
case V4L2_PIX_FMT_VYUY:
canvas = start_canvas;
canvas_config(canvas, (unsigned long)buf, width * 2, canvas_height,
CANVAS_ADDR_NOWRAP,
CANVAS_BLKMODE_LINEAR);
break;
case V4L2_PIX_FMT_YUV444:
case V4L2_PIX_FMT_BGR24:
case V4L2_PIX_FMT_RGB24:
canvas = start_canvas;
canvas_config(canvas, (unsigned long)buf, width * 3, canvas_height,
CANVAS_ADDR_NOWRAP,
CANVAS_BLKMODE_LINEAR);
break;
case V4L2_PIX_FMT_RGB32:
canvas = start_canvas;
canvas_config(canvas, (unsigned long)buf, width * 4, canvas_height,
CANVAS_ADDR_NOWRAP,
CANVAS_BLKMODE_LINEAR);
break;
case V4L2_PIX_FMT_NV12:
case V4L2_PIX_FMT_NV21:
canvas_config(start_canvas, (unsigned long)buf, width, canvas_height,
CANVAS_ADDR_NOWRAP,
CANVAS_BLKMODE_LINEAR);
canvas_config(start_canvas + 1, (unsigned long)(buf + width * height),
width, canvas_height / 2,
CANVAS_ADDR_NOWRAP,
CANVAS_BLKMODE_LINEAR);
canvas = start_canvas | ((start_canvas + 1) << 8);
break;
case V4L2_PIX_FMT_YVU420:
case V4L2_PIX_FMT_YUV420:
canvas_config(start_canvas, (unsigned long)buf, width, canvas_height,
CANVAS_ADDR_NOWRAP,
CANVAS_BLKMODE_LINEAR);
canvas_config(start_canvas + 1, (unsigned long)(buf + width * height),
width / 2, canvas_height / 2,
CANVAS_ADDR_NOWRAP,
CANVAS_BLKMODE_LINEAR);
canvas_config(start_canvas + 2,
(unsigned long)(buf + width * height * 5 / 4),
width / 2, canvas_height / 2,
CANVAS_ADDR_NOWRAP,
CANVAS_BLKMODE_LINEAR);
if (v4l2_format == V4L2_PIX_FMT_YUV420) {
canvas = start_canvas | ((start_canvas + 1) << 8)
| ((start_canvas + 2) << 16);
} else {
canvas = start_canvas | ((start_canvas + 2) << 8)
| ((start_canvas + 1) << 16);
}
break;
default:
break;
}
if (print_cvs_idx == 1) {
pr_err("v4l2_format=%x, canvas=%x\n", v4l2_format, canvas);
print_cvs_idx = 0;
}
return canvas;
}
/* #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 */
int convert_canvas_index(struct amlvideo2_output *output, int start_canvas)
{
int canvas = start_canvas;
int canvas = amlvideo2_canvas[inst][2 * buffer_id];
int v4l2_format = output->v4l2_format;
void *buf = (void *)output->vbuf;
int width = output->width;
int height = output->height;
int canvas_height = height;
const char *canvas_owner0 = "amlvideo2.0";
const char *canvas_owner1 = "amlvideo2.1";
if (canvas < 0)
return -1;
switch (v4l2_format) {
case V4L2_PIX_FMT_RGB565X:
case V4L2_PIX_FMT_VYUY:
canvas = start_canvas;
canvas_config(canvas, (unsigned long)buf,
width * 2, canvas_height,
CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_LINEAR);
break;
case V4L2_PIX_FMT_YUV444:
case V4L2_PIX_FMT_BGR24:
case V4L2_PIX_FMT_RGB24:
canvas_config(canvas, (unsigned long)buf,
width * 3, canvas_height,
CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_LINEAR);
break;
case V4L2_PIX_FMT_RGB32:
canvas_config(canvas, (unsigned long)buf,
width * 4, canvas_height,
CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_LINEAR);
break;
case V4L2_PIX_FMT_NV12:
case V4L2_PIX_FMT_NV21:
if (amlvideo2_canvas[inst][2 * buffer_id + 1] < 0)
return -1;
canvas_config(amlvideo2_canvas[inst][2 * buffer_id],
(unsigned long)buf, width, canvas_height,
CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_LINEAR);
canvas_config(amlvideo2_canvas[inst][2 * buffer_id + 1],
(unsigned long)(buf + width * height),
width, canvas_height / 2,
CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_LINEAR);
canvas = amlvideo2_canvas[inst][2 * buffer_id]
| (amlvideo2_canvas[inst][2 * buffer_id + 1] << 8);
break;
case V4L2_PIX_FMT_YVU420:
case V4L2_PIX_FMT_YUV420:
if (amlvideo2_canvas[inst][2 * buffer_id + 1] < 0)
return -1;
if (yuv420_canvas[inst][buffer_id] < 0)
yuv420_canvas[inst][buffer_id] =
canvas_pool_map_alloc_canvas((inst == 0) ?
canvas_owner0 :
canvas_owner1);
if (yuv420_canvas[inst][buffer_id] < 0)
return -1;
canvas_config(amlvideo2_canvas[inst][2 * buffer_id],
(unsigned long)buf, width, canvas_height,
CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_LINEAR);
canvas_config(amlvideo2_canvas[inst][2 * buffer_id + 1],
(unsigned long)(buf + width * height),
width / 2, canvas_height / 2,
CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_LINEAR);
canvas_config(yuv420_canvas[inst][buffer_id],
(unsigned long)(buf + width * height * 5 / 4),
width / 2, canvas_height / 2,
CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_LINEAR);
if (v4l2_format == V4L2_PIX_FMT_YUV420) {
canvas = amlvideo2_canvas[inst][2 * buffer_id]
| (amlvideo2_canvas[inst][2 * buffer_id + 1]
<< 8) | (yuv420_canvas[inst][buffer_id]
<< 16);
} else {
canvas = amlvideo2_canvas[inst][2 * buffer_id]
| (yuv420_canvas[inst][buffer_id] << 8)
| (amlvideo2_canvas[inst][2 * buffer_id + 1]
<< 16);
}
break;
default:
break;
}
if (print_cvs_idx == 1) {
pr_err("v4l2_format=%x, canvas=%x\n", v4l2_format, canvas);
print_cvs_idx = 0;
}
return canvas;
}
/* #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 */
int convert_canvas_index(struct amlvideo2_output *output,
int inst, int buffer_id)
{
int canvas = amlvideo2_canvas[inst][2 * buffer_id];
int v4l2_format = output->v4l2_format;
const char *canvas_owner0 = "amlvideo2.0";
const char *canvas_owner1 = "amlvideo2.1";
if (canvas < 0)
return -1;
switch (v4l2_format) {
case V4L2_PIX_FMT_RGB565X:
case V4L2_PIX_FMT_VYUY:
canvas = amlvideo2_canvas[inst][2 * buffer_id];
break;
case V4L2_PIX_FMT_YUV444:
case V4L2_PIX_FMT_BGR24:
case V4L2_PIX_FMT_RGB24:
case V4L2_PIX_FMT_RGB32:
canvas = start_canvas;
canvas = amlvideo2_canvas[inst][2 * buffer_id];
break;
case V4L2_PIX_FMT_NV12:
case V4L2_PIX_FMT_NV21:
canvas = start_canvas | ((start_canvas + 1) << 8);
if (amlvideo2_canvas[inst][2 * buffer_id + 1] < 0)
return -1;
canvas = amlvideo2_canvas[inst][2 * buffer_id]
| (amlvideo2_canvas[inst][2 * buffer_id + 1] << 8);
break;
case V4L2_PIX_FMT_YVU420:
case V4L2_PIX_FMT_YUV420:
if (v4l2_format == V4L2_PIX_FMT_YUV420) {
canvas = start_canvas | ((start_canvas + 1) << 8)
| ((start_canvas + 2) << 16);
} else {
canvas = start_canvas | ((start_canvas + 2) << 8)
| ((start_canvas + 1) << 16);
}
if (amlvideo2_canvas[inst][2 * buffer_id + 1] < 0)
return -1;
if (yuv420_canvas[inst][buffer_id] < 0)
yuv420_canvas[inst][buffer_id] =
canvas_pool_map_alloc_canvas((inst == 0) ?
canvas_owner0 :
canvas_owner1);
if (yuv420_canvas[inst][buffer_id] < 0)
return -1;
if (v4l2_format == V4L2_PIX_FMT_YUV420)
canvas = amlvideo2_canvas[inst][2 * buffer_id]
| (amlvideo2_canvas[inst][2 * buffer_id + 1] << 8)
| (yuv420_canvas[inst][buffer_id] << 16);
else
canvas = amlvideo2_canvas[inst][2 * buffer_id]
| (yuv420_canvas[inst][buffer_id] << 8)
| (amlvideo2_canvas[inst][2 * buffer_id + 1] << 16);
break;
default:
break;
@@ -3022,7 +3066,7 @@ int amlvideo2_ge2d_multi_pre_process(struct vframe_s *vf,
int current_mirror;
int cur_angle = 0;
int output_canvas = output->canvas_id;
int temp_canvas = AMLVIDEO2_1_RES_CANVAS + 8;
int temp_canvas;
unsigned long temp_start = node->vid_dev->buffer_start +
(CMA_ALLOC_SIZE * SZ_1M);
int temp_w = vf->width/4;
@@ -3040,6 +3084,16 @@ int amlvideo2_ge2d_multi_pre_process(struct vframe_s *vf,
vf->width, vf->height);
}
if (yuv420_canvas[node->vid][0] < 0)
yuv420_canvas[node->vid][0] =
canvas_pool_map_alloc_canvas("amlvideo2.1");
if (yuv420_canvas[node->vid][0] < 0) {
pr_info("amlvideo2 has no canvas to use %d\n", __LINE__);
return -1;
}
temp_canvas = yuv420_canvas[node->vid][0];
if (amlvideo2_scaledown1 == 0) {
context->config.h_scale_coef_type = FILTER_TYPE_BICUBIC;
context->config.v_scale_coef_type = FILTER_TYPE_BICUBIC;
@@ -3722,21 +3776,21 @@ static int amlvideo2_fillbuff(struct amlvideo2_fh *fh,
output.vbuf = vbuf;
output.width = buf->vb.width;
output.height = buf->vb.height;
output.canvas_id = buf->canvas_id;
output.angle = node->qctl_regs[0];
output.frame = &buf->axis;
output.info.mode = node->mode;
memcpy(&output.info.display_info, &(node->display_info),
sizeof(struct vdisplay_info_s));
if (output.canvas_id == 0) {
output.canvas_id = get_amlvideo2_canvas_index(
&output, (node->vid == 0) ?
(AMLVIDEO2_RES0_CANVAS_INDEX + buf->vb.i * 3) :
(AMLVIDEO2_RES1_CANVAS_INDEX + buf->vb.i * 3));
buf->canvas_id = output.canvas_id;
output.canvas_id =
get_amlvideo2_canvas_index(&output, node->vid, buf->vb.i);
if (output.canvas_id < 0) {
pr_info("amlvideo2: has no canvas value, %d\n", __LINE__);
return -1;
}
//buf->canvas_id = output.canvas_id;
switch (output.v4l2_format) {
case V4L2_PIX_FMT_RGB565X:
case V4L2_PIX_FMT_YUV444:
@@ -4132,7 +4186,8 @@ static int amlvideo2_thread_tick(struct amlvideo2_fh *fh)
else
pr_info("node1 fillbuff start .\n");
}
amlvideo2_fillbuff(fh, buf, vf);
if (amlvideo2_fillbuff(fh, buf, vf) < 0)
pr_info("amlvideo2 fill buff error!\n");
if (amlvideo2_dbg_en & 2) {
if (node->vid == 0)
pr_info("node0 fillbuff end .\n");
@@ -4907,10 +4962,10 @@ static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
output.width = fh->width;
output.height = fh->height;
output.canvas_id = -1;
p->reserved = convert_canvas_index(
&output, fh->node->vid == 0 ?
(AMLVIDEO2_RES0_CANVAS_INDEX + p->index * 3) :
(AMLVIDEO2_RES1_CANVAS_INDEX + p->index * 3));
p->reserved =
convert_canvas_index(&output, fh->node->vid, p->index);
if (p->reserved == (u32)-1)
pr_info("amlvideo2 canvas alloc failed, %d\n", __LINE__);
} else {
p->reserved = 0;
}
@@ -5830,6 +5885,10 @@ static int amlvideo2_open(struct file *file)
struct amlvideo2_fh *fh = NULL;
struct videobuf_res_privdata *res = NULL;
struct resource *reserve = NULL;
int temp_canvas;
const char *canvas_owner0 = "amlvideo2.0";
const char *canvas_owner1 = "amlvideo2.1";
int i;
int ret;
mutex_lock(&node->mutex);
@@ -5869,6 +5928,35 @@ static int amlvideo2_open(struct file *file)
return -ENOMEM;
}
if (node->vid == 0) {
for (i = 0; i < 2 * BUFFER_COUNT; i++) {
amlvideo2_canvas[0][i] =
canvas_pool_map_alloc_canvas(canvas_owner0);
}
} else {
for (i = 0; i < 2 * BUFFER_COUNT; i++) {
amlvideo2_canvas[1][i] =
canvas_pool_map_alloc_canvas(canvas_owner1);
}
}
for (i = 0; i < 2 * BUFFER_COUNT; i++)
if (amlvideo2_canvas[node->vid][i] < 0)
break;
if (i != 2 * BUFFER_COUNT && amlvideo2_canvas[node->vid][i] < 0) {
for (i = 0; i < 2 * BUFFER_COUNT; i++) {
if (amlvideo2_canvas[node->vid][i] >= 0) {
temp_canvas = amlvideo2_canvas[node->vid][i];
canvas_pool_map_free_canvas(temp_canvas);
amlvideo2_canvas[node->vid][i] = -1;
}
}
pr_info("%s: %s alloc canvas failed, %d\n",
(node->vid == 0) ? canvas_owner0 : canvas_owner1,
__func__, __LINE__);
return -ENOMEM;
}
fh = node->fh;
if (fh == NULL) {
node->users--;
@@ -5954,10 +6042,28 @@ static int amlvideo2_close(struct file *file)
{
struct amlvideo2_fh *fh = file->private_data;
struct amlvideo2_node *node = fh->node;
int temp_canvas;
int i;
videobuf_stop(&fh->vb_vidq);
videobuf_mmap_free(&fh->vb_vidq);
amlvideo2_cma_buf_uninit(node->vid_dev, node->vid);
for (i = 0; i < 2 * BUFFER_COUNT; i++) {
if (amlvideo2_canvas[node->vid][i] >= 0) {
temp_canvas = amlvideo2_canvas[node->vid][i];
canvas_pool_map_free_canvas(temp_canvas);
amlvideo2_canvas[node->vid][i] = -1;
}
}
for (i = 0; i < BUFFER_COUNT; i++) {
if (yuv420_canvas[node->vid][i] >= 0) {
temp_canvas = yuv420_canvas[node->vid][i];
canvas_pool_map_free_canvas(temp_canvas);
yuv420_canvas[node->vid][i] = -1;
}
}
mutex_lock(&node->mutex);
if (node->r_type == AML_RECEIVER_NONE) {
/* #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */