fresnel-fourier iter5b-β Phase 7 fix-forward commit D: destination_* for vaapi-copy late-surface flow
Phase 7 empirical: all 5 libva codecs returned all-zero because CreateContext's surfaces_ids[] walk was a no-op for ffmpeg-vaapi-copy which passes surfaces_count=0 to vaCreateContext (per the iter6 comment at context.c:262). Surfaces existed in driver_data's surface_heap but weren't in the param array → destination_* stayed at the zero initialization from CreateSurfaces2 β → BeginPicture's surface_bind_slot saw destination_planes_count=0 → no data assignment → copy_surface_to_image read all-zero. Fix: cache the format-uniform CAPTURE geometry in driver_data (fmt_valid, fmt_planes_count, fmt_buffers_count, fmt_format_height, fmt_sizes[], fmt_bytesperlines[]). Populate at CreateContext after v4l2_get_format(CAPTURE). Walk surface_heap (not just surfaces_ids[]) to fill every existing surface. Add lazy-fill in CreateSurfaces2 for surfaces created AFTER CreateContext. Invalidate cache in DestroyContext. New helper: surface_fill_format_uniform(driver_data, surface_object). Idempotent on destination_planes_count != 0. Signed-off-by: claude-noether <claude-noether@reauktion.de>
This commit is contained in:
+44
-34
@@ -54,7 +54,6 @@ VAStatus RequestCreateContext(VADriverContextP context, VAConfigID config_id,
|
||||
struct request_data *driver_data = context->pDriverData;
|
||||
struct object_config *config_object;
|
||||
struct object_context *context_object = NULL;
|
||||
struct object_surface *surface_object;
|
||||
struct video_format *video_format;
|
||||
unsigned int destination_sizes[VIDEO_MAX_PLANES];
|
||||
unsigned int destination_bytesperlines[VIDEO_MAX_PLANES];
|
||||
@@ -65,7 +64,7 @@ VAStatus RequestCreateContext(VADriverContextP context, VAConfigID config_id,
|
||||
VAContextID id;
|
||||
VAStatus status;
|
||||
unsigned int output_type, capture_type;
|
||||
unsigned int i, j;
|
||||
unsigned int j;
|
||||
bool found;
|
||||
int rc;
|
||||
|
||||
@@ -196,7 +195,7 @@ VAStatus RequestCreateContext(VADriverContextP context, VAConfigID config_id,
|
||||
|
||||
/*
|
||||
* Compute format-uniform destination_* values. Same for all
|
||||
* surfaces of this format; written once per surface here, never
|
||||
* surfaces of this format; written once per surface, never
|
||||
* changed by BeginPicture's slot acquisition.
|
||||
*/
|
||||
if (video_format->v4l2_buffers_count == 1) {
|
||||
@@ -207,39 +206,44 @@ VAStatus RequestCreateContext(VADriverContextP context, VAConfigID config_id,
|
||||
}
|
||||
|
||||
/*
|
||||
* Walk surfaces_ids and populate the format-uniform fields on each
|
||||
* object_surface. CreateSurfaces2 (β) left these zeroed.
|
||||
* iter5b-β Commit D: cache the format-uniform CAPTURE geometry
|
||||
* in driver_data. CreateSurfaces2 calls AFTER this CreateContext
|
||||
* (ffmpeg vaapi-copy late-surface-allocation case) will lazy-fill
|
||||
* via surface_fill_format_uniform(); the surface_heap walk below
|
||||
* fills surfaces that pre-existed when CreateContext fired.
|
||||
*/
|
||||
for (i = 0; i < (unsigned int)surfaces_count; i++) {
|
||||
surface_object = SURFACE(driver_data, surfaces_ids[i]);
|
||||
if (surface_object == NULL) {
|
||||
status = VA_STATUS_ERROR_INVALID_SURFACE;
|
||||
goto error;
|
||||
}
|
||||
surface_object->destination_planes_count = destination_planes_count;
|
||||
surface_object->destination_buffers_count =
|
||||
video_format->v4l2_buffers_count;
|
||||
driver_data->fmt_planes_count = destination_planes_count;
|
||||
driver_data->fmt_buffers_count = video_format->v4l2_buffers_count;
|
||||
driver_data->fmt_format_height = format_height;
|
||||
for (j = 0; j < destination_planes_count; j++) {
|
||||
driver_data->fmt_sizes[j] = destination_sizes[j];
|
||||
driver_data->fmt_bytesperlines[j] =
|
||||
destination_bytesperlines[j];
|
||||
}
|
||||
driver_data->fmt_valid = true;
|
||||
|
||||
if (video_format->v4l2_buffers_count == 1) {
|
||||
for (j = 0; j < destination_planes_count; j++) {
|
||||
surface_object->destination_offsets[j] =
|
||||
j > 0 ? destination_sizes[j - 1] : 0;
|
||||
surface_object->destination_sizes[j] =
|
||||
destination_sizes[j];
|
||||
surface_object->destination_bytesperlines[j] =
|
||||
destination_bytesperlines[0];
|
||||
}
|
||||
} else if (video_format->v4l2_buffers_count == destination_planes_count) {
|
||||
for (j = 0; j < destination_planes_count; j++) {
|
||||
surface_object->destination_offsets[j] = 0;
|
||||
surface_object->destination_sizes[j] =
|
||||
destination_sizes[j];
|
||||
surface_object->destination_bytesperlines[j] =
|
||||
destination_bytesperlines[j];
|
||||
}
|
||||
} else {
|
||||
status = VA_STATUS_ERROR_ALLOCATION_FAILED;
|
||||
goto error;
|
||||
/*
|
||||
* Walk the surface_heap (not just surfaces_ids[]) to populate
|
||||
* destination_* on every existing surface. Pre-Commit-D we walked
|
||||
* surfaces_ids[], which is empty for ffmpeg vaapi-copy consumers
|
||||
* that call vaCreateContext with surfaces_count=0 — those surfaces
|
||||
* exist in the heap but aren't in the param array. Walking the
|
||||
* heap catches both flows. Late-created surfaces (after this
|
||||
* CreateContext) fill via surface_fill_format_uniform in
|
||||
* CreateSurfaces2's per-surface init.
|
||||
*/
|
||||
{
|
||||
struct object_surface *surface_iter;
|
||||
int heap_iter;
|
||||
|
||||
surface_iter = (struct object_surface *)
|
||||
object_heap_first(&driver_data->surface_heap,
|
||||
&heap_iter);
|
||||
while (surface_iter != NULL) {
|
||||
surface_fill_format_uniform(driver_data, surface_iter);
|
||||
surface_iter = (struct object_surface *)
|
||||
object_heap_next(&driver_data->surface_heap,
|
||||
&heap_iter);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -500,7 +504,13 @@ VAStatus RequestDestroyContext(VADriverContextP context, VAContextID context_id)
|
||||
* β doesn't have a last_output_{width,height,pixelformat} cache
|
||||
* (those fields are deleted). Each CreateContext is a fresh
|
||||
* S_FMT(OUTPUT) cycle.
|
||||
*
|
||||
* Commit D: invalidate the format-uniform cache so a CreateSurfaces2
|
||||
* call between DestroyContext and the next CreateContext doesn't
|
||||
* lazy-fill with stale geometry from the now-torn-down session.
|
||||
* The next CreateContext re-populates the cache.
|
||||
*/
|
||||
driver_data->fmt_valid = false;
|
||||
|
||||
return VA_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -90,7 +90,28 @@ struct request_data {
|
||||
* which is naturally one-shot per context cycle; no caching is
|
||||
* required. DestroyContext + next CreateContext rebuild from
|
||||
* scratch.
|
||||
*
|
||||
* iter5b-β Commit D: cache the format-uniform CAPTURE-side
|
||||
* geometry from v4l2_get_format so CreateSurfaces2 can populate
|
||||
* a newly-created surface's destination_* fields without
|
||||
* re-querying the device. Set by CreateContext after the
|
||||
* v4l2_get_format(CAPTURE) call; consumed by both:
|
||||
* 1. CreateContext's surface_heap walk (fills surfaces that
|
||||
* pre-exist when CreateContext fires);
|
||||
* 2. CreateSurfaces2's per-surface init (fills surfaces
|
||||
* created AFTER CreateContext, e.g. ffmpeg vaapi-copy
|
||||
* pool dynamics where the consumer passes surfaces_count=0
|
||||
* to vaCreateContext and creates surfaces lazily).
|
||||
*
|
||||
* fmt_valid is true once CreateContext has populated the cache;
|
||||
* CreateSurfaces2 only lazy-fills when fmt_valid is true.
|
||||
*/
|
||||
bool fmt_valid;
|
||||
unsigned int fmt_format_height;
|
||||
unsigned int fmt_planes_count;
|
||||
unsigned int fmt_buffers_count;
|
||||
unsigned int fmt_sizes[VIDEO_MAX_PLANES];
|
||||
unsigned int fmt_bytesperlines[VIDEO_MAX_PLANES];
|
||||
};
|
||||
|
||||
VAStatus VA_DRIVER_INIT_FUNC(VADriverContextP context);
|
||||
|
||||
@@ -115,6 +115,44 @@ void surface_unbind_slot(struct request_data *driver_data,
|
||||
surface_object->current_slot = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* iter5b-β Commit D: fill format-uniform destination_* on a surface
|
||||
* from driver_data's CAPTURE-format cache. Idempotent: no-op if
|
||||
* destination_planes_count is non-zero already.
|
||||
*/
|
||||
void surface_fill_format_uniform(struct request_data *driver_data,
|
||||
struct object_surface *surface_object)
|
||||
{
|
||||
unsigned int j;
|
||||
|
||||
if (!driver_data->fmt_valid)
|
||||
return;
|
||||
if (surface_object->destination_planes_count != 0)
|
||||
return;
|
||||
|
||||
surface_object->destination_planes_count = driver_data->fmt_planes_count;
|
||||
surface_object->destination_buffers_count = driver_data->fmt_buffers_count;
|
||||
|
||||
if (driver_data->fmt_buffers_count == 1) {
|
||||
for (j = 0; j < driver_data->fmt_planes_count; j++) {
|
||||
surface_object->destination_offsets[j] =
|
||||
j > 0 ? driver_data->fmt_sizes[j - 1] : 0;
|
||||
surface_object->destination_sizes[j] =
|
||||
driver_data->fmt_sizes[j];
|
||||
surface_object->destination_bytesperlines[j] =
|
||||
driver_data->fmt_bytesperlines[0];
|
||||
}
|
||||
} else if (driver_data->fmt_buffers_count == driver_data->fmt_planes_count) {
|
||||
for (j = 0; j < driver_data->fmt_planes_count; j++) {
|
||||
surface_object->destination_offsets[j] = 0;
|
||||
surface_object->destination_sizes[j] =
|
||||
driver_data->fmt_sizes[j];
|
||||
surface_object->destination_bytesperlines[j] =
|
||||
driver_data->fmt_bytesperlines[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VAStatus RequestCreateSurfaces2(VADriverContextP context, unsigned int format,
|
||||
unsigned int width, unsigned int height,
|
||||
VASurfaceID *surfaces_ids,
|
||||
@@ -173,6 +211,17 @@ VAStatus RequestCreateSurfaces2(VADriverContextP context, unsigned int format,
|
||||
|
||||
surface_object->request_fd = -1;
|
||||
|
||||
/*
|
||||
* iter5b-β Commit D: if CreateContext has already populated
|
||||
* the format-uniform cache (driver_data->fmt_valid), fill
|
||||
* the new surface's destination_* immediately. This covers
|
||||
* the case where a consumer creates more surfaces AFTER
|
||||
* CreateContext. The first batch of surfaces (created before
|
||||
* CreateContext) gets filled by CreateContext's surface_heap
|
||||
* walk; this lazy-fill handles late arrivals.
|
||||
*/
|
||||
surface_fill_format_uniform(driver_data, surface_object);
|
||||
|
||||
surfaces_ids[i] = id;
|
||||
}
|
||||
|
||||
|
||||
@@ -165,6 +165,27 @@ VAStatus RequestExportSurfaceHandle(VADriverContextP context,
|
||||
VASurfaceID surface_id, uint32_t mem_type,
|
||||
uint32_t flags, void *descriptor);
|
||||
|
||||
/*
|
||||
* iter5b-β Commit D: populate a surface's format-uniform destination_*
|
||||
* fields (planes_count, buffers_count, offsets, sizes, bytesperlines)
|
||||
* from driver_data's cached CAPTURE-side geometry. Idempotent: skip
|
||||
* if already filled (destination_planes_count != 0). Caller must
|
||||
* ensure driver_data->fmt_valid is true (CreateContext has run).
|
||||
*
|
||||
* Called by:
|
||||
* - context.c::RequestCreateContext after v4l2_get_format(CAPTURE)
|
||||
* populates the cache; walks the surface_heap and fills every
|
||||
* existing surface (covers surfaces created before CreateContext,
|
||||
* including the ffmpeg vaapi-copy case where surfaces_count=0 is
|
||||
* passed but surfaces exist in the heap from earlier
|
||||
* CreateSurfaces2 calls).
|
||||
* - surface.c::RequestCreateSurfaces2 after surface allocation,
|
||||
* covering the case where CreateContext fired before this
|
||||
* CreateSurfaces2 call (fmt cache is valid, fill immediately).
|
||||
*/
|
||||
void surface_fill_format_uniform(struct request_data *driver_data,
|
||||
struct object_surface *surface_object);
|
||||
|
||||
/*
|
||||
* Iter2 Fix 3: bind / unbind a CAPTURE-pool slot to an object_surface.
|
||||
* Called from picture.c::RequestBeginPicture (acquire+bind) and
|
||||
|
||||
Reference in New Issue
Block a user