From 5e31da536d759ae38d592edc7ee452d162e8a8df Mon Sep 17 00:00:00 2001 From: Maheshwar Ajja Date: Mon, 13 May 2019 13:04:13 -0700 Subject: [PATCH] msm: vidc: add superframe encode support In HFR (High Frame Rate) encoding usecases client sends superframe (single input multiple frames). So add support for encoding superframes. Change-Id: I6f726d0ccf5b4b831e517efd3587d822da7eaae5 Signed-off-by: Maheshwar Ajja --- msm/vidc/hfi_packetization.c | 1 + msm/vidc/msm_vdec.c | 9 ++ msm/vidc/msm_venc.c | 16 +++ msm/vidc/msm_vidc_buffer_calculations.c | 18 ++++ msm/vidc/msm_vidc_clocks.c | 8 +- msm/vidc/msm_vidc_clocks.h | 5 + msm/vidc/msm_vidc_common.c | 125 +++++++++++++++++++++++- msm/vidc/msm_vidc_common.h | 10 ++ msm/vidc/msm_vidc_internal.h | 3 + 9 files changed, 192 insertions(+), 3 deletions(-) diff --git a/msm/vidc/hfi_packetization.c b/msm/vidc/hfi_packetization.c index 036a0c4c5d97..71efb4c7412c 100644 --- a/msm/vidc/hfi_packetization.c +++ b/msm/vidc/hfi_packetization.c @@ -876,6 +876,7 @@ static struct hfi_packetization_ops hfi_default = { .session_get_buf_req = create_pkt_cmd_session_get_buf_req, .session_flush = create_pkt_cmd_session_flush, .session_set_property = create_pkt_cmd_session_set_property, + .session_sync_process = create_pkt_cmd_session_sync_process, }; struct hfi_packetization_ops *hfi_get_pkt_ops_handle( diff --git a/msm/vidc/msm_vdec.c b/msm/vidc/msm_vdec.c index eba234ec1462..aad7adcba35a 100644 --- a/msm/vidc/msm_vdec.c +++ b/msm/vidc/msm_vdec.c @@ -397,6 +397,15 @@ static struct msm_vidc_ctrl msm_vdec_ctrls[] = { .default_value = V4L2_MPEG_MSM_VIDC_DISABLE, .step = 1, }, + { + .id = V4L2_CID_MPEG_VIDC_SUPERFRAME, + .name = "Superframe", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 0, + .default_value = 0, + .step = 1, + }, }; #define NUM_CTRLS ARRAY_SIZE(msm_vdec_ctrls) diff --git a/msm/vidc/msm_venc.c b/msm/vidc/msm_venc.c index 6b3e29f16859..10952e4db38b 100644 --- a/msm/vidc/msm_venc.c +++ b/msm/vidc/msm_venc.c @@ -948,6 +948,15 @@ static struct msm_vidc_ctrl msm_venc_ctrls[] = { .default_value = 0, .step = 500, }, + { + .id = V4L2_CID_MPEG_VIDC_SUPERFRAME, + .name = "Superframe", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = VIDC_SUPERFRAME_MAX, + .default_value = 0, + .step = 1, + }, }; #define NUM_CTRLS ARRAY_SIZE(msm_venc_ctrls) @@ -1798,6 +1807,7 @@ int msm_venc_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) case V4L2_CID_MPEG_VIDC_VENC_RC_TIMESTAMP_DISABLE: case V4L2_CID_MPEG_VIDEO_VBV_DELAY: case V4L2_CID_MPEG_VIDC_VENC_BITRATE_SAVINGS: + case V4L2_CID_MPEG_VIDC_SUPERFRAME: dprintk(VIDC_HIGH, "Control set: ID : %x Val : %d\n", ctrl->id, ctrl->val); break; @@ -2166,6 +2176,12 @@ void msm_venc_decide_bframe(struct msm_vidc_inst *inst) goto disable_bframe; } } + + /* do not enable bframe if superframe is enabled */ + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDC_SUPERFRAME); + if (ctrl->val) + goto disable_bframe; + dprintk(VIDC_HIGH, "Bframe can be enabled!\n"); return; diff --git a/msm/vidc/msm_vidc_buffer_calculations.c b/msm/vidc/msm_vidc_buffer_calculations.c index c75a52291fe7..5a9e9f605c03 100644 --- a/msm/vidc/msm_vidc_buffer_calculations.c +++ b/msm/vidc/msm_vidc_buffer_calculations.c @@ -18,6 +18,10 @@ /* extra o/p buffers in case of decoder dcvs */ #define DCVS_DEC_EXTRA_OUTPUT_BUFFERS 4 +/* extra buffers for encoder HFR usecase */ +#define HFR_EXTRA_INPUT_BUFFERS 4 +#define HFR_EXTRA_OUTPUT_BUFFERS 12 + #define HFI_COLOR_FORMAT_YUV420_NV12_UBWC_Y_TILE_WIDTH 32 #define HFI_COLOR_FORMAT_YUV420_NV12_UBWC_Y_TILE_HEIGHT 8 #define HFI_COLOR_FORMAT_YUV420_NV12_UBWC_UV_TILE_WIDTH 16 @@ -724,6 +728,7 @@ int msm_vidc_get_extra_buff_count(struct msm_vidc_inst *inst, enum hal_buffer buffer_type) { unsigned int count = 0; + struct v4l2_format *f; if (!inst || !inst->core) { dprintk(VIDC_ERR, "%s Invalid args\n", __func__); @@ -758,6 +763,19 @@ int msm_vidc_get_extra_buff_count(struct msm_vidc_inst *inst, count = inst->batch.size; } + /* increase both input and output counts for HFR/HSR encode case */ + f = &inst->fmts[INPUT_PORT].v4l2_fmt; + if (is_encode_session(inst) && msm_vidc_get_fps(inst) >= 120 && + !res_is_greater_than(f->fmt.pix_mp.width, + f->fmt.pix_mp.height, 1920, 1088)) { + if (buffer_type == HAL_BUFFER_INPUT && + count < HFR_EXTRA_INPUT_BUFFERS) + count = HFR_EXTRA_INPUT_BUFFERS; + if (buffer_type == HAL_BUFFER_OUTPUT && + count < HFR_EXTRA_OUTPUT_BUFFERS) + count = HFR_EXTRA_OUTPUT_BUFFERS; + } + return count; } diff --git a/msm/vidc/msm_vidc_clocks.c b/msm/vidc/msm_vidc_clocks.c index 08328f16ff87..cfb6e886906c 100644 --- a/msm/vidc/msm_vidc_clocks.c +++ b/msm/vidc/msm_vidc_clocks.c @@ -132,7 +132,7 @@ int msm_vidc_get_mbs_per_frame(struct msm_vidc_inst *inst) return NUM_MBS_PER_FRAME(height, width); } -static int msm_vidc_get_fps(struct msm_vidc_inst *inst) +int msm_vidc_get_fps(struct msm_vidc_inst *inst) { int fps; @@ -148,10 +148,16 @@ static int msm_vidc_get_fps(struct msm_vidc_inst *inst) void update_recon_stats(struct msm_vidc_inst *inst, struct recon_stats_type *recon_stats) { + struct v4l2_ctrl *ctrl; struct recon_buf *binfo; u32 CR = 0, CF = 0; u32 frame_size; + /* do not consider recon stats in case of superframe */ + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDC_SUPERFRAME); + if (ctrl->val) + return; + CR = get_ubwc_compression_ratio(recon_stats->ubwc_stats_info); frame_size = (msm_vidc_get_mbs_per_frame(inst) / (32 * 8) * 3) / 2; diff --git a/msm/vidc/msm_vidc_clocks.h b/msm/vidc/msm_vidc_clocks.h index effbe7c75819..b5e5a92c7dd3 100644 --- a/msm/vidc/msm_vidc_clocks.h +++ b/msm/vidc/msm_vidc_clocks.h @@ -14,6 +14,7 @@ int msm_dcvs_try_enable(struct msm_vidc_inst *inst); bool res_is_less_than(u32 width, u32 height, u32 ref_width, u32 ref_height); bool res_is_greater_than(u32 width, u32 height, u32 ref_width, u32 ref_height); int msm_vidc_get_mbs_per_frame(struct msm_vidc_inst *inst); +int msm_vidc_get_fps(struct msm_vidc_inst *inst); int msm_comm_scale_clocks_and_bus(struct msm_vidc_inst *inst); int msm_comm_init_clocks_and_bus_data(struct msm_vidc_inst *inst); void msm_comm_free_freq_table(struct msm_vidc_inst *inst); @@ -32,4 +33,8 @@ void msm_comm_update_input_cr(struct msm_vidc_inst *inst, u32 index, void update_recon_stats(struct msm_vidc_inst *inst, struct recon_stats_type *recon_stats); void msm_vidc_init_core_clk_ops(struct msm_vidc_core *core); +bool res_is_greater_than(u32 width, u32 height, + u32 ref_width, u32 ref_height); +bool res_is_less_than(u32 width, u32 height, + u32 ref_width, u32 ref_height); #endif diff --git a/msm/vidc/msm_vidc_common.c b/msm/vidc/msm_vidc_common.c index 2f30bd36485f..2ed844988048 100644 --- a/msm/vidc/msm_vidc_common.c +++ b/msm/vidc/msm_vidc_common.c @@ -2436,6 +2436,7 @@ static void handle_ebd(enum hal_command_response cmd, void *data) struct vidc_hal_ebd *empty_buf_done; u32 planes[VIDEO_MAX_PLANES] = {0}; struct v4l2_format *f; + struct v4l2_ctrl *ctrl; if (!response) { dprintk(VIDC_ERR, "Invalid response from vidc_hal\n"); @@ -2468,9 +2469,23 @@ static void handle_ebd(enum hal_command_response cmd, void *data) __func__, planes[0], planes[1]); goto exit; } - mbuf->flags &= ~MSM_VIDC_FLAG_QUEUED; vb = &mbuf->vvb.vb2_buf; + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDC_SUPERFRAME); + if (ctrl->val && empty_buf_done->offset + + empty_buf_done->filled_len < vb->planes[0].length) { + dprintk(VIDC_HIGH, + "%s: %x : addr (%#x): offset (%d) + filled_len (%d) < length (%d)\n", + __func__, hash32_ptr(inst->session), + empty_buf_done->packet_buffer, + empty_buf_done->offset, + empty_buf_done->filled_len, + vb->planes[0].length); + kref_put_mbuf(mbuf); + goto exit; + } + + mbuf->flags &= ~MSM_VIDC_FLAG_QUEUED; vb->planes[0].bytesused = response->input_done.filled_len; if (vb->planes[0].bytesused > vb->planes[0].length) dprintk(VIDC_LOW, "bytesused overflow length\n"); @@ -4315,6 +4330,98 @@ err_bad_input: return rc; } +static int msm_comm_qbuf_superframe_to_hfi(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *mbuf) +{ + int rc, i; + struct hfi_device *hdev; + struct v4l2_format *f; + struct v4l2_ctrl *ctrl; + u64 ts_delta_us; + struct vidc_frame_data *frames; + u32 num_etbs, superframe_count, frame_size, hfi_fmt; + + if (!inst || !inst->core || !inst->core->device || !mbuf) { + dprintk(VIDC_ERR, "%s: Invalid arguments\n", __func__); + return -EINVAL; + } + hdev = inst->core->device; + frames = inst->superframe_data; + + if (!is_input_buffer(mbuf)) + return msm_comm_qbuf_to_hfi(inst, mbuf); + + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDC_SUPERFRAME); + superframe_count = ctrl->val; + if (superframe_count > VIDC_SUPERFRAME_MAX) { + dprintk(VIDC_ERR, "%s: wrong superframe count %d, max %d\n", + __func__, superframe_count, VIDC_SUPERFRAME_MAX); + return -EINVAL; + } + + ts_delta_us = 1000000 / (inst->clk_data.frame_rate >> 16); + f = &inst->fmts[INPUT_PORT].v4l2_fmt; + hfi_fmt = msm_comm_convert_color_fmt(f->fmt.pix_mp.pixelformat); + frame_size = VENUS_BUFFER_SIZE(hfi_fmt, f->fmt.pix_mp.width, + f->fmt.pix_mp.height); + if (frame_size * superframe_count != + mbuf->vvb.vb2_buf.planes[0].length) { + dprintk(VIDC_ERR, + "%s: %#x : invalid superframe length, pxlfmt %#x wxh %dx%d framesize %d count %d length %d\n", + __func__, hash32_ptr(inst->session), + f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.width, + f->fmt.pix_mp.height, frame_size, superframe_count, + mbuf->vvb.vb2_buf.planes[0].length); + return -EINVAL; + } + + num_etbs = 0; + populate_frame_data(&frames[0], mbuf, inst); + /* prepare superframe buffers */ + frames[0].filled_len = frame_size; + /* + * superframe logic updates extradata and eos flags only, so + * ensure no other flags are populated in populate_frame_data() + */ + frames[0].flags &= ~HAL_BUFFERFLAG_EXTRADATA; + frames[0].flags &= ~HAL_BUFFERFLAG_EOS; + if (frames[0].flags) + dprintk(VIDC_ERR, "%s: invalid flags %#x\n", + __func__, frames[0].flags); + frames[0].flags = 0; + + for (i = 0; i < superframe_count; i++) { + if (i) + memcpy(&frames[i], &frames[0], + sizeof(struct vidc_frame_data)); + frames[i].offset += i * frame_size; + frames[i].timestamp += i * ts_delta_us; + if (!i) { + /* first frame */ + if (frames[i].extradata_addr) + frames[i].flags |= HAL_BUFFERFLAG_EXTRADATA; + } else if (i == superframe_count - 1) { + /* last frame */ + if (mbuf->vvb.flags & V4L2_BUF_FLAG_EOS) + frames[i].flags |= HAL_BUFFERFLAG_EOS; + } + num_etbs++; + } + + rc = call_hfi_op(hdev, session_process_batch, inst->session, + num_etbs, frames, 0, NULL); + if (rc) { + dprintk(VIDC_ERR, "%s: Failed to qbuf: %d\n", __func__, rc); + return rc; + } + /* update mbuf flags */ + mbuf->flags |= MSM_VIDC_FLAG_QUEUED; + mbuf->flags &= ~MSM_VIDC_FLAG_DEFERRED; + msm_vidc_debugfs_update(inst, MSM_VIDC_DEBUGFS_EVENT_ETB); + + return 0; +} + static int msm_comm_qbuf_in_rbr(struct msm_vidc_inst *inst, struct msm_vidc_buffer *mbuf) { @@ -4345,6 +4452,7 @@ static int msm_comm_qbuf_in_rbr(struct msm_vidc_inst *inst, int msm_comm_qbuf(struct msm_vidc_inst *inst, struct msm_vidc_buffer *mbuf) { int rc = 0; + struct v4l2_ctrl *ctrl; if (!inst || !mbuf) { dprintk(VIDC_ERR, "%s: Invalid arguments\n", __func__); @@ -4371,7 +4479,11 @@ int msm_comm_qbuf(struct msm_vidc_inst *inst, struct msm_vidc_buffer *mbuf) dprintk(VIDC_ERR, "%s: scale clocks failed\n", __func__); print_vidc_buffer(VIDC_HIGH, "qbuf", inst, mbuf); - rc = msm_comm_qbuf_to_hfi(inst, mbuf); + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDC_SUPERFRAME); + if (ctrl->val) + rc = msm_comm_qbuf_superframe_to_hfi(inst, mbuf); + else + rc = msm_comm_qbuf_to_hfi(inst, mbuf); if (rc) dprintk(VIDC_ERR, "%s: Failed qbuf to hfi: %d\n", __func__, rc); @@ -4975,14 +5087,23 @@ int msm_comm_set_buffer_count(struct msm_vidc_inst *inst, int host_count, int act_count, enum hal_buffer type) { int rc = 0; + struct v4l2_ctrl *ctrl; struct hfi_device *hdev; struct hfi_buffer_count_actual buf_count; + if (!inst || !inst->core || !inst->core->device) { + dprintk(VIDC_ERR, "%s invalid parameters\n", __func__); + return -EINVAL; + } hdev = inst->core->device; buf_count.buffer_type = get_hfi_buffer(type); buf_count.buffer_count_actual = act_count; buf_count.buffer_count_min_host = host_count; + /* set total superframe buffers count */ + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDC_SUPERFRAME); + if (ctrl->val) + buf_count.buffer_count_actual = act_count * ctrl->val; dprintk(VIDC_HIGH, "%s: %x : hal_buffer %d min_host %d actual %d\n", __func__, hash32_ptr(inst->session), type, host_count, act_count); diff --git a/msm/vidc/msm_vidc_common.h b/msm/vidc/msm_vidc_common.h index 7e18a095936c..7d20fd15ae91 100644 --- a/msm/vidc/msm_vidc_common.h +++ b/msm/vidc/msm_vidc_common.h @@ -119,6 +119,16 @@ static inline bool in_port_reconfig(struct msm_vidc_inst *inst) return inst->in_reconfig && inst->bufq[INPUT_PORT].vb2_bufq.streaming; } +static inline bool is_input_buffer(struct msm_vidc_buffer *mbuf) +{ + return mbuf->vvb.vb2_buf.type == INPUT_MPLANE; +} + +static inline bool is_output_buffer(struct msm_vidc_buffer *mbuf) +{ + return mbuf->vvb.vb2_buf.type == OUTPUT_MPLANE; +} + static inline int msm_comm_g_ctrl(struct msm_vidc_inst *inst, struct v4l2_control *ctrl) { diff --git a/msm/vidc/msm_vidc_internal.h b/msm/vidc/msm_vidc_internal.h index 6565760a4c12..1258b4c999e6 100644 --- a/msm/vidc/msm_vidc_internal.h +++ b/msm/vidc/msm_vidc_internal.h @@ -51,6 +51,8 @@ /* Maintains the number of FTB's between each FBD over a window */ #define DCVS_FTB_WINDOW 16 +/* Superframe can have maximum of 32 frames */ +#define VIDC_SUPERFRAME_MAX 32 #define V4L2_EVENT_VIDC_BASE 10 #define INPUT_MPLANE V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE @@ -477,6 +479,7 @@ struct msm_vidc_inst { struct msm_vidc_list etb_data; struct msm_vidc_list fbd_data; struct buffer_requirements buff_req; + struct vidc_frame_data superframe_data[VIDC_SUPERFRAME_MAX]; struct v4l2_ctrl_handler ctrl_handler; struct completion completions[SESSION_MSG_END - SESSION_MSG_START + 1]; struct v4l2_ctrl **cluster;