[libcamera-devel,03/11] libcamera: software_isp: Add SwStats base class
diff mbox series

Message ID 20231214121350.206015-4-hdegoede@redhat.com
State Superseded
Headers show
Series
  • libcamera: introduce Software ISP and Software IPA
Related show

Commit Message

Hans de Goede Dec. 14, 2023, 12:13 p.m. UTC
Add a virtual base class for CPU based software statistics gathering
implementations.

The idea is for the implementations to offer a configure function +
functions to gather statistics on a line by line basis. This allows
CPU based software debayering to call into interlace debayering and
statistics gathering on a line by line bases while the input data
is still hot in the cache.

This base class also allows the user of an implementation to specify
a window over which to gather statistics instead of processing the
whole frame; and it allows the implementation to choose to only
process 1/2, 1/4th, etc. of the lines instead of processing all
lines (in the window) by setting y_skip_mask_ from configure().
Skipping columns is left up the line-processing functions provided
by the implementation.

The base class also provides a processFrame() convenience function
which collects statistics for an entire frame at once for use cases
where CPU based software debayering is not used.

Co-authored-by: Andrey Konovalov <andrey.konovalov@linaro.org>
Signed-off-by: Andrey Konovalov <andrey.konovalov@linaro.org>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 .../internal/software_isp/meson.build         |   6 +
 .../internal/software_isp/swisp_stats.h       |  21 +++
 .../libcamera/internal/software_isp/swstats.h | 150 ++++++++++++++++++
 src/libcamera/software_isp/meson.build        |   5 +
 src/libcamera/software_isp/swstats.cpp        |  65 ++++++++
 5 files changed, 247 insertions(+)
 create mode 100644 include/libcamera/internal/software_isp/meson.build
 create mode 100644 include/libcamera/internal/software_isp/swisp_stats.h
 create mode 100644 include/libcamera/internal/software_isp/swstats.h
 create mode 100644 src/libcamera/software_isp/meson.build
 create mode 100644 src/libcamera/software_isp/swstats.cpp

Patch
diff mbox series

diff --git a/include/libcamera/internal/software_isp/meson.build b/include/libcamera/internal/software_isp/meson.build
new file mode 100644
index 00000000..1c43acc4
--- /dev/null
+++ b/include/libcamera/internal/software_isp/meson.build
@@ -0,0 +1,6 @@ 
+# SPDX-License-Identifier: CC0-1.0
+
+libcamera_internal_headers += files([
+    'swisp_stats.h',
+    'swstats.h',
+])
diff --git a/include/libcamera/internal/software_isp/swisp_stats.h b/include/libcamera/internal/software_isp/swisp_stats.h
new file mode 100644
index 00000000..f7afbaa4
--- /dev/null
+++ b/include/libcamera/internal/software_isp/swisp_stats.h
@@ -0,0 +1,21 @@ 
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2023, Linaro Ltd
+ *
+ * swisp_stats.h - Statistics data format used by the software ISP and software IPA
+ */
+
+#pragma once
+
+namespace libcamera {
+
+struct SwIspStats {
+	unsigned long sumR_;
+	unsigned long sumB_;
+	unsigned long sumG_;
+
+	float bright_ratio;
+	float too_bright_ratio;
+};
+
+} /* namespace libcamera */
diff --git a/include/libcamera/internal/software_isp/swstats.h b/include/libcamera/internal/software_isp/swstats.h
new file mode 100644
index 00000000..0e7407f6
--- /dev/null
+++ b/include/libcamera/internal/software_isp/swstats.h
@@ -0,0 +1,150 @@ 
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2023, Linaro Ltd
+ * Copyright (C) 2023, Red Hat Inc.
+ *
+ * Authors:
+ * Hans de Goede <hdegoede@redhat.com> 
+ *
+ * swstats.h - software statistics base class
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+#include <libcamera/base/log.h>
+#include <libcamera/base/signal.h>
+
+#include <libcamera/geometry.h>
+
+namespace libcamera {
+
+class PixelFormat;
+struct SharedFD;
+struct StreamConfiguration;
+
+LOG_DECLARE_CATEGORY(SwStats)
+
+class SwStats
+{
+public:
+	virtual ~SwStats() = 0;
+
+	virtual bool isValid() const = 0;
+
+	/*
+	 * Setup the SwStats object for the passed in input format.
+	 * Return 0 on success, a negative errno value on failure
+	 * (unsupported format or failed to create the SharedMemObject).
+	 */
+	virtual int configure(const StreamConfiguration &inputCfg) = 0;
+
+	/* Get the FD for the SharedMemObject for the stats. */
+	virtual const SharedFD &getStatsFD() = 0;
+
+protected:
+	typedef void (SwStats::*statsProcessFn)(const uint8_t *src, unsigned int stride);
+	typedef void (SwStats::*statsVoidFn)();
+
+	/* Variables set by configure(), used every line */
+	statsProcessFn stats0_;
+	statsProcessFn stats2_;
+
+	unsigned int bpp_;         /* Memory used per pixel, not precision */
+	unsigned int y_skip_mask_; /* Skip lines where this bitmask is set in y */
+
+	/* Statistics windows, set by setWindow(), used every line */
+	Rectangle window_;
+
+	/* Variables set by configure(), used once per frame */
+	statsVoidFn startFrame_;
+	statsVoidFn finishFrame_;
+	Size patternSize_;
+	unsigned int x_shift_; /* Offset of 0/1 applied to window_.x for bayer variants */
+
+public:
+	/*
+	 * For some input-formats, e.g. Bayer data, processing is done multiple lines
+	 * and/or columns at a time. Get width and height at which the (bayer) pattern
+	 * repeats. Window values are rounded down to a multiple of this and the height
+	 * also indicates if processLine2() should be called or not.
+	 * This may only be called after a successful configure() call.
+	 */
+	const Size &patternSize() { return patternSize_; }
+
+	/*
+	 * Specify window coordinates over which to gather statistics.
+	 */
+	void setWindow(Rectangle window)
+	{
+		window_ = window;
+
+		window_.x &= ~(patternSize_.width - 1);
+		window_.x += x_shift_;
+		window_.y &= ~(patternSize_.height - 1);
+
+		/* width_ - x_shift_ to make sure the window fits */
+		window_.width -= x_shift_;
+		window_.width &= ~(patternSize_.width - 1);
+		window_.height &= ~(patternSize_.height - 1);
+	}
+
+	/*
+	 * Reset state to start statistic gathering for a new frame.
+	 * This may only be called after a successful setWindow() call.
+	 */
+	void startFrame()
+	{
+		(this->*startFrame_)();
+	}
+
+	/*
+	 * Process line 0 of input formats with patternSize height == 1.
+	 * Process line 0 + 1 of input formats with patternSize height >= 2.
+	 * This may only be called after a successful setWindow() call.
+	 */
+	void processLine0(unsigned int y, const uint8_t *src, unsigned int stride)
+	{
+		if ((y & y_skip_mask_) || y < (unsigned int)window_.y ||
+		    y >= (window_.y + window_.height))
+			return;
+
+		(this->*stats0_)(src + window_.x * bpp_ / 8, stride);
+	}
+
+	/*
+	 * Process lines 2 + 3 of input formats with patternSize height == 4.
+	 * This may only be called after a successful setWindow() call.
+	 */
+	void processLine2(unsigned int y, const uint8_t *src, unsigned int stride)
+	{
+		if ((y & y_skip_mask_) || y < (unsigned int)window_.y ||
+		    y >= (window_.y + window_.height))
+			return;
+
+		(this->*stats2_)(src + window_.x * bpp_ / 8, stride);
+	}
+
+	/*
+	 * Finish statistics calculation for current frame and
+	 * store the results in the SharedMemObject.
+	 * This may only be called after a successful setWindow() call.
+	 */
+	void finishFrame()
+	{
+		(this->*finishFrame_)();
+	}
+
+	/*
+	 * Process a whole frame at once, replacing manually calling
+	 * startFrame() + processLine0() + finishFrame().
+	 * This may only be called after a successful setWindow() call.
+	 */
+	void processFrame(const uint8_t *src, unsigned int stride);
+
+	/* The int parameter isn't actually used */
+	Signal<int> statsReady;
+};
+
+} /* namespace libcamera */
diff --git a/src/libcamera/software_isp/meson.build b/src/libcamera/software_isp/meson.build
new file mode 100644
index 00000000..9359075d
--- /dev/null
+++ b/src/libcamera/software_isp/meson.build
@@ -0,0 +1,5 @@ 
+# SPDX-License-Identifier: CC0-1.0
+
+libcamera_sources += files([
+	'swstats.cpp',
+])
diff --git a/src/libcamera/software_isp/swstats.cpp b/src/libcamera/software_isp/swstats.cpp
new file mode 100644
index 00000000..9a5e1a10
--- /dev/null
+++ b/src/libcamera/software_isp/swstats.cpp
@@ -0,0 +1,65 @@ 
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2023, Linaro Ltd
+ * Copyright (C) 2023, Red Hat Inc.
+ *
+ * Authors:
+ * Hans de Goede <hdegoede@redhat.com> 
+ *
+ * swstats.cpp - software statistics base class
+ */
+
+#include "libcamera/internal/software_isp/swstats.h"
+
+namespace libcamera {
+
+LOG_DEFINE_CATEGORY(SwStats)
+
+void SwStats::processFrame(const uint8_t *src, unsigned int stride)
+{
+	unsigned int y_end = window_.y + window_.height;
+
+	startFrame();
+
+	/* Adjust src to point to starting corner of the statistics window */
+	src += window_.y * stride;
+	src += window_.x * bpp_ / 8;
+
+	switch (patternSize_.height) {
+	case 1:
+		for (unsigned int y = window_.y ; y < y_end; y++) {
+			if (!(y & y_skip_mask_))
+				(this->*stats0_)(src, stride);
+			src += stride;
+		}
+		break;
+	case 2:
+		for (unsigned int y = window_.y ; y < y_end; y += 2) {
+			if (!(y & y_skip_mask_))
+				(this->*stats0_)(src, stride);
+			src += 2 * stride;
+		}
+		break;
+	case 4:
+		for (unsigned int y = window_.y ; y < y_end; y += 4) {
+			if (y & y_skip_mask_) {
+				src += 4 * stride;
+				continue;
+			}
+
+			(this->*stats0_)(src, stride);
+			src += 2 * stride;
+			(this->*stats2_)(src, stride);
+			src += 2 * stride;
+		}
+		break;
+	}
+
+	finishFrame();
+}
+
+SwStats::~SwStats()
+{
+}
+
+} /* namespace libcamera */