From 393d02f4133a793410c18356f0ef6408e993896e Mon Sep 17 00:00:00 2001 From: claude-noether Date: Sat, 16 May 2026 11:08:10 +0200 Subject: [PATCH] iter2 step3: HEVC EXT_SPS_*_RPS UAPI header + runtime probe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit src/hevc-ctrls/v4l2-hevc-ext-controls.h (NEW, MIT, ~95 LOC): Verbatim mirror of Linux 7.0 V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS and _LT_RPS control IDs + struct definitions + flag macros. Each symbol is ifndef-guarded so when ampere's linux-api-headers eventually bumps to 7.0+, the kernel header takes precedence and this shim silently no-ops. Citation block links the upstream Casanova v8 series. Per LGPL section 3.b, kernel UAPI struct definitions are excepted from GPL inheritance, so copying them into MIT userspace is fine. src/request.h: added has_hevc_ext_sps_rps_rkvdec + _hantro bool fields on struct request_data — pair-of-flags layout mirrors video_fd_rkvdec / video_fd_hantro (iter38 multi-device-probe pattern, per feedback_multi_device_probe_design). Phase 5 review identified single-scalar storage as a silent-misbehavior risk across device-switch boundaries. src/request.c: - new probe_hevc_ext_sps_rps_controls(fd) helper: queries the two new CIDs via VIDIOC_QUERYCTRL; returns true iff both register. RK3399 rkvdec (linux 6.x or 7.x without VDPU381/383 bindings) returns false; RK3588 rkvdec (VDPU381/383) returns true. - probe each driver_data->video_fd_rkvdec / _hantro after the iter38 multi-device-probe block at VA_DRIVER_INIT time - log-line if rkvdec supports it - diagnostic for Phase 7 src/meson.build: added the new UAPI header to the headers list. Build verified: ninja -C build clean, .so produced. The new probe runs at driver init and stores the result, but nothing CONSUMES the result yet — that's Step 4 (h265_set_controls wiring). Per ampere-kernel-decoders campaign iter2 Phase 4 step 3 (amended by Phase 5 review item 'per-fd storage'). Co-Authored-By: Claude Opus 4.7 --- src/hevc-ctrls/v4l2-hevc-ext-controls.h | 90 +++++++++++++++++++++++++ src/meson.build | 5 ++ src/request.c | 55 +++++++++++++++ src/request.h | 20 ++++++ 4 files changed, 170 insertions(+) create mode 100644 src/hevc-ctrls/v4l2-hevc-ext-controls.h diff --git a/src/hevc-ctrls/v4l2-hevc-ext-controls.h b/src/hevc-ctrls/v4l2-hevc-ext-controls.h new file mode 100644 index 0000000..7f1e7f3 --- /dev/null +++ b/src/hevc-ctrls/v4l2-hevc-ext-controls.h @@ -0,0 +1,90 @@ +/* + * v4l2-hevc-ext-controls.h — verbatim mirror of Linux 7.0+ V4L2 stateless + * HEVC extended-SPS RPS control definitions, shipped as an internal + * header so this libva backend can be built against pre-7.0 + * linux-api-headers packages (currently ampere ships 6.19-1). + * + * Upstream source: linux kernel, include/uapi/linux/v4l2-controls.h + * As-of: Linux 7.0-rc3 (Detlev Casanova / Collabora "VDPU381/VDPU383" + * series, see lkml.org/lkml/2026/1/9/1334). The two CIDs + two structs + * + two flag macros below are byte-for-byte the kernel UAPI definitions. + * + * Once linux-api-headers >= 7.0 is the floor across the fleet, this + * shim becomes redundant — `` will provide the + * same symbols. The include order in h265.c is: this header BEFORE + * , so when the system catches up, the macro + * guards below silently no-op and we use the system definitions. + * + * License: MIT (matches backend's COPYING.MIT). Per LGPL § 3.b., the + * kernel UAPI struct definitions themselves are excepted from the + * kernel's overall GPL and may be copied verbatim into userspace + * binaries without inheriting GPL. + * + * Rationale + iter2 plan: see + * ~/src/ampere-kernel-decoders/phase4_plan_iter2.md (§Step 3) + * ~/src/ampere-kernel-decoders/phase0_findings_iter2.md + */ + +#ifndef LIBVA_V4L2_REQUEST_FOURIER_V4L2_HEVC_EXT_CONTROLS_H +#define LIBVA_V4L2_REQUEST_FOURIER_V4L2_HEVC_EXT_CONTROLS_H + +#include +#include + +#ifndef V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS +# define V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS \ + (V4L2_CID_CODEC_STATELESS_BASE + 408) +#endif + +#ifndef V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS +# define V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS \ + (V4L2_CID_CODEC_STATELESS_BASE + 409) +#endif + +#ifndef V4L2_HEVC_EXT_SPS_ST_RPS_FLAG_INTER_REF_PIC_SET_PRED +# define V4L2_HEVC_EXT_SPS_ST_RPS_FLAG_INTER_REF_PIC_SET_PRED 0x1 +#endif + +#ifndef V4L2_HEVC_EXT_SPS_LT_RPS_FLAG_USED_LT +# define V4L2_HEVC_EXT_SPS_LT_RPS_FLAG_USED_LT 0x1 +#endif + +/* + * struct v4l2_ctrl_hevc_ext_sps_st_rps — HEVC short-term RPS parameters. + * + * Dynamic-size 1-dimension array. Number of elements is + * v4l2_ctrl_hevc_sps::num_short_term_ref_pic_sets + * Can contain up to 65 elements (the H.265 spec § 7.4.3.2.1 maximum). + */ +#ifndef V4L2_HEVC_EXT_SPS_ST_RPS_DEFINED +# define V4L2_HEVC_EXT_SPS_ST_RPS_DEFINED 1 +struct v4l2_ctrl_hevc_ext_sps_st_rps { + __u8 delta_idx_minus1; + __u8 delta_rps_sign; + __u8 num_negative_pics; + __u8 num_positive_pics; + __u32 used_by_curr_pic; + __u32 use_delta_flag; + __u16 abs_delta_rps_minus1; + __u16 delta_poc_s0_minus1[16]; + __u16 delta_poc_s1_minus1[16]; + __u16 flags; +}; +#endif + +/* + * struct v4l2_ctrl_hevc_ext_sps_lt_rps — HEVC long-term RPS parameters. + * + * Dynamic-size 1-dimension array. Number of elements is + * v4l2_ctrl_hevc_sps::num_long_term_ref_pics_sps + * Can contain up to 33 elements (the H.265 spec § 7.4.3.2.1 maximum). + */ +#ifndef V4L2_HEVC_EXT_SPS_LT_RPS_DEFINED +# define V4L2_HEVC_EXT_SPS_LT_RPS_DEFINED 1 +struct v4l2_ctrl_hevc_ext_sps_lt_rps { + __u16 lt_ref_pic_poc_lsb_sps; + __u16 flags; +}; +#endif + +#endif /* LIBVA_V4L2_REQUEST_FOURIER_V4L2_HEVC_EXT_CONTROLS_H */ diff --git a/src/meson.build b/src/meson.build index 5e5f5f7..c05b63e 100644 --- a/src/meson.build +++ b/src/meson.build @@ -89,6 +89,11 @@ headers = [ 'codec.h', 'nv15.h', + # Internal mirror of Linux 7.0 V4L2 HEVC EXT_SPS_*_RPS UAPI defs + # (allows building against pre-7.0 linux-api-headers; redundant + # once the host headers are 7.0+). + 'hevc-ctrls/v4l2-hevc-ext-controls.h', + # Vendored GStreamer + project shim headers (see sources above). 'h265_parser/gst_compat.h', 'h265_parser/gst/gst.h', diff --git a/src/request.c b/src/request.c index 0e1661b..20884be 100644 --- a/src/request.c +++ b/src/request.c @@ -57,6 +57,8 @@ #include #include +#include "hevc-ctrls/v4l2-hevc-ext-controls.h" + /* * fresnel-fourier iter4 Phase 6 commit Z + iter7 Phase 6 (B1a): device-path * auto-detect via media controller topology with decoder-entity discrimination. @@ -286,6 +288,43 @@ out: * - non-NULL → match only that exact driver name * - NULL → match any name in known_decoder_drivers[] */ +/* + * iter2 (ampere-kernel-decoders campaign) — runtime probe for the + * V4L2 stateless HEVC EXT_SPS_{ST,LT}_RPS controls added in + * Linux 7.0 (Casanova VDPU381/VDPU383 series). Returns true iff BOTH + * controls are registered on the given fd. Stored per-fd on + * driver_data so the multi-device-probe model (iter38) doesn't + * silently misbehave when codec routing switches devices. + * + * The two CIDs together are the gate — neither alone is meaningful + * without the other (st-RPS + lt-RPS arrays both need to be set to + * match the SPS num_short_term_ref_pic_sets / num_long_term_ref_pics_sps + * counts). Old kernels (RK3399 rkvdec on linux 6.x) register neither; + * RK3588 rkvdec (VDPU381/383 path) registers both. + * + * Reference: phase4_plan_iter2.md §Step 3 in + * ~/src/ampere-kernel-decoders/. + */ +static bool probe_hevc_ext_sps_rps_controls(int video_fd) +{ + struct v4l2_queryctrl q; + + if (video_fd < 0) + return false; + + memset(&q, 0, sizeof(q)); + q.id = V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS; + if (ioctl(video_fd, VIDIOC_QUERYCTRL, &q) < 0) + return false; + + memset(&q, 0, sizeof(q)); + q.id = V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS; + if (ioctl(video_fd, VIDIOC_QUERYCTRL, &q) < 0) + return false; + + return true; +} + static int find_decoder_device_by_driver(const char *want_driver, char *video_out, size_t video_out_sz, char *media_out, size_t media_out_sz) @@ -644,6 +683,22 @@ VAStatus VA_DRIVER_INIT_FUNC(VADriverContextP context) (void)primary_driver; } + /* + * iter2 (ampere-kernel-decoders): probe the new HEVC EXT_SPS_RPS + * controls on each rkvdec/hantro fd. Result is consumed by + * h265_set_controls per-codec gate. Per-fd storage matches the + * iter38 multi-device-probe pattern (Phase 5 review item). + */ + driver_data->has_hevc_ext_sps_rps_rkvdec = + probe_hevc_ext_sps_rps_controls(driver_data->video_fd_rkvdec); + driver_data->has_hevc_ext_sps_rps_hantro = + probe_hevc_ext_sps_rps_controls(driver_data->video_fd_hantro); + if (driver_data->has_hevc_ext_sps_rps_rkvdec) { + request_log("iter2: kernel registers HEVC EXT_SPS_{ST,LT}_RPS " + "controls on rkvdec fd (will route through " + "vendored GStreamer parser)\n"); + } + status = VA_STATUS_SUCCESS; goto complete; diff --git a/src/request.h b/src/request.h index 9bd92ca..e2b4c86 100644 --- a/src/request.h +++ b/src/request.h @@ -77,6 +77,26 @@ struct request_data { int video_fd_hantro; int media_fd_hantro; + /* + * iter2 (ampere-kernel-decoders campaign) — per-fd probe result + * for the V4L2_CID_STATELESS_HEVC_EXT_SPS_{ST,LT}_RPS controls + * introduced in Linux 7.0 (Casanova VDPU381/VDPU383 series). + * RK3399 rkvdec doesn't have them and the probe returns false; + * RK3588 rkvdec (VDPU381/383) registers them and the probe is + * true. h265_set_controls consults only the rkvdec entry because + * HEVC routes through rkvdec only — hantro's entry stays false + * naturally (it doesn't have rkvdec-specific controls). + * + * The pair-of-flags layout mirrors video_fd_rkvdec / + * video_fd_hantro above (iter38 multi-device-probe pattern, + * memory feedback_multi_device_probe_design). Phase 5 review + * surfaced this as a correctness item: a single scalar on + * driver_data would silently misbehave across device-switch + * boundaries; per-fd storage is the safe shape. + */ + bool has_hevc_ext_sps_rps_rkvdec; + bool has_hevc_ext_sps_rps_hantro; + struct video_format *video_format; /*