[03/11] softisp: Split AWB from Combined Matrix
diff mbox series

Message ID 20260615-libipa-algorithms-v1-3-e949c937422e@ideasonboard.com
State Superseded
Headers show
Series
  • ipa: libipa: Introduce libipa algorithms
Related show

Commit Message

Jacopo Mondi June 15, 2026, 2:05 p.m. UTC
From: Kieran Bingham <kieran.bingham@ideasonboard.com>

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>
Signed-off-by: Jacopo Mondi <jacopo.mondi@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

Barnabás Pőcze June 15, 2026, 2:29 p.m. UTC | #1
Hi

2026. 06. 15. 16:05 keltezéssel, Jacopo Mondi írta:
> From: Kieran Bingham <kieran.bingham@ideasonboard.com>
> 
> Move the AWB gains out of the combined matrix and pass
> them directly to the EGL shaders.

It would be nice to have some explanation as to why
this is desirable/needed, what issue it solves (if any), etc.


> 
> Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
> Signed-off-by: Jacopo Mondi <jacopo.mondi@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 f5c88ea6f896..05155c83d172 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 34f7403a41d6..8ccfacb46a59 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 23747f78a631..9a1992e219dd 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 1b85196ae161..2def33c82c8e 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 fd8de3942aa3..227f698a1fac 100644
> --- a/src/libcamera/software_isp/debayer_egl.cpp
> +++ b/src/libcamera/software_isp/debayer_egl.cpp
> @@ -115,6 +115,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");
> @@ -128,6 +129,7 @@ int DebayerEGL::getShaderVariableLocations(void)
>   
>   	LOG(Debayer, Debug) << "vertexIn " << attributeVertex_ << " textureIn " << attributeTexture_
>   			    << " tex_y " << textureUniformBayerDataIn_
> +			    << " awb " << awbUniformDataIn_
>   			    << " ccm " << ccmUniformDataIn_
>   			    << " blacklevel " << blackLevelUniformDataIn_
>   			    << " gamma " << gammaUniformDataIn_
> @@ -502,6 +504,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 943410fdd1fc..43038b45a109 100644
> --- a/src/libcamera/software_isp/debayer_egl.h
> +++ b/src/libcamera/software_isp/debayer_egl.h
> @@ -90,6 +90,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_;
>   
>
Kieran Bingham June 16, 2026, 11:30 a.m. UTC | #2
Quoting Barnabás Pőcze (2026-06-15 15:29:44)
> Hi
> 
> 2026. 06. 15. 16:05 keltezéssel, Jacopo Mondi írta:
> > From: Kieran Bingham <kieran.bingham@ideasonboard.com>
> > 
> > Move the AWB gains out of the combined matrix and pass
> > them directly to the EGL shaders.
> 
> It would be nice to have some explanation as to why
> this is desirable/needed, what issue it solves (if any), etc.

Lets try a full commit message here:


The AWB and CCM are currently combined into a single matrix which gets
passed to the GPU and CPU ISP implementations. This unfortunately can
cause saturation bugs between the AWB and CCM in areas of high
brightness in a given scene, where one colour channel will saturate
before the others unevenly.

Remove AWB gains from the combined Matrix to allow a specific AWB Gain
stage to be applied, which is then clamped equally on all channels
according to the valid range of sensitivity from the sensor when the
black level is removed.


> > Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
> > Signed-off-by: Jacopo Mondi <jacopo.mondi@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 f5c88ea6f896..05155c83d172 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 34f7403a41d6..8ccfacb46a59 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 23747f78a631..9a1992e219dd 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 1b85196ae161..2def33c82c8e 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 fd8de3942aa3..227f698a1fac 100644
> > --- a/src/libcamera/software_isp/debayer_egl.cpp
> > +++ b/src/libcamera/software_isp/debayer_egl.cpp
> > @@ -115,6 +115,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");
> > @@ -128,6 +129,7 @@ int DebayerEGL::getShaderVariableLocations(void)
> >   
> >       LOG(Debayer, Debug) << "vertexIn " << attributeVertex_ << " textureIn " << attributeTexture_
> >                           << " tex_y " << textureUniformBayerDataIn_
> > +                         << " awb " << awbUniformDataIn_
> >                           << " ccm " << ccmUniformDataIn_
> >                           << " blacklevel " << blackLevelUniformDataIn_
> >                           << " gamma " << gammaUniformDataIn_
> > @@ -502,6 +504,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 943410fdd1fc..43038b45a109 100644
> > --- a/src/libcamera/software_isp/debayer_egl.h
> > +++ b/src/libcamera/software_isp/debayer_egl.h
> > @@ -90,6 +90,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_;
> >   
> > 
>
Milan Zamazal June 16, 2026, 1:21 p.m. UTC | #3
Kieran Bingham <kieran.bingham@ideasonboard.com> writes:

> Quoting Barnabás Pőcze (2026-06-15 15:29:44)
>> Hi
>> 
>> 2026. 06. 15. 16:05 keltezéssel, Jacopo Mondi írta:
>> > From: Kieran Bingham <kieran.bingham@ideasonboard.com>
>> > 
>> > Move the AWB gains out of the combined matrix and pass
>> > them directly to the EGL shaders.
>> 
>> It would be nice to have some explanation as to why
>> this is desirable/needed, what issue it solves (if any), etc.
>
> Lets try a full commit message here:
>
>
> The AWB and CCM are currently combined into a single matrix which gets
> passed to the GPU and CPU ISP implementations. This unfortunately can
> cause saturation bugs between the AWB and CCM in areas of high
> brightness in a given scene, where one colour channel will saturate
> before the others unevenly.
>
> Remove AWB gains from the combined Matrix to allow a specific AWB Gain
> stage to be applied, which is then clamped equally on all channels
> according to the valid range of sensitivity from the sensor when the
> black level is removed.

With this added:

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

>> > Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
>> > Signed-off-by: Jacopo Mondi <jacopo.mondi@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 f5c88ea6f896..05155c83d172 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 34f7403a41d6..8ccfacb46a59 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 23747f78a631..9a1992e219dd 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 1b85196ae161..2def33c82c8e 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 fd8de3942aa3..227f698a1fac 100644
>> > --- a/src/libcamera/software_isp/debayer_egl.cpp
>> > +++ b/src/libcamera/software_isp/debayer_egl.cpp
>> > @@ -115,6 +115,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");
>> > @@ -128,6 +129,7 @@ int DebayerEGL::getShaderVariableLocations(void)
>> >   
>> >       LOG(Debayer, Debug) << "vertexIn " << attributeVertex_ << " textureIn " << attributeTexture_
>> >                           << " tex_y " << textureUniformBayerDataIn_
>> > +                         << " awb " << awbUniformDataIn_
>> >                           << " ccm " << ccmUniformDataIn_
>> >                           << " blacklevel " << blackLevelUniformDataIn_
>> >                           << " gamma " << gammaUniformDataIn_
>> > @@ -502,6 +504,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 943410fdd1fc..43038b45a109 100644
>> > --- a/src/libcamera/software_isp/debayer_egl.h
>> > +++ b/src/libcamera/software_isp/debayer_egl.h
>> > @@ -90,6 +90,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_;
>> >   
>> > 
>>

Patch
diff mbox series

diff --git a/src/ipa/simple/algorithms/awb.cpp b/src/ipa/simple/algorithms/awb.cpp
index f5c88ea6f896..05155c83d172 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 34f7403a41d6..8ccfacb46a59 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 23747f78a631..9a1992e219dd 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 1b85196ae161..2def33c82c8e 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 fd8de3942aa3..227f698a1fac 100644
--- a/src/libcamera/software_isp/debayer_egl.cpp
+++ b/src/libcamera/software_isp/debayer_egl.cpp
@@ -115,6 +115,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");
@@ -128,6 +129,7 @@  int DebayerEGL::getShaderVariableLocations(void)
 
 	LOG(Debayer, Debug) << "vertexIn " << attributeVertex_ << " textureIn " << attributeTexture_
 			    << " tex_y " << textureUniformBayerDataIn_
+			    << " awb " << awbUniformDataIn_
 			    << " ccm " << ccmUniformDataIn_
 			    << " blacklevel " << blackLevelUniformDataIn_
 			    << " gamma " << gammaUniformDataIn_
@@ -502,6 +504,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 943410fdd1fc..43038b45a109 100644
--- a/src/libcamera/software_isp/debayer_egl.h
+++ b/src/libcamera/software_isp/debayer_egl.h
@@ -90,6 +90,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_;