From 22ddb88072656209a36e99635d2f3520a44e4e40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barnab=C3=A1s=20P=C5=91cze?= Date: Fri, 25 Jul 2025 20:18:15 +0200 Subject: [PATCH] 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. --- spa/plugins/libcamera/libcamera-source.cpp | 74 ++++++++++++---------- 1 file changed, 40 insertions(+), 34 deletions(-) diff --git a/spa/plugins/libcamera/libcamera-source.cpp b/spa/plugins/libcamera/libcamera-source.cpp index 75913ec90..d2fe8043f 100644 --- a/spa/plugins/libcamera/libcamera-source.cpp +++ b/spa/plugins/libcamera/libcamera-source.cpp @@ -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(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) { struct impl *impl = (struct impl*) source->data; - struct spa_io_buffers *io; - struct port *port = &impl->out_ports[0]; - uint32_t index, buffer_id; - struct buffer *b; + uint32_t index; uint64_t cnt; if (source->rmask & SPA_IO_ERR) { @@ -1039,37 +1069,13 @@ void libcamera_on_fd_events(struct spa_source *source) return; } - if (spa_ringbuffer_get_read_index(&impl->completed_requests_rb, &index) < 1) { - spa_log_error(impl->log, "nothing is queued"); - return; + auto avail = spa_ringbuffer_get_read_index(&impl->completed_requests_rb, &index); + for (; avail > 0; avail--, index++) { + 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,