| Message ID | 20260810103846.1075936-33-barnabas.pocze@ideasonboard.com |
|---|---|
| State | New |
| Headers | show |
| Series |
|
| Related | show |
On Mon, Aug 10, 2026 at 12:38:28PM +0200, Barnabás Pőcze wrote: > Use the `AgcAlgorithm` class to implement the ipu3 agc algorithm. > > Signed-off-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com> > --- > src/ipa/ipu3/algorithms/agc.cpp | 108 ++++++++++--------------- > src/ipa/ipu3/algorithms/agc.h | 15 ++-- > src/ipa/ipu3/ipa_context.cpp | 49 +++--------- > src/ipa/ipu3/ipa_context.h | 27 +++---- > src/ipa/ipu3/ipu3.cpp | 136 +++++--------------------------- > 5 files changed, 92 insertions(+), 243 deletions(-) > > diff --git a/src/ipa/ipu3/algorithms/agc.cpp b/src/ipa/ipu3/algorithms/agc.cpp > index e74db62960..91923c7f70 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) > { > } > > @@ -76,11 +68,18 @@ int Agc::init(IPAContext &context, const ValueNode &tuningData) > { > int ret; > > - ret = agc_.parseTuningData(tuningData); > + ret = agc_.init(tuningData); > if (ret) > return ret; > > - context.ctrlMap.merge(agc_.controls()); > + ret = agc_.configure(context.configuration.agc, context.activeState.agc, { > + .sensor = context.camHelper.get(), > + .sensorInfo = context.sensorInfo, > + .sensorControls = context.sensorControls, > + .ctrlMap = context.ctrlMap, > + }); > + if (ret) > + return ret; > > return 0; > } > @@ -95,32 +94,36 @@ 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, > + .autoAllowed = true, // \todo if not raw? > + }); > +} > > - /* \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.configuration.agc, context.activeState.agc, frameContext.agc); > } > > Histogram Agc::parseStatistics(const ipu3_uapi_stats_3a *stats, > @@ -228,16 +231,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 +242,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..51133b10d5 100644 > --- a/src/ipa/ipu3/ipa_context.h > +++ b/src/ipa/ipu3/ipa_context.h > @@ -15,6 +15,8 @@ > #include <libcamera/controls.h> > #include <libcamera/geometry.h> > > +#include <libipa/agc.h> > +#include <libipa/camera_sensor_helper.h> > #include <libipa/fc_queue.h> > > namespace libcamera { > @@ -32,18 +34,8 @@ struct IPASessionConfiguration { > ipu3_uapi_grid_config afGrid; > } af; > > - struct { > - utils::Duration minExposureTime; > - utils::Duration maxExposureTime; > - double minAnalogueGain; > - double maxAnalogueGain; > + struct Agc : agc::Session { > } agc; > - > - struct { > - int32_t defVBlank; > - utils::Duration lineDuration; > - Size size; > - } sensor; > }; > > struct IPAActiveState { > @@ -53,11 +45,7 @@ struct IPAActiveState { > bool stable; > } af; > > - struct { > - uint32_t exposure; > - double gain; > - uint32_t constraintMode; > - uint32_t exposureMode; > + struct Agc : agc::ActiveState { > } agc; > > struct { > @@ -81,6 +69,9 @@ struct IPAFrameContext : public FrameContext { > uint32_t exposure; > double gain; > } sensor; > + > + struct Agc : agc::FrameContext { > + } agc; > }; > > struct IPAContext { > @@ -90,10 +81,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 b7897269bb..d1c69fa4cc 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); The code changes look good to me, but I would like to get some tested-by from Dan before getting this in: Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com> Thanks j > > ControlList lensCtrls(lensCtrls_); > lensCtrls.set(V4L2_CID_FOCUS_ABSOLUTE, > -- > 2.55.0 >
diff --git a/src/ipa/ipu3/algorithms/agc.cpp b/src/ipa/ipu3/algorithms/agc.cpp index e74db62960..91923c7f70 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) { } @@ -76,11 +68,18 @@ int Agc::init(IPAContext &context, const ValueNode &tuningData) { int ret; - ret = agc_.parseTuningData(tuningData); + ret = agc_.init(tuningData); if (ret) return ret; - context.ctrlMap.merge(agc_.controls()); + ret = agc_.configure(context.configuration.agc, context.activeState.agc, { + .sensor = context.camHelper.get(), + .sensorInfo = context.sensorInfo, + .sensorControls = context.sensorControls, + .ctrlMap = context.ctrlMap, + }); + if (ret) + return ret; return 0; } @@ -95,32 +94,36 @@ 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, + .autoAllowed = true, // \todo if not raw? + }); +} - /* \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.configuration.agc, context.activeState.agc, frameContext.agc); } Histogram Agc::parseStatistics(const ipu3_uapi_stats_3a *stats, @@ -228,16 +231,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 +242,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..51133b10d5 100644 --- a/src/ipa/ipu3/ipa_context.h +++ b/src/ipa/ipu3/ipa_context.h @@ -15,6 +15,8 @@ #include <libcamera/controls.h> #include <libcamera/geometry.h> +#include <libipa/agc.h> +#include <libipa/camera_sensor_helper.h> #include <libipa/fc_queue.h> namespace libcamera { @@ -32,18 +34,8 @@ struct IPASessionConfiguration { ipu3_uapi_grid_config afGrid; } af; - struct { - utils::Duration minExposureTime; - utils::Duration maxExposureTime; - double minAnalogueGain; - double maxAnalogueGain; + struct Agc : agc::Session { } agc; - - struct { - int32_t defVBlank; - utils::Duration lineDuration; - Size size; - } sensor; }; struct IPAActiveState { @@ -53,11 +45,7 @@ struct IPAActiveState { bool stable; } af; - struct { - uint32_t exposure; - double gain; - uint32_t constraintMode; - uint32_t exposureMode; + struct Agc : agc::ActiveState { } agc; struct { @@ -81,6 +69,9 @@ struct IPAFrameContext : public FrameContext { uint32_t exposure; double gain; } sensor; + + struct Agc : agc::FrameContext { + } agc; }; struct IPAContext { @@ -90,10 +81,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 b7897269bb..d1c69fa4cc 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,
Use the `AgcAlgorithm` class to implement the ipu3 agc algorithm. Signed-off-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com> --- src/ipa/ipu3/algorithms/agc.cpp | 108 ++++++++++--------------- src/ipa/ipu3/algorithms/agc.h | 15 ++-- src/ipa/ipu3/ipa_context.cpp | 49 +++--------- src/ipa/ipu3/ipa_context.h | 27 +++---- src/ipa/ipu3/ipu3.cpp | 136 +++++--------------------------- 5 files changed, 92 insertions(+), 243 deletions(-)