diff --git a/driver/platform/waipio/src/msm_vidc_waipio.c b/driver/platform/waipio/src/msm_vidc_waipio.c index 07b83b3629..42b9bcc112 100644 --- a/driver/platform/waipio/src/msm_vidc_waipio.c +++ b/driver/platform/waipio/src/msm_vidc_waipio.c @@ -239,6 +239,11 @@ static struct msm_platform_inst_capability instance_data_waipio[] = { HFI_PROP_ROTATION, CAP_FLAG_ROOT | CAP_FLAG_OUTPUT_PORT}, + {SUPER_FRAME, ENC, CODECS_ALL, + 0, 16, 1, 0, + V4L2_CID_MPEG_VIDC_SUPERFRAME, + 0}, + {SLICE_INTERFACE, DEC, CODECS_ALL, 0, 0, 0, 0, V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE, diff --git a/driver/vidc/inc/msm_vidc_driver.h b/driver/vidc/inc/msm_vidc_driver.h index 2d482d1fbe..971991594f 100644 --- a/driver/vidc/inc/msm_vidc_driver.h +++ b/driver/vidc/inc/msm_vidc_driver.h @@ -302,5 +302,6 @@ void inst_unlock(struct msm_vidc_inst *inst, const char *function); bool inst_lock_check(struct msm_vidc_inst *inst, const char *function); int msm_vidc_update_meta_port_settings(struct msm_vidc_inst *inst); void msm_vidc_schedule_core_deinit(struct msm_vidc_core *core); +bool msm_vidc_is_super_buffer(struct msm_vidc_inst *inst); #endif // _MSM_VIDC_DRIVER_H_ diff --git a/driver/vidc/inc/msm_vidc_internal.h b/driver/vidc/inc/msm_vidc_internal.h index 234e8ed392..14948dcbb0 100644 --- a/driver/vidc/inc/msm_vidc_internal.h +++ b/driver/vidc/inc/msm_vidc_internal.h @@ -43,7 +43,8 @@ #define MAX_CAP_CHILDREN 16 #define DEFAULT_BITSTREM_ALIGNMENT 16 #define H265_BITSTREM_ALIGNMENT 32 -#define DEFAULT_MAX_HOST_BUF_COUNT 32 +#define DEFAULT_MAX_HOST_ENC_BUF_COUNT 64 +#define DEFAULT_MAX_HOST_DEC_BUF_COUNT 64 #define BIT_DEPTH_8 (8 << 16 | 8) #define BIT_DEPTH_10 (10 << 16 | 10) #define CODED_FRAMES_MBS_ONLY HFI_BITMASK_FRAME_MBS_ONLY_FLAG @@ -266,6 +267,7 @@ enum msm_vidc_inst_capability_type { HFLIP, VFLIP, ROTATION, + SUPER_FRAME, SLICE_INTERFACE, HEADER_MODE, PREPEND_SPSPPS_TO_IDR, diff --git a/driver/vidc/inc/venus_hfi.h b/driver/vidc/inc/venus_hfi.h index 21624faacf..f890df7892 100644 --- a/driver/vidc/inc/venus_hfi.h +++ b/driver/vidc/inc/venus_hfi.h @@ -35,6 +35,8 @@ int venus_hfi_session_command(struct msm_vidc_inst *inst, void *payload, u32 payload_size); int venus_hfi_queue_buffer(struct msm_vidc_inst *inst, struct msm_vidc_buffer *buffer, struct msm_vidc_buffer *metabuf); +int venus_hfi_queue_super_buffer(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *buffer, struct msm_vidc_buffer *metabuf); int venus_hfi_release_buffer(struct msm_vidc_inst *inst, struct msm_vidc_buffer *buffer); int venus_hfi_start(struct msm_vidc_inst *inst, enum msm_vidc_port_type port); diff --git a/driver/vidc/src/msm_venc.c b/driver/vidc/src/msm_venc.c index 6edf76f92b..ecd447dc85 100644 --- a/driver/vidc/src/msm_venc.c +++ b/driver/vidc/src/msm_venc.c @@ -244,7 +244,7 @@ static int msm_venc_set_host_max_buf_count(struct msm_vidc_inst *inst, enum msm_vidc_port_type port) { int rc = 0; - u32 count = DEFAULT_MAX_HOST_BUF_COUNT; + u32 count = DEFAULT_MAX_HOST_ENC_BUF_COUNT; if (port != INPUT_PORT && port != OUTPUT_PORT) { i_vpr_e(inst, "%s: invalid port %d\n", __func__, port); diff --git a/driver/vidc/src/msm_vidc_control.c b/driver/vidc/src/msm_vidc_control.c index f48c9a990c..28c2782bde 100644 --- a/driver/vidc/src/msm_vidc_control.c +++ b/driver/vidc/src/msm_vidc_control.c @@ -204,6 +204,8 @@ static const char *msm_vidc_get_priv_ctrl_name(struct msm_vidc_inst *inst, u32 c return "HEVC I Frame Max QP"; case V4L2_CID_MPEG_VIDC_HEVC_P_FRAME_MAX_QP: return "HEVC P Frame Max QP"; + case V4L2_CID_MPEG_VIDC_SUPERFRAME: + return "Encoder Batching Superframe"; default: i_vpr_e(inst, "%s: ctrl name not available for ctrl id %#x\n", __func__, control_id); diff --git a/driver/vidc/src/msm_vidc_driver.c b/driver/vidc/src/msm_vidc_driver.c index 87d54e616a..967b0b6aca 100644 --- a/driver/vidc/src/msm_vidc_driver.c +++ b/driver/vidc/src/msm_vidc_driver.c @@ -1438,6 +1438,20 @@ struct msm_vidc_buffer *get_meta_buffer(struct msm_vidc_inst *inst, return mbuf; } +bool msm_vidc_is_super_buffer(struct msm_vidc_inst *inst) +{ + struct msm_vidc_inst_capability *capability = NULL; + + if (!inst || !inst->capabilities) { + i_vpr_e(inst, "%s: Invalid params\n", __func__); + return false; + } + + capability = inst->capabilities; + + return !!capability->cap[SUPER_FRAME].value; +} + int msm_vidc_queue_buffer(struct msm_vidc_inst *inst, struct vb2_buffer *vb2) { int rc = 0; @@ -1492,7 +1506,10 @@ int msm_vidc_queue_buffer(struct msm_vidc_inst *inst, struct vb2_buffer *vb2) return -EINVAL; } } - rc = venus_hfi_queue_buffer(inst, buf, meta); + if (msm_vidc_is_super_buffer(inst) && is_input_buffer(buf->type)) + rc = venus_hfi_queue_super_buffer(inst, buf, meta); + else + rc = venus_hfi_queue_buffer(inst, buf, meta); if (rc) return rc; diff --git a/driver/vidc/src/venus_hfi.c b/driver/vidc/src/venus_hfi.c index b1eb5fb14b..ed0c1ff9b7 100644 --- a/driver/vidc/src/venus_hfi.c +++ b/driver/vidc/src/venus_hfi.c @@ -33,6 +33,14 @@ #define MAX_FIRMWARE_NAME_SIZE 128 +#define update_offset(offset, val) ((offset) += (val)) +#define update_timestamp(ts, val) \ + do { \ + do_div((ts), NSEC_PER_USEC); \ + (ts) += (val); \ + (ts) *= NSEC_PER_USEC; \ + } while (0) + extern struct msm_vidc_core *g_core; static int __resume(struct msm_vidc_core *core); @@ -879,6 +887,18 @@ int __iface_cmdq_write(struct msm_vidc_core *core, return rc; } +static int __iface_cmdq_write_intr(struct msm_vidc_core *core, + void *pkt, bool allow) +{ + bool needs_interrupt = false; + int rc = __iface_cmdq_write_relaxed(core, pkt, &needs_interrupt); + + if (!rc && allow && needs_interrupt) + call_venus_op(core, raise_interrupt, core); + + return rc; +} + int __iface_msgq_read(struct msm_vidc_core *core, void *pkt) { u32 tx_req_is_set = 0; @@ -3024,6 +3044,125 @@ unlock: return rc; } +int venus_hfi_queue_super_buffer(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *buffer, struct msm_vidc_buffer *metabuf) +{ + int rc = 0; + struct msm_vidc_core *core; + struct hfi_buffer hfi_buffer; + struct hfi_buffer hfi_meta_buffer; + struct msm_vidc_inst_capability *capability; + u32 frame_size, meta_size, batch_size, cnt = 0; + u64 ts_delta_us; + + if (!inst || !inst->core || !inst->capabilities) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + core = inst->core; + capability = inst->capabilities; + core_lock(core, __func__); + + if (!__valdiate_session(core, inst, __func__)) { + rc = -EINVAL; + goto unlock; + } + + /* Get super yuv buffer */ + rc = get_hfi_buffer(inst, buffer, &hfi_buffer); + if (rc) + goto unlock; + + /* Get super meta buffer */ + if (metabuf) { + rc = get_hfi_buffer(inst, metabuf, &hfi_meta_buffer); + if (rc) + goto unlock; + } + + batch_size = capability->cap[SUPER_FRAME].value; + frame_size = call_session_op(core, buffer_size, inst, MSM_VIDC_BUF_INPUT); + meta_size = call_session_op(core, buffer_size, inst, MSM_VIDC_BUF_INPUT_META); + ts_delta_us = 1000000 / (capability->cap[FRAME_RATE].value >> 16); + + /* Sanitize super yuv buffer */ + if (frame_size * batch_size != buffer->buffer_size) { + i_vpr_e(inst, "%s: invalid super yuv buffer. frame %u, batch %u, buffer size %u\n", + __func__, frame_size, batch_size, buffer->buffer_size); + goto unlock; + } + + /* Sanitize super meta buffer */ + if (metabuf && meta_size * batch_size != metabuf->buffer_size) { + i_vpr_e(inst, "%s: invalid super meta buffer. meta %u, batch %u, buffer size %u\n", + __func__, meta_size, batch_size, metabuf->buffer_size); + goto unlock; + } + + /* Initialize yuv buffer */ + hfi_buffer.data_size = frame_size; + hfi_buffer.addr_offset = 0; + + /* Initialize meta buffer */ + if (metabuf) { + hfi_meta_buffer.data_size = meta_size; + hfi_meta_buffer.addr_offset = 0; + } + + while (cnt < batch_size) { + /* Create header */ + rc = hfi_create_header(inst->packet, inst->packet_size, + inst->session_id, core->header_id++); + if (rc) + goto unlock; + + /* Create yuv packet */ + update_offset(hfi_buffer.addr_offset, (cnt ? frame_size : 0u)); + update_timestamp(hfi_buffer.timestamp, (cnt ? ts_delta_us : 0u)); + rc = hfi_create_packet(inst->packet, + inst->packet_size, + HFI_CMD_BUFFER, + HFI_HOST_FLAGS_INTR_REQUIRED, + HFI_PAYLOAD_STRUCTURE, + get_hfi_port_from_buffer_type(inst, buffer->type), + core->packet_id++, + &hfi_buffer, + sizeof(hfi_buffer)); + if (rc) + goto unlock; + + /* Create meta packet */ + if (metabuf) { + update_offset(hfi_meta_buffer.addr_offset, (cnt ? meta_size : 0u)); + update_timestamp(hfi_meta_buffer.timestamp, (cnt ? ts_delta_us : 0u)); + rc = hfi_create_packet(inst->packet, + inst->packet_size, + HFI_CMD_BUFFER, + HFI_HOST_FLAGS_INTR_REQUIRED, + HFI_PAYLOAD_STRUCTURE, + get_hfi_port_from_buffer_type(inst, metabuf->type), + core->packet_id++, + &hfi_meta_buffer, + sizeof(hfi_meta_buffer)); + if (rc) + goto unlock; + } + + /* Raise interrupt only for last pkt in the batch */ + rc = __iface_cmdq_write_intr(inst->core, inst->packet, (cnt == batch_size - 1)); + if (rc) + goto unlock; + + cnt++; + } +unlock: + core_unlock(core, __func__); + if (rc) + i_vpr_e(inst, "%s: queue super buffer failed: %d\n", __func__, rc); + + return rc; +} + int venus_hfi_queue_buffer(struct msm_vidc_inst *inst, struct msm_vidc_buffer *buffer, struct msm_vidc_buffer *metabuf) { diff --git a/driver/vidc/src/venus_hfi_response.c b/driver/vidc/src/venus_hfi_response.c index ab63612e0d..86f0638813 100644 --- a/driver/vidc/src/venus_hfi_response.c +++ b/driver/vidc/src/venus_hfi_response.c @@ -440,8 +440,15 @@ static int handle_input_buffer(struct msm_vidc_inst *inst, int rc = 0; struct msm_vidc_buffers *buffers; struct msm_vidc_buffer *buf; + struct msm_vidc_core *core; + u32 frame_size, batch_size; bool found; + if (!inst || !buffer || !inst->capabilities || !inst->core) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + core = inst->core; buffers = msm_vidc_get_buffers(inst, MSM_VIDC_BUF_INPUT, __func__); if (!buffers) return -EINVAL; @@ -458,6 +465,16 @@ static int handle_input_buffer(struct msm_vidc_inst *inst, __func__, buffer->index, buffer->base_address); return -EINVAL; } + + frame_size = call_session_op(core, buffer_size, inst, MSM_VIDC_BUF_INPUT); + batch_size = inst->capabilities->cap[SUPER_FRAME].value; + /* attach dequeued flag for, only last frame in the batch */ + if (msm_vidc_is_super_buffer(inst) && + buffer->addr_offset / frame_size < batch_size - 1) { + i_vpr_h(inst, "%s: superframe last buffer not reached: %u, %u, %u\n", + __func__, buffer->addr_offset, frame_size, batch_size); + return 0; + } buf->data_offset = buffer->data_offset; buf->data_size = buffer->data_size; buf->attr &= ~MSM_VIDC_ATTR_QUEUED; @@ -549,8 +566,15 @@ static int handle_input_metadata_buffer(struct msm_vidc_inst *inst, int rc = 0; struct msm_vidc_buffers *buffers; struct msm_vidc_buffer *buf; + struct msm_vidc_core *core; + u32 frame_size, batch_size; bool found; + if (!inst || !buffer || !inst->capabilities || !inst->core) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + core = inst->core; buffers = msm_vidc_get_buffers(inst, MSM_VIDC_BUF_INPUT_META, __func__); if (!buffers) return -EINVAL; @@ -567,6 +591,15 @@ static int handle_input_metadata_buffer(struct msm_vidc_inst *inst, __func__, buffer->index, buffer->base_address); return -EINVAL; } + frame_size = call_session_op(core, buffer_size, inst, MSM_VIDC_BUF_INPUT_META); + batch_size = inst->capabilities->cap[SUPER_FRAME].value; + /* attach dequeued flag for, only last frame in the batch */ + if (msm_vidc_is_super_buffer(inst) && + buffer->addr_offset / frame_size < batch_size - 1) { + i_vpr_h(inst, "%s: superframe last buffer not reached: %u, %u, %u\n", + __func__, buffer->addr_offset, frame_size, batch_size); + return 0; + } buf->data_size = buffer->data_size; buf->attr &= ~MSM_VIDC_ATTR_QUEUED; buf->attr |= MSM_VIDC_ATTR_DEQUEUED; diff --git a/include/uapi/vidc/media/v4l2_vidc_extensions.h b/include/uapi/vidc/media/v4l2_vidc_extensions.h index be3c7293e0..4f176b3ee0 100644 --- a/include/uapi/vidc/media/v4l2_vidc_extensions.h +++ b/include/uapi/vidc/media/v4l2_vidc_extensions.h @@ -116,6 +116,9 @@ enum v4l2_mpeg_vidc_blur_types { #define V4L2_CID_MPEG_VIDC_HEVC_P_FRAME_MAX_QP \ (V4L2_CID_MPEG_VIDC_BASE + 0x27) +/* Encoder Super frame control */ +#define V4L2_CID_MPEG_VIDC_SUPERFRAME (V4L2_CID_MPEG_VIDC_BASE + 0x28) + enum v4l2_mpeg_vidc_metapayload_header_flags { METADATA_FLAGS_NONE = 0, METADATA_FLAGS_TOP_FIELD = (1 << 0),