| Message ID | 20260618-rppx1-ipa-v1-14-32337264cfcd@ideasonboard.com |
|---|---|
| State | New |
| Headers | show |
| Series |
|
| Related | show |
Quoting Jacopo Mondi (2026-06-18 11:18:53) > Add Ccm algorithm to the RPP-X1 IPA. > > The implementation is based on libIPA CcmAlgorithm. > > Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com> > --- > src/ipa/rppx1/algorithms/awb.cpp | 3 +- > src/ipa/rppx1/algorithms/ccm.cpp | 124 +++++++++++++++++++++++++++++++++++ > src/ipa/rppx1/algorithms/ccm.h | 54 +++++++++++++++ > src/ipa/rppx1/algorithms/meson.build | 1 + > src/ipa/rppx1/ipa_context.cpp | 10 +++ > src/ipa/rppx1/ipa_context.h | 3 + > 6 files changed, 193 insertions(+), 2 deletions(-) > > diff --git a/src/ipa/rppx1/algorithms/awb.cpp b/src/ipa/rppx1/algorithms/awb.cpp > index 6316606b4b0f..598e4503513c 100644 > --- a/src/ipa/rppx1/algorithms/awb.cpp > +++ b/src/ipa/rppx1/algorithms/awb.cpp > @@ -275,11 +275,10 @@ RppX1AwbStats Awb::calculateRgbMeans(const IPAFrameContext &frameContext, > rgbMeans = rgbMeans.max(0.0); > > /* > - * \todo > * The ISP computes the AWB means after applying the CCM. Apply > * the inverse as we want to get the raw means before the colour gains. > - * rgbMeans = frameContext.ccm.ccm.inverse() * rgbMeans; > */ > + rgbMeans = frameContext.ccm.ccm.inverse() * rgbMeans; > > /* > * The ISP computes the AWB means after applying the colour gains, > diff --git a/src/ipa/rppx1/algorithms/ccm.cpp b/src/ipa/rppx1/algorithms/ccm.cpp > new file mode 100644 > index 000000000000..4b485d1cff0e > --- /dev/null > +++ b/src/ipa/rppx1/algorithms/ccm.cpp > @@ -0,0 +1,124 @@ > +/* SPDX-License-Identifier: LGPL-2.1-or-later */ > +/* > + * Copyright (C) 2026, Ideas On Board > + * > + * RPP-X1 color correction matrix control algorithm > + */ > + > +#include "ccm.h" > + > +#include <linux/media/dreamchip/rppx1-config.h> > + > +#include <libcamera/base/log.h> > +#include <libcamera/base/utils.h> > + > +#include <libcamera/control_ids.h> > + > +#include <libcamera/ipa/core_ipa_interface.h> > + > +/** > + * \file ccm.h > + */ > + > +namespace libcamera { > + > +namespace ipa::rppx1::algorithms { > + > +LOG_DEFINE_CATEGORY(RppX1Ccm) > + > +/** > + * \class Ccm > + * \brief Color correction matrix algorithm > + */ > + > +/** > + * \copydoc libcamera::ipa::Algorithm::init > + */ > +int Ccm::init([[maybe_unused]] IPAContext &context, const ValueNode &tuningData) > +{ > + return ccmAlgo_.init(tuningData, context.ctrlMap); > +} > + > +/** > + * \copydoc libcamera::ipa::Algorithm::configure > + */ > +int Ccm::configure(IPAContext &context, > + [[maybe_unused]] const IPACameraSensorInfo &configInfo) > +{ > + return ccmAlgo_.configure(context.activeState.ccm, > + context.activeState.awb.automatic.temperatureK); > +} > + > +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; > + > + ccmAlgo_.queueRequest(context.activeState.ccm, frameContext.ccm, controls); > +} All as short as it could be ;-) > + > +void Ccm::setParameters(RppX1Params *params, IPAFrameContext &context) > +{ > + const Matrix<float, 3, 3> &matrix = context.ccm.ccm; > + const Matrix<int16_t, 3, 1> &offsets = context.ccm.offsets; Curious, isn't a Matrix of 1 column (or row) just a Vector? Or is that because we only have an interpolator for the Matrix and it doesn't match to a Vector ? > + > + auto config = params->block<BlockType::CcorPost>(); > + config.setEnabled(true); > + > + /* > + * RPP-X1 coefficients are 16 bits Q4.12 signed fixed-point ranging from > + * -8 (0x8000) to +7.9996 (0x7fff). x1 = 0x1000. > + */ > + for (unsigned int i = 0; i < 3; i++) { > + for (unsigned int j = 0; j < 3; j++) > + config->coeff[i][j] = Q<4, 12>(matrix[i][j]).quantized(); > + } > + > + /* > + * RPP-X1 offsets are 25 bits 2's complement while the CcmAlgorithm > + * class uses int16_t. > + * > + * \todo: Better investigate how negative offsets are handled in the > + * offsets interpolation. > + */ > + for (unsigned int i = 0; i < 3; i++) > + config->offset[i] = static_cast<int32_t>(offsets[i][0]); > + > + LOG(RppX1Ccm, Debug) << "Setting matrix " << matrix; > + LOG(RppX1Ccm, Debug) << "Setting offsets " << offsets; > +} > + > +/** > + * \copydoc libcamera::ipa::Algorithm::prepare > + */ > +void Ccm::prepare(IPAContext &context, const uint32_t frame, > + IPAFrameContext &frameContext, RppX1Params *params) > +{ > + if (frameContext.awb.autoEnabled) > + ccmAlgo_.prepare(context.activeState.ccm, frameContext.ccm, > + frame, frameContext.awb.temperatureK); > + > + setParameters(params, frameContext); > +} > + > +/** > + * \copydoc libcamera::ipa::Algorithm::process > + */ > +void Ccm::process([[maybe_unused]] IPAContext &context, > + [[maybe_unused]] const uint32_t frame, > + IPAFrameContext &frameContext, > + [[maybe_unused]] const RppX1Stats *stats, > + ControlList &metadata) > +{ > + ccmAlgo_.process(frameContext.ccm, metadata); > +} > + > +REGISTER_IPA_ALGORITHM(Ccm, "Ccm") > + > +} /* namespace ipa::rppx1::algorithms */ > + > +} /* namespace libcamera */ > diff --git a/src/ipa/rppx1/algorithms/ccm.h b/src/ipa/rppx1/algorithms/ccm.h > new file mode 100644 > index 000000000000..5e183d255a48 > --- /dev/null > +++ b/src/ipa/rppx1/algorithms/ccm.h > @@ -0,0 +1,54 @@ > +/* SPDX-License-Identifier: LGPL-2.1-or-later */ > +/* > + * Copyright (C) 2026, Ideas On Board > + * > + * RPP-X1 color correction matrix control algorithm > + */ > + > +#pragma once > + > +#include "libcamera/internal/matrix.h" > + > +#include <libipa/ccm.h> > + > +#include "algorithm.h" > + > +namespace libcamera { > + > +namespace ipa::rppx1::algorithms { > + > +class Ccm : public Algorithm > +{ > +public: > + Ccm() {} > + ~Ccm() = default; > + > + int init(IPAContext &context, const ValueNode &tuningData) override; > + int configure(IPAContext &context, > + const IPACameraSensorInfo &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, > + RppX1Params *params) override; > + void process(IPAContext &context, const uint32_t frame, > + IPAFrameContext &frameContext, > + const RppX1Stats *stats, > + ControlList &metadata) override; > + > +private: > + void parseYaml(const ValueNode &tuningData); > + void setParameters(RppX1Params *params, IPAFrameContext &context); > + > + unsigned int ct_; > + Interpolator<Matrix<float, 3, 3>> ccm_; > + Interpolator<Matrix<int16_t, 3, 1>> offsets_; So only still curious if offsets_ should be a Vector - but it's the same ... so I don't think it makes much difference except conceptually? Perhaps this is actually a discussion for the common libipa ccm part not here... so ... Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com> > + > + CcmAlgorithm<Q<4, 12>> ccmAlgo_; > +}; > + > +} /* namespace ipa::rppx1::algorithms */ > + > +} /* namespace libcamera */ > diff --git a/src/ipa/rppx1/algorithms/meson.build b/src/ipa/rppx1/algorithms/meson.build > index 70368ad9bac9..ddebbfbecbee 100644 > --- a/src/ipa/rppx1/algorithms/meson.build > +++ b/src/ipa/rppx1/algorithms/meson.build > @@ -2,4 +2,5 @@ > > rppx1_ipa_algorithms = files([ > 'awb.cpp', > + 'ccm.cpp' > ]) > diff --git a/src/ipa/rppx1/ipa_context.cpp b/src/ipa/rppx1/ipa_context.cpp > index ea7008f5685d..57a2b56774bc 100644 > --- a/src/ipa/rppx1/ipa_context.cpp > +++ b/src/ipa/rppx1/ipa_context.cpp > @@ -51,6 +51,11 @@ namespace libcamera::ipa::rppx1 { > * \copydoc ipa::awb::ActiveState > */ > > +/** > + * \var IPAActiveState::ccm > + * \copydoc ipa::ccm::ActiveState > + */ > + > /** > * \struct IPAFrameContext > * \brief Per-frame context for algorithms > @@ -61,6 +66,11 @@ namespace libcamera::ipa::rppx1 { > * \copydoc ipa::awb::FrameContext > */ > > +/** > + * \var IPAFrameContext::ccm > + * \copydoc ipa::ccm::FrameContext > + */ > + > /** > * \struct IPAContext > * \brief Global IPA context data shared between all algorithms > diff --git a/src/ipa/rppx1/ipa_context.h b/src/ipa/rppx1/ipa_context.h > index 57197d865d3f..bba1d10da73f 100644 > --- a/src/ipa/rppx1/ipa_context.h > +++ b/src/ipa/rppx1/ipa_context.h > @@ -21,6 +21,7 @@ > #include <libipa/fc_queue.h> > > #include "libipa/awb.h" > +#include "libipa/ccm.h" > > namespace libcamera { > > @@ -37,10 +38,12 @@ struct IPASessionConfiguration { > > struct IPAActiveState { > ipa::awb::ActiveState awb; > + ipa::ccm::ActiveState ccm; > }; > > struct IPAFrameContext : public FrameContext { > ipa::awb::FrameContext awb; > + ipa::ccm::FrameContext ccm; > }; > > struct IPAContext { > > -- > 2.54.0 >
Hi Jacopo, Thanks for your work. On 2026-06-18 12:18:53 +0200, Jacopo Mondi wrote: > Add Ccm algorithm to the RPP-X1 IPA. > > The implementation is based on libIPA CcmAlgorithm. > > Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com> Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se> > --- > src/ipa/rppx1/algorithms/awb.cpp | 3 +- > src/ipa/rppx1/algorithms/ccm.cpp | 124 +++++++++++++++++++++++++++++++++++ > src/ipa/rppx1/algorithms/ccm.h | 54 +++++++++++++++ > src/ipa/rppx1/algorithms/meson.build | 1 + > src/ipa/rppx1/ipa_context.cpp | 10 +++ > src/ipa/rppx1/ipa_context.h | 3 + > 6 files changed, 193 insertions(+), 2 deletions(-) > > diff --git a/src/ipa/rppx1/algorithms/awb.cpp b/src/ipa/rppx1/algorithms/awb.cpp > index 6316606b4b0f..598e4503513c 100644 > --- a/src/ipa/rppx1/algorithms/awb.cpp > +++ b/src/ipa/rppx1/algorithms/awb.cpp > @@ -275,11 +275,10 @@ RppX1AwbStats Awb::calculateRgbMeans(const IPAFrameContext &frameContext, > rgbMeans = rgbMeans.max(0.0); > > /* > - * \todo > * The ISP computes the AWB means after applying the CCM. Apply > * the inverse as we want to get the raw means before the colour gains. > - * rgbMeans = frameContext.ccm.ccm.inverse() * rgbMeans; > */ > + rgbMeans = frameContext.ccm.ccm.inverse() * rgbMeans; > > /* > * The ISP computes the AWB means after applying the colour gains, > diff --git a/src/ipa/rppx1/algorithms/ccm.cpp b/src/ipa/rppx1/algorithms/ccm.cpp > new file mode 100644 > index 000000000000..4b485d1cff0e > --- /dev/null > +++ b/src/ipa/rppx1/algorithms/ccm.cpp > @@ -0,0 +1,124 @@ > +/* SPDX-License-Identifier: LGPL-2.1-or-later */ > +/* > + * Copyright (C) 2026, Ideas On Board > + * > + * RPP-X1 color correction matrix control algorithm > + */ > + > +#include "ccm.h" > + > +#include <linux/media/dreamchip/rppx1-config.h> > + > +#include <libcamera/base/log.h> > +#include <libcamera/base/utils.h> > + > +#include <libcamera/control_ids.h> > + > +#include <libcamera/ipa/core_ipa_interface.h> > + > +/** > + * \file ccm.h > + */ > + > +namespace libcamera { > + > +namespace ipa::rppx1::algorithms { > + > +LOG_DEFINE_CATEGORY(RppX1Ccm) > + > +/** > + * \class Ccm > + * \brief Color correction matrix algorithm > + */ > + > +/** > + * \copydoc libcamera::ipa::Algorithm::init > + */ > +int Ccm::init([[maybe_unused]] IPAContext &context, const ValueNode &tuningData) > +{ > + return ccmAlgo_.init(tuningData, context.ctrlMap); > +} > + > +/** > + * \copydoc libcamera::ipa::Algorithm::configure > + */ > +int Ccm::configure(IPAContext &context, > + [[maybe_unused]] const IPACameraSensorInfo &configInfo) > +{ > + return ccmAlgo_.configure(context.activeState.ccm, > + context.activeState.awb.automatic.temperatureK); > +} > + > +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; > + > + ccmAlgo_.queueRequest(context.activeState.ccm, frameContext.ccm, controls); > +} > + > +void Ccm::setParameters(RppX1Params *params, IPAFrameContext &context) > +{ > + const Matrix<float, 3, 3> &matrix = context.ccm.ccm; > + const Matrix<int16_t, 3, 1> &offsets = context.ccm.offsets; > + > + auto config = params->block<BlockType::CcorPost>(); > + config.setEnabled(true); > + > + /* > + * RPP-X1 coefficients are 16 bits Q4.12 signed fixed-point ranging from > + * -8 (0x8000) to +7.9996 (0x7fff). x1 = 0x1000. > + */ > + for (unsigned int i = 0; i < 3; i++) { > + for (unsigned int j = 0; j < 3; j++) > + config->coeff[i][j] = Q<4, 12>(matrix[i][j]).quantized(); > + } > + > + /* > + * RPP-X1 offsets are 25 bits 2's complement while the CcmAlgorithm > + * class uses int16_t. > + * > + * \todo: Better investigate how negative offsets are handled in the > + * offsets interpolation. > + */ > + for (unsigned int i = 0; i < 3; i++) > + config->offset[i] = static_cast<int32_t>(offsets[i][0]); > + > + LOG(RppX1Ccm, Debug) << "Setting matrix " << matrix; > + LOG(RppX1Ccm, Debug) << "Setting offsets " << offsets; > +} > + > +/** > + * \copydoc libcamera::ipa::Algorithm::prepare > + */ > +void Ccm::prepare(IPAContext &context, const uint32_t frame, > + IPAFrameContext &frameContext, RppX1Params *params) > +{ > + if (frameContext.awb.autoEnabled) > + ccmAlgo_.prepare(context.activeState.ccm, frameContext.ccm, > + frame, frameContext.awb.temperatureK); > + > + setParameters(params, frameContext); > +} > + > +/** > + * \copydoc libcamera::ipa::Algorithm::process > + */ > +void Ccm::process([[maybe_unused]] IPAContext &context, > + [[maybe_unused]] const uint32_t frame, > + IPAFrameContext &frameContext, > + [[maybe_unused]] const RppX1Stats *stats, > + ControlList &metadata) > +{ > + ccmAlgo_.process(frameContext.ccm, metadata); > +} > + > +REGISTER_IPA_ALGORITHM(Ccm, "Ccm") > + > +} /* namespace ipa::rppx1::algorithms */ > + > +} /* namespace libcamera */ > diff --git a/src/ipa/rppx1/algorithms/ccm.h b/src/ipa/rppx1/algorithms/ccm.h > new file mode 100644 > index 000000000000..5e183d255a48 > --- /dev/null > +++ b/src/ipa/rppx1/algorithms/ccm.h > @@ -0,0 +1,54 @@ > +/* SPDX-License-Identifier: LGPL-2.1-or-later */ > +/* > + * Copyright (C) 2026, Ideas On Board > + * > + * RPP-X1 color correction matrix control algorithm > + */ > + > +#pragma once > + > +#include "libcamera/internal/matrix.h" > + > +#include <libipa/ccm.h> > + > +#include "algorithm.h" > + > +namespace libcamera { > + > +namespace ipa::rppx1::algorithms { > + > +class Ccm : public Algorithm > +{ > +public: > + Ccm() {} > + ~Ccm() = default; > + > + int init(IPAContext &context, const ValueNode &tuningData) override; > + int configure(IPAContext &context, > + const IPACameraSensorInfo &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, > + RppX1Params *params) override; > + void process(IPAContext &context, const uint32_t frame, > + IPAFrameContext &frameContext, > + const RppX1Stats *stats, > + ControlList &metadata) override; > + > +private: > + void parseYaml(const ValueNode &tuningData); > + void setParameters(RppX1Params *params, IPAFrameContext &context); > + > + unsigned int ct_; > + Interpolator<Matrix<float, 3, 3>> ccm_; > + Interpolator<Matrix<int16_t, 3, 1>> offsets_; > + > + CcmAlgorithm<Q<4, 12>> ccmAlgo_; > +}; > + > +} /* namespace ipa::rppx1::algorithms */ > + > +} /* namespace libcamera */ > diff --git a/src/ipa/rppx1/algorithms/meson.build b/src/ipa/rppx1/algorithms/meson.build > index 70368ad9bac9..ddebbfbecbee 100644 > --- a/src/ipa/rppx1/algorithms/meson.build > +++ b/src/ipa/rppx1/algorithms/meson.build > @@ -2,4 +2,5 @@ > > rppx1_ipa_algorithms = files([ > 'awb.cpp', > + 'ccm.cpp' > ]) > diff --git a/src/ipa/rppx1/ipa_context.cpp b/src/ipa/rppx1/ipa_context.cpp > index ea7008f5685d..57a2b56774bc 100644 > --- a/src/ipa/rppx1/ipa_context.cpp > +++ b/src/ipa/rppx1/ipa_context.cpp > @@ -51,6 +51,11 @@ namespace libcamera::ipa::rppx1 { > * \copydoc ipa::awb::ActiveState > */ > > +/** > + * \var IPAActiveState::ccm > + * \copydoc ipa::ccm::ActiveState > + */ > + > /** > * \struct IPAFrameContext > * \brief Per-frame context for algorithms > @@ -61,6 +66,11 @@ namespace libcamera::ipa::rppx1 { > * \copydoc ipa::awb::FrameContext > */ > > +/** > + * \var IPAFrameContext::ccm > + * \copydoc ipa::ccm::FrameContext > + */ > + > /** > * \struct IPAContext > * \brief Global IPA context data shared between all algorithms > diff --git a/src/ipa/rppx1/ipa_context.h b/src/ipa/rppx1/ipa_context.h > index 57197d865d3f..bba1d10da73f 100644 > --- a/src/ipa/rppx1/ipa_context.h > +++ b/src/ipa/rppx1/ipa_context.h > @@ -21,6 +21,7 @@ > #include <libipa/fc_queue.h> > > #include "libipa/awb.h" > +#include "libipa/ccm.h" > > namespace libcamera { > > @@ -37,10 +38,12 @@ struct IPASessionConfiguration { > > struct IPAActiveState { > ipa::awb::ActiveState awb; > + ipa::ccm::ActiveState ccm; > }; > > struct IPAFrameContext : public FrameContext { > ipa::awb::FrameContext awb; > + ipa::ccm::FrameContext ccm; > }; > > struct IPAContext { > > -- > 2.54.0 >
diff --git a/src/ipa/rppx1/algorithms/awb.cpp b/src/ipa/rppx1/algorithms/awb.cpp index 6316606b4b0f..598e4503513c 100644 --- a/src/ipa/rppx1/algorithms/awb.cpp +++ b/src/ipa/rppx1/algorithms/awb.cpp @@ -275,11 +275,10 @@ RppX1AwbStats Awb::calculateRgbMeans(const IPAFrameContext &frameContext, rgbMeans = rgbMeans.max(0.0); /* - * \todo * The ISP computes the AWB means after applying the CCM. Apply * the inverse as we want to get the raw means before the colour gains. - * rgbMeans = frameContext.ccm.ccm.inverse() * rgbMeans; */ + rgbMeans = frameContext.ccm.ccm.inverse() * rgbMeans; /* * The ISP computes the AWB means after applying the colour gains, diff --git a/src/ipa/rppx1/algorithms/ccm.cpp b/src/ipa/rppx1/algorithms/ccm.cpp new file mode 100644 index 000000000000..4b485d1cff0e --- /dev/null +++ b/src/ipa/rppx1/algorithms/ccm.cpp @@ -0,0 +1,124 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2026, Ideas On Board + * + * RPP-X1 color correction matrix control algorithm + */ + +#include "ccm.h" + +#include <linux/media/dreamchip/rppx1-config.h> + +#include <libcamera/base/log.h> +#include <libcamera/base/utils.h> + +#include <libcamera/control_ids.h> + +#include <libcamera/ipa/core_ipa_interface.h> + +/** + * \file ccm.h + */ + +namespace libcamera { + +namespace ipa::rppx1::algorithms { + +LOG_DEFINE_CATEGORY(RppX1Ccm) + +/** + * \class Ccm + * \brief Color correction matrix algorithm + */ + +/** + * \copydoc libcamera::ipa::Algorithm::init + */ +int Ccm::init([[maybe_unused]] IPAContext &context, const ValueNode &tuningData) +{ + return ccmAlgo_.init(tuningData, context.ctrlMap); +} + +/** + * \copydoc libcamera::ipa::Algorithm::configure + */ +int Ccm::configure(IPAContext &context, + [[maybe_unused]] const IPACameraSensorInfo &configInfo) +{ + return ccmAlgo_.configure(context.activeState.ccm, + context.activeState.awb.automatic.temperatureK); +} + +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; + + ccmAlgo_.queueRequest(context.activeState.ccm, frameContext.ccm, controls); +} + +void Ccm::setParameters(RppX1Params *params, IPAFrameContext &context) +{ + const Matrix<float, 3, 3> &matrix = context.ccm.ccm; + const Matrix<int16_t, 3, 1> &offsets = context.ccm.offsets; + + auto config = params->block<BlockType::CcorPost>(); + config.setEnabled(true); + + /* + * RPP-X1 coefficients are 16 bits Q4.12 signed fixed-point ranging from + * -8 (0x8000) to +7.9996 (0x7fff). x1 = 0x1000. + */ + for (unsigned int i = 0; i < 3; i++) { + for (unsigned int j = 0; j < 3; j++) + config->coeff[i][j] = Q<4, 12>(matrix[i][j]).quantized(); + } + + /* + * RPP-X1 offsets are 25 bits 2's complement while the CcmAlgorithm + * class uses int16_t. + * + * \todo: Better investigate how negative offsets are handled in the + * offsets interpolation. + */ + for (unsigned int i = 0; i < 3; i++) + config->offset[i] = static_cast<int32_t>(offsets[i][0]); + + LOG(RppX1Ccm, Debug) << "Setting matrix " << matrix; + LOG(RppX1Ccm, Debug) << "Setting offsets " << offsets; +} + +/** + * \copydoc libcamera::ipa::Algorithm::prepare + */ +void Ccm::prepare(IPAContext &context, const uint32_t frame, + IPAFrameContext &frameContext, RppX1Params *params) +{ + if (frameContext.awb.autoEnabled) + ccmAlgo_.prepare(context.activeState.ccm, frameContext.ccm, + frame, frameContext.awb.temperatureK); + + setParameters(params, frameContext); +} + +/** + * \copydoc libcamera::ipa::Algorithm::process + */ +void Ccm::process([[maybe_unused]] IPAContext &context, + [[maybe_unused]] const uint32_t frame, + IPAFrameContext &frameContext, + [[maybe_unused]] const RppX1Stats *stats, + ControlList &metadata) +{ + ccmAlgo_.process(frameContext.ccm, metadata); +} + +REGISTER_IPA_ALGORITHM(Ccm, "Ccm") + +} /* namespace ipa::rppx1::algorithms */ + +} /* namespace libcamera */ diff --git a/src/ipa/rppx1/algorithms/ccm.h b/src/ipa/rppx1/algorithms/ccm.h new file mode 100644 index 000000000000..5e183d255a48 --- /dev/null +++ b/src/ipa/rppx1/algorithms/ccm.h @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2026, Ideas On Board + * + * RPP-X1 color correction matrix control algorithm + */ + +#pragma once + +#include "libcamera/internal/matrix.h" + +#include <libipa/ccm.h> + +#include "algorithm.h" + +namespace libcamera { + +namespace ipa::rppx1::algorithms { + +class Ccm : public Algorithm +{ +public: + Ccm() {} + ~Ccm() = default; + + int init(IPAContext &context, const ValueNode &tuningData) override; + int configure(IPAContext &context, + const IPACameraSensorInfo &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, + RppX1Params *params) override; + void process(IPAContext &context, const uint32_t frame, + IPAFrameContext &frameContext, + const RppX1Stats *stats, + ControlList &metadata) override; + +private: + void parseYaml(const ValueNode &tuningData); + void setParameters(RppX1Params *params, IPAFrameContext &context); + + unsigned int ct_; + Interpolator<Matrix<float, 3, 3>> ccm_; + Interpolator<Matrix<int16_t, 3, 1>> offsets_; + + CcmAlgorithm<Q<4, 12>> ccmAlgo_; +}; + +} /* namespace ipa::rppx1::algorithms */ + +} /* namespace libcamera */ diff --git a/src/ipa/rppx1/algorithms/meson.build b/src/ipa/rppx1/algorithms/meson.build index 70368ad9bac9..ddebbfbecbee 100644 --- a/src/ipa/rppx1/algorithms/meson.build +++ b/src/ipa/rppx1/algorithms/meson.build @@ -2,4 +2,5 @@ rppx1_ipa_algorithms = files([ 'awb.cpp', + 'ccm.cpp' ]) diff --git a/src/ipa/rppx1/ipa_context.cpp b/src/ipa/rppx1/ipa_context.cpp index ea7008f5685d..57a2b56774bc 100644 --- a/src/ipa/rppx1/ipa_context.cpp +++ b/src/ipa/rppx1/ipa_context.cpp @@ -51,6 +51,11 @@ namespace libcamera::ipa::rppx1 { * \copydoc ipa::awb::ActiveState */ +/** + * \var IPAActiveState::ccm + * \copydoc ipa::ccm::ActiveState + */ + /** * \struct IPAFrameContext * \brief Per-frame context for algorithms @@ -61,6 +66,11 @@ namespace libcamera::ipa::rppx1 { * \copydoc ipa::awb::FrameContext */ +/** + * \var IPAFrameContext::ccm + * \copydoc ipa::ccm::FrameContext + */ + /** * \struct IPAContext * \brief Global IPA context data shared between all algorithms diff --git a/src/ipa/rppx1/ipa_context.h b/src/ipa/rppx1/ipa_context.h index 57197d865d3f..bba1d10da73f 100644 --- a/src/ipa/rppx1/ipa_context.h +++ b/src/ipa/rppx1/ipa_context.h @@ -21,6 +21,7 @@ #include <libipa/fc_queue.h> #include "libipa/awb.h" +#include "libipa/ccm.h" namespace libcamera { @@ -37,10 +38,12 @@ struct IPASessionConfiguration { struct IPAActiveState { ipa::awb::ActiveState awb; + ipa::ccm::ActiveState ccm; }; struct IPAFrameContext : public FrameContext { ipa::awb::FrameContext awb; + ipa::ccm::FrameContext ccm; }; struct IPAContext {
Add Ccm algorithm to the RPP-X1 IPA. The implementation is based on libIPA CcmAlgorithm. Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com> --- src/ipa/rppx1/algorithms/awb.cpp | 3 +- src/ipa/rppx1/algorithms/ccm.cpp | 124 +++++++++++++++++++++++++++++++++++ src/ipa/rppx1/algorithms/ccm.h | 54 +++++++++++++++ src/ipa/rppx1/algorithms/meson.build | 1 + src/ipa/rppx1/ipa_context.cpp | 10 +++ src/ipa/rppx1/ipa_context.h | 3 + 6 files changed, 193 insertions(+), 2 deletions(-)