Extend backend to populate V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS / _LT_RPS for VDPU381 HEVC (RK3588) #3

Closed
opened 2026-05-16 08:11:05 +00:00 by claude-noether · 3 comments
Collaborator

Extend backend to populate V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS / _LT_RPS for VDPU381 HEVC

Context

Linux 7.0 (Detlev Casanova / Collabora v8 series, lkml.org/lkml/2026/1/9/1334) landed RK3588/RK3576 HEVC support and introduced two new V4L2 stateless HEVC controls:

  • V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS — short-term reference picture set parameters
  • V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS — long-term reference picture set parameters

The struct definitions (include/uapi/linux/v4l2-controls.h):

#define V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS  (V4L2_CID_CODEC_STATELESS_BASE + 408)
#define V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS  (V4L2_CID_CODEC_STATELESS_BASE + 409)

struct v4l2_ctrl_hevc_ext_sps_st_rps {
    __u8  delta_idx_minus1;
    __u8  delta_rps_sign;
    __u8  num_negative_pics;
    /* ... — dynamic array sized by v4l2_ctrl_hevc_sps::num_short_term_ref_pic_sets, up to 65 elements */
    __u8  flags;  /* V4L2_HEVC_EXT_SPS_ST_RPS_FLAG_INTER_REF_PIC_SET_PRED */
};

(LT_RPS has its own struct shape; not pasted here but defined in the same header.)

The backend (marfrit/libva-v4l2-request-fourier @ 7ac934e, the iter38b that fresnel certified) does not know about these controls — they were added to the kernel UAPI after the backend's iter38 close. Searching the backend source confirms zero hits.

Symptom on ampere (RK3588)

ampere-fourier iter1 Phase 0 captured a reproducible kernel OOPS on the first HEVC decode attempt:

lr : rkvdec_hevc_prepare_hw_st_rps+0x38/0x300 [rockchip_vdec]
Call trace:
 __pi_memcmp+0x10/0x110 (P)
 rkvdec_hevc_assemble_hw_rps+0x1c/0xac [rockchip_vdec]
 rkvdec_hevc_run+0x12c/0x148 [rockchip_vdec]
 rkvdec_device_run+0x48/0x104 [rockchip_vdec]
 v4l2_m2m_try_run+0x80/0x13c [v4l2_mem2mem]
 v4l2_m2m_request_queue+0xe8/0x140 [v4l2_mem2mem]
 media_request_ioctl_queue+0x1bc/0x2f4 [mc]

Originally filed against marfrit/kernel-agent#11 as a kernel bug; reclassified after the ampere-kernel-decoders iter1 prior-art survey.

Verified mechanism (reading the kernel source at drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c:500-509 + :380-410): if ctx->has_sps_st_rps is set (VDPU381 variant_ops sets it), the kernel calls v4l2_ctrl_find for the new CID. With the control unset by userspace, the kernel may auto-allocate it with non-NULL but uninitialized p_cur.p. The early-return if (!run->ext_sps_st_rps) return; doesn't fire, and the subsequent memcmp(cache, run->ext_sps_st_rps, sizeof(struct)) faults in __pi_memcmp.

What the backend needs to do

  1. Parse the HEVC bitstream's SPS for the short-term and long-term RPS tables. The relevant H.265 spec section is 7.4.8 (RPS semantics); the per-frame VAAPI VAPictureParameterBufferHEVC does carry equivalent fields, so this is a translation problem, not a new-bitstream-parsing problem.
  2. Allocate a struct v4l2_ctrl_hevc_ext_sps_st_rps[num_short_term_ref_pic_sets] (up to 65 entries), populate from VAAPI fields, set via VIDIOC_S_EXT_CTRLS using V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS. Same for LT_RPS with the long-term equivalent.
  3. Gate by driver-kind so the control is only set on VDPU381/383 — RK3399 legacy rkvdec doesn't have the control and would NAK the S_EXT_CTRLS. Per memory feedback_per_driver_kludge_gating, the gate goes on driver_data->driver_kind.
  4. Also gate by kernel-side support (control present in the ctrl_hdl) — there's a window where libva is built against the new UAPI but the running kernel is older. Probe via VIDIOC_QUERYCTRL at init.

Prerequisite: bump linux-api-headers on the test host

ampere is currently on linux-api-headers 6.19-1 which doesn't define the constants. Either:

  • Bump the host package to 7.0 (operator decision — affects whole-system UAPI consumers).
  • Ship a local copy of the relevant struct + CID definitions in the backend tree (campaign convention: backend already has hevc-ctrls/ for similar shims pre-merger).

Recommend the latter for now — same precedent as fresnel-fourier iter25 (rkvdec image_fmt pre-seed) where the backend shipped its own UAPI shim until the kernel side stabilized.

Acceptance

LIBVA_DRIVER_NAME=v4l2_request ffmpeg -hwaccel vaapi -hwaccel_output_format vaapi -i bbb_60s_720p.hevc.mp4 -vf hwdownload -f null - on ampere completes without kernel OOPS, ideally producing a byte-correct NV12 frame stream. Re-run ampere-fourier Phase 3 with HEVC added and validate against the C1-C6 criteria.

Risk: mechanism reconstruction may be incomplete

The "non-NULL uninitialized p_cur.p" path is my best read of the kernel source, but it isn't yet test-verified. If a minimal backend patch that just registers the new CIDs (even with all-zero or dummy data) leaves the OOPS in place, the actual root cause is something else and we re-open kernel-agent#11.

Refs

  • Casanova v8 series: lkml.org/lkml/2026/1/9/1334
  • Collabora 7.0 retrospective: collabora.com/news-and-blog/news-and-events/from-panthor-to-rk3588-advancing-graphics-video-soc-support-linux-kernel-7.html
  • ampere-kernel-decoders iter1 Phase 0: ~/src/ampere-kernel-decoders/phase0_findings.md
  • Previously filed against (now closed): marfrit/kernel-agent#11
  • Backend source pin to extend from: marfrit/libva-v4l2-request-fourier @ 7ac934e
# Extend backend to populate V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS / _LT_RPS for VDPU381 HEVC ## Context Linux 7.0 (Detlev Casanova / Collabora v8 series, `lkml.org/lkml/2026/1/9/1334`) landed RK3588/RK3576 HEVC support and introduced **two new V4L2 stateless HEVC controls**: - `V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS` — short-term reference picture set parameters - `V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS` — long-term reference picture set parameters The struct definitions (`include/uapi/linux/v4l2-controls.h`): ```c #define V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS (V4L2_CID_CODEC_STATELESS_BASE + 408) #define V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS (V4L2_CID_CODEC_STATELESS_BASE + 409) struct v4l2_ctrl_hevc_ext_sps_st_rps { __u8 delta_idx_minus1; __u8 delta_rps_sign; __u8 num_negative_pics; /* ... — dynamic array sized by v4l2_ctrl_hevc_sps::num_short_term_ref_pic_sets, up to 65 elements */ __u8 flags; /* V4L2_HEVC_EXT_SPS_ST_RPS_FLAG_INTER_REF_PIC_SET_PRED */ }; ``` (LT_RPS has its own struct shape; not pasted here but defined in the same header.) The backend (`marfrit/libva-v4l2-request-fourier @ 7ac934e`, the iter38b that fresnel certified) does not know about these controls — they were added to the kernel UAPI after the backend's iter38 close. Searching the backend source confirms zero hits. ## Symptom on ampere (RK3588) `ampere-fourier` iter1 Phase 0 captured a reproducible kernel OOPS on the first HEVC decode attempt: ``` lr : rkvdec_hevc_prepare_hw_st_rps+0x38/0x300 [rockchip_vdec] Call trace: __pi_memcmp+0x10/0x110 (P) rkvdec_hevc_assemble_hw_rps+0x1c/0xac [rockchip_vdec] rkvdec_hevc_run+0x12c/0x148 [rockchip_vdec] rkvdec_device_run+0x48/0x104 [rockchip_vdec] v4l2_m2m_try_run+0x80/0x13c [v4l2_mem2mem] v4l2_m2m_request_queue+0xe8/0x140 [v4l2_mem2mem] media_request_ioctl_queue+0x1bc/0x2f4 [mc] ``` Originally filed against `marfrit/kernel-agent#11` as a kernel bug; reclassified after the ampere-kernel-decoders iter1 prior-art survey. Verified mechanism (reading the kernel source at `drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c:500-509` + `:380-410`): if `ctx->has_sps_st_rps` is set (VDPU381 variant_ops sets it), the kernel calls `v4l2_ctrl_find` for the new CID. With the control unset by userspace, the kernel may auto-allocate it with non-NULL but uninitialized `p_cur.p`. The early-return `if (!run->ext_sps_st_rps) return;` doesn't fire, and the subsequent `memcmp(cache, run->ext_sps_st_rps, sizeof(struct))` faults in `__pi_memcmp`. ## What the backend needs to do 1. Parse the HEVC bitstream's SPS for the short-term and long-term RPS tables. The relevant H.265 spec section is 7.4.8 (RPS semantics); the per-frame VAAPI `VAPictureParameterBufferHEVC` *does* carry equivalent fields, so this is a translation problem, not a new-bitstream-parsing problem. 2. Allocate a `struct v4l2_ctrl_hevc_ext_sps_st_rps[num_short_term_ref_pic_sets]` (up to 65 entries), populate from VAAPI fields, set via `VIDIOC_S_EXT_CTRLS` using `V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS`. Same for LT_RPS with the long-term equivalent. 3. Gate by driver-kind so the control is only set on VDPU381/383 — RK3399 legacy rkvdec doesn't have the control and would NAK the `S_EXT_CTRLS`. Per memory `feedback_per_driver_kludge_gating`, the gate goes on `driver_data->driver_kind`. 4. Also gate by kernel-side support (control present in the ctrl_hdl) — there's a window where libva is built against the new UAPI but the running kernel is older. Probe via `VIDIOC_QUERYCTRL` at init. ## Prerequisite: bump `linux-api-headers` on the test host ampere is currently on `linux-api-headers 6.19-1` which doesn't define the constants. Either: - Bump the host package to 7.0 (operator decision — affects whole-system UAPI consumers). - Ship a local copy of the relevant struct + CID definitions in the backend tree (campaign convention: backend already has `hevc-ctrls/` for similar shims pre-merger). Recommend the latter for now — same precedent as fresnel-fourier iter25 (`rkvdec image_fmt pre-seed`) where the backend shipped its own UAPI shim until the kernel side stabilized. ## Acceptance `LIBVA_DRIVER_NAME=v4l2_request ffmpeg -hwaccel vaapi -hwaccel_output_format vaapi -i bbb_60s_720p.hevc.mp4 -vf hwdownload -f null -` on ampere completes without kernel OOPS, ideally producing a byte-correct NV12 frame stream. Re-run ampere-fourier Phase 3 with HEVC added and validate against the C1-C6 criteria. ## Risk: mechanism reconstruction may be incomplete The "non-NULL uninitialized `p_cur.p`" path is my best read of the kernel source, but it isn't yet test-verified. If a minimal backend patch that just registers the new CIDs (even with all-zero or dummy data) leaves the OOPS in place, the actual root cause is something else and we re-open `kernel-agent#11`. ## Refs - Casanova v8 series: `lkml.org/lkml/2026/1/9/1334` - Collabora 7.0 retrospective: `collabora.com/news-and-blog/news-and-events/from-panthor-to-rk3588-advancing-graphics-video-soc-support-linux-kernel-7.html` - ampere-kernel-decoders iter1 Phase 0: `~/src/ampere-kernel-decoders/phase0_findings.md` - Previously filed against (now closed): [`marfrit/kernel-agent#11`](https://git.reauktion.de/marfrit/kernel-agent/issues/11) - Backend source pin to extend from: `marfrit/libva-v4l2-request-fourier @ 7ac934e`
Owner

@claude-noether what sources actually use HVEC typically? I use YouTube and mediathek.ard.de - if they do not use HVEC, HVEC should be outscoped and documented as such for all related projects.

@claude-noether what sources actually use HVEC typically? I use YouTube and mediathek.ard.de - if they do not use HVEC, HVEC should be outscoped and documented as such for all related projects.
Author
Collaborator

Triage 2026-05-18 + answering @marfrit's scoping question.

What actually uses HEVC

For the workloads you named:

Source Codecs in use (typical) HEVC?
YouTube VP9 (1080p–4K), AV1 (newer / high-bitrate), H.264 (legacy/mobile fallback) No — YouTube never serves HEVC, deliberately (license avoidance + their VP9/AV1 stack).
mediathek.ard.de H.264 in MP4/HLS for 90%+ of inventory. Some 4K UHD content (rare on ARD; more on ZDF + ORF) may be HEVC, but it's the exception. Mostly no. Worth one ffprobe against a 4K ARD show if you care, but the default H.264 path covers the bulk.
Netflix / Disney+ / Apple TV+ / Amazon Prime HEVC for 4K (mandatory per their UHD specs); H.264 for 1080p; AV1 starting to appear on Netflix Yes, for 4K tiers — but DRM (Widevine L1) gates these in Firefox/Chromium anyway, so the codec doesn't help here.
Local files (.mkv x265 encodes, BluRay rips, archive material) Often HEVC for size efficiency Yes — depends entirely on your collection.
Twitch, Discord video, Jitsi, BBB H.264 No
youtube-dl of Twitch/YouTube content for offline Whatever the source served (so see above) Inherits the source codec

Net: for the YouTube + Mediathek combination, HEVC on ampere has near-zero practical use today. AV1 (kernel-agent#12's sibling thread for libva-v4l2-request-fourier#2) would actually move the needle for YouTube. VP9 is the highest-volume codec for that workload.

For HEVC specifically, fresnel (RK3399) covers it cleanly — rkvdec via libva-v4l2-request-fourier iter38/iter39 produces bit-exact HEVC HW==SW including 10-bit Main10 (verified today during marfrit-packages#21 fix). If you want to decode an HEVC local file, do it on fresnel; ampere doesn't add anything for HEVC.

Implication for this issue cluster

Three currently-open HEVC-on-ampere items:

  1. This issue (libva backend EXT_SPS_*_RPS submission)
  2. kernel-agent#14 (kernel stack-uninit OOPS fix, one-liner)
  3. kernel-agent#15 (HEVC_SLICE_PARAMS registration in vdpu38x_hevc_ctrl_descs)

If HEVC on ampere is out of scope for the fleet, all three can close as won't fix — HEVC handled by fresnel; ampere's HEVC silicon stays uninitialized. The libva backend already routes HEVC profiles correctly today (per the iter38 multi-device probe), so dropping VAProfileHEVC* from ampere's vainfo just means consumers fall back to SW or use fresnel.

If HEVC on ampere is in scope (e.g. you do have local 4K HEVC files you want to play on ampere because of its bigger screen / battery), keep all three open and the priority is:

  1. kernel-agent#14 first (otherwise any HEVC decode oopses the kernel)
  2. kernel-agent#15 second (registers the controls so libva can submit them)
  3. This issue third (libva submits the controls)

Recommendation

Out-of-scope HEVC on ampere unless you can point at a concrete HEVC source in your workflow. The decision update to apply if you go that way (I can do this for you if you confirm):

  • Close this issue + kernel-agent#14 + kernel-agent#15 with consistent "HEVC out of scope for ampere; covered by fresnel" rationale + cross-links.
  • Add a memory entry under feedback_codec_scope_per_host.md (or extend an existing project doc) so future triage doesn't re-litigate.
  • Update libva-v4l2-request-fourier README + ampere section to document the scoping decision (so a future contributor doesn't waste time re-discovering this).

Confirm with a 👍 / "go" / "scope out HEVC on ampere" and I'll execute the closures + memory update. If you want to keep HEVC alive for now, comment back and I'll leave all three open as-is.

**Triage 2026-05-18 + answering @marfrit's scoping question.** ## What actually uses HEVC For the workloads you named: | Source | Codecs in use (typical) | HEVC? | |---|---|---| | YouTube | VP9 (1080p–4K), AV1 (newer / high-bitrate), H.264 (legacy/mobile fallback) | **No** — YouTube never serves HEVC, deliberately (license avoidance + their VP9/AV1 stack). | | mediathek.ard.de | H.264 in MP4/HLS for 90%+ of inventory. Some 4K UHD content (rare on ARD; more on ZDF + ORF) may be HEVC, but it's the exception. | **Mostly no.** Worth one `ffprobe` against a 4K ARD show if you care, but the default H.264 path covers the bulk. | | Netflix / Disney+ / Apple TV+ / Amazon Prime | HEVC for 4K (mandatory per their UHD specs); H.264 for 1080p; AV1 starting to appear on Netflix | **Yes**, for 4K tiers — but DRM (Widevine L1) gates these in Firefox/Chromium anyway, so the codec doesn't help here. | | Local files (.mkv x265 encodes, BluRay rips, archive material) | Often HEVC for size efficiency | **Yes** — depends entirely on your collection. | | Twitch, Discord video, Jitsi, BBB | H.264 | No | | `youtube-dl` of Twitch/YouTube content for offline | Whatever the source served (so see above) | Inherits the source codec | **Net: for the YouTube + Mediathek combination, HEVC on ampere has near-zero practical use today.** AV1 (kernel-agent#12's sibling thread for libva-v4l2-request-fourier#2) would actually move the needle for YouTube. VP9 is the highest-volume codec for that workload. For HEVC specifically, **fresnel (RK3399)** covers it cleanly — rkvdec via libva-v4l2-request-fourier iter38/iter39 produces bit-exact HEVC HW==SW including 10-bit Main10 (verified today during marfrit-packages#21 fix). If you want to decode an HEVC local file, do it on fresnel; ampere doesn't add anything for HEVC. ## Implication for this issue cluster Three currently-open HEVC-on-ampere items: 1. **This issue** (libva backend EXT_SPS_*_RPS submission) 2. [kernel-agent#14](https://git.reauktion.de/marfrit/kernel-agent/issues/14) (kernel stack-uninit OOPS fix, one-liner) 3. [kernel-agent#15](https://git.reauktion.de/marfrit/kernel-agent/issues/15) (HEVC_SLICE_PARAMS registration in vdpu38x_hevc_ctrl_descs) If HEVC on ampere is **out of scope** for the fleet, all three can close as `won't fix — HEVC handled by fresnel; ampere's HEVC silicon stays uninitialized`. The libva backend already routes HEVC profiles correctly today (per the iter38 multi-device probe), so dropping `VAProfileHEVC*` from ampere's vainfo just means consumers fall back to SW or use fresnel. If HEVC on ampere is **in scope** (e.g. you do have local 4K HEVC files you want to play on ampere because of its bigger screen / battery), keep all three open and the priority is: 1. kernel-agent#14 first (otherwise any HEVC decode oopses the kernel) 2. kernel-agent#15 second (registers the controls so libva can submit them) 3. This issue third (libva submits the controls) ## Recommendation **Out-of-scope HEVC on ampere** unless you can point at a concrete HEVC source in your workflow. The decision update to apply if you go that way (I can do this for you if you confirm): - Close this issue + kernel-agent#14 + kernel-agent#15 with consistent "HEVC out of scope for ampere; covered by fresnel" rationale + cross-links. - Add a memory entry under `feedback_codec_scope_per_host.md` (or extend an existing project doc) so future triage doesn't re-litigate. - Update libva-v4l2-request-fourier README + ampere section to document the scoping decision (so a future contributor doesn't waste time re-discovering this). Confirm with a 👍 / "go" / "scope out HEVC on ampere" and I'll execute the closures + memory update. If you want to keep HEVC alive for now, comment back and I'll leave all three open as-is.
marfrit added the EWONTFIX label 2026-05-18 09:44:37 +00:00
Author
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.
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: marfrit/libva-v4l2-request-fourier#3