ampere-av1 Phase 2 step 1: third-device fd scaffolding for vpu981

RK3588 has THREE hantro-vpu instances (legacy MPEG2/VP8 at /dev/video2,
encoder at /dev/video3, vpu981 AV1 at /dev/video4). The existing
2-device probe is "RK3399-shaped knowledge" — silently picks the first
hantro-vpu and never finds vpu981.

This commit adds:
- video_fd_vpu981 + media_fd_vpu981 slots to request_data
- video_node_supports_output_fmt(): capability probe via VIDIOC_ENUM_FMT
  on OUTPUT/OUTPUT_MPLANE queues
- find_decoder_device_by_driver_with_fmt(): walks /dev/media* matching
  driver name AND capability filter (V4L2_PIX_FMT_AV1_FRAME for vpu981)
- 'a' kind in request_device_kind_for_profile (VAProfileAV1Profile0)
- 'a' branch in request_switch_device_for_profile
- vpu981 probe at backend init, alongside existing rkvdec + hantro
- vpu981 fd cleanup in RequestTerminate
- VAProfileAV1Profile0 → V4L2_PIX_FMT_AV1_FRAME in codec.c

Verified on ampere:

  $ LIBVA_DRIVER_NAME=v4l2_request ffmpeg ... 2>&1 | grep iter38
  v4l2-request: auto-selected codec device: /dev/video1 + /dev/media0
  v4l2-request: iter38: also opened hantro-vpu decoder at /dev/video2 + /dev/media1
  v4l2-request: ampere-av1: vpu981 AV1 decoder at /dev/video4 + /dev/media3

Three devices opened. HEVC still works (iter2 EXT_SPS_RPS probe still
triggers on rkvdec, sibling-campaign bit-perfect behaviour preserved).

Next steps: config.c advertise VAProfileAV1Profile0, surface.h add
av1 substruct, picture.c dispatch, av1.{c,h} for the codec dispatch
(~700 LoC mirroring Kwiboo v4l2_request_av1.c).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
claude-noether
2026-05-17 09:53:37 +02:00
parent 1a2c958ab3
commit bed75c0cef
3 changed files with 154 additions and 1 deletions
+2
View File
@@ -44,6 +44,8 @@ unsigned int pixelformat_for_profile(VAProfile profile)
return V4L2_PIX_FMT_VP8_FRAME; return V4L2_PIX_FMT_VP8_FRAME;
case VAProfileVP9Profile0: case VAProfileVP9Profile0:
return V4L2_PIX_FMT_VP9_FRAME; return V4L2_PIX_FMT_VP9_FRAME;
case VAProfileAV1Profile0:
return V4L2_PIX_FMT_AV1_FRAME;
default: default:
return 0; return 0;
} }
+138 -1
View File
@@ -325,6 +325,37 @@ static bool probe_hevc_ext_sps_rps_controls(int video_fd)
return true; return true;
} }
/*
* Inspect a /dev/videoN's OUTPUT formats for `want_pixfmt`. Returns true
* iff at least one OUTPUT/OUTPUT_MPLANE format matches.
*
* Used to discriminate between multiple devices sharing a driver name —
* RK3588 has 3 hantro-vpu instances and only one of them is vpu981 (the
* dedicated AV1 decoder advertising V4L2_PIX_FMT_AV1_FRAME).
*/
static bool video_node_supports_output_fmt(int video_fd, uint32_t want_pixfmt)
{
struct v4l2_fmtdesc desc;
const enum v4l2_buf_type types[] = {
V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
V4L2_BUF_TYPE_VIDEO_OUTPUT,
};
unsigned int t, i;
for (t = 0; t < sizeof(types) / sizeof(types[0]); t++) {
for (i = 0; i < 64; i++) {
memset(&desc, 0, sizeof desc);
desc.index = i;
desc.type = types[t];
if (ioctl(video_fd, VIDIOC_ENUM_FMT, &desc) < 0)
break;
if (desc.pixelformat == want_pixfmt)
return true;
}
}
return false;
}
static int find_decoder_device_by_driver(const char *want_driver, static int find_decoder_device_by_driver(const char *want_driver,
char *video_out, size_t video_out_sz, char *video_out, size_t video_out_sz,
char *media_out, size_t media_out_sz) char *media_out, size_t media_out_sz)
@@ -372,6 +403,65 @@ static int find_decoder_device_by_driver(const char *want_driver,
return -1; return -1;
} }
/*
* ampere-av1-enablement Phase 2 — like find_decoder_device_by_driver but
* additionally verifies the resolved /dev/videoN advertises `want_pixfmt`
* as an OUTPUT format. Required for RK3588 where 3 hantro-vpu instances
* share the driver name but only one is vpu981 (AV1 decoder).
*
* Walks all /dev/media* with matching driver name; takes the first hit
* whose OUTPUT formats include `want_pixfmt`. Non-matching candidates
* (encoder-only nodes, legacy hantro for MPEG2/VP8) are skipped.
*/
static int find_decoder_device_by_driver_with_fmt(const char *want_driver,
uint32_t want_pixfmt,
char *video_out,
size_t video_out_sz,
char *media_out,
size_t media_out_sz)
{
struct media_device_info info;
char path[32];
char vpath[32];
int fd, vfd, i;
for (i = 0; i < 16; i++) {
snprintf(path, sizeof path, "/dev/media%d", i);
fd = open(path, O_RDWR | O_NONBLOCK);
if (fd < 0)
continue;
memset(&info, 0, sizeof info);
if (ioctl(fd, MEDIA_IOC_DEVICE_INFO, &info) != 0) {
close(fd);
continue;
}
if (strcmp(info.driver, want_driver) != 0) {
close(fd);
continue;
}
if (find_decoder_video_node_via_topology(fd, vpath,
sizeof vpath) != 0) {
close(fd);
continue;
}
close(fd);
/* Capability check: does this /dev/videoN advertise the
* codec-specific OUTPUT format? */
vfd = open(vpath, O_RDWR | O_NONBLOCK);
if (vfd < 0)
continue;
if (video_node_supports_output_fmt(vfd, want_pixfmt)) {
close(vfd);
snprintf(video_out, video_out_sz, "%s", vpath);
snprintf(media_out, media_out_sz, "%s", path);
return 0;
}
close(vfd);
}
return -1;
}
static int find_codec_device(char *video_out, size_t video_out_sz, static int find_codec_device(char *video_out, size_t video_out_sz,
char *media_out, size_t media_out_sz) char *media_out, size_t media_out_sz)
{ {
@@ -408,6 +498,8 @@ char request_device_kind_for_profile(VAProfile profile)
case VAProfileMPEG2Main: case VAProfileMPEG2Main:
case VAProfileVP8Version0_3: case VAProfileVP8Version0_3:
return 'h'; return 'h';
case VAProfileAV1Profile0:
return 'a'; /* ampere-av1-enablement: vpu981 dedicated AV1 */
default: default:
return '?'; return '?';
} }
@@ -437,6 +529,9 @@ int request_switch_device_for_profile(struct request_data *driver_data,
} else if (kind == 'h') { } else if (kind == 'h') {
target_video = driver_data->video_fd_hantro; target_video = driver_data->video_fd_hantro;
target_media = driver_data->media_fd_hantro; target_media = driver_data->media_fd_hantro;
} else if (kind == 'a') {
target_video = driver_data->video_fd_vpu981;
target_media = driver_data->media_fd_vpu981;
} else { } else {
return -1; return -1;
} }
@@ -624,6 +719,8 @@ VAStatus VA_DRIVER_INIT_FUNC(VADriverContextP context)
driver_data->media_fd_rkvdec = -1; driver_data->media_fd_rkvdec = -1;
driver_data->video_fd_hantro = -1; driver_data->video_fd_hantro = -1;
driver_data->media_fd_hantro = -1; driver_data->media_fd_hantro = -1;
driver_data->video_fd_vpu981 = -1;
driver_data->media_fd_vpu981 = -1;
/* /*
* iter38: probe BOTH rkvdec and hantro-vpu so a single libva session * iter38: probe BOTH rkvdec and hantro-vpu so a single libva session
@@ -681,6 +778,40 @@ VAStatus VA_DRIVER_INIT_FUNC(VADriverContextP context)
} }
} }
(void)primary_driver; (void)primary_driver;
/*
* ampere-av1-enablement Phase 2 — additionally probe for
* vpu981 (RK3588's dedicated AV1 decoder). Driver name
* "hantro-vpu" alone is ambiguous on RK3588 (3 instances:
* legacy MPEG2/VP8, encoder, vpu981 AV1). Discriminate by
* V4L2_PIX_FMT_AV1_FRAME capability. If the primary or alt
* hantro happens to BE vpu981 (unlikely but possible on
* non-RK3588 boards), this probe finds it again and we just
* dedupe via the fd value.
*/
{
static char av1_video[32], av1_media[32];
if (find_decoder_device_by_driver_with_fmt(
"hantro-vpu", V4L2_PIX_FMT_AV1_FRAME,
av1_video, sizeof av1_video,
av1_media, sizeof av1_media) == 0) {
int av1_v = open(av1_video, O_RDWR | O_NONBLOCK);
int av1_m = (av1_v >= 0)
? open(av1_media, O_RDWR | O_NONBLOCK)
: -1;
if (av1_v >= 0 && av1_m >= 0) {
driver_data->video_fd_vpu981 = av1_v;
driver_data->media_fd_vpu981 = av1_m;
request_log(
"ampere-av1: vpu981 AV1 decoder "
"at %s + %s\n",
av1_video, av1_media);
} else {
if (av1_v >= 0) close(av1_v);
if (av1_m >= 0) close(av1_m);
}
}
}
} }
/* /*
@@ -745,9 +876,15 @@ VAStatus RequestTerminate(VADriverContextP context)
close(driver_data->video_fd_hantro); close(driver_data->video_fd_hantro);
if (driver_data->media_fd_hantro >= 0) if (driver_data->media_fd_hantro >= 0)
close(driver_data->media_fd_hantro); close(driver_data->media_fd_hantro);
if (driver_data->video_fd_vpu981 >= 0)
close(driver_data->video_fd_vpu981);
if (driver_data->media_fd_vpu981 >= 0)
close(driver_data->media_fd_vpu981);
/* Fall back to direct close if neither alt fd captured the active /* Fall back to direct close if neither alt fd captured the active
* pair (env-override path). */ * pair (env-override path). */
if (driver_data->video_fd_rkvdec < 0 && driver_data->video_fd_hantro < 0) { if (driver_data->video_fd_rkvdec < 0 &&
driver_data->video_fd_hantro < 0 &&
driver_data->video_fd_vpu981 < 0) {
if (driver_data->video_fd >= 0) if (driver_data->video_fd >= 0)
close(driver_data->video_fd); close(driver_data->video_fd);
if (driver_data->media_fd >= 0) if (driver_data->media_fd >= 0)
+14
View File
@@ -79,6 +79,20 @@ struct request_data {
int video_fd_hantro; int video_fd_hantro;
int media_fd_hantro; int media_fd_hantro;
/*
* ampere-av1-enablement Phase 2 vpu981 is a THIRD physical
* hantro-vpu instance on RK3588 (separate from the legacy MPEG2/VP8
* hantro at /dev/video2). It's the dedicated AV1 decoder at
* /dev/video4 with card name "rockchip,rk3588-av1-vpu-dec".
*
* Driver-name alone ("hantro-vpu") is ambiguous on RK3588 three
* instances share the name. The probe discriminates by capability:
* which OUTPUT format does the device advertise? Only vpu981
* exposes V4L2_PIX_FMT_AV1_FRAME.
*/
int video_fd_vpu981;
int media_fd_vpu981;
/* /*
* iter2 (ampere-kernel-decoders campaign) per-fd probe result * iter2 (ampere-kernel-decoders campaign) per-fd probe result
* for the V4L2_CID_STATELESS_HEVC_EXT_SPS_{ST,LT}_RPS controls * for the V4L2_CID_STATELESS_HEVC_EXT_SPS_{ST,LT}_RPS controls