From patchwork Mon Feb 16 20:30:27 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 26177 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 E12A0C0DA4 for ; Mon, 16 Feb 2026 20:31:00 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id ABD0162225; Mon, 16 Feb 2026 21:31:00 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="d0aBWrSN"; 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 0B08D62084 for ; Mon, 16 Feb 2026 21:30:58 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1771273858; 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=iCTExq9BSjDZs1cYMuDKGmre0Nkq/Rsd9MERn2JpJ+k=; b=d0aBWrSNbZR/bs7zeq2m87qCWfDF/UpvMZgI9x3o5du04TLB+YdK05DDvY/f+7b5n4+0QN dVxZ/4+pRyUhBjUP8JdewgzyYTo59DxG8GbbVX3Tj2MiTKYTqXuTKtr8e+dLIFoLCSDtbp fNxOHXXT8IgmsURwmhcXsO6TcYciGFE= Received: from mx-prod-mc-03.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-540-Vvl4J4RGO82krFpIB2XERA-1; Mon, 16 Feb 2026 15:30:56 -0500 X-MC-Unique: Vvl4J4RGO82krFpIB2XERA-1 X-Mimecast-MFC-AGG-ID: Vvl4J4RGO82krFpIB2XERA_1771273855 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-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id B7CB119560B2 for ; Mon, 16 Feb 2026 20:30:55 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.44.32.25]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 47AE41800464; Mon, 16 Feb 2026 20:30:53 +0000 (UTC) From: Milan Zamazal To: libcamera-devel@lists.libcamera.org Cc: Milan Zamazal Subject: [RFC PATCH v2 08/14] libcamera: software_isp: Share parameters buffers with debayering Date: Mon, 16 Feb 2026 21:30:27 +0100 Message-ID: <20260216203034.27558-9-mzamazal@redhat.com> In-Reply-To: <20260216203034.27558-1-mzamazal@redhat.com> References: <20260216203034.27558-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: gcI9mzU4riC5yfUrVh9B3nRaQxSTKwDMs3pgZaIjx4M_1771273855 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" Share the multiple parameters buffers with debayering rather than copying the current parameters buffer there. This is done in a similar way as sharing the buffers with IPA in the preceding patch. Signed-off-by: Milan Zamazal --- src/libcamera/software_isp/debayer.cpp | 27 ++++++++- src/libcamera/software_isp/debayer.h | 7 ++- src/libcamera/software_isp/debayer_cpu.cpp | 67 +++++++++++---------- src/libcamera/software_isp/debayer_cpu.h | 11 ++-- src/libcamera/software_isp/debayer_egl.cpp | 14 +++-- src/libcamera/software_isp/debayer_egl.h | 7 ++- src/libcamera/software_isp/software_isp.cpp | 16 ++--- 7 files changed, 92 insertions(+), 57 deletions(-) diff --git a/src/libcamera/software_isp/debayer.cpp b/src/libcamera/software_isp/debayer.cpp index e2e294d3e..ad47c1e8d 100644 --- a/src/libcamera/software_isp/debayer.cpp +++ b/src/libcamera/software_isp/debayer.cpp @@ -11,6 +11,8 @@ #include "debayer.h" +#include + namespace libcamera { /** @@ -21,6 +23,7 @@ namespace libcamera { /** * \fn Debayer::Debayer(const GlobalConfiguration &configuration) * \brief Construct a Debayer object + * \param[in] paramsBuffers SharedFDs of parameter buffers * \param[in] configuration Global configuration reference */ @@ -58,8 +61,22 @@ namespace libcamera { LOG_DEFINE_CATEGORY(Debayer) -Debayer::Debayer(const GlobalConfiguration &configuration) : bench_(configuration) +Debayer::Debayer(const std::vector ¶msBuffers, + const GlobalConfiguration &configuration) : bench_(configuration) { + paramsBuffers_ = std::map(); + + for (auto &sharedFd : paramsBuffers) { + void *mem = mmap(nullptr, sizeof(DebayerParams), PROT_WRITE, + MAP_SHARED, sharedFd.get(), 0); + if (mem == MAP_FAILED) { + LOG(Debayer, Error) << "Unable to map Parameters"; + return; + } + + ASSERT(sharedFd.get() >= 0); + paramsBuffers_[sharedFd.get()] = static_cast(mem); + } } Debayer::~Debayer() @@ -105,13 +122,12 @@ Debayer::~Debayer() */ /** - * \fn void Debayer::process(uint32_t frame, const uint32_t paramsBufferId, FrameBuffer *input, FrameBuffer *output, DebayerParams params) + * \fn void Debayer::process(uint32_t frame, const uint32_t paramsBufferId, FrameBuffer *input, FrameBuffer *output) * \brief Process the bayer data into the requested format * \param[in] frame The frame number * \param[in] paramsBufferId The id of the params buffer in use * \param[in] input The input buffer * \param[in] output The output buffer - * \param[in] params The parameters to be used in debayering * * \note DebayerParams is passed by value deliberately so that a copy is passed * when this is run in another thread by invokeMethod(). @@ -239,6 +255,11 @@ Debayer::~Debayer() * reversed. */ +/** + * \var Debayer::paramsBuffers_ + * \brief Ring of debayering parameters buffers + */ + /** * \var Debayer::bench_ * \brief Benchmarking utility instance for performance measurements diff --git a/src/libcamera/software_isp/debayer.h b/src/libcamera/software_isp/debayer.h index 0c9627d30..a66d0cbbe 100644 --- a/src/libcamera/software_isp/debayer.h +++ b/src/libcamera/software_isp/debayer.h @@ -35,7 +35,8 @@ LOG_DECLARE_CATEGORY(Debayer) class Debayer : public Object { public: - Debayer(const GlobalConfiguration &configuration); + Debayer(const std::vector ¶msBuffers, + const GlobalConfiguration &configuration); virtual ~Debayer() = 0; virtual int configure(const StreamConfiguration &inputCfg, @@ -49,8 +50,7 @@ public: virtual void process(uint32_t frame, const uint32_t paramsBufferId, - FrameBuffer *input, FrameBuffer *output, - const DebayerParams ¶ms) = 0; + FrameBuffer *input, FrameBuffer *output) = 0; virtual int start() { return 0; } virtual void stop() {} @@ -83,6 +83,7 @@ public: PixelFormat inputPixelFormat_; PixelFormat outputPixelFormat_; bool swapRedBlueGains_; + std::map paramsBuffers_; Benchmark bench_; private: diff --git a/src/libcamera/software_isp/debayer_cpu.cpp b/src/libcamera/software_isp/debayer_cpu.cpp index 5d0e780f7..927ac7d10 100644 --- a/src/libcamera/software_isp/debayer_cpu.cpp +++ b/src/libcamera/software_isp/debayer_cpu.cpp @@ -12,13 +12,14 @@ #include "debayer_cpu.h" #include -#include #include #include #include #include +#include + #include #include "libcamera/internal/bayer_format.h" @@ -38,10 +39,13 @@ namespace libcamera { /** * \brief Constructs a DebayerCpu object * \param[in] stats Pointer to the stats object to use + * \param[in] paramsBuffers SharedFDs of parameter buffers * \param[in] configuration The global configuration */ -DebayerCpu::DebayerCpu(std::unique_ptr stats, const GlobalConfiguration &configuration) - : Debayer(configuration), stats_(std::move(stats)) +DebayerCpu::DebayerCpu(std::unique_ptr stats, + const std::vector ¶msBuffers, + const GlobalConfiguration &configuration) + : Debayer(paramsBuffers, configuration), stats_(std::move(stats)) { /* * Reading from uncached buffers may be very slow. @@ -750,13 +754,13 @@ void DebayerCpu::process4(uint32_t frame, const uint8_t *src, uint8_t *dst) } } -void DebayerCpu::updateGammaTable(const DebayerParams ¶ms) +void DebayerCpu::updateGammaTable(const DebayerParams *params) { - const RGB blackLevel = params.blackLevel; + const RGB blackLevel = params->blackLevel; /* Take let's say the green channel black level */ const unsigned int blackIndex = blackLevel[1] * gammaTable_.size(); - const float gamma = params.gamma; - const float contrastExp = params.contrastExp; + const float gamma = params->gamma; + const float contrastExp = params->contrastExp; const float divisor = gammaTable_.size() - blackIndex - 1.0; for (unsigned int i = blackIndex; i < gammaTable_.size(); i++) { @@ -780,12 +784,12 @@ void DebayerCpu::updateGammaTable(const DebayerParams ¶ms) gammaTable_[blackIndex]); } -void DebayerCpu::updateLookupTables(const DebayerParams ¶ms) +void DebayerCpu::updateLookupTables(const DebayerParams *params) { const bool gammaUpdateNeeded = - params.gamma != params_.gamma || - params.blackLevel != params_.blackLevel || - params.contrastExp != params_.contrastExp; + params->gamma != params_.gamma || + params->blackLevel != params_.blackLevel || + params->contrastExp != params_.contrastExp; if (gammaUpdateNeeded) updateGammaTable(params); @@ -796,7 +800,7 @@ void DebayerCpu::updateLookupTables(const DebayerParams ¶ms) const double div = static_cast(kRGBLookupSize) / gammaTableSize; if (ccmEnabled_) { if (gammaUpdateNeeded || - matrixChanged(params.combinedMatrix, params_.combinedMatrix)) { + matrixChanged(params->combinedMatrix, params_.combinedMatrix)) { auto &red = swapRedBlueGains_ ? blueCcm_ : redCcm_; auto &green = greenCcm_; auto &blue = swapRedBlueGains_ ? redCcm_ : blueCcm_; @@ -804,21 +808,21 @@ void DebayerCpu::updateLookupTables(const DebayerParams ¶ms) const unsigned int greenIndex = 1; const unsigned int blueIndex = swapRedBlueGains_ ? 0 : 2; for (unsigned int i = 0; i < kRGBLookupSize; i++) { - red[i].r = std::round(i * params.combinedMatrix[redIndex][0]); - red[i].g = std::round(i * params.combinedMatrix[greenIndex][0]); - red[i].b = std::round(i * params.combinedMatrix[blueIndex][0]); - green[i].r = std::round(i * params.combinedMatrix[redIndex][1]); - green[i].g = std::round(i * params.combinedMatrix[greenIndex][1]); - green[i].b = std::round(i * params.combinedMatrix[blueIndex][1]); - blue[i].r = std::round(i * params.combinedMatrix[redIndex][2]); - blue[i].g = std::round(i * params.combinedMatrix[greenIndex][2]); - blue[i].b = std::round(i * params.combinedMatrix[blueIndex][2]); + red[i].r = std::round(i * params->combinedMatrix[redIndex][0]); + red[i].g = std::round(i * params->combinedMatrix[greenIndex][0]); + red[i].b = std::round(i * params->combinedMatrix[blueIndex][0]); + green[i].r = std::round(i * params->combinedMatrix[redIndex][1]); + green[i].g = std::round(i * params->combinedMatrix[greenIndex][1]); + green[i].b = std::round(i * params->combinedMatrix[blueIndex][1]); + blue[i].r = std::round(i * params->combinedMatrix[redIndex][2]); + blue[i].g = std::round(i * params->combinedMatrix[greenIndex][2]); + blue[i].b = std::round(i * params->combinedMatrix[blueIndex][2]); gammaLut_[i] = gammaTable_[i / div]; } } } else { - if (gammaUpdateNeeded || params.gains != params_.gains) { - auto &gains = params.gains; + if (gammaUpdateNeeded || params->gains != params_.gains) { + auto &gains = params->gains; auto &red = swapRedBlueGains_ ? blue_ : red_; auto &green = green_; auto &blue = swapRedBlueGains_ ? red_ : blue_; @@ -833,18 +837,17 @@ void DebayerCpu::updateLookupTables(const DebayerParams ¶ms) } LOG(Debayer, Debug) - << "Debayer parameters: blackLevel=" << params.blackLevel - << "; gamma=" << params.gamma - << "; contrastExp=" << params.contrastExp - << "; gains=" << params.gains - << "; matrix=" << params.combinedMatrix; + << "Debayer parameters: blackLevel=" << params->blackLevel + << "; gamma=" << params->gamma + << "; contrastExp=" << params->contrastExp + << "; gains=" << params->gains + << "; matrix=" << params->combinedMatrix; - params_ = params; + params_ = *params; } void DebayerCpu::process(uint32_t frame, const uint32_t paramsBufferId, - FrameBuffer *input, FrameBuffer *output, - const DebayerParams ¶ms) + FrameBuffer *input, FrameBuffer *output) { bench_.startFrame(); @@ -852,8 +855,8 @@ void DebayerCpu::process(uint32_t frame, const uint32_t paramsBufferId, dmaSyncBegin(dmaSyncers, input, output); + DebayerParams *params = paramsBuffers_.at(paramsBufferId); updateLookupTables(params); - releaseIspParams.emit(paramsBufferId); /* Copy metadata from the input buffer */ diff --git a/src/libcamera/software_isp/debayer_cpu.h b/src/libcamera/software_isp/debayer_cpu.h index 13253f999..5e3670b37 100644 --- a/src/libcamera/software_isp/debayer_cpu.h +++ b/src/libcamera/software_isp/debayer_cpu.h @@ -16,6 +16,7 @@ #include #include +#include #include "libcamera/internal/bayer_format.h" #include "libcamera/internal/global_configuration.h" @@ -29,7 +30,9 @@ namespace libcamera { class DebayerCpu : public Debayer { public: - DebayerCpu(std::unique_ptr stats, const GlobalConfiguration &configuration); + DebayerCpu(std::unique_ptr stats, + const std::vector ¶msBuffers, + const GlobalConfiguration &configuration); ~DebayerCpu(); int configure(const StreamConfiguration &inputCfg, @@ -41,7 +44,7 @@ public: strideAndFrameSize(const PixelFormat &outputFormat, const Size &size); void process(uint32_t frame, const uint32_t paramsBufferId, - FrameBuffer *input, FrameBuffer *output, const DebayerParams ¶ms); + FrameBuffer *input, FrameBuffer *output); SizeRange sizes(PixelFormat inputFormat, const Size &inputSize); const SharedFD &getStatsFD() { return stats_->getStatsFD(); } @@ -112,8 +115,8 @@ private: void memcpyNextLine(const uint8_t *linePointers[]); void process2(uint32_t frame, const uint8_t *src, uint8_t *dst); void process4(uint32_t frame, const uint8_t *src, uint8_t *dst); - void updateGammaTable(const DebayerParams ¶ms); - void updateLookupTables(const DebayerParams ¶ms); + void updateGammaTable(const DebayerParams *params); + void updateLookupTables(const DebayerParams *params); /* Max. supported Bayer pattern height is 4, debayering this requires 5 lines */ static constexpr unsigned int kMaxLineBuffers = 5; diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp index 947c05c07..c24590994 100644 --- a/src/libcamera/software_isp/debayer_egl.cpp +++ b/src/libcamera/software_isp/debayer_egl.cpp @@ -32,10 +32,13 @@ namespace libcamera { * \fn DebayerEGL::DebayerEGL(std::unique_ptr stats, const GlobalConfiguration &configuration) * \brief Construct a DebayerEGL object * \param[in] stats Statistics processing object + * \param[in] paramsBuffers SharedFDs of parameter buffers * \param[in] configuration Global configuration reference */ -DebayerEGL::DebayerEGL(std::unique_ptr stats, const GlobalConfiguration &configuration) - : Debayer(configuration), stats_(std::move(stats)) +DebayerEGL::DebayerEGL(std::unique_ptr stats, + const std::vector ¶msBuffers, + const GlobalConfiguration &configuration) + : Debayer(paramsBuffers, configuration), stats_(std::move(stats)) { } @@ -534,8 +537,7 @@ int DebayerEGL::debayerGPU(MappedFrameBuffer &in, int out_fd, const DebayerParam } void DebayerEGL::process(uint32_t frame, const uint32_t paramsBufferId, - FrameBuffer *input, FrameBuffer *output, - const DebayerParams ¶ms) + FrameBuffer *input, FrameBuffer *output) { bench_.startFrame(); @@ -549,6 +551,9 @@ void DebayerEGL::process(uint32_t frame, const uint32_t paramsBufferId, metadata.sequence = input->metadata().sequence; metadata.timestamp = input->metadata().timestamp; + DebayerParams params = *paramsBuffers_.at(paramsBufferId); + releaseIspParams.emit(paramsBufferId); + MappedFrameBuffer in(input, MappedFrameBuffer::MapFlag::Read); if (!in.isValid()) { LOG(Debayer, Error) << "mmap-ing buffer(s) failed"; @@ -559,7 +564,6 @@ void DebayerEGL::process(uint32_t frame, const uint32_t paramsBufferId, LOG(Debayer, Error) << "debayerGPU failed"; goto error; } - releaseIspParams.emit(paramsBufferId); bench_.finishFrame(); diff --git a/src/libcamera/software_isp/debayer_egl.h b/src/libcamera/software_isp/debayer_egl.h index 7f29f53e6..435ff7d31 100644 --- a/src/libcamera/software_isp/debayer_egl.h +++ b/src/libcamera/software_isp/debayer_egl.h @@ -38,7 +38,9 @@ namespace libcamera { class DebayerEGL : public Debayer { public: - DebayerEGL(std::unique_ptr stats, const GlobalConfiguration &configuration); + DebayerEGL(std::unique_ptr stats, + const std::vector ¶msBuffers, + const GlobalConfiguration &configuration); ~DebayerEGL(); int configure(const StreamConfiguration &inputCfg, @@ -51,8 +53,7 @@ public: std::tuple strideAndFrameSize(const PixelFormat &outputFormat, const Size &size); void process(uint32_t frame, const uint32_t paramsBufferId, - FrameBuffer *input, FrameBuffer *output, - const DebayerParams ¶ms); + FrameBuffer *input, FrameBuffer *output); int start(); void stop(); diff --git a/src/libcamera/software_isp/software_isp.cpp b/src/libcamera/software_isp/software_isp.cpp index 2bc0d30b1..230396bee 100644 --- a/src/libcamera/software_isp/software_isp.cpp +++ b/src/libcamera/software_isp/software_isp.cpp @@ -102,6 +102,10 @@ SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, const CameraSensor *sensor, } stats->statsReady.connect(this, &SoftwareIsp::statsReady); + std::vector fdParams; + for (auto &item : sharedParams_) + fdParams.emplace_back(item.second.fd()); + #if HAVE_DEBAYER_EGL std::optional softISPMode = configuration.envOption("LIBCAMERA_SOFTISP_MODE", { "software_isp", "mode" }); if (softISPMode) { @@ -113,15 +117,14 @@ SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, const CameraSensor *sensor, } if (!softISPMode || softISPMode == "gpu") - debayer_ = std::make_unique(std::move(stats), configuration); + debayer_ = std::make_unique(std::move(stats), fdParams, + configuration); #endif if (!debayer_) - debayer_ = std::make_unique(std::move(stats), configuration); + debayer_ = std::make_unique(std::move(stats), fdParams, + configuration); - std::vector fdParams; - for (auto &item : sharedParams_) - fdParams.emplace_back(item.second.fd()); debayer_->inputBufferReady.connect(this, &SoftwareIsp::inputReady); debayer_->outputBufferReady.connect(this, &SoftwareIsp::outputReady); debayer_->releaseIspParams.connect(this, &SoftwareIsp::releaseIspParams); @@ -426,9 +429,8 @@ void SoftwareIsp::process(uint32_t frame, FrameBuffer *input, FrameBuffer *outpu const uint32_t paramsBufferId = availableParams_.front(); availableParams_.pop(); ipa_->computeParams(frame, paramsBufferId); - debayerParams_ = *sharedParams_.at(paramsBufferId); debayer_->invokeMethod(&Debayer::process, - ConnectionTypeQueued, frame, paramsBufferId, input, output, debayerParams_); + ConnectionTypeQueued, frame, paramsBufferId, input, output); } void SoftwareIsp::saveIspParams(uint32_t paramsBufferId)