diff --git a/driver/platform/pineapple/src/msm_vidc_pineapple.c b/driver/platform/pineapple/src/msm_vidc_pineapple.c index c07e143403..451c303afa 100644 --- a/driver/platform/pineapple/src/msm_vidc_pineapple.c +++ b/driver/platform/pineapple/src/msm_vidc_pineapple.c @@ -21,6 +21,7 @@ #include "msm_vidc_iris33.h" #include "hfi_property.h" #include "hfi_command.h" +#include "venus_hfi.h" #define DEFAULT_VIDEO_CONCEAL_COLOR_BLACK 0x8020010 #define MAX_BASE_LAYER_PRIORITY_ID 63 @@ -325,6 +326,64 @@ static struct msm_platform_core_capability core_data_pineapple[] = { {SUPPORTS_REQUESTS, 1}, }; +static int msm_vidc_set_ring_buffer_count_pineapple(void *instance, + enum msm_vidc_inst_capability_type cap_id) +{ + int rc = 0; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *) instance; + struct v4l2_format *output_fmt, *input_fmt; + struct msm_vidc_core* core; + u32 count = 0, data_size = 0, pixel_count = 0, fps = 0; + + if (!inst || !inst->capabilities) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + core = inst->core; + output_fmt = &inst->fmts[OUTPUT_PORT]; + input_fmt = &inst->fmts[INPUT_PORT]; + + fps = inst->capabilities->cap[FRAME_RATE].value >> 16; + pixel_count = output_fmt->fmt.pix_mp.width * + output_fmt->fmt.pix_mp.height; + + /* check if current session supports ring buffer enablement */ + if (!(pixel_count >= 7680 * 4320 && fps >= 30) && + !(pixel_count >= 3840 * 2160 && fps >= 120) && + !(pixel_count >= 1920 * 1080 && fps >= 480) && + !(pixel_count >= 1280 * 720 && fps >= 960)) { + i_vpr_h(inst, + "%s: session %ux%u@%u fps does not support ring buffer\n", + __func__, output_fmt->fmt.pix_mp.width, + output_fmt->fmt.pix_mp.height, fps); + inst->capabilities->cap[cap_id].value = 0; + } else { + data_size = input_fmt->fmt.pix_mp.plane_fmt[0].sizeimage; + rc = call_session_op(core, ring_buf_count, inst, data_size); + if (rc) { + i_vpr_e(inst, "%s: failed to calculate ring buf count\n", + __func__); + /* ignore error */ + rc = 0; + inst->capabilities->cap[cap_id].value = 0; + } + } + + count = inst->capabilities->cap[cap_id].value; + i_vpr_h(inst, "%s: ring buffer count: %u\n", __func__, count); + rc = venus_hfi_session_property(inst, + HFI_PROP_ENC_RING_BIN_BUF, + HFI_HOST_FLAGS_NONE, + HFI_PORT_BITSTREAM, + HFI_PAYLOAD_U32, + &count, + sizeof(u32)); + if (rc) + return rc; + + return rc; +} + static struct msm_platform_inst_capability instance_cap_data_pineapple[] = { /* {cap, domain, codec, * min, max, step_or_mask, value, @@ -525,6 +584,9 @@ static struct msm_platform_inst_capability instance_cap_data_pineapple[] = { {MB_CYCLES_FW_VPP, DEC, CODECS_ALL, 66234, 66234, 1, 66234}, + {ENC_RING_BUFFER_COUNT, ENC, CODECS_ALL, + 0, MAX_ENC_RING_BUF_COUNT, 1, 0}, + {CLIENT_ID, ENC|DEC, CODECS_ALL, INVALID_CLIENT_ID, INT_MAX, 1, INVALID_CLIENT_ID, V4L2_CID_MPEG_VIDC_CLIENT_ID}, @@ -1988,6 +2050,11 @@ static struct msm_platform_inst_cap_dependency instance_cap_dependency_data_pine {0}, msm_vidc_adjust_dec_operating_rate}, + {ENC_RING_BUFFER_COUNT, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_ring_buffer_count_pineapple}, + {SECURE_MODE, ENC|DEC, H264|HEVC|VP9|AV1, {0}, NULL, diff --git a/driver/platform/pineapple/src/pineapple.c b/driver/platform/pineapple/src/pineapple.c index 3448cde2a6..97987933c1 100644 --- a/driver/platform/pineapple/src/pineapple.c +++ b/driver/platform/pineapple/src/pineapple.c @@ -12,6 +12,7 @@ #include "msm_vidc_iris33.h" #include "hfi_property.h" #include "hfi_command.h" +#include "venus_hfi.h" #define DEFAULT_VIDEO_CONCEAL_COLOR_BLACK 0x8020010 #define MAX_BASE_LAYER_PRIORITY_ID 63 @@ -222,6 +223,64 @@ static struct msm_platform_core_capability core_data_pineapple[] = { {SUPPORTS_REQUESTS, 0}, }; +static int msm_vidc_set_ring_buffer_count_pineapple(void *instance, + enum msm_vidc_inst_capability_type cap_id) +{ + int rc = 0; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *) instance; + struct v4l2_format *output_fmt, *input_fmt; + struct msm_vidc_core* core; + u32 count = 0, data_size = 0, pixel_count = 0, fps = 0; + + if (!inst || !inst->capabilities) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + core = inst->core; + output_fmt = &inst->fmts[OUTPUT_PORT]; + input_fmt = &inst->fmts[INPUT_PORT]; + + fps = inst->capabilities->cap[FRAME_RATE].value >> 16; + pixel_count = output_fmt->fmt.pix_mp.width * + output_fmt->fmt.pix_mp.height; + + /* check if current session supports ring buffer enablement */ + if (!(pixel_count >= 7680 * 4320 && fps >= 30) && + !(pixel_count >= 3840 * 2160 && fps >= 120) && + !(pixel_count >= 1920 * 1080 && fps >= 480) && + !(pixel_count >= 1280 * 720 && fps >= 960)) { + i_vpr_h(inst, + "%s: session %ux%u@%u fps does not support ring buffer\n", + __func__, output_fmt->fmt.pix_mp.width, + output_fmt->fmt.pix_mp.height, fps); + inst->capabilities->cap[cap_id].value = 0; + } else { + data_size = input_fmt->fmt.pix_mp.plane_fmt[0].sizeimage; + rc = call_session_op(core, ring_buf_count, inst, data_size); + if (rc) { + i_vpr_e(inst, "%s: failed to calculate ring buf count\n", + __func__); + /* ignore error */ + rc = 0; + inst->capabilities->cap[cap_id].value = 0; + } + } + + count = inst->capabilities->cap[cap_id].value; + i_vpr_h(inst, "%s: ring buffer count: %u\n", __func__, count); + rc = venus_hfi_session_property(inst, + HFI_PROP_ENC_RING_BIN_BUF, + HFI_HOST_FLAGS_NONE, + HFI_PORT_BITSTREAM, + HFI_PAYLOAD_U32, + &count, + sizeof(u32)); + if (rc) + return rc; + + return rc; +} + static struct msm_platform_inst_capability instance_cap_data_pineapple[] = { /* {cap, domain, codec, * min, max, step_or_mask, value, @@ -340,6 +399,9 @@ static struct msm_platform_inst_capability instance_cap_data_pineapple[] = { {MB_CYCLES_FW_VPP, DEC, CODECS_ALL, 66234, 66234, 1, 66234}, + {ENC_RING_BUFFER_COUNT, ENC, CODECS_ALL, + 0, MAX_ENC_RING_BUF_COUNT, 1, 0}, + {CLIENT_ID, ENC|DEC, CODECS_ALL, INVALID_CLIENT_ID, INT_MAX, 1, INVALID_CLIENT_ID, 0}, @@ -1255,6 +1317,11 @@ static struct msm_platform_inst_cap_dependency instance_cap_dependency_data_pine NULL, msm_vidc_set_q16}, + {ENC_RING_BUFFER_COUNT, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_ring_buffer_count_pineapple}, + {HFLIP, ENC, CODECS_ALL, {0}, NULL, diff --git a/driver/variant/iris33/inc/msm_vidc_power_iris33.h b/driver/variant/iris33/inc/msm_vidc_power_iris33.h index 1047f4cfa3..cff964540b 100644 --- a/driver/variant/iris33/inc/msm_vidc_power_iris33.h +++ b/driver/variant/iris33/inc/msm_vidc_power_iris33.h @@ -12,6 +12,7 @@ #define ENABLE_LEGACY_POWER_CALCULATIONS 1 +int msm_vidc_ring_buf_count_iris33(struct msm_vidc_inst *inst, u32 data_size); u64 msm_vidc_calc_freq_iris33(struct msm_vidc_inst* inst, u32 data_size); int msm_vidc_calc_bw_iris33(struct msm_vidc_inst* inst, struct vidc_bus_vote_data* vote_data); diff --git a/driver/variant/iris33/src/msm_vidc_buffer_iris33.c b/driver/variant/iris33/src/msm_vidc_buffer_iris33.c index 8c298be647..7086b04d33 100644 --- a/driver/variant/iris33/src/msm_vidc_buffer_iris33.c +++ b/driver/variant/iris33/src/msm_vidc_buffer_iris33.c @@ -338,7 +338,7 @@ static u32 msm_vidc_encoder_bin_size_iris33(struct msm_vidc_inst *inst) { struct msm_vidc_core *core; u32 size = 0; - u32 width, height, num_vpp_pipes, stage, profile; + u32 width, height, num_vpp_pipes, stage, profile, ring_buf_count; struct v4l2_format *f; if (!inst || !inst->core || !inst->capabilities) { @@ -356,13 +356,14 @@ static u32 msm_vidc_encoder_bin_size_iris33(struct msm_vidc_inst *inst) width = f->fmt.pix_mp.width; height = f->fmt.pix_mp.height; profile = inst->capabilities->cap[PROFILE].value; + ring_buf_count = inst->capabilities->cap[ENC_RING_BUFFER_COUNT].value; if (inst->codec == MSM_VIDC_H264) HFI_BUFFER_BIN_H264E(size, inst->hfi_rc_type, width, - height, stage, num_vpp_pipes, profile); + height, stage, num_vpp_pipes, profile, ring_buf_count); else if (inst->codec == MSM_VIDC_HEVC || inst->codec == MSM_VIDC_HEIC) HFI_BUFFER_BIN_H265E(size, inst->hfi_rc_type, width, - height, stage, num_vpp_pipes, profile); + height, stage, num_vpp_pipes, profile, ring_buf_count); i_vpr_l(inst, "%s: size %d\n", __func__, size); return size; diff --git a/driver/variant/iris33/src/msm_vidc_iris33.c b/driver/variant/iris33/src/msm_vidc_iris33.c index c6d4d466f0..4281c42550 100644 --- a/driver/variant/iris33/src/msm_vidc_iris33.c +++ b/driver/variant/iris33/src/msm_vidc_iris33.c @@ -1231,6 +1231,7 @@ static struct msm_vidc_session_ops msm_session_ops = { .buffer_size = msm_buffer_size_iris33, .min_count = msm_buffer_min_count_iris33, .extra_count = msm_buffer_extra_count_iris33, + .ring_buf_count = msm_vidc_ring_buf_count_iris33, .calc_freq = msm_vidc_calc_freq_iris33, .calc_bw = msm_vidc_calc_bw_iris33, .decide_work_route = msm_vidc_decide_work_route_iris33, diff --git a/driver/variant/iris33/src/msm_vidc_power_iris33.c b/driver/variant/iris33/src/msm_vidc_power_iris33.c index 77b6516f7c..3760dc4a77 100644 --- a/driver/variant/iris33/src/msm_vidc_power_iris33.c +++ b/driver/variant/iris33/src/msm_vidc_power_iris33.c @@ -12,6 +12,8 @@ #include "perf_static_model.h" #include "msm_vidc_power.h" +#define VPP_MIN_FREQ_MARGIN_PERCENT 5 /* to be tuned */ + static u64 __calculate_decoder(struct vidc_bus_vote_data *d); static u64 __calculate_encoder(struct vidc_bus_vote_data *d); static u64 __calculate(struct msm_vidc_inst* inst, struct vidc_bus_vote_data *d); @@ -284,6 +286,49 @@ static int msm_vidc_init_codec_input_bus(struct msm_vidc_inst *inst, struct vidc return 0; } +static bool is_vpp_cycles_close_to_freq_corner(struct msm_vidc_core *core, + u64 vpp_min_freq) +{ + u64 margin_freq = 0; + u64 closest_freq_upper_corner = 0; + u32 margin_percent = 0; + int i = 0; + + if (!core || !core->resource || !core->resource->freq_set.freq_tbl || + !core->resource->freq_set.count) { + d_vpr_e("%s: invalid params\n", __func__); + return false; + } + + vpp_min_freq = vpp_min_freq * 1000000; /* convert to hz */ + + closest_freq_upper_corner = + core->resource->freq_set.freq_tbl[0].freq; + + if (vpp_min_freq > closest_freq_upper_corner) + return false; + + /* get the closest freq corner for vpp_min_freq */ + for (i = 0; i < core->resource->freq_set.count; i++) { + if (vpp_min_freq <= + core->resource->freq_set.freq_tbl[i].freq) { + closest_freq_upper_corner = + core->resource->freq_set.freq_tbl[i].freq; + } else { + break; + } + } + + margin_freq = closest_freq_upper_corner - vpp_min_freq; + margin_percent = div_u64((margin_freq * 100), closest_freq_upper_corner); + + /* check if margin is less than cutoff */ + if (margin_percent < VPP_MIN_FREQ_MARGIN_PERCENT) + return true; + + return false; +} + static u64 msm_vidc_calc_freq_iris33_new(struct msm_vidc_inst *inst, u32 data_size) { u64 freq = 0; @@ -311,6 +356,25 @@ static u64 msm_vidc_calc_freq_iris33_new(struct msm_vidc_inst *inst, u32 data_si ret = msm_vidc_calculate_frequency(codec_input, &codec_output); if (ret) return freq; + + if (inst->domain == MSM_VIDC_ENCODER) { + if (!inst->capabilities->cap[ENC_RING_BUFFER_COUNT].value && + is_vpp_cycles_close_to_freq_corner(core, + codec_output.vpp_min_freq)) { + /* + * if ring buffer not enabled and required vpp cycles + * is too close to the frequency corner then increase + * the vpp cycles by VPP_MIN_FREQ_MARGIN_PERCENT + */ + codec_output.vpp_min_freq += div_u64( + codec_output.vpp_min_freq * + VPP_MIN_FREQ_MARGIN_PERCENT, 100); + codec_output.hw_min_freq = max( + codec_output.hw_min_freq, + codec_output.vpp_min_freq); + } + } + freq = codec_output.hw_min_freq * 1000000; /* Convert to Hz */ i_vpr_p(inst, "%s: filled len %d, required freq %llu, fps %u, mbpf %u\n", @@ -1173,4 +1237,47 @@ int msm_vidc_calc_bw_iris33(struct msm_vidc_inst *inst, value = msm_vidc_calc_bw_iris33_new(inst, vidc_data); return value; -} \ No newline at end of file +} + +int msm_vidc_ring_buf_count_iris33(struct msm_vidc_inst *inst, u32 data_size) +{ + int rc = 0; + struct msm_vidc_core *core; + struct api_calculation_input codec_input; + struct api_calculation_freq_output codec_output; + + if (!inst || !inst->core || !inst->capabilities) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + core = inst->core; + + if (!core->resource || !core->resource->freq_set.freq_tbl || + !core->resource->freq_set.count) { + i_vpr_e(inst, "%s: invalid frequency table\n", __func__); + return -EINVAL; + } + + if (ENABLE_LEGACY_POWER_CALCULATIONS) + return 0; + + memset(&codec_input, 0, sizeof(struct api_calculation_input)); + memset(&codec_output, 0, sizeof(struct api_calculation_freq_output)); + rc = msm_vidc_init_codec_input_freq(inst, data_size, &codec_input); + if (rc) + return rc; + rc = msm_vidc_calculate_frequency(codec_input, &codec_output); + if (rc) + return rc; + + /* check if vpp_min_freq is exceeding closest freq corner margin */ + if (is_vpp_cycles_close_to_freq_corner(core, + codec_output.vpp_min_freq)) + /* enables ring buffer */ + inst->capabilities->cap[ENC_RING_BUFFER_COUNT].value = + MAX_ENC_RING_BUF_COUNT; + else + inst->capabilities->cap[ENC_RING_BUFFER_COUNT].value = 0; + + return 0; +} diff --git a/driver/vidc/inc/msm_vidc_inst.h b/driver/vidc/inc/msm_vidc_inst.h index 139b528d0d..7c288e5e78 100644 --- a/driver/vidc/inc/msm_vidc_inst.h +++ b/driver/vidc/inc/msm_vidc_inst.h @@ -28,6 +28,7 @@ struct msm_vidc_session_ops { int (*buffer_size)(struct msm_vidc_inst *inst, enum msm_vidc_buffer_type type); int (*min_count)(struct msm_vidc_inst *inst, enum msm_vidc_buffer_type type); int (*extra_count)(struct msm_vidc_inst *inst, enum msm_vidc_buffer_type type); + int (*ring_buf_count)(struct msm_vidc_inst *inst, u32 data_size); }; struct msm_vidc_mem_list_info { diff --git a/driver/vidc/inc/msm_vidc_internal.h b/driver/vidc/inc/msm_vidc_internal.h index d6dea35e60..7f84fc40a4 100644 --- a/driver/vidc/inc/msm_vidc_internal.h +++ b/driver/vidc/inc/msm_vidc_internal.h @@ -101,6 +101,7 @@ enum msm_vidc_metadata_bits { #define MAX_ENCODING_REFERNCE_FRAMES 7 #define MAX_LTR_FRAME_COUNT_5 5 #define MAX_LTR_FRAME_COUNT_2 2 +#define MAX_ENC_RING_BUF_COUNT 5 /* to be tuned */ #define DCVS_WINDOW 16 #define ENC_FPS_WINDOW 3 @@ -288,6 +289,7 @@ enum msm_vidc_metadata_bits { CAP(MB_CYCLES_LP) \ CAP(MB_CYCLES_FW) \ CAP(MB_CYCLES_FW_VPP) \ + CAP(ENC_RING_BUFFER_COUNT) \ CAP(CLIENT_ID) \ CAP(SECURE_MODE) \ CAP(FENCE_ID) \ diff --git a/driver/vidc/src/msm_venc.c b/driver/vidc/src/msm_venc.c index 71a9f6db42..853950f92b 100644 --- a/driver/vidc/src/msm_venc.c +++ b/driver/vidc/src/msm_venc.c @@ -456,6 +456,29 @@ static int msm_venc_set_quality_mode(struct msm_vidc_inst *inst) return 0; } +static int msm_venc_set_ring_buffer_count(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct msm_vidc_inst_cap *cap; + + if (!inst->capabilities) { + i_vpr_e(inst, "%s: invalid params\n", __func__); + return -EINVAL; + } + cap = &inst->capabilities->cap[ENC_RING_BUFFER_COUNT]; + + if (!cap->set) + return 0; + + rc = cap->set(inst, ENC_RING_BUFFER_COUNT); + if (rc) { + i_vpr_e(inst, "%s: set cap failed\n", __func__); + return rc; + } + + return 0; +} + static int msm_venc_set_input_properties(struct msm_vidc_inst *inst) { int i, j, rc = 0; @@ -544,6 +567,10 @@ static int msm_venc_set_internal_properties(struct msm_vidc_inst *inst) if (rc) return rc; + rc = msm_venc_set_ring_buffer_count(inst); + if (rc) + return rc; + return rc; } @@ -1006,6 +1033,10 @@ int msm_venc_streamon_output(struct msm_vidc_inst *inst) if (rc) goto error; + rc = msm_venc_set_internal_properties(inst); + if (rc) + goto error; + rc = msm_venc_get_output_internal_buffers(inst); if (rc) goto error; @@ -1018,10 +1049,6 @@ int msm_venc_streamon_output(struct msm_vidc_inst *inst) if (rc) goto error; - rc = msm_venc_set_internal_properties(inst); - if (rc) - goto error; - rc = msm_venc_property_subscription(inst, OUTPUT_PORT); if (rc) goto error;