From 3ca1e20b3d38a7009c9c604eabe5b10ca5df0606 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. (cherry picked from commit 22ddb88072656209a36e99635d2f3520a44e4e40) --- 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 874ed4885..9f665c523 100644 --- a/spa/plugins/libcamera/libcamera-source.cpp +++ b/spa/plugins/libcamera/libcamera-source.cpp @@ -1010,14 +1010,44 @@ done: return res; } +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) { @@ -1037,37 +1067,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,