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:
@@ -44,6 +44,8 @@ unsigned int pixelformat_for_profile(VAProfile profile)
|
||||
return V4L2_PIX_FMT_VP8_FRAME;
|
||||
case VAProfileVP9Profile0:
|
||||
return V4L2_PIX_FMT_VP9_FRAME;
|
||||
case VAProfileAV1Profile0:
|
||||
return V4L2_PIX_FMT_AV1_FRAME;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
+138
-1
@@ -325,6 +325,37 @@ static bool probe_hevc_ext_sps_rps_controls(int video_fd)
|
||||
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,
|
||||
char *video_out, size_t video_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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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,
|
||||
char *media_out, size_t media_out_sz)
|
||||
{
|
||||
@@ -408,6 +498,8 @@ char request_device_kind_for_profile(VAProfile profile)
|
||||
case VAProfileMPEG2Main:
|
||||
case VAProfileVP8Version0_3:
|
||||
return 'h';
|
||||
case VAProfileAV1Profile0:
|
||||
return 'a'; /* ampere-av1-enablement: vpu981 dedicated AV1 */
|
||||
default:
|
||||
return '?';
|
||||
}
|
||||
@@ -437,6 +529,9 @@ int request_switch_device_for_profile(struct request_data *driver_data,
|
||||
} else if (kind == 'h') {
|
||||
target_video = driver_data->video_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 {
|
||||
return -1;
|
||||
}
|
||||
@@ -624,6 +719,8 @@ VAStatus VA_DRIVER_INIT_FUNC(VADriverContextP context)
|
||||
driver_data->media_fd_rkvdec = -1;
|
||||
driver_data->video_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
|
||||
@@ -681,6 +778,40 @@ VAStatus VA_DRIVER_INIT_FUNC(VADriverContextP context)
|
||||
}
|
||||
}
|
||||
(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);
|
||||
if (driver_data->media_fd_hantro >= 0)
|
||||
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
|
||||
* 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)
|
||||
close(driver_data->video_fd);
|
||||
if (driver_data->media_fd >= 0)
|
||||
|
||||
@@ -79,6 +79,20 @@ struct request_data {
|
||||
int video_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
|
||||
* for the V4L2_CID_STATELESS_HEVC_EXT_SPS_{ST,LT}_RPS controls
|
||||
|
||||
Reference in New Issue
Block a user