{"id":27065,"url":"https://patchwork.libcamera.org/api/patches/27065/?format=json","web_url":"https://patchwork.libcamera.org/patch/27065/","project":{"id":1,"url":"https://patchwork.libcamera.org/api/projects/1/?format=json","name":"libcamera","link_name":"libcamera","list_id":"libcamera_core","list_email":"libcamera-devel@lists.libcamera.org","web_url":"","scm_url":"","webscm_url":""},"msgid":"<20260626-ipu3-libipa-rework-v2-5-41546e23de3e@ideasonboard.com>","date":"2026-06-26T13:05:52","name":"[v2,05/12] ipa: ipu3: ccm: Add a Colour Correction Matrix algorithm","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"fee9662f5bce23292b0a5f0384cb86cd2e53be59","submitter":{"id":156,"url":"https://patchwork.libcamera.org/api/people/156/?format=json","name":"Dan Scally","email":"dan.scally@ideasonboard.com"},"delegate":null,"mbox":"https://patchwork.libcamera.org/patch/27065/mbox/","series":[{"id":6022,"url":"https://patchwork.libcamera.org/api/series/6022/?format=json","web_url":"https://patchwork.libcamera.org/project/libcamera/list/?series=6022","date":"2026-06-26T13:05:47","name":"libipa: Re-work IPU3 IPA to use libipa algorithms","version":2,"mbox":"https://patchwork.libcamera.org/series/6022/mbox/"}],"comments":"https://patchwork.libcamera.org/api/patches/27065/comments/","check":"pending","checks":"https://patchwork.libcamera.org/api/patches/27065/checks/","tags":{},"headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id DE9DCC3304\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri, 26 Jun 2026 13:06:19 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id F1B2E65EEE;\n\tFri, 26 Jun 2026 15:06:12 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 1A68865EE7\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 26 Jun 2026 15:06:06 +0200 (CEST)","from [127.0.1.1]\n\t(chfd-03-b2-v4wan-176392-cust229.vm15.cable.virginm.net\n\t[82.19.20.230])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 24FEA1438;\n\tFri, 26 Jun 2026 15:05:25 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"MwR/yKVT\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1782479125;\n\tbh=uGLdvDgcqMhdrFOKVJf1d7WCwiHYzz3bBtYelD5Zv+c=;\n\th=From:Date:Subject:References:In-Reply-To:To:Cc:From;\n\tb=MwR/yKVTXqk+IkPxQKlMher243Qddb7N4zJXwFcObehSlM27yaR0a7fp7MzZAqsed\n\ten6EYYovMAYUbr5yBAIu7kZ/YDPNExGnBfZNN21ZR2Csh68gkc1owDeSEsA0/3YCCF\n\tSv3jEKbDKdRv2kJMhDkLmAH3Kq1peYIf+rUdSXo4=","From":"Daniel Scally <dan.scally@ideasonboard.com>","Date":"Fri, 26 Jun 2026 14:05:52 +0100","Subject":"[PATCH v2 05/12] ipa: ipu3: ccm: Add a Colour Correction Matrix\n\talgorithm","MIME-Version":"1.0","Content-Type":"text/plain; charset=\"utf-8\"","Content-Transfer-Encoding":"7bit","Message-Id":"<20260626-ipu3-libipa-rework-v2-5-41546e23de3e@ideasonboard.com>","References":"<20260626-ipu3-libipa-rework-v2-0-41546e23de3e@ideasonboard.com>","In-Reply-To":"<20260626-ipu3-libipa-rework-v2-0-41546e23de3e@ideasonboard.com>","To":"libcamera-devel@lists.libcamera.org","Cc":"Daniel Scally <dan.scally@ideasonboard.com>, \n\tKieran Bingham <kieran.bingham@ideasonboard.com>, \n\tJacopo Mondi <jacopo.mondi@ideasonboard.com>","X-Mailer":"b4 0.14.2","X-Developer-Signature":"v=1; a=openpgp-sha256; l=8109;\n\ti=dan.scally@ideasonboard.com; h=from:subject:message-id;\n\tbh=uGLdvDgcqMhdrFOKVJf1d7WCwiHYzz3bBtYelD5Zv+c=;\n\tb=owEBbQKS/ZANAwAKAchJV3psRXUyAcsmYgBqPnk6SYGLrrf3djBtl7i2+GVME6/EhTXETEv78\n\t3eh9SYfziWJAjMEAAEKAB0WIQQqyuwyDnZdb+mxmm/ISVd6bEV1MgUCaj55OgAKCRDISVd6bEV1\n\tMkptEACE0/y1HFM+SGua8GEWE5dBHG6P/7bzNVP8duL+SRBwezXVA8krvPYgI+33Dp2mL1PHop6\n\tzuf93E46lxQQT6g91YnZsm9eUXzSKjXVZS/u0nLrWQOBohh1H5KxhdHO3RFgUvYVEnvzmPri0JG\n\t+502bI2ugFR7LX39JuEkGHte+Mr9K7841+/rHfmaRQOnCcKsscoSpNgJ2i1w6JR5fUARjb880B4\n\tFcSDqD9usw53C5hsnMpE3pnd7ZV87Z7f6ZYDHnYQ3iip2n4jLTNe8YELtk9kbmq4iZyewpTYJke\n\twF5iIza/BZhk7ZuWLbYH2JmOIz7KHYTBKGgvyPS/Xm/KAVtA1L8GSsFhajBQ0Exy2p6A0hLTUuJ\n\toCtY/ht3CVLh9OeHjKdjYnu85HvUicxk3P6KcAgvb55pzA95aCQQdernGt+BLQSsUyn8flm066S\n\tGtLup54g7c9B+n4kjt7Dw4sP4Vz7mDuFLweX8qGcZPWVH6WOYcIQ/AKmTMm3sWqOCZBigvjZhLR\n\tYTFfY9v0+sD+eYQtqy1ND+Kk6865DdYz5otoIYIc87MHX2gvoBwylXieoSYDPi36/ARY1vKHpZC\n\tfqwvNipDzfo4G3BJTAhTXL1Qzhlb5cNL/+fFhFouzBZYxgurOACt6ohzF1fahLZhtGbPC3ofkac\n\t251Ue/fNVjO2U0w==","X-Developer-Key":"i=dan.scally@ideasonboard.com; a=openpgp;\n\tfpr=EEC699ACA1B7CB5D31330C0BBD501C2A3546CCF6","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"},"content":"Add a Colour Correction Matrix algorithm that uses the new libipa\nimplementation. The module isn't well documented in the kernel but\nthe default values from the driver suggest a Q3.13 format.\n\nReviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\nReviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\nSigned-off-by: Daniel Scally <dan.scally@ideasonboard.com>\n---\nChanges in v2:\n\n        - Fixed includes\n\t- Documentation comment rework\n\t- Some styling changes\n---\n src/ipa/ipu3/algorithms/ccm.cpp     | 116 ++++++++++++++++++++++++++++++++++++\n src/ipa/ipu3/algorithms/ccm.h       |  48 +++++++++++++++\n src/ipa/ipu3/algorithms/meson.build |   1 +\n src/ipa/ipu3/ipa_context.cpp        |  10 ++++\n src/ipa/ipu3/ipa_context.h          |   3 +\n 5 files changed, 178 insertions(+)","diff":"diff --git a/src/ipa/ipu3/algorithms/ccm.cpp b/src/ipa/ipu3/algorithms/ccm.cpp\nnew file mode 100644\nindex 0000000000000000000000000000000000000000..44b8c107b079c544c5afd1fce3cbe355f6dacd76\n--- /dev/null\n+++ b/src/ipa/ipu3/algorithms/ccm.cpp\n@@ -0,0 +1,116 @@\n+/* SPDX-License-Identifier: LGPL-2.1-or-later */\n+/*\n+ * Copyright (C) 2026, Ideas On Board\n+ *\n+ * IPU3 Colour correction matrix algorithm\n+ */\n+\n+#include \"ccm.h\"\n+\n+/**\n+ * \\file ccm.h\n+ */\n+\n+namespace libcamera {\n+\n+namespace ipa::ipu3::algorithms {\n+\n+/**\n+ * \\class Ccm\n+ * \\brief The IPU3 color correction matrix algorithm\n+ */\n+\n+LOG_DEFINE_CATEGORY(IPU3Ccm)\n+\n+/**\n+ * \\copydoc libcamera::ipa::Algorithm::init\n+ */\n+int Ccm::init(IPAContext &context, const ValueNode &tuningData)\n+{\n+\treturn ccmAlgo_.init(tuningData, context.ctrlMap);\n+}\n+\n+/**\n+ * \\copydoc libcamera::ipa::Algorithm::configure\n+ */\n+int Ccm::configure(IPAContext &context,\n+\t\t   [[maybe_unused]] const IPAConfigInfo &configInfo)\n+{\n+\treturn ccmAlgo_.configure(context.activeState.ccm,\n+\t\t\t\t  context.activeState.awb.automatic.temperatureK);\n+}\n+\n+/**\n+ * \\copydoc libcamera::ipa::Algorithm::queueRequest\n+ */\n+void Ccm::queueRequest(IPAContext &context, [[maybe_unused]] const uint32_t frame,\n+\t\t       IPAFrameContext &frameContext,\n+\t\t       const ControlList &controls)\n+{\n+\t/* Nothing to do here, the ccm will be calculated in prepare() */\n+\tif (frameContext.awb.autoEnabled)\n+\t\treturn;\n+\n+\tccmAlgo_.queueRequest(context.activeState.ccm, frameContext.ccm, controls);\n+}\n+\n+void Ccm::setParameters(ipu3_uapi_params *params, IPAFrameContext &context)\n+{\n+\tconst Matrix<float, 3, 3> &matrix = context.ccm.ccm;\n+\tconst Matrix<int16_t, 3, 1> &offsets = context.ccm.offsets;\n+\n+\tparams->use.acc_ccm = 1;\n+\n+\tparams->acc_param.ccm.coeff_m11 = Q<3, 13>(matrix[0][0]).quantized();\n+\tparams->acc_param.ccm.coeff_m12 = Q<3, 13>(matrix[0][1]).quantized();\n+\tparams->acc_param.ccm.coeff_m13 = Q<3, 13>(matrix[0][2]).quantized();\n+\tparams->acc_param.ccm.coeff_o_r = offsets[0][0];\n+\n+\tparams->acc_param.ccm.coeff_m21 = Q<3, 13>(matrix[1][0]).quantized();\n+\tparams->acc_param.ccm.coeff_m22 = Q<3, 13>(matrix[1][1]).quantized();\n+\tparams->acc_param.ccm.coeff_m23 = Q<3, 13>(matrix[1][2]).quantized();\n+\tparams->acc_param.ccm.coeff_o_g = offsets[1][0];\n+\n+\tparams->acc_param.ccm.coeff_m31 = Q<3, 13>(matrix[2][0]).quantized();\n+\tparams->acc_param.ccm.coeff_m32 = Q<3, 13>(matrix[2][1]).quantized();\n+\tparams->acc_param.ccm.coeff_m33 = Q<3, 13>(matrix[2][2]).quantized();\n+\tparams->acc_param.ccm.coeff_o_b = offsets[2][0];\n+\n+\tLOG(IPU3Ccm, Debug) << \"Setting matrix \" << matrix;\n+\tLOG(IPU3Ccm, Debug) << \"Setting offsets \" << offsets;\n+}\n+\n+/**\n+ * \\copydoc libcamera::ipa::Algorithm::prepare\n+ */\n+void Ccm::prepare(IPAContext &context, const uint32_t frame,\n+\t\t  IPAFrameContext &frameContext, ipu3_uapi_params *params)\n+{\n+\tif (!frameContext.awb.autoEnabled) {\n+\t\tsetParameters(params, frameContext);\n+\t\treturn;\n+\t}\n+\n+\tccmAlgo_.prepare(context.activeState.ccm, frameContext.ccm, frame,\n+\t\t\t frameContext.awb.temperatureK);\n+\n+\tsetParameters(params, frameContext);\n+}\n+\n+/**\n+ * \\copydoc libcamera::ipa::Algorithm::process\n+ */\n+void Ccm::process([[maybe_unused]] IPAContext &context,\n+\t\t  [[maybe_unused]] const uint32_t frame,\n+\t\t  IPAFrameContext &frameContext,\n+\t\t  [[maybe_unused]] const ipu3_uapi_stats_3a *stats,\n+\t\t  ControlList &metadata)\n+{\n+\tccmAlgo_.process(frameContext.ccm, metadata);\n+}\n+\n+REGISTER_IPA_ALGORITHM(Ccm, \"Ccm\")\n+\n+} /* namespace ipa::ipu3::algorithms */\n+\n+} /* namespace libcamera */\ndiff --git a/src/ipa/ipu3/algorithms/ccm.h b/src/ipa/ipu3/algorithms/ccm.h\nnew file mode 100644\nindex 0000000000000000000000000000000000000000..9103de54b32b795d0efd22fad15ca6defb194057\n--- /dev/null\n+++ b/src/ipa/ipu3/algorithms/ccm.h\n@@ -0,0 +1,48 @@\n+/* SPDX-License-Identifier: LGPL-2.1-or-later */\n+/*\n+ * Copyright (C) 2026, Ideas On Board\n+ *\n+ * IPU3 Colour correction matrix algorithm\n+ */\n+\n+#pragma once\n+\n+#include <linux/intel-ipu3.h>\n+\n+#include <libcamera/controls.h>\n+\n+#include \"libcamera/internal/value_node.h\"\n+\n+#include <libipa/ccm.h>\n+#include <libipa/fixedpoint.h>\n+\n+#include \"algorithm.h\"\n+#include \"ipa_context.h\"\n+\n+namespace libcamera {\n+\n+namespace ipa::ipu3::algorithms {\n+\n+class Ccm : public Algorithm\n+{\n+public:\n+\tint init(IPAContext &context, const ValueNode &tuningData) override;\n+\tint configure(IPAContext &context, const IPAConfigInfo &configInfo) override;\n+\tvoid queueRequest(IPAContext &context, const uint32_t frame,\n+\t\t\t  IPAFrameContext &frameContext,\n+\t\t\t  const ControlList &controls) override;\n+\tvoid prepare(IPAContext &context, const uint32_t frame,\n+\t\t     IPAFrameContext &frameContext,\n+\t\t     ipu3_uapi_params *params) override;\n+\tvoid process(IPAContext &context, const uint32_t frame,\n+\t\t     IPAFrameContext &frameContext,\n+\t\t     const ipu3_uapi_stats_3a *stats,\n+\t\t     ControlList &metadata) override;\n+\n+private:\n+\tvoid setParameters(ipu3_uapi_params *params, IPAFrameContext &context);\n+\tCcmAlgorithm<Q<3, 13>> ccmAlgo_;\n+};\n+\n+} /* namespace ipa::ipu3::algorithms */\n+} /* namespace libcamera */\ndiff --git a/src/ipa/ipu3/algorithms/meson.build b/src/ipa/ipu3/algorithms/meson.build\nindex b70a551cacf6cbdedf3ab41771a34ddcdae9fd8b..3dafd2fda9897942cf87d9640665c4fcff383859 100644\n--- a/src/ipa/ipu3/algorithms/meson.build\n+++ b/src/ipa/ipu3/algorithms/meson.build\n@@ -5,5 +5,6 @@ ipu3_ipa_algorithms = files([\n     'agc.cpp',\n     'awb.cpp',\n     'blc.cpp',\n+    'ccm.cpp',\n     'tone_mapping.cpp',\n ])\ndiff --git a/src/ipa/ipu3/ipa_context.cpp b/src/ipa/ipu3/ipa_context.cpp\nindex e33c925f42b87887467a32dd46a42248a8723415..469905a43c4300bfa7a7fee5777f4a51837cf4c6 100644\n--- a/src/ipa/ipu3/ipa_context.cpp\n+++ b/src/ipa/ipu3/ipa_context.cpp\n@@ -114,6 +114,11 @@ namespace libcamera::ipa::ipu3 {\n  * \\brief Active auto-white balance parameters for the IPA\n  */\n \n+/**\n+ * \\var IPAActiveState::ccm\n+ * \\brief Active colour Correction Matrix parameters for the IPA\n+ */\n+\n /**\n  * \\var IPASessionConfiguration::sensor\n  * \\brief Sensor-specific configuration of the IPA\n@@ -177,4 +182,9 @@ namespace libcamera::ipa::ipu3 {\n  * \\brief Per-frame auto-white balance parameters for the IPA\n  */\n \n+/**\n+ * \\var IPAFrameContext::ccm\n+ * \\brief Per-frame colour Correction Matrix parameters for the IPA\n+ */\n+\n } /* namespace libcamera::ipa::ipu3 */\ndiff --git a/src/ipa/ipu3/ipa_context.h b/src/ipa/ipu3/ipa_context.h\nindex 564cedde51d9e20263c4cc2767853d2a5f02d2e1..6445db2603645d804b6caa40cde65099c4e57511 100644\n--- a/src/ipa/ipu3/ipa_context.h\n+++ b/src/ipa/ipu3/ipa_context.h\n@@ -16,6 +16,7 @@\n #include <libcamera/geometry.h>\n \n #include <libipa/awb.h>\n+#include <libipa/ccm.h>\n #include <libipa/fc_queue.h>\n \n namespace libcamera {\n@@ -62,6 +63,7 @@ struct IPAActiveState {\n \t} agc;\n \n \tipa::awb::ActiveState awb;\n+\tipa::ccm::ActiveState ccm;\n \n \tstruct {\n \t\tdouble gamma;\n@@ -76,6 +78,7 @@ struct IPAFrameContext : public FrameContext {\n \t} sensor;\n \n \tipa::awb::FrameContext awb;\n+\tipa::ccm::FrameContext ccm;\n };\n \n struct IPAContext {\n","prefixes":["v2","05/12"]}