iter5 Track E: move LAST_OUTPUT_WIDTH/HEIGHT from process-global to per-driver-data
Sonnet review 7.3 / 9.6 from iter1 + carried iter2/3/4 substrate. Two libva driver_data instances in the same process (e.g. Firefox playing two tabs at different resolutions, or Firefox + mpv via the same dlopened backend) would race on the static cache. Move to struct request_data.last_output_width/height. The V4L2 device fd is already per-driver_data, so this is the correct binding unit (one fd, one current OUTPUT format). Verified: two concurrent mpv processes (2s stagger) both decode 300 frames cleanly with no cross-corruption. Same-instant init still hits kernel-level fd contention on /dev/video1 (hantro is a single-instance device); cross-process serialization is out of scope for a libva backend. Resolves the surface_reset_format_cache() callsite: now takes driver_data parameter (was zero-arg). Also drops the 'rc' unused-variable warning in v4l2_ioctl_controls that the iter5 sweep left behind. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+29
-25
@@ -48,31 +48,34 @@
|
||||
#include "video.h"
|
||||
|
||||
/*
|
||||
* Per-process cache of the OUTPUT format we've set. The previous
|
||||
* SET_FORMAT_OF_OUTPUT_ONCE pattern was a latent bug (Sonnet Phase 5
|
||||
* review finding 7.3): mpv probes with small surfaces (e.g. 128x128)
|
||||
* before requesting the real resolution (e.g. 1920x1088). The
|
||||
* once-only set kept the OUTPUT — and consequently the kernel-derived
|
||||
* CAPTURE — format pinned to the probe size. Subsequent
|
||||
* v4l2_get_format on CAPTURE then returned the small format, the
|
||||
* VADRMPRIMESurfaceDescriptor was filled with width=1920 height=1088
|
||||
* but pitch=128 offset=16384, and Mesa rejected the import with
|
||||
* "WSI pitch too small." That manifested as the solid-blue render in
|
||||
* mpv vaapi mode and the SW fallback in Firefox after frame 0.
|
||||
* Per-driver-data cache of the OUTPUT format we've set on the V4L2
|
||||
* device. iter5 Track E: was process-global static
|
||||
* LAST_OUTPUT_WIDTH/HEIGHT before this commit. See request.h
|
||||
* struct request_data.last_output_width/height for the rationale.
|
||||
*
|
||||
* Fix: track (width, height) and re-set the OUTPUT format whenever
|
||||
* the resolution changes. Re-setting requires REQBUFS(0) on both
|
||||
* queues first because S_FMT after CREATE_BUFS is rejected by V4L2;
|
||||
* we tear down and let the next allocation cycle recreate buffers
|
||||
* at the new resolution.
|
||||
* The previous SET_FORMAT_OF_OUTPUT_ONCE pattern was a latent bug
|
||||
* (Sonnet Phase 5 review finding 7.3): mpv probes with small surfaces
|
||||
* (e.g. 128x128) before requesting the real resolution (e.g.
|
||||
* 1920x1088). The once-only set kept the OUTPUT — and consequently
|
||||
* the kernel-derived CAPTURE — format pinned to the probe size.
|
||||
* Subsequent v4l2_get_format on CAPTURE then returned the small
|
||||
* format, the VADRMPRIMESurfaceDescriptor was filled with width=1920
|
||||
* height=1088 but pitch=128 offset=16384, and Mesa rejected the
|
||||
* import with "WSI pitch too small." That manifested as the
|
||||
* solid-blue render in mpv vaapi mode and the SW fallback in Firefox
|
||||
* after frame 0.
|
||||
*
|
||||
* Fix: track (width, height) per driver_data and re-set the OUTPUT
|
||||
* format whenever the resolution changes. Re-setting requires
|
||||
* REQBUFS(0) on both queues first because S_FMT after CREATE_BUFS is
|
||||
* rejected by V4L2; we tear down and let the next allocation cycle
|
||||
* recreate buffers at the new resolution.
|
||||
*/
|
||||
static unsigned int LAST_OUTPUT_WIDTH = 0;
|
||||
static unsigned int LAST_OUTPUT_HEIGHT = 0;
|
||||
|
||||
void surface_reset_format_cache(void)
|
||||
void surface_reset_format_cache(struct request_data *driver_data)
|
||||
{
|
||||
LAST_OUTPUT_WIDTH = 0;
|
||||
LAST_OUTPUT_HEIGHT = 0;
|
||||
driver_data->last_output_width = 0;
|
||||
driver_data->last_output_height = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -170,7 +173,8 @@ VAStatus RequestCreateSurfaces2(VADriverContextP context, unsigned int format,
|
||||
unsigned int pixelformat = V4L2_PIX_FMT_H264_SLICE;
|
||||
unsigned int output_type = v4l2_type_video_output(true);
|
||||
|
||||
if (LAST_OUTPUT_WIDTH != width || LAST_OUTPUT_HEIGHT != height) {
|
||||
if (driver_data->last_output_width != width ||
|
||||
driver_data->last_output_height != height) {
|
||||
/*
|
||||
* If we've previously allocated buffers at a different
|
||||
* resolution, tear them down on BOTH queues before re-setting
|
||||
@@ -189,7 +193,7 @@ VAStatus RequestCreateSurfaces2(VADriverContextP context, unsigned int format,
|
||||
* cap_pool_init below is skipped, and the slots' v4l2_index
|
||||
* fields point to dead buffers from the prior resolution.
|
||||
*/
|
||||
if (LAST_OUTPUT_WIDTH != 0) {
|
||||
if (driver_data->last_output_width != 0) {
|
||||
if (driver_data->capture_pool.initialized)
|
||||
cap_pool_destroy(&driver_data->capture_pool,
|
||||
driver_data->video_fd,
|
||||
@@ -206,8 +210,8 @@ VAStatus RequestCreateSurfaces2(VADriverContextP context, unsigned int format,
|
||||
if (rc < 0)
|
||||
return VA_STATUS_ERROR_OPERATION_FAILED;
|
||||
|
||||
LAST_OUTPUT_WIDTH = width;
|
||||
LAST_OUTPUT_HEIGHT = height;
|
||||
driver_data->last_output_width = width;
|
||||
driver_data->last_output_height = height;
|
||||
}
|
||||
|
||||
if (format != VA_RT_FORMAT_YUV420)
|
||||
|
||||
Reference in New Issue
Block a user