[v2,1/8] libcamera: software_isp: Let a single point decide about computing stats
diff mbox series

Message ID 20261031184040.20139-2-mzamazal@redhat.com
State New
Headers show
Series
  • Autofocus basics for software ISP
Related show

Commit Message

Milan Zamazal Oct. 31, 2026, 6:40 p.m. UTC
Currently, the decision whether to compute stats for a given frame is
implemented in SwStatsCpu in several places and duplicated in
debayer_egl.cpp.  Let's decide it solely in SwStatsCpu.  This will also
help if a more flexible or complex update frequency is introduced,
e.g. to support stats for autofocus.

Signed-off-by: Milan Zamazal <mzamazal@redhat.com>
---
 .../internal/software_isp/swstats_cpu.h       | 21 ++++++++++---------
 src/libcamera/software_isp/debayer_egl.cpp    |  6 +++---
 src/libcamera/software_isp/swstats_cpu.cpp    | 16 +++++++++++---
 3 files changed, 27 insertions(+), 16 deletions(-)

Patch
diff mbox series

diff --git a/include/libcamera/internal/software_isp/swstats_cpu.h b/include/libcamera/internal/software_isp/swstats_cpu.h
index 551870921..615049084 100644
--- a/include/libcamera/internal/software_isp/swstats_cpu.h
+++ b/include/libcamera/internal/software_isp/swstats_cpu.h
@@ -38,14 +38,6 @@  public:
 	SwStatsCpu(const CameraManager &cm);
 	~SwStatsCpu() = default;
 
-	/*
-	 * The combination of pipeline + sensor delays means that
-	 * exposure changes can take up to 3 frames to get applied,
-	 * Run stats once every 4 frames to ensure any previous
-	 * exposure changes have been applied.
-	 */
-	static constexpr uint32_t kStatPerNumFrames = 4;
-
 	bool isValid() const { return sharedStats_.fd().isValid(); }
 
 	const SharedFD &getStatsFD() { return sharedStats_.fd(); }
@@ -54,13 +46,14 @@  public:
 
 	int configure(const StreamConfiguration &inputCfg, unsigned int statsBufferCount = 1);
 	void setWindow(const Rectangle &window);
+	bool updating(uint32_t frame);
 	void startFrame(uint32_t frame);
 	void finishFrame(uint32_t frame, uint32_t bufferId);
 	void processFrame(uint32_t frame, uint32_t bufferId, MappedFrameBuffer &input);
 
 	void processLine0(uint32_t frame, unsigned int y, const uint8_t *src[], unsigned int statsBufferIndex = 0)
 	{
-		if (frame % kStatPerNumFrames)
+		if (!updating(frame))
 			return;
 
 		if ((y & ySkipMask_) || y < static_cast<unsigned int>(window_.y) ||
@@ -72,7 +65,7 @@  public:
 
 	void processLine2(uint32_t frame, unsigned int y, const uint8_t *src[], unsigned int statsBufferIndex = 0)
 	{
-		if (frame % kStatPerNumFrames)
+		if (!updating(frame))
 			return;
 
 		if ((y & ySkipMask_) || y < static_cast<unsigned int>(window_.y) ||
@@ -88,6 +81,14 @@  private:
 	using statsProcessFn = void (SwStatsCpu::*)(const uint8_t *src[], SwIspStats &stats);
 	using processFrameFn = void (SwStatsCpu::*)(MappedFrameBuffer &in);
 
+	/*
+	 * The combination of pipeline + sensor delays means that
+	 * exposure changes can take up to 3 frames to get applied,
+	 * Run stats once every 4 frames to ensure any previous
+	 * exposure changes have been applied.
+	 */
+	static constexpr uint32_t kStatPerNumFrames = 4;
+
 	int setupStandardBayerOrder(BayerFormat::Order order);
 	/* Bayer 8 bpp unpacked */
 	void statsBGGR8Line0(const uint8_t *src[], SwIspStats &stats);
diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp
index 33933b11d..af5eaab93 100644
--- a/src/libcamera/software_isp/debayer_egl.cpp
+++ b/src/libcamera/software_isp/debayer_egl.cpp
@@ -646,9 +646,7 @@  void DebayerEGL::process(uint32_t frame, FrameBuffer *input, FrameBuffer *output
 	metadata.planes()[0].bytesused = output->planes()[0].length;
 
 	/* Calculate stats for the whole frame */
-	if (frame % SwStatsCpu::kStatPerNumFrames) {
-		stats_->finishFrame(frame, 0);
-	} else {
+	if (stats_->updating(frame)) {
 		if (!inMapped) {
 			/*
 			 * The buffer was directly imported into EGL and thus
@@ -660,6 +658,8 @@  void DebayerEGL::process(uint32_t frame, FrameBuffer *input, FrameBuffer *output
 			inMapped.emplace(input, MappedFrameBuffer::MapFlag::Read);
 		}
 		stats_->processFrame(frame, 0, inMapped.value());
+	} else {
+		stats_->finishFrame(frame, 0);
 	}
 	inDmaSyncer.reset();
 
diff --git a/src/libcamera/software_isp/swstats_cpu.cpp b/src/libcamera/software_isp/swstats_cpu.cpp
index 74633815e..0aa5597a9 100644
--- a/src/libcamera/software_isp/swstats_cpu.cpp
+++ b/src/libcamera/software_isp/swstats_cpu.cpp
@@ -398,7 +398,7 @@  void SwStatsCpu::statsGBRG12PLine0(const uint8_t *src[], SwIspStats &stats)
  */
 void SwStatsCpu::startFrame(uint32_t frame)
 {
-	if (frame % kStatPerNumFrames)
+	if (!updating(frame))
 		return;
 
 	if (window_.width == 0)
@@ -420,7 +420,7 @@  void SwStatsCpu::startFrame(uint32_t frame)
  */
 void SwStatsCpu::finishFrame(uint32_t frame, uint32_t bufferId)
 {
-	bool valid = frame % kStatPerNumFrames == 0;
+	bool valid = updating(frame);
 
 	if (valid) {
 		sharedStats_->sum_ = RGB<uint64_t>({ 0, 0, 0 });
@@ -622,7 +622,7 @@  void SwStatsCpu::processBayerFrame2(MappedFrameBuffer &in)
  */
 void SwStatsCpu::processFrame(uint32_t frame, uint32_t bufferId, MappedFrameBuffer &input)
 {
-	if (frame % kStatPerNumFrames) {
+	if (!updating(frame)) {
 		finishFrame(frame, bufferId);
 		return;
 	}
@@ -634,4 +634,14 @@  void SwStatsCpu::processFrame(uint32_t frame, uint32_t bufferId, MappedFrameBuff
 	bench_.finishFrame();
 }
 
+/**
+ * \brief Determine whether stats update is required for the given frame
+ * \param[in] frame The frame number
+ * \return Whether the stats are updated for the given frame
+ */
+bool SwStatsCpu::updating(uint32_t frame)
+{
+	return frame % kStatPerNumFrames == 0;
+}
+
 } /* namespace libcamera */