video: driver: Enhance fence support

- Introduce V4L2_EVENT_VIDC_METADATA to post fence fd returned in
  ETB metadata done buffer.
- V4L2_CID_MPEG_VIDC_SW_FENCE_FD g_ctrl support for client to get
  fence fd for requested fence id.
- Addition of fence delivery and subscribtion support.
- Fence property packetization to send to firmware via FTB buffer.

Change-Id: Ifb289849e352af2c4729aa95040bd83753979970
Signed-off-by: Akshata Sahukar <quic_asahukar@quicinc.com>
This commit is contained in:
Akshata Sahukar
2022-02-07 11:45:56 -08:00
parent 93b88b9d69
commit 22cc24de7f
9 changed files with 273 additions and 29 deletions

View File

@@ -277,18 +277,29 @@ static struct msm_platform_inst_capability instance_data_kalama[] = {
{0},
NULL, msm_vidc_set_u32},
{SW_FENCE_ENABLE, DEC, CODECS_ALL,
/*
* Client will enable V4L2_CID_MPEG_VIDC_INPUT_METADATA_OUTBUF_FENCE
* to get fence_id in input metadata buffer done.
*/
{INPUT_META_OUTBUF_FENCE, DEC, CODECS_ALL,
V4L2_MPEG_MSM_VIDC_DISABLE, V4L2_MPEG_MSM_VIDC_ENABLE,
1, V4L2_MPEG_MSM_VIDC_DISABLE,
V4L2_CID_MPEG_VIDC_SW_FENCE_ENABLE,
V4L2_CID_MPEG_VIDC_INPUT_METADATA_OUTBUF_FENCE,
HFI_PROP_FENCE},
/*
* Client to do set_ctrl with FENCE_ID to set fence_id
* and then client will do get_ctrl with FENCE_FD to get
* fence_fd corresponding to client set fence_id.
*/
{FENCE_ID, DEC, CODECS_ALL,
0, INT_MAX, 1, 0,
V4L2_CID_MPEG_VIDC_SW_FENCE_ID},
V4L2_CID_MPEG_VIDC_SW_FENCE_ID,
0,
CAP_FLAG_DYNAMIC_ALLOWED | CAP_FLAG_OUTPUT_PORT},
{FENCE_FD, DEC, CODECS_ALL,
0, INT_MAX, 1, 0,
INVALID_FD, INT_MAX, 1, INVALID_FD,
V4L2_CID_MPEG_VIDC_SW_FENCE_FD},
{TS_REORDER, DEC, H264|HEVC,

View File

@@ -298,7 +298,7 @@ int msm_vidc_alloc_and_queue_session_internal_buffers(struct msm_vidc_inst *inst
enum msm_vidc_buffer_type buffer_type);
int msm_vidc_release_internal_buffers(struct msm_vidc_inst *inst,
enum msm_vidc_buffer_type buffer_type);
int msm_vidc_vb2_buffer_done(struct msm_vidc_inst *inst,
int msm_vidc_buffer_done(struct msm_vidc_inst *inst,
struct msm_vidc_buffer *buf);
int msm_vidc_remove_session(struct msm_vidc_inst *inst);
int msm_vidc_add_session(struct msm_vidc_inst *inst);

View File

@@ -61,6 +61,7 @@
#define MAX_SUPPORTED_MIN_QUALITY 70
#define MIN_CHROMA_QP_OFFSET -12
#define MAX_CHROMA_QP_OFFSET 0
#define INVALID_FD -1
#define DCVS_WINDOW 16
#define ENC_FPS_WINDOW 3
@@ -379,7 +380,7 @@ enum msm_vidc_inst_capability_type {
MB_CYCLES_FW,
MB_CYCLES_FW_VPP,
SECURE_MODE,
SW_FENCE_ENABLE,
INPUT_META_OUTBUF_FENCE,
FENCE_ID,
FENCE_FD,
TS_REORDER,

View File

@@ -77,6 +77,7 @@ static const u32 msm_vdec_output_subscribe_for_properties[] = {
HFI_PROP_PICTURE_TYPE,
HFI_PROP_DPB_LIST,
HFI_PROP_CABAC_SESSION,
HFI_PROP_FENCE,
};
static const u32 msm_vdec_internal_buffer_type[] = {
@@ -1230,6 +1231,8 @@ static int msm_vdec_subscribe_property(struct msm_vidc_inst *inst,
HFI_PAYLOAD_U32_ARRAY,
&payload[0],
(count + 1) * sizeof(u32));
if (rc)
return rc;
return rc;
}
@@ -1241,7 +1244,15 @@ static int msm_vdec_subscribe_metadata(struct msm_vidc_inst *inst,
u32 payload[32] = {0};
u32 i, count = 0;
struct msm_vidc_inst_capability *capability;
static const u32 metadata_list[] = {
const u32 metadata_input_list[] = {
INPUT_META_OUTBUF_FENCE,
/*
* when fence enabled, client needs output buffer_tag
* in input metadata buffer done.
*/
META_OUTPUT_BUF_TAG,
};
const u32 metadata_output_list[] = {
META_BITSTREAM_RESOLUTION,
META_CROP_OFFSETS,
META_DPB_MISR,
@@ -1253,6 +1264,9 @@ static int msm_vdec_subscribe_metadata(struct msm_vidc_inst *inst,
META_SEI_MASTERING_DISP,
META_SEI_CLL,
META_HDR10PLUS,
/*
* client needs input buffer tag in output metadata buffer done.
*/
META_BUF_TAG,
META_DPB_TAG_LIST,
META_SUBFRAME_OUTPUT,
@@ -1268,14 +1282,28 @@ static int msm_vdec_subscribe_metadata(struct msm_vidc_inst *inst,
capability = inst->capabilities;
payload[0] = HFI_MODE_METADATA;
for (i = 0; i < ARRAY_SIZE(metadata_list); i++) {
if (capability->cap[metadata_list[i]].value &&
msm_vidc_allow_metadata(inst, metadata_list[i])) {
if (port == INPUT_PORT) {
for (i = 0; i < ARRAY_SIZE(metadata_input_list); i++) {
if (capability->cap[metadata_input_list[i]].value &&
msm_vidc_allow_metadata(inst, metadata_input_list[i])) {
payload[count + 1] =
capability->cap[metadata_list[i]].hfi_id;
capability->cap[metadata_input_list[i]].hfi_id;
count++;
}
};
}
} else if (port == OUTPUT_PORT) {
for (i = 0; i < ARRAY_SIZE(metadata_output_list); i++) {
if (capability->cap[metadata_output_list[i]].value &&
msm_vidc_allow_metadata(inst, metadata_output_list[i])) {
payload[count + 1] =
capability->cap[metadata_output_list[i]].hfi_id;
count++;
}
}
} else {
i_vpr_e(inst, "%s: invalid port: %d\n", __func__, port);
return -EINVAL;
}
rc = venus_hfi_session_command(inst,
HFI_CMD_SUBSCRIBE_MODE,
@@ -1283,6 +1311,8 @@ static int msm_vdec_subscribe_metadata(struct msm_vidc_inst *inst,
HFI_PAYLOAD_U32_ARRAY,
&payload[0],
(count + 1) * sizeof(u32));
if (rc)
return rc;
return rc;
}
@@ -1294,10 +1324,10 @@ static int msm_vdec_set_delivery_mode_metadata(struct msm_vidc_inst *inst,
u32 payload[32] = {0};
u32 i, count = 0;
struct msm_vidc_inst_capability *capability;
static const u32 metadata_input_list[] = {
const u32 metadata_input_list[] = {
META_BUF_TAG,
};
static const u32 metadata_output_list[] = {
const u32 metadata_output_list[] = {
META_OUTPUT_BUF_TAG,
};
@@ -1338,6 +1368,62 @@ static int msm_vdec_set_delivery_mode_metadata(struct msm_vidc_inst *inst,
HFI_PAYLOAD_U32_ARRAY,
&payload[0],
(count + 1) * sizeof(u32));
if (rc)
return rc;
return rc;
}
static int msm_vdec_set_delivery_mode_property(struct msm_vidc_inst *inst,
enum msm_vidc_port_type port)
{
int rc = 0;
u32 payload[32] = {0};
u32 i, count = 0;
struct msm_vidc_inst_capability *capability;
const u32 property_output_list[] = {
INPUT_META_OUTBUF_FENCE,
};
const u32 property_input_list[] = {};
if (!inst || !inst->capabilities) {
d_vpr_e("%s: invalid params\n", __func__);
return -EINVAL;
}
i_vpr_h(inst, "%s()\n", __func__);
capability = inst->capabilities;
payload[0] = HFI_MODE_PROPERTY;
if (port == INPUT_PORT) {
for (i = 0; i < ARRAY_SIZE(property_input_list); i++) {
if (capability->cap[property_input_list[i]].value) {
payload[count + 1] =
capability->cap[property_input_list[i]].hfi_id;
count++;
}
}
} else if (port == OUTPUT_PORT) {
for (i = 0; i < ARRAY_SIZE(property_output_list); i++) {
if (capability->cap[property_output_list[i]].value) {
payload[count + 1] =
capability->cap[property_output_list[i]].hfi_id;
count++;
}
}
} else {
i_vpr_e(inst, "%s: invalid port: %d\n", __func__, port);
return -EINVAL;
}
rc = venus_hfi_session_command(inst,
HFI_CMD_DELIVERY_MODE,
port,
HFI_PAYLOAD_U32_ARRAY,
&payload[0],
(count + 1) * sizeof(u32));
if (rc)
return rc;
return rc;
}
@@ -1354,6 +1440,8 @@ static int msm_vdec_session_resume(struct msm_vidc_inst *inst,
HFI_PAYLOAD_NONE,
NULL,
0);
if (rc)
return rc;
return rc;
}
@@ -1984,6 +2072,10 @@ int msm_vdec_streamon_output(struct msm_vidc_inst *inst)
if (rc)
goto error;
rc = msm_vdec_set_delivery_mode_property(inst, OUTPUT_PORT);
if (rc)
return rc;
rc = msm_vdec_set_delivery_mode_metadata(inst, OUTPUT_PORT);
if (rc)
return rc;
@@ -2887,6 +2979,7 @@ int msm_vdec_subscribe_event(struct msm_vidc_inst *inst,
switch (sub->type) {
case V4L2_EVENT_EOS:
case V4L2_EVENT_VIDC_METADATA:
rc = v4l2_event_subscribe(&inst->event_handler, sub, MAX_EVENTS, NULL);
break;
case V4L2_EVENT_SOURCE_CHANGE:

View File

@@ -82,7 +82,7 @@ static const struct msm_vidc_cap_name cap_name_arr[] = {
{MB_CYCLES_FW, "MB_CYCLES_FW" },
{MB_CYCLES_FW_VPP, "MB_CYCLES_FW_VPP" },
{SECURE_MODE, "SECURE_MODE" },
{SW_FENCE_ENABLE, "SW_FENCE_ENABLE" },
{INPUT_META_OUTBUF_FENCE, "INPUT_META_OUTBUF_FENCE" },
{FENCE_ID, "FENCE_ID" },
{FENCE_FD, "FENCE_FD" },
{TS_REORDER, "TS_REORDER" },
@@ -1412,6 +1412,14 @@ bool msm_vidc_allow_property(struct msm_vidc_inst *inst, u32 hfi_id)
is_allowed = false;
}
break;
case HFI_PROP_FENCE:
if (!inst->capabilities->cap[INPUT_META_OUTBUF_FENCE].value) {
i_vpr_h(inst,
"%s: cap: %24s not enabled, hence not allowed to subscribe\n",
__func__, cap_name(INPUT_META_OUTBUF_FENCE));
is_allowed = false;
}
break;
default:
is_allowed = true;
break;
@@ -2016,6 +2024,46 @@ int msm_vidc_state_change_last_flag(struct msm_vidc_inst *inst)
return rc;
}
int msm_vidc_get_fence_fd(struct msm_vidc_inst *inst, int *fence_fd)
{
int rc = 0;
struct msm_vidc_fence *fence, *dummy_fence;
bool found = false;
*fence_fd = INVALID_FD;
if (!inst || !inst->capabilities) {
d_vpr_e("%s: invalid params\n", __func__);
return -EINVAL;
}
list_for_each_entry_safe(fence, dummy_fence, &inst->fence_list, list) {
if (fence->dma_fence.seqno ==
(u64)inst->capabilities->cap[FENCE_ID].value) {
found = true;
break;
}
}
if (!found) {
i_vpr_e(inst, "%s: could not find matching fence for fence id: %d\n",
__func__, inst->capabilities->cap[FENCE_ID].value);
rc = -EINVAL;
goto exit;
}
if (fence->fd == INVALID_FD) {
rc = msm_vidc_create_fence_fd(inst, fence);
if (rc)
goto exit;
}
*fence_fd = fence->fd;
exit:
return rc;
}
int msm_vidc_get_control(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl)
{
int rc = 0;
@@ -2041,6 +2089,12 @@ int msm_vidc_get_control(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl)
i_vpr_h(inst, "%s: film grain present: %d\n",
__func__, ctrl->val);
break;
case V4L2_CID_MPEG_VIDC_SW_FENCE_FD:
rc = msm_vidc_get_fence_fd(inst, &ctrl->val);
if (!rc)
i_vpr_l(inst, "%s: fence fd: %d\n",
__func__, ctrl->val);
break;
default:
i_vpr_e(inst, "invalid ctrl %s id %d\n",
ctrl->name, ctrl->id);
@@ -3272,7 +3326,7 @@ int msm_vidc_queue_buffer_single(struct msm_vidc_inst *inst, struct vb2_buffer *
if (!buf)
return -EINVAL;
if (inst->capabilities->cap[SW_FENCE_ENABLE].value &&
if (inst->capabilities->cap[INPUT_META_OUTBUF_FENCE].value &&
is_output_buffer(buf->type)) {
fence = msm_vidc_fence_create(inst);
if (!fence)
@@ -3646,7 +3700,7 @@ int msm_vidc_release_internal_buffers(struct msm_vidc_inst *inst,
return 0;
}
int msm_vidc_vb2_buffer_done(struct msm_vidc_inst *inst,
static int msm_vidc_vb2_buffer_done(struct msm_vidc_inst *inst,
struct msm_vidc_buffer *buf)
{
int type, port, state;
@@ -3714,6 +3768,53 @@ int msm_vidc_vb2_buffer_done(struct msm_vidc_inst *inst,
return 0;
}
static int msm_vidc_v4l2_buffer_event(struct msm_vidc_inst *inst,
struct msm_vidc_buffer *buf)
{
int rc = 0;
struct v4l2_event event = {0};
struct v4l2_event_vidc_metadata *event_data = NULL;
if (!inst || !buf) {
d_vpr_e("%s: invalid params\n", __func__);
return -EINVAL;
}
if (buf->type != MSM_VIDC_BUF_INPUT_META) {
i_vpr_e(inst, "%s: unsupported buffer type %s\n",
__func__, buf_name(buf->type));
return -EINVAL;
}
event.type = V4L2_EVENT_VIDC_METADATA;
event_data = (struct v4l2_event_vidc_metadata *)event.u.data;
event_data->type = INPUT_META_PLANE;
event_data->fd = buf->fd;
v4l2_event_queue_fh(&inst->event_handler, &event);
return rc;
}
int msm_vidc_buffer_done(struct msm_vidc_inst *inst,
struct msm_vidc_buffer *buf)
{
if (!inst || !inst->capabilities || !buf) {
d_vpr_e("%s: invalid params\n", __func__);
return -EINVAL;
}
if (buf->type == MSM_VIDC_BUF_INPUT_META &&
inst->capabilities->cap[INPUT_META_VIA_REQUEST].value) {
if (inst->capabilities->cap[INPUT_META_OUTBUF_FENCE].value)
return msm_vidc_v4l2_buffer_event(inst, buf);
} else {
return msm_vidc_vb2_buffer_done(inst, buf);
}
return 0;
}
int msm_vidc_event_queue_init(struct msm_vidc_inst *inst)
{
int rc = 0;
@@ -5086,7 +5187,7 @@ int msm_vidc_flush_buffers(struct msm_vidc_inst *inst,
buf->attr & MSM_VIDC_ATTR_DEFERRED) {
print_vidc_buffer(VIDC_HIGH, "high", "flushing buffer", inst, buf);
if (!(buf->attr & MSM_VIDC_ATTR_BUFFER_DONE))
msm_vidc_vb2_buffer_done(inst, buf);
msm_vidc_buffer_done(inst, buf);
msm_vidc_put_driver_buf(inst, buf);
}
}
@@ -5229,7 +5330,7 @@ void msm_vidc_destroy_buffers(struct msm_vidc_inst *inst)
list_for_each_entry_safe(buf, dummy, &buffers->list, list) {
print_vidc_buffer(VIDC_ERR, "err ", "destroying ", inst, buf);
if (!(buf->attr & MSM_VIDC_ATTR_BUFFER_DONE))
msm_vidc_vb2_buffer_done(inst, buf);
msm_vidc_buffer_done(inst, buf);
msm_vidc_put_driver_buf(inst, buf);
}
msm_vidc_unmap_buffers(inst, ext_buf_types[i]);
@@ -5267,7 +5368,7 @@ void msm_vidc_destroy_buffers(struct msm_vidc_inst *inst)
}
list_for_each_entry_safe(fence, dummy_fence, &inst->fence_list, list) {
i_vpr_e(inst, "%s: destroying fence id: %llu",
i_vpr_e(inst, "%s: destroying fence id: %llu\n",
__func__, fence->dma_fence.seqno);
msm_vidc_fence_destroy(inst, fence);
}

View File

@@ -63,6 +63,7 @@ struct msm_vidc_fence *msm_vidc_fence_create(struct msm_vidc_inst *inst)
return NULL;
}
fence->fd = INVALID_FD;
spin_lock_init(&fence->lock);
dma_fence_init(&fence->dma_fence, &msm_vidc_dma_fence_ops,
&fence->lock, inst->fence_context.ctx_num,

View File

@@ -3523,9 +3523,19 @@ int venus_hfi_queue_buffer(struct msm_vidc_inst *inst,
goto unlock;
}
if (inst->capabilities->cap[SW_FENCE_ENABLE].value &&
if (inst->capabilities->cap[INPUT_META_OUTBUF_FENCE].value &&
is_output_buffer(buffer->type)) {
/* TODO(AS): create fence property packet to send to fw */
rc = hfi_create_packet(inst->packet,
inst->packet_size,
HFI_PROP_FENCE,
0,
HFI_PAYLOAD_U64,
HFI_PORT_RAW,
core->packet_id++,
&buffer->fence_id,
sizeof(u64));
if (rc)
goto unlock;
}
rc = venus_hfi_add_pending_packets(inst);

View File

@@ -1115,7 +1115,7 @@ static int handle_dequeue_buffers(struct msm_vidc_inst *inst)
"vb2 done already", inst, buf);
} else {
buf->attr |= MSM_VIDC_ATTR_BUFFER_DONE;
msm_vidc_vb2_buffer_done(inst, buf);
msm_vidc_buffer_done(inst, buf);
}
msm_vidc_put_driver_buf(inst, buf);
}
@@ -1557,7 +1557,7 @@ static int handle_session_property(struct msm_vidc_inst *inst,
__func__, payload_ptr[0], inst->capabilities->cap[PIPE].value);
break;
case HFI_PROP_FENCE:
if (inst->capabilities->cap[SW_FENCE_ENABLE].value) {
if (inst->capabilities->cap[INPUT_META_OUTBUF_FENCE].value) {
if (payload_ptr) {
fence_id = payload_ptr[0];
rc = msm_vidc_fence_signal(inst, fence_id);

View File

@@ -200,8 +200,8 @@ enum v4l2_mpeg_video_av1_tier {
/* Control to enable input metadata via request api */
#define V4L2_CID_MPEG_VIDC_INPUT_METADATA_VIA_REQUEST_ENABLE \
(V4L2_CID_MPEG_VIDC_BASE + 0x37)
/* Control to enable software fence feature */
#define V4L2_CID_MPEG_VIDC_SW_FENCE_ENABLE \
/* Enables Output buffer fence id via input metadata */
#define V4L2_CID_MPEG_VIDC_INPUT_METADATA_OUTBUF_FENCE \
(V4L2_CID_MPEG_VIDC_BASE + 0x38)
/* Control to set fence id to driver in order get corresponding fence fd */
#define V4L2_CID_MPEG_VIDC_SW_FENCE_ID \
@@ -345,6 +345,7 @@ enum v4l2_mpeg_vidc_metadata {
METADATA_ROI_INFO = 0x03000173,
METADATA_DPB_TAG_LIST = 0x03000179,
METADATA_MAX_NUM_REORDER_FRAMES = 0x03000127,
METADATA_FENCE = 0x0300018B,
};
enum meta_interlace_info {
META_INTERLACE_INFO_NONE = 0x00000000,
@@ -358,4 +359,30 @@ enum meta_interlace_info {
/* vendor controls end */
/* vendor events start */
/*
* Vendor event structure looks like below (reference videodev2.h)
* struct v4l2_event {
* __u32 type;
* union {
* struct v4l2_event_src_change src_change;
* ...
* / ********** vendor event structure ******** /
* __u8 data[64];
* } u;
* __u32 pending;
* ...
* }
*/
#define V4L2_EVENT_VIDC_METADATA \
(V4L2_EVENT_PRIVATE_START + 0x1)
struct v4l2_event_vidc_metadata {
__u32 type;
__s32 fd;
__u8 reserved[56];
};
/* vendor events end */
#endif