[RFC,v2,08/14] libcamera: software_isp: Share parameters buffers with debayering
diff mbox series

Message ID 20260216203034.27558-9-mzamazal@redhat.com
State New
Headers show
Series
  • Software ISP: Share params and stats buffers
Related show

Commit Message

Milan Zamazal Feb. 16, 2026, 8:30 p.m. UTC
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 <mzamazal@redhat.com>
---
 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(-)

Patch
diff mbox series

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 <sys/mman.h>
+
 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<SharedFD> &paramsBuffers,
+		 const GlobalConfiguration &configuration) : bench_(configuration)
 {
+	paramsBuffers_ = std::map<unsigned int, DebayerParams *>();
+
+	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<DebayerParams *>(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<SharedFD> &paramsBuffers,
+		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 &params) = 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<unsigned int, DebayerParams *> 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 <algorithm>
-#include <stdlib.h>
 #include <sys/ioctl.h>
 #include <time.h>
 #include <utility>
 
 #include <linux/dma-buf.h>
 
+#include <libcamera/base/shared_fd.h>
+
 #include <libcamera/formats.h>
 
 #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<SwStatsCpu> stats, const GlobalConfiguration &configuration)
-	: Debayer(configuration), stats_(std::move(stats))
+DebayerCpu::DebayerCpu(std::unique_ptr<SwStatsCpu> stats,
+		       const std::vector<SharedFD> &paramsBuffers,
+		       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 &params)
+void DebayerCpu::updateGammaTable(const DebayerParams *params)
 {
-	const RGB<float> blackLevel = params.blackLevel;
+	const RGB<float> 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 &params)
 		  gammaTable_[blackIndex]);
 }
 
-void DebayerCpu::updateLookupTables(const DebayerParams &params)
+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 &params)
 	const double div = static_cast<double>(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 &params)
 			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 &params)
 	}
 
 	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 &params)
+			 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 <vector>
 
 #include <libcamera/base/object.h>
+#include <libcamera/base/shared_fd.h>
 
 #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<SwStatsCpu> stats, const GlobalConfiguration &configuration);
+	DebayerCpu(std::unique_ptr<SwStatsCpu> stats,
+		   const std::vector<SharedFD> &paramsBuffers,
+		   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 &params);
+		     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 &params);
-	void updateLookupTables(const DebayerParams &params);
+	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<SwStatsCpu> 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<SwStatsCpu> stats, const GlobalConfiguration &configuration)
-	: Debayer(configuration), stats_(std::move(stats))
+DebayerEGL::DebayerEGL(std::unique_ptr<SwStatsCpu> stats,
+		       const std::vector<SharedFD> &paramsBuffers,
+		       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 &params)
+			 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<SwStatsCpu> stats, const GlobalConfiguration &configuration);
+	DebayerEGL(std::unique_ptr<SwStatsCpu> stats,
+		   const std::vector<SharedFD> &paramsBuffers,
+		   const GlobalConfiguration &configuration);
 	~DebayerEGL();
 
 	int configure(const StreamConfiguration &inputCfg,
@@ -51,8 +53,7 @@  public:
 	std::tuple<unsigned int, unsigned int> strideAndFrameSize(const PixelFormat &outputFormat, const Size &size);
 
 	void process(uint32_t frame, const uint32_t paramsBufferId,
-		     FrameBuffer *input, FrameBuffer *output,
-		     const DebayerParams &params);
+		     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<SharedFD> fdParams;
+	for (auto &item : sharedParams_)
+		fdParams.emplace_back(item.second.fd());
+
 #if HAVE_DEBAYER_EGL
 	std::optional<std::string> 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<DebayerEGL>(std::move(stats), configuration);
+		debayer_ = std::make_unique<DebayerEGL>(std::move(stats), fdParams,
+							configuration);
 
 #endif
 	if (!debayer_)
-		debayer_ = std::make_unique<DebayerCpu>(std::move(stats), configuration);
+		debayer_ = std::make_unique<DebayerCpu>(std::move(stats), fdParams,
+							configuration);
 
-	std::vector<SharedFD> 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)