| Message ID | 20260623-libipa-algorithms-v2-6-f97433f12e4e@ideasonboard.com |
|---|---|
| State | Superseded |
| Headers | show |
| Series |
|
| Related | show |
Quoting Jacopo Mondi (2026-06-23 14:55:01) > From: Kieran Bingham <kieran.bingham@ideasonboard.com> > Hello apparently me?! I don't actually remember writing this patch anymore, so does that make me viable to review it ? > Now that libipa provides a common CCM algorithm implementation, > replace the custom handling with the common Ccm. > > Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com> > Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com> > --- > src/ipa/simple/algorithms/ccm.cpp | 69 +++++++++++++++++++++------------------ > src/ipa/simple/algorithms/ccm.h | 23 ++++++++----- > src/ipa/simple/ipa_context.h | 5 +-- > 3 files changed, 55 insertions(+), 42 deletions(-) > > diff --git a/src/ipa/simple/algorithms/ccm.cpp b/src/ipa/simple/algorithms/ccm.cpp > index ff37c718c6e4..6cf55bd93db0 100644 > --- a/src/ipa/simple/algorithms/ccm.cpp > +++ b/src/ipa/simple/algorithms/ccm.cpp > @@ -8,54 +8,61 @@ > > #include "ccm.h" > > -#include <libcamera/base/log.h> > -#include <libcamera/base/utils.h> > - > -#include <libcamera/control_ids.h> > - > #include "libcamera/internal/matrix.h" > > -namespace { > - > -constexpr unsigned int kTemperatureThreshold = 100; > - > -} > - > namespace libcamera { > > namespace ipa::soft::algorithms { > > LOG_DEFINE_CATEGORY(IPASoftCcm) > > +/** > + * \copydoc libcamera::ipa::Algorithm::init > + */ > int Ccm::init([[maybe_unused]] IPAContext &context, const ValueNode &tuningData) > { > - int ret = ccm_.readYaml(tuningData["ccms"], "ct", "ccm"); > - if (ret < 0) { > - LOG(IPASoftCcm, Error) > - << "Failed to parse 'ccm' parameter from tuning file."; > - return ret; > - } > + return ccmAlgo_.init(tuningData, context.ctrlMap); > +} > + > +/** > + * \copydoc libcamera::ipa::Algorithm::configure > + */ > +int Ccm::configure(IPAContext &context, > + [[maybe_unused]] const IPAConfigInfo &configInfo) > +{ > + return ccmAlgo_.configure(context.activeState.ccm, > + context.activeState.awb.automatic.temperatureK); > +} > > - context.ccmEnabled = true; > +/** > + * \copydoc libcamera::ipa::Algorithm::queueRequest > + */ > +void Ccm::queueRequest(IPAContext &context, > + [[maybe_unused]] const uint32_t frame, > + IPAFrameContext &frameContext, > + const ControlList &controls) > +{ > + /* Nothing to do here, the ccm will be calculated in prepare() */ > + if (frameContext.awb.autoEnabled) > + return; > > - return 0; > + ccmAlgo_.queueRequest(context.activeState.ccm, frameContext.ccm, controls); > } > > void Ccm::prepare(IPAContext &context, [[maybe_unused]] const uint32_t frame, > IPAFrameContext &frameContext, [[maybe_unused]] DebayerParams *params) > { > - const unsigned int ct = frameContext.awb.temperatureK; > - > - /* Change CCM only on bigger temperature changes. */ > - if (!currentCcm_ || > - utils::abs_diff(ct, lastCt_) >= kTemperatureThreshold) { > - currentCcm_ = ccm_.getInterpolated(ct); > - lastCt_ = ct; > - } > - > + if (frameContext.awb.autoEnabled) > + ccmAlgo_.prepare(context.activeState.ccm, frameContext.ccm, > + frame, frameContext.awb.temperatureK); > + > + /* > + * \todo: Split out combined matrix into individual parameters in > + * DebayerParams and perform any pre-multiplication combination in the > + * SoftISP component directly. > + */ Hrm, actually I remember writing this. anyway this all still looks sane, but I'll hold off a tag as it is my own code... Anyone else want to throw weight on this ? -- Kieran > context.activeState.combinedMatrix = > - currentCcm_.value() * context.activeState.combinedMatrix; > - frameContext.ccm = currentCcm_.value(); > + frameContext.ccm.ccm * context.activeState.combinedMatrix; > } > > void Ccm::process([[maybe_unused]] IPAContext &context, > @@ -64,7 +71,7 @@ void Ccm::process([[maybe_unused]] IPAContext &context, > [[maybe_unused]] const SwIspStats *stats, > ControlList &metadata) > { > - metadata.set(controls::ColourCorrectionMatrix, frameContext.ccm.data()); > + ccmAlgo_.process(frameContext.ccm, metadata); > } > > REGISTER_IPA_ALGORITHM(Ccm, "Ccm") > diff --git a/src/ipa/simple/algorithms/ccm.h b/src/ipa/simple/algorithms/ccm.h > index b20a7da8aa33..0d35347ea583 100644 > --- a/src/ipa/simple/algorithms/ccm.h > +++ b/src/ipa/simple/algorithms/ccm.h > @@ -7,13 +7,15 @@ > > #pragma once > > -#include <optional> > +#include <libcamera/controls.h> > > -#include "libcamera/internal/matrix.h" > +#include "libcamera/internal/value_node.h" > > -#include <libipa/interpolator.h> > +#include "libipa/ccm.h" > +#include "libipa/fixedpoint.h" > > #include "algorithm.h" > +#include "ipa_context.h" > > namespace libcamera { > > @@ -22,10 +24,15 @@ namespace ipa::soft::algorithms { > class Ccm : public Algorithm > { > public: > - Ccm() = default; > - ~Ccm() = default; > - > int init(IPAContext &context, const ValueNode &tuningData) override; > + > + int configure(IPAContext &context, const IPAConfigInfo &configInfo) override; > + > + void queueRequest(IPAContext &context, > + [[maybe_unused]] const uint32_t frame, > + IPAFrameContext &frameContext, > + const ControlList &controls) override; > + > void prepare(IPAContext &context, > const uint32_t frame, > IPAFrameContext &frameContext, > @@ -36,9 +43,7 @@ public: > ControlList &metadata) override; > > private: > - unsigned int lastCt_; > - Interpolator<Matrix<float, 3, 3>> ccm_; > - std::optional<Matrix<float, 3, 3>> currentCcm_; > + CcmAlgorithm<Q<4, 16>> ccmAlgo_; > }; > > } /* namespace ipa::soft::algorithms */ > diff --git a/src/ipa/simple/ipa_context.h b/src/ipa/simple/ipa_context.h > index 29643a655ce1..ff312ae8f4e7 100644 > --- a/src/ipa/simple/ipa_context.h > +++ b/src/ipa/simple/ipa_context.h > @@ -17,6 +17,7 @@ > #include "libcamera/internal/vector.h" > > #include <libipa/awb.h> > +#include <libipa/ccm.h> > #include <libipa/fc_queue.h> > > #include "core_ipa_interface.h" > @@ -38,6 +39,7 @@ struct IPASessionConfiguration { > > struct IPAActiveState { > ipa::awb::ActiveState awb; > + ipa::ccm::ActiveState ccm; > > struct { > int32_t exposure; > @@ -63,8 +65,7 @@ struct IPAActiveState { > > struct IPAFrameContext : public FrameContext { > ipa::awb::FrameContext awb; > - > - Matrix<float, 3, 3> ccm; > + ipa::ccm::FrameContext ccm; > > struct { > int32_t exposure; > > -- > 2.54.0 >
Quoting Kieran Bingham (2026-06-24 16:13:05) > Quoting Jacopo Mondi (2026-06-23 14:55:01) > > From: Kieran Bingham <kieran.bingham@ideasonboard.com> > > > > Hello apparently me?! > > I don't actually remember writing this patch anymore, so does that make > me viable to review it ? Hi you. This patch fails to account for context_.ccmEnabled! As such it causes the Saturation control to stop being initialised or utilised (which is processed through updating the CCM). Of course that should be split out separately somehow, but that's for later. For now - we'll need to keep setting ccmEnabled = true; during init() still. > > > Now that libipa provides a common CCM algorithm implementation, > > replace the custom handling with the common Ccm. > > > > Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com> > > Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com> > > --- > > src/ipa/simple/algorithms/ccm.cpp | 69 +++++++++++++++++++++------------------ > > src/ipa/simple/algorithms/ccm.h | 23 ++++++++----- > > src/ipa/simple/ipa_context.h | 5 +-- > > 3 files changed, 55 insertions(+), 42 deletions(-) > > > > diff --git a/src/ipa/simple/algorithms/ccm.cpp b/src/ipa/simple/algorithms/ccm.cpp > > index ff37c718c6e4..6cf55bd93db0 100644 > > --- a/src/ipa/simple/algorithms/ccm.cpp > > +++ b/src/ipa/simple/algorithms/ccm.cpp > > @@ -8,54 +8,61 @@ > > > > #include "ccm.h" > > > > -#include <libcamera/base/log.h> > > -#include <libcamera/base/utils.h> > > - > > -#include <libcamera/control_ids.h> > > - > > #include "libcamera/internal/matrix.h" > > > > -namespace { > > - > > -constexpr unsigned int kTemperatureThreshold = 100; > > - > > -} > > - > > namespace libcamera { > > > > namespace ipa::soft::algorithms { > > > > LOG_DEFINE_CATEGORY(IPASoftCcm) > > > > +/** > > + * \copydoc libcamera::ipa::Algorithm::init > > + */ > > int Ccm::init([[maybe_unused]] IPAContext &context, const ValueNode &tuningData) > > { > > - int ret = ccm_.readYaml(tuningData["ccms"], "ct", "ccm"); > > - if (ret < 0) { > > - LOG(IPASoftCcm, Error) > > - << "Failed to parse 'ccm' parameter from tuning file."; > > - return ret; > > - } > > + return ccmAlgo_.init(tuningData, context.ctrlMap); > > +} > > + > > +/** > > + * \copydoc libcamera::ipa::Algorithm::configure > > + */ > > +int Ccm::configure(IPAContext &context, > > + [[maybe_unused]] const IPAConfigInfo &configInfo) > > +{ > > + return ccmAlgo_.configure(context.activeState.ccm, > > + context.activeState.awb.automatic.temperatureK); > > +} > > > > - context.ccmEnabled = true; Setting this is what enables the Saturation control somehow it seems. This should go before the return statement of course, if there's a failure - it won't matter as the IPA will fail to load, but continuing to set the flag will keep Saturation controls working until that gets reworked and split out of the combined matrix. The following fixup could be applied to this patch: diff --git a/src/ipa/simple/algorithms/ccm.cpp b/src/ipa/simple/algorithms/ccm.cpp index 6cf55bd93db0..e0cbd453e32f 100644 --- a/src/ipa/simple/algorithms/ccm.cpp +++ b/src/ipa/simple/algorithms/ccm.cpp @@ -21,6 +21,9 @@ LOG_DEFINE_CATEGORY(IPASoftCcm) */ int Ccm::init([[maybe_unused]] IPAContext &context, const ValueNode &tuningData) { + /* Informs the 'adjust' component that CCM is available to apply Saturation */ + context.ccmEnabled = true; + return ccmAlgo_.init(tuningData, context.ctrlMap); } -- Kieran > > +/** > > + * \copydoc libcamera::ipa::Algorithm::queueRequest > > + */ > > +void Ccm::queueRequest(IPAContext &context, > > + [[maybe_unused]] const uint32_t frame, > > + IPAFrameContext &frameContext, > > + const ControlList &controls) > > +{ > > + /* Nothing to do here, the ccm will be calculated in prepare() */ > > + if (frameContext.awb.autoEnabled) > > + return; > > > > - return 0; > > + ccmAlgo_.queueRequest(context.activeState.ccm, frameContext.ccm, controls); > > } > > > > void Ccm::prepare(IPAContext &context, [[maybe_unused]] const uint32_t frame, > > IPAFrameContext &frameContext, [[maybe_unused]] DebayerParams *params) > > { > > - const unsigned int ct = frameContext.awb.temperatureK; > > - > > - /* Change CCM only on bigger temperature changes. */ > > - if (!currentCcm_ || > > - utils::abs_diff(ct, lastCt_) >= kTemperatureThreshold) { > > - currentCcm_ = ccm_.getInterpolated(ct); > > - lastCt_ = ct; > > - } > > - > > + if (frameContext.awb.autoEnabled) > > + ccmAlgo_.prepare(context.activeState.ccm, frameContext.ccm, > > + frame, frameContext.awb.temperatureK); > > + > > + /* > > + * \todo: Split out combined matrix into individual parameters in > > + * DebayerParams and perform any pre-multiplication combination in the > > + * SoftISP component directly. > > + */ > > Hrm, actually I remember writing this. > > anyway this all still looks sane, but I'll hold off a tag as it is my > own code... > > Anyone else want to throw weight on this ? > > -- > Kieran > > > > context.activeState.combinedMatrix = > > - currentCcm_.value() * context.activeState.combinedMatrix; > > - frameContext.ccm = currentCcm_.value(); > > + frameContext.ccm.ccm * context.activeState.combinedMatrix; > > } > > > > void Ccm::process([[maybe_unused]] IPAContext &context, > > @@ -64,7 +71,7 @@ void Ccm::process([[maybe_unused]] IPAContext &context, > > [[maybe_unused]] const SwIspStats *stats, > > ControlList &metadata) > > { > > - metadata.set(controls::ColourCorrectionMatrix, frameContext.ccm.data()); > > + ccmAlgo_.process(frameContext.ccm, metadata); > > } > > > > REGISTER_IPA_ALGORITHM(Ccm, "Ccm") > > diff --git a/src/ipa/simple/algorithms/ccm.h b/src/ipa/simple/algorithms/ccm.h > > index b20a7da8aa33..0d35347ea583 100644 > > --- a/src/ipa/simple/algorithms/ccm.h > > +++ b/src/ipa/simple/algorithms/ccm.h > > @@ -7,13 +7,15 @@ > > > > #pragma once > > > > -#include <optional> > > +#include <libcamera/controls.h> > > > > -#include "libcamera/internal/matrix.h" > > +#include "libcamera/internal/value_node.h" > > > > -#include <libipa/interpolator.h> > > +#include "libipa/ccm.h" > > +#include "libipa/fixedpoint.h" > > > > #include "algorithm.h" > > +#include "ipa_context.h" > > > > namespace libcamera { > > > > @@ -22,10 +24,15 @@ namespace ipa::soft::algorithms { > > class Ccm : public Algorithm > > { > > public: > > - Ccm() = default; > > - ~Ccm() = default; > > - > > int init(IPAContext &context, const ValueNode &tuningData) override; > > + > > + int configure(IPAContext &context, const IPAConfigInfo &configInfo) override; > > + > > + void queueRequest(IPAContext &context, > > + [[maybe_unused]] const uint32_t frame, > > + IPAFrameContext &frameContext, > > + const ControlList &controls) override; > > + > > void prepare(IPAContext &context, > > const uint32_t frame, > > IPAFrameContext &frameContext, > > @@ -36,9 +43,7 @@ public: > > ControlList &metadata) override; > > > > private: > > - unsigned int lastCt_; > > - Interpolator<Matrix<float, 3, 3>> ccm_; > > - std::optional<Matrix<float, 3, 3>> currentCcm_; > > + CcmAlgorithm<Q<4, 16>> ccmAlgo_; > > }; > > > > } /* namespace ipa::soft::algorithms */ > > diff --git a/src/ipa/simple/ipa_context.h b/src/ipa/simple/ipa_context.h > > index 29643a655ce1..ff312ae8f4e7 100644 > > --- a/src/ipa/simple/ipa_context.h > > +++ b/src/ipa/simple/ipa_context.h > > @@ -17,6 +17,7 @@ > > #include "libcamera/internal/vector.h" > > > > #include <libipa/awb.h> > > +#include <libipa/ccm.h> > > #include <libipa/fc_queue.h> > > > > #include "core_ipa_interface.h" > > @@ -38,6 +39,7 @@ struct IPASessionConfiguration { > > > > struct IPAActiveState { > > ipa::awb::ActiveState awb; > > + ipa::ccm::ActiveState ccm; > > > > struct { > > int32_t exposure; > > @@ -63,8 +65,7 @@ struct IPAActiveState { > > > > struct IPAFrameContext : public FrameContext { > > ipa::awb::FrameContext awb; > > - > > - Matrix<float, 3, 3> ccm; > > + ipa::ccm::FrameContext ccm; > > > > struct { > > int32_t exposure; > > > > -- > > 2.54.0 > >
diff --git a/src/ipa/simple/algorithms/ccm.cpp b/src/ipa/simple/algorithms/ccm.cpp index ff37c718c6e4..6cf55bd93db0 100644 --- a/src/ipa/simple/algorithms/ccm.cpp +++ b/src/ipa/simple/algorithms/ccm.cpp @@ -8,54 +8,61 @@ #include "ccm.h" -#include <libcamera/base/log.h> -#include <libcamera/base/utils.h> - -#include <libcamera/control_ids.h> - #include "libcamera/internal/matrix.h" -namespace { - -constexpr unsigned int kTemperatureThreshold = 100; - -} - namespace libcamera { namespace ipa::soft::algorithms { LOG_DEFINE_CATEGORY(IPASoftCcm) +/** + * \copydoc libcamera::ipa::Algorithm::init + */ int Ccm::init([[maybe_unused]] IPAContext &context, const ValueNode &tuningData) { - int ret = ccm_.readYaml(tuningData["ccms"], "ct", "ccm"); - if (ret < 0) { - LOG(IPASoftCcm, Error) - << "Failed to parse 'ccm' parameter from tuning file."; - return ret; - } + return ccmAlgo_.init(tuningData, context.ctrlMap); +} + +/** + * \copydoc libcamera::ipa::Algorithm::configure + */ +int Ccm::configure(IPAContext &context, + [[maybe_unused]] const IPAConfigInfo &configInfo) +{ + return ccmAlgo_.configure(context.activeState.ccm, + context.activeState.awb.automatic.temperatureK); +} - context.ccmEnabled = true; +/** + * \copydoc libcamera::ipa::Algorithm::queueRequest + */ +void Ccm::queueRequest(IPAContext &context, + [[maybe_unused]] const uint32_t frame, + IPAFrameContext &frameContext, + const ControlList &controls) +{ + /* Nothing to do here, the ccm will be calculated in prepare() */ + if (frameContext.awb.autoEnabled) + return; - return 0; + ccmAlgo_.queueRequest(context.activeState.ccm, frameContext.ccm, controls); } void Ccm::prepare(IPAContext &context, [[maybe_unused]] const uint32_t frame, IPAFrameContext &frameContext, [[maybe_unused]] DebayerParams *params) { - const unsigned int ct = frameContext.awb.temperatureK; - - /* Change CCM only on bigger temperature changes. */ - if (!currentCcm_ || - utils::abs_diff(ct, lastCt_) >= kTemperatureThreshold) { - currentCcm_ = ccm_.getInterpolated(ct); - lastCt_ = ct; - } - + if (frameContext.awb.autoEnabled) + ccmAlgo_.prepare(context.activeState.ccm, frameContext.ccm, + frame, frameContext.awb.temperatureK); + + /* + * \todo: Split out combined matrix into individual parameters in + * DebayerParams and perform any pre-multiplication combination in the + * SoftISP component directly. + */ context.activeState.combinedMatrix = - currentCcm_.value() * context.activeState.combinedMatrix; - frameContext.ccm = currentCcm_.value(); + frameContext.ccm.ccm * context.activeState.combinedMatrix; } void Ccm::process([[maybe_unused]] IPAContext &context, @@ -64,7 +71,7 @@ void Ccm::process([[maybe_unused]] IPAContext &context, [[maybe_unused]] const SwIspStats *stats, ControlList &metadata) { - metadata.set(controls::ColourCorrectionMatrix, frameContext.ccm.data()); + ccmAlgo_.process(frameContext.ccm, metadata); } REGISTER_IPA_ALGORITHM(Ccm, "Ccm") diff --git a/src/ipa/simple/algorithms/ccm.h b/src/ipa/simple/algorithms/ccm.h index b20a7da8aa33..0d35347ea583 100644 --- a/src/ipa/simple/algorithms/ccm.h +++ b/src/ipa/simple/algorithms/ccm.h @@ -7,13 +7,15 @@ #pragma once -#include <optional> +#include <libcamera/controls.h> -#include "libcamera/internal/matrix.h" +#include "libcamera/internal/value_node.h" -#include <libipa/interpolator.h> +#include "libipa/ccm.h" +#include "libipa/fixedpoint.h" #include "algorithm.h" +#include "ipa_context.h" namespace libcamera { @@ -22,10 +24,15 @@ namespace ipa::soft::algorithms { class Ccm : public Algorithm { public: - Ccm() = default; - ~Ccm() = default; - int init(IPAContext &context, const ValueNode &tuningData) override; + + int configure(IPAContext &context, const IPAConfigInfo &configInfo) override; + + void queueRequest(IPAContext &context, + [[maybe_unused]] const uint32_t frame, + IPAFrameContext &frameContext, + const ControlList &controls) override; + void prepare(IPAContext &context, const uint32_t frame, IPAFrameContext &frameContext, @@ -36,9 +43,7 @@ public: ControlList &metadata) override; private: - unsigned int lastCt_; - Interpolator<Matrix<float, 3, 3>> ccm_; - std::optional<Matrix<float, 3, 3>> currentCcm_; + CcmAlgorithm<Q<4, 16>> ccmAlgo_; }; } /* namespace ipa::soft::algorithms */ diff --git a/src/ipa/simple/ipa_context.h b/src/ipa/simple/ipa_context.h index 29643a655ce1..ff312ae8f4e7 100644 --- a/src/ipa/simple/ipa_context.h +++ b/src/ipa/simple/ipa_context.h @@ -17,6 +17,7 @@ #include "libcamera/internal/vector.h" #include <libipa/awb.h> +#include <libipa/ccm.h> #include <libipa/fc_queue.h> #include "core_ipa_interface.h" @@ -38,6 +39,7 @@ struct IPASessionConfiguration { struct IPAActiveState { ipa::awb::ActiveState awb; + ipa::ccm::ActiveState ccm; struct { int32_t exposure; @@ -63,8 +65,7 @@ struct IPAActiveState { struct IPAFrameContext : public FrameContext { ipa::awb::FrameContext awb; - - Matrix<float, 3, 3> ccm; + ipa::ccm::FrameContext ccm; struct { int32_t exposure;