[v1] libcamera: libipa: camera_sensor_helper: Use `variant` instead of `union`
diff mbox series

Message ID 20241205122702.1105835-1-pobrn@protonmail.com
State Superseded
Headers show
Series
  • [v1] libcamera: libipa: camera_sensor_helper: Use `variant` instead of `union`
Related show

Commit Message

Barnabás Pőcze Dec. 5, 2024, 12:27 p.m. UTC
Use an `std::variant` to store the analogue gain instead of a bare union + tag.

Signed-off-by: Barnabás Pőcze <pobrn@protonmail.com>
---
 src/ipa/libipa/camera_sensor_helper.cpp | 198 ++++++++----------------
 src/ipa/libipa/camera_sensor_helper.h   |  18 +--
 2 files changed, 70 insertions(+), 146 deletions(-)

Comments

Laurent Pinchart Dec. 5, 2024, 7:58 p.m. UTC | #1
Hi Barnabás,

Thank you for the patch.

On Thu, Dec 05, 2024 at 12:27:05PM +0000, Barnabás Pőcze wrote:
> Use an `std::variant` to store the analogue gain instead of a bare union + tag.

Sounds like the right tool for the job.

> Signed-off-by: Barnabás Pőcze <pobrn@protonmail.com>

Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

> ---
>  src/ipa/libipa/camera_sensor_helper.cpp | 198 ++++++++----------------
>  src/ipa/libipa/camera_sensor_helper.h   |  18 +--
>  2 files changed, 70 insertions(+), 146 deletions(-)
> 
> diff --git a/src/ipa/libipa/camera_sensor_helper.cpp b/src/ipa/libipa/camera_sensor_helper.cpp
> index a76e5e75..ac3d712b 100644
> --- a/src/ipa/libipa/camera_sensor_helper.cpp
> +++ b/src/ipa/libipa/camera_sensor_helper.cpp
> @@ -87,21 +87,18 @@ namespace ipa {
>   */
>  uint32_t CameraSensorHelper::gainCode(double gain) const
>  {
> -	const AnalogueGainConstants &k = gainConstants_;
> +	if (auto *l = std::get_if<AnalogueGainLinear>(&gain_)) {
> +		ASSERT(l->m0 == 0 || l->m1 == 0);
>  
> -	switch (gainType_) {
> -	case AnalogueGainLinear:
> -		ASSERT(k.linear.m0 == 0 || k.linear.m1 == 0);
> -
> -		return (k.linear.c0 - k.linear.c1 * gain) /
> -		       (k.linear.m1 * gain - k.linear.m0);
> -
> -	case AnalogueGainExponential:
> -		ASSERT(k.exp.a != 0 && k.exp.m != 0);
> -
> -		return std::log2(gain / k.exp.a) / k.exp.m;
> +		return (l->c0 - l->c1 * gain) /
> +		       (l->m1 * gain - l->m0);
> +	}
> +	else if (auto *e = std::get_if<AnalogueGainExp>(&gain_)) {
> +		ASSERT(e->a != 0 && e->m != 0);
>  
> -	default:
> +		return std::log2(gain / e->a) / e->m;
> +	}
> +	else {
>  		ASSERT(false);
>  		return 0;
>  	}
> @@ -119,38 +116,28 @@ uint32_t CameraSensorHelper::gainCode(double gain) const
>   */
>  double CameraSensorHelper::gain(uint32_t gainCode) const
>  {
> -	const AnalogueGainConstants &k = gainConstants_;
>  	double gain = static_cast<double>(gainCode);
>  
> -	switch (gainType_) {
> -	case AnalogueGainLinear:
> -		ASSERT(k.linear.m0 == 0 || k.linear.m1 == 0);
> -
> -		return (k.linear.m0 * gain + k.linear.c0) /
> -		       (k.linear.m1 * gain + k.linear.c1);
> +	if (auto *l = std::get_if<AnalogueGainLinear>(&gain_)) {
> +		ASSERT(l->m0 == 0 || l->m1 == 0);
>  
> -	case AnalogueGainExponential:
> -		ASSERT(k.exp.a != 0 && k.exp.m != 0);
> -
> -		return k.exp.a * std::exp2(k.exp.m * gain);
> +		return (l->m0 * gain + l->c0) /
> +		       (l->m1 * gain + l->c1);
> +	}
> +	else if (auto *e = std::get_if<AnalogueGainExp>(&gain_)) {
> +		ASSERT(e->a != 0 && e->m != 0);
>  
> -	default:
> +		return e->a * std::exp2(e->m * gain);
> +	}
> +	else {
>  		ASSERT(false);
>  		return 0.0;
>  	}
>  }
>  
>  /**
> - * \enum CameraSensorHelper::AnalogueGainType
> - * \brief The gain calculation modes as defined by the MIPI CCS
> - *
> - * Describes the image sensor analogue gain capabilities.
> - * Two modes are possible, depending on the sensor: Linear and Exponential.
> - */
> -
> -/**
> - * \var CameraSensorHelper::AnalogueGainLinear
> - * \brief Gain is computed using linear gain estimation
> + * \struct CameraSensorHelper::AnalogueGainLinear
> + * \brief Analogue gain constants for the linear gain model
>   *
>   * The relationship between the integer gain parameter and the resulting gain
>   * multiplier is given by the following equation:
> @@ -165,11 +152,27 @@ double CameraSensorHelper::gain(uint32_t gainCode) const
>   * The full Gain equation therefore reduces to either:
>   *
>   * \f$gain=\frac{c0}{m1x+c1}\f$ or \f$\frac{m0x+c0}{c1}\f$
> + *
> + * \var CameraSensorHelper::AnalogueGainLinear::m0
> + * \brief Constant used in the linear gain coding/decoding
> + *
> + * \note Either m0 or m1 shall be zero.
> + *
> + * \var CameraSensorHelper::AnalogueGainLinear::c0
> + * \brief Constant used in the linear gain coding/decoding
> + *
> + * \var CameraSensorHelper::AnalogueGainLinear::m1
> + * \brief Constant used in the linear gain coding/decoding
> + *
> + * \note Either m0 or m1 shall be zero.
> + *
> + * \var CameraSensorHelper::AnalogueGainLinear::c1
> + * \brief Constant used in the linear gain coding/decoding
>   */
>  
>  /**
> - * \var CameraSensorHelper::AnalogueGainExponential
> - * \brief Gain is expressed using an exponential model
> + * \struct CameraSensorHelper::AnalogueGainExp
> + * \brief Analogue gain constants for the exponential gain model
>   *
>   * The relationship between the integer gain parameter and the resulting gain
>   * multiplier is given by the following equation:
> @@ -185,54 +188,14 @@ double CameraSensorHelper::gain(uint32_t gainCode) const
>   *
>   * When the gain is expressed in dB, 'a' is equal to 1 and 'm' to
>   * \f$log_{2}{10^{\frac{1}{20}}}\f$.
> - */
> -
> -/**
> - * \struct CameraSensorHelper::AnalogueGainLinearConstants
> - * \brief Analogue gain constants for the linear gain model
> - *
> - * \var CameraSensorHelper::AnalogueGainLinearConstants::m0
> - * \brief Constant used in the linear gain coding/decoding
> - *
> - * \note Either m0 or m1 shall be zero.
> - *
> - * \var CameraSensorHelper::AnalogueGainLinearConstants::c0
> - * \brief Constant used in the linear gain coding/decoding
> - *
> - * \var CameraSensorHelper::AnalogueGainLinearConstants::m1
> - * \brief Constant used in the linear gain coding/decoding
> - *
> - * \note Either m0 or m1 shall be zero.
> - *
> - * \var CameraSensorHelper::AnalogueGainLinearConstants::c1
> - * \brief Constant used in the linear gain coding/decoding
> - */
> -
> -/**
> - * \struct CameraSensorHelper::AnalogueGainExpConstants
> - * \brief Analogue gain constants for the exponential gain model
>   *
> - * \var CameraSensorHelper::AnalogueGainExpConstants::a
> + * \var CameraSensorHelper::AnalogueGainExp::a
>   * \brief Constant used in the exponential gain coding/decoding
>   *
> - * \var CameraSensorHelper::AnalogueGainExpConstants::m
> + * \var CameraSensorHelper::AnalogueGainExp::m
>   * \brief Constant used in the exponential gain coding/decoding
>   */
>  
> -/**
> - * \struct CameraSensorHelper::AnalogueGainConstants
> - * \brief Analogue gain model constants
> - *
> - * This union stores the constants used to calculate the analogue gain. The
> - * CameraSensorHelper::gainType_ variable selects which union member is valid.
> - *
> - * \var CameraSensorHelper::AnalogueGainConstants::linear
> - * \brief Constants for the linear gain model
> - *
> - * \var CameraSensorHelper::AnalogueGainConstants::exp
> - * \brief Constants for the exponential gain model
> - */
> -
>  /**
>   * \var CameraSensorHelper::blackLevel_
>   * \brief The black level of the sensor
> @@ -240,12 +203,7 @@ double CameraSensorHelper::gain(uint32_t gainCode) const
>   */
>  
>  /**
> - * \var CameraSensorHelper::gainType_
> - * \brief The analogue gain model type
> - */
> -
> -/**
> - * \var CameraSensorHelper::gainConstants_
> + * \var CameraSensorHelper::gain_
>   * \brief The analogue gain parameters used for calculation
>   *
>   * The analogue gain is calculated through a formula, and its parameters are
> @@ -526,8 +484,7 @@ public:
>  	{
>  		/* From datasheet: 64 at 10bits. */
>  		blackLevel_ = 4096;
> -		gainType_ = AnalogueGainLinear;
> -		gainConstants_.linear = { 100, 0, 0, 1024 };
> +		gain_ = AnalogueGainLinear{ 100, 0, 0, 1024 };
>  	}
>  };
>  REGISTER_CAMERA_SENSOR_HELPER("gc05a2", CameraSensorHelperGc05a2)
> @@ -539,8 +496,7 @@ public:
>  	{
>  		/* From datasheet: 64 at 10bits. */
>  		blackLevel_ = 4096;
> -		gainType_ = AnalogueGainLinear;
> -		gainConstants_.linear = { 100, 0, 0, 1024 };
> +		gain_ = AnalogueGainLinear{ 100, 0, 0, 1024 };
>  	}
>  };
>  REGISTER_CAMERA_SENSOR_HELPER("gc08a3", CameraSensorHelperGc08a3)
> @@ -552,8 +508,7 @@ public:
>  	{
>  		/* From datasheet: 64 at 10bits. */
>  		blackLevel_ = 4096;
> -		gainType_ = AnalogueGainLinear;
> -		gainConstants_.linear = { 0, 512, -1, 512 };
> +		gain_ = AnalogueGainLinear{ 0, 512, -1, 512 };
>  	}
>  };
>  REGISTER_CAMERA_SENSOR_HELPER("imx214", CameraSensorHelperImx214)
> @@ -565,8 +520,7 @@ public:
>  	{
>  		/* From datasheet: 64 at 10bits. */
>  		blackLevel_ = 4096;
> -		gainType_ = AnalogueGainLinear;
> -		gainConstants_.linear = { 0, 256, -1, 256 };
> +		gain_ = AnalogueGainLinear{ 0, 256, -1, 256 };
>  	}
>  };
>  REGISTER_CAMERA_SENSOR_HELPER("imx219", CameraSensorHelperImx219)
> @@ -578,8 +532,7 @@ public:
>  	{
>  		/* From datasheet: 0x40 at 10bits. */
>  		blackLevel_ = 4096;
> -		gainType_ = AnalogueGainLinear;
> -		gainConstants_.linear = { 0, 512, -1, 512 };
> +		gain_ = AnalogueGainLinear{ 0, 512, -1, 512 };
>  	}
>  };
>  REGISTER_CAMERA_SENSOR_HELPER("imx258", CameraSensorHelperImx258)
> @@ -591,8 +544,7 @@ public:
>  	{
>  		/* From datasheet: 0x32 at 10bits. */
>  		blackLevel_ = 3200;
> -		gainType_ = AnalogueGainLinear;
> -		gainConstants_.linear = { 0, 2048, -1, 2048 };
> +		gain_ = AnalogueGainLinear{ 0, 2048, -1, 2048 };
>  	}
>  };
>  REGISTER_CAMERA_SENSOR_HELPER("imx283", CameraSensorHelperImx283)
> @@ -604,8 +556,7 @@ public:
>  	{
>  		/* From datasheet: 0xf0 at 12bits. */
>  		blackLevel_ = 3840;
> -		gainType_ = AnalogueGainExponential;
> -		gainConstants_.exp = { 1.0, expGainDb(0.3) };
> +		gain_ = AnalogueGainExp{ 1.0, expGainDb(0.3) };
>  	}
>  };
>  REGISTER_CAMERA_SENSOR_HELPER("imx290", CameraSensorHelperImx290)
> @@ -615,8 +566,7 @@ class CameraSensorHelperImx296 : public CameraSensorHelper
>  public:
>  	CameraSensorHelperImx296()
>  	{
> -		gainType_ = AnalogueGainExponential;
> -		gainConstants_.exp = { 1.0, expGainDb(0.1) };
> +		gain_ = AnalogueGainExp{ 1.0, expGainDb(0.1) };
>  	}
>  };
>  REGISTER_CAMERA_SENSOR_HELPER("imx296", CameraSensorHelperImx296)
> @@ -633,8 +583,7 @@ public:
>  	{
>  		/* From datasheet: 0x32 at 10bits. */
>  		blackLevel_ = 3200;
> -		gainType_ = AnalogueGainExponential;
> -		gainConstants_.exp = { 1.0, expGainDb(0.3) };
> +		gain_ = AnalogueGainExp{ 1.0, expGainDb(0.3) };
>  	}
>  };
>  REGISTER_CAMERA_SENSOR_HELPER("imx335", CameraSensorHelperImx335)
> @@ -644,8 +593,7 @@ class CameraSensorHelperImx415 : public CameraSensorHelper
>  public:
>  	CameraSensorHelperImx415()
>  	{
> -		gainType_ = AnalogueGainExponential;
> -		gainConstants_.exp = { 1.0, expGainDb(0.3) };
> +		gain_ = AnalogueGainExp{ 1.0, expGainDb(0.3) };
>  	}
>  };
>  REGISTER_CAMERA_SENSOR_HELPER("imx415", CameraSensorHelperImx415)
> @@ -660,8 +608,7 @@ class CameraSensorHelperImx477 : public CameraSensorHelper
>  public:
>  	CameraSensorHelperImx477()
>  	{
> -		gainType_ = AnalogueGainLinear;
> -		gainConstants_.linear = { 0, 1024, -1, 1024 };
> +		gain_ = AnalogueGainLinear{ 0, 1024, -1, 1024 };
>  	}
>  };
>  REGISTER_CAMERA_SENSOR_HELPER("imx477", CameraSensorHelperImx477)
> @@ -675,8 +622,7 @@ public:
>  		 * The Sensor Manual doesn't appear to document the gain model.
>  		 * This has been validated with some empirical testing only.
>  		 */
> -		gainType_ = AnalogueGainLinear;
> -		gainConstants_.linear = { 1, 0, 0, 128 };
> +		gain_ = AnalogueGainLinear{ 1, 0, 0, 128 };
>  	}
>  };
>  REGISTER_CAMERA_SENSOR_HELPER("ov2685", CameraSensorHelperOv2685)
> @@ -686,8 +632,7 @@ class CameraSensorHelperOv2740 : public CameraSensorHelper
>  public:
>  	CameraSensorHelperOv2740()
>  	{
> -		gainType_ = AnalogueGainLinear;
> -		gainConstants_.linear = { 1, 0, 0, 128 };
> +		gain_ = AnalogueGainLinear{ 1, 0, 0, 128 };
>  	}
>  };
>  REGISTER_CAMERA_SENSOR_HELPER("ov2740", CameraSensorHelperOv2740)
> @@ -699,8 +644,7 @@ public:
>  	{
>  		/* From datasheet: 0x40 at 12bits. */
>  		blackLevel_ = 1024;
> -		gainType_ = AnalogueGainLinear;
> -		gainConstants_.linear = { 1, 0, 0, 128 };
> +		gain_ = AnalogueGainLinear{ 1, 0, 0, 128 };
>  	}
>  };
>  REGISTER_CAMERA_SENSOR_HELPER("ov4689", CameraSensorHelperOv4689)
> @@ -712,8 +656,7 @@ public:
>  	{
>  		/* From datasheet: 0x10 at 10bits. */
>  		blackLevel_ = 1024;
> -		gainType_ = AnalogueGainLinear;
> -		gainConstants_.linear = { 1, 0, 0, 16 };
> +		gain_ = AnalogueGainLinear{ 1, 0, 0, 16 };
>  	}
>  };
>  REGISTER_CAMERA_SENSOR_HELPER("ov5640", CameraSensorHelperOv5640)
> @@ -723,8 +666,7 @@ class CameraSensorHelperOv5647 : public CameraSensorHelper
>  public:
>  	CameraSensorHelperOv5647()
>  	{
> -		gainType_ = AnalogueGainLinear;
> -		gainConstants_.linear = { 1, 0, 0, 16 };
> +		gain_ = AnalogueGainLinear{ 1, 0, 0, 16 };
>  	}
>  };
>  REGISTER_CAMERA_SENSOR_HELPER("ov5647", CameraSensorHelperOv5647)
> @@ -734,8 +676,7 @@ class CameraSensorHelperOv5670 : public CameraSensorHelper
>  public:
>  	CameraSensorHelperOv5670()
>  	{
> -		gainType_ = AnalogueGainLinear;
> -		gainConstants_.linear = { 1, 0, 0, 128 };
> +		gain_ = AnalogueGainLinear{ 1, 0, 0, 128 };
>  	}
>  };
>  REGISTER_CAMERA_SENSOR_HELPER("ov5670", CameraSensorHelperOv5670)
> @@ -747,8 +688,7 @@ public:
>  	{
>  		/* From Linux kernel driver: 0x40 at 10bits. */
>  		blackLevel_ = 4096;
> -		gainType_ = AnalogueGainLinear;
> -		gainConstants_.linear = { 1, 0, 0, 128 };
> +		gain_ = AnalogueGainLinear{ 1, 0, 0, 128 };
>  	}
>  };
>  REGISTER_CAMERA_SENSOR_HELPER("ov5675", CameraSensorHelperOv5675)
> @@ -758,8 +698,7 @@ class CameraSensorHelperOv5693 : public CameraSensorHelper
>  public:
>  	CameraSensorHelperOv5693()
>  	{
> -		gainType_ = AnalogueGainLinear;
> -		gainConstants_.linear = { 1, 0, 0, 16 };
> +		gain_ = AnalogueGainLinear{ 1, 0, 0, 16 };
>  	}
>  };
>  REGISTER_CAMERA_SENSOR_HELPER("ov5693", CameraSensorHelperOv5693)
> @@ -769,8 +708,7 @@ class CameraSensorHelperOv64a40 : public CameraSensorHelper
>  public:
>  	CameraSensorHelperOv64a40()
>  	{
> -		gainType_ = AnalogueGainLinear;
> -		gainConstants_.linear = { 1, 0, 0, 128 };
> +		gain_ = AnalogueGainLinear{ 1, 0, 0, 128 };
>  	}
>  };
>  REGISTER_CAMERA_SENSOR_HELPER("ov64a40", CameraSensorHelperOv64a40)
> @@ -780,15 +718,13 @@ class CameraSensorHelperOv8858 : public CameraSensorHelper
>  public:
>  	CameraSensorHelperOv8858()
>  	{
> -		gainType_ = AnalogueGainLinear;
> -
>  		/*
>  		 * \todo Validate the selected 1/128 step value as it differs
>  		 * from what the sensor manual describes.
>  		 *
>  		 * See: https://patchwork.linuxtv.org/project/linux-media/patch/20221106171129.166892-2-nicholas@rothemail.net/#142267
>  		 */
> -		gainConstants_.linear = { 1, 0, 0, 128 };
> +		gain_ = AnalogueGainLinear{ 1, 0, 0, 128 };
>  	}
>  };
>  REGISTER_CAMERA_SENSOR_HELPER("ov8858", CameraSensorHelperOv8858)
> @@ -798,8 +734,7 @@ class CameraSensorHelperOv8865 : public CameraSensorHelper
>  public:
>  	CameraSensorHelperOv8865()
>  	{
> -		gainType_ = AnalogueGainLinear;
> -		gainConstants_.linear = { 1, 0, 0, 128 };
> +		gain_ = AnalogueGainLinear{ 1, 0, 0, 128 };
>  	}
>  };
>  REGISTER_CAMERA_SENSOR_HELPER("ov8865", CameraSensorHelperOv8865)
> @@ -809,8 +744,7 @@ class CameraSensorHelperOv13858 : public CameraSensorHelper
>  public:
>  	CameraSensorHelperOv13858()
>  	{
> -		gainType_ = AnalogueGainLinear;
> -		gainConstants_.linear = { 1, 0, 0, 128 };
> +		gain_ = AnalogueGainLinear{ 1, 0, 0, 128 };
>  	}
>  };
>  REGISTER_CAMERA_SENSOR_HELPER("ov13858", CameraSensorHelperOv13858)
> diff --git a/src/ipa/libipa/camera_sensor_helper.h b/src/ipa/libipa/camera_sensor_helper.h
> index 75868205..a9300a64 100644
> --- a/src/ipa/libipa/camera_sensor_helper.h
> +++ b/src/ipa/libipa/camera_sensor_helper.h
> @@ -11,6 +11,7 @@
>  #include <optional>
>  #include <stdint.h>
>  #include <string>
> +#include <variant>
>  #include <vector>
>  
>  #include <libcamera/base/class.h>
> @@ -30,31 +31,20 @@ public:
>  	virtual double gain(uint32_t gainCode) const;
>  
>  protected:
> -	enum AnalogueGainType {
> -		AnalogueGainLinear,
> -		AnalogueGainExponential,
> -	};
> -
> -	struct AnalogueGainLinearConstants {
> +	struct AnalogueGainLinear {
>  		int16_t m0;
>  		int16_t c0;
>  		int16_t m1;
>  		int16_t c1;
>  	};
>  
> -	struct AnalogueGainExpConstants {
> +	struct AnalogueGainExp {
>  		double a;
>  		double m;
>  	};
>  
> -	union AnalogueGainConstants {
> -		AnalogueGainLinearConstants linear;
> -		AnalogueGainExpConstants exp;
> -	};
> -
>  	std::optional<int16_t> blackLevel_;
> -	AnalogueGainType gainType_;
> -	AnalogueGainConstants gainConstants_;
> +	std::variant<std::monostate, AnalogueGainLinear, AnalogueGainExp> gain_;
>  
>  private:
>  	LIBCAMERA_DISABLE_COPY_AND_MOVE(CameraSensorHelper)
Laurent Pinchart Dec. 9, 2024, 2:28 a.m. UTC | #2
On Thu, Dec 05, 2024 at 09:58:15PM +0200, Laurent Pinchart wrote:
> Hi Barnabás,
> 
> Thank you for the patch.
> 
> On Thu, Dec 05, 2024 at 12:27:05PM +0000, Barnabás Pőcze wrote:
> > Use an `std::variant` to store the analogue gain instead of a bare union + tag.
> 
> Sounds like the right tool for the job.
> 
> > Signed-off-by: Barnabás Pőcze <pobrn@protonmail.com>
> 
> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> 
> > ---
> >  src/ipa/libipa/camera_sensor_helper.cpp | 198 ++++++++----------------
> >  src/ipa/libipa/camera_sensor_helper.h   |  18 +--
> >  2 files changed, 70 insertions(+), 146 deletions(-)
> > 
> > diff --git a/src/ipa/libipa/camera_sensor_helper.cpp b/src/ipa/libipa/camera_sensor_helper.cpp
> > index a76e5e75..ac3d712b 100644
> > --- a/src/ipa/libipa/camera_sensor_helper.cpp
> > +++ b/src/ipa/libipa/camera_sensor_helper.cpp
> > @@ -87,21 +87,18 @@ namespace ipa {
> >   */
> >  uint32_t CameraSensorHelper::gainCode(double gain) const
> >  {
> > -	const AnalogueGainConstants &k = gainConstants_;
> > +	if (auto *l = std::get_if<AnalogueGainLinear>(&gain_)) {
> > +		ASSERT(l->m0 == 0 || l->m1 == 0);
> >  
> > -	switch (gainType_) {
> > -	case AnalogueGainLinear:
> > -		ASSERT(k.linear.m0 == 0 || k.linear.m1 == 0);
> > -
> > -		return (k.linear.c0 - k.linear.c1 * gain) /
> > -		       (k.linear.m1 * gain - k.linear.m0);
> > -
> > -	case AnalogueGainExponential:
> > -		ASSERT(k.exp.a != 0 && k.exp.m != 0);
> > -
> > -		return std::log2(gain / k.exp.a) / k.exp.m;
> > +		return (l->c0 - l->c1 * gain) /
> > +		       (l->m1 * gain - l->m0);
> > +	}
> > +	else if (auto *e = std::get_if<AnalogueGainExp>(&gain_)) {

Actually checkstyle.py reports an issue here and in a few other places.
You can keep my Rb tag for v2 after fixing that.

> > +		ASSERT(e->a != 0 && e->m != 0);
> >  
> > -	default:
> > +		return std::log2(gain / e->a) / e->m;
> > +	}
> > +	else {
> >  		ASSERT(false);
> >  		return 0;
> >  	}
> > @@ -119,38 +116,28 @@ uint32_t CameraSensorHelper::gainCode(double gain) const
> >   */
> >  double CameraSensorHelper::gain(uint32_t gainCode) const
> >  {
> > -	const AnalogueGainConstants &k = gainConstants_;
> >  	double gain = static_cast<double>(gainCode);
> >  
> > -	switch (gainType_) {
> > -	case AnalogueGainLinear:
> > -		ASSERT(k.linear.m0 == 0 || k.linear.m1 == 0);
> > -
> > -		return (k.linear.m0 * gain + k.linear.c0) /
> > -		       (k.linear.m1 * gain + k.linear.c1);
> > +	if (auto *l = std::get_if<AnalogueGainLinear>(&gain_)) {
> > +		ASSERT(l->m0 == 0 || l->m1 == 0);
> >  
> > -	case AnalogueGainExponential:
> > -		ASSERT(k.exp.a != 0 && k.exp.m != 0);
> > -
> > -		return k.exp.a * std::exp2(k.exp.m * gain);
> > +		return (l->m0 * gain + l->c0) /
> > +		       (l->m1 * gain + l->c1);
> > +	}
> > +	else if (auto *e = std::get_if<AnalogueGainExp>(&gain_)) {
> > +		ASSERT(e->a != 0 && e->m != 0);
> >  
> > -	default:
> > +		return e->a * std::exp2(e->m * gain);
> > +	}
> > +	else {
> >  		ASSERT(false);
> >  		return 0.0;
> >  	}
> >  }
> >  
> >  /**
> > - * \enum CameraSensorHelper::AnalogueGainType
> > - * \brief The gain calculation modes as defined by the MIPI CCS
> > - *
> > - * Describes the image sensor analogue gain capabilities.
> > - * Two modes are possible, depending on the sensor: Linear and Exponential.
> > - */
> > -
> > -/**
> > - * \var CameraSensorHelper::AnalogueGainLinear
> > - * \brief Gain is computed using linear gain estimation
> > + * \struct CameraSensorHelper::AnalogueGainLinear
> > + * \brief Analogue gain constants for the linear gain model
> >   *
> >   * The relationship between the integer gain parameter and the resulting gain
> >   * multiplier is given by the following equation:
> > @@ -165,11 +152,27 @@ double CameraSensorHelper::gain(uint32_t gainCode) const
> >   * The full Gain equation therefore reduces to either:
> >   *
> >   * \f$gain=\frac{c0}{m1x+c1}\f$ or \f$\frac{m0x+c0}{c1}\f$
> > + *
> > + * \var CameraSensorHelper::AnalogueGainLinear::m0
> > + * \brief Constant used in the linear gain coding/decoding
> > + *
> > + * \note Either m0 or m1 shall be zero.
> > + *
> > + * \var CameraSensorHelper::AnalogueGainLinear::c0
> > + * \brief Constant used in the linear gain coding/decoding
> > + *
> > + * \var CameraSensorHelper::AnalogueGainLinear::m1
> > + * \brief Constant used in the linear gain coding/decoding
> > + *
> > + * \note Either m0 or m1 shall be zero.
> > + *
> > + * \var CameraSensorHelper::AnalogueGainLinear::c1
> > + * \brief Constant used in the linear gain coding/decoding
> >   */
> >  
> >  /**
> > - * \var CameraSensorHelper::AnalogueGainExponential
> > - * \brief Gain is expressed using an exponential model
> > + * \struct CameraSensorHelper::AnalogueGainExp
> > + * \brief Analogue gain constants for the exponential gain model
> >   *
> >   * The relationship between the integer gain parameter and the resulting gain
> >   * multiplier is given by the following equation:
> > @@ -185,54 +188,14 @@ double CameraSensorHelper::gain(uint32_t gainCode) const
> >   *
> >   * When the gain is expressed in dB, 'a' is equal to 1 and 'm' to
> >   * \f$log_{2}{10^{\frac{1}{20}}}\f$.
> > - */
> > -
> > -/**
> > - * \struct CameraSensorHelper::AnalogueGainLinearConstants
> > - * \brief Analogue gain constants for the linear gain model
> > - *
> > - * \var CameraSensorHelper::AnalogueGainLinearConstants::m0
> > - * \brief Constant used in the linear gain coding/decoding
> > - *
> > - * \note Either m0 or m1 shall be zero.
> > - *
> > - * \var CameraSensorHelper::AnalogueGainLinearConstants::c0
> > - * \brief Constant used in the linear gain coding/decoding
> > - *
> > - * \var CameraSensorHelper::AnalogueGainLinearConstants::m1
> > - * \brief Constant used in the linear gain coding/decoding
> > - *
> > - * \note Either m0 or m1 shall be zero.
> > - *
> > - * \var CameraSensorHelper::AnalogueGainLinearConstants::c1
> > - * \brief Constant used in the linear gain coding/decoding
> > - */
> > -
> > -/**
> > - * \struct CameraSensorHelper::AnalogueGainExpConstants
> > - * \brief Analogue gain constants for the exponential gain model
> >   *
> > - * \var CameraSensorHelper::AnalogueGainExpConstants::a
> > + * \var CameraSensorHelper::AnalogueGainExp::a
> >   * \brief Constant used in the exponential gain coding/decoding
> >   *
> > - * \var CameraSensorHelper::AnalogueGainExpConstants::m
> > + * \var CameraSensorHelper::AnalogueGainExp::m
> >   * \brief Constant used in the exponential gain coding/decoding
> >   */
> >  
> > -/**
> > - * \struct CameraSensorHelper::AnalogueGainConstants
> > - * \brief Analogue gain model constants
> > - *
> > - * This union stores the constants used to calculate the analogue gain. The
> > - * CameraSensorHelper::gainType_ variable selects which union member is valid.
> > - *
> > - * \var CameraSensorHelper::AnalogueGainConstants::linear
> > - * \brief Constants for the linear gain model
> > - *
> > - * \var CameraSensorHelper::AnalogueGainConstants::exp
> > - * \brief Constants for the exponential gain model
> > - */
> > -
> >  /**
> >   * \var CameraSensorHelper::blackLevel_
> >   * \brief The black level of the sensor
> > @@ -240,12 +203,7 @@ double CameraSensorHelper::gain(uint32_t gainCode) const
> >   */
> >  
> >  /**
> > - * \var CameraSensorHelper::gainType_
> > - * \brief The analogue gain model type
> > - */
> > -
> > -/**
> > - * \var CameraSensorHelper::gainConstants_
> > + * \var CameraSensorHelper::gain_
> >   * \brief The analogue gain parameters used for calculation
> >   *
> >   * The analogue gain is calculated through a formula, and its parameters are
> > @@ -526,8 +484,7 @@ public:
> >  	{
> >  		/* From datasheet: 64 at 10bits. */
> >  		blackLevel_ = 4096;
> > -		gainType_ = AnalogueGainLinear;
> > -		gainConstants_.linear = { 100, 0, 0, 1024 };
> > +		gain_ = AnalogueGainLinear{ 100, 0, 0, 1024 };
> >  	}
> >  };
> >  REGISTER_CAMERA_SENSOR_HELPER("gc05a2", CameraSensorHelperGc05a2)
> > @@ -539,8 +496,7 @@ public:
> >  	{
> >  		/* From datasheet: 64 at 10bits. */
> >  		blackLevel_ = 4096;
> > -		gainType_ = AnalogueGainLinear;
> > -		gainConstants_.linear = { 100, 0, 0, 1024 };
> > +		gain_ = AnalogueGainLinear{ 100, 0, 0, 1024 };
> >  	}
> >  };
> >  REGISTER_CAMERA_SENSOR_HELPER("gc08a3", CameraSensorHelperGc08a3)
> > @@ -552,8 +508,7 @@ public:
> >  	{
> >  		/* From datasheet: 64 at 10bits. */
> >  		blackLevel_ = 4096;
> > -		gainType_ = AnalogueGainLinear;
> > -		gainConstants_.linear = { 0, 512, -1, 512 };
> > +		gain_ = AnalogueGainLinear{ 0, 512, -1, 512 };
> >  	}
> >  };
> >  REGISTER_CAMERA_SENSOR_HELPER("imx214", CameraSensorHelperImx214)
> > @@ -565,8 +520,7 @@ public:
> >  	{
> >  		/* From datasheet: 64 at 10bits. */
> >  		blackLevel_ = 4096;
> > -		gainType_ = AnalogueGainLinear;
> > -		gainConstants_.linear = { 0, 256, -1, 256 };
> > +		gain_ = AnalogueGainLinear{ 0, 256, -1, 256 };
> >  	}
> >  };
> >  REGISTER_CAMERA_SENSOR_HELPER("imx219", CameraSensorHelperImx219)
> > @@ -578,8 +532,7 @@ public:
> >  	{
> >  		/* From datasheet: 0x40 at 10bits. */
> >  		blackLevel_ = 4096;
> > -		gainType_ = AnalogueGainLinear;
> > -		gainConstants_.linear = { 0, 512, -1, 512 };
> > +		gain_ = AnalogueGainLinear{ 0, 512, -1, 512 };
> >  	}
> >  };
> >  REGISTER_CAMERA_SENSOR_HELPER("imx258", CameraSensorHelperImx258)
> > @@ -591,8 +544,7 @@ public:
> >  	{
> >  		/* From datasheet: 0x32 at 10bits. */
> >  		blackLevel_ = 3200;
> > -		gainType_ = AnalogueGainLinear;
> > -		gainConstants_.linear = { 0, 2048, -1, 2048 };
> > +		gain_ = AnalogueGainLinear{ 0, 2048, -1, 2048 };
> >  	}
> >  };
> >  REGISTER_CAMERA_SENSOR_HELPER("imx283", CameraSensorHelperImx283)
> > @@ -604,8 +556,7 @@ public:
> >  	{
> >  		/* From datasheet: 0xf0 at 12bits. */
> >  		blackLevel_ = 3840;
> > -		gainType_ = AnalogueGainExponential;
> > -		gainConstants_.exp = { 1.0, expGainDb(0.3) };
> > +		gain_ = AnalogueGainExp{ 1.0, expGainDb(0.3) };
> >  	}
> >  };
> >  REGISTER_CAMERA_SENSOR_HELPER("imx290", CameraSensorHelperImx290)
> > @@ -615,8 +566,7 @@ class CameraSensorHelperImx296 : public CameraSensorHelper
> >  public:
> >  	CameraSensorHelperImx296()
> >  	{
> > -		gainType_ = AnalogueGainExponential;
> > -		gainConstants_.exp = { 1.0, expGainDb(0.1) };
> > +		gain_ = AnalogueGainExp{ 1.0, expGainDb(0.1) };
> >  	}
> >  };
> >  REGISTER_CAMERA_SENSOR_HELPER("imx296", CameraSensorHelperImx296)
> > @@ -633,8 +583,7 @@ public:
> >  	{
> >  		/* From datasheet: 0x32 at 10bits. */
> >  		blackLevel_ = 3200;
> > -		gainType_ = AnalogueGainExponential;
> > -		gainConstants_.exp = { 1.0, expGainDb(0.3) };
> > +		gain_ = AnalogueGainExp{ 1.0, expGainDb(0.3) };
> >  	}
> >  };
> >  REGISTER_CAMERA_SENSOR_HELPER("imx335", CameraSensorHelperImx335)
> > @@ -644,8 +593,7 @@ class CameraSensorHelperImx415 : public CameraSensorHelper
> >  public:
> >  	CameraSensorHelperImx415()
> >  	{
> > -		gainType_ = AnalogueGainExponential;
> > -		gainConstants_.exp = { 1.0, expGainDb(0.3) };
> > +		gain_ = AnalogueGainExp{ 1.0, expGainDb(0.3) };
> >  	}
> >  };
> >  REGISTER_CAMERA_SENSOR_HELPER("imx415", CameraSensorHelperImx415)
> > @@ -660,8 +608,7 @@ class CameraSensorHelperImx477 : public CameraSensorHelper
> >  public:
> >  	CameraSensorHelperImx477()
> >  	{
> > -		gainType_ = AnalogueGainLinear;
> > -		gainConstants_.linear = { 0, 1024, -1, 1024 };
> > +		gain_ = AnalogueGainLinear{ 0, 1024, -1, 1024 };
> >  	}
> >  };
> >  REGISTER_CAMERA_SENSOR_HELPER("imx477", CameraSensorHelperImx477)
> > @@ -675,8 +622,7 @@ public:
> >  		 * The Sensor Manual doesn't appear to document the gain model.
> >  		 * This has been validated with some empirical testing only.
> >  		 */
> > -		gainType_ = AnalogueGainLinear;
> > -		gainConstants_.linear = { 1, 0, 0, 128 };
> > +		gain_ = AnalogueGainLinear{ 1, 0, 0, 128 };
> >  	}
> >  };
> >  REGISTER_CAMERA_SENSOR_HELPER("ov2685", CameraSensorHelperOv2685)
> > @@ -686,8 +632,7 @@ class CameraSensorHelperOv2740 : public CameraSensorHelper
> >  public:
> >  	CameraSensorHelperOv2740()
> >  	{
> > -		gainType_ = AnalogueGainLinear;
> > -		gainConstants_.linear = { 1, 0, 0, 128 };
> > +		gain_ = AnalogueGainLinear{ 1, 0, 0, 128 };
> >  	}
> >  };
> >  REGISTER_CAMERA_SENSOR_HELPER("ov2740", CameraSensorHelperOv2740)
> > @@ -699,8 +644,7 @@ public:
> >  	{
> >  		/* From datasheet: 0x40 at 12bits. */
> >  		blackLevel_ = 1024;
> > -		gainType_ = AnalogueGainLinear;
> > -		gainConstants_.linear = { 1, 0, 0, 128 };
> > +		gain_ = AnalogueGainLinear{ 1, 0, 0, 128 };
> >  	}
> >  };
> >  REGISTER_CAMERA_SENSOR_HELPER("ov4689", CameraSensorHelperOv4689)
> > @@ -712,8 +656,7 @@ public:
> >  	{
> >  		/* From datasheet: 0x10 at 10bits. */
> >  		blackLevel_ = 1024;
> > -		gainType_ = AnalogueGainLinear;
> > -		gainConstants_.linear = { 1, 0, 0, 16 };
> > +		gain_ = AnalogueGainLinear{ 1, 0, 0, 16 };
> >  	}
> >  };
> >  REGISTER_CAMERA_SENSOR_HELPER("ov5640", CameraSensorHelperOv5640)
> > @@ -723,8 +666,7 @@ class CameraSensorHelperOv5647 : public CameraSensorHelper
> >  public:
> >  	CameraSensorHelperOv5647()
> >  	{
> > -		gainType_ = AnalogueGainLinear;
> > -		gainConstants_.linear = { 1, 0, 0, 16 };
> > +		gain_ = AnalogueGainLinear{ 1, 0, 0, 16 };
> >  	}
> >  };
> >  REGISTER_CAMERA_SENSOR_HELPER("ov5647", CameraSensorHelperOv5647)
> > @@ -734,8 +676,7 @@ class CameraSensorHelperOv5670 : public CameraSensorHelper
> >  public:
> >  	CameraSensorHelperOv5670()
> >  	{
> > -		gainType_ = AnalogueGainLinear;
> > -		gainConstants_.linear = { 1, 0, 0, 128 };
> > +		gain_ = AnalogueGainLinear{ 1, 0, 0, 128 };
> >  	}
> >  };
> >  REGISTER_CAMERA_SENSOR_HELPER("ov5670", CameraSensorHelperOv5670)
> > @@ -747,8 +688,7 @@ public:
> >  	{
> >  		/* From Linux kernel driver: 0x40 at 10bits. */
> >  		blackLevel_ = 4096;
> > -		gainType_ = AnalogueGainLinear;
> > -		gainConstants_.linear = { 1, 0, 0, 128 };
> > +		gain_ = AnalogueGainLinear{ 1, 0, 0, 128 };
> >  	}
> >  };
> >  REGISTER_CAMERA_SENSOR_HELPER("ov5675", CameraSensorHelperOv5675)
> > @@ -758,8 +698,7 @@ class CameraSensorHelperOv5693 : public CameraSensorHelper
> >  public:
> >  	CameraSensorHelperOv5693()
> >  	{
> > -		gainType_ = AnalogueGainLinear;
> > -		gainConstants_.linear = { 1, 0, 0, 16 };
> > +		gain_ = AnalogueGainLinear{ 1, 0, 0, 16 };
> >  	}
> >  };
> >  REGISTER_CAMERA_SENSOR_HELPER("ov5693", CameraSensorHelperOv5693)
> > @@ -769,8 +708,7 @@ class CameraSensorHelperOv64a40 : public CameraSensorHelper
> >  public:
> >  	CameraSensorHelperOv64a40()
> >  	{
> > -		gainType_ = AnalogueGainLinear;
> > -		gainConstants_.linear = { 1, 0, 0, 128 };
> > +		gain_ = AnalogueGainLinear{ 1, 0, 0, 128 };
> >  	}
> >  };
> >  REGISTER_CAMERA_SENSOR_HELPER("ov64a40", CameraSensorHelperOv64a40)
> > @@ -780,15 +718,13 @@ class CameraSensorHelperOv8858 : public CameraSensorHelper
> >  public:
> >  	CameraSensorHelperOv8858()
> >  	{
> > -		gainType_ = AnalogueGainLinear;
> > -
> >  		/*
> >  		 * \todo Validate the selected 1/128 step value as it differs
> >  		 * from what the sensor manual describes.
> >  		 *
> >  		 * See: https://patchwork.linuxtv.org/project/linux-media/patch/20221106171129.166892-2-nicholas@rothemail.net/#142267
> >  		 */
> > -		gainConstants_.linear = { 1, 0, 0, 128 };
> > +		gain_ = AnalogueGainLinear{ 1, 0, 0, 128 };
> >  	}
> >  };
> >  REGISTER_CAMERA_SENSOR_HELPER("ov8858", CameraSensorHelperOv8858)
> > @@ -798,8 +734,7 @@ class CameraSensorHelperOv8865 : public CameraSensorHelper
> >  public:
> >  	CameraSensorHelperOv8865()
> >  	{
> > -		gainType_ = AnalogueGainLinear;
> > -		gainConstants_.linear = { 1, 0, 0, 128 };
> > +		gain_ = AnalogueGainLinear{ 1, 0, 0, 128 };
> >  	}
> >  };
> >  REGISTER_CAMERA_SENSOR_HELPER("ov8865", CameraSensorHelperOv8865)
> > @@ -809,8 +744,7 @@ class CameraSensorHelperOv13858 : public CameraSensorHelper
> >  public:
> >  	CameraSensorHelperOv13858()
> >  	{
> > -		gainType_ = AnalogueGainLinear;
> > -		gainConstants_.linear = { 1, 0, 0, 128 };
> > +		gain_ = AnalogueGainLinear{ 1, 0, 0, 128 };
> >  	}
> >  };
> >  REGISTER_CAMERA_SENSOR_HELPER("ov13858", CameraSensorHelperOv13858)
> > diff --git a/src/ipa/libipa/camera_sensor_helper.h b/src/ipa/libipa/camera_sensor_helper.h
> > index 75868205..a9300a64 100644
> > --- a/src/ipa/libipa/camera_sensor_helper.h
> > +++ b/src/ipa/libipa/camera_sensor_helper.h
> > @@ -11,6 +11,7 @@
> >  #include <optional>
> >  #include <stdint.h>
> >  #include <string>
> > +#include <variant>
> >  #include <vector>
> >  
> >  #include <libcamera/base/class.h>
> > @@ -30,31 +31,20 @@ public:
> >  	virtual double gain(uint32_t gainCode) const;
> >  
> >  protected:
> > -	enum AnalogueGainType {
> > -		AnalogueGainLinear,
> > -		AnalogueGainExponential,
> > -	};
> > -
> > -	struct AnalogueGainLinearConstants {
> > +	struct AnalogueGainLinear {
> >  		int16_t m0;
> >  		int16_t c0;
> >  		int16_t m1;
> >  		int16_t c1;
> >  	};
> >  
> > -	struct AnalogueGainExpConstants {
> > +	struct AnalogueGainExp {
> >  		double a;
> >  		double m;
> >  	};
> >  
> > -	union AnalogueGainConstants {
> > -		AnalogueGainLinearConstants linear;
> > -		AnalogueGainExpConstants exp;
> > -	};
> > -
> >  	std::optional<int16_t> blackLevel_;
> > -	AnalogueGainType gainType_;
> > -	AnalogueGainConstants gainConstants_;
> > +	std::variant<std::monostate, AnalogueGainLinear, AnalogueGainExp> gain_;
> >  
> >  private:
> >  	LIBCAMERA_DISABLE_COPY_AND_MOVE(CameraSensorHelper)

Patch
diff mbox series

diff --git a/src/ipa/libipa/camera_sensor_helper.cpp b/src/ipa/libipa/camera_sensor_helper.cpp
index a76e5e75..ac3d712b 100644
--- a/src/ipa/libipa/camera_sensor_helper.cpp
+++ b/src/ipa/libipa/camera_sensor_helper.cpp
@@ -87,21 +87,18 @@  namespace ipa {
  */
 uint32_t CameraSensorHelper::gainCode(double gain) const
 {
-	const AnalogueGainConstants &k = gainConstants_;
+	if (auto *l = std::get_if<AnalogueGainLinear>(&gain_)) {
+		ASSERT(l->m0 == 0 || l->m1 == 0);
 
-	switch (gainType_) {
-	case AnalogueGainLinear:
-		ASSERT(k.linear.m0 == 0 || k.linear.m1 == 0);
-
-		return (k.linear.c0 - k.linear.c1 * gain) /
-		       (k.linear.m1 * gain - k.linear.m0);
-
-	case AnalogueGainExponential:
-		ASSERT(k.exp.a != 0 && k.exp.m != 0);
-
-		return std::log2(gain / k.exp.a) / k.exp.m;
+		return (l->c0 - l->c1 * gain) /
+		       (l->m1 * gain - l->m0);
+	}
+	else if (auto *e = std::get_if<AnalogueGainExp>(&gain_)) {
+		ASSERT(e->a != 0 && e->m != 0);
 
-	default:
+		return std::log2(gain / e->a) / e->m;
+	}
+	else {
 		ASSERT(false);
 		return 0;
 	}
@@ -119,38 +116,28 @@  uint32_t CameraSensorHelper::gainCode(double gain) const
  */
 double CameraSensorHelper::gain(uint32_t gainCode) const
 {
-	const AnalogueGainConstants &k = gainConstants_;
 	double gain = static_cast<double>(gainCode);
 
-	switch (gainType_) {
-	case AnalogueGainLinear:
-		ASSERT(k.linear.m0 == 0 || k.linear.m1 == 0);
-
-		return (k.linear.m0 * gain + k.linear.c0) /
-		       (k.linear.m1 * gain + k.linear.c1);
+	if (auto *l = std::get_if<AnalogueGainLinear>(&gain_)) {
+		ASSERT(l->m0 == 0 || l->m1 == 0);
 
-	case AnalogueGainExponential:
-		ASSERT(k.exp.a != 0 && k.exp.m != 0);
-
-		return k.exp.a * std::exp2(k.exp.m * gain);
+		return (l->m0 * gain + l->c0) /
+		       (l->m1 * gain + l->c1);
+	}
+	else if (auto *e = std::get_if<AnalogueGainExp>(&gain_)) {
+		ASSERT(e->a != 0 && e->m != 0);
 
-	default:
+		return e->a * std::exp2(e->m * gain);
+	}
+	else {
 		ASSERT(false);
 		return 0.0;
 	}
 }
 
 /**
- * \enum CameraSensorHelper::AnalogueGainType
- * \brief The gain calculation modes as defined by the MIPI CCS
- *
- * Describes the image sensor analogue gain capabilities.
- * Two modes are possible, depending on the sensor: Linear and Exponential.
- */
-
-/**
- * \var CameraSensorHelper::AnalogueGainLinear
- * \brief Gain is computed using linear gain estimation
+ * \struct CameraSensorHelper::AnalogueGainLinear
+ * \brief Analogue gain constants for the linear gain model
  *
  * The relationship between the integer gain parameter and the resulting gain
  * multiplier is given by the following equation:
@@ -165,11 +152,27 @@  double CameraSensorHelper::gain(uint32_t gainCode) const
  * The full Gain equation therefore reduces to either:
  *
  * \f$gain=\frac{c0}{m1x+c1}\f$ or \f$\frac{m0x+c0}{c1}\f$
+ *
+ * \var CameraSensorHelper::AnalogueGainLinear::m0
+ * \brief Constant used in the linear gain coding/decoding
+ *
+ * \note Either m0 or m1 shall be zero.
+ *
+ * \var CameraSensorHelper::AnalogueGainLinear::c0
+ * \brief Constant used in the linear gain coding/decoding
+ *
+ * \var CameraSensorHelper::AnalogueGainLinear::m1
+ * \brief Constant used in the linear gain coding/decoding
+ *
+ * \note Either m0 or m1 shall be zero.
+ *
+ * \var CameraSensorHelper::AnalogueGainLinear::c1
+ * \brief Constant used in the linear gain coding/decoding
  */
 
 /**
- * \var CameraSensorHelper::AnalogueGainExponential
- * \brief Gain is expressed using an exponential model
+ * \struct CameraSensorHelper::AnalogueGainExp
+ * \brief Analogue gain constants for the exponential gain model
  *
  * The relationship between the integer gain parameter and the resulting gain
  * multiplier is given by the following equation:
@@ -185,54 +188,14 @@  double CameraSensorHelper::gain(uint32_t gainCode) const
  *
  * When the gain is expressed in dB, 'a' is equal to 1 and 'm' to
  * \f$log_{2}{10^{\frac{1}{20}}}\f$.
- */
-
-/**
- * \struct CameraSensorHelper::AnalogueGainLinearConstants
- * \brief Analogue gain constants for the linear gain model
- *
- * \var CameraSensorHelper::AnalogueGainLinearConstants::m0
- * \brief Constant used in the linear gain coding/decoding
- *
- * \note Either m0 or m1 shall be zero.
- *
- * \var CameraSensorHelper::AnalogueGainLinearConstants::c0
- * \brief Constant used in the linear gain coding/decoding
- *
- * \var CameraSensorHelper::AnalogueGainLinearConstants::m1
- * \brief Constant used in the linear gain coding/decoding
- *
- * \note Either m0 or m1 shall be zero.
- *
- * \var CameraSensorHelper::AnalogueGainLinearConstants::c1
- * \brief Constant used in the linear gain coding/decoding
- */
-
-/**
- * \struct CameraSensorHelper::AnalogueGainExpConstants
- * \brief Analogue gain constants for the exponential gain model
  *
- * \var CameraSensorHelper::AnalogueGainExpConstants::a
+ * \var CameraSensorHelper::AnalogueGainExp::a
  * \brief Constant used in the exponential gain coding/decoding
  *
- * \var CameraSensorHelper::AnalogueGainExpConstants::m
+ * \var CameraSensorHelper::AnalogueGainExp::m
  * \brief Constant used in the exponential gain coding/decoding
  */
 
-/**
- * \struct CameraSensorHelper::AnalogueGainConstants
- * \brief Analogue gain model constants
- *
- * This union stores the constants used to calculate the analogue gain. The
- * CameraSensorHelper::gainType_ variable selects which union member is valid.
- *
- * \var CameraSensorHelper::AnalogueGainConstants::linear
- * \brief Constants for the linear gain model
- *
- * \var CameraSensorHelper::AnalogueGainConstants::exp
- * \brief Constants for the exponential gain model
- */
-
 /**
  * \var CameraSensorHelper::blackLevel_
  * \brief The black level of the sensor
@@ -240,12 +203,7 @@  double CameraSensorHelper::gain(uint32_t gainCode) const
  */
 
 /**
- * \var CameraSensorHelper::gainType_
- * \brief The analogue gain model type
- */
-
-/**
- * \var CameraSensorHelper::gainConstants_
+ * \var CameraSensorHelper::gain_
  * \brief The analogue gain parameters used for calculation
  *
  * The analogue gain is calculated through a formula, and its parameters are
@@ -526,8 +484,7 @@  public:
 	{
 		/* From datasheet: 64 at 10bits. */
 		blackLevel_ = 4096;
-		gainType_ = AnalogueGainLinear;
-		gainConstants_.linear = { 100, 0, 0, 1024 };
+		gain_ = AnalogueGainLinear{ 100, 0, 0, 1024 };
 	}
 };
 REGISTER_CAMERA_SENSOR_HELPER("gc05a2", CameraSensorHelperGc05a2)
@@ -539,8 +496,7 @@  public:
 	{
 		/* From datasheet: 64 at 10bits. */
 		blackLevel_ = 4096;
-		gainType_ = AnalogueGainLinear;
-		gainConstants_.linear = { 100, 0, 0, 1024 };
+		gain_ = AnalogueGainLinear{ 100, 0, 0, 1024 };
 	}
 };
 REGISTER_CAMERA_SENSOR_HELPER("gc08a3", CameraSensorHelperGc08a3)
@@ -552,8 +508,7 @@  public:
 	{
 		/* From datasheet: 64 at 10bits. */
 		blackLevel_ = 4096;
-		gainType_ = AnalogueGainLinear;
-		gainConstants_.linear = { 0, 512, -1, 512 };
+		gain_ = AnalogueGainLinear{ 0, 512, -1, 512 };
 	}
 };
 REGISTER_CAMERA_SENSOR_HELPER("imx214", CameraSensorHelperImx214)
@@ -565,8 +520,7 @@  public:
 	{
 		/* From datasheet: 64 at 10bits. */
 		blackLevel_ = 4096;
-		gainType_ = AnalogueGainLinear;
-		gainConstants_.linear = { 0, 256, -1, 256 };
+		gain_ = AnalogueGainLinear{ 0, 256, -1, 256 };
 	}
 };
 REGISTER_CAMERA_SENSOR_HELPER("imx219", CameraSensorHelperImx219)
@@ -578,8 +532,7 @@  public:
 	{
 		/* From datasheet: 0x40 at 10bits. */
 		blackLevel_ = 4096;
-		gainType_ = AnalogueGainLinear;
-		gainConstants_.linear = { 0, 512, -1, 512 };
+		gain_ = AnalogueGainLinear{ 0, 512, -1, 512 };
 	}
 };
 REGISTER_CAMERA_SENSOR_HELPER("imx258", CameraSensorHelperImx258)
@@ -591,8 +544,7 @@  public:
 	{
 		/* From datasheet: 0x32 at 10bits. */
 		blackLevel_ = 3200;
-		gainType_ = AnalogueGainLinear;
-		gainConstants_.linear = { 0, 2048, -1, 2048 };
+		gain_ = AnalogueGainLinear{ 0, 2048, -1, 2048 };
 	}
 };
 REGISTER_CAMERA_SENSOR_HELPER("imx283", CameraSensorHelperImx283)
@@ -604,8 +556,7 @@  public:
 	{
 		/* From datasheet: 0xf0 at 12bits. */
 		blackLevel_ = 3840;
-		gainType_ = AnalogueGainExponential;
-		gainConstants_.exp = { 1.0, expGainDb(0.3) };
+		gain_ = AnalogueGainExp{ 1.0, expGainDb(0.3) };
 	}
 };
 REGISTER_CAMERA_SENSOR_HELPER("imx290", CameraSensorHelperImx290)
@@ -615,8 +566,7 @@  class CameraSensorHelperImx296 : public CameraSensorHelper
 public:
 	CameraSensorHelperImx296()
 	{
-		gainType_ = AnalogueGainExponential;
-		gainConstants_.exp = { 1.0, expGainDb(0.1) };
+		gain_ = AnalogueGainExp{ 1.0, expGainDb(0.1) };
 	}
 };
 REGISTER_CAMERA_SENSOR_HELPER("imx296", CameraSensorHelperImx296)
@@ -633,8 +583,7 @@  public:
 	{
 		/* From datasheet: 0x32 at 10bits. */
 		blackLevel_ = 3200;
-		gainType_ = AnalogueGainExponential;
-		gainConstants_.exp = { 1.0, expGainDb(0.3) };
+		gain_ = AnalogueGainExp{ 1.0, expGainDb(0.3) };
 	}
 };
 REGISTER_CAMERA_SENSOR_HELPER("imx335", CameraSensorHelperImx335)
@@ -644,8 +593,7 @@  class CameraSensorHelperImx415 : public CameraSensorHelper
 public:
 	CameraSensorHelperImx415()
 	{
-		gainType_ = AnalogueGainExponential;
-		gainConstants_.exp = { 1.0, expGainDb(0.3) };
+		gain_ = AnalogueGainExp{ 1.0, expGainDb(0.3) };
 	}
 };
 REGISTER_CAMERA_SENSOR_HELPER("imx415", CameraSensorHelperImx415)
@@ -660,8 +608,7 @@  class CameraSensorHelperImx477 : public CameraSensorHelper
 public:
 	CameraSensorHelperImx477()
 	{
-		gainType_ = AnalogueGainLinear;
-		gainConstants_.linear = { 0, 1024, -1, 1024 };
+		gain_ = AnalogueGainLinear{ 0, 1024, -1, 1024 };
 	}
 };
 REGISTER_CAMERA_SENSOR_HELPER("imx477", CameraSensorHelperImx477)
@@ -675,8 +622,7 @@  public:
 		 * The Sensor Manual doesn't appear to document the gain model.
 		 * This has been validated with some empirical testing only.
 		 */
-		gainType_ = AnalogueGainLinear;
-		gainConstants_.linear = { 1, 0, 0, 128 };
+		gain_ = AnalogueGainLinear{ 1, 0, 0, 128 };
 	}
 };
 REGISTER_CAMERA_SENSOR_HELPER("ov2685", CameraSensorHelperOv2685)
@@ -686,8 +632,7 @@  class CameraSensorHelperOv2740 : public CameraSensorHelper
 public:
 	CameraSensorHelperOv2740()
 	{
-		gainType_ = AnalogueGainLinear;
-		gainConstants_.linear = { 1, 0, 0, 128 };
+		gain_ = AnalogueGainLinear{ 1, 0, 0, 128 };
 	}
 };
 REGISTER_CAMERA_SENSOR_HELPER("ov2740", CameraSensorHelperOv2740)
@@ -699,8 +644,7 @@  public:
 	{
 		/* From datasheet: 0x40 at 12bits. */
 		blackLevel_ = 1024;
-		gainType_ = AnalogueGainLinear;
-		gainConstants_.linear = { 1, 0, 0, 128 };
+		gain_ = AnalogueGainLinear{ 1, 0, 0, 128 };
 	}
 };
 REGISTER_CAMERA_SENSOR_HELPER("ov4689", CameraSensorHelperOv4689)
@@ -712,8 +656,7 @@  public:
 	{
 		/* From datasheet: 0x10 at 10bits. */
 		blackLevel_ = 1024;
-		gainType_ = AnalogueGainLinear;
-		gainConstants_.linear = { 1, 0, 0, 16 };
+		gain_ = AnalogueGainLinear{ 1, 0, 0, 16 };
 	}
 };
 REGISTER_CAMERA_SENSOR_HELPER("ov5640", CameraSensorHelperOv5640)
@@ -723,8 +666,7 @@  class CameraSensorHelperOv5647 : public CameraSensorHelper
 public:
 	CameraSensorHelperOv5647()
 	{
-		gainType_ = AnalogueGainLinear;
-		gainConstants_.linear = { 1, 0, 0, 16 };
+		gain_ = AnalogueGainLinear{ 1, 0, 0, 16 };
 	}
 };
 REGISTER_CAMERA_SENSOR_HELPER("ov5647", CameraSensorHelperOv5647)
@@ -734,8 +676,7 @@  class CameraSensorHelperOv5670 : public CameraSensorHelper
 public:
 	CameraSensorHelperOv5670()
 	{
-		gainType_ = AnalogueGainLinear;
-		gainConstants_.linear = { 1, 0, 0, 128 };
+		gain_ = AnalogueGainLinear{ 1, 0, 0, 128 };
 	}
 };
 REGISTER_CAMERA_SENSOR_HELPER("ov5670", CameraSensorHelperOv5670)
@@ -747,8 +688,7 @@  public:
 	{
 		/* From Linux kernel driver: 0x40 at 10bits. */
 		blackLevel_ = 4096;
-		gainType_ = AnalogueGainLinear;
-		gainConstants_.linear = { 1, 0, 0, 128 };
+		gain_ = AnalogueGainLinear{ 1, 0, 0, 128 };
 	}
 };
 REGISTER_CAMERA_SENSOR_HELPER("ov5675", CameraSensorHelperOv5675)
@@ -758,8 +698,7 @@  class CameraSensorHelperOv5693 : public CameraSensorHelper
 public:
 	CameraSensorHelperOv5693()
 	{
-		gainType_ = AnalogueGainLinear;
-		gainConstants_.linear = { 1, 0, 0, 16 };
+		gain_ = AnalogueGainLinear{ 1, 0, 0, 16 };
 	}
 };
 REGISTER_CAMERA_SENSOR_HELPER("ov5693", CameraSensorHelperOv5693)
@@ -769,8 +708,7 @@  class CameraSensorHelperOv64a40 : public CameraSensorHelper
 public:
 	CameraSensorHelperOv64a40()
 	{
-		gainType_ = AnalogueGainLinear;
-		gainConstants_.linear = { 1, 0, 0, 128 };
+		gain_ = AnalogueGainLinear{ 1, 0, 0, 128 };
 	}
 };
 REGISTER_CAMERA_SENSOR_HELPER("ov64a40", CameraSensorHelperOv64a40)
@@ -780,15 +718,13 @@  class CameraSensorHelperOv8858 : public CameraSensorHelper
 public:
 	CameraSensorHelperOv8858()
 	{
-		gainType_ = AnalogueGainLinear;
-
 		/*
 		 * \todo Validate the selected 1/128 step value as it differs
 		 * from what the sensor manual describes.
 		 *
 		 * See: https://patchwork.linuxtv.org/project/linux-media/patch/20221106171129.166892-2-nicholas@rothemail.net/#142267
 		 */
-		gainConstants_.linear = { 1, 0, 0, 128 };
+		gain_ = AnalogueGainLinear{ 1, 0, 0, 128 };
 	}
 };
 REGISTER_CAMERA_SENSOR_HELPER("ov8858", CameraSensorHelperOv8858)
@@ -798,8 +734,7 @@  class CameraSensorHelperOv8865 : public CameraSensorHelper
 public:
 	CameraSensorHelperOv8865()
 	{
-		gainType_ = AnalogueGainLinear;
-		gainConstants_.linear = { 1, 0, 0, 128 };
+		gain_ = AnalogueGainLinear{ 1, 0, 0, 128 };
 	}
 };
 REGISTER_CAMERA_SENSOR_HELPER("ov8865", CameraSensorHelperOv8865)
@@ -809,8 +744,7 @@  class CameraSensorHelperOv13858 : public CameraSensorHelper
 public:
 	CameraSensorHelperOv13858()
 	{
-		gainType_ = AnalogueGainLinear;
-		gainConstants_.linear = { 1, 0, 0, 128 };
+		gain_ = AnalogueGainLinear{ 1, 0, 0, 128 };
 	}
 };
 REGISTER_CAMERA_SENSOR_HELPER("ov13858", CameraSensorHelperOv13858)
diff --git a/src/ipa/libipa/camera_sensor_helper.h b/src/ipa/libipa/camera_sensor_helper.h
index 75868205..a9300a64 100644
--- a/src/ipa/libipa/camera_sensor_helper.h
+++ b/src/ipa/libipa/camera_sensor_helper.h
@@ -11,6 +11,7 @@ 
 #include <optional>
 #include <stdint.h>
 #include <string>
+#include <variant>
 #include <vector>
 
 #include <libcamera/base/class.h>
@@ -30,31 +31,20 @@  public:
 	virtual double gain(uint32_t gainCode) const;
 
 protected:
-	enum AnalogueGainType {
-		AnalogueGainLinear,
-		AnalogueGainExponential,
-	};
-
-	struct AnalogueGainLinearConstants {
+	struct AnalogueGainLinear {
 		int16_t m0;
 		int16_t c0;
 		int16_t m1;
 		int16_t c1;
 	};
 
-	struct AnalogueGainExpConstants {
+	struct AnalogueGainExp {
 		double a;
 		double m;
 	};
 
-	union AnalogueGainConstants {
-		AnalogueGainLinearConstants linear;
-		AnalogueGainExpConstants exp;
-	};
-
 	std::optional<int16_t> blackLevel_;
-	AnalogueGainType gainType_;
-	AnalogueGainConstants gainConstants_;
+	std::variant<std::monostate, AnalogueGainLinear, AnalogueGainExp> gain_;
 
 private:
 	LIBCAMERA_DISABLE_COPY_AND_MOVE(CameraSensorHelper)