Răsfoiți Sursa

video: driver: enable encoder superframe batching support

Added HFR/HSR superframe handling support for encoder.

Change-Id: I28ced3f223cd78d00b1a654a79bcac3b02f378dc
Signed-off-by: Govindaraj Rajagopal <[email protected]>
Govindaraj Rajagopal 4 ani în urmă
părinte
comite
f02bbaf836

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

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

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

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

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

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

+ 18 - 1
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;
 

+ 139 - 0
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)
 {

+ 33 - 0
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;

+ 3 - 0
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),