Просмотр исходного кода

video: driver: Add support to enable enc ring buffer

Add support to enable ring buffer for enc intermediate
bin buffer to improve encoding performance.

Change-Id: Ifbf50cb48278c62c09a20bc7626a3b6288813830
Signed-off-by: Akshata Sahukar <[email protected]>
Akshata Sahukar 2 лет назад
Родитель
Сommit
9a5fea8ef3

+ 67 - 0
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,

+ 67 - 0
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,

+ 1 - 0
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);

+ 4 - 3
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;

+ 1 - 0
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,

+ 108 - 1
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;
-}
+}
+
+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;
+}

+ 1 - 0
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 {

+ 2 - 0
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)                             \

+ 31 - 4
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,19 +1033,19 @@ int msm_venc_streamon_output(struct msm_vidc_inst *inst)
 	if (rc)
 		goto error;
 
-	rc = msm_venc_get_output_internal_buffers(inst);
+	rc = msm_venc_set_internal_properties(inst);
 	if (rc)
 		goto error;
 
-	rc = msm_venc_create_output_internal_buffers(inst);
+	rc = msm_venc_get_output_internal_buffers(inst);
 	if (rc)
 		goto error;
 
-	rc = msm_venc_queue_output_internal_buffers(inst);
+	rc = msm_venc_create_output_internal_buffers(inst);
 	if (rc)
 		goto error;
 
-	rc = msm_venc_set_internal_properties(inst);
+	rc = msm_venc_queue_output_internal_buffers(inst);
 	if (rc)
 		goto error;