From patchwork Wed Aug 13 10:25:00 2025 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: 24097 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 E369EBDCC1 for ; Wed, 13 Aug 2025 10:25:09 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id DB0E369250; Wed, 13 Aug 2025 12:25:07 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="t8D69gpq"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id F13686922C for ; Wed, 13 Aug 2025 12:25:04 +0200 (CEST) Received: from pb-laptop.local (185.221.141.188.nat.pool.zt.hu [185.221.141.188]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 7E0ED346 for ; Wed, 13 Aug 2025 12:24:11 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1755080651; bh=5HAUt5rRjVjrzuGazKTPnrgTw8ZKjuEOLatJGTUunxI=; h=From:To:Subject:Date:In-Reply-To:References:From; b=t8D69gpqm4rugSOx7+86rF8wTNxoFI4ulHTViRgDZOZqc5Dx+/rysXW7PHq6gDHfA lkU086kmSM+3n66xR5R3X063+iz9os/gZBjNZs0E94BPbbfOufosd2IC+zyCbSggmG rbH8ou/cSogUhS0BRy1KCwIwufBG86J/pO/P4quc= From: =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= To: libcamera-devel@lists.libcamera.org Subject: [RFC PATCH v2 1/2] libcamera: base: thread: Make `removeMessages()` public Date: Wed, 13 Aug 2025 12:25:00 +0200 Message-ID: <20250813102501.1645940-2-barnabas.pocze@ideasonboard.com> X-Mailer: git-send-email 2.50.1 In-Reply-To: <20250813102501.1645940-1-barnabas.pocze@ideasonboard.com> References: <20250813102501.1645940-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" Sometimes there is a need to remove pending messages of an object. For example, when the main purpose of a thread is to carry out work asynchronously using invoke messages, then there might be a need to stop processing because some kind of state has changed. This can be done in two main ways: flushing messages or removing them. This changes enables the second option, which is useful if the effects of the pending messages are no longer desired. Signed-off-by: Barnabás Pőcze Reviewed-by: Laurent Pinchart --- include/libcamera/base/thread.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/libcamera/base/thread.h b/include/libcamera/base/thread.h index b9284c2c0..eb1a52ab1 100644 --- a/include/libcamera/base/thread.h +++ b/include/libcamera/base/thread.h @@ -50,6 +50,7 @@ public: void dispatchMessages(Message::Type type = Message::Type::None, Object *receiver = nullptr); + void removeMessages(Object *receiver); protected: int exec(); @@ -64,7 +65,6 @@ private: void setThreadAffinityInternal(); void postMessage(std::unique_ptr msg, Object *receiver); - void removeMessages(Object *receiver); friend class Object; friend class ThreadData; From patchwork Wed Aug 13 10:25:01 2025 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: 24098 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 BBED3C3295 for ; Wed, 13 Aug 2025 10:25:10 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 5DE1369253; Wed, 13 Aug 2025 12:25:08 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="Q1b5glAw"; 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 3831D6923C for ; Wed, 13 Aug 2025 12:25:05 +0200 (CEST) Received: from pb-laptop.local (185.221.141.188.nat.pool.zt.hu [185.221.141.188]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id BDCC5351 for ; Wed, 13 Aug 2025 12:24:11 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1755080651; bh=J4gwGlh2r6YAzia66QDh6qgPCGZW/+A8kiIyyEu3Zo0=; h=From:To:Subject:Date:In-Reply-To:References:From; b=Q1b5glAwQwzp1IMdniD+QsMkvOJr804EzPvGQf4noeG/sHzjr7uJJ9FvSFFXtFafH b/hGpoBRwncSqHQr6U5v8mhCR0L56tiCu1cbmURKNU48C/+yQVrFCjwq2GckUDIe1K x+FKzO9DDw3wGycnVd1Ve/AVia5emjc9x/eIjFHs= From: =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= To: libcamera-devel@lists.libcamera.org Subject: [RFC PATCH v2 2/2] libcamera: pipeline: virtual: Move image generation to separate thread Date: Wed, 13 Aug 2025 12:25:01 +0200 Message-ID: <20250813102501.1645940-3-barnabas.pocze@ideasonboard.com> X-Mailer: git-send-email 2.50.1 In-Reply-To: <20250813102501.1645940-1-barnabas.pocze@ideasonboard.com> References: <20250813102501.1645940-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" Currently the virtual pipeline generates the images synchronously. This is not ideal because it blocks the camera manager's internal thread, and because its behaviour is different from other existing pipeline handlers, all of which complete requests asynchronously. So move the image generation to a separate thread by deriving `VirtualCameraData` from `Thread`, as well as `Object` and using the existing asynchronous signal and method call mechanism. Signed-off-by: Barnabás Pőcze Reviewed-by: Laurent Pinchart --- src/libcamera/pipeline/virtual/virtual.cpp | 87 ++++++++++++++-------- src/libcamera/pipeline/virtual/virtual.h | 9 ++- 2 files changed, 66 insertions(+), 30 deletions(-) diff --git a/src/libcamera/pipeline/virtual/virtual.cpp b/src/libcamera/pipeline/virtual/virtual.cpp index 049ebcba5..48857491d 100644 --- a/src/libcamera/pipeline/virtual/virtual.cpp +++ b/src/libcamera/pipeline/virtual/virtual.cpp @@ -107,6 +107,14 @@ private: bool initFrameGenerator(Camera *camera); + void onBufferCompleted(FrameBuffer *buffer) + { + Request *request = buffer->request(); + + if (completeBuffer(request, buffer)) + completeRequest(request); + } + DmaBufAllocator dmaBufAllocator_; bool resetCreated_ = false; @@ -129,6 +137,38 @@ VirtualCameraData::VirtualCameraData(PipelineHandler *pipe, /* \todo Support multiple streams and pass multi_stream_test */ streamConfigs_.resize(kMaxStream); + + moveToThread(this); +} + +void VirtualCameraData::queueRequest(Request *request) +{ + for (auto const &[stream, buffer] : request->buffers()) { + bool found = false; + /* map buffer and fill test patterns */ + for (auto &streamConfig : streamConfigs_) { + if (stream == &streamConfig.stream) { + FrameMetadata &fmd = buffer->_d()->metadata(); + + fmd.status = FrameMetadata::Status::FrameSuccess; + fmd.sequence = streamConfig.seq++; + fmd.timestamp = currentTimestamp(); + + for (const auto [i, p] : utils::enumerate(buffer->planes())) + fmd.planes()[i].bytesused = p.length; + + found = true; + + if (streamConfig.frameGenerator->generateFrame( + stream->configuration().size, buffer)) + fmd.status = FrameMetadata::Status::FrameError; + + bufferCompleted.emit(buffer); + break; + } + } + ASSERT(found); + } } VirtualCameraConfiguration::VirtualCameraConfiguration(VirtualCameraData *data) @@ -291,11 +331,27 @@ int PipelineHandlerVirtual::start([[maybe_unused]] Camera *camera, for (auto &s : data->streamConfigs_) s.seq = 0; + data->bufferCompleted.connect(this, &PipelineHandlerVirtual::onBufferCompleted); + data->start(); + return 0; } -void PipelineHandlerVirtual::stopDevice([[maybe_unused]] Camera *camera) +void PipelineHandlerVirtual::stopDevice(Camera *camera) { + VirtualCameraData *data = cameraData(camera); + + /* Cancel pending work. */ + data->exit(); + data->wait(); + data->removeMessages(data); + + /* Process pending `bufferCompleted` signals. */ + thread()->dispatchMessages(Message::Type::InvokeMessage, this); + data->bufferCompleted.disconnect(this); + + while (!data->queuedRequests_.empty()) + cancelRequest(data->queuedRequests_.front()); } int PipelineHandlerVirtual::queueRequestDevice([[maybe_unused]] Camera *camera, @@ -304,35 +360,8 @@ int PipelineHandlerVirtual::queueRequestDevice([[maybe_unused]] Camera *camera, VirtualCameraData *data = cameraData(camera); const auto timestamp = currentTimestamp(); - for (auto const &[stream, buffer] : request->buffers()) { - bool found = false; - /* map buffer and fill test patterns */ - for (auto &streamConfig : data->streamConfigs_) { - if (stream == &streamConfig.stream) { - FrameMetadata &fmd = buffer->_d()->metadata(); - - fmd.status = FrameMetadata::Status::FrameSuccess; - fmd.sequence = streamConfig.seq++; - fmd.timestamp = timestamp; - - for (const auto [i, p] : utils::enumerate(buffer->planes())) - fmd.planes()[i].bytesused = p.length; - - found = true; - - if (streamConfig.frameGenerator->generateFrame( - stream->configuration().size, buffer)) - fmd.status = FrameMetadata::Status::FrameError; - - completeBuffer(request, buffer); - break; - } - } - ASSERT(found); - } - request->metadata().set(controls::SensorTimestamp, timestamp); - completeRequest(request); + data->invokeMethod(&VirtualCameraData::queueRequest, ConnectionTypeQueued, request); return 0; } diff --git a/src/libcamera/pipeline/virtual/virtual.h b/src/libcamera/pipeline/virtual/virtual.h index 683cb82b4..2d83dfe54 100644 --- a/src/libcamera/pipeline/virtual/virtual.h +++ b/src/libcamera/pipeline/virtual/virtual.h @@ -11,6 +11,8 @@ #include #include +#include +#include #include #include @@ -25,7 +27,9 @@ namespace libcamera { using VirtualFrame = std::variant; -class VirtualCameraData : public Camera::Private +class VirtualCameraData : public Camera::Private, + public Thread, + public Object { public: const static unsigned int kMaxStream = 3; @@ -54,9 +58,12 @@ public: ~VirtualCameraData() = default; + void queueRequest(Request *request); + Configuration config_; std::vector streamConfigs_; + Signal bufferCompleted; }; } /* namespace libcamera */