From patchwork Mon Jun 29 16:29:51 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= X-Patchwork-Id: 27107 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 84A0CC3261 for ; Mon, 29 Jun 2026 16:31:19 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 0B3E865FA9; Mon, 29 Jun 2026 18:31:19 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="HKQYbxnZ"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 44E0365F32 for ; Mon, 29 Jun 2026 18:30:27 +0200 (CEST) Received: from pb-laptop.local (185.221.140.128.nat.pool.zt.hu [185.221.140.128]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 21F2B8D4 for ; Mon, 29 Jun 2026 18:29:44 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1782750584; bh=rKHRs0PTnPSsrt/YEvBC7o9qWbw+5n2Y4Q5hgJakESI=; h=From:To:Subject:Date:In-Reply-To:References:From; b=HKQYbxnZVlVhuPODkNQRdMBI8ULPN/qsAEZoa6DoFklSzBAutPg9bysNrHfFh646n LwrzmJrCHa0YsJPdTklueJsC9pprP6iDb0DO4eHscBKT5xhUI5yF6Iok+LDEes7Ui7 zKHRZLZFUXfUC3seTUUJdwGLlw2zrrMMM37gYjM0= From: =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= To: libcamera-devel@lists.libcamera.org Subject: [RFC PATCH v1 28/54] libcamera: pipeline_handler: Acquire buffers if not using pool Date: Mon, 29 Jun 2026 18:29:51 +0200 Message-ID: <20260629163017.863145-29-barnabas.pocze@ideasonboard.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260629163017.863145-1-barnabas.pocze@ideasonboard.com> References: <20260629163017.863145-1-barnabas.pocze@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" If the pipeline handler itself is not using the camera's buffer pool, then ensure that each stream of the request has a buffer by retrieving buffers before `queueRequestDevice()`. Additionally, try to queue the waiting requests if a buffer has been added to the pool. Signed-off-by: Barnabás Pőcze --- include/libcamera/internal/pipeline_handler.h | 4 ++ include/libcamera/internal/request.h | 2 + src/libcamera/pipeline_handler.cpp | 61 ++++++++++++++++++- src/libcamera/request.cpp | 5 ++ 4 files changed, 71 insertions(+), 1 deletion(-) diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h index e978557036..d7544642fb 100644 --- a/include/libcamera/internal/pipeline_handler.h +++ b/include/libcamera/internal/pipeline_handler.h @@ -39,6 +39,7 @@ class PipelineHandler : public std::enable_shared_from_this, public: struct Options { unsigned int maxQueuedRequestsDevice = 32; + bool usesBufferPool = false; }; PipelineHandler(CameraManager *manager, const Options &options); @@ -110,9 +111,12 @@ private: void mediaDeviceDisconnected(std::shared_ptr media); virtual void disconnect(); + [[nodiscard]] bool prepareRequest(Request *request); void doQueueRequest(Request *request); void doQueueRequests(Camera *camera); + void buffersAdded(Camera *camera); + std::vector> mediaDevices_; std::vector> cameras_; diff --git a/include/libcamera/internal/request.h b/include/libcamera/internal/request.h index 922d14f14c..f5aae3c1dc 100644 --- a/include/libcamera/internal/request.h +++ b/include/libcamera/internal/request.h @@ -29,6 +29,8 @@ public: Camera *camera() const { return camera_; } bool hasPendingBuffers() const { return pending_ > 0; } + [[nodiscard]] Request::BufferMap &buffers() { return LIBCAMERA_O_PTR()->bufferMap_; } // \todo fixme suboptimal + ControlList &metadata() { return metadata_; } bool completeBuffer(FrameBuffer *buffer); diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp index efea534649..36e1509b2b 100644 --- a/src/libcamera/pipeline_handler.cpp +++ b/src/libcamera/pipeline_handler.cpp @@ -78,6 +78,16 @@ LOG_DEFINE_CATEGORY(Pipeline) * queue, to be queued at a later stage. */ +/** + * \var PipelineHandler::Options::usesBufferPool + * \brief Whether or not the pipeline handler uses the camera's buffer pool + * + * If this option is set to \a false, then the pipeline handler base class + * will ensure that the requests have the necessary buffers when queueRequestDevice() + * is called. Otherwise it is the responsibility of the derived class to + * manage the buffers. + */ + /** * \brief Construct a PipelineHandler instance * \param[in] manager The camera manager @@ -493,6 +503,38 @@ void PipelineHandler::queueRequest(Request *request) doQueueRequests(camera); } +bool PipelineHandler::prepareRequest(Request *request) +{ + if (!options_.usesBufferPool) { + Camera *camera = request->_d()->camera(); + Camera::Private *data = camera->_d(); + auto &buffers = request->_d()->buffers(); + + ASSERT(request->_d()->pending_ == buffers.size()); + + for (auto &[stream, buffer] : buffers) { + auto it = data->streamData_.find(stream); + ASSERT(it != data->streamData_.end()); + ASSERT(it->second.active); + + if (buffer) + continue; + + auto &pool = it->second.buffers; + if (pool.empty()) + return false; + + buffer = pool.back(); + pool.pop_back(); + + buffer->_d()->setRequest(request); + buffer->_d()->stream_ = stream; + } + } + + return true; +} + /** * \brief Queue one requests to the device */ @@ -514,6 +556,9 @@ void PipelineHandler::doQueueRequest(Request *request) int ret = queueRequestDevice(camera, request); if (ret) cancelRequest(request); + // \todo what to do with buffers from pool? probably nothing? + // let's say it's the applications responsibility to process + // *all* buffers in *all* completed requests } /** @@ -530,6 +575,8 @@ void PipelineHandler::doQueueRequests(Camera *camera) break; Request *request = data->waitingRequests_.front(); + if (!prepareRequest(request)) + break; /* * Pop the request first, in case doQueueRequests() is called @@ -625,6 +672,12 @@ void PipelineHandler::cancelRequest(Request *request) completeRequest(request); } +void PipelineHandler::buffersAdded(Camera *camera) +{ + if (!options_.usesBufferPool) + doQueueRequests(camera); +} + /** * \fn PipelineHandler::addBuffer() * \brief Add buffers to the buffer pool of the camera @@ -679,18 +732,24 @@ void PipelineHandler::addBuffer(Camera *camera, << "Waiting on fence:" << buffer->_d()->fence()->fd().get() << " for stream:" << stream << " buffer:" << buffer; - it2->notifier.activated.connect(this, [=] { + it2->notifier.activated.connect(this, [=, this] { LOG(Pipeline, Debug) << "Activated fence:" << it2->buffer->_d()->fence()->fd().get() << " for stream:" << it2->stream << " buffer:" << it2->buffer; + PipelineHandler *self = this; + Camera *cam = camera; + std::ignore = it2->buffer->releaseFence(); it->second.buffers.push_back(it2->buffer); d->pendingFences_.erase(it2); /* Lambda is now destroy, no captured variable should be accessed. */ + + self->buffersAdded(cam); }); } else { it->second.buffers.push_back(buffer); + buffersAdded(camera); } } diff --git a/src/libcamera/request.cpp b/src/libcamera/request.cpp index 4df8b0f1ad..5bb1617b51 100644 --- a/src/libcamera/request.cpp +++ b/src/libcamera/request.cpp @@ -79,6 +79,11 @@ Request::Private::~Private() * otherwise */ +/** + * \fn Request::Private::buffers() + * \copydoc Request::buffers() + */ + /** * \fn Request::Private::metadata() * \brief Retrieve the request's metadata