Files
libva-v4l2-request-fourier/src/request_pool.c
T
test0r 565f5c0de4 context: introduce request_pool, decouple OUTPUT buffers from surfaces
Commit 3 of the upstreamable plan (upstreamable_design.md §1, §5).
Replaces the prior per-surface OUTPUT-buffer ownership model with a
small driver-wide pool sized by codec pipeline depth (4 H.264 frames
in flight), allocated unconditionally regardless of caller's
num_render_targets.

Prior art (kernel UAPI dev-stateless-decoder.rst, ffmpeg
v4l2_request.c, Chromium V4L2StatelessVideoDecoder, GStreamer
v4l2slh264dec) all decouple OUTPUT and CAPTURE pool sizing. fourier's
"output_count == surfaces_count" model was a category error: OUTPUT
buffers are request-time bitstream slots, CAPTURE buffers are
picture-time DPB slots; their lifecycles and sizing are independent.

Changes:
  * NEW src/request_pool.{c,h} (~200 LoC):
      - request_pool_init(): CREATE_BUFS + per-slot QUERYBUF + mmap.
      - request_pool_destroy(): munmap all, idempotent.
      - request_pool_acquire(): round-robin claim; returns V4L2 buffer
        index of an unused slot or -1.
      - request_pool_release(): mark slot free for reuse.
      - request_pool_slot(): accessor for ptr/size given a buffer index.

  * src/request.h: add struct request_pool output_pool to request_data.

  * src/context.c::RequestCreateContext: replace the per-surface
    OUTPUT loop with a single request_pool_init() call (count=4,
    independent of surfaces_count). Drop the now-unused locals
    (length, offset, source_data, output_buffers_count, index,
    index_base, i, surface_object). DELETES patch 0002's
    "output_buffers_count = ... ? ... : 4" hack inline — the pool's
    own count parameter supersedes it.

  * src/picture.c::RequestBeginPicture: borrow a pool slot at frame
    start, write its mmap pointer/size/index into the surface's
    transient source_* fields. The fields stay (still useful as
    a borrow handle that the existing codec_store_buffer memcpys
    target), but no longer represent surface-permanent ownership.
    Reset slices_size/slices_count here too (was implicit on first
    Render).

  * src/surface.c::RequestSyncSurface: after VIDIOC_DQBUF returns
    the OUTPUT buffer, release the pool slot and clear the surface's
    borrow handle. Fixes the segv on second-frame submission.

  * src/surface.c::RequestDestroySurfaces: remove the munmap of
    source_data — pool owns the mmap.

  * src/request.c::RequestTerminate: call request_pool_destroy()
    before close(video_fd) so munmaps still target a valid fd.

  * src/meson.build: add request_pool.c and request_pool.h to the
    sources/headers lists.

This commit removes 0002's OUTPUT-pool hack inline (the
"floor to 4" line is gone). The DECODE_MODE/START_CODE block in 0002
remains until commit 4 lands.

Build-verified clean on aarch64.

Signed-off-by: Markus Fritsche <fritsche.markus@gmail.com>
2026-05-04 09:45:05 +00:00

148 lines
3.0 KiB
C

/*
* Copyright (C) 2026 Markus Fritsche <fritsche.markus@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND.
*/
#include "request_pool.h"
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include "utils.h"
#include "v4l2.h"
int request_pool_init(struct request_pool *pool, int video_fd,
unsigned int output_type, unsigned int count)
{
unsigned int index_base;
unsigned int length;
unsigned int offset;
unsigned int i;
int rc;
if (pool == NULL || count == 0)
return -1;
if (pool->initialized)
return 0;
pool->slots = calloc(count, sizeof(*pool->slots));
if (pool->slots == NULL)
return -1;
pool->count = count;
pool->next = 0;
rc = v4l2_create_buffers(video_fd, output_type, count, &index_base);
if (rc < 0)
goto error;
for (i = 0; i < count; i++) {
pool->slots[i].index = index_base + i;
pool->slots[i].busy = false;
rc = v4l2_query_buffer(video_fd, output_type,
pool->slots[i].index,
&length, &offset, 1);
if (rc < 0)
goto error;
pool->slots[i].data = mmap(NULL, length,
PROT_READ | PROT_WRITE,
MAP_SHARED, video_fd, offset);
if (pool->slots[i].data == MAP_FAILED) {
pool->slots[i].data = NULL;
goto error;
}
pool->slots[i].size = length;
}
pool->initialized = true;
return 0;
error:
request_pool_destroy(pool);
return -1;
}
void request_pool_destroy(struct request_pool *pool)
{
unsigned int i;
if (pool == NULL || pool->slots == NULL)
return;
for (i = 0; i < pool->count; i++) {
if (pool->slots[i].data != NULL && pool->slots[i].size > 0)
munmap(pool->slots[i].data, pool->slots[i].size);
}
free(pool->slots);
pool->slots = NULL;
pool->count = 0;
pool->next = 0;
pool->initialized = false;
}
int request_pool_acquire(struct request_pool *pool)
{
unsigned int start;
unsigned int i;
if (pool == NULL || !pool->initialized || pool->count == 0)
return -1;
start = pool->next;
for (i = 0; i < pool->count; i++) {
unsigned int slot = (start + i) % pool->count;
if (!pool->slots[slot].busy) {
pool->slots[slot].busy = true;
pool->next = (slot + 1) % pool->count;
return (int)pool->slots[slot].index;
}
}
/* All slots busy; caller must wait for an in-flight DQBUF. */
return -1;
}
void request_pool_release(struct request_pool *pool, unsigned int index)
{
unsigned int i;
if (pool == NULL || pool->slots == NULL)
return;
for (i = 0; i < pool->count; i++) {
if (pool->slots[i].index == index) {
pool->slots[i].busy = false;
return;
}
}
}
struct request_pool_slot *request_pool_slot(struct request_pool *pool,
unsigned int index)
{
unsigned int i;
if (pool == NULL || pool->slots == NULL)
return NULL;
for (i = 0; i < pool->count; i++) {
if (pool->slots[i].index == index)
return &pool->slots[i];
}
return NULL;
}