[v3,06/11] tests: Check the configured CPU image crop
diff mbox series

Message ID 20261016202818.1405645-7-halfline@gmail.com
State New
Headers show
Series
  • software-isp: Align crops, statistics and metadata
Related show

Commit Message

Ray Strode Oct. 16, 2026, 8:28 p.m. UTC
From: Ray Strode <rstrode@redhat.com>

This commit checks the crop returned by CPU debayering for supported Bayer
input formats and both RGB channel orders.

Unpacked kernels may shift the first rendered pixel by one column depending
on the Bayer pattern and output channel order. The reported image region
must include that shift, while the specialized packed kernels retain their
unshifted origin.

The configuration-only cases cover all four standard Bayer orders at 8, 10
and 12 bits, including packed RAW10 and RAW12. Reusing the debayer across
configurations also checks that changing formats clears a previous phase
shift.

Signed-off-by: Ray Strode <rstrode@redhat.com>
---
 test/meson.build                   |   1 +
 test/software_isp/debayer-crop.cpp | 102 +++++++++++++++++++++++++++++
 test/software_isp/meson.build      |  20 ++++++
 3 files changed, 123 insertions(+)
 create mode 100644 test/software_isp/debayer-crop.cpp
 create mode 100644 test/software_isp/meson.build

Patch
diff mbox series

diff --git a/test/meson.build b/test/meson.build
index 5027b7b1..fc72d105 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -35,6 +35,7 @@  subdir('media_device')
 subdir('process')
 subdir('py')
 subdir('serialization')
+subdir('software_isp')
 subdir('stream')
 subdir('v4l2_compat')
 subdir('v4l2_subdevice')
diff --git a/test/software_isp/debayer-crop.cpp b/test/software_isp/debayer-crop.cpp
new file mode 100644
index 00000000..40355b5a
--- /dev/null
+++ b/test/software_isp/debayer-crop.cpp
@@ -0,0 +1,102 @@ 
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2026, Red Hat Inc.
+ *
+ * CPU debayer crop configuration tests
+ */
+
+#include <functional>
+#include <iostream>
+#include <memory>
+#include <tuple>
+#include <utility>
+#include <vector>
+
+#include <libcamera/camera_manager.h>
+#include <libcamera/formats.h>
+#include <libcamera/stream.h>
+
+#include "libcamera/internal/formats.h"
+#include "libcamera/internal/software_isp/swstats_cpu.h"
+
+#include "debayer_cpu.h"
+#include "test.h"
+
+using namespace libcamera;
+
+class DebayerCropTest : public Test
+{
+protected:
+	int run() override
+	{
+		CameraManager manager;
+		auto stats = std::make_unique<SwStatsCpu>(manager);
+		if (!stats->isValid())
+			return TestFail;
+
+		DebayerCpu debayer(std::move(stats), manager);
+		static const struct {
+			PixelFormat input;
+			int rgbShift;
+			int bgrShift;
+		} cases[] = {
+			{ formats::SBGGR8, 0, 1 },
+			{ formats::SGBRG8, 1, 0 },
+			{ formats::SGRBG8, 0, 1 },
+			{ formats::SRGGB8, 1, 0 },
+			{ formats::SBGGR10, 0, 1 },
+			{ formats::SGBRG10, 1, 0 },
+			{ formats::SGRBG10, 0, 1 },
+			{ formats::SRGGB10, 1, 0 },
+			{ formats::SBGGR12, 0, 1 },
+			{ formats::SGBRG12, 1, 0 },
+			{ formats::SGRBG12, 0, 1 },
+			{ formats::SRGGB12, 1, 0 },
+			/* Packed kernels use each Bayer order without a phase shift. */
+			{ formats::SBGGR10_CSI2P, 0, 0 },
+			{ formats::SGBRG10_CSI2P, 0, 0 },
+			{ formats::SGRBG10_CSI2P, 0, 0 },
+			{ formats::SRGGB10_CSI2P, 0, 0 },
+			{ formats::SBGGR12_CSI2P, 0, 0 },
+			{ formats::SGBRG12_CSI2P, 0, 0 },
+			{ formats::SGRBG12_CSI2P, 0, 0 },
+			{ formats::SRGGB12_CSI2P, 0, 0 },
+		};
+
+		for (const auto &entry : cases) {
+			StreamConfiguration input;
+			input.pixelFormat = entry.input;
+			input.size = { 1928, 1092 };
+			input.stride = PixelFormatInfo::info(entry.input).stride(input.size.width, 0);
+
+			for (PixelFormat format : { formats::RGB888, formats::BGR888,
+						    formats::XRGB8888, formats::XBGR8888 }) {
+				StreamConfiguration output;
+				output.pixelFormat = format;
+				output.size = { 1280, 720 };
+				std::tie(output.stride, output.frameSize) =
+					debayer.strideAndFrameSize(format, output.size);
+				const std::vector<std::reference_wrapper<const StreamConfiguration>> outputs{ output };
+				if (debayer.configure(input, outputs, false)) {
+					std::cerr << "Unable to configure " << entry.input << " -> " << format
+						  << std::endl;
+					return TestFail;
+				}
+
+				int shift = (format == formats::RGB888 || format == formats::XRGB8888)
+						    ? entry.rgbShift
+						    : entry.bgrShift;
+				Rectangle expected(324 + shift, 186, 1280, 720);
+				if (debayer.inputCrop() != expected) {
+					std::cerr << "Crop for " << entry.input << " -> " << format << " is "
+						  << debayer.inputCrop() << ", expected " << expected << std::endl;
+					return TestFail;
+				}
+			}
+		}
+
+		return TestPass;
+	}
+};
+
+TEST_REGISTER(DebayerCropTest)
diff --git a/test/software_isp/meson.build b/test/software_isp/meson.build
new file mode 100644
index 00000000..ebabde59
--- /dev/null
+++ b/test/software_isp/meson.build
@@ -0,0 +1,20 @@ 
+# SPDX-License-Identifier: CC0-1.0
+
+if not softisp_enabled
+    subdir_done()
+endif
+
+software_isp_tests = [
+    {'name': 'debayer-crop', 'sources': ['debayer-crop.cpp']},
+]
+
+foreach test : software_isp_tests
+    exe = executable(test['name'], test['sources'],
+                     dependencies : libcamera_private,
+                     implicit_include_directories : false,
+                     link_with : test_libraries,
+                     include_directories : [test_includes_internal,
+                                            '../../src/libcamera/software_isp/'])
+
+    test(test['name'], exe, suite : 'software_isp')
+endforeach