From patchwork Thu Jun 4 09:50: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: 26836 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 D2476C328C for ; Thu, 4 Jun 2026 09:51:56 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 8A09263741; Thu, 4 Jun 2026 11:51:56 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="MLRYCo3s"; 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 E2A9E63733 for ; Thu, 4 Jun 2026 11:51:54 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1780566713; 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=7euhAtbwddrv5/CMcfmu7aeGVYwz3eIBeIEaZt1wgWs=; b=MLRYCo3s65lxx01SRQWZRs6Hi0RLQcFziBvrqTdMx4XFJ3Zrolfl9V8Wq/lVnx/TcV8nYx uWb7Q9UACGlgZfe5AOCA1tBa3U8pUe8/fH0ncyR6sNe1jscUHofKyN8H6WK7KGK+ebb4GW QFFaDltCZhTyVrj4NSa7/9OsM7rHTXw= Received: from mx-prod-mc-06.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-470-CwXj_GaaPzusu6B1lrUEOw-1; Thu, 04 Jun 2026 05:51:50 -0400 X-MC-Unique: CwXj_GaaPzusu6B1lrUEOw-1 X-Mimecast-MFC-AGG-ID: CwXj_GaaPzusu6B1lrUEOw_1780566709 Received: from mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.4]) (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-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 7C1CD180047F; Thu, 4 Jun 2026 09:51:49 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.44.34.156]) by mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 9BFB130001A1; Thu, 4 Jun 2026 09:51:47 +0000 (UTC) From: Milan Zamazal To: libcamera-devel@lists.libcamera.org Cc: Milan Zamazal , =?utf-8?b?QmFybmFiw6FzIFDFkWN6?= =?utf-8?q?e?= , johannes.goede@oss.qualcomm.com Subject: [RFC PATCH v3 11/17] libcamera: software_isp: Share parameters buffers with debayering Date: Thu, 4 Jun 2026 11:50:57 +0200 Message-ID: <20260604095105.68798-16-mzamazal@redhat.com> In-Reply-To: <20260604095105.68798-1-mzamazal@redhat.com> References: <20260604095105.68798-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.4 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: _SoqBzod-b_wHCsRWFDp6jKTlEx-uLP3Mz0Nl-EyG6U_1780566709 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 --- .../internal/software_isp/software_isp.h | 2 - src/libcamera/software_isp/debayer.cpp | 29 ++++++-- src/libcamera/software_isp/debayer.h | 9 +-- src/libcamera/software_isp/debayer_cpu.cpp | 66 ++++++++++--------- src/libcamera/software_isp/debayer_cpu.h | 12 ++-- src/libcamera/software_isp/debayer_egl.cpp | 15 +++-- src/libcamera/software_isp/debayer_egl.h | 7 +- src/libcamera/software_isp/software_isp.cpp | 21 +++--- 8 files changed, 91 insertions(+), 70 deletions(-) diff --git a/include/libcamera/internal/software_isp/software_isp.h b/include/libcamera/internal/software_isp/software_isp.h index e3419305b..9ea0ed4db 100644 --- a/include/libcamera/internal/software_isp/software_isp.h +++ b/include/libcamera/internal/software_isp/software_isp.h @@ -89,7 +89,6 @@ public: Signal setSensorControls; private: - void saveIspParams(const uint32_t paramsBufferId); void paramsBufferReady(const uint32_t paramsBufferId); bool allocateParamsBuffers(const unsigned int bufferCount); void setSensorCtrls(const ControlList &sensorControls); @@ -99,7 +98,6 @@ private: std::unique_ptr debayer_; Thread ispWorkerThread_; std::map> sharedParams_; - DebayerParams debayerParams_; std::vector availableParams_; DmaBufAllocator dmaHeap_; bool ccmEnabled_; diff --git a/src/libcamera/software_isp/debayer.cpp b/src/libcamera/software_isp/debayer.cpp index 7b1be52b2..28e04d0df 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 { /** @@ -54,15 +56,29 @@ LOG_DEFINE_CATEGORY(Debayer) /** * \brief Construct a Debayer object + * \param[in] paramsBuffers ids and SharedFDs of parameter buffers * \param[in] cm The camera manager */ -Debayer::Debayer(const CameraManager &cm) +Debayer::Debayer(const std::map ¶msBuffers, const CameraManager &cm) : bench_(cm, "Debayer") { + for (auto &[bufferId, sharedFd] : paramsBuffers) { + void *mem = mmap(nullptr, sizeof(DebayerParams), + PROT_READ | PROT_WRITE, MAP_SHARED, + sharedFd.get(), 0); + if (mem == MAP_FAILED) { + LOG(Debayer, Error) << "Unable to map Parameters"; + return; + } + + paramsBuffers_[bufferId] = static_cast(mem); + } } Debayer::~Debayer() { + for (auto &item : paramsBuffers_) + munmap(item.second, sizeof(DebayerParams)); } /** @@ -104,16 +120,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(). */ /** @@ -240,6 +252,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 9a97851b7..6cefa4c01 100644 --- a/src/libcamera/software_isp/debayer.h +++ b/src/libcamera/software_isp/debayer.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2023, Linaro Ltd - * Copyright (C) 2023, Red Hat Inc. + * Copyright (C) 2023-2026 Red Hat Inc. * * Authors: * Hans de Goede @@ -35,7 +35,8 @@ LOG_DECLARE_CATEGORY(Debayer) class Debayer : public Object { public: - Debayer(const CameraManager &cm); + Debayer(const std::map ¶msBuffers, + const CameraManager &cm); 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 51b58fce5..7813eb695 100644 --- a/src/libcamera/software_isp/debayer_cpu.cpp +++ b/src/libcamera/software_isp/debayer_cpu.cpp @@ -12,12 +12,12 @@ #include "debayer_cpu.h" #include -#include #include #include #include +#include #include #include @@ -90,10 +90,13 @@ DebayerCpuThread::DebayerCpuThread(DebayerCpu *debayer, unsigned int threadIndex /** * \brief Constructs a DebayerCpu object * \param[in] stats Pointer to the stats object to use + * \param[in] paramsBuffers SharedFDs of parameter buffers * \param[in] cm The camera manager */ -DebayerCpu::DebayerCpu(std::unique_ptr stats, const CameraManager &cm) - : Debayer(cm), stats_(std::move(stats)) +DebayerCpu::DebayerCpu(std::unique_ptr stats, + const std::map ¶msBuffers, + const CameraManager &cm) + : Debayer(paramsBuffers, cm), stats_(std::move(stats)) { /* * Reading from uncached buffers may be very slow. @@ -879,13 +882,13 @@ void DebayerCpuThread::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++) { @@ -909,12 +912,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); @@ -925,7 +928,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_; @@ -933,21 +936,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_; @@ -962,18 +965,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(); @@ -981,8 +983,8 @@ void DebayerCpu::process(uint32_t frame, const uint32_t paramsBufferId, dmaSyncBegin(dmaSyncers, input, output); + DebayerParams *params = paramsBuffers_.at(paramsBufferId); updateLookupTables(params); - paramsBufferReady.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 1b4e8548a..56d9087da 100644 --- a/src/libcamera/software_isp/debayer_cpu.h +++ b/src/libcamera/software_isp/debayer_cpu.h @@ -17,6 +17,7 @@ #include #include +#include #include @@ -32,7 +33,9 @@ class DebayerCpuThread; class DebayerCpu : public Debayer { public: - DebayerCpu(std::unique_ptr stats, const CameraManager &cm); + DebayerCpu(std::unique_ptr stats, + const std::map ¶msBuffers, + const CameraManager &cm); ~DebayerCpu(); int configure(const StreamConfiguration &inputCfg, @@ -43,8 +46,7 @@ public: std::tuple strideAndFrameSize(const PixelFormat &outputFormat, const Size &size) override; void process(uint32_t frame, const uint32_t paramsBufferId, - FrameBuffer *input, FrameBuffer *output, - const DebayerParams ¶ms) override; + FrameBuffer *input, FrameBuffer *output) override; int start() override; void stop() override; SizeRange sizes(PixelFormat inputFormat, const Size &inputSize) override; @@ -119,8 +121,8 @@ private: int setDebayerFunctions(PixelFormat inputFormat, PixelFormat outputFormat, bool ccmEnabled); - void updateGammaTable(const DebayerParams ¶ms); - void updateLookupTables(const DebayerParams ¶ms); + void updateGammaTable(const DebayerParams *params); + void updateLookupTables(const DebayerParams *params); static constexpr unsigned int kRGBLookupSize = 256; static constexpr unsigned int kGammaLookupSize = 1024; diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp index 60fd5463f..77696f1e7 100644 --- a/src/libcamera/software_isp/debayer_egl.cpp +++ b/src/libcamera/software_isp/debayer_egl.cpp @@ -37,10 +37,13 @@ namespace libcamera { /** * \brief Construct a DebayerEGL object * \param[in] stats Statistics processing object + * \param[in] paramsBuffers SharedFDs of parameter buffers * \param[in] cm The camera manager */ -DebayerEGL::DebayerEGL(std::unique_ptr stats, const CameraManager &cm) - : Debayer(cm), stats_(std::move(stats)) +DebayerEGL::DebayerEGL(std::unique_ptr stats, + const std::map ¶msBuffers, + const CameraManager &cm) + : Debayer(paramsBuffers, cm), stats_(std::move(stats)) { } @@ -547,8 +550,7 @@ int DebayerEGL::debayerGPU(FrameBuffer *input, FrameBuffer *output, const Debaye } void DebayerEGL::process(uint32_t frame, const uint32_t paramsBufferId, - FrameBuffer *input, FrameBuffer *output, - const DebayerParams ¶ms) + FrameBuffer *input, FrameBuffer *output) { bench_.startFrame(); @@ -561,11 +563,13 @@ void DebayerEGL::process(uint32_t frame, const uint32_t paramsBufferId, std::optional inMapped; std::optional inDmaSyncer; + DebayerParams params = *paramsBuffers_.at(paramsBufferId); + paramsBufferReady.emit(paramsBufferId); + if (debayerGPU(input, output, params, &inMapped, &inDmaSyncer)) { LOG(Debayer, Error) << "debayerGPU failed"; goto error; } - paramsBufferReady.emit(paramsBufferId); metadata.planes()[0].bytesused = output->planes()[0].length; @@ -596,7 +600,6 @@ void DebayerEGL::process(uint32_t frame, const uint32_t paramsBufferId, return; error: - paramsBufferReady.emit(paramsBufferId); bench_.finishFrame(); metadata.status = FrameMetadata::FrameError; return; diff --git a/src/libcamera/software_isp/debayer_egl.h b/src/libcamera/software_isp/debayer_egl.h index a3a4448e7..43e3dcb15 100644 --- a/src/libcamera/software_isp/debayer_egl.h +++ b/src/libcamera/software_isp/debayer_egl.h @@ -39,7 +39,9 @@ class CameraManager; class DebayerEGL : public Debayer { public: - DebayerEGL(std::unique_ptr stats, const CameraManager &cm); + DebayerEGL(std::unique_ptr stats, + const std::map ¶msBuffers, + const CameraManager &cm); ~DebayerEGL(); int configure(const StreamConfiguration &inputCfg, @@ -52,8 +54,7 @@ public: std::tuple strideAndFrameSize(const PixelFormat &outputFormat, const Size &size) override; void process(uint32_t frame, const uint32_t paramsBufferId, - FrameBuffer *input, FrameBuffer *output, - const DebayerParams ¶ms) override; + FrameBuffer *input, FrameBuffer *output) override; int start() override; void stop() override; diff --git a/src/libcamera/software_isp/software_isp.cpp b/src/libcamera/software_isp/software_isp.cpp index 7f3bfe812..dbe4cc270 100644 --- a/src/libcamera/software_isp/software_isp.cpp +++ b/src/libcamera/software_isp/software_isp.cpp @@ -106,6 +106,10 @@ SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, } stats->statsReady.connect(this, &SoftwareIsp::statsReady); + std::map fdParams; + for (auto &[bufferId, item] : sharedParams_) + fdParams[bufferId] = item.fd(); + #if HAVE_DEBAYER_EGL const GlobalConfiguration &configuration = cm._d()->configuration(); std::optional softISPMode = configuration.option({ "software_isp", "mode" }); @@ -120,15 +124,14 @@ SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, } if (!softISPMode || softISPMode == "gpu") - debayer_ = std::make_unique(std::move(stats), cm); + debayer_ = std::make_unique(std::move(stats), fdParams, + cm); #endif if (!debayer_) - debayer_ = std::make_unique(std::move(stats), cm); + debayer_ = std::make_unique(std::move(stats), fdParams, + cm); - std::map fdParams; - for (auto &[bufferId, item] : sharedParams_) - fdParams[bufferId] = item.fd(); debayer_->inputBufferReady.connect(this, &SoftwareIsp::inputReady); debayer_->outputBufferReady.connect(this, &SoftwareIsp::outputReady); debayer_->paramsBufferReady.connect(this, &SoftwareIsp::paramsBufferReady); @@ -168,7 +171,6 @@ SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, return; } - ipa_->paramsComputed.connect(this, &SoftwareIsp::saveIspParams); ipa_->metadataReady.connect(this, [this](uint32_t frame, const ControlList &metadata) { metadataReady.emit(frame, metadata); @@ -444,16 +446,11 @@ int SoftwareIsp::process(uint32_t frame, FrameBuffer *input, FrameBuffer *output ipa_->computeParams(frame, paramsBufferId); debayer_->invokeMethod(&Debayer::process, ConnectionTypeQueued, frame, paramsBufferId, - input, output, debayerParams_); + input, output); return 0; } -void SoftwareIsp::saveIspParams(const uint32_t paramsBufferId) -{ - debayerParams_ = *sharedParams_.at(paramsBufferId); -} - void SoftwareIsp::paramsBufferReady(const uint32_t paramsBufferId) { availableParams_.push_back(paramsBufferId);