From patchwork Fri Nov 6 12:58:05 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= X-Patchwork-Id: 28786 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 46C7AC3307 for ; Fri, 6 Nov 2026 12:58:13 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 41B206A7D5; Fri, 6 Nov 2026 13:58:12 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="BZtKE4cI"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D6ABF69213 for ; Fri, 6 Nov 2026 13:58:10 +0100 (CET) Received: from pb-laptop.local (185.221.143.99.nat.pool.zt.hu [185.221.143.99]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 34D6FC23; Fri, 6 Nov 2026 13:55:51 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1793969751; bh=6eEqdH8GIRJZCKHqMD8NuVrNY3PpLCN1D4Rt4GcnCBw=; h=From:To:Cc:Subject:Date:From; b=BZtKE4cIB5lQGfIWvA+GLFiQqZ8TjPZDoHzIJ+0swsDgCadTFdQH1H/ErkTKnq/Wj RQPbsZ8CPgVTraMILqy0T5iLATkRvQVDR0wd1N3jKn+DGHqVEXSA/+lMUlCoGmPv6x hHFV3plQagzGoBfrbFU1bC8bgTSbo/7D2jXRDwmU= From: =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= To: libcamera-devel@lists.libcamera.org Cc: Kieran Bingham , Stefan Klug Subject: [RFC PATCH v2 1/3] ipa: libipa: histogram: Add `empty()` Date: Fri, 6 Nov 2026 13:58:05 +0100 Message-ID: <20261106125807.1238919-1-barnabas.pocze@ideasonboard.com> X-Mailer: git-send-email 2.56.0 MIME-Version: 1.0 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" Empty histograms are usually of little use, so add a function that checks if the histogram contains any data points. Signed-off-by: Barnabás Pőcze Reviewed-by: Kieran Bingham Reviewed-by: Stefan Klug --- src/ipa/libipa/histogram.cpp | 10 ++++++++++ src/ipa/libipa/histogram.h | 1 + 2 files changed, 11 insertions(+) diff --git a/src/ipa/libipa/histogram.cpp b/src/ipa/libipa/histogram.cpp index 9e46a05a90..c516ace7da 100644 --- a/src/ipa/libipa/histogram.cpp +++ b/src/ipa/libipa/histogram.cpp @@ -74,6 +74,16 @@ Histogram::Histogram(std::span data) * \return Number of values */ +/** + * \fn Histogram::empty() + * \brief Determine if the histogram is empty + * + * An empty histogram is one which has only empty bins, + * that is, bins with a count of 0. + * + * \return True if the histogram is empty + */ + /** * \fn Histogram::operator[](size_t bin) const * \brief Retrieve the value for \a bin diff --git a/src/ipa/libipa/histogram.h b/src/ipa/libipa/histogram.h index b50868ab4d..cbc34e8c70 100644 --- a/src/ipa/libipa/histogram.h +++ b/src/ipa/libipa/histogram.h @@ -41,6 +41,7 @@ public: uint64_t cumulativeFrequency(double bin) const; double quantile(double q, uint32_t first = 0, uint32_t last = UINT_MAX) const; double interQuantileMean(double lowQuantile, double hiQuantile) const; + bool empty() const { return total() == 0; } uint32_t operator[](size_t bin) const { From patchwork Fri Nov 6 12:58:06 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= X-Patchwork-Id: 28787 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 0B419C3307 for ; Fri, 6 Nov 2026 12:58:15 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 4A7166A7D1; Fri, 6 Nov 2026 13:58:13 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="JtccPYL+"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 0B8FA6A7C1 for ; Fri, 6 Nov 2026 13:58:11 +0100 (CET) Received: from pb-laptop.local (185.221.143.99.nat.pool.zt.hu [185.221.143.99]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 8613918C7 for ; Fri, 6 Nov 2026 13:55:51 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1793969751; bh=UX4yhgK+UDjlwIaW+nAYMg2xSsoviojbIxuwRqhGY60=; h=From:To:Subject:Date:In-Reply-To:References:From; b=JtccPYL+P1Ihsj2LYjVlbLD3+XOQa//E0f+wwg4Ji+x7KFuzbXlPxXV4yM95PjwQ1 UUmi+tu5JbU0vxC6NKenBNxLid1+cbSJAaxddYjR4K5z2WEOYBDUqX0ayBhg8A7Ilh Z60fyrqSd3HOnqaiQmYytcIAZxn5j2AB5m2ZRatM= From: =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= To: libcamera-devel@lists.libcamera.org Subject: [RFC PATCH v2 2/3] ipa: mali-c55: agc: Remove color temperature calculation Date: Fri, 6 Nov 2026 13:58:06 +0100 Message-ID: <20261106125807.1238919-2-barnabas.pocze@ideasonboard.com> X-Mailer: git-send-email 2.56.0 In-Reply-To: <20261106125807.1238919-1-barnabas.pocze@ideasonboard.com> References: <20261106125807.1238919-1-barnabas.pocze@ideasonboard.com> MIME-Version: 1.0 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" The color temperature is already calculated by the "Awb" algorithm, and since usually that runs first, that value goes in the metadata. The "Awb" value is used by the "Ccm" algorithm, the "Agc" value is used by the "Lsc" algorithm. So remove the calculation and adjust the "Lsc" algorithm to use the same color temperature as "Ccm". Signed-off-by: Barnabás Pőcze Reviewed-by: Stefan Klug Reviewed-by: Kieran Bingham --- src/ipa/mali-c55/algorithms/agc.cpp | 5 ----- src/ipa/mali-c55/algorithms/lsc.cpp | 6 +++--- src/ipa/mali-c55/ipa_context.h | 5 +---- 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/ipa/mali-c55/algorithms/agc.cpp b/src/ipa/mali-c55/algorithms/agc.cpp index 2c747da891..bf9d3f7d4a 100644 --- a/src/ipa/mali-c55/algorithms/agc.cpp +++ b/src/ipa/mali-c55/algorithms/agc.cpp @@ -257,9 +257,6 @@ void Agc::process(IPAContext &context, } statistics_.parseStatistics(stats); - context.activeState.agc.temperatureK = estimateCCT({ { statistics_.rHist.interQuantileMean(0, 1), - statistics_.gHist.interQuantileMean(0, 1), - statistics_.bHist.interQuantileMean(0, 1) } }); agc_.process(context.configuration.agc, context.activeState.agc, frameContext.agc, {{ .traits = AgcTraits(statistics_), @@ -267,8 +264,6 @@ void Agc::process(IPAContext &context, .exposure = frameContext.sensor.exposure, .gain = frameContext.sensor.gain, }}, metadata); - - metadata.set(controls::ColourTemperature, context.activeState.agc.temperatureK); } REGISTER_IPA_ALGORITHM(Agc, "Agc") diff --git a/src/ipa/mali-c55/algorithms/lsc.cpp b/src/ipa/mali-c55/algorithms/lsc.cpp index e65e2a1807..4944f2aae4 100644 --- a/src/ipa/mali-c55/algorithms/lsc.cpp +++ b/src/ipa/mali-c55/algorithms/lsc.cpp @@ -180,8 +180,8 @@ std::tuple Lsc::findBankAndAlpha(uint32_t ct) const return { i, alpha }; } -void Lsc::prepare(IPAContext &context, [[maybe_unused]] const uint32_t frame, - [[maybe_unused]] IPAFrameContext &frameContext, +void Lsc::prepare([[maybe_unused]] IPAContext &context, [[maybe_unused]] const uint32_t frame, + IPAFrameContext &frameContext, MaliC55Params *params) { /* @@ -192,7 +192,7 @@ void Lsc::prepare(IPAContext &context, [[maybe_unused]] const uint32_t frame, * that table and if we're past the first frame then we can just do * nothing - the config will never change. */ - uint32_t temperatureK = context.activeState.agc.temperatureK; + uint32_t temperatureK = frameContext.awb.colourTemperature; uint8_t bank, alpha; if (colourTemperatures_.size() == 1) { diff --git a/src/ipa/mali-c55/ipa_context.h b/src/ipa/mali-c55/ipa_context.h index 030e0052ad..74585351c7 100644 --- a/src/ipa/mali-c55/ipa_context.h +++ b/src/ipa/mali-c55/ipa_context.h @@ -38,10 +38,7 @@ struct IPASessionConfiguration { }; struct IPAActiveState { - struct Agc : agc::ActiveState { - uint32_t temperatureK; - } agc; - + ipa::agc::ActiveState agc; ipa::awb::ActiveState awb; ipa::ccm::ActiveState ccm; ipa::gamma::ActiveState gamma; From patchwork Fri Nov 6 12:58:07 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= X-Patchwork-Id: 28788 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 32005C335C for ; Fri, 6 Nov 2026 12:58:16 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id C61B76A7D4; Fri, 6 Nov 2026 13:58:13 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="sSBQ5XrC"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 2B2B56A7C3 for ; Fri, 6 Nov 2026 13:58:11 +0100 (CET) Received: from pb-laptop.local (185.221.143.99.nat.pool.zt.hu [185.221.143.99]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id C009918E1 for ; Fri, 6 Nov 2026 13:55:51 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1793969751; bh=u1ZtM+tKAgVYf1JfTm1o8uqUVYPnR/TuFmVrn0P81Sk=; h=From:To:Subject:Date:In-Reply-To:References:From; b=sSBQ5XrCXkMTQHQE0pu6nTaJ/ZGQOmRhy5Ma/M8Q0cPGHOL7Upo8hBfYcsJ63R3jZ X7oQmaz9GIhZY/KgkmiG5F6t3Kn7CyfC/VnJJTaqQsZKKp6p2jynF1c6A/ysrlX+A9 CuGBQInxpttQdxI6j8N+Iin2vnXaPQKKZShV9mTw= From: =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= To: libcamera-devel@lists.libcamera.org Subject: [RFC PATCH v2 3/3] ipa: mali-c55: agc: Ignore invalid statistics Date: Fri, 6 Nov 2026 13:58:07 +0100 Message-ID: <20261106125807.1238919-3-barnabas.pocze@ideasonboard.com> X-Mailer: git-send-email 2.56.0 In-Reply-To: <20261106125807.1238919-1-barnabas.pocze@ideasonboard.com> References: <20261106125807.1238919-1-barnabas.pocze@ideasonboard.com> MIME-Version: 1.0 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" It is possible that, for example, the first frame has no valid statistics yet. In that case the histograms are empty. This is problematic because e.g. `interQuantileMean()` may return NaN, which causes issues in the calculations (this affects both the color temperature calculation and `AgcTraits::estimanteLuminance()` as well). Previously this has not manifested itself because implementation details in `AgcMeanLuminance` prevented the NaNs from propagating, but 25cb6cd274d3 ("libipa: agc_mean_luminance: Improve inital gain estimation") has changed that. So ignore statistics if any of the color histograms are empty. Signed-off-by: Barnabás Pőcze Reviewed-by: Kieran Bingham --- src/ipa/mali-c55/algorithms/agc.cpp | 19 +++++++++++++------ src/ipa/mali-c55/algorithms/agc.h | 5 +++++ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/ipa/mali-c55/algorithms/agc.cpp b/src/ipa/mali-c55/algorithms/agc.cpp index bf9d3f7d4a..1b7687e723 100644 --- a/src/ipa/mali-c55/algorithms/agc.cpp +++ b/src/ipa/mali-c55/algorithms/agc.cpp @@ -257,13 +257,20 @@ void Agc::process(IPAContext &context, } statistics_.parseStatistics(stats); + if (!statistics_.isValid()) { + LOG(MaliC55Agc, Debug) << "Ignoring invalid statistics"; + agc_.process(context.configuration.agc, context.activeState.agc, frameContext.agc, {}, metadata); + return; + } - agc_.process(context.configuration.agc, context.activeState.agc, frameContext.agc, {{ - .traits = AgcTraits(statistics_), - .yHist = statistics_.yHist, - .exposure = frameContext.sensor.exposure, - .gain = frameContext.sensor.gain, - }}, metadata); + agc_.process(context.configuration.agc, context.activeState.agc, frameContext.agc, + { { + .traits = AgcTraits(statistics_), + .yHist = statistics_.yHist, + .exposure = frameContext.sensor.exposure, + .gain = frameContext.sensor.gain, + } }, + metadata); } REGISTER_IPA_ALGORITHM(Agc, "Agc") diff --git a/src/ipa/mali-c55/algorithms/agc.h b/src/ipa/mali-c55/algorithms/agc.h index 809a57c53a..998ef57210 100644 --- a/src/ipa/mali-c55/algorithms/agc.h +++ b/src/ipa/mali-c55/algorithms/agc.h @@ -32,6 +32,11 @@ public: uint32_t decodeBinValue(uint16_t binVal); void parseStatistics(const mali_c55_stats_buffer *stats); + bool isValid() const + { + return !rHist.empty() && !gHist.empty() && !bHist.empty(); + } + Histogram rHist; Histogram gHist; Histogram bHist;