| Message ID | 20210818155403.268694-1-jeanmichel.hautbois@ideasonboard.com |
|---|---|
| Headers | show |
| Series |
|
| Related | show |
On 18/08/2021 16:53, Jean-Michel Hautbois wrote: > Introduce three functions in the Algorithm class to manage algorithms: > - configure which is called when IPA is configured only > - prepare called on EventFillParams event at each frame ... at each frame when the request is queued > - process called on EventStatReady event at each frame at each frame completion when the statistics have been generated. > As AGC already has a process function with different arguments, let's > temporarily disable the warnings from the compiler in this same commit. > It will be removed when AGC will be fully modular. I'd write that paragraph as: """ The existing AGC implementation already has a function named process(), though it has different arguments. Adding the new virtual process() interface causes a compiler warning due to the AGC implementation overloading a virtual function, even though the overload can be resolved correctly. Temporarily disable the warning in this commit to maintain bisection until the AGC is converted to the new interface. """ > Signed-off-by: Jean-Michel Hautbois <jeanmichel.hautbois@ideasonboard.com> > --- > meson.build | 4 +++ > src/ipa/ipu3/algorithms/algorithm.cpp | 46 +++++++++++++++++++++++++++ > src/ipa/ipu3/algorithms/algorithm.h | 9 ++++++ > 3 files changed, 59 insertions(+) > > diff --git a/meson.build b/meson.build > index a49c484f..4a10e2b6 100644 > --- a/meson.build > +++ b/meson.build > @@ -108,6 +108,10 @@ if cc.has_argument('-Wno-c99-designator') > ] > endif > > +# Do not warn when a function declaration hides virtual functions from > +# a base class > +cpp_arguments += '-Wno-overloaded-virtual' > + > c_arguments += common_arguments > cpp_arguments += common_arguments > > diff --git a/src/ipa/ipu3/algorithms/algorithm.cpp b/src/ipa/ipu3/algorithms/algorithm.cpp > index 325d34f0..d43a0e90 100644 > --- a/src/ipa/ipu3/algorithms/algorithm.cpp > +++ b/src/ipa/ipu3/algorithms/algorithm.cpp > @@ -25,6 +25,52 @@ namespace ipa::ipu3 { > * to manage algorithms regardless of their specific type. > */ > > +/** > + * \param[in] context The IPAContext structure reference Should be updated the same as prepare below. > + * \param[in] configInfo The IPAConfigInfo structure reference > + * \return 0 if sucess, an error code otherwise s/sucess/successful/ > + * > + * \brief Sets the IPAconfiguration to the proper values based on the /IPAconfiguration/IPAConfiguration provided by the IPAContext/ But this isn't just about 'setting values in the IPAConfiguration'... """ \brief Configure the Algorithm given an IPAConfigInfo Algorithms may implement a configure operation to pre-calculate parameters prior to commencing streaming. Configuration state may be stored in the IPAConfiguration structure of the IPAContext. """ > + * IPAConfigInfo values. > + * > + * It is called one time when IPA is configured. It is meant to prepare everything > + * needed by the algorithms for their calculations. > + */ > +int Algorithm::configure([[maybe_unused]] IPAContext &context, [[maybe_unused]] const IPAConfigInfo &configInfo) > +{ > + return 0; > +} > + > +/** > + * \param[in] context The IPAContext structure reference Should this be inout? I'm not entirely certain. I'd probably just list it as "The shared IPA context" or "The global IPA context" ? > + * \param[in] params The parameters structure reference to fill \param[out] params The IPU3 specific parameters. > + * > + * \brief Fill the parameter buffer with the updated context values > + * > + * While streaming, an EventFillParams event is received from the pipeline handler. > + * The algorithms should then fill the parameter structure with any updated value > + * they have calculated before the IPA passes it back to the ISP. """ While streaming, the IPA will configure the IPU3 IMGU through it's parameter structure. Algorithms shall fill in the parameter structure fields appropriately to configure algorithm blocks that they are responsible for. The structure should be updated to set the enable fields and use flags of any algorithms they are responsible for. """ > + */ > +void Algorithm::prepare([[maybe_unused]] IPAContext &context, [[maybe_unused]] ipu3_uapi_params ¶ms) > +{ > +} > + > +/** > + * \param[in] context The IPAContext structure reference Same as the usage in prepare, however you chose to update that one. > + * \param[in] stats The statistics structure to use \param[in] stats The IPU3 statistics and ISP results > + * > + * \brief Fill the context buffer using the received statistics buffer \brief Process ISP statistics, and run algorithm operations. > + * > + * While streaming, an EventStatReady event is received from the pipeline handler. > + * The algorithms can then use the statistics buffer received to update their > + * internal state. This state can be shared with other algorithms through the > + * context->frameContext structure. """ While streaming, the IPA will receive the generated statistics from the IPU3 IMGU of processed frames. Algorithms shall use this data to run calculations and update their state accordingly. Processing shall not take an undue amount of time, and any extended or computationally expensive calculations or operations must be handled asynchronously in a separate thread. Algorithms can store state in their respective IPAFrameContext structures, and reference state from the IPAFrameContext of other algorithms. \todo Historical data may be required as part of the processing. Either the previous frame, or the IPAFrameContext state of the frame that generated the statistics for this operation may be required for some advanced algorithms to prevent oscillations or support control loops correctly. Only a single IPAFrameContext is available currently, and so any data stored may represent the results of the previously completed operations. Care shall be taken to ensure the ordering of access to the information such that the algorithms use up to date state as required. """ > + */ > +void Algorithm::process([[maybe_unused]] IPAContext &context, [[maybe_unused]] const ipu3_uapi_stats_3a *stats) > +{ > +} > + > } /* namespace ipa::ipu3 */ > > } /* namespace libcamera */ > + > diff --git a/src/ipa/ipu3/algorithms/algorithm.h b/src/ipa/ipu3/algorithms/algorithm.h > index 072f01c4..bd1f923d 100644 > --- a/src/ipa/ipu3/algorithms/algorithm.h > +++ b/src/ipa/ipu3/algorithms/algorithm.h > @@ -7,6 +7,9 @@ > #ifndef __LIBCAMERA_IPA_IPU3_ALGORITHM_H__ > #define __LIBCAMERA_IPA_IPU3_ALGORITHM_H__ > > +#include <libcamera/ipa/ipu3_ipa_interface.h> > + > +#include "ipa_context.h" > namespace libcamera { > > namespace ipa::ipu3 { > @@ -15,6 +18,12 @@ class Algorithm > { > public: > virtual ~Algorithm() {} > + > + virtual int configure(IPAContext &context, const IPAConfigInfo &configInfo); > + > + virtual void prepare(IPAContext &context, ipu3_uapi_params ¶ms); > + > + virtual void process(IPAContext &context, const ipu3_uapi_stats_3a *stats); How is the params able to be passed as a reference, while the stats is a pointer ... Can/should they both be the same? (Can stats be passed by reference? or is it already a pointer, and if so - shouldn't params be the same?, or vice-versa) > }; > > } /* namespace ipa::ipu3 */ >
Hi Jean-Michel, Thank you for the patch. On Wed, Aug 18, 2021 at 05:54:01PM +0200, Jean-Michel Hautbois wrote: > In preparation for using the AGC through the new algorithm interfaces, > convert the existing code to use the new function types. > > Now that the process call is rewritten, re-enable the compiler flag to > warn when a function declaration hides virtual functions from a base class > (-Woverloaded-virtual). > > We never use converged_ so remove its declaration. > The controls may not need to be updated at each call, but it should be > decided on the context side and not by a specific call by using a lock > status in the Agc structure for instance. > > Signed-off-by: Jean-Michel Hautbois <jeanmichel.hautbois@ideasonboard.com> > Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com> > --- > meson.build | 4 ---- > src/ipa/ipu3/ipu3.cpp | 8 +++----- > src/ipa/ipu3/ipu3_agc.cpp | 19 +++++++------------ > src/ipa/ipu3/ipu3_agc.h | 9 ++------- > 4 files changed, 12 insertions(+), 28 deletions(-) > > diff --git a/meson.build b/meson.build > index 4a10e2b6..a49c484f 100644 > --- a/meson.build > +++ b/meson.build > @@ -108,10 +108,6 @@ if cc.has_argument('-Wno-c99-designator') > ] > endif > > -# Do not warn when a function declaration hides virtual functions from > -# a base class > -cpp_arguments += '-Wno-overloaded-virtual' > - > c_arguments += common_arguments > cpp_arguments += common_arguments > > diff --git a/src/ipa/ipu3/ipu3.cpp b/src/ipa/ipu3/ipu3.cpp > index 2b4a4c8c..423cc957 100644 > --- a/src/ipa/ipu3/ipu3.cpp > +++ b/src/ipa/ipu3/ipu3.cpp > @@ -341,7 +341,7 @@ int IPAIPU3::configure(const IPAConfigInfo &configInfo) > awbAlgo_ = std::make_unique<IPU3Awb>(); > > agcAlgo_ = std::make_unique<IPU3Agc>(); > - agcAlgo_->initialise(context_.configuration.grid.bdsGrid, sensorInfo_); > + agcAlgo_->configure(context_, configInfo); > > return 0; > } > @@ -418,8 +418,7 @@ void IPAIPU3::fillParams(unsigned int frame, ipu3_uapi_params *params) > for (auto const &algo : algorithms_) > algo->prepare(context_, params_); > > - if (agcAlgo_->updateControls()) > - awbAlgo_->prepare(context_, params_); > + awbAlgo_->prepare(context_, params_); > > *params = params_; > > @@ -447,8 +446,7 @@ void IPAIPU3::parseStatistics(unsigned int frame, > > awbAlgo_->process(context_, stats); > > - if (agcAlgo_->updateControls()) > - setControls(frame); > + setControls(frame); > > /* \todo Use VBlank value calculated from each frame exposure. */ > int64_t frameDuration = sensorInfo_.lineLength * (defVBlank_ + sensorInfo_.outputSize.height) / > diff --git a/src/ipa/ipu3/ipu3_agc.cpp b/src/ipa/ipu3/ipu3_agc.cpp > index c6782ff4..1c1f5fb5 100644 > --- a/src/ipa/ipu3/ipu3_agc.cpp > +++ b/src/ipa/ipu3/ipu3_agc.cpp > @@ -51,20 +51,20 @@ static constexpr double kEvGainTarget = 0.5; > static constexpr uint8_t kCellSize = 8; > > IPU3Agc::IPU3Agc() > - : frameCount_(0), lastFrame_(0), converged_(false), > - updateControls_(false), iqMean_(0.0), > - lineDuration_(0s), maxExposureTime_(0s), > - prevExposure_(0s), prevExposureNoDg_(0s), > + : frameCount_(0), lastFrame_(0), iqMean_(0.0), lineDuration_(0s), > + maxExposureTime_(0s), prevExposure_(0s), prevExposureNoDg_(0s), > currentExposure_(0s), currentExposureNoDg_(0s) > { > } > > -void IPU3Agc::initialise(struct ipu3_uapi_grid_config &bdsGrid, const IPACameraSensorInfo &sensorInfo) > +int IPU3Agc::configure(IPAContext &context, const IPAConfigInfo &configInfo) > { > - aeGrid_ = bdsGrid; > + aeGrid_ = context.configuration.grid.bdsGrid; Do we need to keep a copy of the grid, can't we git it from the context when needed ? It doesn't have to be addressed in this patch, could be done on top if easier. > > - lineDuration_ = sensorInfo.lineLength * 1.0s / sensorInfo.pixelRate; > + lineDuration_ = configInfo.sensorInfo.lineLength * 1.0s / configInfo.sensorInfo.pixelRate; Line wrap again :-) Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> > maxExposureTime_ = kMaxExposure * lineDuration_; > + > + return 0; > } > > void IPU3Agc::processBrightness(const ipu3_uapi_stats_3a *stats) > @@ -144,8 +144,6 @@ void IPU3Agc::filterExposure() > > void IPU3Agc::lockExposureGain(uint32_t &exposure, double &gain) > { > - updateControls_ = false; > - > /* Algorithm initialization should wait for first valid frames */ > /* \todo - have a number of frames given by DelayedControls ? > * - implement a function for IIR */ > @@ -155,7 +153,6 @@ void IPU3Agc::lockExposureGain(uint32_t &exposure, double &gain) > /* Are we correctly exposed ? */ > if (std::abs(iqMean_ - kEvGainTarget * knumHistogramBins) <= 1) { > LOG(IPU3Agc, Debug) << "!!! Good exposure with iqMean = " << iqMean_; > - converged_ = true; > } else { > double newGain = kEvGainTarget * knumHistogramBins / iqMean_; > > @@ -178,12 +175,10 @@ void IPU3Agc::lockExposureGain(uint32_t &exposure, double &gain) > exposure = std::clamp(static_cast<uint32_t>(exposure * currentExposure_ / currentExposureNoDg_), kMinExposure, kMaxExposure); > newExposure = currentExposure_ / exposure; > gain = std::clamp(static_cast<uint32_t>(gain * currentExposure_ / newExposure), kMinGain, kMaxGain); > - updateControls_ = true; > } else if (currentShutter >= maxExposureTime_) { > gain = std::clamp(static_cast<uint32_t>(gain * currentExposure_ / currentExposureNoDg_), kMinGain, kMaxGain); > newExposure = currentExposure_ / gain; > exposure = std::clamp(static_cast<uint32_t>(exposure * currentExposure_ / newExposure), kMinExposure, kMaxExposure); > - updateControls_ = true; > } > LOG(IPU3Agc, Debug) << "Adjust exposure " << exposure * lineDuration_ << " and gain " << gain; > } > diff --git a/src/ipa/ipu3/ipu3_agc.h b/src/ipa/ipu3/ipu3_agc.h > index f8290abd..0e922664 100644 > --- a/src/ipa/ipu3/ipu3_agc.h > +++ b/src/ipa/ipu3/ipu3_agc.h > @@ -29,10 +29,8 @@ public: > IPU3Agc(); > ~IPU3Agc() = default; > > - void initialise(struct ipu3_uapi_grid_config &bdsGrid, const IPACameraSensorInfo &sensorInfo); > - void process(IPAContext &context, const ipu3_uapi_stats_3a *stats); > - bool converged() { return converged_; } > - bool updateControls() { return updateControls_; } > + int configure(IPAContext &context, const IPAConfigInfo &configInfo) override; > + void process(IPAContext &context, const ipu3_uapi_stats_3a *stats) override; > > private: > void processBrightness(const ipu3_uapi_stats_3a *stats); > @@ -44,9 +42,6 @@ private: > uint64_t frameCount_; > uint64_t lastFrame_; > > - bool converged_; > - bool updateControls_; > - > double iqMean_; > > Duration lineDuration_;
This patch series splits the algorithms in IPU3 into a modular form. When the Metadata class was discussed a proposal from Kieran was to have a fully-defined structure which would be used to pass the context between algorithms and the IPAIPU3 class, as well as between the algorithms themselves. The algorithms are statically emplaced in a list for the moment, and a registration system may be used later. In order to demonstrate how to add a new algorithm, patch 5/9 moves the contrast algorithm from AWB into its own algorithm. Patch 6/9 and 7/9 change the AWB and AGC to use the new interface. And the two latest patches are indeed the usage of the new modular interface applied to AWB and AGC. Jean-Michel Hautbois (9): ipa: move libipa::Algorithm to ipa/ipu3/algorithms ipa: ipu3: Introduce a Context structure ipa: ipu3: Add the functions to the Algorithm class ipa: ipu3: Introduce modular algorithm ipa: ipu3: Introduce a modular contrast algorithm ipa: ipu3: convert AWB to the new algorithm interface ipa: ipu3: convert AGC to the new algorithm interface ipa: ipu3: Move IPU3 awb into algorithms ipa: ipu3: Move IPU3 agc into algorithms .../ipu3/{ipu3_agc.cpp => algorithms/agc.cpp} | 39 ++-- src/ipa/ipu3/{ipu3_agc.h => algorithms/agc.h} | 32 ++-- src/ipa/ipu3/algorithms/algorithm.cpp | 76 ++++++++ src/ipa/ipu3/algorithms/algorithm.h | 33 ++++ .../ipu3/{ipu3_awb.cpp => algorithms/awb.cpp} | 168 +++++++----------- src/ipa/ipu3/{ipu3_awb.h => algorithms/awb.h} | 26 +-- src/ipa/ipu3/algorithms/contrast.cpp | 53 ++++++ src/ipa/ipu3/algorithms/contrast.h | 32 ++++ src/ipa/ipu3/algorithms/meson.build | 8 + src/ipa/ipu3/ipa_context.h | 54 ++++++ src/ipa/ipu3/ipu3.cpp | 124 +++++++++---- src/ipa/ipu3/meson.build | 6 +- src/ipa/libipa/algorithm.cpp | 39 ---- src/ipa/libipa/algorithm.h | 24 --- src/ipa/libipa/libipa.cpp | 22 +++ src/ipa/libipa/meson.build | 5 +- 16 files changed, 484 insertions(+), 257 deletions(-) rename src/ipa/ipu3/{ipu3_agc.cpp => algorithms/agc.cpp} (88%) rename src/ipa/ipu3/{ipu3_agc.h => algorithms/agc.h} (51%) create mode 100644 src/ipa/ipu3/algorithms/algorithm.cpp create mode 100644 src/ipa/ipu3/algorithms/algorithm.h rename src/ipa/ipu3/{ipu3_awb.cpp => algorithms/awb.cpp} (71%) rename src/ipa/ipu3/{ipu3_awb.h => algorithms/awb.h} (77%) create mode 100644 src/ipa/ipu3/algorithms/contrast.cpp create mode 100644 src/ipa/ipu3/algorithms/contrast.h create mode 100644 src/ipa/ipu3/algorithms/meson.build create mode 100644 src/ipa/ipu3/ipa_context.h delete mode 100644 src/ipa/libipa/algorithm.cpp delete mode 100644 src/ipa/libipa/algorithm.h create mode 100644 src/ipa/libipa/libipa.cpp