[v8,31/47] ipa: ipu3: agc: Port to `AgcAlgorithm`
diff mbox series

Message ID 20260824091407.502020-32-barnabas.pocze@ideasonboard.com
State Accepted
Headers show
Series
  • ipa: libipa: agc rework
Related show

Commit Message

Barnabás Pőcze Aug. 24, 2026, 9:13 a.m. UTC
Use the `AgcAlgorithm` class to implement the ipu3 agc algorithm.

Signed-off-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>
Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
---
 src/ipa/ipu3/algorithms/agc.cpp | 111 +++++++++-----------------
 src/ipa/ipu3/algorithms/agc.h   |  15 ++--
 src/ipa/ipu3/ipa_context.cpp    |  49 +++---------
 src/ipa/ipu3/ipa_context.h      |  30 +++----
 src/ipa/ipu3/ipu3.cpp           | 136 +++++---------------------------
 5 files changed, 89 insertions(+), 252 deletions(-)

Comments

Stefan Klug Aug. 26, 2026, 8:40 a.m. UTC | #1
Hi Barnabás,

Quoting Barnabás Pőcze (2026-08-24 11:13:50)
> Use the `AgcAlgorithm` class to implement the ipu3 agc algorithm.
> 
> Signed-off-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>
> Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>


I can't test this but skimming over the changes it looks good to me.

Reviewed-by: Stefan Klug <stefan.klug@ideasonboard.com>

Best regards,
Stefan


> ---
>  src/ipa/ipu3/algorithms/agc.cpp | 111 +++++++++-----------------
>  src/ipa/ipu3/algorithms/agc.h   |  15 ++--
>  src/ipa/ipu3/ipa_context.cpp    |  49 +++---------
>  src/ipa/ipu3/ipa_context.h      |  30 +++----
>  src/ipa/ipu3/ipu3.cpp           | 136 +++++---------------------------
>  5 files changed, 89 insertions(+), 252 deletions(-)
> 
> diff --git a/src/ipa/ipu3/algorithms/agc.cpp b/src/ipa/ipu3/algorithms/agc.cpp
> index e74db62960..29a562d667 100644
> --- a/src/ipa/ipu3/algorithms/agc.cpp
> +++ b/src/ipa/ipu3/algorithms/agc.cpp
> @@ -8,7 +8,6 @@
>  #include "agc.h"
>  
>  #include <algorithm>
> -#include <chrono>
>  
>  #include <libcamera/base/log.h>
>  #include <libcamera/base/utils.h>
> @@ -48,17 +47,10 @@ namespace ipa::ipu3::algorithms {
>  
>  LOG_DEFINE_CATEGORY(IPU3Agc)
>  
> -/* Minimum limit for analogue gain value */
> -static constexpr double kMinAnalogueGain = 1.0;
> -
> -/* \todo Honour the FrameDurationLimits control instead of hardcoding a limit */
> -static constexpr utils::Duration kMaxExposureTime = 60ms;
> -
>  /* Histogram constants */
>  static constexpr uint32_t knumHistogramBins = 256;
>  
>  Agc::Agc()
> -       : minExposureTime_(0s), maxExposureTime_(0s)
>  {
>  }
>  
> @@ -74,15 +66,12 @@ Agc::Agc()
>   */
>  int Agc::init(IPAContext &context, const ValueNode &tuningData)
>  {
> -       int ret;
> -
> -       ret = agc_.parseTuningData(tuningData);
> -       if (ret)
> -               return ret;
> -
> -       context.ctrlMap.merge(agc_.controls());
> -
> -       return 0;
> +       return agc_.init(tuningData, {
> +               .sensor = context.camHelper.get(),
> +               .sensorInfo = context.sensorInfo,
> +               .sensorControls = context.sensorControls,
> +               .ctrlMap = context.ctrlMap,
> +       });
>  }
>  
>  /**
> @@ -95,32 +84,35 @@ int Agc::init(IPAContext &context, const ValueNode &tuningData)
>  int Agc::configure(IPAContext &context,
>                    [[maybe_unused]] const IPAConfigInfo &configInfo)
>  {
> -       const IPASessionConfiguration &configuration = context.configuration;
> -       IPAActiveState &activeState = context.activeState;
> -
> -       stride_ = configuration.grid.stride;
> -       bdsGrid_ = configuration.grid.bdsGrid;
> -
> -       minExposureTime_ = configuration.agc.minExposureTime;
> -       maxExposureTime_ = std::min(configuration.agc.maxExposureTime,
> -                                   kMaxExposureTime);
> -
> -       minAnalogueGain_ = std::max(configuration.agc.minAnalogueGain, kMinAnalogueGain);
> -       maxAnalogueGain_ = configuration.agc.maxAnalogueGain;
> -
> -       /* Configure the default exposure and gain. */
> -       activeState.agc.gain = minAnalogueGain_;
> -       activeState.agc.exposure = 10ms / configuration.sensor.lineDuration;
> -
> -       context.activeState.agc.constraintMode = agc_.constraintModes().begin()->first;
> -       context.activeState.agc.exposureMode = agc_.exposureModeHelpers().begin()->first;
> +       stride_ =  context.configuration.grid.stride;
> +       bdsGrid_ = context.configuration.grid.bdsGrid;
> +
> +       return agc_.configure(context.configuration.agc, context.activeState.agc, {
> +               .sensor = context.camHelper.get(),
> +               .sensorInfo = context.sensorInfo,
> +               .sensorControls = context.sensorControls,
> +               .ctrlMap = context.ctrlMap,
> +       });
> +}
>  
> -       /* \todo Run this again when FrameDurationLimits is passed in */
> -       agc_.setLimits(minExposureTime_, maxExposureTime_, minAnalogueGain_,
> -                      maxAnalogueGain_, {});
> -       agc_.resetFrameCount();
> +/**
> + * \copydoc libcamera::ipa::Algorithm::queueRequest
> + */
> +void Agc::queueRequest(IPAContext &context, [[maybe_unused]] const uint32_t frame,
> +                      IPAFrameContext &frameContext, const ControlList &controls)
> +{
> +       agc_.queueRequest(context.configuration.agc, context.activeState.agc,
> +                         frameContext.agc, controls);
> +}
>  
> -       return 0;
> +/**
> + * \copydoc libcamera::ipa::Algorithm::prepare
> + */
> +void Agc::prepare(IPAContext &context, [[maybe_unused]] const uint32_t frame,
> +                 IPAFrameContext &frameContext,
> +                 [[maybe_unused]] ipu3_uapi_params *params)
> +{
> +       agc_.prepare(context.activeState.agc, frameContext.agc);
>  }
>  
>  Histogram Agc::parseStatistics(const ipu3_uapi_stats_3a *stats,
> @@ -228,16 +220,7 @@ void Agc::process(IPAContext &context, [[maybe_unused]] const uint32_t frame,
>  {
>         Histogram hist = parseStatistics(stats, context.configuration.grid.bdsGrid);
>  
> -       /*
> -        * The Agc algorithm needs to know the effective exposure value that was
> -        * applied to the sensor when the statistics were collected.
> -        */
> -       utils::Duration exposureTime = context.configuration.sensor.lineDuration
> -                                    * frameContext.sensor.exposure;
> -       double analogueGain = frameContext.sensor.gain;
> -       utils::Duration effectiveExposureValue = exposureTime * analogueGain;
> -
> -       const auto &newEv = agc_.calculateNewEv({
> +       agc_.process(context.configuration.agc, context.activeState.agc, frameContext.agc, {{
>                 .traits = AgcTraits{
>                         rgbTriples_,
>                         {{
> @@ -248,29 +231,9 @@ void Agc::process(IPAContext &context, [[maybe_unused]] const uint32_t frame,
>                         bdsGrid_,
>                 },
>                 .yHist = hist,
> -               .effectiveExposureValue = effectiveExposureValue,
> -               .constraintModeIndex = context.activeState.agc.constraintMode,
> -               .exposureModeIndex = context.activeState.agc.exposureMode,
> -       });
> -
> -       LOG(IPU3Agc, Debug)
> -               << "Divided up exposure time, analogue gain and digital gain are "
> -               << newEv.exposureTime << ", " << newEv.analogueGain << " and " << newEv.digitalGain;
> -
> -       IPAActiveState &activeState = context.activeState;
> -       /* Update the estimated exposure time and gain. */
> -       activeState.agc.exposure = newEv.exposureTime / context.configuration.sensor.lineDuration;
> -       activeState.agc.gain = newEv.analogueGain;
> -
> -       metadata.set(controls::AnalogueGain, frameContext.sensor.gain);
> -       metadata.set(controls::ExposureTime, exposureTime.get<std::micro>());
> -
> -       /* \todo Use VBlank value calculated from each frame exposure. */
> -       uint32_t vTotal = context.configuration.sensor.size.height
> -                       + context.configuration.sensor.defVBlank;
> -       utils::Duration frameDuration = context.configuration.sensor.lineDuration
> -                                     * vTotal;
> -       metadata.set(controls::FrameDuration, frameDuration.get<std::micro>());
> +               .exposure = frameContext.sensor.exposure,
> +               .gain = frameContext.sensor.gain,
> +       }}, metadata);
>  }
>  
>  REGISTER_IPA_ALGORITHM(Agc, "Agc")
> diff --git a/src/ipa/ipu3/algorithms/agc.h b/src/ipa/ipu3/algorithms/agc.h
> index d08da7600e..634b1f8a7a 100644
> --- a/src/ipa/ipu3/algorithms/agc.h
> +++ b/src/ipa/ipu3/algorithms/agc.h
> @@ -13,7 +13,7 @@
>  
>  #include <libcamera/geometry.h>
>  
> -#include "libipa/agc_mean_luminance.h"
> +#include "libipa/agc.h"
>  #include "libipa/histogram.h"
>  
>  #include "algorithm.h"
> @@ -32,6 +32,11 @@ public:
>  
>         int init(IPAContext &context, const ValueNode &tuningData) override;
>         int configure(IPAContext &context, const IPAConfigInfo &configInfo) override;
> +       void queueRequest(IPAContext &context, const uint32_t frame,
> +                         IPAFrameContext &frameContext, const ControlList &controls) override;
> +       void prepare(IPAContext &context, const uint32_t frame,
> +                    IPAFrameContext &frameContext,
> +                    ipu3_uapi_params *params)  override;
>         void process(IPAContext &context, const uint32_t frame,
>                      IPAFrameContext &frameContext,
>                      const ipu3_uapi_stats_3a *stats,
> @@ -41,17 +46,11 @@ private:
>         Histogram parseStatistics(const ipu3_uapi_stats_3a *stats,
>                                   const ipu3_uapi_grid_config &grid);
>  
> -       utils::Duration minExposureTime_;
> -       utils::Duration maxExposureTime_;
> -
> -       double minAnalogueGain_;
> -       double maxAnalogueGain_;
> -
>         uint32_t stride_;
>         ipu3_uapi_grid_config bdsGrid_;
>         std::vector<std::tuple<uint8_t, uint8_t, uint8_t>> rgbTriples_;
>  
> -       AgcMeanLuminance agc_;
> +       AgcAlgorithm agc_;
>  };
>  
>  } /* namespace ipa::ipu3::algorithms */
> diff --git a/src/ipa/ipu3/ipa_context.cpp b/src/ipa/ipu3/ipa_context.cpp
> index 3b22f79176..c358b09981 100644
> --- a/src/ipa/ipu3/ipa_context.cpp
> +++ b/src/ipa/ipu3/ipa_context.cpp
> @@ -46,12 +46,21 @@ namespace libcamera::ipa::ipu3 {
>   * \var IPAContext::configuration
>   * \brief The IPA session configuration, immutable during the session
>   *
> + * \var IPAContext::sensorInfo
> + * \brief The IPA camera session details, immutable during the session
> + *
> + * \var IPAContext::sensorControls
> + * \brief The camera sensor controls, immutable during the session
> + *
>   * \var IPAContext::frameContexts
>   * \brief Ring buffer of the IPAFrameContext(s)
>   *
>   * \var IPAContext::activeState
>   * \brief The current state of IPA algorithms
>   *
> + * \var IPAContext::camHelper
> + * \brief The camera sensor helper
> + *
>   * \var IPAContext::ctrlMap
>   * \brief A ControlInfoMap::Map of controls populated by the algorithms
>   */
> @@ -95,48 +104,11 @@ namespace libcamera::ipa::ipu3 {
>  /**
>   * \var IPASessionConfiguration::agc
>   * \brief AGC parameters configuration of the IPA
> - *
> - * \var IPASessionConfiguration::agc.minExposureTime
> - * \brief Minimum exposure time supported with the configured sensor
> - *
> - * \var IPASessionConfiguration::agc.maxExposureTime
> - * \brief Maximum exposure time supported with the configured sensor
> - *
> - * \var IPASessionConfiguration::agc.minAnalogueGain
> - * \brief Minimum analogue gain supported with the configured sensor
> - *
> - * \var IPASessionConfiguration::agc.maxAnalogueGain
> - * \brief Maximum analogue gain supported with the configured sensor
> - */
> -
> -/**
> - * \var IPASessionConfiguration::sensor
> - * \brief Sensor-specific configuration of the IPA
> - *
> - * \var IPASessionConfiguration::sensor.lineDuration
> - * \brief Line duration in microseconds
> - *
> - * \var IPASessionConfiguration::sensor.defVBlank
> - * \brief The default vblank value of the sensor
> - *
> - * \var IPASessionConfiguration::sensor.size
> - * \brief Sensor output resolution
>   */
>  
>  /**
>   * \var IPAActiveState::agc
>   * \brief Context for the Automatic Gain Control algorithm
> - *
> - * The exposure and gain determined are expected to be applied to the sensor
> - * at the earliest opportunity.
> - *
> - * \var IPAActiveState::agc.exposure
> - * \brief Exposure time expressed as a number of lines
> - *
> - * \var IPAActiveState::agc.gain
> - * \brief Analogue gain multiplier
> - *
> - * The gain should be adapted to the sensor specific gain code before applying.
>   */
>  
>  /**
> @@ -185,6 +157,9 @@ namespace libcamera::ipa::ipu3 {
>   *
>   * \var IPAFrameContext::sensor.gain
>   * \brief Analogue gain multiplier
> + *
> + * \var IPAFrameContext::agc
> + * \brief Per-frame state for the AGC algorithm
>   */
>  
>  } /* namespace libcamera::ipa::ipu3 */
> diff --git a/src/ipa/ipu3/ipa_context.h b/src/ipa/ipu3/ipa_context.h
> index 97fcf06cd4..e8f27bc429 100644
> --- a/src/ipa/ipu3/ipa_context.h
> +++ b/src/ipa/ipu3/ipa_context.h
> @@ -15,6 +15,10 @@
>  #include <libcamera/controls.h>
>  #include <libcamera/geometry.h>
>  
> +#include <libcamera/ipa/core_ipa_interface.h>
> +
> +#include <libipa/agc.h>
> +#include <libipa/camera_sensor_helper.h>
>  #include <libipa/fc_queue.h>
>  
>  namespace libcamera {
> @@ -32,18 +36,7 @@ struct IPASessionConfiguration {
>                 ipu3_uapi_grid_config afGrid;
>         } af;
>  
> -       struct {
> -               utils::Duration minExposureTime;
> -               utils::Duration maxExposureTime;
> -               double minAnalogueGain;
> -               double maxAnalogueGain;
> -       } agc;
> -
> -       struct {
> -               int32_t defVBlank;
> -               utils::Duration lineDuration;
> -               Size size;
> -       } sensor;
> +       agc::Session agc;
>  };
>  
>  struct IPAActiveState {
> @@ -53,12 +46,7 @@ struct IPAActiveState {
>                 bool stable;
>         } af;
>  
> -       struct {
> -               uint32_t exposure;
> -               double gain;
> -               uint32_t constraintMode;
> -               uint32_t exposureMode;
> -       } agc;
> +       agc::ActiveState agc;
>  
>         struct {
>                 struct {
> @@ -81,6 +69,8 @@ struct IPAFrameContext : public FrameContext {
>                 uint32_t exposure;
>                 double gain;
>         } sensor;
> +
> +       agc::FrameContext agc;
>  };
>  
>  struct IPAContext {
> @@ -90,10 +80,14 @@ struct IPAContext {
>         }
>  
>         IPASessionConfiguration configuration;
> +       IPACameraSensorInfo sensorInfo;
> +       ControlInfoMap sensorControls;
>         IPAActiveState activeState;
>  
>         FCQueue<IPAFrameContext> frameContexts;
>  
> +       std::unique_ptr<CameraSensorHelper> camHelper;
> +
>         ControlInfoMap::Map ctrlMap;
>  };
>  
> diff --git a/src/ipa/ipu3/ipu3.cpp b/src/ipa/ipu3/ipu3.cpp
> index 4b4e524d90..031b2e4f4d 100644
> --- a/src/ipa/ipu3/ipu3.cpp
> +++ b/src/ipa/ipu3/ipu3.cpp
> @@ -6,7 +6,6 @@
>   */
>  
>  #include <algorithm>
> -#include <array>
>  #include <cmath>
>  #include <limits>
>  #include <map>
> @@ -166,24 +165,15 @@ protected:
>         std::string logPrefix() const override;
>  
>  private:
> -       void updateControls(const IPACameraSensorInfo &sensorInfo,
> -                           const ControlInfoMap &sensorControls,
> -                           ControlInfoMap *ipaControls);
> -       void updateSessionConfiguration(const ControlInfoMap &sensorControls);
> +       void updateControls(ControlInfoMap *ipaControls);
>  
>         void setControls(unsigned int frame);
>         void calculateBdsGrid(const Size &bdsOutputSize);
>  
>         std::map<unsigned int, MappedFrameBuffer> buffers_;
>  
> -       ControlInfoMap sensorCtrls_;
>         ControlInfoMap lensCtrls_;
>  
> -       IPACameraSensorInfo sensorInfo_;
> -
> -       /* Interface to the Camera Helper */
> -       std::unique_ptr<CameraSensorHelper> camHelper_;
> -
>         /* Local parameter storage */
>         struct IPAContext context_;
>  };
> @@ -198,36 +188,6 @@ std::string IPAIPU3::logPrefix() const
>         return "ipu3";
>  }
>  
> -/**
> - * \brief Compute IPASessionConfiguration using the sensor information and the
> - * sensor V4L2 controls
> - */
> -void IPAIPU3::updateSessionConfiguration(const ControlInfoMap &sensorControls)
> -{
> -       const ControlInfo vBlank = sensorControls.find(V4L2_CID_VBLANK)->second;
> -       context_.configuration.sensor.defVBlank = vBlank.def().get<int32_t>();
> -
> -       const ControlInfo &v4l2Exposure = sensorControls.find(V4L2_CID_EXPOSURE)->second;
> -       int32_t minExposure = v4l2Exposure.min().get<int32_t>();
> -       int32_t maxExposure = v4l2Exposure.max().get<int32_t>();
> -
> -       const ControlInfo &v4l2Gain = sensorControls.find(V4L2_CID_ANALOGUE_GAIN)->second;
> -       int32_t minGain = v4l2Gain.min().get<int32_t>();
> -       int32_t maxGain = v4l2Gain.max().get<int32_t>();
> -
> -       /*
> -        * When the AGC computes the new exposure values for a frame, it needs
> -        * to know the limits for exposure time and analogue gain.
> -        * As it depends on the sensor, update it with the controls.
> -        *
> -        * \todo take VBLANK into account for maximum exposure time
> -        */
> -       context_.configuration.agc.minExposureTime = minExposure * context_.configuration.sensor.lineDuration;
> -       context_.configuration.agc.maxExposureTime = maxExposure * context_.configuration.sensor.lineDuration;
> -       context_.configuration.agc.minAnalogueGain = camHelper_->gain(minGain);
> -       context_.configuration.agc.maxAnalogueGain = camHelper_->gain(maxGain);
> -}
> -
>  /**
>   * \brief Compute camera controls using the sensor information and the sensor
>   * V4L2 controls
> @@ -240,54 +200,12 @@ void IPAIPU3::updateSessionConfiguration(const ControlInfoMap &sensorControls)
>   * - controls::ExposureTime
>   * - controls::FrameDurationLimits
>   */
> -void IPAIPU3::updateControls(const IPACameraSensorInfo &sensorInfo,
> -                            const ControlInfoMap &sensorControls,
> -                            ControlInfoMap *ipaControls)
> +void IPAIPU3::updateControls(ControlInfoMap *ipaControls)
>  {
> -       ControlInfoMap::Map controls{};
> -       double lineDuration = context_.configuration.sensor.lineDuration.get<std::micro>();
> -
> -       /*
> -        * Compute exposure time limits by using line length and pixel rate
> -        * converted to microseconds. Use the V4L2_CID_EXPOSURE control to get
> -        * exposure min, max and default and convert it from lines to
> -        * microseconds.
> -        */
> -       const ControlInfo &v4l2Exposure = sensorControls.find(V4L2_CID_EXPOSURE)->second;
> -       int32_t minExposure = v4l2Exposure.min().get<int32_t>() * lineDuration;
> -       int32_t maxExposure = v4l2Exposure.max().get<int32_t>() * lineDuration;
> -       int32_t defExposure = v4l2Exposure.def().get<int32_t>() * lineDuration;
> -       controls[&controls::ExposureTime] = ControlInfo(minExposure, maxExposure,
> -                                                       defExposure);
> +       ControlInfoMap::Map ctrlMap;
>  
> -       /*
> -        * Compute the frame duration limits.
> -        *
> -        * The frame length is computed assuming a fixed line length combined
> -        * with the vertical frame sizes.
> -        */
> -       const ControlInfo &v4l2HBlank = sensorControls.find(V4L2_CID_HBLANK)->second;
> -       uint32_t hblank = v4l2HBlank.def().get<int32_t>();
> -       uint32_t lineLength = sensorInfo.outputSize.width + hblank;
> -
> -       const ControlInfo &v4l2VBlank = sensorControls.find(V4L2_CID_VBLANK)->second;
> -       std::array<uint32_t, 3> frameHeights{
> -               v4l2VBlank.min().get<int32_t>() + sensorInfo.outputSize.height,
> -               v4l2VBlank.max().get<int32_t>() + sensorInfo.outputSize.height,
> -               v4l2VBlank.def().get<int32_t>() + sensorInfo.outputSize.height,
> -       };
> -
> -       std::array<int64_t, 3> frameDurations;
> -       for (unsigned int i = 0; i < frameHeights.size(); ++i) {
> -               uint64_t frameSize = lineLength * frameHeights[i];
> -               frameDurations[i] = frameSize / (sensorInfo.pixelRate / 1000000U);
> -       }
> -       controls[&controls::FrameDurationLimits] = ControlInfo(frameDurations[0],
> -                                                              frameDurations[1],
> -                                                              Span<const int64_t, 2>{ { frameDurations[2], frameDurations[2] } });
> -
> -       controls.insert(context_.ctrlMap.begin(), context_.ctrlMap.end());
> -       *ipaControls = ControlInfoMap(std::move(controls), controls::controls);
> +       ctrlMap.insert(context_.ctrlMap.begin(), context_.ctrlMap.end());
> +       *ipaControls = ControlInfoMap(std::move(ctrlMap), controls::controls);
>  }
>  
>  /**
> @@ -302,18 +220,19 @@ int IPAIPU3::init(const IPASettings &settings,
>                   const ControlInfoMap &sensorControls,
>                   ControlInfoMap *ipaControls)
>  {
> -       camHelper_ = CameraSensorHelperFactoryBase::create(settings.sensorModel);
> -       if (camHelper_ == nullptr) {
> +       context_.camHelper = CameraSensorHelperFactoryBase::create(settings.sensorModel);
> +       if (!context_.camHelper) {
>                 LOG(IPAIPU3, Error)
>                         << "Failed to create camera sensor helper for "
>                         << settings.sensorModel;
>                 return -ENODEV;
>         }
>  
> +       context_.sensorInfo = sensorInfo;
> +       context_.sensorControls = sensorControls;
> +
>         /* Clean context */
>         context_.configuration = {};
> -       context_.configuration.sensor.lineDuration =
> -               sensorInfo.minLineLength * 1.0s / sensorInfo.pixelRate;
>  
>         /* Load the tuning data file. */
>         File file(settings.configurationFile);
> @@ -347,7 +266,7 @@ int IPAIPU3::init(const IPASettings &settings,
>                 return ret;
>  
>         /* Initialize controls. */
> -       updateControls(sensorInfo, sensorControls, ipaControls);
> +       updateControls(ipaControls);
>  
>         return 0;
>  }
> @@ -466,7 +385,8 @@ int IPAIPU3::configure(const IPAConfigInfo &configInfo,
>                 return -ENODATA;
>         }
>  
> -       sensorInfo_ = configInfo.sensorInfo;
> +       context_.sensorInfo = configInfo.sensorInfo;
> +       context_.sensorControls = configInfo.sensorControls;
>  
>         lensCtrls_ = configInfo.lensControls;
>  
> @@ -475,31 +395,16 @@ int IPAIPU3::configure(const IPAConfigInfo &configInfo,
>         context_.configuration = {};
>         context_.frameContexts.clear();
>  
> -       /* Initialise the sensor configuration. */
> -       context_.configuration.sensor.lineDuration =
> -               sensorInfo_.minLineLength * 1.0s / sensorInfo_.pixelRate;
> -       context_.configuration.sensor.size = sensorInfo_.outputSize;
> -
> -       /*
> -        * Compute the sensor V4L2 controls to be used by the algorithms and
> -        * to be set on the sensor.
> -        */
> -       sensorCtrls_ = configInfo.sensorControls;
> -
>         calculateBdsGrid(configInfo.bdsOutputSize);
>  
> -       /* Update the camera controls using the new sensor settings. */
> -       updateControls(sensorInfo_, sensorCtrls_, ipaControls);
> -
> -       /* Update the IPASessionConfiguration using the sensor settings. */
> -       updateSessionConfiguration(sensorCtrls_);
> -
>         for (const auto &algo : algorithms()) {
>                 int ret = algo->configure(context_, configInfo);
>                 if (ret)
>                         return ret;
>         }
>  
> +       updateControls(ipaControls);
> +
>         return 0;
>  }
>  
> @@ -598,7 +503,7 @@ void IPAIPU3::processStats(const uint32_t frame,
>         IPAFrameContext &frameContext = context_.frameContexts.get(frame);
>  
>         std::tie(frameContext.sensor.exposure, frameContext.sensor.gain) =
> -               agc::extractControls(sensorControls, camHelper_.get());
> +               agc::extractControls(sensorControls, context_.camHelper.get());
>  
>         ControlList metadata(controls::controls);
>  
> @@ -643,10 +548,11 @@ void IPAIPU3::queueRequest(const uint32_t frame, const ControlList &controls)
>   */
>  void IPAIPU3::setControls(unsigned int frame)
>  {
> -       ControlList ctrls(sensorCtrls_);
> -       agc::prepareControls(ctrls, camHelper_.get(),
> -                            context_.activeState.agc.exposure,
> -                            context_.activeState.agc.gain);
> +       IPAFrameContext &frameContext = context_.frameContexts.get(frame);
> +
> +       ControlList ctrls(context_.sensorControls);
> +       agc::prepareControls(ctrls, context_.camHelper.get(),
> +                            frameContext.agc.exposure, frameContext.agc.gain);
>  
>         ControlList lensCtrls(lensCtrls_);
>         lensCtrls.set(V4L2_CID_FOCUS_ABSOLUTE,
> -- 
> 2.55.0
>

Patch
diff mbox series

diff --git a/src/ipa/ipu3/algorithms/agc.cpp b/src/ipa/ipu3/algorithms/agc.cpp
index e74db62960..29a562d667 100644
--- a/src/ipa/ipu3/algorithms/agc.cpp
+++ b/src/ipa/ipu3/algorithms/agc.cpp
@@ -8,7 +8,6 @@ 
 #include "agc.h"
 
 #include <algorithm>
-#include <chrono>
 
 #include <libcamera/base/log.h>
 #include <libcamera/base/utils.h>
@@ -48,17 +47,10 @@  namespace ipa::ipu3::algorithms {
 
 LOG_DEFINE_CATEGORY(IPU3Agc)
 
-/* Minimum limit for analogue gain value */
-static constexpr double kMinAnalogueGain = 1.0;
-
-/* \todo Honour the FrameDurationLimits control instead of hardcoding a limit */
-static constexpr utils::Duration kMaxExposureTime = 60ms;
-
 /* Histogram constants */
 static constexpr uint32_t knumHistogramBins = 256;
 
 Agc::Agc()
-	: minExposureTime_(0s), maxExposureTime_(0s)
 {
 }
 
@@ -74,15 +66,12 @@  Agc::Agc()
  */
 int Agc::init(IPAContext &context, const ValueNode &tuningData)
 {
-	int ret;
-
-	ret = agc_.parseTuningData(tuningData);
-	if (ret)
-		return ret;
-
-	context.ctrlMap.merge(agc_.controls());
-
-	return 0;
+	return agc_.init(tuningData, {
+		.sensor = context.camHelper.get(),
+		.sensorInfo = context.sensorInfo,
+		.sensorControls = context.sensorControls,
+		.ctrlMap = context.ctrlMap,
+	});
 }
 
 /**
@@ -95,32 +84,35 @@  int Agc::init(IPAContext &context, const ValueNode &tuningData)
 int Agc::configure(IPAContext &context,
 		   [[maybe_unused]] const IPAConfigInfo &configInfo)
 {
-	const IPASessionConfiguration &configuration = context.configuration;
-	IPAActiveState &activeState = context.activeState;
-
-	stride_ = configuration.grid.stride;
-	bdsGrid_ = configuration.grid.bdsGrid;
-
-	minExposureTime_ = configuration.agc.minExposureTime;
-	maxExposureTime_ = std::min(configuration.agc.maxExposureTime,
-				    kMaxExposureTime);
-
-	minAnalogueGain_ = std::max(configuration.agc.minAnalogueGain, kMinAnalogueGain);
-	maxAnalogueGain_ = configuration.agc.maxAnalogueGain;
-
-	/* Configure the default exposure and gain. */
-	activeState.agc.gain = minAnalogueGain_;
-	activeState.agc.exposure = 10ms / configuration.sensor.lineDuration;
-
-	context.activeState.agc.constraintMode = agc_.constraintModes().begin()->first;
-	context.activeState.agc.exposureMode = agc_.exposureModeHelpers().begin()->first;
+	stride_ =  context.configuration.grid.stride;
+	bdsGrid_ = context.configuration.grid.bdsGrid;
+
+	return agc_.configure(context.configuration.agc, context.activeState.agc, {
+		.sensor = context.camHelper.get(),
+		.sensorInfo = context.sensorInfo,
+		.sensorControls = context.sensorControls,
+		.ctrlMap = context.ctrlMap,
+	});
+}
 
-	/* \todo Run this again when FrameDurationLimits is passed in */
-	agc_.setLimits(minExposureTime_, maxExposureTime_, minAnalogueGain_,
-		       maxAnalogueGain_, {});
-	agc_.resetFrameCount();
+/**
+ * \copydoc libcamera::ipa::Algorithm::queueRequest
+ */
+void Agc::queueRequest(IPAContext &context, [[maybe_unused]] const uint32_t frame,
+		       IPAFrameContext &frameContext, const ControlList &controls)
+{
+	agc_.queueRequest(context.configuration.agc, context.activeState.agc,
+			  frameContext.agc, controls);
+}
 
-	return 0;
+/**
+ * \copydoc libcamera::ipa::Algorithm::prepare
+ */
+void Agc::prepare(IPAContext &context, [[maybe_unused]] const uint32_t frame,
+		  IPAFrameContext &frameContext,
+		  [[maybe_unused]] ipu3_uapi_params *params)
+{
+	agc_.prepare(context.activeState.agc, frameContext.agc);
 }
 
 Histogram Agc::parseStatistics(const ipu3_uapi_stats_3a *stats,
@@ -228,16 +220,7 @@  void Agc::process(IPAContext &context, [[maybe_unused]] const uint32_t frame,
 {
 	Histogram hist = parseStatistics(stats, context.configuration.grid.bdsGrid);
 
-	/*
-	 * The Agc algorithm needs to know the effective exposure value that was
-	 * applied to the sensor when the statistics were collected.
-	 */
-	utils::Duration exposureTime = context.configuration.sensor.lineDuration
-				     * frameContext.sensor.exposure;
-	double analogueGain = frameContext.sensor.gain;
-	utils::Duration effectiveExposureValue = exposureTime * analogueGain;
-
-	const auto &newEv = agc_.calculateNewEv({
+	agc_.process(context.configuration.agc, context.activeState.agc, frameContext.agc, {{
 		.traits = AgcTraits{
 			rgbTriples_,
 			{{
@@ -248,29 +231,9 @@  void Agc::process(IPAContext &context, [[maybe_unused]] const uint32_t frame,
 			bdsGrid_,
 		},
 		.yHist = hist,
-		.effectiveExposureValue = effectiveExposureValue,
-		.constraintModeIndex = context.activeState.agc.constraintMode,
-		.exposureModeIndex = context.activeState.agc.exposureMode,
-	});
-
-	LOG(IPU3Agc, Debug)
-		<< "Divided up exposure time, analogue gain and digital gain are "
-		<< newEv.exposureTime << ", " << newEv.analogueGain << " and " << newEv.digitalGain;
-
-	IPAActiveState &activeState = context.activeState;
-	/* Update the estimated exposure time and gain. */
-	activeState.agc.exposure = newEv.exposureTime / context.configuration.sensor.lineDuration;
-	activeState.agc.gain = newEv.analogueGain;
-
-	metadata.set(controls::AnalogueGain, frameContext.sensor.gain);
-	metadata.set(controls::ExposureTime, exposureTime.get<std::micro>());
-
-	/* \todo Use VBlank value calculated from each frame exposure. */
-	uint32_t vTotal = context.configuration.sensor.size.height
-			+ context.configuration.sensor.defVBlank;
-	utils::Duration frameDuration = context.configuration.sensor.lineDuration
-				      * vTotal;
-	metadata.set(controls::FrameDuration, frameDuration.get<std::micro>());
+		.exposure = frameContext.sensor.exposure,
+		.gain = frameContext.sensor.gain,
+	}}, metadata);
 }
 
 REGISTER_IPA_ALGORITHM(Agc, "Agc")
diff --git a/src/ipa/ipu3/algorithms/agc.h b/src/ipa/ipu3/algorithms/agc.h
index d08da7600e..634b1f8a7a 100644
--- a/src/ipa/ipu3/algorithms/agc.h
+++ b/src/ipa/ipu3/algorithms/agc.h
@@ -13,7 +13,7 @@ 
 
 #include <libcamera/geometry.h>
 
-#include "libipa/agc_mean_luminance.h"
+#include "libipa/agc.h"
 #include "libipa/histogram.h"
 
 #include "algorithm.h"
@@ -32,6 +32,11 @@  public:
 
 	int init(IPAContext &context, const ValueNode &tuningData) override;
 	int configure(IPAContext &context, const IPAConfigInfo &configInfo) override;
+	void queueRequest(IPAContext &context, const uint32_t frame,
+			  IPAFrameContext &frameContext, const ControlList &controls) override;
+	void prepare(IPAContext &context, const uint32_t frame,
+		     IPAFrameContext &frameContext,
+		     ipu3_uapi_params *params)  override;
 	void process(IPAContext &context, const uint32_t frame,
 		     IPAFrameContext &frameContext,
 		     const ipu3_uapi_stats_3a *stats,
@@ -41,17 +46,11 @@  private:
 	Histogram parseStatistics(const ipu3_uapi_stats_3a *stats,
 				  const ipu3_uapi_grid_config &grid);
 
-	utils::Duration minExposureTime_;
-	utils::Duration maxExposureTime_;
-
-	double minAnalogueGain_;
-	double maxAnalogueGain_;
-
 	uint32_t stride_;
 	ipu3_uapi_grid_config bdsGrid_;
 	std::vector<std::tuple<uint8_t, uint8_t, uint8_t>> rgbTriples_;
 
-	AgcMeanLuminance agc_;
+	AgcAlgorithm agc_;
 };
 
 } /* namespace ipa::ipu3::algorithms */
diff --git a/src/ipa/ipu3/ipa_context.cpp b/src/ipa/ipu3/ipa_context.cpp
index 3b22f79176..c358b09981 100644
--- a/src/ipa/ipu3/ipa_context.cpp
+++ b/src/ipa/ipu3/ipa_context.cpp
@@ -46,12 +46,21 @@  namespace libcamera::ipa::ipu3 {
  * \var IPAContext::configuration
  * \brief The IPA session configuration, immutable during the session
  *
+ * \var IPAContext::sensorInfo
+ * \brief The IPA camera session details, immutable during the session
+ *
+ * \var IPAContext::sensorControls
+ * \brief The camera sensor controls, immutable during the session
+ *
  * \var IPAContext::frameContexts
  * \brief Ring buffer of the IPAFrameContext(s)
  *
  * \var IPAContext::activeState
  * \brief The current state of IPA algorithms
  *
+ * \var IPAContext::camHelper
+ * \brief The camera sensor helper
+ *
  * \var IPAContext::ctrlMap
  * \brief A ControlInfoMap::Map of controls populated by the algorithms
  */
@@ -95,48 +104,11 @@  namespace libcamera::ipa::ipu3 {
 /**
  * \var IPASessionConfiguration::agc
  * \brief AGC parameters configuration of the IPA
- *
- * \var IPASessionConfiguration::agc.minExposureTime
- * \brief Minimum exposure time supported with the configured sensor
- *
- * \var IPASessionConfiguration::agc.maxExposureTime
- * \brief Maximum exposure time supported with the configured sensor
- *
- * \var IPASessionConfiguration::agc.minAnalogueGain
- * \brief Minimum analogue gain supported with the configured sensor
- *
- * \var IPASessionConfiguration::agc.maxAnalogueGain
- * \brief Maximum analogue gain supported with the configured sensor
- */
-
-/**
- * \var IPASessionConfiguration::sensor
- * \brief Sensor-specific configuration of the IPA
- *
- * \var IPASessionConfiguration::sensor.lineDuration
- * \brief Line duration in microseconds
- *
- * \var IPASessionConfiguration::sensor.defVBlank
- * \brief The default vblank value of the sensor
- *
- * \var IPASessionConfiguration::sensor.size
- * \brief Sensor output resolution
  */
 
 /**
  * \var IPAActiveState::agc
  * \brief Context for the Automatic Gain Control algorithm
- *
- * The exposure and gain determined are expected to be applied to the sensor
- * at the earliest opportunity.
- *
- * \var IPAActiveState::agc.exposure
- * \brief Exposure time expressed as a number of lines
- *
- * \var IPAActiveState::agc.gain
- * \brief Analogue gain multiplier
- *
- * The gain should be adapted to the sensor specific gain code before applying.
  */
 
 /**
@@ -185,6 +157,9 @@  namespace libcamera::ipa::ipu3 {
  *
  * \var IPAFrameContext::sensor.gain
  * \brief Analogue gain multiplier
+ *
+ * \var IPAFrameContext::agc
+ * \brief Per-frame state for the AGC algorithm
  */
 
 } /* namespace libcamera::ipa::ipu3 */
diff --git a/src/ipa/ipu3/ipa_context.h b/src/ipa/ipu3/ipa_context.h
index 97fcf06cd4..e8f27bc429 100644
--- a/src/ipa/ipu3/ipa_context.h
+++ b/src/ipa/ipu3/ipa_context.h
@@ -15,6 +15,10 @@ 
 #include <libcamera/controls.h>
 #include <libcamera/geometry.h>
 
+#include <libcamera/ipa/core_ipa_interface.h>
+
+#include <libipa/agc.h>
+#include <libipa/camera_sensor_helper.h>
 #include <libipa/fc_queue.h>
 
 namespace libcamera {
@@ -32,18 +36,7 @@  struct IPASessionConfiguration {
 		ipu3_uapi_grid_config afGrid;
 	} af;
 
-	struct {
-		utils::Duration minExposureTime;
-		utils::Duration maxExposureTime;
-		double minAnalogueGain;
-		double maxAnalogueGain;
-	} agc;
-
-	struct {
-		int32_t defVBlank;
-		utils::Duration lineDuration;
-		Size size;
-	} sensor;
+	agc::Session agc;
 };
 
 struct IPAActiveState {
@@ -53,12 +46,7 @@  struct IPAActiveState {
 		bool stable;
 	} af;
 
-	struct {
-		uint32_t exposure;
-		double gain;
-		uint32_t constraintMode;
-		uint32_t exposureMode;
-	} agc;
+	agc::ActiveState agc;
 
 	struct {
 		struct {
@@ -81,6 +69,8 @@  struct IPAFrameContext : public FrameContext {
 		uint32_t exposure;
 		double gain;
 	} sensor;
+
+	agc::FrameContext agc;
 };
 
 struct IPAContext {
@@ -90,10 +80,14 @@  struct IPAContext {
 	}
 
 	IPASessionConfiguration configuration;
+	IPACameraSensorInfo sensorInfo;
+	ControlInfoMap sensorControls;
 	IPAActiveState activeState;
 
 	FCQueue<IPAFrameContext> frameContexts;
 
+	std::unique_ptr<CameraSensorHelper> camHelper;
+
 	ControlInfoMap::Map ctrlMap;
 };
 
diff --git a/src/ipa/ipu3/ipu3.cpp b/src/ipa/ipu3/ipu3.cpp
index 4b4e524d90..031b2e4f4d 100644
--- a/src/ipa/ipu3/ipu3.cpp
+++ b/src/ipa/ipu3/ipu3.cpp
@@ -6,7 +6,6 @@ 
  */
 
 #include <algorithm>
-#include <array>
 #include <cmath>
 #include <limits>
 #include <map>
@@ -166,24 +165,15 @@  protected:
 	std::string logPrefix() const override;
 
 private:
-	void updateControls(const IPACameraSensorInfo &sensorInfo,
-			    const ControlInfoMap &sensorControls,
-			    ControlInfoMap *ipaControls);
-	void updateSessionConfiguration(const ControlInfoMap &sensorControls);
+	void updateControls(ControlInfoMap *ipaControls);
 
 	void setControls(unsigned int frame);
 	void calculateBdsGrid(const Size &bdsOutputSize);
 
 	std::map<unsigned int, MappedFrameBuffer> buffers_;
 
-	ControlInfoMap sensorCtrls_;
 	ControlInfoMap lensCtrls_;
 
-	IPACameraSensorInfo sensorInfo_;
-
-	/* Interface to the Camera Helper */
-	std::unique_ptr<CameraSensorHelper> camHelper_;
-
 	/* Local parameter storage */
 	struct IPAContext context_;
 };
@@ -198,36 +188,6 @@  std::string IPAIPU3::logPrefix() const
 	return "ipu3";
 }
 
-/**
- * \brief Compute IPASessionConfiguration using the sensor information and the
- * sensor V4L2 controls
- */
-void IPAIPU3::updateSessionConfiguration(const ControlInfoMap &sensorControls)
-{
-	const ControlInfo vBlank = sensorControls.find(V4L2_CID_VBLANK)->second;
-	context_.configuration.sensor.defVBlank = vBlank.def().get<int32_t>();
-
-	const ControlInfo &v4l2Exposure = sensorControls.find(V4L2_CID_EXPOSURE)->second;
-	int32_t minExposure = v4l2Exposure.min().get<int32_t>();
-	int32_t maxExposure = v4l2Exposure.max().get<int32_t>();
-
-	const ControlInfo &v4l2Gain = sensorControls.find(V4L2_CID_ANALOGUE_GAIN)->second;
-	int32_t minGain = v4l2Gain.min().get<int32_t>();
-	int32_t maxGain = v4l2Gain.max().get<int32_t>();
-
-	/*
-	 * When the AGC computes the new exposure values for a frame, it needs
-	 * to know the limits for exposure time and analogue gain.
-	 * As it depends on the sensor, update it with the controls.
-	 *
-	 * \todo take VBLANK into account for maximum exposure time
-	 */
-	context_.configuration.agc.minExposureTime = minExposure * context_.configuration.sensor.lineDuration;
-	context_.configuration.agc.maxExposureTime = maxExposure * context_.configuration.sensor.lineDuration;
-	context_.configuration.agc.minAnalogueGain = camHelper_->gain(minGain);
-	context_.configuration.agc.maxAnalogueGain = camHelper_->gain(maxGain);
-}
-
 /**
  * \brief Compute camera controls using the sensor information and the sensor
  * V4L2 controls
@@ -240,54 +200,12 @@  void IPAIPU3::updateSessionConfiguration(const ControlInfoMap &sensorControls)
  * - controls::ExposureTime
  * - controls::FrameDurationLimits
  */
-void IPAIPU3::updateControls(const IPACameraSensorInfo &sensorInfo,
-			     const ControlInfoMap &sensorControls,
-			     ControlInfoMap *ipaControls)
+void IPAIPU3::updateControls(ControlInfoMap *ipaControls)
 {
-	ControlInfoMap::Map controls{};
-	double lineDuration = context_.configuration.sensor.lineDuration.get<std::micro>();
-
-	/*
-	 * Compute exposure time limits by using line length and pixel rate
-	 * converted to microseconds. Use the V4L2_CID_EXPOSURE control to get
-	 * exposure min, max and default and convert it from lines to
-	 * microseconds.
-	 */
-	const ControlInfo &v4l2Exposure = sensorControls.find(V4L2_CID_EXPOSURE)->second;
-	int32_t minExposure = v4l2Exposure.min().get<int32_t>() * lineDuration;
-	int32_t maxExposure = v4l2Exposure.max().get<int32_t>() * lineDuration;
-	int32_t defExposure = v4l2Exposure.def().get<int32_t>() * lineDuration;
-	controls[&controls::ExposureTime] = ControlInfo(minExposure, maxExposure,
-							defExposure);
+	ControlInfoMap::Map ctrlMap;
 
-	/*
-	 * Compute the frame duration limits.
-	 *
-	 * The frame length is computed assuming a fixed line length combined
-	 * with the vertical frame sizes.
-	 */
-	const ControlInfo &v4l2HBlank = sensorControls.find(V4L2_CID_HBLANK)->second;
-	uint32_t hblank = v4l2HBlank.def().get<int32_t>();
-	uint32_t lineLength = sensorInfo.outputSize.width + hblank;
-
-	const ControlInfo &v4l2VBlank = sensorControls.find(V4L2_CID_VBLANK)->second;
-	std::array<uint32_t, 3> frameHeights{
-		v4l2VBlank.min().get<int32_t>() + sensorInfo.outputSize.height,
-		v4l2VBlank.max().get<int32_t>() + sensorInfo.outputSize.height,
-		v4l2VBlank.def().get<int32_t>() + sensorInfo.outputSize.height,
-	};
-
-	std::array<int64_t, 3> frameDurations;
-	for (unsigned int i = 0; i < frameHeights.size(); ++i) {
-		uint64_t frameSize = lineLength * frameHeights[i];
-		frameDurations[i] = frameSize / (sensorInfo.pixelRate / 1000000U);
-	}
-	controls[&controls::FrameDurationLimits] = ControlInfo(frameDurations[0],
-							       frameDurations[1],
-							       Span<const int64_t, 2>{ { frameDurations[2], frameDurations[2] } });
-
-	controls.insert(context_.ctrlMap.begin(), context_.ctrlMap.end());
-	*ipaControls = ControlInfoMap(std::move(controls), controls::controls);
+	ctrlMap.insert(context_.ctrlMap.begin(), context_.ctrlMap.end());
+	*ipaControls = ControlInfoMap(std::move(ctrlMap), controls::controls);
 }
 
 /**
@@ -302,18 +220,19 @@  int IPAIPU3::init(const IPASettings &settings,
 		  const ControlInfoMap &sensorControls,
 		  ControlInfoMap *ipaControls)
 {
-	camHelper_ = CameraSensorHelperFactoryBase::create(settings.sensorModel);
-	if (camHelper_ == nullptr) {
+	context_.camHelper = CameraSensorHelperFactoryBase::create(settings.sensorModel);
+	if (!context_.camHelper) {
 		LOG(IPAIPU3, Error)
 			<< "Failed to create camera sensor helper for "
 			<< settings.sensorModel;
 		return -ENODEV;
 	}
 
+	context_.sensorInfo = sensorInfo;
+	context_.sensorControls = sensorControls;
+
 	/* Clean context */
 	context_.configuration = {};
-	context_.configuration.sensor.lineDuration =
-		sensorInfo.minLineLength * 1.0s / sensorInfo.pixelRate;
 
 	/* Load the tuning data file. */
 	File file(settings.configurationFile);
@@ -347,7 +266,7 @@  int IPAIPU3::init(const IPASettings &settings,
 		return ret;
 
 	/* Initialize controls. */
-	updateControls(sensorInfo, sensorControls, ipaControls);
+	updateControls(ipaControls);
 
 	return 0;
 }
@@ -466,7 +385,8 @@  int IPAIPU3::configure(const IPAConfigInfo &configInfo,
 		return -ENODATA;
 	}
 
-	sensorInfo_ = configInfo.sensorInfo;
+	context_.sensorInfo = configInfo.sensorInfo;
+	context_.sensorControls = configInfo.sensorControls;
 
 	lensCtrls_ = configInfo.lensControls;
 
@@ -475,31 +395,16 @@  int IPAIPU3::configure(const IPAConfigInfo &configInfo,
 	context_.configuration = {};
 	context_.frameContexts.clear();
 
-	/* Initialise the sensor configuration. */
-	context_.configuration.sensor.lineDuration =
-		sensorInfo_.minLineLength * 1.0s / sensorInfo_.pixelRate;
-	context_.configuration.sensor.size = sensorInfo_.outputSize;
-
-	/*
-	 * Compute the sensor V4L2 controls to be used by the algorithms and
-	 * to be set on the sensor.
-	 */
-	sensorCtrls_ = configInfo.sensorControls;
-
 	calculateBdsGrid(configInfo.bdsOutputSize);
 
-	/* Update the camera controls using the new sensor settings. */
-	updateControls(sensorInfo_, sensorCtrls_, ipaControls);
-
-	/* Update the IPASessionConfiguration using the sensor settings. */
-	updateSessionConfiguration(sensorCtrls_);
-
 	for (const auto &algo : algorithms()) {
 		int ret = algo->configure(context_, configInfo);
 		if (ret)
 			return ret;
 	}
 
+	updateControls(ipaControls);
+
 	return 0;
 }
 
@@ -598,7 +503,7 @@  void IPAIPU3::processStats(const uint32_t frame,
 	IPAFrameContext &frameContext = context_.frameContexts.get(frame);
 
 	std::tie(frameContext.sensor.exposure, frameContext.sensor.gain) =
-		agc::extractControls(sensorControls, camHelper_.get());
+		agc::extractControls(sensorControls, context_.camHelper.get());
 
 	ControlList metadata(controls::controls);
 
@@ -643,10 +548,11 @@  void IPAIPU3::queueRequest(const uint32_t frame, const ControlList &controls)
  */
 void IPAIPU3::setControls(unsigned int frame)
 {
-	ControlList ctrls(sensorCtrls_);
-	agc::prepareControls(ctrls, camHelper_.get(),
-			     context_.activeState.agc.exposure,
-			     context_.activeState.agc.gain);
+	IPAFrameContext &frameContext = context_.frameContexts.get(frame);
+
+	ControlList ctrls(context_.sensorControls);
+	agc::prepareControls(ctrls, context_.camHelper.get(),
+			     frameContext.agc.exposure, frameContext.agc.gain);
 
 	ControlList lensCtrls(lensCtrls_);
 	lensCtrls.set(V4L2_CID_FOCUS_ABSOLUTE,