[v4,14/18] libcamera: debayer_cpu: Add support for 8, 10 and 12 bpp unpacked bayer input
diff mbox series

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

Commit Message

Hans de Goede Feb. 29, 2024, 6:36 p.m. UTC
Add support for 8, 10 and 12 bpp unpacked bayer input for all 4 standard
bayer orders.

Tested-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org> # sc8280xp Lenovo x13s
Tested-by: Pavel Machek <pavel@ucw.cz>
Reviewed-by: Pavel Machek <pavel@ucw.cz>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
Changes in v3:
- Also add support for 12bpp (by Kieran Bingham)
---
 src/libcamera/software_isp/debayer_cpu.cpp | 128 +++++++++++++++++++++
 src/libcamera/software_isp/debayer_cpu.h   |  13 +++
 2 files changed, 141 insertions(+)

Comments

Milan Zamazal March 4, 2024, 5:42 p.m. UTC | #1
Hans de Goede <hdegoede@redhat.com> writes:

> Add support for 8, 10 and 12 bpp unpacked bayer input for all 4 standard
> bayer orders.
>
> Tested-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org> # sc8280xp Lenovo x13s
> Tested-by: Pavel Machek <pavel@ucw.cz>
> Reviewed-by: Pavel Machek <pavel@ucw.cz>
> Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
> Signed-off-by: Hans de Goede <hdegoede@redhat.com>

Reviewed-by: Milan Zamazal <mzamazal@redhat.com>

(My e-mail client displays smileys in this patch so it must be right.)

> ---
> Changes in v3:
> - Also add support for 12bpp (by Kieran Bingham)
> ---
>  src/libcamera/software_isp/debayer_cpu.cpp | 128 +++++++++++++++++++++
>  src/libcamera/software_isp/debayer_cpu.h   |  13 +++
>  2 files changed, 141 insertions(+)
>
> diff --git a/src/libcamera/software_isp/debayer_cpu.cpp b/src/libcamera/software_isp/debayer_cpu.cpp
> index 53e90776..22ae99cd 100644
> --- a/src/libcamera/software_isp/debayer_cpu.cpp
> +++ b/src/libcamera/software_isp/debayer_cpu.cpp
> @@ -56,6 +56,11 @@ DebayerCpu::~DebayerCpu()
>  		free(lineBuffers_[i]);
>  }
>  
> +#define DECLARE_SRC_POINTERS(pixel_t)                            \
> +	const pixel_t *prev = (const pixel_t *)src[0] + xShift_; \
> +	const pixel_t *curr = (const pixel_t *)src[1] + xShift_; \
> +	const pixel_t *next = (const pixel_t *)src[2] + xShift_;
> +
>  // RGR
>  // GBG
>  // RGR
> @@ -92,6 +97,70 @@ DebayerCpu::~DebayerCpu()
>  	*dst++ = red_[curr[x] / (div)];                                                        \
>  	x++;
>  
> +void DebayerCpu::debayer8_BGBG_BGR888(uint8_t *dst, const uint8_t *src[])
> +{
> +	DECLARE_SRC_POINTERS(uint8_t)
> +
> +	for (int x = 0; x < (int)window_.width;) {
> +		BGGR_BGR888(1, 1, 1)
> +		GBRG_BGR888(1, 1, 1)
> +	}
> +}
> +
> +void DebayerCpu::debayer8_GRGR_BGR888(uint8_t *dst, const uint8_t *src[])
> +{
> +	DECLARE_SRC_POINTERS(uint8_t)
> +
> +	for (int x = 0; x < (int)window_.width;) {
> +		GRBG_BGR888(1, 1, 1)
> +		RGGB_BGR888(1, 1, 1)
> +	}
> +}
> +
> +void DebayerCpu::debayer10_BGBG_BGR888(uint8_t *dst, const uint8_t *src[])
> +{
> +	DECLARE_SRC_POINTERS(uint16_t)
> +
> +	for (int x = 0; x < (int)window_.width;) {
> +		/* divide values by 4 for 10 -> 8 bpp value */
> +		BGGR_BGR888(1, 1, 4)
> +		GBRG_BGR888(1, 1, 4)
> +	}
> +}
> +
> +void DebayerCpu::debayer10_GRGR_BGR888(uint8_t *dst, const uint8_t *src[])
> +{
> +	DECLARE_SRC_POINTERS(uint16_t)
> +
> +	for (int x = 0; x < (int)window_.width;) {
> +		/* divide values by 4 for 10 -> 8 bpp value */
> +		GRBG_BGR888(1, 1, 4)
> +		RGGB_BGR888(1, 1, 4)
> +	}
> +}
> +
> +void DebayerCpu::debayer12_BGBG_BGR888(uint8_t *dst, const uint8_t *src[])
> +{
> +	DECLARE_SRC_POINTERS(uint16_t)
> +
> +	for (int x = 0; x < (int)window_.width;) {
> +		/* divide values by 16 for 12 -> 8 bpp value */
> +		BGGR_BGR888(1, 1, 16)
> +		GBRG_BGR888(1, 1, 16)
> +	}
> +}
> +
> +void DebayerCpu::debayer12_GRGR_BGR888(uint8_t *dst, const uint8_t *src[])
> +{
> +	DECLARE_SRC_POINTERS(uint16_t)
> +
> +	for (int x = 0; x < (int)window_.width;) {
> +		/* divide values by 16 for 12 -> 8 bpp value */
> +		GRBG_BGR888(1, 1, 16)
> +		RGGB_BGR888(1, 1, 16)
> +	}
> +}
> +
>  void DebayerCpu::debayer10P_BGBG_BGR888(uint8_t *dst, const uint8_t *src[])
>  {
>  	const int width_in_bytes = window_.width * 5 / 4;
> @@ -186,6 +255,16 @@ int DebayerCpu::getInputConfig(PixelFormat inputFormat, DebayerInputConfig &conf
>  	BayerFormat bayerFormat =
>  		BayerFormat::fromPixelFormat(inputFormat);
>  
> +	if ((bayerFormat.bitDepth == 8 || bayerFormat.bitDepth == 10 || bayerFormat.bitDepth == 12) &&
> +	    bayerFormat.packing == BayerFormat::Packing::None &&
> +	    isStandardBayerOrder(bayerFormat.order)) {
> +		config.bpp = (bayerFormat.bitDepth + 7) & ~7;
> +		config.patternSize.width = 2;
> +		config.patternSize.height = 2;
> +		config.outputFormats = std::vector<PixelFormat>({ formats::RGB888 });
> +		return 0;
> +	}
> +
>  	if (bayerFormat.bitDepth == 10 &&
>  	    bayerFormat.packing == BayerFormat::Packing::CSI2 &&
>  	    isStandardBayerOrder(bayerFormat.order)) {
> @@ -213,12 +292,61 @@ int DebayerCpu::getOutputConfig(PixelFormat outputFormat, DebayerOutputConfig &c
>  	return -EINVAL;
>  }
>  
> +/*
> + * Check for standard Bayer orders and set xShift_ and swap debayer0/1, so that
> + * a single pair of BGGR debayer functions can be used for all 4 standard orders.
> + */
> +int DebayerCpu::setupStandardBayerOrder(BayerFormat::Order order)
> +{
> +	switch (order) {
> +	case BayerFormat::BGGR:
> +		break;
> +	case BayerFormat::GBRG:
> +		xShift_ = 1; /* BGGR -> GBRG */
> +		break;
> +	case BayerFormat::GRBG:
> +		std::swap(debayer0_, debayer1_); /* BGGR -> GRBG */
> +		break;
> +	case BayerFormat::RGGB:
> +		xShift_ = 1; /* BGGR -> GBRG */
> +		std::swap(debayer0_, debayer1_); /* GBRG -> RGGB */
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
>  /* TODO: this ignores outputFormat since there is only 1 supported outputFormat for now */
>  int DebayerCpu::setDebayerFunctions(PixelFormat inputFormat, [[maybe_unused]] PixelFormat outputFormat)
>  {
>  	BayerFormat bayerFormat =
>  		BayerFormat::fromPixelFormat(inputFormat);
>  
> +	xShift_ = 0;
> +
> +	if ((bayerFormat.bitDepth == 8 || bayerFormat.bitDepth == 10 || bayerFormat.bitDepth == 12) &&
> +	    bayerFormat.packing == BayerFormat::Packing::None &&
> +	    isStandardBayerOrder(bayerFormat.order)) {
> +		switch (bayerFormat.bitDepth) {
> +		case 8:
> +			debayer0_ = &DebayerCpu::debayer8_BGBG_BGR888;
> +			debayer1_ = &DebayerCpu::debayer8_GRGR_BGR888;
> +			break;
> +		case 10:
> +			debayer0_ = &DebayerCpu::debayer10_BGBG_BGR888;
> +			debayer1_ = &DebayerCpu::debayer10_GRGR_BGR888;
> +			break;
> +		case 12:
> +			debayer0_ = &DebayerCpu::debayer12_BGBG_BGR888;
> +			debayer1_ = &DebayerCpu::debayer12_GRGR_BGR888;
> +			break;
> +		}
> +		setupStandardBayerOrder(bayerFormat.order);
> +		return 0;
> +	}
> +
>  	if (bayerFormat.bitDepth == 10 &&
>  	    bayerFormat.packing == BayerFormat::Packing::CSI2) {
>  		switch (bayerFormat.order) {
> diff --git a/src/libcamera/software_isp/debayer_cpu.h b/src/libcamera/software_isp/debayer_cpu.h
> index 98782838..73ca41f1 100644
> --- a/src/libcamera/software_isp/debayer_cpu.h
> +++ b/src/libcamera/software_isp/debayer_cpu.h
> @@ -17,6 +17,8 @@
>  
>  #include <libcamera/base/object.h>
>  
> +#include "libcamera/internal/bayer_format.h"
> +
>  #include "debayer.h"
>  #include "swstats_cpu.h"
>  
> @@ -82,6 +84,15 @@ private:
>  	 */
>  	using debayerFn = void (DebayerCpu::*)(uint8_t *dst, const uint8_t *src[]);
>  
> +	/* 8-bit raw bayer format */
> +	void debayer8_BGBG_BGR888(uint8_t *dst, const uint8_t *src[]);
> +	void debayer8_GRGR_BGR888(uint8_t *dst, const uint8_t *src[]);
> +	/* unpacked 10-bit raw bayer format */
> +	void debayer10_BGBG_BGR888(uint8_t *dst, const uint8_t *src[]);
> +	void debayer10_GRGR_BGR888(uint8_t *dst, const uint8_t *src[]);
> +	/* unpacked 12-bit raw bayer format */
> +	void debayer12_BGBG_BGR888(uint8_t *dst, const uint8_t *src[]);
> +	void debayer12_GRGR_BGR888(uint8_t *dst, const uint8_t *src[]);
>  	/* CSI-2 packed 10-bit raw bayer format (all the 4 orders) */
>  	void debayer10P_BGBG_BGR888(uint8_t *dst, const uint8_t *src[]);
>  	void debayer10P_GRGR_BGR888(uint8_t *dst, const uint8_t *src[]);
> @@ -103,6 +114,7 @@ private:
>  
>  	int getInputConfig(PixelFormat inputFormat, DebayerInputConfig &config);
>  	int getOutputConfig(PixelFormat outputFormat, DebayerOutputConfig &config);
> +	int setupStandardBayerOrder(BayerFormat::Order order);
>  	int setDebayerFunctions(PixelFormat inputFormat, PixelFormat outputFormat);
>  	void setupInputMemcpy(const uint8_t *linePointers[]);
>  	void shiftLinePointers(const uint8_t *linePointers[], const uint8_t *src);
> @@ -131,6 +143,7 @@ private:
>  	unsigned int lineBufferLength_;
>  	unsigned int lineBufferPadding_;
>  	unsigned int lineBufferIndex_;
> +	unsigned int xShift_; /* Offset of 0/1 applied to window_.x */
>  	bool enableInputMemcpy_;
>  	float gamma_correction_;
>  	unsigned int measuredFrames_;

Patch
diff mbox series

diff --git a/src/libcamera/software_isp/debayer_cpu.cpp b/src/libcamera/software_isp/debayer_cpu.cpp
index 53e90776..22ae99cd 100644
--- a/src/libcamera/software_isp/debayer_cpu.cpp
+++ b/src/libcamera/software_isp/debayer_cpu.cpp
@@ -56,6 +56,11 @@  DebayerCpu::~DebayerCpu()
 		free(lineBuffers_[i]);
 }
 
+#define DECLARE_SRC_POINTERS(pixel_t)                            \
+	const pixel_t *prev = (const pixel_t *)src[0] + xShift_; \
+	const pixel_t *curr = (const pixel_t *)src[1] + xShift_; \
+	const pixel_t *next = (const pixel_t *)src[2] + xShift_;
+
 // RGR
 // GBG
 // RGR
@@ -92,6 +97,70 @@  DebayerCpu::~DebayerCpu()
 	*dst++ = red_[curr[x] / (div)];                                                        \
 	x++;
 
+void DebayerCpu::debayer8_BGBG_BGR888(uint8_t *dst, const uint8_t *src[])
+{
+	DECLARE_SRC_POINTERS(uint8_t)
+
+	for (int x = 0; x < (int)window_.width;) {
+		BGGR_BGR888(1, 1, 1)
+		GBRG_BGR888(1, 1, 1)
+	}
+}
+
+void DebayerCpu::debayer8_GRGR_BGR888(uint8_t *dst, const uint8_t *src[])
+{
+	DECLARE_SRC_POINTERS(uint8_t)
+
+	for (int x = 0; x < (int)window_.width;) {
+		GRBG_BGR888(1, 1, 1)
+		RGGB_BGR888(1, 1, 1)
+	}
+}
+
+void DebayerCpu::debayer10_BGBG_BGR888(uint8_t *dst, const uint8_t *src[])
+{
+	DECLARE_SRC_POINTERS(uint16_t)
+
+	for (int x = 0; x < (int)window_.width;) {
+		/* divide values by 4 for 10 -> 8 bpp value */
+		BGGR_BGR888(1, 1, 4)
+		GBRG_BGR888(1, 1, 4)
+	}
+}
+
+void DebayerCpu::debayer10_GRGR_BGR888(uint8_t *dst, const uint8_t *src[])
+{
+	DECLARE_SRC_POINTERS(uint16_t)
+
+	for (int x = 0; x < (int)window_.width;) {
+		/* divide values by 4 for 10 -> 8 bpp value */
+		GRBG_BGR888(1, 1, 4)
+		RGGB_BGR888(1, 1, 4)
+	}
+}
+
+void DebayerCpu::debayer12_BGBG_BGR888(uint8_t *dst, const uint8_t *src[])
+{
+	DECLARE_SRC_POINTERS(uint16_t)
+
+	for (int x = 0; x < (int)window_.width;) {
+		/* divide values by 16 for 12 -> 8 bpp value */
+		BGGR_BGR888(1, 1, 16)
+		GBRG_BGR888(1, 1, 16)
+	}
+}
+
+void DebayerCpu::debayer12_GRGR_BGR888(uint8_t *dst, const uint8_t *src[])
+{
+	DECLARE_SRC_POINTERS(uint16_t)
+
+	for (int x = 0; x < (int)window_.width;) {
+		/* divide values by 16 for 12 -> 8 bpp value */
+		GRBG_BGR888(1, 1, 16)
+		RGGB_BGR888(1, 1, 16)
+	}
+}
+
 void DebayerCpu::debayer10P_BGBG_BGR888(uint8_t *dst, const uint8_t *src[])
 {
 	const int width_in_bytes = window_.width * 5 / 4;
@@ -186,6 +255,16 @@  int DebayerCpu::getInputConfig(PixelFormat inputFormat, DebayerInputConfig &conf
 	BayerFormat bayerFormat =
 		BayerFormat::fromPixelFormat(inputFormat);
 
+	if ((bayerFormat.bitDepth == 8 || bayerFormat.bitDepth == 10 || bayerFormat.bitDepth == 12) &&
+	    bayerFormat.packing == BayerFormat::Packing::None &&
+	    isStandardBayerOrder(bayerFormat.order)) {
+		config.bpp = (bayerFormat.bitDepth + 7) & ~7;
+		config.patternSize.width = 2;
+		config.patternSize.height = 2;
+		config.outputFormats = std::vector<PixelFormat>({ formats::RGB888 });
+		return 0;
+	}
+
 	if (bayerFormat.bitDepth == 10 &&
 	    bayerFormat.packing == BayerFormat::Packing::CSI2 &&
 	    isStandardBayerOrder(bayerFormat.order)) {
@@ -213,12 +292,61 @@  int DebayerCpu::getOutputConfig(PixelFormat outputFormat, DebayerOutputConfig &c
 	return -EINVAL;
 }
 
+/*
+ * Check for standard Bayer orders and set xShift_ and swap debayer0/1, so that
+ * a single pair of BGGR debayer functions can be used for all 4 standard orders.
+ */
+int DebayerCpu::setupStandardBayerOrder(BayerFormat::Order order)
+{
+	switch (order) {
+	case BayerFormat::BGGR:
+		break;
+	case BayerFormat::GBRG:
+		xShift_ = 1; /* BGGR -> GBRG */
+		break;
+	case BayerFormat::GRBG:
+		std::swap(debayer0_, debayer1_); /* BGGR -> GRBG */
+		break;
+	case BayerFormat::RGGB:
+		xShift_ = 1; /* BGGR -> GBRG */
+		std::swap(debayer0_, debayer1_); /* GBRG -> RGGB */
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 /* TODO: this ignores outputFormat since there is only 1 supported outputFormat for now */
 int DebayerCpu::setDebayerFunctions(PixelFormat inputFormat, [[maybe_unused]] PixelFormat outputFormat)
 {
 	BayerFormat bayerFormat =
 		BayerFormat::fromPixelFormat(inputFormat);
 
+	xShift_ = 0;
+
+	if ((bayerFormat.bitDepth == 8 || bayerFormat.bitDepth == 10 || bayerFormat.bitDepth == 12) &&
+	    bayerFormat.packing == BayerFormat::Packing::None &&
+	    isStandardBayerOrder(bayerFormat.order)) {
+		switch (bayerFormat.bitDepth) {
+		case 8:
+			debayer0_ = &DebayerCpu::debayer8_BGBG_BGR888;
+			debayer1_ = &DebayerCpu::debayer8_GRGR_BGR888;
+			break;
+		case 10:
+			debayer0_ = &DebayerCpu::debayer10_BGBG_BGR888;
+			debayer1_ = &DebayerCpu::debayer10_GRGR_BGR888;
+			break;
+		case 12:
+			debayer0_ = &DebayerCpu::debayer12_BGBG_BGR888;
+			debayer1_ = &DebayerCpu::debayer12_GRGR_BGR888;
+			break;
+		}
+		setupStandardBayerOrder(bayerFormat.order);
+		return 0;
+	}
+
 	if (bayerFormat.bitDepth == 10 &&
 	    bayerFormat.packing == BayerFormat::Packing::CSI2) {
 		switch (bayerFormat.order) {
diff --git a/src/libcamera/software_isp/debayer_cpu.h b/src/libcamera/software_isp/debayer_cpu.h
index 98782838..73ca41f1 100644
--- a/src/libcamera/software_isp/debayer_cpu.h
+++ b/src/libcamera/software_isp/debayer_cpu.h
@@ -17,6 +17,8 @@ 
 
 #include <libcamera/base/object.h>
 
+#include "libcamera/internal/bayer_format.h"
+
 #include "debayer.h"
 #include "swstats_cpu.h"
 
@@ -82,6 +84,15 @@  private:
 	 */
 	using debayerFn = void (DebayerCpu::*)(uint8_t *dst, const uint8_t *src[]);
 
+	/* 8-bit raw bayer format */
+	void debayer8_BGBG_BGR888(uint8_t *dst, const uint8_t *src[]);
+	void debayer8_GRGR_BGR888(uint8_t *dst, const uint8_t *src[]);
+	/* unpacked 10-bit raw bayer format */
+	void debayer10_BGBG_BGR888(uint8_t *dst, const uint8_t *src[]);
+	void debayer10_GRGR_BGR888(uint8_t *dst, const uint8_t *src[]);
+	/* unpacked 12-bit raw bayer format */
+	void debayer12_BGBG_BGR888(uint8_t *dst, const uint8_t *src[]);
+	void debayer12_GRGR_BGR888(uint8_t *dst, const uint8_t *src[]);
 	/* CSI-2 packed 10-bit raw bayer format (all the 4 orders) */
 	void debayer10P_BGBG_BGR888(uint8_t *dst, const uint8_t *src[]);
 	void debayer10P_GRGR_BGR888(uint8_t *dst, const uint8_t *src[]);
@@ -103,6 +114,7 @@  private:
 
 	int getInputConfig(PixelFormat inputFormat, DebayerInputConfig &config);
 	int getOutputConfig(PixelFormat outputFormat, DebayerOutputConfig &config);
+	int setupStandardBayerOrder(BayerFormat::Order order);
 	int setDebayerFunctions(PixelFormat inputFormat, PixelFormat outputFormat);
 	void setupInputMemcpy(const uint8_t *linePointers[]);
 	void shiftLinePointers(const uint8_t *linePointers[], const uint8_t *src);
@@ -131,6 +143,7 @@  private:
 	unsigned int lineBufferLength_;
 	unsigned int lineBufferPadding_;
 	unsigned int lineBufferIndex_;
+	unsigned int xShift_; /* Offset of 0/1 applied to window_.x */
 	bool enableInputMemcpy_;
 	float gamma_correction_;
 	unsigned int measuredFrames_;