[4/5] ipa: libipa: awb: Update manual gains with automatic
diff mbox series

Message ID 20260928-awb-state-v1-4-9b1bb8b9e51b@ideasonboard.com
State New
Headers show
Series
  • Add AwbState metadata and AwbTrigger control
Related show

Commit Message

Dan Scally Sept. 28, 2026, 11:14 a.m. UTC
The present behaviour of the AWB algorithm is to decouple manual and
automatic gains completely. If AwbEnable is set to false, this leads
to a jarring transition to the (possibly default 1.0) manual gains.
Instead update the manual gains with the automatic ones if we're in
automatic mode so that when AwbEnable is set to false the gains are
seen to "freeze" at their current values rather than revert to the
last configured manual value.

As this is the exact behaviour of the AwbStateLocked value of the
AwbState metadata item, set that when AwbEnable == false is passed.

Signed-off-by: Daniel Scally <dan.scally@ideasonboard.com>
---
 src/ipa/libipa/awb.cpp | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)

Comments

Barnabás Pőcze Oct. 6, 2026, 9:53 a.m. UTC | #1
Hi

2026. 09. 28. 13:14 keltezéssel, Daniel Scally írta:
> The present behaviour of the AWB algorithm is to decouple manual and
> automatic gains completely. If AwbEnable is set to false, this leads
> to a jarring transition to the (possibly default 1.0) manual gains.
> Instead update the manual gains with the automatic ones if we're in
> automatic mode so that when AwbEnable is set to false the gains are
> seen to "freeze" at their current values rather than revert to the
> last configured manual value.

I think this should be documented like it is for the agc controls:

   When transitioning from Auto to Manual mode and no ExposureTime control
   is provided by the application, the last value computed by the AE
   algorithm when the mode was Auto will be used. If the ExposureTimeMode
   was never set to Auto (either because the camera started in Manual mode,
   or Auto is not supported by the camera), the camera should use a
   best-effort default value.



> 
> As this is the exact behaviour of the AwbStateLocked value of the
> AwbState metadata item, set that when AwbEnable == false is passed.
> 
> Signed-off-by: Daniel Scally <dan.scally@ideasonboard.com>
> ---
>   src/ipa/libipa/awb.cpp | 15 ++++++++++++---
>   1 file changed, 12 insertions(+), 3 deletions(-)
> 
> diff --git a/src/ipa/libipa/awb.cpp b/src/ipa/libipa/awb.cpp
> index d1a75020843a03b3530dce4b6bd82f228ec6bed9..0c6a01bd780ce00d21c1f7fdd8ba2ed468c4f4a1 100644
> --- a/src/ipa/libipa/awb.cpp
> +++ b/src/ipa/libipa/awb.cpp
> @@ -246,12 +246,14 @@ int AwbAlgorithmBase::init(const ValueNode &tuningData)
>    */
>   int AwbAlgorithmBase::configure(awb::ActiveState &state)
>   {
> -	state.manual.gains = RGB<double>{ 1.0 };
>   	auto gains = impl_->gainsFromColourTemperature(kDefaultColourTemperature);
> -	if (gains)
> +	if (gains) {
> +		state.manual.gains = *gains;
>   		state.automatic.gains = *gains;
> -	else
> +	} else {
> +		state.manual.gains = RGB<double>{ 1.0 };
>   		state.automatic.gains = RGB<double>{ 1.0 };
> +	}
>   
>   	state.autoEnabled = true;
>   	state.manual.colourTemperature = kDefaultColourTemperature;
> @@ -286,6 +288,10 @@ void AwbAlgorithmBase::queueRequest(awb::ActiveState &state,
>   	const auto &awbEnable = controls.get(controls::AwbEnable);
>   	if (awbEnable && *awbEnable != state.autoEnabled) {
>   		state.autoEnabled = *awbEnable;
> +		if (state.autoEnabled)
> +			convergedState_ = controls::AwbStateEnum::AwbStateSearching;
> +		else
> +			convergedState_ = controls::AwbStateEnum::AwbStateLocked;
>   
>   		LOG(Awb, Debug)
>   			<< (*awbEnable ? "Enabling" : "Disabling") << " Awb";
> @@ -445,6 +451,9 @@ void AwbAlgorithmBase::process(awb::ActiveState &state,
>   	state.automatic.colourTemperature = awbResult.colourTemperature;
>   	state.automatic.gains = newGains;
>   
> +	if (state.autoEnabled)
> +		state.manual.gains = newGains;

I'm trying to understand why the agc algorithm does this quite differently.
The only thing I can think of is that the first frame with `AwbEnable == false`
will potentially use a bit older automatic gains because the `process()` calls
that happen between the `queueRequest()` and `prepare()` of the first "manual"
frame won't have an effect.


> +
>   	/* Populate metadata. */
>   	metadata.set(controls::AwbEnable, frameContext.autoEnabled);
>   	metadata.set(controls::ColourGains, { static_cast<float>(frameContext.gains.r()),
>

Patch
diff mbox series

diff --git a/src/ipa/libipa/awb.cpp b/src/ipa/libipa/awb.cpp
index d1a75020843a03b3530dce4b6bd82f228ec6bed9..0c6a01bd780ce00d21c1f7fdd8ba2ed468c4f4a1 100644
--- a/src/ipa/libipa/awb.cpp
+++ b/src/ipa/libipa/awb.cpp
@@ -246,12 +246,14 @@  int AwbAlgorithmBase::init(const ValueNode &tuningData)
  */
 int AwbAlgorithmBase::configure(awb::ActiveState &state)
 {
-	state.manual.gains = RGB<double>{ 1.0 };
 	auto gains = impl_->gainsFromColourTemperature(kDefaultColourTemperature);
-	if (gains)
+	if (gains) {
+		state.manual.gains = *gains;
 		state.automatic.gains = *gains;
-	else
+	} else {
+		state.manual.gains = RGB<double>{ 1.0 };
 		state.automatic.gains = RGB<double>{ 1.0 };
+	}
 
 	state.autoEnabled = true;
 	state.manual.colourTemperature = kDefaultColourTemperature;
@@ -286,6 +288,10 @@  void AwbAlgorithmBase::queueRequest(awb::ActiveState &state,
 	const auto &awbEnable = controls.get(controls::AwbEnable);
 	if (awbEnable && *awbEnable != state.autoEnabled) {
 		state.autoEnabled = *awbEnable;
+		if (state.autoEnabled)
+			convergedState_ = controls::AwbStateEnum::AwbStateSearching;
+		else
+			convergedState_ = controls::AwbStateEnum::AwbStateLocked;
 
 		LOG(Awb, Debug)
 			<< (*awbEnable ? "Enabling" : "Disabling") << " Awb";
@@ -445,6 +451,9 @@  void AwbAlgorithmBase::process(awb::ActiveState &state,
 	state.automatic.colourTemperature = awbResult.colourTemperature;
 	state.automatic.gains = newGains;
 
+	if (state.autoEnabled)
+		state.manual.gains = newGains;
+
 	/* Populate metadata. */
 	metadata.set(controls::AwbEnable, frameContext.autoEnabled);
 	metadata.set(controls::ColourGains, { static_cast<float>(frameContext.gains.r()),