rkvdec HEVC: missing HEVC_SLICE_PARAMS registration in vdpu38x_hevc_ctrl_descs #15

Closed
opened 2026-05-16 11:18:16 +00:00 by marfrit · 2 comments
Owner

Summary

Follow-up to #14. The Casanova/Collabora v7.0 HEVC series introduced vdpu38x_hevc_ctrl_descs[] for RK3588 (vdpu381) and RK3576 (vdpu383) but forgot to register V4L2_CID_STATELESS_HEVC_SLICE_PARAMS. Every per-frame VIDIOC_S_EXT_CTRLS then fails with -EINVAL because find_ref_lock returns NULL for 0xa40a92.

Repro

  • Host: ampere (CoolPi CM5 GenBook, RK3588), 7.0.0-rc3 + mmind v7.0 + Casanova HEVC v7.0 + #14 fix.
  • LIBVA_DRIVER_NAME=v4l2_request ffmpeg -hwaccel vaapi ... -frames:v 3 ...
  • pre-patch: ffmpeg exit 0 but /tmp/o.nv12 all zeros, dmesg:
v4l2-ctrls: prepare_ext_ctrls: video0: cannot find control id 0xa40a92
video0: VIDIOC_S_EXT_CTRLS: error -22: ..., count=5, error_idx=5, name=HEVC Sequence Parameter Set, ..., name=HEVC Slice Parameters, id/size=0xa40a92/280, ...

The cannot find dprintk is gated behind V4L2_DEV_DEBUG_CTRL = 0x20. Default dev_debug=0 hides this. Enable per-device:

for v in /sys/class/video4linux/video*/dev_debug; do echo 0x3f | sudo tee $v; done

Root cause

drivers/media/platform/rockchip/rkvdec/rkvdec.c has two HEVC tables. The legacy rkvdec_hevc_ctrl_descs[] (RK3399, line 189) registers SLICE_PARAMS:

{
    .cfg.id = V4L2_CID_STATELESS_HEVC_SLICE_PARAMS,
    .cfg.flags = V4L2_CTRL_FLAG_DYNAMIC_ARRAY,
    .cfg.type = V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS,
    .cfg.dims = { 600 },
},

The new vdpu38x_hevc_ctrl_descs[] doesn't. Both feed rkvdec_hevc_run_preamble (rkvdec-hevc-common.c:485-488) which does v4l2_ctrl_find(..., V4L2_CID_STATELESS_HEVC_SLICE_PARAMS) and stores ctrl->p_cur.p + ctrl->new_elems. With the new table, find returns NULL, but userspace already failed S_EXT_CTRLS before that, so no controls commit at all → decoder runs on zero-init state.

Fix (verified working)

--- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
@@ -242,6 +242,12 @@ static const struct rkvdec_ctrl_desc vdpu38x_hevc_ctrl_descs[] = {
         {
                 .cfg.id = V4L2_CID_STATELESS_HEVC_DECODE_PARAMS,
         },
+        {
+                .cfg.id = V4L2_CID_STATELESS_HEVC_SLICE_PARAMS,
+                .cfg.flags = V4L2_CTRL_FLAG_DYNAMIC_ARRAY,
+                .cfg.type = V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS,
+                .cfg.dims = { 600 },
+        },
         {
                 .cfg.id = V4L2_CID_STATELESS_HEVC_SPS,
                 .cfg.ops = &rkvdec_ctrl_ops,

5 lines. Mirror of the legacy entry. dims = {600} = absolute max slices/frame for HEVC level > 6 (matches visl + legacy rkvdec).

Verification on ampere

  • ffmpeg exit 0
  • dmesg post-test: zero cannot find control id, zero S_EXT_CTRLS: error, zero Internal error
  • /tmp/o.nv12 = 4147200 bytes (exact 3×NV12 frame size)
  • All bytes are 16 (Y) or 128 (Cb/Cr) — structurally valid blank/black frames
  • Decoder runs without rejecting the batch, but produces solid black — separate downstream bug filed as #16 (forthcoming)

Scope

  • Affects: vdpu381 (RK3588) + vdpu383 (RK3576). Both bind via vdpu38x_hevc_ctrl_descs[].
  • Does NOT affect RK3399 legacy path (rkvdec_hevc_ctrl_descs[] already has the entry).
  • All HEVC decode on RK3588/RK3576 was broken pre-patch.

Campaign cross-ref

Found in ampere-kernel-decoders iter4 (commit 46c956b). Full forensic trace in iter4_close.md. Same kernel module from #14 fix carried, plus this patch.

Blocks iter5 (decoder-produces-empty-output investigation).

## Summary Follow-up to #14. The Casanova/Collabora v7.0 HEVC series introduced `vdpu38x_hevc_ctrl_descs[]` for RK3588 (vdpu381) and RK3576 (vdpu383) but forgot to register `V4L2_CID_STATELESS_HEVC_SLICE_PARAMS`. Every per-frame `VIDIOC_S_EXT_CTRLS` then fails with `-EINVAL` because `find_ref_lock` returns NULL for `0xa40a92`. ## Repro - Host: ampere (CoolPi CM5 GenBook, RK3588), 7.0.0-rc3 + mmind v7.0 + Casanova HEVC v7.0 + #14 fix. - `LIBVA_DRIVER_NAME=v4l2_request ffmpeg -hwaccel vaapi ... -frames:v 3 ...` - pre-patch: ffmpeg exit 0 but `/tmp/o.nv12` all zeros, dmesg: ``` v4l2-ctrls: prepare_ext_ctrls: video0: cannot find control id 0xa40a92 video0: VIDIOC_S_EXT_CTRLS: error -22: ..., count=5, error_idx=5, name=HEVC Sequence Parameter Set, ..., name=HEVC Slice Parameters, id/size=0xa40a92/280, ... ``` The `cannot find` dprintk is **gated behind `V4L2_DEV_DEBUG_CTRL = 0x20`**. Default dev_debug=0 hides this. Enable per-device: ``` for v in /sys/class/video4linux/video*/dev_debug; do echo 0x3f | sudo tee $v; done ``` ## Root cause `drivers/media/platform/rockchip/rkvdec/rkvdec.c` has two HEVC tables. The legacy `rkvdec_hevc_ctrl_descs[]` (RK3399, line 189) registers SLICE_PARAMS: ```c { .cfg.id = V4L2_CID_STATELESS_HEVC_SLICE_PARAMS, .cfg.flags = V4L2_CTRL_FLAG_DYNAMIC_ARRAY, .cfg.type = V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS, .cfg.dims = { 600 }, }, ``` The new `vdpu38x_hevc_ctrl_descs[]` doesn't. Both feed `rkvdec_hevc_run_preamble` (rkvdec-hevc-common.c:485-488) which does `v4l2_ctrl_find(..., V4L2_CID_STATELESS_HEVC_SLICE_PARAMS)` and stores `ctrl->p_cur.p` + `ctrl->new_elems`. With the new table, `find` returns NULL, but userspace already failed `S_EXT_CTRLS` before that, so no controls commit at all → decoder runs on zero-init state. ## Fix (verified working) ```diff --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c @@ -242,6 +242,12 @@ static const struct rkvdec_ctrl_desc vdpu38x_hevc_ctrl_descs[] = { { .cfg.id = V4L2_CID_STATELESS_HEVC_DECODE_PARAMS, }, + { + .cfg.id = V4L2_CID_STATELESS_HEVC_SLICE_PARAMS, + .cfg.flags = V4L2_CTRL_FLAG_DYNAMIC_ARRAY, + .cfg.type = V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS, + .cfg.dims = { 600 }, + }, { .cfg.id = V4L2_CID_STATELESS_HEVC_SPS, .cfg.ops = &rkvdec_ctrl_ops, ``` 5 lines. Mirror of the legacy entry. `dims = {600}` = absolute max slices/frame for HEVC level > 6 (matches visl + legacy rkvdec). ## Verification on ampere - ffmpeg exit 0 - dmesg post-test: zero `cannot find control id`, zero `S_EXT_CTRLS: error`, zero `Internal error` - `/tmp/o.nv12` = 4147200 bytes (exact 3×NV12 frame size) - All bytes are 16 (Y) or 128 (Cb/Cr) — structurally valid blank/black frames - Decoder runs without rejecting the batch, but produces solid black — separate downstream bug filed as #16 (forthcoming) ## Scope - Affects: vdpu381 (RK3588) + vdpu383 (RK3576). Both bind via `vdpu38x_hevc_ctrl_descs[]`. - Does NOT affect RK3399 legacy path (`rkvdec_hevc_ctrl_descs[]` already has the entry). - All HEVC decode on RK3588/RK3576 was broken pre-patch. ## Campaign cross-ref Found in `ampere-kernel-decoders` iter4 (commit 46c956b). Full forensic trace in `iter4_close.md`. Same kernel module from #14 fix carried, plus this patch. Blocks iter5 (decoder-produces-empty-output investigation).
Collaborator

Empirical verification: HEVC_SLICE_PARAMS registration eliminates EINVAL

Applied the 5-line patch to ampere's running kernel tree (linux-rockchip v7.0-rc3 + mmind v7.0 + Casanova HEVC v7.0 + #14 fix) and re-ran the exact repro on a fresh reboot. Patch carried on top of the #14 fix (ext_sps NULL init in run_preamble).

Patch as applied

--- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
@@ -242,6 +242,12 @@ static const struct rkvdec_ctrl_desc vdpu38x_hevc_ctrl_descs[] = {
 	{
 		.cfg.id = V4L2_CID_STATELESS_HEVC_DECODE_PARAMS,
 	},
+	{
+		.cfg.id = V4L2_CID_STATELESS_HEVC_SLICE_PARAMS,
+		.cfg.flags = V4L2_CTRL_FLAG_DYNAMIC_ARRAY,
+		.cfg.type = V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS,
+		.cfg.dims = { 600 },
+	},
 	{
 		.cfg.id = V4L2_CID_STATELESS_HEVC_SPS,
 		.cfg.ops = &rkvdec_ctrl_ops,

Confirmed in source at drivers/media/platform/rockchip/rkvdec/rkvdec.c:239-248. Built via make M=drivers/media/platform/rockchip/rkvdec modules, installed to /lib/modules/7.0.0-rc3-devices+/kernel/..., depmod, fresh reboot (uptime 19 min at test, module .ko timestamp 13:16, boot at 13:17).

Test

LIBVA_DRIVER_NAME=v4l2_request ffmpeg -hwaccel vaapi -hwaccel_output_format vaapi \
  -i ~/measurements/encoded/bbb_60s_720p.hevc.mp4 -vf hwdownload,format=nv12 \
  -frames:v 3 -f rawvideo -pix_fmt nv12 /tmp/o.nv12

Result

  • ffmpeg exit code: 0
  • dmesg post-test: 0 occurrences of cannot find control id, S_EXT_CTRLS: error, Internal error (full grep returned empty)
  • /tmp/o.nv12: 4147200 bytes — exact match for 3 × 1280 × 720 × 1.5 NV12 frames
  • md5sum: 25ae521379343783da65b1fc80b1e8e8 — bit-identical to the iter4-close substrate run, confirming reproducibility across reboot
  • backend log shows clean per-frame BeginPicture / RenderPicture / EndPicture cycles; no kernel-side rejection of the 5-ctrl batch

Unique-byte breakdown

$ od -An -tu1 -w1 /tmp/o.nv12 | sort -u
  16
 128

Only Y=16 (luma black) and Cb/Cr=128 (chroma neutral). Structurally valid 3-frame NV12, content all black. This is the downstream bug already noted in the issue body (slated for #16 / iter5) and explicitly out of scope for this issue — the success criterion here is EINVAL gone + decoder runs + dmesg clean, all of which hold.

Diagnostic noise (harmless)

The iter4 Phase 6 pr_warn("iter4-DIAG validate_sps: ...") in rkvdec_hevc_validate_sps now fires per-frame (≈ 32 lines per 3-frame test) rather than the twice-per-session observed pre-patch. Expected consequence of the patch: with S_EXT_CTRLS now succeeding, the SPS ctrl is genuinely committed each frame, so the validate callback runs each time. The diagnostic is module-private and will be stripped before any upstream submission — leaving in place for iter5 instrumentation.

Scope confirmed

Fix targets the vdpu38x_hevc_ctrl_descs[] table consumed by both RK3588 (vdpu381) and RK3576 (vdpu383). Legacy rkvdec_hevc_ctrl_descs[] (RK3399) already had the entry and is unaffected. Report-only — not promoting or closing here.

## Empirical verification: HEVC_SLICE_PARAMS registration eliminates EINVAL Applied the 5-line patch to ampere's running kernel tree (`linux-rockchip` v7.0-rc3 + mmind v7.0 + Casanova HEVC v7.0 + #14 fix) and re-ran the exact repro on a fresh reboot. Patch carried on top of the #14 fix (`ext_sps NULL init in run_preamble`). ### Patch as applied ```diff --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c @@ -242,6 +242,12 @@ static const struct rkvdec_ctrl_desc vdpu38x_hevc_ctrl_descs[] = { { .cfg.id = V4L2_CID_STATELESS_HEVC_DECODE_PARAMS, }, + { + .cfg.id = V4L2_CID_STATELESS_HEVC_SLICE_PARAMS, + .cfg.flags = V4L2_CTRL_FLAG_DYNAMIC_ARRAY, + .cfg.type = V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS, + .cfg.dims = { 600 }, + }, { .cfg.id = V4L2_CID_STATELESS_HEVC_SPS, .cfg.ops = &rkvdec_ctrl_ops, ``` Confirmed in source at `drivers/media/platform/rockchip/rkvdec/rkvdec.c:239-248`. Built via `make M=drivers/media/platform/rockchip/rkvdec modules`, installed to `/lib/modules/7.0.0-rc3-devices+/kernel/...`, depmod, fresh reboot (uptime 19 min at test, module .ko timestamp 13:16, boot at 13:17). ### Test ``` LIBVA_DRIVER_NAME=v4l2_request ffmpeg -hwaccel vaapi -hwaccel_output_format vaapi \ -i ~/measurements/encoded/bbb_60s_720p.hevc.mp4 -vf hwdownload,format=nv12 \ -frames:v 3 -f rawvideo -pix_fmt nv12 /tmp/o.nv12 ``` ### Result - **ffmpeg exit code: 0** - **dmesg post-test: 0 occurrences** of `cannot find control id`, `S_EXT_CTRLS: error`, `Internal error` (full grep returned empty) - **/tmp/o.nv12: 4147200 bytes** — exact match for 3 × 1280 × 720 × 1.5 NV12 frames - **md5sum: `25ae521379343783da65b1fc80b1e8e8`** — bit-identical to the iter4-close substrate run, confirming reproducibility across reboot - backend log shows clean per-frame `BeginPicture` / `RenderPicture` / `EndPicture` cycles; no kernel-side rejection of the 5-ctrl batch ### Unique-byte breakdown ``` $ od -An -tu1 -w1 /tmp/o.nv12 | sort -u 16 128 ``` Only Y=16 (luma black) and Cb/Cr=128 (chroma neutral). Structurally valid 3-frame NV12, content all black. This is the downstream bug already noted in the issue body (slated for #16 / iter5) and explicitly out of scope for this issue — the success criterion here is EINVAL gone + decoder runs + dmesg clean, all of which hold. ### Diagnostic noise (harmless) The iter4 Phase 6 `pr_warn("iter4-DIAG validate_sps: ...")` in `rkvdec_hevc_validate_sps` now fires per-frame (≈ 32 lines per 3-frame test) rather than the twice-per-session observed pre-patch. Expected consequence of the patch: with `S_EXT_CTRLS` now succeeding, the SPS ctrl is genuinely committed each frame, so the validate callback runs each time. The diagnostic is module-private and will be stripped before any upstream submission — leaving in place for iter5 instrumentation. ### Scope confirmed Fix targets the `vdpu38x_hevc_ctrl_descs[]` table consumed by both RK3588 (vdpu381) and RK3576 (vdpu383). Legacy `rkvdec_hevc_ctrl_descs[]` (RK3399) already had the entry and is unaffected. Report-only — not promoting or closing here.
marfrit added the EWONTFIX label 2026-05-18 09:44:38 +00:00
Collaborator

EWONTFIX 2026-05-18.

HEVC on ampere (RK3588) is scoped out indefinitely. Joint decision covering this issue plus kernel-agent#14 (kernel stack-uninit OOPS), kernel-agent#15 (HEVC_SLICE_PARAMS registration), and libva-v4l2-request-fourier#3 (libva backend EXT_SPS_*_RPS submission).

Rationale

  • Fleet HEVC consumption is near-zero for the workloads that matter: YouTube serves VP9 / AV1 / H.264 (never HEVC); mediathek.ard.de is H.264-dominant; DRM-gated 4K streams (Netflix/Apple TV+/Disney+) are blocked by Widevine L1 in the fleet's browsers anyway.
  • HEVC where it IS needed (local files, archive content) is already covered by fresnel (RK3399), which decodes HEVC + Main10 bit-exact HW==SW via libva-v4l2-request-fourier iter38/iter39 (verified during marfrit-packages#21 fix earlier today).
  • Ampere's value to the fleet is bigger silicon for YouTube AV1 (per daedalus-fourier README's "YouTube ∩ Pi5-HW = ∅" framing) — HEVC on ampere doesn't move that needle.

Reopen criteria

Reopen any of the three if a concrete HEVC workflow emerges on ampere (4K local file collection, HEVC-encoded archive that doesn't fit on fresnel, specific app that requires HEVC and runs only on ampere). The kernel side fix in #14 + #15 is closed-form (one-liner each); the libva side in #3 is straightforward bitstream-translation work. None of the analysis is lost; it's all archived in the closed issues' bodies + comments.

Closing.

**EWONTFIX 2026-05-18.** HEVC on ampere (RK3588) is scoped out indefinitely. Joint decision covering this issue plus [kernel-agent#14](https://git.reauktion.de/marfrit/kernel-agent/issues/14) (kernel stack-uninit OOPS), [kernel-agent#15](https://git.reauktion.de/marfrit/kernel-agent/issues/15) (HEVC_SLICE_PARAMS registration), and [libva-v4l2-request-fourier#3](https://git.reauktion.de/marfrit/libva-v4l2-request-fourier/issues/3) (libva backend EXT_SPS_*_RPS submission). ## Rationale - Fleet HEVC consumption is near-zero for the workloads that matter: YouTube serves VP9 / AV1 / H.264 (never HEVC); mediathek.ard.de is H.264-dominant; DRM-gated 4K streams (Netflix/Apple TV+/Disney+) are blocked by Widevine L1 in the fleet's browsers anyway. - HEVC where it IS needed (local files, archive content) is already covered by **fresnel** (RK3399), which decodes HEVC + Main10 bit-exact HW==SW via libva-v4l2-request-fourier iter38/iter39 (verified during marfrit-packages#21 fix earlier today). - Ampere's value to the fleet is bigger silicon for YouTube AV1 (per `daedalus-fourier` README's "YouTube ∩ Pi5-HW = ∅" framing) — HEVC on ampere doesn't move that needle. ## Reopen criteria Reopen any of the three if a concrete HEVC workflow emerges on ampere (4K local file collection, HEVC-encoded archive that doesn't fit on fresnel, specific app that requires HEVC and runs only on ampere). The kernel side fix in #14 + #15 is closed-form (one-liner each); the libva side in #3 is straightforward bitstream-translation work. None of the analysis is lost; it's all archived in the closed issues' bodies + comments. Closing.
Sign in to join this conversation.