spa: libcamera: source: process all requests in the ring buffer

It is possible that multiple requests complete before the data loop can run
`libcamera_on_fd_events()`. However, previously only the earliest item was
processed from the ring buffer, meaning that in those cases request processing
could be lagging request completion by multiple requests.

Fix that by getting the number of available requests and processing them all.
This commit is contained in:
Barnabás Pőcze 2025-07-25 20:18:15 +02:00
parent c01a2977a5
commit 22ddb88072

View file

@ -1012,14 +1012,44 @@ int spa_libcamera_apply_controls(struct impl *impl, libcamera::ControlList&& con
); );
} }
void handle_completed_request(struct impl *impl, libcamera::Request *request)
{
const auto request_id = request->cookie();
struct port *port = &impl->out_ports[0];
buffer *b = &port->buffers[request_id];
spa_log_trace(impl->log, "%p: request %p[%" PRIu64 "] process status:%u seq:%" PRIu32,
impl, request, request_id, static_cast<unsigned int>(request->status()),
request->sequence());
spa_list_append(&port->queue, &b->link);
spa_io_buffers *io = port->io;
if (io == nullptr) {
b = spa_list_first(&port->queue, struct buffer, link);
spa_list_remove(&b->link);
SPA_FLAG_SET(b->flags, BUFFER_FLAG_OUTSTANDING);
spa_libcamera_buffer_recycle(impl, port, b->id);
} else if (io->status != SPA_STATUS_HAVE_DATA) {
if (io->buffer_id < port->n_buffers)
spa_libcamera_buffer_recycle(impl, port, io->buffer_id);
b = spa_list_first(&port->queue, struct buffer, link);
spa_list_remove(&b->link);
SPA_FLAG_SET(b->flags, BUFFER_FLAG_OUTSTANDING);
io->buffer_id = b->id;
io->status = SPA_STATUS_HAVE_DATA;
spa_log_trace(impl->log, "%p: now queued %" PRIu32, impl, b->id);
}
spa_node_call_ready(&impl->callbacks, SPA_STATUS_HAVE_DATA);
}
void libcamera_on_fd_events(struct spa_source *source) void libcamera_on_fd_events(struct spa_source *source)
{ {
struct impl *impl = (struct impl*) source->data; struct impl *impl = (struct impl*) source->data;
struct spa_io_buffers *io; uint32_t index;
struct port *port = &impl->out_ports[0];
uint32_t index, buffer_id;
struct buffer *b;
uint64_t cnt; uint64_t cnt;
if (source->rmask & SPA_IO_ERR) { if (source->rmask & SPA_IO_ERR) {
@ -1039,37 +1069,13 @@ void libcamera_on_fd_events(struct spa_source *source)
return; return;
} }
if (spa_ringbuffer_get_read_index(&impl->completed_requests_rb, &index) < 1) { auto avail = spa_ringbuffer_get_read_index(&impl->completed_requests_rb, &index);
spa_log_error(impl->log, "nothing is queued"); for (; avail > 0; avail--, index++) {
return; auto *request = impl->completed_requests[index & MASK_BUFFERS];
spa_ringbuffer_read_update(&impl->completed_requests_rb, index + 1);
handle_completed_request(impl, request);
} }
auto *request = impl->completed_requests[index & MASK_BUFFERS];
spa_ringbuffer_read_update(&impl->completed_requests_rb, index + 1);
buffer_id = request->cookie();
b = &port->buffers[buffer_id];
spa_list_append(&port->queue, &b->link);
io = port->io;
if (io == nullptr) {
b = spa_list_first(&port->queue, struct buffer, link);
spa_list_remove(&b->link);
SPA_FLAG_SET(b->flags, BUFFER_FLAG_OUTSTANDING);
spa_libcamera_buffer_recycle(impl, port, b->id);
} else if (io->status != SPA_STATUS_HAVE_DATA) {
if (io->buffer_id < port->n_buffers)
spa_libcamera_buffer_recycle(impl, port, io->buffer_id);
b = spa_list_first(&port->queue, struct buffer, link);
spa_list_remove(&b->link);
SPA_FLAG_SET(b->flags, BUFFER_FLAG_OUTSTANDING);
io->buffer_id = b->id;
io->status = SPA_STATUS_HAVE_DATA;
spa_log_trace(impl->log, "libcamera %p: now queued %d", impl, b->id);
}
spa_node_call_ready(&impl->callbacks, SPA_STATUS_HAVE_DATA);
} }
int spa_libcamera_use_buffers(struct impl *impl, struct port *port, int spa_libcamera_use_buffers(struct impl *impl, struct port *port,