Re: [PATCH] Add support for multi_slice in iris encoder
From: Vikash Garodia
Date: Fri Jun 26 2026 - 08:29:20 EST
On 4/28/2026 12:44 PM, Sachin Kumar Garg wrote:
Add multi-slice encoding support with MAX_MB and MAX_BYTES modes.
Clients can enable slice mode using V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE
control and configure slice size via V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB
or V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES controls.
Signed-off-by: Sachin Kumar Garg <sachin.garg@xxxxxxxxxxxxxxxx>
---
This series adds the support for multi slice feature in the
series ?
Qualcomm Iris driver.
Multi-slice mode allows encoding a single frame into multiple slices,
which can improve error resilience and enable parallel processing.
The feature supports two slice modes:
- MAX_MB mode: Slices are created based on macroblock count, controlled
via V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB
- MAX_BYTES mode: Slices are created based on byte size, controlled via
V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES
Clients can enable slice mode using the
V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE control.
This series adds multi-slice support for HFI Gen2 targets (SM8550 and later).
Support for HFI Gen1 targets will be added in a follow-up series.
This Patch has been verified with GST level.
specify the platform tested.
Command used:
gst-launch-1.0 -v videotestsrc ! video/x-raw,format=NV12, \
width=1280,height=720,framerate=30/1 ! v4l2h264enc output-io-mode=4 |
capture-io-mode=4 extra-controls="controls,video_bitrate_mode=1, \
slice_partitioning_method=1,number_of_mbs_in_a_slice=460;" \
! filesink location=/opt/test_enc.h264
---
drivers/media/platform/qcom/iris/iris_ctrls.c | 89 ++++++++++++++++++++++
drivers/media/platform/qcom/iris/iris_ctrls.h | 1 +
.../platform/qcom/iris/iris_hfi_gen2_defines.h | 2 +
.../platform/qcom/iris/iris_platform_common.h | 3 +
.../media/platform/qcom/iris/iris_platform_gen2.c | 31 ++++++++
5 files changed, 126 insertions(+)
diff --git a/drivers/media/platform/qcom/iris/iris_ctrls.c b/drivers/media/platform/qcom/iris/iris_ctrls.c
index 3cec957580f5..52b92241e7f0 100644
--- a/drivers/media/platform/qcom/iris/iris_ctrls.c
+++ b/drivers/media/platform/qcom/iris/iris_ctrls.c
@@ -13,6 +13,15 @@
#define CABAC_MAX_BITRATE 160000000
#define CAVLC_MAX_BITRATE 220000000
+#define MAX_SLICES_PER_FRAME 10
can you reconfirm this if this is indeed limited to 10 ?
+#define MAX_SLICES_FRAME_RATE 60
+#define MAX_MB_SLICE_WIDTH 4096
+#define MAX_MB_SLICE_HEIGHT 2160
+#define MAX_BYTES_SLICE_WIDTH 1920
+#define MAX_BYTES_SLICE_HEIGHT 1088
+#define MIN_HEVC_SLICE_WIDTH 384
+#define MIN_AVC_SLICE_WIDTH 192
+#define MIN_SLICE_HEIGHT 128
static inline bool iris_valid_cap_id(enum platform_inst_fw_cap_type cap_id)
{
@@ -112,6 +121,12 @@ static enum platform_inst_fw_cap_type iris_get_cap_id(u32 id)
return IR_TYPE;
case V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD:
return IR_PERIOD;
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
+ return SLICE_MODE;
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES:
+ return SLICE_MAX_BYTES;
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:
+ return SLICE_MAX_MB;
default:
return INST_FW_CAP_MAX;
}
@@ -213,6 +228,12 @@ static u32 iris_get_v4l2_id(enum platform_inst_fw_cap_type cap_id)
return V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE;
case IR_PERIOD:
return V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD;
+ case SLICE_MODE:
+ return V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE;
+ case SLICE_MAX_BYTES:
+ return V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES;
+ case SLICE_MAX_MB:
+ return V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB;
default:
return 0;
}
@@ -996,6 +1017,74 @@ int iris_set_ir_period(struct iris_inst *inst, enum platform_inst_fw_cap_type ca
&ir_period, sizeof(u32));
}
+int iris_set_slice_count(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id)
+{
+ const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops;
+ u32 slice_mode = inst->fw_caps[SLICE_MODE].value;
+ u32 bitrate = inst->fw_caps[BITRATE].value;
+ u32 rc_type = inst->fw_caps[BITRATE_MODE].value;
+ u32 fps = inst->frame_rate;
+ u32 output_width = inst->fmt_dst->fmt.pix_mp.width;
+ u32 output_height = inst->fmt_dst->fmt.pix_mp.height;
+ u32 mbpf = NUM_MBS_PER_FRAME(output_height, output_width);
+ u32 max_width, max_height, min_width, min_height;
+ u32 max_avg_slicesize, hfi_value, hfi_id;
+
+ if (slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE) {
+ dev_dbg(inst->core->dev, "slice mode is: %u, ignore setting to fw\n", slice_mode);
+ return 0;
+ }
+ if (!fps) {
+ dev_err(inst->core->dev, "Invalid frame rate %d\n", fps);
+ return -EINVAL;
+ }
+ if (fps > MAX_SLICES_FRAME_RATE ||
+ (rc_type != HFI_RC_OFF && rc_type != HFI_RC_CBR_CFR &&
+ rc_type != HFI_RC_CBR_VFR)) {
+ dev_err(inst->core->dev, "slice unsupported, fps: %u, rc_type: %#x\n",
+ fps, rc_type);
+ return -EINVAL;
+ }
+
+ max_width = (slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB) ?
+ MAX_MB_SLICE_WIDTH : MAX_BYTES_SLICE_WIDTH;
+ max_height = (slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB) ?
+ MAX_MB_SLICE_HEIGHT : MAX_BYTES_SLICE_HEIGHT;
+ min_width = (inst->codec == V4L2_PIX_FMT_HEVC) ?
+ MIN_HEVC_SLICE_WIDTH : MIN_AVC_SLICE_WIDTH;
+ min_height = MIN_SLICE_HEIGHT;
All these values are made into common setter, if there is a SOC, which supports different capabilities, these need to be redesigned. Can you see on how to make this platform specific capabilities and then make the checks generic to be used for all SOCs ?
+
+ if (output_width < min_width || output_height < min_height ||
+ output_width > max_width || output_height > max_height) {
+ dev_err(inst->core->dev, "slice unsupported, codec: %#x wxh: [%dx%d]\n",
+ inst->codec, output_width, output_height);
+ return -EINVAL;
+ }
+
+ if (slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB) {
+ hfi_value = inst->fw_caps[SLICE_MAX_MB].value;
+ hfi_value = max(hfi_value, mbpf / MAX_SLICES_PER_FRAME);
+ if (inst->codec == V4L2_PIX_FMT_HEVC)
+ hfi_value = (hfi_value + 3) / 4;
+ hfi_id = inst->fw_caps[SLICE_MAX_MB].hfi_id;
+ } else if (slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES) {
+ hfi_value = inst->fw_caps[SLICE_MAX_BYTES].value;
+ if (rc_type != HFI_RC_OFF) {
+ max_avg_slicesize = ((bitrate / fps) / 8) / MAX_SLICES_PER_FRAME;
+ hfi_value = max(hfi_value, max_avg_slicesize);
+ }
+ hfi_id = inst->fw_caps[SLICE_MAX_BYTES].hfi_id;
+ } else {
+ return -EINVAL;
+ }
+
+ return hfi_ops->session_set_property(inst, hfi_id,
+ HFI_HOST_FLAGS_NONE,
+ iris_get_port_info(inst, cap_id),
+ HFI_PAYLOAD_U32,
+ &hfi_value, sizeof(u32));
+}
+
int iris_set_properties(struct iris_inst *inst, u32 plane)
{
const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops;
diff --git a/drivers/media/platform/qcom/iris/iris_ctrls.h b/drivers/media/platform/qcom/iris/iris_ctrls.h
index 9518803577bc..5280ee00d9a0 100644
--- a/drivers/media/platform/qcom/iris/iris_ctrls.h
+++ b/drivers/media/platform/qcom/iris/iris_ctrls.h
@@ -35,6 +35,7 @@ int iris_set_qp_range(struct iris_inst *inst, enum platform_inst_fw_cap_type cap
int iris_set_rotation(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id);
int iris_set_flip(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id);
int iris_set_ir_period(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id);
+int iris_set_slice_count(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id);
int iris_set_properties(struct iris_inst *inst, u32 plane);
#endif
diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h b/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h
index cecf771c55dd..8a27f246e114 100644
--- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h
+++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h
@@ -71,6 +71,8 @@ enum hfi_rate_control {
#define HFI_PROP_MIN_QP_PACKED 0x0300012f
#define HFI_PROP_MAX_QP_PACKED 0x03000130
#define HFI_PROP_IR_RANDOM_PERIOD 0x03000131
+#define HFI_PROP_MULTI_SLICE_MB_COUNT 0x03000132
+#define HFI_PROP_MULTI_SLICE_BYTES_COUNT 0x03000133
#define HFI_PROP_TOTAL_BITRATE 0x0300013b
#define HFI_PROP_MAX_GOP_FRAMES 0x03000146
#define HFI_PROP_MAX_B_FRAMES 0x03000147
diff --git a/drivers/media/platform/qcom/iris/iris_platform_common.h b/drivers/media/platform/qcom/iris/iris_platform_common.h
index 5a489917580e..05962d8fbb25 100644
--- a/drivers/media/platform/qcom/iris/iris_platform_common.h
+++ b/drivers/media/platform/qcom/iris/iris_platform_common.h
@@ -159,6 +159,9 @@ enum platform_inst_fw_cap_type {
VFLIP,
IR_TYPE,
IR_PERIOD,
+ SLICE_MODE,
+ SLICE_MAX_BYTES,
+ SLICE_MAX_MB,
INST_FW_CAP_MAX,
};
diff --git a/drivers/media/platform/qcom/iris/iris_platform_gen2.c b/drivers/media/platform/qcom/iris/iris_platform_gen2.c
index 5da90d47f9c6..191154a8ab8d 100644
--- a/drivers/media/platform/qcom/iris/iris_platform_gen2.c
+++ b/drivers/media/platform/qcom/iris/iris_platform_gen2.c
@@ -18,6 +18,8 @@
#define VIDEO_ARCH_LX 1
#define BITRATE_MAX 245000000
+#define MAX_SLICE_MB_SIZE \
+ (((4096 + 15) >> 4) * ((2304 + 15) >> 4))
Why is 2304 inconsistent with "MAX_MB_SLICE_HEIGHT 2160" ?
Regards,
Vikash