new file mode 100644
@@ -0,0 +1,116 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2026, Ideas On Board
+ *
+ * IPU3 Colour correction matrix algorithm
+ */
+
+#include "ccm.h"
+
+/**
+ * \file ccm.h
+ */
+
+namespace libcamera {
+
+namespace ipa::ipu3::algorithms {
+
+/**
+ * \class Ccm
+ * \brief The IPU3 color correction matrix algorithm
+ */
+
+LOG_DEFINE_CATEGORY(IPU3Ccm)
+
+/**
+ * \copydoc libcamera::ipa::Algorithm::init
+ */
+int Ccm::init(IPAContext &context, const ValueNode &tuningData)
+{
+ 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);
+}
+
+/**
+ * \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;
+
+ ccmAlgo_.queueRequest(context.activeState.ccm, frameContext.ccm, controls);
+}
+
+void Ccm::setParameters(ipu3_uapi_params *params, IPAFrameContext &context)
+{
+ const Matrix<float, 3, 3> &matrix = context.ccm.ccm;
+ const Matrix<int16_t, 3, 1> &offsets = context.ccm.offsets;
+
+ params->use.acc_ccm = 1;
+
+ params->acc_param.ccm.coeff_m11 = Q<3, 13>(matrix[0][0]).quantized();
+ params->acc_param.ccm.coeff_m12 = Q<3, 13>(matrix[0][1]).quantized();
+ params->acc_param.ccm.coeff_m13 = Q<3, 13>(matrix[0][2]).quantized();
+ params->acc_param.ccm.coeff_o_r = offsets[0][0];
+
+ params->acc_param.ccm.coeff_m21 = Q<3, 13>(matrix[1][0]).quantized();
+ params->acc_param.ccm.coeff_m22 = Q<3, 13>(matrix[1][1]).quantized();
+ params->acc_param.ccm.coeff_m23 = Q<3, 13>(matrix[1][2]).quantized();
+ params->acc_param.ccm.coeff_o_g = offsets[1][0];
+
+ params->acc_param.ccm.coeff_m31 = Q<3, 13>(matrix[2][0]).quantized();
+ params->acc_param.ccm.coeff_m32 = Q<3, 13>(matrix[2][1]).quantized();
+ params->acc_param.ccm.coeff_m33 = Q<3, 13>(matrix[2][2]).quantized();
+ params->acc_param.ccm.coeff_o_b = offsets[2][0];
+
+ LOG(IPU3Ccm, Debug) << "Setting matrix " << matrix;
+ LOG(IPU3Ccm, Debug) << "Setting offsets " << offsets;
+}
+
+/**
+ * \copydoc libcamera::ipa::Algorithm::prepare
+ */
+void Ccm::prepare(IPAContext &context, const uint32_t frame,
+ IPAFrameContext &frameContext, ipu3_uapi_params *params)
+{
+ if (!frameContext.awb.autoEnabled) {
+ setParameters(params, frameContext);
+ return;
+ }
+
+ 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 ipu3_uapi_stats_3a *stats,
+ ControlList &metadata)
+{
+ ccmAlgo_.process(frameContext.ccm, metadata);
+}
+
+REGISTER_IPA_ALGORITHM(Ccm, "Ccm")
+
+} /* namespace ipa::ipu3::algorithms */
+
+} /* namespace libcamera */
new file mode 100644
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2026, Ideas On Board
+ *
+ * IPU3 Colour correction matrix algorithm
+ */
+
+#pragma once
+
+#include <linux/intel-ipu3.h>
+
+#include <libipa/ccm.h>
+#include <libipa/fixedpoint.h>
+
+#include "algorithm.h"
+
+namespace libcamera {
+
+namespace ipa::ipu3::algorithms {
+
+class Ccm : public Algorithm
+{
+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,
+ ControlList &metadata) override;
+
+private:
+ void setParameters(ipu3_uapi_params *params, IPAFrameContext &context);
+ CcmAlgorithm<Q<3, 13>> ccmAlgo_;
+};
+
+} /* namespace ipa::ipu3::algorithms */
+} /* namespace libcamera */
@@ -5,5 +5,6 @@ ipu3_ipa_algorithms = files([
'agc.cpp',
'awb.cpp',
'blc.cpp',
+ 'ccm.cpp',
'tone_mapping.cpp',
])
@@ -114,6 +114,11 @@ namespace libcamera::ipa::ipu3 {
* \brief Active auto-white balance parameters for the IPA
*/
+/**
+ * \var IPAActiveState::ccm
+ * \brief Active colour Correction Matrix parameters for the IPA
+ */
+
/**
* \var IPASessionConfiguration::sensor
* \brief Sensor-specific configuration of the IPA
@@ -182,4 +187,9 @@ namespace libcamera::ipa::ipu3 {
* \brief Per-frame auto-white balance parameters for the IPA
*/
+/**
+ * \var IPAFrameContext::ccm
+ * \brief Per-frame colour Correction Matrix parameters for the IPA
+ */
+
} /* namespace libcamera::ipa::ipu3 */
@@ -16,6 +16,7 @@
#include <libcamera/geometry.h>
#include <libipa/awb.h>
+#include <libipa/ccm.h>
#include <libipa/fc_queue.h>
namespace libcamera {
@@ -64,6 +65,7 @@ struct IPAActiveState {
} agc;
ipa::awb::ActiveState awb;
+ ipa::ccm::ActiveState ccm;
struct {
double gamma;
@@ -78,6 +80,7 @@ struct IPAFrameContext : public FrameContext {
} sensor;
ipa::awb::FrameContext awb;
+ ipa::ccm::FrameContext ccm;
};
struct IPAContext {
Add a Colour Correction Matrix algorithm that uses the new libipa implementation. The module isn't well documented in the kernel but the default values from the driver suggest a Q3.13 format. Signed-off-by: Daniel Scally <dan.scally@ideasonboard.com> --- src/ipa/ipu3/algorithms/ccm.cpp | 116 ++++++++++++++++++++++++++++++++++++ src/ipa/ipu3/algorithms/ccm.h | 43 +++++++++++++ src/ipa/ipu3/algorithms/meson.build | 1 + src/ipa/ipu3/ipa_context.cpp | 10 ++++ src/ipa/ipu3/ipa_context.h | 3 + 5 files changed, 173 insertions(+)