[RFC,v3,14/17] libcamera: software_isp: Allocate statistics buffers
diff mbox series

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

Commit Message

Milan Zamazal June 4, 2026, 9:51 a.m. UTC
In order to be able to use multiple shared statistics buffers, we must
allocate them.  They are allocated in SoftwareIsp and passed to
SwIspStats.  This changes the previous behavior when the (single) shared
statistics buffer was created in SwIspStats.  Centralizing it to
SoftwareIsp makes sharing multiple buffers with IPA easier.

Currently only one of the allocated buffers is used.  This will be
changed once the buffers are shared with IPA in a followup patch.

Signed-off-by: Milan Zamazal <mzamazal@redhat.com>
---
 .../internal/software_isp/software_isp.h      |  5 +++
 .../internal/software_isp/swstats_cpu.h       | 11 ++---
 src/libcamera/software_isp/software_isp.cpp   | 44 ++++++++++++++++---
 src/libcamera/software_isp/swstats_cpu.cpp    | 26 ++++++-----
 4 files changed, 62 insertions(+), 24 deletions(-)

Patch
diff mbox series

diff --git a/include/libcamera/internal/software_isp/software_isp.h b/include/libcamera/internal/software_isp/software_isp.h
index 3e879c630..451596163 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 {
 
@@ -91,6 +92,10 @@  public:
 private:
 	void paramsBufferReady(const uint32_t paramsBufferId);
 	bool allocateParamsBuffers(const unsigned int bufferCount);
+	std::unique_ptr<SwStatsCpu> allocateStatsBuffers(
+		const CameraManager &cm,
+		std::map<uint32_t, SharedFD> &fdStats,
+		const unsigned int bufferCount);
 	void setSensorCtrls(const ControlList &sensorControls);
 	void statsReady(uint32_t frame, const uint32_t statsBufferId);
 	void statsProcessed(const uint32_t statsBufferId);
diff --git a/include/libcamera/internal/software_isp/swstats_cpu.h b/include/libcamera/internal/software_isp/swstats_cpu.h
index fd3f97cbb..cf2f88fcb 100644
--- a/include/libcamera/internal/software_isp/swstats_cpu.h
+++ b/include/libcamera/internal/software_isp/swstats_cpu.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 <hdegoede@redhat.com>
@@ -11,6 +11,7 @@ 
 
 #pragma once
 
+#include <map>
 #include <stdint.h>
 #include <vector>
 
@@ -35,7 +36,7 @@  struct StreamConfiguration;
 class SwStatsCpu
 {
 public:
-	SwStatsCpu(const CameraManager &cm);
+	SwStatsCpu(const CameraManager &cm, std::unique_ptr<std::map<uint32_t, SharedMemObject<SwIspStats>>> sharedStats);
 	~SwStatsCpu() = default;
 
 	/*
@@ -46,9 +47,9 @@  public:
 	 */
 	static constexpr uint32_t kStatPerNumFrames = 4;
 
-	bool isValid() const { return sharedStats_.fd().isValid(); }
+	bool isValid() const { return sharedStats_->begin()->second.fd().isValid(); }
 
-	const SharedFD &getStatsFD() { return sharedStats_.fd(); }
+	const SharedFD &getStatsFD() { return sharedStats_->begin()->second.fd(); }
 
 	const Size &patternSize() { return patternSize_; }
 
@@ -119,7 +120,7 @@  private:
 	unsigned int sumShift_;
 
 	std::vector<SwIspStats> stats_;
-	SharedMemObject<SwIspStats> sharedStats_;
+	std::unique_ptr<std::map<uint32_t, SharedMemObject<SwIspStats>>> sharedStats_;
 	Benchmark bench_;
 };
 
diff --git a/src/libcamera/software_isp/software_isp.cpp b/src/libcamera/software_isp/software_isp.cpp
index c44e035b8..c4da647e8 100644
--- a/src/libcamera/software_isp/software_isp.cpp
+++ b/src/libcamera/software_isp/software_isp.cpp
@@ -14,6 +14,8 @@ 
 #include <sys/mman.h>
 #include <sys/types.h>
 #include <unistd.h>
+#include <utility>
+#include <vector>
 
 #include <libcamera/base/log.h>
 #include <libcamera/base/shared_fd.h>
@@ -26,7 +28,10 @@ 
 
 #include "libcamera/internal/bayer_format.h"
 #include "libcamera/internal/framebuffer.h"
+#include "libcamera/internal/ipa_manager.h"
+#include "libcamera/internal/shared_mem_object.h"
 #include "libcamera/internal/software_isp/debayer_params.h"
+#include "libcamera/internal/software_isp/swisp_stats.h"
 
 #include "debayer_cpu.h"
 #if HAVE_DEBAYER_EGL
@@ -99,17 +104,15 @@  SoftwareIsp::SoftwareIsp(PipelineHandler *pipe,
 
 	const CameraManager &cm = *pipe->cameraManager();
 
-	auto stats = std::make_unique<SwStatsCpu>(cm);
-	if (!stats->isValid()) {
-		LOG(SoftwareIsp, Error) << "Failed to create SwStatsCpu object";
-		return;
-	}
-	stats->statsReady.connect(this, &SoftwareIsp::statsReady);
-
 	std::map<uint32_t, SharedFD> fdParams;
 	for (auto &[bufferId, item] : sharedParams_)
 		fdParams[bufferId] = item.fd();
 
+	std::map<uint32_t, SharedFD> fdStats;
+	auto stats = allocateStatsBuffers(cm, fdStats, bufferCount);
+	if (!stats)
+		return;
+
 #if HAVE_DEBAYER_EGL
 	const GlobalConfiguration &configuration = cm._d()->configuration();
 	std::optional<std::string> softISPMode = configuration.option<std::string>({ "software_isp", "mode" });
@@ -203,6 +206,33 @@  bool SoftwareIsp::allocateParamsBuffers(const unsigned int bufferCount)
 	return true;
 }
 
+std::unique_ptr<SwStatsCpu> SoftwareIsp::allocateStatsBuffers(
+	const CameraManager &cm,
+	std::map<uint32_t, SharedFD> &fdStats,
+	const unsigned int bufferCount)
+{
+	auto sharedStats = std::make_unique<std::map<uint32_t, SharedMemObject<SwIspStats>>>();
+	for (unsigned int bufferId = 0; bufferId < bufferCount; bufferId++) {
+		auto shared = SharedMemObject<SwIspStats>("softIsp_stats");
+		if (!shared) {
+			LOG(SoftwareIsp, Error) << "Failed to create shared memory for statistics";
+			return nullptr;
+		}
+		if (!shared.fd().isValid()) {
+			LOG(SoftwareIsp, Error) << "Invalid fd of shared statistics";
+			return nullptr;
+		}
+
+		fdStats[bufferId] = shared.fd();
+		sharedStats->emplace(bufferId, std::move(shared));
+	}
+
+	auto stats = std::make_unique<SwStatsCpu>(cm, std::move(sharedStats));
+	stats->statsReady.connect(this, &SoftwareIsp::statsReady);
+
+	return stats;
+}
+
 /**
  * \fn int SoftwareIsp::loadConfiguration([[maybe_unused]] const std::string &filename)
  * \brief Load a configuration from a file
diff --git a/src/libcamera/software_isp/swstats_cpu.cpp b/src/libcamera/software_isp/swstats_cpu.cpp
index 0e645f7e1..e6beb9692 100644
--- a/src/libcamera/software_isp/swstats_cpu.cpp
+++ b/src/libcamera/software_isp/swstats_cpu.cpp
@@ -11,6 +11,8 @@ 
 
 #include "libcamera/internal/software_isp/swstats_cpu.h"
 
+#include <memory>
+
 #include <libcamera/base/log.h>
 
 #include <libcamera/stream.h>
@@ -36,9 +38,11 @@  namespace libcamera {
  */
 
 /**
- * \fn SwStatsCpu::SwStatsCpu(const CameraManager &cm)
+ * \fn SwStatsCpu::SwStatsCpu(const CameraManager &cm, std::unique_ptr<std::map<uint32_t, SharedMemObject<SwIspStats>>> sharedStats)
  * \brief Construct a SwStatsCpu object
  * \param[in] cm The camera manager
+ * \param[in] sharedStats Mapping of statistics buffer ids to statistics
+ *   instances that are shared with the IPA
  *
  * Creates a SwStatsCpu object and initialises shared memory for statistics
  * exchange.
@@ -159,12 +163,9 @@  namespace libcamera {
 
 LOG_DEFINE_CATEGORY(SwStatsCpu)
 
-SwStatsCpu::SwStatsCpu(const CameraManager &cm)
-	: sharedStats_("softIsp_stats"), bench_(cm, "CPU stats")
+SwStatsCpu::SwStatsCpu(const CameraManager &cm, std::unique_ptr<std::map<uint32_t, SharedMemObject<SwIspStats>>> sharedStats)
+	: sharedStats_(std::move(sharedStats)), bench_(cm, "CPU stats")
 {
-	if (!sharedStats_)
-		LOG(SwStatsCpu, Error)
-			<< "Failed to create shared memory for statistics";
 }
 
 static constexpr unsigned int kRedYMul = 77; /* 0.299 * 256 */
@@ -354,20 +355,21 @@  void SwStatsCpu::finishFrame(uint32_t frame,
 			     const uint32_t statsBufferId)
 {
 	bool valid = frame % kStatPerNumFrames == 0;
+	SharedMemObject<SwIspStats> &stats = sharedStats_->at(statsBufferId);
 
 	if (valid) {
-		sharedStats_->sum_ = RGB<uint64_t>({ 0, 0, 0 });
-		sharedStats_->yHistogram.fill(0);
+		stats->sum_ = RGB<uint64_t>({ 0, 0, 0 });
+		stats->yHistogram.fill(0);
 		for (const auto &s : stats_) {
-			sharedStats_->sum_ += s.sum_;
+			stats->sum_ += s.sum_;
 			for (unsigned int j = 0; j < SwIspStats::kYHistogramSize; j++)
-				sharedStats_->yHistogram[j] += s.yHistogram[j];
+				stats->yHistogram[j] += s.yHistogram[j];
 		}
 
-		sharedStats_->sum_ >>= sumShift_;
+		stats->sum_ >>= sumShift_;
 	}
 
-	sharedStats_->valid = valid;
+	stats->valid = valid;
 	statsReady.emit(frame, statsBufferId);
 }