[02/13] softisp: Split AWB from Combined Matrix
diff mbox series

Message ID 20260407-kbingham-awb-split-v1-2-a39af3f4dc20@ideasonboard.com
State New
Headers show
Series
  • ipa: simple: Convert to libipa AWB implementation
Related show

Commit Message

Kieran Bingham April 7, 2026, 10:01 p.m. UTC
Move the AWB gains out of the combined matrix and pass
them directly to the EGL shaders.

Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
---
 src/ipa/simple/algorithms/awb.cpp          | 16 +++-------------
 src/ipa/simple/ipa_context.h               |  5 +----
 src/libcamera/shaders/bayer_1x_packed.frag |  4 ++++
 src/libcamera/shaders/bayer_unpacked.frag  |  4 ++++
 src/libcamera/software_isp/debayer_egl.cpp |  5 +++++
 src/libcamera/software_isp/debayer_egl.h   |  3 +++
 6 files changed, 20 insertions(+), 17 deletions(-)

Comments

Laurent Pinchart April 8, 2026, 12:01 a.m. UTC | #1
On Tue, Apr 07, 2026 at 11:01:05PM +0100, Kieran Bingham wrote:
> Move the AWB gains out of the combined matrix and pass
> them directly to the EGL shaders.
> 
> Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
> ---
>  src/ipa/simple/algorithms/awb.cpp          | 16 +++-------------
>  src/ipa/simple/ipa_context.h               |  5 +----
>  src/libcamera/shaders/bayer_1x_packed.frag |  4 ++++
>  src/libcamera/shaders/bayer_unpacked.frag  |  4 ++++
>  src/libcamera/software_isp/debayer_egl.cpp |  5 +++++
>  src/libcamera/software_isp/debayer_egl.h   |  3 +++
>  6 files changed, 20 insertions(+), 17 deletions(-)
> 
> diff --git a/src/ipa/simple/algorithms/awb.cpp b/src/ipa/simple/algorithms/awb.cpp
> index f5c88ea6f896ff8a7ffdc328e09a4d4aa99df5e4..05155c83d172d64609053ba940a4c12a2248bb04 100644
> --- a/src/ipa/simple/algorithms/awb.cpp
> +++ b/src/ipa/simple/algorithms/awb.cpp
> @@ -38,15 +38,8 @@ void Awb::prepare(IPAContext &context,
>  		  DebayerParams *params)
>  {
>  	auto &gains = context.activeState.awb.gains;
> -	Matrix<float, 3, 3> gainMatrix = { { gains.r(), 0, 0,
> -					     0, gains.g(), 0,
> -					     0, 0, gains.b() } };
> -	context.activeState.combinedMatrix =
> -		gainMatrix * context.activeState.combinedMatrix;

The combined matrix is used by the CPU implementation too, aren't you
breaking AWB there ?

> -
> -	frameContext.gains.red = gains.r();
> -	frameContext.gains.blue = gains.b();
>  
> +	frameContext.gains = gains;
>  	params->gains = gains;
>  }
>  
> @@ -59,11 +52,8 @@ void Awb::process(IPAContext &context,
>  	const SwIspStats::Histogram &histogram = stats->yHistogram;
>  	const uint8_t blackLevel = context.activeState.blc.level;
>  
> -	const float mdGains[] = {
> -		static_cast<float>(frameContext.gains.red),
> -		static_cast<float>(frameContext.gains.blue)
> -	};
> -	metadata.set(controls::ColourGains, mdGains);
> +	metadata.set(controls::ColourGains, { frameContext.gains.r(),
> +					      frameContext.gains.b() });
>  
>  	if (!stats->valid)
>  		return;
> diff --git a/src/ipa/simple/ipa_context.h b/src/ipa/simple/ipa_context.h
> index 34f7403a41d690cb3f0c271827ae2e915b6ea49d..8ccfacb46a59cedb5a0ad051d67f7c1f40af4b52 100644
> --- a/src/ipa/simple/ipa_context.h
> +++ b/src/ipa/simple/ipa_context.h
> @@ -71,10 +71,7 @@ struct IPAFrameContext : public FrameContext {
>  		double gain;
>  	} sensor;
>  
> -	struct {
> -		double red;
> -		double blue;
> -	} gains;
> +	RGB<float> gains;
>  
>  	float gamma;
>  	std::optional<float> contrast;
> diff --git a/src/libcamera/shaders/bayer_1x_packed.frag b/src/libcamera/shaders/bayer_1x_packed.frag
> index 23747f78a6313503a46b61ed5bae6e7c178c5745..9a1992e219dd066945b3f46ec509f47a31590385 100644
> --- a/src/libcamera/shaders/bayer_1x_packed.frag
> +++ b/src/libcamera/shaders/bayer_1x_packed.frag
> @@ -65,6 +65,7 @@ uniform vec2 tex_step;
>  uniform vec2 tex_bayer_first_red;
>  
>  uniform sampler2D tex_y;
> +uniform vec3 awb;

I'd name this wbGains or colourGains, that's more explicit. Same below.

>  uniform mat3 ccm;
>  uniform vec3 blacklevel;
>  uniform float gamma;
> @@ -227,6 +228,9 @@ void main(void)
>  
>  	rgb = rgb - blacklevel;
>  
> +	/* Apply AWB gains, and saturate each channel at sensor range */
> +	rgb = clamp(rgb * awb, vec3(0.0), vec3(1.0) - blacklevel);
> +
>  	/*
>  	 *   CCM is a 3x3 in the format
>  	 *
> diff --git a/src/libcamera/shaders/bayer_unpacked.frag b/src/libcamera/shaders/bayer_unpacked.frag
> index 76ffc47a8a29f242c1fba88f32bd8db731edeee0..87e4e4915fe19679943fdcc3d213a0224b89065e 100644
> --- a/src/libcamera/shaders/bayer_unpacked.frag
> +++ b/src/libcamera/shaders/bayer_unpacked.frag
> @@ -24,6 +24,7 @@ uniform sampler2D       tex_y;
>  varying vec4            center;
>  varying vec4            yCoord;
>  varying vec4            xCoord;
> +uniform vec3            awb;
>  uniform mat3            ccm;
>  uniform vec3            blacklevel;
>  uniform float           gamma;
> @@ -130,6 +131,9 @@ void main(void) {
>  
>  	rgb = rgb - blacklevel;
>  
> +	/* Apply AWB gains, and saturate each channel at sensor range */
> +	rgb = clamp(rgb * awb, vec3(0.0), vec3(1.0) - blacklevel);
> +
>  	/*
>  	 *   CCM is a 3x3 in the format
>  	 *
> diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp
> index 2ad258bca69fb8dff19e35d9239ebd7d350590ae..738036e649224f370bdf9a0cc59b399f8b1066de 100644
> --- a/src/libcamera/software_isp/debayer_egl.cpp
> +++ b/src/libcamera/software_isp/debayer_egl.cpp
> @@ -100,6 +100,7 @@ int DebayerEGL::getShaderVariableLocations(void)
>  	attributeTexture_ = glGetAttribLocation(programId_, "textureIn");
>  
>  	textureUniformBayerDataIn_ = glGetUniformLocation(programId_, "tex_y");
> +	awbUniformDataIn_ = glGetUniformLocation(programId_, "awb");
>  	ccmUniformDataIn_ = glGetUniformLocation(programId_, "ccm");
>  	blackLevelUniformDataIn_ = glGetUniformLocation(programId_, "blacklevel");
>  	gammaUniformDataIn_ = glGetUniformLocation(programId_, "gamma");
> @@ -113,6 +114,7 @@ int DebayerEGL::getShaderVariableLocations(void)
>  
>  	LOG(Debayer, Debug) << "vertexIn " << attributeVertex_ << " textureIn " << attributeTexture_
>  			    << " tex_y " << textureUniformBayerDataIn_
> +			    << " awb " << awbUniformDataIn_
>  			    << " ccm " << ccmUniformDataIn_
>  			    << " blacklevel " << blackLevelUniformDataIn_
>  			    << " gamma " << gammaUniformDataIn_
> @@ -481,6 +483,9 @@ void DebayerEGL::setShaderVariableValues(const DebayerParams &params)
>  	glUniform3f(blackLevelUniformDataIn_, params.blackLevel[0], params.blackLevel[1], params.blackLevel[2]);
>  	LOG(Debayer, Debug) << " blackLevelUniformDataIn_ " << blackLevelUniformDataIn_ << " data " << params.blackLevel;
>  
> +	glUniform3f(awbUniformDataIn_, params.gains[0], params.gains[1], params.gains[2]);
> +	LOG(Debayer, Debug) << " awbUniformDataIn_ " << awbUniformDataIn_ << " data " << params.gains;
> +
>  	/*
>  	 * Gamma
>  	 */
> diff --git a/src/libcamera/software_isp/debayer_egl.h b/src/libcamera/software_isp/debayer_egl.h
> index bdde676f2394e7298006c88bbec75917800af4ad..23ef99117fbd209246ae565141a2365c6a7b0a63 100644
> --- a/src/libcamera/software_isp/debayer_egl.h
> +++ b/src/libcamera/software_isp/debayer_egl.h
> @@ -97,6 +97,9 @@ private:
>  
>  	GLint textureUniformBayerDataIn_;
>  
> +	/* Per-frame AWB gains */

All the uniforms below are per-frame parameters, I'd drop the
"per-frame".

Sorting the members in processing block order (in a separate patch)
would make it easier to follow the code.

> +	GLint awbUniformDataIn_;
> +
>  	/* Represent per-frame CCM as a uniform vector of floats 3 x 3 */
>  	GLint ccmUniformDataIn_;
>  
>

Patch
diff mbox series

diff --git a/src/ipa/simple/algorithms/awb.cpp b/src/ipa/simple/algorithms/awb.cpp
index f5c88ea6f896ff8a7ffdc328e09a4d4aa99df5e4..05155c83d172d64609053ba940a4c12a2248bb04 100644
--- a/src/ipa/simple/algorithms/awb.cpp
+++ b/src/ipa/simple/algorithms/awb.cpp
@@ -38,15 +38,8 @@  void Awb::prepare(IPAContext &context,
 		  DebayerParams *params)
 {
 	auto &gains = context.activeState.awb.gains;
-	Matrix<float, 3, 3> gainMatrix = { { gains.r(), 0, 0,
-					     0, gains.g(), 0,
-					     0, 0, gains.b() } };
-	context.activeState.combinedMatrix =
-		gainMatrix * context.activeState.combinedMatrix;
-
-	frameContext.gains.red = gains.r();
-	frameContext.gains.blue = gains.b();
 
+	frameContext.gains = gains;
 	params->gains = gains;
 }
 
@@ -59,11 +52,8 @@  void Awb::process(IPAContext &context,
 	const SwIspStats::Histogram &histogram = stats->yHistogram;
 	const uint8_t blackLevel = context.activeState.blc.level;
 
-	const float mdGains[] = {
-		static_cast<float>(frameContext.gains.red),
-		static_cast<float>(frameContext.gains.blue)
-	};
-	metadata.set(controls::ColourGains, mdGains);
+	metadata.set(controls::ColourGains, { frameContext.gains.r(),
+					      frameContext.gains.b() });
 
 	if (!stats->valid)
 		return;
diff --git a/src/ipa/simple/ipa_context.h b/src/ipa/simple/ipa_context.h
index 34f7403a41d690cb3f0c271827ae2e915b6ea49d..8ccfacb46a59cedb5a0ad051d67f7c1f40af4b52 100644
--- a/src/ipa/simple/ipa_context.h
+++ b/src/ipa/simple/ipa_context.h
@@ -71,10 +71,7 @@  struct IPAFrameContext : public FrameContext {
 		double gain;
 	} sensor;
 
-	struct {
-		double red;
-		double blue;
-	} gains;
+	RGB<float> gains;
 
 	float gamma;
 	std::optional<float> contrast;
diff --git a/src/libcamera/shaders/bayer_1x_packed.frag b/src/libcamera/shaders/bayer_1x_packed.frag
index 23747f78a6313503a46b61ed5bae6e7c178c5745..9a1992e219dd066945b3f46ec509f47a31590385 100644
--- a/src/libcamera/shaders/bayer_1x_packed.frag
+++ b/src/libcamera/shaders/bayer_1x_packed.frag
@@ -65,6 +65,7 @@  uniform vec2 tex_step;
 uniform vec2 tex_bayer_first_red;
 
 uniform sampler2D tex_y;
+uniform vec3 awb;
 uniform mat3 ccm;
 uniform vec3 blacklevel;
 uniform float gamma;
@@ -227,6 +228,9 @@  void main(void)
 
 	rgb = rgb - blacklevel;
 
+	/* Apply AWB gains, and saturate each channel at sensor range */
+	rgb = clamp(rgb * awb, vec3(0.0), vec3(1.0) - blacklevel);
+
 	/*
 	 *   CCM is a 3x3 in the format
 	 *
diff --git a/src/libcamera/shaders/bayer_unpacked.frag b/src/libcamera/shaders/bayer_unpacked.frag
index 76ffc47a8a29f242c1fba88f32bd8db731edeee0..87e4e4915fe19679943fdcc3d213a0224b89065e 100644
--- a/src/libcamera/shaders/bayer_unpacked.frag
+++ b/src/libcamera/shaders/bayer_unpacked.frag
@@ -24,6 +24,7 @@  uniform sampler2D       tex_y;
 varying vec4            center;
 varying vec4            yCoord;
 varying vec4            xCoord;
+uniform vec3            awb;
 uniform mat3            ccm;
 uniform vec3            blacklevel;
 uniform float           gamma;
@@ -130,6 +131,9 @@  void main(void) {
 
 	rgb = rgb - blacklevel;
 
+	/* Apply AWB gains, and saturate each channel at sensor range */
+	rgb = clamp(rgb * awb, vec3(0.0), vec3(1.0) - blacklevel);
+
 	/*
 	 *   CCM is a 3x3 in the format
 	 *
diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp
index 2ad258bca69fb8dff19e35d9239ebd7d350590ae..738036e649224f370bdf9a0cc59b399f8b1066de 100644
--- a/src/libcamera/software_isp/debayer_egl.cpp
+++ b/src/libcamera/software_isp/debayer_egl.cpp
@@ -100,6 +100,7 @@  int DebayerEGL::getShaderVariableLocations(void)
 	attributeTexture_ = glGetAttribLocation(programId_, "textureIn");
 
 	textureUniformBayerDataIn_ = glGetUniformLocation(programId_, "tex_y");
+	awbUniformDataIn_ = glGetUniformLocation(programId_, "awb");
 	ccmUniformDataIn_ = glGetUniformLocation(programId_, "ccm");
 	blackLevelUniformDataIn_ = glGetUniformLocation(programId_, "blacklevel");
 	gammaUniformDataIn_ = glGetUniformLocation(programId_, "gamma");
@@ -113,6 +114,7 @@  int DebayerEGL::getShaderVariableLocations(void)
 
 	LOG(Debayer, Debug) << "vertexIn " << attributeVertex_ << " textureIn " << attributeTexture_
 			    << " tex_y " << textureUniformBayerDataIn_
+			    << " awb " << awbUniformDataIn_
 			    << " ccm " << ccmUniformDataIn_
 			    << " blacklevel " << blackLevelUniformDataIn_
 			    << " gamma " << gammaUniformDataIn_
@@ -481,6 +483,9 @@  void DebayerEGL::setShaderVariableValues(const DebayerParams &params)
 	glUniform3f(blackLevelUniformDataIn_, params.blackLevel[0], params.blackLevel[1], params.blackLevel[2]);
 	LOG(Debayer, Debug) << " blackLevelUniformDataIn_ " << blackLevelUniformDataIn_ << " data " << params.blackLevel;
 
+	glUniform3f(awbUniformDataIn_, params.gains[0], params.gains[1], params.gains[2]);
+	LOG(Debayer, Debug) << " awbUniformDataIn_ " << awbUniformDataIn_ << " data " << params.gains;
+
 	/*
 	 * Gamma
 	 */
diff --git a/src/libcamera/software_isp/debayer_egl.h b/src/libcamera/software_isp/debayer_egl.h
index bdde676f2394e7298006c88bbec75917800af4ad..23ef99117fbd209246ae565141a2365c6a7b0a63 100644
--- a/src/libcamera/software_isp/debayer_egl.h
+++ b/src/libcamera/software_isp/debayer_egl.h
@@ -97,6 +97,9 @@  private:
 
 	GLint textureUniformBayerDataIn_;
 
+	/* Per-frame AWB gains */
+	GLint awbUniformDataIn_;
+
 	/* Represent per-frame CCM as a uniform vector of floats 3 x 3 */
 	GLint ccmUniformDataIn_;