From patchwork Mon Jun 29 16:30:08 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: 27123 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 F1FBAC3261 for ; Mon, 29 Jun 2026 16:31:36 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 9B31B65FB5; Mon, 29 Jun 2026 18:31:36 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="SQLqhFjL"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 53A5265F58 for ; Mon, 29 Jun 2026 18:30:31 +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 161DBE91 for ; Mon, 29 Jun 2026 18:29:48 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1782750588; bh=aRpYZWGIoniLqjhqzwyxfl+wM9XzsrE02kWnvo9W4Ls=; h=From:To:Subject:Date:In-Reply-To:References:From; b=SQLqhFjL7V73XO++PjUqLb+HswWKpOklzGAbrd1GkmNbT/f1eUWl3+an00KacGCH1 YoOcvLS3fmsM0jgZ/exBKrK3DsE//HDQWQBVBl71BpGZbjTRFlI0mv8daQsXAPz0wO wrRqun1i1N/hapc4rD22QEZMRj5sYi7/gMr82Sec= From: =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= To: libcamera-devel@lists.libcamera.org Subject: [RFC PATCH v1 45/54] v4l2: Use camera buffer pool Date: Mon, 29 Jun 2026 18:30:08 +0200 Message-ID: <20260629163017.863145-46-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" Port to using the camera's buffer pool. TODO: this is probably suboptimal in multiple respects Signed-off-by: Barnabás Pőcze --- src/v4l2/v4l2_camera.cpp | 84 ++++++++++++++++++++++++++++------------ src/v4l2/v4l2_camera.h | 4 +- 2 files changed, 63 insertions(+), 25 deletions(-) diff --git a/src/v4l2/v4l2_camera.cpp b/src/v4l2/v4l2_camera.cpp index aae9fae68c..3bcf841cd0 100644 --- a/src/v4l2/v4l2_camera.cpp +++ b/src/v4l2/v4l2_camera.cpp @@ -70,24 +70,30 @@ void V4L2Camera::unbind() void V4L2Camera::requestComplete(Request *request) { - if (request->status() == Request::RequestCancelled) - return; + bool hasBuffer = false; /* We only have one stream at the moment. */ { MutexLocker locker(bufferMutex_); - FrameBuffer *buffer = request->buffers().begin()->second; - completedBuffers_.emplace_back(buffer->cookie(), buffer->metadata()); + FrameBuffer *buffer = request->findBuffer(config_->at(0).stream()); - uint64_t data = 1; - int ret = ::write(efd_, &data, sizeof(data)); - if (ret != sizeof(data)) - LOG(V4L2Compat, Error) << "Failed to signal eventfd POLLIN"; + if (buffer) { + completedBuffers_.emplace_back(buffer->cookie(), buffer->metadata()); + + uint64_t data = 1; + int ret = ::write(efd_, &data, sizeof(data)); + if (ret != sizeof(data)) + LOG(V4L2Compat, Error) << "Failed to signal eventfd POLLIN"; + + hasBuffer = true; + } request->reuse(); + freeRequests_.push_back(request); } - bufferCV_.notify_all(); + if (hasBuffer) + bufferCV_.notify_all(); } int V4L2Camera::configure(StreamConfiguration *streamConfigOut, @@ -150,6 +156,7 @@ int V4L2Camera::allocBuffers() return ret; const auto &buffers = bufferAllocator_->buffers(stream); + MutexLocker locker(bufferMutex_); for (size_t i = 0; i < buffers.size(); i++) { std::unique_ptr request = camera_->createRequest(i); @@ -157,6 +164,7 @@ int V4L2Camera::allocBuffers() requestPool_.clear(); return -ENOMEM; } + freeRequests_.push_back(request.get()); requestPool_.push_back(std::move(request)); buffers[i]->setCookie(i); @@ -167,9 +175,15 @@ int V4L2Camera::allocBuffers() void V4L2Camera::freeBuffers() { - pendingRequests_.clear(); + { + MutexLocker locker(bufferMutex_); + freeRequests_.clear(); + } + requestPool_.clear(); + pendingBuffers_.clear(); + Stream *stream = config_->at(0).stream(); bufferAllocator_->free(stream); } @@ -199,21 +213,34 @@ int V4L2Camera::streamOn() isRunning_ = true; - for (Request *req : pendingRequests_) { + Stream *stream = config_->at(0).stream(); + + MutexLocker locker(bufferMutex_); + + for (FrameBuffer *buffer : pendingBuffers_) { + ASSERT(!pendingBuffers_.empty()); + Request *req = freeRequests_.back(); + freeRequests_.pop_back(); + + req->enableStream(stream, true); + /* \todo What should we do if this returns -EINVAL? */ ret = camera_->queueRequest(req); if (ret < 0) return ret == -EACCES ? -EBUSY : ret; + + /* \todo error handling how? */ + std::ignore = camera_->addBuffer(stream, buffer); } - pendingRequests_.clear(); + pendingBuffers_.clear(); return 0; } int V4L2Camera::streamOff() { - pendingRequests_.clear(); + pendingBuffers_.clear(); if (!isRunning_) { for (std::unique_ptr &req : requestPool_) @@ -238,33 +265,42 @@ int V4L2Camera::streamOff() int V4L2Camera::qbuf(unsigned int index) { - if (index >= requestPool_.size()) { + Stream *stream = config_->at(0).stream(); + const auto &buffers = bufferAllocator_->buffers(stream); + + if (index >= buffers.size()) { LOG(V4L2Compat, Error) << "Invalid index"; return -EINVAL; } - Request *request = requestPool_[index].get(); - Stream *stream = config_->at(0).stream(); - FrameBuffer *buffer = bufferAllocator_->buffers(stream)[index].get(); - int ret = request->addBuffer(stream, buffer); - if (ret < 0) { - LOG(V4L2Compat, Error) << "Can't set buffer for request"; - return -ENOMEM; - } + FrameBuffer *buffer = buffers[index].get(); if (!isRunning_) { - pendingRequests_.push_back(request); + pendingBuffers_.push_back(buffer); return 0; } + MutexLocker locker(bufferMutex_); + + if (freeRequests_.empty()) + return -EBUSY; + + Request *request = freeRequests_.back(); + request->controls().merge(std::move(controls_)); + request->enableStream(stream, true); - ret = camera_->queueRequest(request); + int ret = camera_->queueRequest(request); if (ret < 0) { LOG(V4L2Compat, Error) << "Can't queue request"; return ret == -EACCES ? -EBUSY : ret; } + freeRequests_.pop_back(); + + /* \todo error handling how? */ + std::ignore = camera_->addBuffer(stream, buffer); + return 0; } diff --git a/src/v4l2/v4l2_camera.h b/src/v4l2/v4l2_camera.h index 06e37077b2..f51313ef36 100644 --- a/src/v4l2/v4l2_camera.h +++ b/src/v4l2/v4l2_camera.h @@ -79,8 +79,10 @@ private: std::unique_ptr bufferAllocator_; std::vector> requestPool_; + std::vector freeRequests_ + LIBCAMERA_TSA_GUARDED_BY(bufferMutex_); - std::deque pendingRequests_; + std::deque pendingBuffers_; std::deque completedBuffers_ LIBCAMERA_TSA_GUARDED_BY(bufferMutex_);