[libcamera-devel,RFC] Add 8-bit bayer support.
diff mbox series

Message ID ZXt1mDW1SpMyLrbT@duo.ucw.cz
State New
Headers show
Series
  • [libcamera-devel,RFC] Add 8-bit bayer support.
Related show

Commit Message

Pavel Machek Dec. 14, 2023, 9:37 p.m. UTC
---

Did I get it mostly right? I can't test other formats but providing
them should not be too hard. Does it make sense to add this to your
series or is it better to just wait for v1 to be merged?

Comments

Hans de Goede Dec. 15, 2023, 2:17 p.m. UTC | #1
Hi Pavel,

On 12/14/23 22:37, Pavel Machek wrote:
> ---
> 
> Did I get it mostly right? I can't test other formats but providing
> them should not be too hard. Does it make sense to add this to your
> series or is it better to just wait for v1 to be merged?

Yes this looks about right. Yesterday I finished about a 10
day libcamera sprint so for now I'm not going to touch
libcamera for a few days.

I plan to get back to libcamera again on Wednesday.
I'll add a commit adding 8bpp bayer, all 4 orders,
to my personal libcamera softisp branch then and when
that is in place I'll send you an email asking to test it.

Regards,

Hans


> 
> 
> diff --git a/include/libcamera/internal/software_isp/debayer_cpu.h b/include/libcamera/internal/software_isp/debayer_cpu.h
> index 7fb5be77..f3bb4321 100644
> --- a/include/libcamera/internal/software_isp/debayer_cpu.h
> +++ b/include/libcamera/internal/software_isp/debayer_cpu.h
> @@ -67,6 +67,9 @@ private:
>  	void debayer10P_GBGB_BGR888(uint8_t *dst, const uint8_t *src);
>  	void debayer10P_RGRG_BGR888(uint8_t *dst, const uint8_t *src);
>  
> +	void debayer8_BGBG_BGR888(uint8_t *dst, const uint8_t *src);
> +	void debayer8_GRGR_BGR888(uint8_t *dst, const uint8_t *src);
> +
>  	typedef void (DebayerCpu::*debayerFn)(uint8_t *dst, const uint8_t *src);
>  
>  	struct DebayerInputConfig {
> diff --git a/include/libcamera/internal/software_isp/swstats_cpu.h b/include/libcamera/internal/software_isp/swstats_cpu.h
> index 0ceb995f..3c43e146 100644
> --- a/include/libcamera/internal/software_isp/swstats_cpu.h
> +++ b/include/libcamera/internal/software_isp/swstats_cpu.h
> @@ -29,6 +29,8 @@ public:
>  	/* FIXME this should be dropped once AWB has moved to the IPA */
>  	SwIspStats getStats() { return *sharedStats_; }
>  private:
> +	void statsBGGR8Line0(const uint8_t *src, unsigned int stride);
> +
>  	void statsBGGR10PLine0(const uint8_t *src, unsigned int stride);
>  	void statsGBRG10PLine0(const uint8_t *src, unsigned int stride);
>  	void statsGRBG10PLine0(const uint8_t *src, unsigned int stride);
> diff --git a/src/libcamera/software_isp/debayer_cpu.cpp b/src/libcamera/software_isp/debayer_cpu.cpp
> index 3eacdd5d..52910a03 100644
> --- a/src/libcamera/software_isp/debayer_cpu.cpp
> +++ b/src/libcamera/software_isp/debayer_cpu.cpp
> @@ -111,6 +111,36 @@ void DebayerCpu::debayer10P_GRGR_BGR888(uint8_t *dst, const uint8_t *src)
>  	}
>  }
>  
> +void DebayerCpu::debayer8_BGBG_BGR888(uint8_t *dst, const uint8_t *src)
> +{
> +	const int width_in_bytes = window_.width;
> +	struct ctxt_8bit_src c = {
> +		src - inputConfig_.stride, src, src + inputConfig_.stride,
> +		red_, green_, blue_ };
> +
> +	for (int x = 0; x < width_in_bytes; ) {
> +		/* Even pixel */
> +		bggr8_bgr888(c, dst, x++, 1, 1);
> +		/* Odd pixel BGGR -> GBRG */
> +		gbrg8_bgr888(c, dst, x++, 1, 1);
> +	}
> +}
> +
> +void DebayerCpu::debayer8_GRGR_BGR888(uint8_t *dst, const uint8_t *src)
> +{
> +	const int width_in_bytes = window_.width;
> +	struct ctxt_8bit_src c = {
> +		src - inputConfig_.stride, src, src + inputConfig_.stride,
> +		red_, green_, blue_ };
> +
> +	for (int x = 0; x < width_in_bytes; ) {
> +		/* Even pixel */
> +		grbg8_bgr888(c, dst, x++, 1, 1);
> +		/* Odd pixel GRBG -> RGGB */
> +		rggb8_bgr888(c, dst, x++, 1, 1);
> +	}
> +}
> +
>  void DebayerCpu::debayer10P_GBGB_BGR888(uint8_t *dst, const uint8_t *src)
>  {
>  	const int width_in_bytes = window_.width * 5 / 4;
> @@ -152,6 +182,22 @@ int DebayerCpu::getInputConfig(PixelFormat inputFormat, DebayerInputConfig &conf
>  	BayerFormat bayerFormat =
>  		BayerFormat::fromPixelFormat(inputFormat);
>  
> +	if (bayerFormat.bitDepth == 8) {
> +	    	config.bpp = 8;
> +		config.patternSize.height = 2;
> +		config.patternSize.width = 4;
> +		config.x_shift = 0;
> +		config.outputFormats = std::vector<PixelFormat>({ formats::RGB888 });
> +
> +		switch (bayerFormat.order) {
> +		case BayerFormat::BGGR:
> +			return 0;
> +		default:
> +			break;
> +		}
> +	/* } else if (future supported fmts) { ... */
> +	}
> +
>  	if (bayerFormat.bitDepth == 10 &&
>  	    bayerFormat.packing == BayerFormat::Packing::CSI2) {
>  	    	config.bpp = 10;
> @@ -195,6 +241,17 @@ int DebayerCpu::setDebayerFunctions(PixelFormat inputFormat, [[maybe_unused]] Pi
>  	BayerFormat bayerFormat =
>  		BayerFormat::fromPixelFormat(inputFormat);
>  
> +	if (bayerFormat.bitDepth == 8) {
> +		switch (bayerFormat.order) {
> +		case BayerFormat::BGGR:
> +			debayer0_ = &DebayerCpu::debayer8_BGBG_BGR888;
> +			debayer1_ = &DebayerCpu::debayer8_GRGR_BGR888;
> +			return 0;
> +		default:
> +			break;
> +		}
> +	}
> +
>  	if (bayerFormat.bitDepth == 10 &&
>  	    bayerFormat.packing == BayerFormat::Packing::CSI2) {
>  		switch (bayerFormat.order) {
> diff --git a/src/libcamera/software_isp/swstats_cpu.cpp b/src/libcamera/software_isp/swstats_cpu.cpp
> index 15f23953..e65b1b65 100644
> --- a/src/libcamera/software_isp/swstats_cpu.cpp
> +++ b/src/libcamera/software_isp/swstats_cpu.cpp
> @@ -37,9 +37,9 @@ static const unsigned int GREEN_Y_MUL = 150;		/* 0.59 * 256 */
>  static const unsigned int BLUE_Y_MUL = 29;		/* 0.11 * 256 */
>  
>  static inline __attribute__((always_inline)) void
> -statsBayer10P(const int width, const uint8_t *src0, const uint8_t *src1, bool bggr, unsigned int &bright_sum_, unsigned int &too_bright_sum_, SwIspStats &stats_)
> +statsBayer10P(const int width, const uint8_t *src0, const uint8_t *src1, bool bggr, unsigned int &bright_sum_, unsigned int &too_bright_sum_, SwIspStats &stats_, bool is10p)
>  {
> -	const int width_in_bytes = width * 5 / 4;
> +	const int width_in_bytes = width * (4 + is10p) / 4;
>  	uint8_t r, g, b, g2;
>  	unsigned int y_val;
>  	unsigned int sumR = 0;
> @@ -49,7 +49,7 @@ statsBayer10P(const int width, const uint8_t *src0, const uint8_t *src1, bool bg
>  	unsigned int bright_sum = 0;
>  	unsigned int too_bright_sum = 0;
>  
> -	for (int x = 0; x < width_in_bytes; x += 5) {
> +	for (int x = 0; x < width_in_bytes; x += (4 + is10p)) {
>  		if (bggr) {
>  			/* BGGR */
>  			b  = src0[x];
> @@ -84,26 +84,31 @@ statsBayer10P(const int width, const uint8_t *src0, const uint8_t *src1, bool bg
>  	too_bright_sum_ += too_bright_sum;
>  }
>  
> +void SwStatsCpu::statsBGGR8Line0(const uint8_t *src, unsigned int stride)
> +{
> +	statsBayer10P(window_.width, src, src + stride, true, bright_sum_, too_bright_sum_, stats_, false);
> +}
> +
>  void SwStatsCpu::statsBGGR10PLine0(const uint8_t *src, unsigned int stride)
>  {
> -	statsBayer10P(window_.width, src, src + stride, true, bright_sum_, too_bright_sum_, stats_);
> +	statsBayer10P(window_.width, src, src + stride, true, bright_sum_, too_bright_sum_, stats_, true);
>  }
>  
>  void SwStatsCpu::statsGBRG10PLine0(const uint8_t *src, unsigned int stride)
>  {
> -	statsBayer10P(window_.width, src, src + stride, false, bright_sum_, too_bright_sum_, stats_);
> +	statsBayer10P(window_.width, src, src + stride, false, bright_sum_, too_bright_sum_, stats_, true);
>  }
>  
>  void SwStatsCpu::statsGRBG10PLine0(const uint8_t *src, unsigned int stride)
>  {
>  	/* GRBG is BGGR with the lines swapped */
> -	statsBayer10P(window_.width, src + stride, src, true, bright_sum_, too_bright_sum_, stats_);
> +	statsBayer10P(window_.width, src + stride, src, true, bright_sum_, too_bright_sum_, stats_, true);
>  }
>  
>  void SwStatsCpu::statsRGGB10PLine0(const uint8_t *src, unsigned int stride)
>  {
>  	/* RGGB is GBRG with the lines swapped */
> -	statsBayer10P(window_.width, src + stride, src, false, bright_sum_, too_bright_sum_, stats_);
> +	statsBayer10P(window_.width, src + stride, src, false, bright_sum_, too_bright_sum_, stats_, true);
>  }
>  
>  void SwStatsCpu::resetStats(void)
> @@ -134,6 +139,24 @@ int SwStatsCpu::configure(const StreamConfiguration &inputCfg)
>  	startFrame_ = (SwStats::statsVoidFn)&SwStatsCpu::resetStats;
>  	finishFrame_ = (SwStats::statsVoidFn)&SwStatsCpu::finishStats;
>  
> +	if (bayerFormat.bitDepth == 8) {
> +		bpp_ = 8;
> +		patternSize_.height = 2;
> +		patternSize_.width = 4;
> +		y_skip_mask_ = 0x0c; /* Skip every 3th and 4th line */
> +		x_shift_ = 0;
> +
> +		switch (bayerFormat.order) {
> +		case BayerFormat::BGGR:
> +			stats0_ = (SwStats::statsProcessFn)&SwStatsCpu::statsBGGR8Line0;
> +			return 0;
> +		default:
> +			break;
> +		}
> +	/* } else if (future supported fmts) { ... */
> +	}
> +
> +
>  	if (bayerFormat.bitDepth == 10 &&
>  	    bayerFormat.packing == BayerFormat::Packing::CSI2) {
>  		bpp_ = 10;
>

Patch
diff mbox series

diff --git a/include/libcamera/internal/software_isp/debayer_cpu.h b/include/libcamera/internal/software_isp/debayer_cpu.h
index 7fb5be77..f3bb4321 100644
--- a/include/libcamera/internal/software_isp/debayer_cpu.h
+++ b/include/libcamera/internal/software_isp/debayer_cpu.h
@@ -67,6 +67,9 @@  private:
 	void debayer10P_GBGB_BGR888(uint8_t *dst, const uint8_t *src);
 	void debayer10P_RGRG_BGR888(uint8_t *dst, const uint8_t *src);
 
+	void debayer8_BGBG_BGR888(uint8_t *dst, const uint8_t *src);
+	void debayer8_GRGR_BGR888(uint8_t *dst, const uint8_t *src);
+
 	typedef void (DebayerCpu::*debayerFn)(uint8_t *dst, const uint8_t *src);
 
 	struct DebayerInputConfig {
diff --git a/include/libcamera/internal/software_isp/swstats_cpu.h b/include/libcamera/internal/software_isp/swstats_cpu.h
index 0ceb995f..3c43e146 100644
--- a/include/libcamera/internal/software_isp/swstats_cpu.h
+++ b/include/libcamera/internal/software_isp/swstats_cpu.h
@@ -29,6 +29,8 @@  public:
 	/* FIXME this should be dropped once AWB has moved to the IPA */
 	SwIspStats getStats() { return *sharedStats_; }
 private:
+	void statsBGGR8Line0(const uint8_t *src, unsigned int stride);
+
 	void statsBGGR10PLine0(const uint8_t *src, unsigned int stride);
 	void statsGBRG10PLine0(const uint8_t *src, unsigned int stride);
 	void statsGRBG10PLine0(const uint8_t *src, unsigned int stride);
diff --git a/src/libcamera/software_isp/debayer_cpu.cpp b/src/libcamera/software_isp/debayer_cpu.cpp
index 3eacdd5d..52910a03 100644
--- a/src/libcamera/software_isp/debayer_cpu.cpp
+++ b/src/libcamera/software_isp/debayer_cpu.cpp
@@ -111,6 +111,36 @@  void DebayerCpu::debayer10P_GRGR_BGR888(uint8_t *dst, const uint8_t *src)
 	}
 }
 
+void DebayerCpu::debayer8_BGBG_BGR888(uint8_t *dst, const uint8_t *src)
+{
+	const int width_in_bytes = window_.width;
+	struct ctxt_8bit_src c = {
+		src - inputConfig_.stride, src, src + inputConfig_.stride,
+		red_, green_, blue_ };
+
+	for (int x = 0; x < width_in_bytes; ) {
+		/* Even pixel */
+		bggr8_bgr888(c, dst, x++, 1, 1);
+		/* Odd pixel BGGR -> GBRG */
+		gbrg8_bgr888(c, dst, x++, 1, 1);
+	}
+}
+
+void DebayerCpu::debayer8_GRGR_BGR888(uint8_t *dst, const uint8_t *src)
+{
+	const int width_in_bytes = window_.width;
+	struct ctxt_8bit_src c = {
+		src - inputConfig_.stride, src, src + inputConfig_.stride,
+		red_, green_, blue_ };
+
+	for (int x = 0; x < width_in_bytes; ) {
+		/* Even pixel */
+		grbg8_bgr888(c, dst, x++, 1, 1);
+		/* Odd pixel GRBG -> RGGB */
+		rggb8_bgr888(c, dst, x++, 1, 1);
+	}
+}
+
 void DebayerCpu::debayer10P_GBGB_BGR888(uint8_t *dst, const uint8_t *src)
 {
 	const int width_in_bytes = window_.width * 5 / 4;
@@ -152,6 +182,22 @@  int DebayerCpu::getInputConfig(PixelFormat inputFormat, DebayerInputConfig &conf
 	BayerFormat bayerFormat =
 		BayerFormat::fromPixelFormat(inputFormat);
 
+	if (bayerFormat.bitDepth == 8) {
+	    	config.bpp = 8;
+		config.patternSize.height = 2;
+		config.patternSize.width = 4;
+		config.x_shift = 0;
+		config.outputFormats = std::vector<PixelFormat>({ formats::RGB888 });
+
+		switch (bayerFormat.order) {
+		case BayerFormat::BGGR:
+			return 0;
+		default:
+			break;
+		}
+	/* } else if (future supported fmts) { ... */
+	}
+
 	if (bayerFormat.bitDepth == 10 &&
 	    bayerFormat.packing == BayerFormat::Packing::CSI2) {
 	    	config.bpp = 10;
@@ -195,6 +241,17 @@  int DebayerCpu::setDebayerFunctions(PixelFormat inputFormat, [[maybe_unused]] Pi
 	BayerFormat bayerFormat =
 		BayerFormat::fromPixelFormat(inputFormat);
 
+	if (bayerFormat.bitDepth == 8) {
+		switch (bayerFormat.order) {
+		case BayerFormat::BGGR:
+			debayer0_ = &DebayerCpu::debayer8_BGBG_BGR888;
+			debayer1_ = &DebayerCpu::debayer8_GRGR_BGR888;
+			return 0;
+		default:
+			break;
+		}
+	}
+
 	if (bayerFormat.bitDepth == 10 &&
 	    bayerFormat.packing == BayerFormat::Packing::CSI2) {
 		switch (bayerFormat.order) {
diff --git a/src/libcamera/software_isp/swstats_cpu.cpp b/src/libcamera/software_isp/swstats_cpu.cpp
index 15f23953..e65b1b65 100644
--- a/src/libcamera/software_isp/swstats_cpu.cpp
+++ b/src/libcamera/software_isp/swstats_cpu.cpp
@@ -37,9 +37,9 @@  static const unsigned int GREEN_Y_MUL = 150;		/* 0.59 * 256 */
 static const unsigned int BLUE_Y_MUL = 29;		/* 0.11 * 256 */
 
 static inline __attribute__((always_inline)) void
-statsBayer10P(const int width, const uint8_t *src0, const uint8_t *src1, bool bggr, unsigned int &bright_sum_, unsigned int &too_bright_sum_, SwIspStats &stats_)
+statsBayer10P(const int width, const uint8_t *src0, const uint8_t *src1, bool bggr, unsigned int &bright_sum_, unsigned int &too_bright_sum_, SwIspStats &stats_, bool is10p)
 {
-	const int width_in_bytes = width * 5 / 4;
+	const int width_in_bytes = width * (4 + is10p) / 4;
 	uint8_t r, g, b, g2;
 	unsigned int y_val;
 	unsigned int sumR = 0;
@@ -49,7 +49,7 @@  statsBayer10P(const int width, const uint8_t *src0, const uint8_t *src1, bool bg
 	unsigned int bright_sum = 0;
 	unsigned int too_bright_sum = 0;
 
-	for (int x = 0; x < width_in_bytes; x += 5) {
+	for (int x = 0; x < width_in_bytes; x += (4 + is10p)) {
 		if (bggr) {
 			/* BGGR */
 			b  = src0[x];
@@ -84,26 +84,31 @@  statsBayer10P(const int width, const uint8_t *src0, const uint8_t *src1, bool bg
 	too_bright_sum_ += too_bright_sum;
 }
 
+void SwStatsCpu::statsBGGR8Line0(const uint8_t *src, unsigned int stride)
+{
+	statsBayer10P(window_.width, src, src + stride, true, bright_sum_, too_bright_sum_, stats_, false);
+}
+
 void SwStatsCpu::statsBGGR10PLine0(const uint8_t *src, unsigned int stride)
 {
-	statsBayer10P(window_.width, src, src + stride, true, bright_sum_, too_bright_sum_, stats_);
+	statsBayer10P(window_.width, src, src + stride, true, bright_sum_, too_bright_sum_, stats_, true);
 }
 
 void SwStatsCpu::statsGBRG10PLine0(const uint8_t *src, unsigned int stride)
 {
-	statsBayer10P(window_.width, src, src + stride, false, bright_sum_, too_bright_sum_, stats_);
+	statsBayer10P(window_.width, src, src + stride, false, bright_sum_, too_bright_sum_, stats_, true);
 }
 
 void SwStatsCpu::statsGRBG10PLine0(const uint8_t *src, unsigned int stride)
 {
 	/* GRBG is BGGR with the lines swapped */
-	statsBayer10P(window_.width, src + stride, src, true, bright_sum_, too_bright_sum_, stats_);
+	statsBayer10P(window_.width, src + stride, src, true, bright_sum_, too_bright_sum_, stats_, true);
 }
 
 void SwStatsCpu::statsRGGB10PLine0(const uint8_t *src, unsigned int stride)
 {
 	/* RGGB is GBRG with the lines swapped */
-	statsBayer10P(window_.width, src + stride, src, false, bright_sum_, too_bright_sum_, stats_);
+	statsBayer10P(window_.width, src + stride, src, false, bright_sum_, too_bright_sum_, stats_, true);
 }
 
 void SwStatsCpu::resetStats(void)
@@ -134,6 +139,24 @@  int SwStatsCpu::configure(const StreamConfiguration &inputCfg)
 	startFrame_ = (SwStats::statsVoidFn)&SwStatsCpu::resetStats;
 	finishFrame_ = (SwStats::statsVoidFn)&SwStatsCpu::finishStats;
 
+	if (bayerFormat.bitDepth == 8) {
+		bpp_ = 8;
+		patternSize_.height = 2;
+		patternSize_.width = 4;
+		y_skip_mask_ = 0x0c; /* Skip every 3th and 4th line */
+		x_shift_ = 0;
+
+		switch (bayerFormat.order) {
+		case BayerFormat::BGGR:
+			stats0_ = (SwStats::statsProcessFn)&SwStatsCpu::statsBGGR8Line0;
+			return 0;
+		default:
+			break;
+		}
+	/* } else if (future supported fmts) { ... */
+	}
+
+
 	if (bayerFormat.bitDepth == 10 &&
 	    bayerFormat.packing == BayerFormat::Packing::CSI2) {
 		bpp_ = 10;