From patchwork Thu Jun 18 10:18:53 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 26929 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 2A560C3310 for ; Thu, 18 Jun 2026 10:19:16 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 75ED562B32; Thu, 18 Jun 2026 12:19:15 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="PZPrBhA8"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id B3210629E3 for ; Thu, 18 Jun 2026 12:19:03 +0200 (CEST) Received: from [192.168.125.177] (mob-109-113-4-199.net.vodafone.it [109.113.4.199]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 382212590; Thu, 18 Jun 2026 12:18:28 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1781777908; bh=Uo14V8xv8NdLqXdbwptWsj5GofZHVGzwazfa8t67n2k=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=PZPrBhA8UTrNMd/90FiqYITcWaQnYlpAnNjuJAb7Ye+HUFD5NvpFKfYFfpXL97AcH aIg0/XYjBDErbApWXPOpjepEFHW4MlMZa6/+KHcU99nt4AzkCx4ynHhP51skH9QPoA lYurhFBGXSn6SUHTJFfHvzv4sw+SXuKd/O3ANBdw= From: Jacopo Mondi Date: Thu, 18 Jun 2026 12:18:53 +0200 Subject: [PATCH 14/14] ipa: rppx1: Add Ccm algorithm MIME-Version: 1.0 Message-Id: <20260618-rppx1-ipa-v1-14-32337264cfcd@ideasonboard.com> References: <20260618-rppx1-ipa-v1-0-32337264cfcd@ideasonboard.com> In-Reply-To: <20260618-rppx1-ipa-v1-0-32337264cfcd@ideasonboard.com> To: =?utf-8?q?Niklas_S=C3=B6derlund?= , libcamera-devel@lists.libcamera.org Cc: Jacopo Mondi X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=8128; i=jacopo.mondi@ideasonboard.com; h=from:subject:message-id; bh=Uo14V8xv8NdLqXdbwptWsj5GofZHVGzwazfa8t67n2k=; b=owEBbQKS/ZANAwAKAXI0Bo8WoVY8AcsmYgBqM8YKJZmZxVQna/U6TvrSg3aw0EiU3i4xZUzoq RoRQNVlVhiJAjMEAAEKAB0WIQS1xD1IgJogio9YOMByNAaPFqFWPAUCajPGCgAKCRByNAaPFqFW PDnZD/42Xqm7u6JCysWka4KOGxulySLFsTVAjkfBo9UATq4j81q36L/niTFeZwXRb5a640TSB8u tklugP4ocQJYx1Mh+BD+oMBB888COW6+rVD4DC/lt+I5dgIzncTwGUvgJ6z1tFR9GgahLbcS7Yh HttaJU+hjJO5lupFs4q23V4cDXBGJ+KLIKKrF7/9klINev4M4x8EOP//UYc5A9GMqRGWNndM3Rj jKcQw7/HCtoNbKWaTOWJ0fsBLX6Y4LuTQRLTZgKJ/XsVaLTTWl3B1GCYo5UTrBWoBGYEPbjXxb2 PIjBId/IOgXH/vE1yZm6OE3zXKJN80YuK+Ymv02VkYerjKlfcnZAKb+hseOl6umOQxpShXI4TL1 LHQJS2PQKziWznRiemJhHT/NCNWzB2WLVLUfw4chCVxD4yi6pBim2XwXSUS1KS7lsNybcmJfaGm rf+zMEeR5PXqdhT4SL547dbYrcepiKZNrIpEZxyQoy/BgaxhcJUMHNt+h8k3WUaJ/Um50H7Ty+a +J5z0NKIso/ChDnYjcjh/SnKFmx9jmCVBdBPk33GZXJV3Txc/1kGIFwzeqeoDNBPylQne9yngkq NTaYYPuFd5A495lbllmDzVGNFlphGe3ulH34+l1GUjHSyMkIyC+tgnt3ScqJIldH/BXXe2XoKP5 58DAyXICH58MOBQ== X-Developer-Key: i=jacopo.mondi@ideasonboard.com; a=openpgp; fpr=72392EDC88144A65C701EA9BA5826A2587AD026B X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Add Ccm algorithm to the RPP-X1 IPA. The implementation is based on libIPA CcmAlgorithm. Signed-off-by: Jacopo Mondi --- 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 + +#include +#include + +#include + +#include + +/** + * \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 &matrix = context.ccm.ccm; + const Matrix &offsets = context.ccm.offsets; + + auto config = params->block(); + 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(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 + +#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> ccm_; + Interpolator> offsets_; + + CcmAlgorithm> 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 #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 {