From patchwork Mon Oct 5 13:16:56 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 28397 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 501E8C3316 for ; Mon, 5 Oct 2026 13:17:16 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id E0C49689E9; Mon, 5 Oct 2026 15:17:15 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="OE96mGeY"; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id AB77F689CA for ; Mon, 5 Oct 2026 15:17:13 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1791206232; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=ZqaV868B9IGPt2wkYIjC/ZuRbXMp08QZwY08fThbV30=; b=OE96mGeYH1lYeIZ3aF64r4GchgTtKLcd4VkGFkjxivEx+yg56JR4fBa1pZCeX5GFIJamZM 8niCGFxXIgdADfg8C8EnHoeXxgzJbCA12XGUdZiUx5WIG8TlJ7ycRBOeD5lAabV/18No7q NxZyERDho4/z1XXAEiNh9eyFiwXZQPs= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-128-J4WeskhrNHm_wXmcNn0X2w-1; Mon, 05 Oct 2026 09:17:09 -0400 X-MC-Unique: J4WeskhrNHm_wXmcNn0X2w-1 X-Mimecast-MFC-AGG-ID: J4WeskhrNHm_wXmcNn0X2w_1791206228 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 1EEB41800EFA; Mon, 5 Oct 2026 13:17:08 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.redhat.corp (headnet03.pony-001.prod.iad2.dc.redhat.com [10.2.32.114]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id EEFE7180057F; Mon, 5 Oct 2026 13:17:06 +0000 (UTC) From: Milan Zamazal To: libcamera-devel@lists.libcamera.org Cc: Milan Zamazal , Kieran Bingham Subject: [PATCH 1/3] libcamera: software_isp: Use shared stats Date: Mon, 5 Oct 2026 15:16:56 +0200 Message-ID: <20261005131700.97438-2-mzamazal@redhat.com> In-Reply-To: <20261005131700.97438-1-mzamazal@redhat.com> References: <20261005131700.97438-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: 61UlhjRRUfAwKUuX3n-CTyqibNzBNkiuDPr5Rag88aw_1791206228 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true 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" The SwStatsCpu instance created in SoftwareIsp is currently moved to the corresponding debayering object. This binds the stats to debayering, but we'd like to be able to use stats with raw output as well. Let's keep the created stats in SoftwareIsp as a shared pointer that is still passed to the debayering objects but remains accessible outside them. This also allows us to get rid of Debayer::getStatsFD method. Signed-off-by: Milan Zamazal --- .../libcamera/internal/software_isp/software_isp.h | 2 ++ src/libcamera/software_isp/debayer.cpp | 10 ---------- src/libcamera/software_isp/debayer.h | 2 -- src/libcamera/software_isp/debayer_cpu.cpp | 2 +- src/libcamera/software_isp/debayer_cpu.h | 5 ++--- src/libcamera/software_isp/debayer_egl.cpp | 2 +- src/libcamera/software_isp/debayer_egl.h | 6 ++---- src/libcamera/software_isp/software_isp.cpp | 12 ++++++------ 8 files changed, 14 insertions(+), 27 deletions(-) diff --git a/include/libcamera/internal/software_isp/software_isp.h b/include/libcamera/internal/software_isp/software_isp.h index b8b24bb1b..7c41bc7ad 100644 --- a/include/libcamera/internal/software_isp/software_isp.h +++ b/include/libcamera/internal/software_isp/software_isp.h @@ -33,6 +33,7 @@ #include "libcamera/internal/pipeline_handler.h" #include "libcamera/internal/shared_mem_object.h" #include "libcamera/internal/software_isp/debayer_params.h" +#include "libcamera/internal/software_isp/swstats_cpu.h" namespace libcamera { @@ -101,6 +102,7 @@ private: DebayerParams debayerParams_; DmaBufAllocator dmaHeap_; bool ccmEnabled_; + std::shared_ptr stats_; std::unique_ptr ipa_; std::deque queuedInputBuffers_; diff --git a/src/libcamera/software_isp/debayer.cpp b/src/libcamera/software_isp/debayer.cpp index a4854e51b..7a151fa14 100644 --- a/src/libcamera/software_isp/debayer.cpp +++ b/src/libcamera/software_isp/debayer.cpp @@ -132,16 +132,6 @@ Debayer::~Debayer() * \return The valid size ranges or an empty range if there are none */ -/** - * \fn const SharedFD &Debayer::getStatsFD() - * \brief Get the file descriptor for the statistics - * - * This file descriptor provides access to the output statistics buffer - * associated with the current debayering process. - * - * \return The file descriptor pointing to the statistics data - */ - /** * \fn unsigned int Debayer::frameSize() * \brief Get the output frame size diff --git a/src/libcamera/software_isp/debayer.h b/src/libcamera/software_isp/debayer.h index 556852260..2287ce995 100644 --- a/src/libcamera/software_isp/debayer.h +++ b/src/libcamera/software_isp/debayer.h @@ -54,8 +54,6 @@ public: virtual SizeRange sizes(PixelFormat inputFormat, const Size &inputSize) = 0; - virtual const SharedFD &getStatsFD() = 0; - unsigned int frameSize() { return outputConfig_.frameSize; } Signal inputBufferReady; diff --git a/src/libcamera/software_isp/debayer_cpu.cpp b/src/libcamera/software_isp/debayer_cpu.cpp index ce8b3c647..022e56a3d 100644 --- a/src/libcamera/software_isp/debayer_cpu.cpp +++ b/src/libcamera/software_isp/debayer_cpu.cpp @@ -93,7 +93,7 @@ DebayerCpuThread::DebayerCpuThread(DebayerCpu *debayer, unsigned int threadIndex * \param[in] stats Pointer to the stats object to use * \param[in] cm The camera manager */ -DebayerCpu::DebayerCpu(std::unique_ptr stats, const CameraManager &cm) +DebayerCpu::DebayerCpu(std::shared_ptr stats, const CameraManager &cm) : Debayer(cm), stats_(std::move(stats)) { /* diff --git a/src/libcamera/software_isp/debayer_cpu.h b/src/libcamera/software_isp/debayer_cpu.h index 2c88c9e1a..1190216fb 100644 --- a/src/libcamera/software_isp/debayer_cpu.h +++ b/src/libcamera/software_isp/debayer_cpu.h @@ -32,7 +32,7 @@ class DebayerCpuThread; class DebayerCpu : public Debayer { public: - DebayerCpu(std::unique_ptr stats, const CameraManager &cm); + DebayerCpu(std::shared_ptr stats, const CameraManager &cm); ~DebayerCpu(); int configure(const StreamConfiguration &inputCfg, @@ -46,7 +46,6 @@ public: int start() override; void stop() override; SizeRange sizes(PixelFormat inputFormat, const Size &inputSize) override; - const SharedFD &getStatsFD() override { return stats_->getStatsFD(); } private: friend class DebayerCpuThread; @@ -153,7 +152,7 @@ private: debayerFn debayer2_; debayerFn debayer3_; Rectangle window_; - std::unique_ptr stats_; + std::shared_ptr stats_; unsigned int xShift_; /* Offset of 0/1 applied to window_.x */ static constexpr unsigned int kMinThreads = 1; diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp index 300822f9d..df294d6d6 100644 --- a/src/libcamera/software_isp/debayer_egl.cpp +++ b/src/libcamera/software_isp/debayer_egl.cpp @@ -42,7 +42,7 @@ namespace libcamera { * \param[in] cm The camera manager * \param[in] display The EGL display to use */ -DebayerEGL::DebayerEGL(std::unique_ptr stats, const CameraManager &cm, EGLDisplay display) +DebayerEGL::DebayerEGL(std::shared_ptr stats, const CameraManager &cm, EGLDisplay display) : Debayer(cm), stats_(std::move(stats)), egl_(display) { } diff --git a/src/libcamera/software_isp/debayer_egl.h b/src/libcamera/software_isp/debayer_egl.h index 30e51a477..ffa4f61a4 100644 --- a/src/libcamera/software_isp/debayer_egl.h +++ b/src/libcamera/software_isp/debayer_egl.h @@ -40,7 +40,7 @@ class CameraManager; class DebayerEGL : public Debayer { public: - DebayerEGL(std::unique_ptr stats, const CameraManager &cm, EGLDisplay display); + DebayerEGL(std::shared_ptr stats, const CameraManager &cm, EGLDisplay display); ~DebayerEGL(); int configure(const StreamConfiguration &inputCfg, @@ -57,8 +57,6 @@ public: int start() override; void stop() override; - const SharedFD &getStatsFD() override { return stats_->getStatsFD(); } - SizeRange sizes(PixelFormat inputFormat, const Size &inputSize) override; private: @@ -112,7 +110,7 @@ private: Size nativeOutputSize_; Rectangle window_; - std::unique_ptr stats_; + std::shared_ptr stats_; eGL egl_; uint32_t width_; uint32_t height_; diff --git a/src/libcamera/software_isp/software_isp.cpp b/src/libcamera/software_isp/software_isp.cpp index a40976055..46a7cb5c1 100644 --- a/src/libcamera/software_isp/software_isp.cpp +++ b/src/libcamera/software_isp/software_isp.cpp @@ -98,12 +98,12 @@ SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, const CameraSensor *sensor, const CameraManager &cm = *pipe->cameraManager(); - auto stats = std::make_unique(cm); - if (!stats->isValid()) { + stats_ = std::make_shared(cm); + if (!stats_->isValid()) { LOG(SoftwareIsp, Error) << "Failed to create SwStatsCpu object"; return; } - stats->statsReady.connect(this, &SoftwareIsp::statsReady); + stats_->statsReady.connect(this, &SoftwareIsp::statsReady); #if HAVE_DEBAYER_EGL const GlobalConfiguration &configuration = cm._d()->configuration(); @@ -121,7 +121,7 @@ SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, const CameraSensor *sensor, if (!softISPMode || softISPMode == "gpu") { auto display = eGL::probeDisplay(); if (display != EGL_NO_DISPLAY) { - debayer_ = std::make_unique(std::move(stats), cm, display); + debayer_ = std::make_unique(stats_, cm, display); } else { LOG(SoftwareIsp, Info) << "EGL not available, falling back to CPU debayer"; @@ -130,7 +130,7 @@ SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, const CameraSensor *sensor, #endif if (!debayer_) - debayer_ = std::make_unique(std::move(stats), cm); + debayer_ = std::make_unique(stats_, cm); debayer_->inputBufferReady.connect(this, &SoftwareIsp::inputReady); debayer_->outputBufferReady.connect(this, &SoftwareIsp::outputReady); @@ -158,7 +158,7 @@ SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, const CameraSensor *sensor, } ret = ipa_->init(IPASettings{ ipaTuningFile, sensor->model() }, - debayer_->getStatsFD(), + stats_->getStatsFD(), sharedParams_.fd(), sensorInfo, sensor->controls(), From patchwork Mon Oct 5 13:16:57 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 28399 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 71EC6C3357 for ; Mon, 5 Oct 2026 13:17:20 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 4849A68A4C; Mon, 5 Oct 2026 15:17:19 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="Dbz4OpDq"; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 553BE689E9 for ; Mon, 5 Oct 2026 15:17:15 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1791206234; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=T+Ex6QelgClmAbj0l+lKSSHufG7fswHpJ9MX2GGVjSk=; b=Dbz4OpDq+dN4sYEEmnlRAmPMGSIoZtxBFTk2EcQodbbN3ET6fZLGPrtKk5QeBDEB7XxM+K 3Io7uzbt04fHv7yjOFKBcg8Fc1teR/nl1roUzIkrBC3wOEZpRlwCZPDAZrmpCneSrk4Wg6 nzdV9VojNRxqy0KIAoyRkX373yD16MU= Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-280-sFL2H4dnPdmwlqhROvV9ag-1; Mon, 05 Oct 2026 09:17:10 -0400 X-MC-Unique: sFL2H4dnPdmwlqhROvV9ag-1 X-Mimecast-MFC-AGG-ID: sFL2H4dnPdmwlqhROvV9ag_1791206230 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id D4B561955F61; Mon, 5 Oct 2026 13:17:09 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.redhat.corp (headnet03.pony-001.prod.iad2.dc.redhat.com [10.2.32.114]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 98C0E180057F; Mon, 5 Oct 2026 13:17:08 +0000 (UTC) From: Milan Zamazal To: libcamera-devel@lists.libcamera.org Cc: Milan Zamazal , Kieran Bingham Subject: [PATCH 2/3] libcamera: software_isp: Separate IPA start/stop Date: Mon, 5 Oct 2026 15:16:57 +0200 Message-ID: <20261005131700.97438-3-mzamazal@redhat.com> In-Reply-To: <20261005131700.97438-1-mzamazal@redhat.com> References: <20261005131700.97438-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: jpV6sCVyOus6zlaUrapOtYDq57ejDWqMaSqyFaSdxiE_1791206230 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true 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" The SoftwareIsp start() and stop() methods start both the IPA and debayering. Let's isolate the IPA start and stop into separate methods. This allows starting just the softisp IPA from the simple pipeline, which is useful to get information from the IPA even with only raw output. Signed-off-by: Milan Zamazal --- .../internal/software_isp/software_isp.h | 3 ++ src/libcamera/software_isp/software_isp.cpp | 28 +++++++++++++++++-- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/include/libcamera/internal/software_isp/software_isp.h b/include/libcamera/internal/software_isp/software_isp.h index 7c41bc7ad..3e420242b 100644 --- a/include/libcamera/internal/software_isp/software_isp.h +++ b/include/libcamera/internal/software_isp/software_isp.h @@ -78,6 +78,9 @@ public: int start(); void stop(); + int startIpa(); + void stopIpa(); + void queueRequest(const uint32_t frame, const ControlList &controls); int queueBuffers(uint32_t frame, FrameBuffer *input, const std::map &outputs); diff --git a/src/libcamera/software_isp/software_isp.cpp b/src/libcamera/software_isp/software_isp.cpp index 46a7cb5c1..11e0c49ed 100644 --- a/src/libcamera/software_isp/software_isp.cpp +++ b/src/libcamera/software_isp/software_isp.cpp @@ -378,7 +378,7 @@ int SoftwareIsp::queueBuffers(uint32_t frame, FrameBuffer *input, */ int SoftwareIsp::start() { - int ret = ipa_->start(); + int ret = startIpa(); if (ret) return ret; @@ -388,6 +388,19 @@ int SoftwareIsp::start() ConnectionTypeBlocking); } +/** + * \brief Starts the software ISP IPA + * + * Only the IPA is started here. If you want full software ISP with debayering, + * use \a start() instead. + * + * \return 0 on success, any other value indicates an error + */ +int SoftwareIsp::startIpa() +{ + return ipa_->start(); +} + /** * \brief Stops the Software ISP streaming operation * @@ -409,7 +422,7 @@ void SoftwareIsp::stop() Thread::current()->dispatchMessages(Message::Type::InvokeMessage, this); - ipa_->stop(); + stopIpa(); for (auto buffer : queuedOutputBuffers_) { buffer->_d()->cancel(); @@ -424,6 +437,17 @@ void SoftwareIsp::stop() queuedInputBuffers_.clear(); } +/** + * \brief Stops the software ISP IPA + * + * Only the IPA is stopped here. If you stop full software ISP with debayering, + * use \a stop() instead. + */ +void SoftwareIsp::stopIpa() +{ + ipa_->stop(); +} + /** * \brief Passes the input framebuffer to the ISP worker to process * \param[in] frame The frame number From patchwork Mon Oct 5 13:16:58 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 28398 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 0C95EC3307 for ; Mon, 5 Oct 2026 13:17:18 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 8D15D68A6F; Mon, 5 Oct 2026 15:17:18 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="bgmGUFlC"; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 04B91689CA for ; Mon, 5 Oct 2026 15:17:14 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1791206234; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=PuyNnw4KphmFcRuS+7L/07tcEWwlRwrznx25T5HcG9o=; b=bgmGUFlCZ9+HX7dF/VVL126I4xa2rob4tSjXLI0n0G2Xc3jj6mLdfFKaRoy/KSznwvOYci n5uhaw/ytQgpQTCFbdhLlaf+3beb4R2kq/38l8jU+yJl1ZSy6m7udnfntewSnzPyL9dQYR BcfUH+McT2+/0CErC5PmzLwLD9asqW4= Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-176-S02687liNXGKMaeTuvQEhg-1; Mon, 05 Oct 2026 09:17:12 -0400 X-MC-Unique: S02687liNXGKMaeTuvQEhg-1 X-Mimecast-MFC-AGG-ID: S02687liNXGKMaeTuvQEhg_1791206231 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 62AA11956050; Mon, 5 Oct 2026 13:17:11 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.redhat.corp (headnet03.pony-001.prod.iad2.dc.redhat.com [10.2.32.114]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 3F45E1800592; Mon, 5 Oct 2026 13:17:10 +0000 (UTC) From: Milan Zamazal To: libcamera-devel@lists.libcamera.org Cc: Milan Zamazal , Kieran Bingham Subject: [PATCH 3/3] libcamera: software_isp: Allow running IPA and stats on raw Date: Mon, 5 Oct 2026 15:16:58 +0200 Message-ID: <20261005131700.97438-4-mzamazal@redhat.com> In-Reply-To: <20261005131700.97438-1-mzamazal@redhat.com> References: <20261005131700.97438-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: kjBXWM4w1yU-7iqMr_Wd4-KbZr1Rf1aFnnl2SbAuEzc_1791206231 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true 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" `simple' pipeline can basically pass raw buffers from V4L2 to the output. While the raw data is untouched, we may still want to: - Gather statistics from it. - Run IPA on the images (without modifying the images). - Provide metadata from the IPA. - Adjust exposure/gain. This patch implements all of that. Since this imposes some overhead, a new configuration option pipelines.simple.enable_raw_ipa is added. The option is on by default as at least the metadata and exposure adjustments may be useful. Using a configuration option rather than a runtime-adjustable option is not perfect, but I don't know what better mechanism to use. The patch attempts to fit into the current structure as close as possible, with minimum changes. Future enhancements might include computing the stats asynchronously or even splitting `simple' pipeline into separate components (debayering, converter, raw output). Signed-off-by: Milan Zamazal --- Documentation/runtime_configuration.rst | 10 +++++ .../internal/software_isp/software_isp.h | 3 +- src/libcamera/pipeline/simple/simple.cpp | 36 ++++++++++++++--- src/libcamera/software_isp/software_isp.cpp | 40 ++++++++++++++++--- 4 files changed, 77 insertions(+), 12 deletions(-) diff --git a/Documentation/runtime_configuration.rst b/Documentation/runtime_configuration.rst index a71b715a1..1d93ad3a8 100644 --- a/Documentation/runtime_configuration.rst +++ b/Documentation/runtime_configuration.rst @@ -46,6 +46,7 @@ file structure: supported_devices: - driver: # driver name, e.g. `mxc-isi` software_isp: # true/false + enable_raw_ipa: # true/false software_isp: copy_input_buffer: # true/false measure: @@ -81,6 +82,7 @@ Configuration file example supported_devices: - driver: mxc-isi software_isp: true + enable_raw_ipa: true software_isp: copy_input_buffer: false measure: @@ -157,6 +159,14 @@ pipelines.simple.supported_devices.driver, pipelines.simple.supported_devices.so Example `software_isp` value: ``true`` +pipelines.simple.enable_raw_ipa + Whether image processing algorithms are enabled also with raw-only + output. When enabled, statistics is gathered for raw-only output, + image processing algorithms are run on it, metadata is produced and + exposure is adjusted. + + Example value: ``true`` + software_isp.copy_input_buffer Define whether input buffers should be copied into standard (cached) memory in software ISP. This is done by default to prevent very slow diff --git a/include/libcamera/internal/software_isp/software_isp.h b/include/libcamera/internal/software_isp/software_isp.h index 3e420242b..b4c57dbf5 100644 --- a/include/libcamera/internal/software_isp/software_isp.h +++ b/include/libcamera/internal/software_isp/software_isp.h @@ -67,7 +67,8 @@ public: int configure(const StreamConfiguration &inputCfg, const std::vector> &outputCfgs, const ipa::softisp::IPAConfigInfo &configInfo, - ControlInfoMap *ipaControls); + ControlInfoMap *ipaControls, + bool debayerEnabled); int exportBuffers(const Stream *stream, unsigned int count, std::vector> *buffers); diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp index 35c29ceca..dd1d69a5b 100644 --- a/src/libcamera/pipeline/simple/simple.cpp +++ b/src/libcamera/pipeline/simple/simple.cpp @@ -427,6 +427,7 @@ public: V4L2Subdevice *subdev(const MediaEntity *entity); std::shared_ptr converter() { return converter_; } bool swIspEnabled() const { return swIspEnabled_; } + bool rawIpaEnabled() const { return rawIpaEnabled_; } protected: int queueRequestDevice(Camera *camera, Request *request) override; @@ -460,6 +461,7 @@ private: std::shared_ptr converter_; bool swIspEnabled_; + bool rawIpaEnabled_ = true; }; /* ----------------------------------------------------------------------------- @@ -968,6 +970,11 @@ void SimpleCameraData::imageBufferReady(FrameBuffer *buffer) conversionQueue_.pop(); return; + } else if (pipe->rawIpaEnabled()) { + /* \todo Make the processing asynchronous? */ + swIsp_->process(request->sequence(), buffer, nullptr); + pipe->completeBuffer(request, buffer); + return; } /* Otherwise simply complete the request. */ @@ -1591,7 +1598,8 @@ int SimplePipelineHandler::configure(Camera *camera, CameraConfiguration *c) data->rawStream_ = &data->streams_[i]; } - if (outputCfgs.empty()) + if (outputCfgs.empty() && + (data->converter_ || !data->rawStream_ || !rawIpaEnabled_)) return 0; StreamConfiguration inputCfg; @@ -1605,7 +1613,12 @@ int SimplePipelineHandler::configure(Camera *camera, CameraConfiguration *c) } else { ipa::softisp::IPAConfigInfo configInfo; configInfo.sensorControls = data->sensor_->controls(); - return data->swIsp_->configure(inputCfg, outputCfgs, configInfo, &data->controlInfo_); + return data->swIsp_->configure( + inputCfg, + outputCfgs, + configInfo, + &data->controlInfo_, + data->useConversion_); } } @@ -1698,6 +1711,12 @@ int SimplePipelineHandler::start(Camera *camera, [[maybe_unused]] const ControlL if (!data->rawStream_) for (std::unique_ptr &buffer : data->conversionBuffers_) video->queueBuffer(buffer.get()); + } else if (data->swIsp_) { + ret = data->swIsp_->startIpa(); + if (ret < 0) { + stop(camera); + return ret; + } } return 0; @@ -1720,6 +1739,8 @@ void SimplePipelineHandler::stopDevice(Camera *camera) data->converter_->stop(); else if (data->swIsp_) data->swIsp_->stop(); + } else if (data->swIsp_) { + data->swIsp_->stopIpa(); } video->streamOff(); @@ -1763,6 +1784,8 @@ int SimplePipelineHandler::queueRequestDevice(Camera *camera, Request *request) data->conversionQueue_.push({ request, std::move(buffers) }); if (data->swIsp_) data->swIsp_->queueRequest(request->sequence(), request->controls()); + } else if (data->swIsp_ && rawIpaEnabled_) { + data->swIsp_->queueRequest(request->sequence(), request->controls()); } return 0; @@ -1882,9 +1905,8 @@ bool SimplePipelineHandler::matchDevice(std::shared_ptr media, swIspEnabled_ = info.swIspEnabled; const GlobalConfiguration &configuration = cameraManager()->_d()->configuration(); - for (const ValueNode &entry : - configuration.configuration()["pipelines"]["simple"]["supported_devices"] - .asList()) { + auto &simpleConfiguration = configuration.configuration()["pipelines"]["simple"]; + for (const ValueNode &entry : simpleConfiguration["supported_devices"].asList()) { auto name = entry["driver"].get(); if (name == info.driver) { swIspEnabled_ = entry["software_isp"].get().value_or(swIspEnabled_); @@ -1903,6 +1925,10 @@ bool SimplePipelineHandler::matchDevice(std::shared_ptr media, */ ASSERT(!converter_); numStreams = 2; + + auto enableRawIpa = simpleConfiguration["enable_raw_ipa"].get(); + if (enableRawIpa) + rawIpaEnabled_ = enableRawIpa.value(); } /* Locate the sensors. */ diff --git a/src/libcamera/software_isp/software_isp.cpp b/src/libcamera/software_isp/software_isp.cpp index 11e0c49ed..594125f8f 100644 --- a/src/libcamera/software_isp/software_isp.cpp +++ b/src/libcamera/software_isp/software_isp.cpp @@ -25,6 +25,7 @@ #include "libcamera/internal/bayer_format.h" #include "libcamera/internal/framebuffer.h" +#include "libcamera/internal/mapped_framebuffer.h" #include "libcamera/internal/software_isp/debayer_params.h" #include "debayer_cpu.h" @@ -280,19 +281,34 @@ uint32_t SoftwareIsp::preferredInputStride(const PixelFormat &inputFormat, const * \param[in] outputCfgs The output configurations * \param[in] configInfo The IPA configuration data, received from the pipeline handler * \param[out] ipaControls The IPA controls to update + * \param[in] debayerEnabled Whether debayering should be performed in addition + * to stats and IPA processing * \return 0 on success, a negative errno on failure */ int SoftwareIsp::configure(const StreamConfiguration &inputCfg, const std::vector> &outputCfgs, const ipa::softisp::IPAConfigInfo &configInfo, - ControlInfoMap *ipaControls) + ControlInfoMap *ipaControls, + bool debayerEnabled) { - ASSERT(ipa_ && debayer_); + ASSERT(ipa_ && (!debayerEnabled || debayer_)); + + int ret; + if (!debayerEnabled) { + ret = stats_->configure(inputCfg); + if (ret < 0) + return ret; + stats_->setWindow(Rectangle(inputCfg.size)); + } - int ret = ipa_->configure(configInfo, ipaControls); + ret = ipa_->configure(configInfo, ipaControls); if (ret < 0) return ret; + if (!debayerEnabled) { + return 0; + } + ret = debayer_->configure(inputCfg, outputCfgs, ccmEnabled_); if (ret < 0) return ret; @@ -452,13 +468,25 @@ void SoftwareIsp::stopIpa() * \brief Passes the input framebuffer to the ISP worker to process * \param[in] frame The frame number * \param[in] input The input framebuffer - * \param[out] output The framebuffer to write the processed frame to + * \param[out] output The framebuffer to write the processed frame to; if + * nullptr then debayering is skipped and stats are processed synchronously */ void SoftwareIsp::process(uint32_t frame, FrameBuffer *input, FrameBuffer *output) { ipa_->computeParams(frame); - debayer_->invokeMethod(&Debayer::process, - ConnectionTypeQueued, frame, input, output, debayerParams_); + + if (output) { + debayer_->invokeMethod(&Debayer::process, + ConnectionTypeQueued, frame, input, output, debayerParams_); + } else { + /* Compute stats, which are otherwise computed in debayering */ + if (frame % SwStatsCpu::kStatPerNumFrames) { + stats_->finishFrame(frame, 0); + } else { + MappedFrameBuffer inputMapped(input, MappedFrameBuffer::MapFlag::Read); + stats_->processFrame(frame, 0, inputMapped); + } + } } void SoftwareIsp::saveIspParams([[maybe_unused]] uint32_t frame)