From patchwork Tue Oct 28 21:17:34 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rui Wang X-Patchwork-Id: 24871 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 4D315BE080 for ; Tue, 28 Oct 2025 21:18:10 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 41EC360802; Tue, 28 Oct 2025 22:18:09 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="Nd6aJryY"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 0A674606DE for ; Tue, 28 Oct 2025 22:18:08 +0100 (CET) Received: from rui-Precision-7560.local (unknown [209.216.122.90]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id B30ABAD0; Tue, 28 Oct 2025 22:16:18 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1761686179; bh=/XZgJDbVY0HfCPhaQ4pLnEGwoVRoIu1I+Hn5f1+ysJg=; h=From:To:Cc:Subject:Date:From; b=Nd6aJryYJeJPXS6QXbyvg5Cra5rrbBKI+wo9sCM2ogRYZH82xQ5u428Eq9XHQfzeL jA1j2ADbrLRjO266hFdrtwS6XdV3+7NdxzU9zuwqZn2aIC1+lC6fFBfWjPlpH0gc3a Rp72Io3szsnfDCgRFjm/pojsScMQ1181WSiFCDn8= From: Rui Wang To: libcamera-devel@lists.libcamera.org Cc: Rui Wang Subject: [PATCH v1 01/17] ipa: rkisp1: algorithms: add Denoise base class shell Date: Tue, 28 Oct 2025 17:17:34 -0400 Message-ID: <20251028211751.2761420-1-rui.wang@ideasonboard.com> X-Mailer: git-send-email 2.43.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" Introduce the abstract DenoiseBaseAlgorithm class as a shared foundation for the DPF and Filter algorithms. The base class provides pure virtual hooks for control handling, manual overrides, and mode transitions, plus common state members for enable/manual/dev mode tracking. Derived classes must implement the pure virtual methods to provide algorithm-specific behavior. Signed-off-by: Rui Wang --- src/ipa/rkisp1/algorithms/denoise.h | 34 +++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/ipa/rkisp1/algorithms/denoise.h diff --git a/src/ipa/rkisp1/algorithms/denoise.h b/src/ipa/rkisp1/algorithms/denoise.h new file mode 100644 index 00000000..8f109db4 --- /dev/null +++ b/src/ipa/rkisp1/algorithms/denoise.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2025, Ideas On Board + * + * RkISP1 Denoising Algorithms Base Class + */ + +#pragma once + +#include "algorithm.h" + +namespace libcamera { + +namespace ipa::rkisp1::algorithms { + +/** + * \class DenoiseBaseAlgorithm + * \brief Base class for RkISP1 denoising algorithms + * + * This abstract base class provides common functionality for denoising algorithms + * in the RkISP1 Image Processing Algorithm (IPA). + * + * Derived classes must implement algorithm-specific behavior. + */ +class DenoiseBaseAlgorithm : public ipa::rkisp1::Algorithm +{ +protected: + DenoiseBaseAlgorithm() = default; + ~DenoiseBaseAlgorithm() = default; +}; + +} /* namespace ipa::rkisp1::algorithms */ + +} /* namespace libcamera */ From patchwork Tue Oct 28 21:17:35 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rui Wang X-Patchwork-Id: 24872 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 35946BE080 for ; Tue, 28 Oct 2025 21:18:17 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id E00896082E; Tue, 28 Oct 2025 22:18:16 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="NBeQiBAJ"; 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 50560606DE for ; Tue, 28 Oct 2025 22:18:15 +0100 (CET) Received: from rui-Precision-7560.local (unknown [209.216.122.90]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 18820AD0; Tue, 28 Oct 2025 22:16:25 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1761686186; bh=c4T8Q10S0W1EbJ7ObczOLcOiIE/Idualcu82YoHQtPk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=NBeQiBAJO6Ytb3WEYwhV0O/0b93Odjw44AI3KmGtobj1KmUmyWDNky+MuSxKeoym9 vqOi0T5Wvv3BCJhjpsUAYWBzisyWKkiZj+x6XOFx+9sUT24WR/XtYXmGBSkhflKWJB ALDCUGIoM8DKTK+MSs+Umtsu9G8ybyJfotdRKbgw= From: Rui Wang To: libcamera-devel@lists.libcamera.org Cc: Rui Wang Subject: [PATCH v1 02/17] ipa: rkisp1: algorithms: add Denoise ISO helpers Date: Tue, 28 Oct 2025 17:17:35 -0400 Message-ID: <20251028211751.2761420-2-rui.wang@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251028211751.2761420-1-rui.wang@ideasonboard.com> References: <20251028211751.2761420-1-rui.wang@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" Provide reusable ISO computation and band selection helpers. computeIso derives an effective ISO value from the AGC gain (approx ISO = gain * 100). selectIsoBand searches the tuning ISO level table for the appropriate band given the current ISO, falling back to the last band if ISO exceeds all defined ranges. Signed-off-by: Rui Wang --- src/ipa/rkisp1/algorithms/denoise.h | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/ipa/rkisp1/algorithms/denoise.h b/src/ipa/rkisp1/algorithms/denoise.h index 8f109db4..d97301f0 100644 --- a/src/ipa/rkisp1/algorithms/denoise.h +++ b/src/ipa/rkisp1/algorithms/denoise.h @@ -7,6 +7,8 @@ #pragma once +#include "../ipa_context.h" + #include "algorithm.h" namespace libcamera { @@ -27,8 +29,34 @@ class DenoiseBaseAlgorithm : public ipa::rkisp1::Algorithm protected: DenoiseBaseAlgorithm() = default; ~DenoiseBaseAlgorithm() = default; + + unsigned computeIso(const IPAContext &context, + const IPAFrameContext &frameContext) const; + template + int selectIsoBand(unsigned iso, const LevelContainer &levels) const; }; +inline unsigned DenoiseBaseAlgorithm::computeIso(const IPAContext &context, + const IPAFrameContext &frameContext) const +{ + double ag = frameContext.agc.gain ? frameContext.agc.gain + : context.activeState.agc.automatic.gain; + return static_cast(ag * 100.0 + 0.5); +} + +template +int DenoiseBaseAlgorithm::selectIsoBand(unsigned iso, const LevelContainer &levels) const +{ + if (levels.empty()) + return -1; + int idx = 0; + while (idx < static_cast(levels.size()) && iso > levels[idx].maxIso) + ++idx; + if (idx >= static_cast(levels.size())) + idx = static_cast(levels.size()) - 1; + return idx; +} + } /* namespace ipa::rkisp1::algorithms */ } /* namespace libcamera */ From patchwork Tue Oct 28 21:17:36 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rui Wang X-Patchwork-Id: 24873 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 25190BE080 for ; Tue, 28 Oct 2025 21:18:34 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id CBA976083B; Tue, 28 Oct 2025 22:18:33 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="XJc6h0Qw"; 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 42D42606DE for ; Tue, 28 Oct 2025 22:18:32 +0100 (CET) Received: from rui-Precision-7560.local (unknown [209.216.122.90]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 78E8EAD0; Tue, 28 Oct 2025 22:16:42 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1761686203; bh=SsvWV+xB3JRGT/WULtXjRSmec9iz3gykbMx1sCx7sMg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=XJc6h0QwxbfCGk+z+e+hN2MUm/ntTkGD/PusHInrueIA5rC5hXu297reMyxq/LixI Gk0i1RlGVr8xXHpzrqBQY3cHmUKNk55JiEzijqe0Ct9nurVYh07VzTXC7xW9BDYMUa mNoQlArfMXkzGzZlTFdQPTCFJQIUGFUSmA1A63Xk= From: Rui Wang To: libcamera-devel@lists.libcamera.org Cc: Rui Wang Subject: [PATCH v1 03/17] ipa: rkisp1: algorithms: add Denoise state toggles Date: Tue, 28 Oct 2025 17:17:36 -0400 Message-ID: <20251028211751.2761420-3-rui.wang@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251028211751.2761420-1-rui.wang@ideasonboard.com> References: <20251028211751.2761420-1-rui.wang@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" Add state management helpers to DenoiseBaseAlgorithm: - EnableState struct to track enable/disable state changes - processEnableToggle() to detect state transitions - Manual mode setters/getters (setManualMode, isManualMode) - Developer mode setters/getters (setDevMode, isDevMode) - Private member variables for mode tracking These helpers provide shared state management for derived DPF and Filter algorithms. Signed-off-by: Rui Wang --- src/ipa/rkisp1/algorithms/denoise.h | 31 ++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/src/ipa/rkisp1/algorithms/denoise.h b/src/ipa/rkisp1/algorithms/denoise.h index d97301f0..f40e5aa1 100644 --- a/src/ipa/rkisp1/algorithms/denoise.h +++ b/src/ipa/rkisp1/algorithms/denoise.h @@ -15,27 +15,40 @@ namespace libcamera { namespace ipa::rkisp1::algorithms { -/** - * \class DenoiseBaseAlgorithm - * \brief Base class for RkISP1 denoising algorithms - * - * This abstract base class provides common functionality for denoising algorithms - * in the RkISP1 Image Processing Algorithm (IPA). - * - * Derived classes must implement algorithm-specific behavior. - */ class DenoiseBaseAlgorithm : public ipa::rkisp1::Algorithm { protected: DenoiseBaseAlgorithm() = default; ~DenoiseBaseAlgorithm() = default; + struct EnableState { + bool enabled = true; /**< Current enable state */ + bool lastEnabled = true; /**< Previous enable state for change detection */ + }; + bool processEnableToggle(bool value, EnableState &state); + + void setManualMode(bool manual) { manualMode_ = manual; } + + void setDevMode(bool dev) { devMode_ = dev; } + bool isManualMode() const { return manualMode_; } + bool isDevMode() const { return devMode_; } unsigned computeIso(const IPAContext &context, const IPAFrameContext &frameContext) const; template int selectIsoBand(unsigned iso, const LevelContainer &levels) const; + +private: + bool manualMode_ = false; /**< Current manual/auto mode state */ + bool devMode_ = false; /**< Developer mode state for advanced controls */ }; +inline bool DenoiseBaseAlgorithm::processEnableToggle(bool value, EnableState &state) +{ + state.lastEnabled = state.enabled; + state.enabled = value; + return state.enabled != state.lastEnabled; +} + inline unsigned DenoiseBaseAlgorithm::computeIso(const IPAContext &context, const IPAFrameContext &frameContext) const { From patchwork Tue Oct 28 21:17:37 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rui Wang X-Patchwork-Id: 24874 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 E7D43BE080 for ; Tue, 28 Oct 2025 21:18:36 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 9788460844; Tue, 28 Oct 2025 22:18:36 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="iEFE/IhD"; 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 2F15D606DE for ; Tue, 28 Oct 2025 22:18:35 +0100 (CET) Received: from rui-Precision-7560.local (unknown [209.216.122.90]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id DCB4BAD0; Tue, 28 Oct 2025 22:16:45 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1761686206; bh=+eyGqc5p9uACWenOcU/Wnu+Z5BE8b3Mww6kmViso+Wk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=iEFE/IhDikSMcoJ5VZu90xZJpz3b2k4YWSVQyPM6IK/HHo4TV01S0EHv6WI2ILMiJ I//vyfLW7C5Cwxst4AHAUb7KA1M4n1p61qiZyB2jg6e3Dtr19Aig7yY5jesJmZ1hHh /rVX/o9CGqtADRZQedaG1Aon2msscbD/CQZgubxk= From: Rui Wang To: libcamera-devel@lists.libcamera.org Cc: Rui Wang Subject: [PATCH v1 04/17] ipa: rkisp1: algorithms: Add YAML parsing helper utilities Date: Tue, 28 Oct 2025 17:17:37 -0400 Message-ID: <20251028211751.2761420-4-rui.wang@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251028211751.2761420-1-rui.wang@ideasonboard.com> References: <20251028211751.2761420-1-rui.wang@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" Introduce yaml_helper.h with standardized functions for parsing YAML configuration data in RkISP1 IPA algorithms. Provides type-safe parsing for optional values, lists, enums, and specialized filter coefficients. Key functions: - opt8/16/32/bool: Type-safe optional value parsing with defaults - optList8/16: List parsing with size validation - optEnum: String-to-enum mapping with validation - optFilterCoeffs: Specialized filter coefficient parsing Signed-off-by: Rui Wang --- src/ipa/rkisp1/algorithms/yaml_helper.h | 123 ++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 src/ipa/rkisp1/algorithms/yaml_helper.h diff --git a/src/ipa/rkisp1/algorithms/yaml_helper.h b/src/ipa/rkisp1/algorithms/yaml_helper.h new file mode 100644 index 00000000..ed2ba926 --- /dev/null +++ b/src/ipa/rkisp1/algorithms/yaml_helper.h @@ -0,0 +1,123 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2025, Ideas On Board + * + * RkISP1 YAML parsing helper functions + */ + +#pragma once + +#include +#include +#include + +#include "libcamera/internal/yaml_parser.h" + +namespace libcamera { + +namespace ipa::rkisp1::algorithms { + +namespace yamlHelper { + +inline void opt32(const YamlObject &level, const char *key, std::optional &dst) +{ + dst = level[key].get(); +} + +inline void opt16(const YamlObject &level, const char *key, std::optional &dst) +{ + dst = level[key].get(); +} + +inline void opt8(const YamlObject &level, const char *key, std::optional &dst) +{ + dst = level[key].get(); +} + +inline void optbool(const YamlObject &level, const char *key, std::optional &dst) +{ + dst = level[key].get(); +} + +inline void optbool(const YamlObject &level, const char *key, bool &dst, bool defaultVal) +{ + std::optional val = level[key].get(); + dst = val.value_or(defaultVal); +} + +inline void opt8(const YamlObject &level, const char *key, uint8_t &dst, uint8_t defaultVal) +{ + std::optional val = level[key].get(); + dst = val.value_or(defaultVal); +} + +inline void opt16(const YamlObject &level, const char *key, uint16_t &dst, uint16_t defaultVal) +{ + std::optional val = level[key].get(); + dst = val.value_or(defaultVal); +} + +inline void opt32(const YamlObject &level, const char *key, uint32_t &dst, uint32_t defaultVal) +{ + std::optional val = level[key].get(); + dst = val.value_or(defaultVal); +} + +inline bool optList8(const YamlObject &level, const char *key, std::vector &dst, size_t expectedSize) +{ + std::optional> val = level[key].getList(); + if (!val || val->size() != expectedSize) + return false; + dst = *val; + return true; +} + +inline bool optList16(const YamlObject &level, const char *key, std::vector &dst, size_t expectedSize) +{ + std::optional> val = level[key].getList(); + if (!val || val->size() != expectedSize) + return false; + dst = *val; + return true; +} + +template +inline bool optEnum(const YamlObject &level, const char *key, EnumType &dst, EnumType defaultVal, + const std::map &enumMap) +{ + std::optional val = level[key].get(); + if (!val) { + dst = defaultVal; + return true; + } + auto it = enumMap.find(*val); + if (it == enumMap.end()) + return false; + dst = it->second; + return true; +} + +inline bool optFilterCoeffs(const YamlObject &level, const char *key, uint8_t *coeffs, uint32_t &filterSize, size_t maxCoeffs) +{ + std::optional> val = level[key].getList(); + if (!val) + return false; + + size_t size = val->size(); + if (size == maxCoeffs - 1) { + filterSize = 0; // 9x9 filter + } else if (size == maxCoeffs) { + filterSize = 1; // 13x9 filter + } else { + return false; // Invalid size + } + + std::copy_n(val->begin(), size, coeffs); + return true; +} + +} /* namespace yamlHelper */ + +} /* namespace ipa::rkisp1::algorithms */ + +} /* namespace libcamera */ From patchwork Tue Oct 28 21:17:38 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rui Wang X-Patchwork-Id: 24875 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 B70EDBE080 for ; Tue, 28 Oct 2025 21:18:38 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 777EA60855; Tue, 28 Oct 2025 22:18:38 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="ITsrH78T"; 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 83F94606DE for ; Tue, 28 Oct 2025 22:18:37 +0100 (CET) Received: from rui-Precision-7560.local (unknown [209.216.122.90]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id E14C1AD0; Tue, 28 Oct 2025 22:16:47 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1761686208; bh=eeCBzBL8knMj7SOHL8cPG4cTxQ4Q8BekHEC9qDqMWqo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ITsrH78TSxr9a4masl/kXCVovsyeAPDz2FmARMbYeliFfxsYmguE8ThspfBwdA1fr OHRKv1sJ6by5jtfDKKSaAao9O6JOFSgLpeXp1GQYfPoLeMOUt1cO4uwWGTl/7F9211 ZoHxBVZWxc+MM4ORVrUgvqQtWv9gEX5U0RN04F2g= From: Rui Wang To: libcamera-devel@lists.libcamera.org Cc: Rui Wang Subject: [PATCH v1 05/17] ipa: rkisp1: algorithms: dpf: add Dpf parseSingleConfig helper Date: Tue, 28 Oct 2025 17:17:38 -0400 Message-ID: <20251028211751.2761420-5-rui.wang@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251028211751.2761420-1-rui.wang@ideasonboard.com> References: <20251028211751.2761420-1-rui.wang@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" Rework domain filter, NLL, gain, and strength parsing into a parseSingleConfig() helper. This extracts the parsing logic so it can be reused for both the base tuning and per-ISO-level configuration blocks. Signed-off-by: Rui Wang --- src/ipa/rkisp1/algorithms/dpf.cpp | 109 ++++++++++++++++++++++++++++++ src/ipa/rkisp1/algorithms/dpf.h | 7 +- 2 files changed, 115 insertions(+), 1 deletion(-) diff --git a/src/ipa/rkisp1/algorithms/dpf.cpp b/src/ipa/rkisp1/algorithms/dpf.cpp index cb6095da..9d1e6435 100644 --- a/src/ipa/rkisp1/algorithms/dpf.cpp +++ b/src/ipa/rkisp1/algorithms/dpf.cpp @@ -171,6 +171,115 @@ int Dpf::init([[maybe_unused]] IPAContext &context, return 0; } +bool Dpf::parseSingleConfig(const YamlObject &config, + rkisp1_cif_isp_dpf_config &cfg, + rkisp1_cif_isp_dpf_strength_config &strength) +{ + /* + * The domain kernel is configured with a 9x9 kernel for the green + * pixels, and a 13x9 or 9x9 kernel for red and blue pixels. + * + * For the green component, we have the 9x9 kernel specified + * as 6 coefficients: + * Y + * ^ + * 4 | 6 5 4 5 6 + * 3 | 5 3 3 5 + * 2 | 5 3 2 3 5 + * 1 | 3 1 1 3 + * 0 - 4 2 0 2 4 + * -1 | 3 1 1 3 + * -2 | 5 3 2 3 5 + * -3 | 5 3 3 5 + * -4 | 6 5 4 5 6 + * +---------|--------> X + * -4....-1 0 1 2 3 4 + * + * For the red and blue components, we have the 13x9 kernel specified + * as 6 coefficients: + * + * Y + * ^ + * 4 | 6 5 4 3 4 5 6 + * | + * 2 | 5 4 2 1 2 4 5 + * | + * 0 - 5 3 1 0 1 3 5 + * | + * -2 | 5 4 2 1 2 4 5 + * | + * -4 | 6 5 4 3 4 5 6 + * +----------|-------------|---> X + * -6...........-1 0 1......6 + * + * For a 9x9 kernel, columns -6 and 6 are dropped, so coefficient + * number 6 is not used. + */ + + if (!config.contains("DomainFilter")) { + LOG(RkISP1Dpf, Error) << "DomainFilter section missing"; + return false; + } + const YamlObject &dFObject = config["DomainFilter"]; + + std::vector gCoeffs; + if (!yamlHelper::optList8(dFObject, "g", gCoeffs, RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS)) + return false; + std::copy_n(gCoeffs.begin(), gCoeffs.size(), std::begin(cfg.g_flt.spatial_coeff)); + cfg.g_flt.gr_enable = true; + cfg.g_flt.gb_enable = true; + + uint32_t rbFilterSize; + if (!yamlHelper::optFilterCoeffs(dFObject, "rb", cfg.rb_flt.spatial_coeff, rbFilterSize, RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS)) + return false; + cfg.rb_flt.fltsize = rbFilterSize ? RKISP1_CIF_ISP_DPF_RB_FILTERSIZE_13x9 : RKISP1_CIF_ISP_DPF_RB_FILTERSIZE_9x9; + cfg.rb_flt.r_enable = true; + cfg.rb_flt.b_enable = true; + + if (!config.contains("NoiseLevelFunction")) { + LOG(RkISP1Dpf, Error) << "NoiseLevelFunction section missing"; + return false; + } + const YamlObject &rFObject = config["NoiseLevelFunction"]; + + std::vector nllCoeffs; + if (!yamlHelper::optList16(rFObject, "coeff", nllCoeffs, RKISP1_CIF_ISP_DPF_MAX_NLF_COEFFS)) + return false; + std::copy_n(nllCoeffs.begin(), nllCoeffs.size(), std::begin(cfg.nll.coeff)); + + const std::map scaleModeMap = { + { "linear", RKISP1_CIF_ISP_NLL_SCALE_LINEAR }, + { "logarithmic", RKISP1_CIF_ISP_NLL_SCALE_LOGARITHMIC } + }; + if (!yamlHelper::optEnum(rFObject, "scale-mode", cfg.nll.scale_mode, RKISP1_CIF_ISP_NLL_SCALE_LINEAR, scaleModeMap)) { + LOG(RkISP1Dpf, Error) << "NoiseLevelFunction:scale-mode expected 'linear' or 'logarithmic'"; + return false; + } + + if (!config.contains("Gain")) { + LOG(RkISP1Dpf, Error) << "Gain section missing"; + return false; + } + const YamlObject &gObject = config["Gain"]; + + yamlHelper::opt32(gObject, "gain_mode", cfg.gain.mode, RKISP1_CIF_ISP_DPF_GAIN_USAGE_AWB_LSC_GAINS); + yamlHelper::opt16(gObject, "nf_r_gain", cfg.gain.nf_r_gain, 256); + yamlHelper::opt16(gObject, "nf_b_gain", cfg.gain.nf_b_gain, 256); + yamlHelper::opt16(gObject, "nf_gr_gain", cfg.gain.nf_gr_gain, 256); + yamlHelper::opt16(gObject, "nf_gb_gain", cfg.gain.nf_gb_gain, 256); + + if (!config.contains("FilterStrength")) { + LOG(RkISP1Dpf, Error) << "FilterStrength section missing"; + return false; + } + const YamlObject &fSObject = config["FilterStrength"]; + + yamlHelper::opt8(fSObject, "r", strength.r, 64); + yamlHelper::opt8(fSObject, "g", strength.g, 64); + yamlHelper::opt8(fSObject, "b", strength.b, 64); + return true; +} + /** * \copydoc libcamera::ipa::Algorithm::queueRequest */ diff --git a/src/ipa/rkisp1/algorithms/dpf.h b/src/ipa/rkisp1/algorithms/dpf.h index 2dd8cd36..cfd6ef44 100644 --- a/src/ipa/rkisp1/algorithms/dpf.h +++ b/src/ipa/rkisp1/algorithms/dpf.h @@ -10,12 +10,14 @@ #include #include "algorithm.h" +#include "denoise.h" +#include "yaml_helper.h" namespace libcamera { namespace ipa::rkisp1::algorithms { -class Dpf : public Algorithm +class Dpf : public DenoiseBaseAlgorithm { public: Dpf(); @@ -32,6 +34,9 @@ public: private: struct rkisp1_cif_isp_dpf_config config_; struct rkisp1_cif_isp_dpf_strength_config strengthConfig_; + bool parseSingleConfig(const YamlObject &config, + rkisp1_cif_isp_dpf_config &cfg, + rkisp1_cif_isp_dpf_strength_config &strength); }; } /* namespace ipa::rkisp1::algorithms */ From patchwork Tue Oct 28 21:17:39 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rui Wang X-Patchwork-Id: 24876 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 CC244BE080 for ; Tue, 28 Oct 2025 21:18:40 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 8C5AA60810; Tue, 28 Oct 2025 22:18:40 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="jZpLwstd"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id CD4B560857 for ; Tue, 28 Oct 2025 22:18:38 +0100 (CET) Received: from rui-Precision-7560.local (unknown [209.216.122.90]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 87BE8AD0; Tue, 28 Oct 2025 22:16:49 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1761686210; bh=Trv+AgvvlCtuEhbgOacWmb+5oWJPm9tv6x2/CUl7rp8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=jZpLwstdausn2z9U4xcyfV39ojzgX0RUIh4Xp+SmbtCwZBFVmPJK3p0z7GMwP3MH7 EhfRJT1UETI4/Qpc9mjjUl7Ipgn3Y2K5T0WoFVgPdnz7aDxCuNXhZQINmJexvOX8Jo 7EUceZ6E0cs5zkfWulW5he5D9LqPpOJRrJfBWkWI= From: Rui Wang To: libcamera-devel@lists.libcamera.org Cc: Rui Wang Subject: [PATCH v1 06/17] ipa: rkisp1: algorithms: dpf: add Dpf parseConfig Date: Tue, 28 Oct 2025 17:17:39 -0400 Message-ID: <20251028211751.2761420-6-rui.wang@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251028211751.2761420-1-rui.wang@ideasonboard.com> References: <20251028211751.2761420-1-rui.wang@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" Load tuning flags and ISO levels on top of the single-config helper. The parseConfig() function wraps parseSingleConfig() to load the base configuration, then parses optional enable/devmode flags and any ISO-banded overrides. ISO levels are sorted by maxIso threshold for efficient band selection at runtime. Signed-off-by: Rui Wang --- src/ipa/rkisp1/algorithms/denoise.h | 1 + src/ipa/rkisp1/algorithms/dpf.cpp | 42 +++++++++++++++++++++++++++++ src/ipa/rkisp1/algorithms/dpf.h | 21 +++++++++++++-- 3 files changed, 62 insertions(+), 2 deletions(-) diff --git a/src/ipa/rkisp1/algorithms/denoise.h b/src/ipa/rkisp1/algorithms/denoise.h index f40e5aa1..5fc78588 100644 --- a/src/ipa/rkisp1/algorithms/denoise.h +++ b/src/ipa/rkisp1/algorithms/denoise.h @@ -36,6 +36,7 @@ protected: const IPAFrameContext &frameContext) const; template int selectIsoBand(unsigned iso, const LevelContainer &levels) const; + virtual bool parseConfig(const YamlObject &tuningData) = 0; private: bool manualMode_ = false; /**< Current manual/auto mode state */ diff --git a/src/ipa/rkisp1/algorithms/dpf.cpp b/src/ipa/rkisp1/algorithms/dpf.cpp index 9d1e6435..d1b89691 100644 --- a/src/ipa/rkisp1/algorithms/dpf.cpp +++ b/src/ipa/rkisp1/algorithms/dpf.cpp @@ -171,6 +171,48 @@ int Dpf::init([[maybe_unused]] IPAContext &context, return 0; } +bool Dpf::parseConfig(const YamlObject &tuningData) +{ + // Parse base config + if (!parseSingleConfig(tuningData, config_, strengthConfig_)) + return false; + + baseConfig_ = config_; + baseStrengthConfig_ = strengthConfig_; + + /* Optional master enable flag (default true). If false, we parse but won't program. */ + yamlHelper::optbool(tuningData, "enable", enableDpf_, true); + + /* Optional developer mode flag (default true). If false, only basic manual controls available. */ + bool devMode = true; + yamlHelper::optbool(tuningData, "devmode", devMode, true); + setDevMode(devMode); + + // Parse ISO levels + if (tuningData.contains("IsoLevels")) { + useIsoLevels_ = true; + isoLevels_.clear(); + for (const auto &entry : tuningData["IsoLevels"].asList()) { + std::optional maxIsoOpt = entry["maxIso"].get(); + if (!maxIsoOpt) { + LOG(RkISP1Dpf, Error) << "IsoLevels entry missing maxIso"; + continue; + } + IsoLevelConfig lvl{}; + lvl.maxIso = *maxIsoOpt; + if (!parseSingleConfig(entry, lvl.dpf, lvl.strength)) + continue; + isoLevels_.push_back(lvl); + } + std::sort(isoLevels_.begin(), isoLevels_.end(), + [](const IsoLevelConfig &a, const IsoLevelConfig &b) { + return a.maxIso < b.maxIso; + }); + } + + return true; +} + bool Dpf::parseSingleConfig(const YamlObject &config, rkisp1_cif_isp_dpf_config &cfg, rkisp1_cif_isp_dpf_strength_config &strength) diff --git a/src/ipa/rkisp1/algorithms/dpf.h b/src/ipa/rkisp1/algorithms/dpf.h index cfd6ef44..faeb6c27 100644 --- a/src/ipa/rkisp1/algorithms/dpf.h +++ b/src/ipa/rkisp1/algorithms/dpf.h @@ -32,8 +32,25 @@ public: RkISP1Params *params) override; private: - struct rkisp1_cif_isp_dpf_config config_; - struct rkisp1_cif_isp_dpf_strength_config strengthConfig_; + struct rkisp1_cif_isp_dpf_config config_ { + }; + struct rkisp1_cif_isp_dpf_strength_config strengthConfig_ { + }; + struct rkisp1_cif_isp_dpf_config baseConfig_ { + }; + struct rkisp1_cif_isp_dpf_strength_config baseStrengthConfig_ { + }; + struct IsoLevelConfig { + unsigned int maxIso; /* inclusive upper bound */ + struct rkisp1_cif_isp_dpf_config dpf; + struct rkisp1_cif_isp_dpf_strength_config strength; + }; + + std::vector isoLevels_; + bool useIsoLevels_ = false; + bool enableDpf_ = true; /* YAML master enable */ + + bool parseConfig(const YamlObject &tuningData) override; bool parseSingleConfig(const YamlObject &config, rkisp1_cif_isp_dpf_config &cfg, rkisp1_cif_isp_dpf_strength_config &strength); From patchwork Tue Oct 28 21:17:40 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rui Wang X-Patchwork-Id: 24877 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 A6031BE080 for ; Tue, 28 Oct 2025 21:18:42 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 5DF1160859; Tue, 28 Oct 2025 22:18:42 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="k/oi66q7"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 10DB360810 for ; Tue, 28 Oct 2025 22:18:40 +0100 (CET) Received: from rui-Precision-7560.local (unknown [209.216.122.90]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id E389CAD0; Tue, 28 Oct 2025 22:16:50 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1761686211; bh=FSFjx2+KBC3XX1PCsgKL4Mp1WBBisM+Ozsd5gNs4tsw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=k/oi66q7V7joWNQ4OAUzluyjMJPuEthU7r/L575OtmnqlpLJmfJpUCflHVxt/sYY7 0kKknwrtz89BGmnYmUrD3M0lZuihZ+UkwBXg1jx+cjmhNFwAossu6jtRYUPlZQDom3 Lo2oPf8+u2o3JmgvK5isE39VwaxWNgVDkLSNJiDQ= From: Rui Wang To: libcamera-devel@lists.libcamera.org Cc: Rui Wang Subject: [PATCH v1 07/17] ipa: rkisp1: algorithms: dpf: refactor Dpf init for tuning Date: Tue, 28 Oct 2025 17:17:40 -0400 Message-ID: <20251028211751.2761420-7-rui.wang@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251028211751.2761420-1-rui.wang@ideasonboard.com> References: <20251028211751.2761420-1-rui.wang@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" Replace the inline parsing in init() with a call to parseConfig(). This simplifies init() and allows the parsing logic to be reused. The refactor also adds logging of the parsed base tuning and preserves the base config for manual mode restoration. The init method now: - Calls parseConfig() to load tuning data - Logs the parsed base configuration - Caches base config for manual mode restore - Logs ISO level count if present - Registers controls via getControlMap() Signed-off-by: Rui Wang --- src/ipa/rkisp1/algorithms/dpf.cpp | 141 +++++------------------------- 1 file changed, 24 insertions(+), 117 deletions(-) diff --git a/src/ipa/rkisp1/algorithms/dpf.cpp b/src/ipa/rkisp1/algorithms/dpf.cpp index d1b89691..a5059741 100644 --- a/src/ipa/rkisp1/algorithms/dpf.cpp +++ b/src/ipa/rkisp1/algorithms/dpf.cpp @@ -8,6 +8,7 @@ #include "dpf.h" #include +#include #include #include @@ -47,127 +48,33 @@ Dpf::Dpf() int Dpf::init([[maybe_unused]] IPAContext &context, const YamlObject &tuningData) { - std::vector values; - - /* - * The domain kernel is configured with a 9x9 kernel for the green - * pixels, and a 13x9 or 9x9 kernel for red and blue pixels. - */ - const YamlObject &dFObject = tuningData["DomainFilter"]; - - /* - * For the green component, we have the 9x9 kernel specified - * as 6 coefficients: - * Y - * ^ - * 4 | 6 5 4 5 6 - * 3 | 5 3 3 5 - * 2 | 5 3 2 3 5 - * 1 | 3 1 1 3 - * 0 - 4 2 0 2 4 - * -1 | 3 1 1 3 - * -2 | 5 3 2 3 5 - * -3 | 5 3 3 5 - * -4 | 6 5 4 5 6 - * +---------|--------> X - * -4....-1 0 1 2 3 4 - */ - values = dFObject["g"].getList().value_or(std::vector{}); - if (values.size() != RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS) { - LOG(RkISP1Dpf, Error) - << "Invalid 'DomainFilter:g': expected " - << RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS - << " elements, got " << values.size(); + /* Parse tuning block */ + if (!parseConfig(tuningData)) return -EINVAL; - } - std::copy_n(values.begin(), values.size(), - std::begin(config_.g_flt.spatial_coeff)); - - config_.g_flt.gr_enable = true; - config_.g_flt.gb_enable = true; - - /* - * For the red and blue components, we have the 13x9 kernel specified - * as 6 coefficients: - * - * Y - * ^ - * 4 | 6 5 4 3 4 5 6 - * | - * 2 | 5 4 2 1 2 4 5 - * | - * 0 - 5 3 1 0 1 3 5 - * | - * -2 | 5 4 2 1 2 4 5 - * | - * -4 | 6 5 4 3 4 5 6 - * +-------------|------------> X - * -6 -4 -2 0 2 4 6 - * - * For a 9x9 kernel, columns -6 and 6 are dropped, so coefficient - * number 6 is not used. - */ - values = dFObject["rb"].getList().value_or(std::vector{}); - if (values.size() != RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS && - values.size() != RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS - 1) { - LOG(RkISP1Dpf, Error) - << "Invalid 'DomainFilter:rb': expected " - << RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS - 1 - << " or " << RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS - << " elements, got " << values.size(); - return -EINVAL; - } - - config_.rb_flt.fltsize = values.size() == RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS - ? RKISP1_CIF_ISP_DPF_RB_FILTERSIZE_13x9 - : RKISP1_CIF_ISP_DPF_RB_FILTERSIZE_9x9; - - std::copy_n(values.begin(), values.size(), - std::begin(config_.rb_flt.spatial_coeff)); - - config_.rb_flt.r_enable = true; - config_.rb_flt.b_enable = true; - - /* - * The range kernel is configured with a noise level lookup table (NLL) - * which stores a piecewise linear function that characterizes the - * sensor noise profile as a noise level function curve (NLF). - */ - const YamlObject &rFObject = tuningData["NoiseLevelFunction"]; - - std::vector nllValues; - nllValues = rFObject["coeff"].getList().value_or(std::vector{}); - if (nllValues.size() != RKISP1_CIF_ISP_DPF_MAX_NLF_COEFFS) { - LOG(RkISP1Dpf, Error) - << "Invalid 'RangeFilter:coeff': expected " - << RKISP1_CIF_ISP_DPF_MAX_NLF_COEFFS - << " elements, got " << nllValues.size(); - return -EINVAL; - } + /* Log parsed base tuning (counts are always full-sized for base). */ + LOG(RkISP1Dpf, Info) + << "DPF init: base tuning parsed, G coeffs=" + << RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS + << ", RB fltsize=" + << (config_.rb_flt.fltsize == RKISP1_CIF_ISP_DPF_RB_FILTERSIZE_13x9 ? "13x9" : "9x9") + << ", NLL coeffs=" << RKISP1_CIF_ISP_DPF_MAX_NLF_COEFFS + << ", NLL scale=" + << (config_.nll.scale_mode == RKISP1_CIF_ISP_NLL_SCALE_LOGARITHMIC ? "log" : "linear") + << ", Strength (r,g,b)=" + << (int)strengthConfig_.r << "," << (int)strengthConfig_.g + << "," << (int)strengthConfig_.b; + + /* Preserve base (non-ISO) YAML configuration for restoration after manual mode. */ + baseConfig_ = config_; + baseStrengthConfig_ = strengthConfig_; - std::copy_n(nllValues.begin(), nllValues.size(), - std::begin(config_.nll.coeff)); - - std::string scaleMode = rFObject["scale-mode"].get(""); - if (scaleMode == "linear") { - config_.nll.scale_mode = RKISP1_CIF_ISP_NLL_SCALE_LINEAR; - } else if (scaleMode == "logarithmic") { - config_.nll.scale_mode = RKISP1_CIF_ISP_NLL_SCALE_LOGARITHMIC; - } else { - LOG(RkISP1Dpf, Error) - << "Invalid 'RangeFilter:scale-mode': expected " - << "'linear' or 'logarithmic' value, got " - << scaleMode; - return -EINVAL; + /* Optional ISO-banded tuning */ + if (useIsoLevels_) { + LOG(RkISP1Dpf, Info) + << "DPF init: loaded " << isoLevels_.size() + << " ISO level(s) from tuning"; } - - const YamlObject &fSObject = tuningData["FilterStrength"]; - - strengthConfig_.r = fSObject["r"].get(64); - strengthConfig_.g = fSObject["g"].get(64); - strengthConfig_.b = fSObject["b"].get(64); - return 0; } From patchwork Tue Oct 28 21:17:41 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rui Wang X-Patchwork-Id: 24878 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 C9553BE080 for ; Tue, 28 Oct 2025 21:18:44 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 7DF5060867; Tue, 28 Oct 2025 22:18:44 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="nu8Siwzr"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 6200E60864 for ; Tue, 28 Oct 2025 22:18:42 +0100 (CET) Received: from rui-Precision-7560.local (unknown [209.216.122.90]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 0B0A0E1F; Tue, 28 Oct 2025 22:16:52 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1761686213; bh=jV7eEV2O6t6DQUr2PmLI8Lue2KoK1wOeHnNaSiDF37A=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=nu8SiwzrnapMJzReKsyFASYvXMPR6xcwGlNps2tAE5SXpyq9CPz6oBwmCkQJKeb1C 7d+fC7LYiqbyDlXM7TamL5+kbbYvWmgsHvo/cXkDpaAqmro958+nurvql0zhabVIVR C8cHYbDBruckTEtwfDNKBQzTiQf5iitywRYoxfjc= From: Rui Wang To: libcamera-devel@lists.libcamera.org Cc: Rui Wang Subject: [PATCH v1 08/17] ipa: rkisp1: controls: define control block Date: Tue, 28 Oct 2025 17:17:41 -0400 Message-ID: <20251028211751.2761420-8-rui.wang@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251028211751.2761420-1-rui.wang@ideasonboard.com> References: <20251028211751.2761420-1-rui.wang@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" Reserve the next free vendor allocation for rkisp1 and add the dedicated control_ids_rkisp1.yaml. Hook the new YAML into the Meson build so the generated control headers expose the rkisp1 control namespace. Signed-off-by: Rui Wang --- include/libcamera/meson.build | 1 + src/libcamera/control_ids_rkisp1.yaml | 24 ++++++++++++++++++++++++ src/libcamera/control_ranges.yaml | 4 +++- 3 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 src/libcamera/control_ids_rkisp1.yaml diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build index 30ea76f9..3fd7ef94 100644 --- a/include/libcamera/meson.build +++ b/include/libcamera/meson.build @@ -39,6 +39,7 @@ controls_map = { 'draft': 'control_ids_draft.yaml', 'rpi/pisp': 'control_ids_rpi.yaml', 'rpi/vc4': 'control_ids_rpi.yaml', + 'rkisp1': 'control_ids_rkisp1.yaml', }, 'properties': { diff --git a/src/libcamera/control_ids_rkisp1.yaml b/src/libcamera/control_ids_rkisp1.yaml new file mode 100644 index 00000000..2f29d508 --- /dev/null +++ b/src/libcamera/control_ids_rkisp1.yaml @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# Copyright (C) 2025, Ideas On Board +# +# RkISP1 specific control definitions +--- +# Unless otherwise stated, all controls are bi-directional, i.e. they can be +# set through Request::controls() and returned out through Request::metadata(). +vendor: rkisp1 +controls: + # --- RkISP1 DPF controls --- + - DpfEnable: + type: bool + direction: inout + description: | + Enable or disable the Denoise Pre-Filter (DPF) block. + + When disabled (false) the hardware DPF is forced off regardless of + tuning or ISO level selection. When enabled (true) the algorithm may + program parameters and adapt them per ISO band or manual overrides. + + Reported in metadata as a boolean. + +... diff --git a/src/libcamera/control_ranges.yaml b/src/libcamera/control_ranges.yaml index 6752eb98..fc60de80 100644 --- a/src/libcamera/control_ranges.yaml +++ b/src/libcamera/control_ranges.yaml @@ -15,6 +15,8 @@ ranges: rpi: 20000 # Controls for debug metadata debug: 30000 - # Next range starts at 40000 + # RkISP1 vendor controls + rkisp1: 40000 + # Next range starts at 50000 ... From patchwork Tue Oct 28 21:17:42 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rui Wang X-Patchwork-Id: 24879 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 968D1BE080 for ; Tue, 28 Oct 2025 21:18:48 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 3E6276086D; Tue, 28 Oct 2025 22:18:48 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="YlFPhQ7B"; 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 EF6B86082E for ; Tue, 28 Oct 2025 22:18:46 +0100 (CET) Received: from rui-Precision-7560.local (unknown [209.216.122.90]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 43F271127; Tue, 28 Oct 2025 22:16:57 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1761686217; bh=zNy83JNJ07WUcf2XuDb7bWd83wJfMp4DWSgffFPJik8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=YlFPhQ7BIdNf2YsmvleXB/zQ5rWGVsPwQQrHeJKgc/F9l8NHZ8lqIYuoJe5H0d42W Gz28mx8B070BM0nQspfMD1uFduyxseFaKkFySBEejneTYXavrMdjDuEILJ/PmzFR8C qylyGmtvkbEx16QIX7iBf9868wm/WkbrQwrNhQp4= From: Rui Wang To: libcamera-devel@lists.libcamera.org Cc: Rui Wang Subject: [PATCH v1 09/17] ipa: rkisp1: algorithms: dpf: handle DPF enable toggle Date: Tue, 28 Oct 2025 17:17:42 -0400 Message-ID: <20251028211751.2761420-9-rui.wang@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251028211751.2761420-1-rui.wang@ideasonboard.com> References: <20251028211751.2761420-1-rui.wang@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" Implement handleEnableControl() to process the DpfEnable control and synchronize the enable state across context and frame state. Update queueRequest() to call this handler, clearing the update flag first. The enable control allows applications to globally enable/disable DPF processing without changing other configuration. Changes are logged and trigger frame updates. This replaces the previous draft::NoiseReductionMode handling with the new RkISP1-specific DpfEnable control. Signed-off-by: Rui Wang --- src/ipa/rkisp1/algorithms/denoise.h | 1 + src/ipa/rkisp1/algorithms/dpf.cpp | 48 ++++++++++------------------- src/ipa/rkisp1/algorithms/dpf.h | 1 + 3 files changed, 18 insertions(+), 32 deletions(-) diff --git a/src/ipa/rkisp1/algorithms/denoise.h b/src/ipa/rkisp1/algorithms/denoise.h index 5fc78588..5bc3f941 100644 --- a/src/ipa/rkisp1/algorithms/denoise.h +++ b/src/ipa/rkisp1/algorithms/denoise.h @@ -37,6 +37,7 @@ protected: template int selectIsoBand(unsigned iso, const LevelContainer &levels) const; virtual bool parseConfig(const YamlObject &tuningData) = 0; + virtual void handleEnableControl(const ControlList &controls, IPAFrameContext &frameContext, IPAContext &context) = 0; private: bool manualMode_ = false; /**< Current manual/auto mode state */ diff --git a/src/ipa/rkisp1/algorithms/dpf.cpp b/src/ipa/rkisp1/algorithms/dpf.cpp index a5059741..d0bed3e4 100644 --- a/src/ipa/rkisp1/algorithms/dpf.cpp +++ b/src/ipa/rkisp1/algorithms/dpf.cpp @@ -229,6 +229,20 @@ bool Dpf::parseSingleConfig(const YamlObject &config, return true; } +void Dpf::handleEnableControl(const ControlList &controls, IPAFrameContext &frameContext, IPAContext &context) +{ + if (const auto &c = controls.get(controls::rkisp1::DpfEnable); c) { + bool requested = *c != 0; + if (requested != enableDpf_) { + enableDpf_ = requested; + frameContext.dpf.update = true; + LOG(RkISP1Dpf, Info) << "DPF global " << (enableDpf_ ? "enabled" : "disabled"); + } + } + context.activeState.dpf.denoise = enableDpf_; + frameContext.dpf.denoise = enableDpf_; +} + /** * \copydoc libcamera::ipa::Algorithm::queueRequest */ @@ -237,38 +251,8 @@ void Dpf::queueRequest(IPAContext &context, IPAFrameContext &frameContext, const ControlList &controls) { - auto &dpf = context.activeState.dpf; - bool update = false; - - const auto &denoise = controls.get(controls::draft::NoiseReductionMode); - if (denoise) { - LOG(RkISP1Dpf, Debug) << "Set denoise to " << *denoise; - - switch (*denoise) { - case controls::draft::NoiseReductionModeOff: - if (dpf.denoise) { - dpf.denoise = false; - update = true; - } - break; - case controls::draft::NoiseReductionModeMinimal: - case controls::draft::NoiseReductionModeHighQuality: - case controls::draft::NoiseReductionModeFast: - if (!dpf.denoise) { - dpf.denoise = true; - update = true; - } - break; - default: - LOG(RkISP1Dpf, Error) - << "Unsupported denoise value " - << *denoise; - break; - } - } - - frameContext.dpf.denoise = dpf.denoise; - frameContext.dpf.update = update; + frameContext.dpf.update = false; + handleEnableControl(controls, frameContext, context); } /** diff --git a/src/ipa/rkisp1/algorithms/dpf.h b/src/ipa/rkisp1/algorithms/dpf.h index faeb6c27..c01f711c 100644 --- a/src/ipa/rkisp1/algorithms/dpf.h +++ b/src/ipa/rkisp1/algorithms/dpf.h @@ -50,6 +50,7 @@ private: bool useIsoLevels_ = false; bool enableDpf_ = true; /* YAML master enable */ + void handleEnableControl(const ControlList &controls, IPAFrameContext &frameContext, IPAContext &context) override; bool parseConfig(const YamlObject &tuningData) override; bool parseSingleConfig(const YamlObject &config, rkisp1_cif_isp_dpf_config &cfg, From patchwork Tue Oct 28 21:17:43 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rui Wang X-Patchwork-Id: 24880 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 9F631BE080 for ; Tue, 28 Oct 2025 21:18:50 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 2FBA160859; Tue, 28 Oct 2025 22:18:50 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="dfG9Jt8B"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 4F8916086F for ; Tue, 28 Oct 2025 22:18:48 +0100 (CET) Received: from rui-Precision-7560.local (unknown [209.216.122.90]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 17E1AAD0; Tue, 28 Oct 2025 22:16:58 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1761686219; bh=umoNTAq5Rg0Hhy6p7LhEHZo9ugpgiKdSfwh1KxILWj0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=dfG9Jt8BSXhjKRarWSq0jpa4zCumtgz9mE+J5Cesw18TeGqySHd/2Gjt/4/oaW+Xp 5eFUeFICMbCN1Q17b7tnEIR/oL5Bx5JTRuDcPsT8IeQ00AXZxmxzyMj+bTtne/WNpJ XHFIHbu1yv2KaMSCR+/keLRkXpgy5sCw6HLupkdw= From: Rui Wang To: libcamera-devel@lists.libcamera.org Cc: Rui Wang Subject: [PATCH v1 10/17] ipa: rkisp1: algorithms: dpf: collect DPF manual overrides Date: Tue, 28 Oct 2025 17:17:43 -0400 Message-ID: <20251028211751.2761420-10-rui.wang@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251028211751.2761420-1-rui.wang@ideasonboard.com> References: <20251028211751.2761420-1-rui.wang@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" Implement collectManualOverrides() to capture strength and developer-mode override arrays from control requests. Extend queueRequest() to collect overrides in manual mode and mark frames dirty when strength values differ from the active configuration. Developer mode controls (spatial coefficients, filter size, NLL tables) are only collected when devmode is enabled. The function populates the overrides_ structure which will be applied during prepare(). Signed-off-by: Rui Wang --- src/ipa/rkisp1/algorithms/denoise.h | 1 + src/ipa/rkisp1/algorithms/dpf.cpp | 58 +++++++++++++++++++++++++ src/ipa/rkisp1/algorithms/dpf.h | 30 +++++++++++++ src/libcamera/control_ids_rkisp1.yaml | 62 +++++++++++++++++++++++++++ 4 files changed, 151 insertions(+) diff --git a/src/ipa/rkisp1/algorithms/denoise.h b/src/ipa/rkisp1/algorithms/denoise.h index 5bc3f941..1a874def 100644 --- a/src/ipa/rkisp1/algorithms/denoise.h +++ b/src/ipa/rkisp1/algorithms/denoise.h @@ -38,6 +38,7 @@ protected: int selectIsoBand(unsigned iso, const LevelContainer &levels) const; virtual bool parseConfig(const YamlObject &tuningData) = 0; virtual void handleEnableControl(const ControlList &controls, IPAFrameContext &frameContext, IPAContext &context) = 0; + virtual void collectManualOverrides(const ControlList &controls) = 0; private: bool manualMode_ = false; /**< Current manual/auto mode state */ diff --git a/src/ipa/rkisp1/algorithms/dpf.cpp b/src/ipa/rkisp1/algorithms/dpf.cpp index d0bed3e4..145f10b7 100644 --- a/src/ipa/rkisp1/algorithms/dpf.cpp +++ b/src/ipa/rkisp1/algorithms/dpf.cpp @@ -243,6 +243,53 @@ void Dpf::handleEnableControl(const ControlList &controls, IPAFrameContext &fram frameContext.dpf.denoise = enableDpf_; } +void Dpf::collectManualOverrides(const ControlList &controls) +{ + if (const auto &c = controls.get(controls::rkisp1::DpfChannelStrengths); c) { + if (c->size() == 3) { + overrides_.strength = DpfStrengthSettings{ static_cast((*c)[0]), static_cast((*c)[1]), static_cast((*c)[2]) }; + } + } + if (isDevMode()) { + if (const auto &c = controls.get(controls::rkisp1::DpfGreenSpatialCoefficients); c) { + if (c->size() == RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS) { + DpfSpatialGreenSettings green; + std::copy_n(c->begin(), RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS, green.coeffs.begin()); + overrides_.spatialGreen = green; + } + } + if (const auto &c = controls.get(controls::rkisp1::DpfRedBlueSpatialCoefficients); c) { + if (c->size() == RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS) { + DpfSpatialRbSettings rb; + std::copy_n(c->begin(), RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS, rb.coeffs.begin()); + rb.size = (config_.rb_flt.fltsize == RKISP1_CIF_ISP_DPF_RB_FILTERSIZE_13x9) ? 1 : 0; + overrides_.spatialRb = rb; + } + } + if (const auto &c = controls.get(controls::rkisp1::DpfRbFilterSize); c) { + overrides_.rbSize = *c ? 1 : 0; + } + if (const auto &c = controls.get(controls::rkisp1::DpfNoiseLevelLookupCoefficients); c) { + if (c->size() == RKISP1_CIF_ISP_DPF_MAX_NLF_COEFFS) { + DpfNllSettings nll; + std::copy_n(c->begin(), RKISP1_CIF_ISP_DPF_MAX_NLF_COEFFS, nll.coeffs.begin()); + nll.scaleMode = (config_.nll.scale_mode == RKISP1_CIF_ISP_NLL_SCALE_LOGARITHMIC) ? 1 : 0; + overrides_.nll = nll; + } + } + if (const auto &c = controls.get(controls::rkisp1::DpfNoiseLevelLookupScaleMode); c) { + if (overrides_.nll) { + overrides_.nll->scaleMode = *c ? 1 : 0; + } else { + DpfNllSettings nll; + std::copy_n(std::begin(config_.nll.coeff), RKISP1_CIF_ISP_DPF_MAX_NLF_COEFFS, nll.coeffs.begin()); + nll.scaleMode = *c ? 1 : 0; + overrides_.nll = nll; + } + } + } +} + /** * \copydoc libcamera::ipa::Algorithm::queueRequest */ @@ -253,6 +300,17 @@ void Dpf::queueRequest(IPAContext &context, { frameContext.dpf.update = false; handleEnableControl(controls, frameContext, context); + + if (isManualMode()) { + collectManualOverrides(controls); + // Check if manual overrides have changed and trigger update + if (overrides_.strength && + (overrides_.strength->r != strengthConfig_.r || + overrides_.strength->g != strengthConfig_.g || + overrides_.strength->b != strengthConfig_.b)) { + frameContext.dpf.update = true; + } + } } /** diff --git a/src/ipa/rkisp1/algorithms/dpf.h b/src/ipa/rkisp1/algorithms/dpf.h index c01f711c..1a33a8c4 100644 --- a/src/ipa/rkisp1/algorithms/dpf.h +++ b/src/ipa/rkisp1/algorithms/dpf.h @@ -34,23 +34,53 @@ public: private: struct rkisp1_cif_isp_dpf_config config_ { }; + struct rkisp1_cif_isp_dpf_strength_config strengthConfig_ { }; + struct rkisp1_cif_isp_dpf_config baseConfig_ { }; + struct rkisp1_cif_isp_dpf_strength_config baseStrengthConfig_ { }; + + struct DpfStrengthSettings { + uint16_t r, g, b; + }; + + struct DpfSpatialGreenSettings { + std::array coeffs; + }; + + struct DpfSpatialRbSettings { + std::array coeffs; + uint8_t size; // 0=9x9, 1=13x9 + }; + + struct DpfNllSettings { + std::array coeffs; + uint8_t scaleMode; // 0 linear, 1 log + }; struct IsoLevelConfig { unsigned int maxIso; /* inclusive upper bound */ struct rkisp1_cif_isp_dpf_config dpf; struct rkisp1_cif_isp_dpf_strength_config strength; }; + struct Overrides { + std::optional strength; + std::optional spatialGreen; + std::optional spatialRb; + std::optional rbSize; + std::optional nll; + void clear() { *this = Overrides{}; } + } overrides_; std::vector isoLevels_; bool useIsoLevels_ = false; bool enableDpf_ = true; /* YAML master enable */ void handleEnableControl(const ControlList &controls, IPAFrameContext &frameContext, IPAContext &context) override; + void collectManualOverrides(const ControlList &controls) override; bool parseConfig(const YamlObject &tuningData) override; bool parseSingleConfig(const YamlObject &config, rkisp1_cif_isp_dpf_config &cfg, diff --git a/src/libcamera/control_ids_rkisp1.yaml b/src/libcamera/control_ids_rkisp1.yaml index 2f29d508..bf7875e9 100644 --- a/src/libcamera/control_ids_rkisp1.yaml +++ b/src/libcamera/control_ids_rkisp1.yaml @@ -21,4 +21,66 @@ controls: Reported in metadata as a boolean. + - DpfChannelStrengths: + type: int32_t + direction: inout + description: | + Override filter strength for R,G,B channels. Values map to hardware + strength registers (0..255 typical). Size must be exactly 3 when set. + Order: R,G,B. If unset the tuning / ISO level derived strengths apply. + size: [3] + + - DpfGreenSpatialCoefficients: + type: int32_t + direction: inout + description: | + Override 9x9 green spatial kernel coefficients (6 values). Order must + follow tuning file convention. Each value 0..63 typical. All 6 required + when provided; otherwise ignored. + size: [6] + + - DpfRedBlueSpatialCoefficients: + type: int32_t + direction: inout + description: | + Override Red/Blue spatial kernel coefficients (6 values). Applies to + either 9x9 or 13x9 depending on DpfRbFilterSize. For 9x9 the last + column pair is dropped in hardware. Values 0..63 typical. + size: [6] + + - DpfRbFilterSize: + type: int32_t + direction: inout + description: | + Override RB spatial filter size selection. + enum: + - name: DpfRbFilterSize9x9 + value: 0 + description: Use 9x9 RB domain filter. + - name: DpfRbFilterSize13x9 + value: 1 + description: Use 13x9 RB domain filter (if coefficients valid). + + - DpfNoiseLevelLookupCoefficients: + type: int32_t + direction: inout + description: | + Override Noise Level Lookup (NLL) piecewise-linear coefficients + (17 values). Must supply full set when used or override is ignored. + size: [17] + + - DpfNoiseLevelLookupScaleMode: + type: int32_t + direction: inout + description: | + Override NLL scale mode (0=linear,1=logarithmic). Matches hardware + RKISP1_CIF_ISP_NLL_SCALE_* constants. + enum: + - name: DpfNoiseLevelLookupScaleLinear + value: 0 + description: Linear scale. + - name: DpfNoiseLevelLookupScaleLogarithmic + value: 1 + description: Logarithmic scale. + ... From patchwork Tue Oct 28 21:17:44 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rui Wang X-Patchwork-Id: 24881 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 719F6BE080 for ; Tue, 28 Oct 2025 21:18:53 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id A4FB060883; Tue, 28 Oct 2025 22:18:52 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="kcs/GXT6"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id AD9CE60844 for ; Tue, 28 Oct 2025 22:18:49 +0100 (CET) Received: from rui-Precision-7560.local (unknown [209.216.122.90]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 7B7B8AD0; Tue, 28 Oct 2025 22:17:00 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1761686221; bh=QPqeJ3qV3kxcVH0Yz7W/FsO3VOQKFjM7mgOFJmo0700=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=kcs/GXT6cUCiYViPI/+hhNb7lLfWaJFn9EvepmblV23mYieGzUkQY+/QDFfjAvgdT TzxrcnvW7Ouy5rMUIc6LBmLHmOi4fWuZ3lqYH61VFhiRjsxy9ixz5aJD9eCkSkaetf /QkSpxYRkk3QRkf0ni103I3pD7Xp6O5ewjo/7oXg= From: Rui Wang To: libcamera-devel@lists.libcamera.org Cc: Rui Wang Subject: [PATCH v1 11/17] ipa: rkisp1: algorithms: dpf: detect DPF dev overrides Date: Tue, 28 Oct 2025 17:17:44 -0400 Message-ID: <20251028211751.2761420-11-rui.wang@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251028211751.2761420-1-rui.wang@ideasonboard.com> References: <20251028211751.2761420-1-rui.wang@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" Introduce checkDevModeOverridesChanged() to detect when developer-mode controls have been modified. This function compares override values against the current hardware configuration for: - Spatial coefficients (green and RB) - RB filter size - NLL coefficients and scale mode Updates queueRequest() to trigger hardware updates whenever dev-mode overrides differ from active settings. This ensures spatial kernels, NLL tables, and filter size changes are applied immediately in manual mode. Signed-off-by: Rui Wang --- src/ipa/rkisp1/algorithms/dpf.cpp | 51 +++++++++++++++++++++++++++++++ src/ipa/rkisp1/algorithms/dpf.h | 5 +++ 2 files changed, 56 insertions(+) diff --git a/src/ipa/rkisp1/algorithms/dpf.cpp b/src/ipa/rkisp1/algorithms/dpf.cpp index 145f10b7..cefa5da5 100644 --- a/src/ipa/rkisp1/algorithms/dpf.cpp +++ b/src/ipa/rkisp1/algorithms/dpf.cpp @@ -290,6 +290,54 @@ void Dpf::collectManualOverrides(const ControlList &controls) } } +bool Dpf::checkDevModeOverridesChanged() +{ + if (!isDevMode()) + return false; + + bool changed = false; + if (overrides_.spatialGreen) { + bool coeffsChanged = false; + for (unsigned i = 0; i < RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS; ++i) { + if (overrides_.spatialGreen->coeffs[i] != config_.g_flt.spatial_coeff[i]) { + coeffsChanged = true; + break; + } + } + if (coeffsChanged) { + changed = true; + } + } + if (overrides_.spatialRb) { + bool coeffsChanged = false; + for (unsigned i = 0; i < RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS; ++i) { + if (overrides_.spatialRb->coeffs[i] != config_.rb_flt.spatial_coeff[i]) { + coeffsChanged = true; + break; + } + } + if (coeffsChanged) { + changed = true; + } + } + if (overrides_.rbSize && *overrides_.rbSize != (config_.rb_flt.fltsize == RKISP1_CIF_ISP_DPF_RB_FILTERSIZE_13x9 ? 1 : 0)) { + changed = true; + } + if (overrides_.nll) { + bool coeffsChanged = false; + for (unsigned i = 0; i < RKISP1_CIF_ISP_DPF_MAX_NLF_COEFFS; ++i) { + if (overrides_.nll->coeffs[i] != config_.nll.coeff[i]) { + coeffsChanged = true; + break; + } + } + if (coeffsChanged || overrides_.nll->scaleMode != (config_.nll.scale_mode == RKISP1_CIF_ISP_NLL_SCALE_LOGARITHMIC ? 1 : 0)) { + changed = true; + } + } + return changed; +} + /** * \copydoc libcamera::ipa::Algorithm::queueRequest */ @@ -310,6 +358,9 @@ void Dpf::queueRequest(IPAContext &context, overrides_.strength->b != strengthConfig_.b)) { frameContext.dpf.update = true; } + if (checkDevModeOverridesChanged()) { + frameContext.dpf.update = true; + } } } diff --git a/src/ipa/rkisp1/algorithms/dpf.h b/src/ipa/rkisp1/algorithms/dpf.h index 1a33a8c4..b971619b 100644 --- a/src/ipa/rkisp1/algorithms/dpf.h +++ b/src/ipa/rkisp1/algorithms/dpf.h @@ -80,8 +80,13 @@ private: bool enableDpf_ = true; /* YAML master enable */ void handleEnableControl(const ControlList &controls, IPAFrameContext &frameContext, IPAContext &context) override; + void collectManualOverrides(const ControlList &controls) override; + + bool checkDevModeOverridesChanged(); + bool parseConfig(const YamlObject &tuningData) override; + bool parseSingleConfig(const YamlObject &config, rkisp1_cif_isp_dpf_config &cfg, rkisp1_cif_isp_dpf_strength_config &strength); From patchwork Tue Oct 28 21:17:45 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Rui Wang X-Patchwork-Id: 24882 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 8C3FCC32CE for ; Tue, 28 Oct 2025 21:18:54 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 246BF60891; Tue, 28 Oct 2025 22:18:54 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="Y/CfCbvy"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 41E6D60877 for ; Tue, 28 Oct 2025 22:18:51 +0100 (CET) Received: from rui-Precision-7560.local (unknown [209.216.122.90]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id F28521864; Tue, 28 Oct 2025 22:17:01 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1761686222; bh=VM7BJW0PIRTikYJfzWD7uCOHDDpHhwK0H4wJuK3onrQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Y/CfCbvy+eGsOCHiSfEEmNZCGEBHIXIKJHGN+IssLiciaWkSpV68t/cmS6zREuMbV HhC1bJ+8EJak48RzTY9Gz1P2zZ2l/S5MgtQSgs2X6pbuABg8r9NojBc2TLHi1IN1g7 xMZcTHnBwyfVS7B/0u1mCdYoh0GxLr9fpfeTjK10= From: Rui Wang To: libcamera-devel@lists.libcamera.org Cc: Rui Wang Subject: [PATCH v1 12/17] ipa: rkisp1: algorithms: dpf: manage DPF mode transitions Date: Tue, 28 Oct 2025 17:17:45 -0400 Message-ID: <20251028211751.2761420-12-rui.wang@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251028211751.2761420-1-rui.wang@ideasonboard.com> References: <20251028211751.2761420-1-rui.wang@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" Implement hysteresis-aware mode switching via processModeChange(), snapshot the current configuration when entering manual mode, and restore base tuning when returning to auto mode. The implementation includes: - processModeChange(): Detects DpfMode control changes with hysteresis to prevent rapid mode toggling (minimum 5-frame interval) - snapshotCurrentToOverrides(): Captures current config when entering manual mode so users can continue from current state - restoreAutoConfig(): Restores base or ISO-banded config when returning to auto mode, clearing all manual overrides Updates queueRequest() to handle mode transitions with appropriate logging and config restoration. Signed-off-by: Rui Wang --- src/ipa/rkisp1/algorithms/denoise.h | 14 +++++ src/ipa/rkisp1/algorithms/dpf.cpp | 76 +++++++++++++++++++++++++++ src/ipa/rkisp1/algorithms/dpf.h | 11 ++++ src/libcamera/control_ids_rkisp1.yaml | 39 ++++++++++++++ 4 files changed, 140 insertions(+) diff --git a/src/ipa/rkisp1/algorithms/denoise.h b/src/ipa/rkisp1/algorithms/denoise.h index 1a874def..c4b5b0af 100644 --- a/src/ipa/rkisp1/algorithms/denoise.h +++ b/src/ipa/rkisp1/algorithms/denoise.h @@ -20,10 +20,12 @@ class DenoiseBaseAlgorithm : public ipa::rkisp1::Algorithm protected: DenoiseBaseAlgorithm() = default; ~DenoiseBaseAlgorithm() = default; + struct EnableState { bool enabled = true; /**< Current enable state */ bool lastEnabled = true; /**< Previous enable state for change detection */ }; + bool processEnableToggle(bool value, EnableState &state); void setManualMode(bool manual) { manualMode_ = manual; } @@ -31,15 +33,27 @@ protected: void setDevMode(bool dev) { devMode_ = dev; } bool isManualMode() const { return manualMode_; } + bool isDevMode() const { return devMode_; } + unsigned computeIso(const IPAContext &context, const IPAFrameContext &frameContext) const; + template int selectIsoBand(unsigned iso, const LevelContainer &levels) const; + virtual bool parseConfig(const YamlObject &tuningData) = 0; + virtual void handleEnableControl(const ControlList &controls, IPAFrameContext &frameContext, IPAContext &context) = 0; + virtual void collectManualOverrides(const ControlList &controls) = 0; + virtual bool processModeChange(const ControlList &controls, uint32_t currentFrame) = 0; + + virtual void snapshotCurrentToOverrides() = 0; + + virtual void restoreAutoConfig(IPAContext &context, IPAFrameContext &frameContext) = 0; + private: bool manualMode_ = false; /**< Current manual/auto mode state */ bool devMode_ = false; /**< Developer mode state for advanced controls */ diff --git a/src/ipa/rkisp1/algorithms/dpf.cpp b/src/ipa/rkisp1/algorithms/dpf.cpp index cefa5da5..f6bbe3e4 100644 --- a/src/ipa/rkisp1/algorithms/dpf.cpp +++ b/src/ipa/rkisp1/algorithms/dpf.cpp @@ -338,6 +338,71 @@ bool Dpf::checkDevModeOverridesChanged() return changed; } +void Dpf::snapshotCurrentToOverrides() +{ + overrides_.clear(); + overrides_.strength = DpfStrengthSettings{ strengthConfig_.r, strengthConfig_.g, strengthConfig_.b }; + if (isDevMode()) { + DpfSpatialGreenSettings green; + std::copy_n(std::begin(config_.g_flt.spatial_coeff), RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS, green.coeffs.begin()); + overrides_.spatialGreen = green; + DpfSpatialRbSettings rb; + std::copy_n(std::begin(config_.rb_flt.spatial_coeff), RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS, rb.coeffs.begin()); + rb.size = (config_.rb_flt.fltsize == RKISP1_CIF_ISP_DPF_RB_FILTERSIZE_13x9) ? 1 : 0; + overrides_.spatialRb = rb; + overrides_.rbSize = rb.size; + DpfNllSettings nll; + std::copy_n(std::begin(config_.nll.coeff), RKISP1_CIF_ISP_DPF_MAX_NLF_COEFFS, nll.coeffs.begin()); + nll.scaleMode = (config_.nll.scale_mode == RKISP1_CIF_ISP_NLL_SCALE_LOGARITHMIC) ? 1 : 0; + overrides_.nll = nll; + } +} + +void Dpf::restoreAutoConfig(IPAContext &context, IPAFrameContext &frameContext) +{ + overrides_.clear(); + if (useIsoLevels_) { + unsigned iso = computeIso(context, frameContext); + int idx = DenoiseBaseAlgorithm::selectIsoBand(iso, isoLevels_); + if (idx >= 0) { + config_ = isoLevels_[idx].dpf; + strengthConfig_ = isoLevels_[idx].strength; + lastIsoIndex_ = idx; + } + } else { + config_ = baseConfig_; + strengthConfig_ = baseStrengthConfig_; + lastIsoIndex_ = -1; + } + frameContext.dpf.update = true; +} + +bool Dpf::processModeChange(const ControlList &controls, uint32_t currentFrame) +{ + const auto &cMode = controls.get(controls::rkisp1::DpfMode); + if (!cMode) + return false; + + bool requested = (*cMode == controls::rkisp1::DpfModeManual); + if (requested == isManualMode()) + return false; + + // Prevent rapid mode changes (hysteresis to avoid application bugs) + uint32_t framesSinceLastChange = currentFrame - lastModeChangeFrame_; + if (framesSinceLastChange < kMinModeChangeInterval && lastModeChangeFrame_ != 0) { + LOG(RkISP1Dpf, Debug) << "Ignoring rapid mode change (hysteresis): requested=" + << (requested ? "manual" : "auto") + << ", current=" << (isManualMode() ? "manual" : "auto") + << ", framesSinceLast=" << framesSinceLastChange; + return false; + } + + setManualMode(requested); + // Reset overrides if switching to auto mode , make sure the config will apply to next frame + lastModeChangeFrame_ = currentFrame; + return true; +} + /** * \copydoc libcamera::ipa::Algorithm::queueRequest */ @@ -348,6 +413,17 @@ void Dpf::queueRequest(IPAContext &context, { frameContext.dpf.update = false; handleEnableControl(controls, frameContext, context); + bool modeChanged = processModeChange(controls, frame); + if (modeChanged) { + if (isManualMode()) { + snapshotCurrentToOverrides(); + LOG(RkISP1Dpf, Info) << "DPF mode=Manual (snapshot captured)"; + } else { + restoreAutoConfig(context, frameContext); + LOG(RkISP1Dpf, Info) << "DPF mode=Auto (restored auto config)"; + } + frameContext.dpf.update = true; + } if (isManualMode()) { collectManualOverrides(controls); diff --git a/src/ipa/rkisp1/algorithms/dpf.h b/src/ipa/rkisp1/algorithms/dpf.h index b971619b..b6676203 100644 --- a/src/ipa/rkisp1/algorithms/dpf.h +++ b/src/ipa/rkisp1/algorithms/dpf.h @@ -78,6 +78,11 @@ private: std::vector isoLevels_; bool useIsoLevels_ = false; bool enableDpf_ = true; /* YAML master enable */ + int lastIsoIndex_ = -1; + + /* Mode change protection */ + uint32_t lastModeChangeFrame_ = 0; + static constexpr uint32_t kMinModeChangeInterval = 2; /* frames */ void handleEnableControl(const ControlList &controls, IPAFrameContext &frameContext, IPAContext &context) override; @@ -90,6 +95,12 @@ private: bool parseSingleConfig(const YamlObject &config, rkisp1_cif_isp_dpf_config &cfg, rkisp1_cif_isp_dpf_strength_config &strength); + + bool processModeChange(const ControlList &controls, uint32_t currentFrame) override; + + void snapshotCurrentToOverrides() override; + + void restoreAutoConfig(IPAContext &context, IPAFrameContext &frameContext) override; }; } /* namespace ipa::rkisp1::algorithms */ diff --git a/src/libcamera/control_ids_rkisp1.yaml b/src/libcamera/control_ids_rkisp1.yaml index bf7875e9..78b95447 100644 --- a/src/libcamera/control_ids_rkisp1.yaml +++ b/src/libcamera/control_ids_rkisp1.yaml @@ -82,5 +82,44 @@ controls: - name: DpfNoiseLevelLookupScaleLogarithmic value: 1 description: Logarithmic scale. + - DpfMode: + type: int32_t + direction: inout + description: | + Controls the operating mode of the Denoise Pre-Filter (DPF) algorithm. + + In Auto mode the algorithm selects parameters automatically from the + sensor tuning data and (if provided) the ISO level table. Changes in + scene brightness (analogue gain / ISO) may cause the algorithm to + re-evaluate and reprogram the hardware when an ISO band boundary is + crossed. + + In Manual mode the automatically selected parameters are frozen at + the moment the mode switch occurs (a snapshot is taken). Subsequent + per‑frame automatic ISO/tuning updates are disabled until the mode is + set back to Auto. While in Manual mode the application may modify any + of the override controls (e.g. DpfChannelStrengths, DpfGreenSpatialCoefficients, + DpfRedBlueSpatialCoefficients, DpfRbFilterSize, DpfNoiseLevelLookupCoefficients, + DpfNoiseLevelLookupScaleMode). Changes are applied immediately to hardware. + + Transition Rules: + * Auto -> Manual: The current effective (auto-selected) parameters + are captured as the initial manual override values. + * Manual -> Auto: All manual override state is discarded and the + algorithm immediately reverts to automatic tuning selection, + potentially reprogramming hardware that same frame. + + If the application switches to Manual but supplies no overrides, + the previously auto-derived parameters continue to be used unchanged. + + \\sa DpfEnable + \\sa DpfChannelStrengths + enum: + - name: DpfModeAuto + value: 0 + description: Automatic mode - algorithm selects parameters based on tuning data. + - name: DpfModeManual + value: 1 + description: Manual mode - parameters are frozen and can be overridden. ... From patchwork Tue Oct 28 21:17:46 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rui Wang X-Patchwork-Id: 24883 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 5A9F1BE080 for ; Tue, 28 Oct 2025 21:18:55 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id C9AFA6086F; Tue, 28 Oct 2025 22:18:54 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="RQexXYOe"; 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 AB71960887 for ; Tue, 28 Oct 2025 22:18:52 +0100 (CET) Received: from rui-Precision-7560.local (unknown [209.216.122.90]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 5E88B1864; Tue, 28 Oct 2025 22:17:03 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1761686224; bh=UayJ33sCZKLJm8XhFu0HRt1O7AxezNxr4NJvV45GOW8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=RQexXYOeeHqmwDJq8FKzANap7RyzFf10DGE0mWy5g1YkB48v9n934aaXctQRD4Ybq TQbE0tu15qbkp9XmnNANvA2FPz7Iq38uYBfpNW3ETZDH3yMVoEOvHHtX6Fk/Qkf9Zh Z8h59DYv4+96D3uymkr7DrtEdvs6E6Z8cWSLaiCI= From: Rui Wang To: libcamera-devel@lists.libcamera.org Cc: Rui Wang Subject: [PATCH v1 13/17] ipa: rkisp1: algorithms: dpf: apply DPF overrides Date: Tue, 28 Oct 2025 17:17:46 -0400 Message-ID: <20251028211751.2761420-13-rui.wang@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251028211751.2761420-1-rui.wang@ideasonboard.com> References: <20251028211751.2761420-1-rui.wang@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" Implement applyOverridesTo() to merge manual overrides into hardware state and add logConfigIfChanged() to make configuration updates visible in logs for debugging. applyOverridesTo() applies all collected manual overrides to the DPF configuration in manual mode: - Channel strengths (R/G/B) - Spatial coefficients (green and RB) - RB filter size - NLL coefficients and scale mode logConfigIfChanged() provides detailed logging of configuration changes, including all coefficients, strength values, ISO band selection, and control mode. Uses static state tracking to log only when changes occur. Added include for ostringstream usage in logging. Signed-off-by: Rui Wang --- src/ipa/rkisp1/algorithms/dpf.cpp | 104 ++++++++++++++++++++++++++++++ src/ipa/rkisp1/algorithms/dpf.h | 4 ++ 2 files changed, 108 insertions(+) diff --git a/src/ipa/rkisp1/algorithms/dpf.cpp b/src/ipa/rkisp1/algorithms/dpf.cpp index f6bbe3e4..75e083eb 100644 --- a/src/ipa/rkisp1/algorithms/dpf.cpp +++ b/src/ipa/rkisp1/algorithms/dpf.cpp @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -403,6 +404,109 @@ bool Dpf::processModeChange(const ControlList &controls, uint32_t currentFrame) return true; } +void Dpf::applyOverridesTo(rkisp1_cif_isp_dpf_config &cfg, + rkisp1_cif_isp_dpf_strength_config &str, + bool &anyOverride) +{ + if (!isManualMode()) + return; /* only apply overrides in manual mode */ + + if (overrides_.strength) { + str.r = overrides_.strength->r; + str.g = overrides_.strength->g; + str.b = overrides_.strength->b; + anyOverride = true; + } + if (overrides_.spatialGreen) { + for (unsigned i = 0; i < RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS; ++i) { + cfg.g_flt.spatial_coeff[i] = overrides_.spatialGreen->coeffs[i]; + } + anyOverride = true; + } + if (overrides_.spatialRb) { + for (unsigned i = 0; i < RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS; ++i) { + cfg.rb_flt.spatial_coeff[i] = overrides_.spatialRb->coeffs[i]; + } + anyOverride = true; + } + if (overrides_.rbSize) { + cfg.rb_flt.fltsize = *overrides_.rbSize ? RKISP1_CIF_ISP_DPF_RB_FILTERSIZE_13x9 + : RKISP1_CIF_ISP_DPF_RB_FILTERSIZE_9x9; + anyOverride = true; + } + if (overrides_.nll) { + for (unsigned i = 0; i < RKISP1_CIF_ISP_DPF_MAX_NLF_COEFFS; ++i) { + cfg.nll.coeff[i] = overrides_.nll->coeffs[i]; + } + cfg.nll.scale_mode = overrides_.nll->scaleMode ? RKISP1_CIF_ISP_NLL_SCALE_LOGARITHMIC + : RKISP1_CIF_ISP_NLL_SCALE_LINEAR; + anyOverride = true; + } + if (anyOverride) { + config_ = cfg; + strengthConfig_ = str; + LOG(RkISP1Dpf, Info) + << "DPF manual overrides applied: strength=" + << (int)strengthConfig_.r << "," << (int)strengthConfig_.g << "," << (int)strengthConfig_.b + << (overrides_.spatialGreen ? " gKernel" : "") + << (overrides_.spatialRb ? " rbKernel" : "") + << (overrides_.rbSize ? " rbSize" : "") + << (overrides_.nll ? " nll" : ""); + } +} + +void Dpf::logConfigIfChanged(unsigned iso, int isoIndex, bool anyOverride, const IPAFrameContext &frameContext) +{ + static rkisp1_cif_isp_dpf_config lastCfg{}; + static rkisp1_cif_isp_dpf_strength_config lastStr{}; + static bool haveLast = false; + bool cfgChanged = !haveLast || memcmp(&lastCfg, &config_, sizeof(config_)) != 0; + bool strChanged = !haveLast || memcmp(&lastStr, &strengthConfig_, sizeof(strengthConfig_)) != 0; + if (!(cfgChanged || strChanged)) + return; + std::ostringstream gs, rbs, nll; + gs << '['; + rbs << '['; + nll << '['; + for (unsigned i = 0; i < RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS; ++i) { + if (i) { + gs << ','; + rbs << ','; + } + gs << (int)config_.g_flt.spatial_coeff[i]; + rbs << (int)config_.rb_flt.spatial_coeff[i]; + } + for (unsigned i = 0; i < RKISP1_CIF_ISP_DPF_MAX_NLF_COEFFS; ++i) { + if (i) + nll << ','; + nll << config_.nll.coeff[i]; + } + gs << ']'; + rbs << ']'; + nll << ']'; + const char *modeStr = + config_.gain.mode == RKISP1_CIF_ISP_DPF_GAIN_USAGE_AWB_LSC_GAINS ? "AWB+LSC" : config_.gain.mode == RKISP1_CIF_ISP_DPF_GAIN_USAGE_AWB_GAINS ? "AWB" + : config_.gain.mode == RKISP1_CIF_ISP_DPF_GAIN_USAGE_LSC_GAINS ? "LSC" + : config_.gain.mode == RKISP1_CIF_ISP_DPF_GAIN_USAGE_NF_GAINS ? "NF" + : config_.gain.mode == RKISP1_CIF_ISP_DPF_GAIN_USAGE_NF_LSC_GAINS ? "NF+LSC" + : "disabled"; + LOG(RkISP1Dpf, Info) << "DPF config update: rb_fltsize=" + << (config_.rb_flt.fltsize == RKISP1_CIF_ISP_DPF_RB_FILTERSIZE_13x9 ? "13x9" : "9x9") + << ", nll_scale=" + << (config_.nll.scale_mode == RKISP1_CIF_ISP_NLL_SCALE_LOGARITHMIC ? "log" : "linear") + << ", gain_mode=" << modeStr + << ", strength=" << (int)strengthConfig_.r << "," << (int)strengthConfig_.g << "," << (int)strengthConfig_.b + << ", g=" << gs.str() << ", rb=" << rbs.str() << ", nll=" << nll.str() + << ", iso=" << iso + << (useIsoLevels_ && isoIndex >= 0 ? (", iso_band=" + std::to_string(isoIndex) + (lastIsoIndex_ == isoIndex ? "" : "(new)")) : "") + << ", control mode=" << (isManualMode() ? "manual" : "auto") + << ", denoise=" << (frameContext.dpf.denoise ? "enabled" : "disabled") + << (anyOverride ? " (overrides applied)" : ""); + lastCfg = config_; + lastStr = strengthConfig_; + haveLast = true; +} + /** * \copydoc libcamera::ipa::Algorithm::queueRequest */ diff --git a/src/ipa/rkisp1/algorithms/dpf.h b/src/ipa/rkisp1/algorithms/dpf.h index b6676203..8c34abcf 100644 --- a/src/ipa/rkisp1/algorithms/dpf.h +++ b/src/ipa/rkisp1/algorithms/dpf.h @@ -101,6 +101,10 @@ private: void snapshotCurrentToOverrides() override; void restoreAutoConfig(IPAContext &context, IPAFrameContext &frameContext) override; + + void applyOverridesTo(rkisp1_cif_isp_dpf_config &cfg, rkisp1_cif_isp_dpf_strength_config &str, bool &anyOverride); + + void logConfigIfChanged(unsigned iso, int isoIndex, bool anyOverride, const IPAFrameContext &frameContext); }; } /* namespace ipa::rkisp1::algorithms */ From patchwork Tue Oct 28 21:17:47 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Rui Wang X-Patchwork-Id: 24884 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 CAE96BE080 for ; Tue, 28 Oct 2025 21:18:57 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 7DAFC6089B; Tue, 28 Oct 2025 22:18:57 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="cdL9ZeCA"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 999A760887 for ; Tue, 28 Oct 2025 22:18:53 +0100 (CET) Received: from rui-Precision-7560.local (unknown [209.216.122.90]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 712861864; Tue, 28 Oct 2025 22:17:04 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1761686225; bh=1nrA08DwgiY3jQFsCGYM5LlwqCP9ZaNyZYYHOzYXTe4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=cdL9ZeCA3W3v4kTd132T1dE5gfRW8xKIwLAut7cJ7+5cYhzQIV82FBF4yasAGFM3O oZ3zVQkFpBgS33Ib/QPwDC/mnhNkImz5TXeSZ08YogeZ09lMchr57nHlmATuy+ibih XEmiev+4J5jgfhLb+4XwztAcTC9eyqOfVN48MyaM= From: Rui Wang To: libcamera-devel@lists.libcamera.org Cc: Rui Wang Subject: [PATCH v1 14/17] ipa: rkisp1: algorithms: dpf: refactor DPF prepare flow Date: Tue, 28 Oct 2025 17:17:47 -0400 Message-ID: <20251028211751.2761420-14-rui.wang@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251028211751.2761420-1-rui.wang@ideasonboard.com> References: <20251028211751.2761420-1-rui.wang@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" Split prepare() into explicit auto and manual mode branches. The auto path selects ISO bands and disables processing at high light levels, while the manual path applies user overrides before programming hardware. Key changes: - prepare() now branches to prepareAutoMode or prepareManualMode - prepareAutoMode(): Handles ISO band selection, disables DPF at ISO≤100, programs hardware with selected config - prepareManualMode(): Programs base config then applies manual overrides via applyOverridesTo() - Both modes call logConfigIfChanged() for visibility - Added debug logging to queueRequest() The refactor removes the old AWB/LSC gain mode logic, now relying on gain_mode from tuning configuration. Signed-off-by: Rui Wang --- src/ipa/rkisp1/algorithms/denoise.h | 6 ++ src/ipa/rkisp1/algorithms/dpf.cpp | 113 ++++++++++++++++++++-------- src/ipa/rkisp1/algorithms/dpf.h | 6 ++ 3 files changed, 92 insertions(+), 33 deletions(-) diff --git a/src/ipa/rkisp1/algorithms/denoise.h b/src/ipa/rkisp1/algorithms/denoise.h index c4b5b0af..e2bedc41 100644 --- a/src/ipa/rkisp1/algorithms/denoise.h +++ b/src/ipa/rkisp1/algorithms/denoise.h @@ -54,6 +54,12 @@ protected: virtual void restoreAutoConfig(IPAContext &context, IPAFrameContext &frameContext) = 0; + virtual void prepareAutoMode(IPAContext &context, const uint32_t frame, + IPAFrameContext &frameContext, RkISP1Params *params) = 0; + + virtual void prepareManualMode(IPAContext &context, const uint32_t frame, + IPAFrameContext &frameContext, RkISP1Params *params) = 0; + private: bool manualMode_ = false; /**< Current manual/auto mode state */ bool devMode_ = false; /**< Developer mode state for advanced controls */ diff --git a/src/ipa/rkisp1/algorithms/dpf.cpp b/src/ipa/rkisp1/algorithms/dpf.cpp index 75e083eb..c4597932 100644 --- a/src/ipa/rkisp1/algorithms/dpf.cpp +++ b/src/ipa/rkisp1/algorithms/dpf.cpp @@ -542,6 +542,11 @@ void Dpf::queueRequest(IPAContext &context, frameContext.dpf.update = true; } } + + LOG(RkISP1Dpf, Debug) << "queueRequest: denoise=" << frameContext.dpf.denoise + << ", update=" << frameContext.dpf.update + << (enableDpf_ ? "" : " (DPF disabled)") + << (modeChanged ? " (mode change)" : ""); } /** @@ -550,42 +555,84 @@ void Dpf::queueRequest(IPAContext &context, void Dpf::prepare(IPAContext &context, const uint32_t frame, IPAFrameContext &frameContext, RkISP1Params *params) { + // check if master denoise toggle on + if (!frameContext.dpf.denoise) { + auto cfg = params->block(); + cfg.setEnabled(false); + auto str = params->block(); + str.setEnabled(false); + return; + } + + if (isManualMode()) + prepareManualMode(context, frame, frameContext, params); + else + prepareAutoMode(context, frame, frameContext, params); +} + +void Dpf::prepareAutoMode(IPAContext &context, const uint32_t frame, + IPAFrameContext &frameContext, RkISP1Params *params) +{ + unsigned iso = computeIso(context, frameContext); + bool baseIsoSkip = iso <= 100; + + // Select different dpf config determined by iso Level + if (useIsoLevels_) { + int idx = DenoiseBaseAlgorithm::selectIsoBand(iso, isoLevels_); + if (idx >= 0 && idx != lastIsoIndex_) { + config_ = isoLevels_[idx].dpf; + strengthConfig_ = isoLevels_[idx].strength; + frameContext.dpf.update = true; + lastIsoIndex_ = idx; + } + } + // Disable dpf denoise due to high light + if (baseIsoSkip) { + auto cfg = params->block(); + cfg.setEnabled(false); + auto str = params->block(); + str.setEnabled(false); + return; + } + if (!frameContext.dpf.update && frame > 0) return; - auto config = params->block(); - config.setEnabled(frameContext.dpf.denoise); - - if (frameContext.dpf.denoise) { - *config = config_; - - const auto &awb = context.configuration.awb; - const auto &lsc = context.configuration.lsc; - - auto &mode = config->gain.mode; - - /* - * The DPF needs to take into account the total amount of - * digital gain, which comes from the AWB and LSC modules. The - * DPF hardware can be programmed with a digital gain value - * manually, but can also use the gains supplied by the AWB and - * LSC modules automatically when they are enabled. Use that - * mode of operation as it simplifies control of the DPF. - */ - if (awb.enabled && lsc.enabled) - mode = RKISP1_CIF_ISP_DPF_GAIN_USAGE_AWB_LSC_GAINS; - else if (awb.enabled) - mode = RKISP1_CIF_ISP_DPF_GAIN_USAGE_AWB_GAINS; - else if (lsc.enabled) - mode = RKISP1_CIF_ISP_DPF_GAIN_USAGE_LSC_GAINS; - else - mode = RKISP1_CIF_ISP_DPF_GAIN_USAGE_DISABLED; - } - - if (frame == 0) { - auto strengthConfig = params->block(); - strengthConfig.setEnabled(true); - *strengthConfig = strengthConfig_; + auto cfgBlock = params->block(); + cfgBlock.setEnabled(true); + *cfgBlock = config_; + + cfgBlock->gain.mode = config_.gain.mode; + + if (frameContext.dpf.update) { + auto strBlock = params->block(); + strBlock.setEnabled(true); + *strBlock = strengthConfig_; + logConfigIfChanged(iso, lastIsoIndex_, false, frameContext); + } +} + +void Dpf::prepareManualMode(IPAContext &context, const uint32_t frame, + IPAFrameContext &frameContext, RkISP1Params *params) +{ + unsigned iso = computeIso(context, frameContext); + + if (!frameContext.dpf.update && frame > 0) + return; + + auto cfgBlock = params->block(); + cfgBlock.setEnabled(true); + *cfgBlock = config_; + + cfgBlock->gain.mode = config_.gain.mode; + + if (frame == 0 || frameContext.dpf.update) { + auto strBlock = params->block(); + strBlock.setEnabled(true); + *strBlock = strengthConfig_; + bool anyOverride = false; + applyOverridesTo(*cfgBlock, *strBlock, anyOverride); + logConfigIfChanged(iso, lastIsoIndex_, anyOverride, frameContext); } } diff --git a/src/ipa/rkisp1/algorithms/dpf.h b/src/ipa/rkisp1/algorithms/dpf.h index 8c34abcf..d84ba45f 100644 --- a/src/ipa/rkisp1/algorithms/dpf.h +++ b/src/ipa/rkisp1/algorithms/dpf.h @@ -105,6 +105,12 @@ private: void applyOverridesTo(rkisp1_cif_isp_dpf_config &cfg, rkisp1_cif_isp_dpf_strength_config &str, bool &anyOverride); void logConfigIfChanged(unsigned iso, int isoIndex, bool anyOverride, const IPAFrameContext &frameContext); + + void prepareAutoMode(IPAContext &context, const uint32_t frame, + IPAFrameContext &frameContext, RkISP1Params *params) override; + + void prepareManualMode(IPAContext &context, const uint32_t frame, + IPAFrameContext &frameContext, RkISP1Params *params) override; }; } /* namespace ipa::rkisp1::algorithms */ From patchwork Tue Oct 28 21:17:48 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rui Wang X-Patchwork-Id: 24885 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 ABA4EBE080 for ; Tue, 28 Oct 2025 21:18:59 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 5CE3D60877; Tue, 28 Oct 2025 22:18:59 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="inIvD9I0"; 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 D42AC60883 for ; Tue, 28 Oct 2025 22:18:55 +0100 (CET) Received: from rui-Precision-7560.local (unknown [209.216.122.90]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 7840F1864; Tue, 28 Oct 2025 22:17:06 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1761686227; bh=73DZhhr9Oc3haxy/EfonptYIeR7fwDWTvkhUFYfGWn4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=inIvD9I0qY1Cx+hjX40LWbocgaMa0GWeE5zR40CVdbvTkzJ6zKVGiuFjZLJY2ESt4 o1cKp17nG+mjlT4Z663SoEKA/6Z8e8E4c9p4Okxcva3X7y7XzR888KH8Rk1nOtirRS v0yCBf4OQ8+mquWu8YEG7zGuQsUrMFyorpdSO8ro= From: Rui Wang To: libcamera-devel@lists.libcamera.org Cc: Rui Wang Subject: [PATCH v1 15/17] ipa: rkisp1: algorithms: dpf: expose DPF control map Date: Tue, 28 Oct 2025 17:17:48 -0400 Message-ID: <20251028211751.2761420-15-rui.wang@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251028211751.2761420-1-rui.wang@ideasonboard.com> References: <20251028211751.2761420-1-rui.wang@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" Implement getControlMap() to provide the RkISP1 DPF controls with tuning- derived defaults. The map includes: - DpfEnable (master enable toggle) - DpfMode (auto/manual mode selection) - DpfChannelStrengths (R/G/B strength values) - Developer mode controls when enabled: - Spatial coefficients (green and RB) - RB filter size (9x9 or 13x9) - NLL coefficients and scale mode - DpfIso (read-only ISO indicator) This control map is registered during init() to expose DPF controls to applications. Signed-off-by: Rui Wang --- src/ipa/rkisp1/algorithms/denoise.h | 2 ++ src/ipa/rkisp1/algorithms/dpf.cpp | 29 +++++++++++++++++++++++++++ src/ipa/rkisp1/algorithms/dpf.h | 2 ++ src/libcamera/control_ids_rkisp1.yaml | 8 ++++++++ 4 files changed, 41 insertions(+) diff --git a/src/ipa/rkisp1/algorithms/denoise.h b/src/ipa/rkisp1/algorithms/denoise.h index e2bedc41..53a0b642 100644 --- a/src/ipa/rkisp1/algorithms/denoise.h +++ b/src/ipa/rkisp1/algorithms/denoise.h @@ -60,6 +60,8 @@ protected: virtual void prepareManualMode(IPAContext &context, const uint32_t frame, IPAFrameContext &frameContext, RkISP1Params *params) = 0; + virtual ControlInfoMap::Map getControlMap() const = 0; + private: bool manualMode_ = false; /**< Current manual/auto mode state */ bool devMode_ = false; /**< Developer mode state for advanced controls */ diff --git a/src/ipa/rkisp1/algorithms/dpf.cpp b/src/ipa/rkisp1/algorithms/dpf.cpp index c4597932..59c3559e 100644 --- a/src/ipa/rkisp1/algorithms/dpf.cpp +++ b/src/ipa/rkisp1/algorithms/dpf.cpp @@ -507,6 +507,35 @@ void Dpf::logConfigIfChanged(unsigned iso, int isoIndex, bool anyOverride, const haveLast = true; } +ControlInfoMap::Map Dpf::getControlMap() const +{ + ControlInfoMap::Map map; + map[&controls::rkisp1::DpfEnable] = ControlInfo(false, true, enableDpf_); + map[&controls::rkisp1::DpfMode] = ControlInfo(controls::rkisp1::DpfModeValues, ControlValue(controls::rkisp1::DpfModeAuto)); + std::array strengthDefault = { static_cast(baseStrengthConfig_.r), static_cast(baseStrengthConfig_.g), static_cast(baseStrengthConfig_.b) }; + map[&controls::rkisp1::DpfChannelStrengths] = ControlInfo(0, 255, Span(strengthDefault)); + if (isDevMode()) { + std::array greenCoeffs; + for (unsigned i = 0; i < RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS; ++i) + greenCoeffs[i] = baseConfig_.g_flt.spatial_coeff[i]; + map[&controls::rkisp1::DpfGreenSpatialCoefficients] = ControlInfo(0, 63, Span(greenCoeffs)); + std::array rbCoeffs; + for (unsigned i = 0; i < RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS; ++i) + rbCoeffs[i] = baseConfig_.rb_flt.spatial_coeff[i]; + map[&controls::rkisp1::DpfRedBlueSpatialCoefficients] = ControlInfo(0, 63, Span(rbCoeffs)); + int32_t rbSizeDefault = (baseConfig_.rb_flt.fltsize == RKISP1_CIF_ISP_DPF_RB_FILTERSIZE_13x9) ? 1 : 0; + map[&controls::rkisp1::DpfRbFilterSize] = ControlInfo(controls::rkisp1::DpfRbFilterSizeValues, ControlValue(rbSizeDefault)); + std::array nllCoeffs; + for (unsigned i = 0; i < RKISP1_CIF_ISP_DPF_MAX_NLF_COEFFS; ++i) + nllCoeffs[i] = baseConfig_.nll.coeff[i]; + map[&controls::rkisp1::DpfNoiseLevelLookupCoefficients] = ControlInfo(0, 1023, Span(nllCoeffs)); + int32_t scaleModeDefault = (baseConfig_.nll.scale_mode == RKISP1_CIF_ISP_NLL_SCALE_LOGARITHMIC) ? 1 : 0; + map[&controls::rkisp1::DpfNoiseLevelLookupScaleMode] = ControlInfo(controls::rkisp1::DpfNoiseLevelLookupScaleModeValues, ControlValue(scaleModeDefault)); + } + map[&controls::rkisp1::DpfIso] = ControlInfo(0, 3200, 0); + return map; +} + /** * \copydoc libcamera::ipa::Algorithm::queueRequest */ diff --git a/src/ipa/rkisp1/algorithms/dpf.h b/src/ipa/rkisp1/algorithms/dpf.h index d84ba45f..5db50143 100644 --- a/src/ipa/rkisp1/algorithms/dpf.h +++ b/src/ipa/rkisp1/algorithms/dpf.h @@ -111,6 +111,8 @@ private: void prepareManualMode(IPAContext &context, const uint32_t frame, IPAFrameContext &frameContext, RkISP1Params *params) override; + + ControlInfoMap::Map getControlMap() const override; }; } /* namespace ipa::rkisp1::algorithms */ diff --git a/src/libcamera/control_ids_rkisp1.yaml b/src/libcamera/control_ids_rkisp1.yaml index 78b95447..af95a753 100644 --- a/src/libcamera/control_ids_rkisp1.yaml +++ b/src/libcamera/control_ids_rkisp1.yaml @@ -121,5 +121,13 @@ controls: - name: DpfModeManual value: 1 description: Manual mode - parameters are frozen and can be overridden. + + - DpfIso: + type: int32_t + direction: out + description: | + Estimated scene ISO value used for DPF tuning selection. Derived + from analogue gain (approx ISO = gain * 100). Provided each frame + for client awareness and debugging. Range 0..409600. ... From patchwork Tue Oct 28 21:17:49 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rui Wang X-Patchwork-Id: 24886 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 92B5BBE080 for ; Tue, 28 Oct 2025 21:19:08 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 504DB6086F; Tue, 28 Oct 2025 22:19:08 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="VAENglTG"; 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 5E2CC60808 for ; Tue, 28 Oct 2025 22:19:07 +0100 (CET) Received: from rui-Precision-7560.local (unknown [209.216.122.90]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id EC7FEE1F; Tue, 28 Oct 2025 22:17:17 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1761686238; bh=JPHlc3x2o23BpgvfoYpOddyjlh0IkwV1i6stakY1UFw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=VAENglTGD/W/7RUEC49PCMUpUqMqaCsVUgXGj1qt7g8jgIzglZ0DTpGNzLz0i245k wJSjJUb1sWueL9UF0dt7uNfLs6Lig4OnEO7wHxIj8i2rrORShGdJOV7Z+s82ScX19z kPnrUhNXe0BYPhrKbRCo4n/+aDsfWQLMBdVXaSz4= From: Rui Wang To: libcamera-devel@lists.libcamera.org Cc: Rui Wang Subject: [PATCH v1 16/17] ipa: rkisp1: algorithms: dpf: publish DPF metadata Date: Tue, 28 Oct 2025 17:17:49 -0400 Message-ID: <20251028211751.2761420-16-rui.wang@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251028211751.2761420-1-rui.wang@ideasonboard.com> References: <20251028211751.2761420-1-rui.wang@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" Implement process() and fillMetadata() to publish DPF status and current configuration values in frame metadata. This allows applications to read back the active DPF settings. Metadata published every frame: - DpfIso: Current ISO value computed from AGC gains - DpfMode: Current mode (auto/manual) - DpfChannelStrengths: Active R/G/B strength values Developer mode metadata (when enabled): - DpfGreenSpatialCoefficients: Green spatial filter coefficients - DpfRedBlueSpatialCoefficients: RB spatial filter coefficients - DpfRbFilterSize: RB filter size (9x9 or 13x9) - DpfNoiseLevelLookupCoefficients: NLL coefficients - DpfNoiseLevelLookupScaleMode: NLL scale mode (linear/log) The metadata acts as control reflection, showing applications what settings are actually active in the hardware. Signed-off-by: Rui Wang --- src/ipa/rkisp1/algorithms/denoise.h | 2 + src/ipa/rkisp1/algorithms/dpf.cpp | 58 +++++++++++++++++++++++++++++ src/ipa/rkisp1/algorithms/dpf.h | 6 +++ 3 files changed, 66 insertions(+) diff --git a/src/ipa/rkisp1/algorithms/denoise.h b/src/ipa/rkisp1/algorithms/denoise.h index 53a0b642..fdbf3445 100644 --- a/src/ipa/rkisp1/algorithms/denoise.h +++ b/src/ipa/rkisp1/algorithms/denoise.h @@ -62,6 +62,8 @@ protected: virtual ControlInfoMap::Map getControlMap() const = 0; + virtual void fillMetadata(IPAContext &context, IPAFrameContext &frameContext, ControlList &metadata) = 0; + private: bool manualMode_ = false; /**< Current manual/auto mode state */ bool devMode_ = false; /**< Developer mode state for advanced controls */ diff --git a/src/ipa/rkisp1/algorithms/dpf.cpp b/src/ipa/rkisp1/algorithms/dpf.cpp index 59c3559e..1d168d60 100644 --- a/src/ipa/rkisp1/algorithms/dpf.cpp +++ b/src/ipa/rkisp1/algorithms/dpf.cpp @@ -76,6 +76,10 @@ int Dpf::init([[maybe_unused]] IPAContext &context, << "DPF init: loaded " << isoLevels_.size() << " ISO level(s) from tuning"; } + + // init controls value from Yaml + auto dpfMap = getControlMap(); + context.ctrlMap.insert(dpfMap.begin(), dpfMap.end()); return 0; } @@ -665,6 +669,60 @@ void Dpf::prepareManualMode(IPAContext &context, const uint32_t frame, } } +/** + * \copydoc libcamera::ipa::Algorithm::process + */ +void Dpf::process(IPAContext &context, const uint32_t frame [[maybe_unused]], + IPAFrameContext &frameContext, + const rkisp1_stat_buffer *stats [[maybe_unused]], + ControlList &metadata) +{ + fillMetadata(context, frameContext, metadata); +} + +void Dpf::fillMetadata(IPAContext &context, IPAFrameContext &frameContext, ControlList &metadata) +{ + unsigned iso = computeIso(context, frameContext); + metadata.set(controls::rkisp1::DpfIso, static_cast(iso)); + metadata.set(controls::rkisp1::DpfMode, isManualMode() ? controls::rkisp1::DpfModeManual : controls::rkisp1::DpfModeAuto); + + /* Publish current values every frame (acts like controls.set reflection). */ + + /* Strength (R,G,B) - always available */ + int32_t strength[3] = { (int32_t)strengthConfig_.r, + (int32_t)strengthConfig_.g, + (int32_t)strengthConfig_.b }; + metadata.set(controls::rkisp1::DpfChannelStrengths, Span(strength)); + + if (isDevMode()) { + /* Advanced controls only in devmode */ + /* Spatial kernels */ + int32_t gCoeffs[RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS]; + int32_t rbCoeffs[RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS]; + for (unsigned i = 0; i < RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS; ++i) { + gCoeffs[i] = config_.g_flt.spatial_coeff[i]; + rbCoeffs[i] = config_.rb_flt.spatial_coeff[i]; + } + metadata.set(controls::rkisp1::DpfGreenSpatialCoefficients, + Span(gCoeffs)); + metadata.set(controls::rkisp1::DpfRedBlueSpatialCoefficients, + Span(rbCoeffs)); + + /* RB filter size (0=9x9,1=13x9) */ + int32_t fltSize = (config_.rb_flt.fltsize == RKISP1_CIF_ISP_DPF_RB_FILTERSIZE_13x9) ? 1 : 0; + metadata.set(controls::rkisp1::DpfRbFilterSize, fltSize); + + /* NLL coefficients and scale */ + int32_t nll[RKISP1_CIF_ISP_DPF_MAX_NLF_COEFFS]; + for (unsigned i = 0; i < RKISP1_CIF_ISP_DPF_MAX_NLF_COEFFS; ++i) + nll[i] = config_.nll.coeff[i]; + metadata.set(controls::rkisp1::DpfNoiseLevelLookupCoefficients, + Span(nll)); + int32_t scaleMode = (config_.nll.scale_mode == RKISP1_CIF_ISP_NLL_SCALE_LOGARITHMIC) ? 1 : 0; + metadata.set(controls::rkisp1::DpfNoiseLevelLookupScaleMode, scaleMode); + } +} + REGISTER_IPA_ALGORITHM(Dpf, "Dpf") } /* namespace ipa::rkisp1::algorithms */ diff --git a/src/ipa/rkisp1/algorithms/dpf.h b/src/ipa/rkisp1/algorithms/dpf.h index 5db50143..02f02869 100644 --- a/src/ipa/rkisp1/algorithms/dpf.h +++ b/src/ipa/rkisp1/algorithms/dpf.h @@ -30,6 +30,10 @@ public: void prepare(IPAContext &context, const uint32_t frame, IPAFrameContext &frameContext, RkISP1Params *params) override; + void process(IPAContext &context, const uint32_t frame [[maybe_unused]], + IPAFrameContext &frameContext, + const rkisp1_stat_buffer *stats [[maybe_unused]], + ControlList &metadata) override; private: struct rkisp1_cif_isp_dpf_config config_ { @@ -113,6 +117,8 @@ private: IPAFrameContext &frameContext, RkISP1Params *params) override; ControlInfoMap::Map getControlMap() const override; + + void fillMetadata(IPAContext &context, IPAFrameContext &frameContext, ControlList &metadata) override; }; } /* namespace ipa::rkisp1::algorithms */ From patchwork Tue Oct 28 21:17:50 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rui Wang X-Patchwork-Id: 24887 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 B1061BE080 for ; Tue, 28 Oct 2025 21:19:13 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 682EA6086F; Tue, 28 Oct 2025 22:19:13 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="U3T6sCWs"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id BB58860808 for ; Tue, 28 Oct 2025 22:19:11 +0100 (CET) Received: from rui-Precision-7560.local (unknown [209.216.122.90]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 6890A1122; Tue, 28 Oct 2025 22:17:22 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1761686243; bh=i7npOlrFIDZGueYrXOlERwCf1wHEChuJd7PRFw7TVyk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=U3T6sCWsnYMChmESYOlP95q/OqICLnjUAyHacyRH2cQYNLRl3Vh+p+Ll8kqZwoyCV sBag1u5SXQ2G3oF/hRyh+mJ2JYkOw3d4pZizX4rq464zSjRqRQMQRfrlYns2miZP+W /JehBNbaeYoANCMpBPNFx8VqlMFY6SQ/N5tA3u9k= From: Rui Wang To: libcamera-devel@lists.libcamera.org Cc: Rui Wang Subject: [PATCH v1 17/17] ipa: rkisp1: data: add IMX219 tuning for DPF Date: Tue, 28 Oct 2025 17:17:50 -0400 Message-ID: <20251028211751.2761420-17-rui.wang@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251028211751.2761420-1-rui.wang@ideasonboard.com> References: <20251028211751.2761420-1-rui.wang@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" Add comprehensive tuning data for IMX219 camera sensor including: - AGC metering modes and exposure modes - AWB Bayesian algorithm with color gains - CCM (Color Correction Matrix) for different color temperatures - DPCC (Defect Pixel Cluster Correction) configuration - DPF (Denoise Pre-Filter) with ISO-adaptive tuning * Domain filter spatial kernels per ISO band * Noise level functions with linear scaling * Filter strength adjustments (64-140 range) * AWB+LSC gain mode configuration * Tuning covers ISO ranges: 100, 200, 400, 800, 1600, 3200. Signed-off-by: Rui Wang --- src/ipa/rkisp1/data/imx219.yaml | 289 ++++++++++++++++++++++++++++++++ 1 file changed, 289 insertions(+) diff --git a/src/ipa/rkisp1/data/imx219.yaml b/src/ipa/rkisp1/data/imx219.yaml index 0d99cb52..d8ac0c78 100644 --- a/src/ipa/rkisp1/data/imx219.yaml +++ b/src/ipa/rkisp1/data/imx219.yaml @@ -4,8 +4,114 @@ version: 1 algorithms: - Agc: + AeMeteringMode: + MeteringCentreWeighted: [ 0, 0, 0, 0, 0, 0, 6, 8, 6, 0, 0, 8, 16, 8, 0, 0, 6, 8, 6, 0, 0, 0, 0, 0, 0 ] + MeteringSpot: [ 0, 0, 0, 0, 0, 0, 2, 4, 2, 0, 0, 4, 16, 4, 0, 0, 2, 4, 2, 0, 0, 0, 0, 0, 0 ] + MeteringMatrix: [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ] + AeExposureMode: + ExposureNormal: + exposureTime: [ 100, 10000, 15000, 30000, 60000, 120000 ] + gain: [ 1.0, 1.0, 2.0, 6.0, 6.0, 6.0 ] + ExposureShort: + exposureTime: [ 100, 5000, 10000, 20000, 120000 ] + gain: [ 4.0, 4.0, 6.0, 6.0, 6.0 ] + ExposureCustom: + exposureTime: [ 100, 10000, 30000, 60000, 120000 ] + gain: [ 6.0, 6.0, 6.0, 6.0, 6.0 ] + AeConstraintMode: + ConstraintNormal: + lower: + qLo: 0.96 + qHi: 1.0 + yTarget: 0.5 + ConstraintHighlight: + lower: + qLo: 0.98 + qHi: 1.0 + yTarget: 0.5 + upper: + qLo: 0.98 + qHi: 1.0 + yTarget: 0.8 + relativeLuminanceTarget: 0.38 + - Lux: + referenceY: 0.1100404927222605 + referenceExposureTime: 10000 + referenceAnalogueGain: 1.0 + referenceDigitalGain: 1.0 + referenceLux: 1000 - Awb: + algorithm: "bayes" + AwbMode: + AwbAuto: + lo: 2500 + hi: 8000 + AwbIncandescent: + lo: 2500 + hi: 3000 + AwbTungsten: + lo: 3000 + hi: 3500 + AwbFluorescent: + lo: 4000 + hi: 4700 + AwbIndoor: + lo: 3000 + hi: 5000 + AwbDaylight: + lo: 5500 + hi: 6500 + AwbCloudy: + lo: 6500 + hi: 8000 + priors: + - lux: 0 + ct: [ 2000, 13000 ] + probability: [ 1.0, 1.0 ] + colourGains: + - ct: 2000 + gains: [ 0.7052683546089288, 3.3036009250082587 ] + - ct: 3500 + gains: [ 1.168770453482936, 2.509410288582183 ] + - ct: 5000 + gains: [ 1.4365752047119666, 1.9519812609798948 ] + - ct: 6500 + gains: [ 1.5730690577316344, 1.7325017325017324 ] + - ct: 8000 + gains: [ 1.7298045320878743, 1.527650473571647 ] + transversePos: 0.01 + transverseNeg: 0.01 - BlackLevelCorrection: + - Ccm: + ccms: + - ct: 2000 + ccm: [ + 2.33831, 0.05412, -1.39242, -1.07561, 2.69265, -0.61704, -1.06246, -4.54151, + 6.60396, + ] + - ct: 3500 + ccm: [ + 1.94309, -0.61703, -0.32605, -0.63624, 1.98043, -0.34419, -0.06228, -1.70311, + 2.76539, + ] + - ct: 5000 + ccm: [ + 1.89171, -0.69651, -0.19519, -0.52877, 1.88519, -0.35641, -0.01512, -1.20358, + 2.21871, + ] + - ct: 6500 + ccm: [ + 1.85577, -0.70949, -0.14627, -0.47878, 1.87216, -0.39337, -0.01145, -1.02604, + 2.03749, + ] + - ct: 8000 + ccm: [ + 1.85859, -0.72919, -0.12939, -0.46756, 1.84927, -0.38171, -0.02651, -0.83045, + 1.85695, + ] + - ColorProcessing: + - GammaOutCorrection: + gamma: 2.2 - LensShadingCorrection: x-size: [ 0.0625, 0.0625, 0.0625, 0.0625, 0.0625, 0.0625, 0.0625, 0.0625 ] y-size: [ 0.0625, 0.0625, 0.0625, 0.0625, 0.0625, 0.0625, 0.0625, 0.0625 ] @@ -111,4 +217,187 @@ algorithms: 1438, 1226, 1059, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1025, 1054, 1185, 1326, 1334, 1334, ] + - DefectPixelClusterCorrection: + # DPCC (Defect Pixel Cluster Correction) algorithm + # fixed-set: true would force use of pre-defined (fixed) set; keep false for dynamic. + fixed-set: false + # Up to 3 sets may be defined. Provide at least one with conservative defaults. + # These zero / low values act as a no-op baseline; tune per sensor after characterization. + sets: + - pg-factor: # PG (Projection Gain) method factors + green: 0 # Typical range 0..15 + red-blue: 0 + ro-limits: # RO (Rank Order) limits + green: 0 # Typical range 0..63 + red-blue: 0 + rg-factor: # RG (Region Growth) factors + green: 0 # Typical range 0..15 + red-blue: 0 + rnd-offsets: # RND (Random) offsets + green: 0 # Typical range 0..31 + red-blue: 0 + rnd-threshold: # RND thresholds + green: 0 # Typical range 0..1023 + red-blue: 0 + line-threshold: # LC line thresholds + green: 0 # Typical range 0..1023 + red-blue: 0 + line-mad-factor: # LC line mean absolute deviation factor + green: 0 # Typical range 0..63 + red-blue: 0 + - Dpf: + # Master toggle (optional). Set to false to disable DPF programming. + enable: true + # Developer mode toggle (optional). Set to false to hide advanced controls from clients. + devmode: false + # Tuning parameters for rkisp1 DPF (denoise) + DomainFilter: + # 9x9 kernel for green is always 6 coefficients + g: [ 18, 13, 9, 5, 3, 1 ] + # RB: keep moderate width; IsoLevels override per ISO + rb: [ 18, 15, 12, 8, 5, 2 ] + NoiseLevelFunction: + # Base NLL: mild increase vs previous to better classify low-level noise + coeff: [ + 0, 14, 28, 42, 58, 76, 96, 120, + 148, 180, 216, 256, 300, 348, 400, 456, + 520 + ] + scale-mode: "linear" + FilterStrength: + # Base strength (was 72) -> 80 for stronger baseline denoise while preserving detail + r: 80 + g: 80 + b: 80 + Gain: + # Base gain settings - supports all 7 modes: 0=disabled, 1=NF, 2=LSC, 3=NF+LSC, 4=AWB, 5=AWB+LSC, 6=MAX + gain_mode: 5 # AWB+LSC gains for optimal denoising with color correction + nf_r_gain: 256 + nf_b_gain: 256 + nf_gr_gain: 256 + nf_gb_gain: 256 + IsoLevels: + # ISO-banded tuning for 100/200/400/800/1600/3200 (placeholders; refine with measurements). + - maxIso: 100 + DomainFilter: + g: [ 14, 10, 7, 4, 2, 1 ] + rb: [ 14, 11, 8, 4, 2, 1 ] + NoiseLevelFunction: + coeff: [ 0, 10, 20, 30, 42, 56, 72, 90, 112, 138, 168, 200, 236, 276, 320, 368, 420 ] + scale-mode: "linear" + FilterStrength: + r: 64 + g: 64 + b: 64 + Gain: + gain_mode: 5 # AWB+LSC gains + nf_r_gain: 256 + nf_b_gain: 256 + nf_gr_gain: 256 + nf_gb_gain: 256 + - maxIso: 200 + DomainFilter: + g: [ 15, 11, 8, 4, 2, 1 ] + # Low ISO: conservative RB kernel to retain fine detail + rb: [ 15, 12, 9, 5, 3, 1 ] + NoiseLevelFunction: + # Slightly steeper early ramp to suppress chroma speckle + coeff: [ + 0, 12, 24, 36, 50, 66, 84, 104, + 128, 154, 184, 216, 252, 292, 336, 384, + 440 + ] + scale-mode: "linear" + FilterStrength: + # Low ISO strength (was 64) -> 72 + r: 72 + g: 72 + b: 72 + Gain: + gain_mode: 5 # AWB+LSC gains + nf_r_gain: 256 + nf_b_gain: 256 + nf_gr_gain: 256 + nf_gb_gain: 256 + - maxIso: 400 + DomainFilter: + g: [ 16, 12, 9, 5, 3, 1 ] + rb: [ 16, 13, 10, 6, 4, 2 ] + NoiseLevelFunction: + coeff: [ 0, 16, 32, 48, 66, 86, 108, 132, 160, 192, 228, 268, 312, 360, 412, 468, 528 ] + scale-mode: "linear" + FilterStrength: + r: 88 + g: 88 + b: 88 + Gain: + gain_mode: 5 # AWB+LSC gains + nf_r_gain: 256 + nf_b_gain: 256 + nf_gr_gain: 256 + nf_gb_gain: 256 + - maxIso: 800 + DomainFilter: + g: [ 18, 14, 10, 6, 3, 1 ] + # Mid ISO: widen RB for stronger smoothing + rb: [ 18, 16, 13, 9, 5, 3 ] + NoiseLevelFunction: + coeff: [ + 0, 20, 40, 60, 82, 106, 132, 160, + 192, 228, 268, 312, 360, 412, 468, 528, + 592 + ] + scale-mode: "linear" + FilterStrength: + # Mid ISO strength (was 88) -> 100 + r: 100 + g: 100 + b: 100 + Gain: + gain_mode: 5 # AWB+LSC gains + nf_r_gain: 256 + nf_b_gain: 256 + nf_gr_gain: 256 + nf_gb_gain: 256 + - maxIso: 1600 + DomainFilter: + # Emulate 13x9-like smoothing for green (hardware green kernel size fixed; increase coeff magnitudes) + g: [ 22, 18, 13, 8, 5, 2 ] + # High ISO: wider RB kernel for stronger spatial denoise + rb: [ 20, 18, 16, 11, 7, 3 ] + NoiseLevelFunction: + coeff: [ + 0, 26, 52, 78, 106, 138, 172, 208, + 248, 292, 340, 392, 448, 508, 572, 640, + 712 + ] + scale-mode: "linear" + FilterStrength: + # High ISO strength (was 108) -> 120 + r: 120 + g: 120 + b: 120 + Gain: + gain_mode: 5 # AWB+LSC gains + nf_r_gain: 256 + nf_b_gain: 256 + nf_gr_gain: 256 + nf_gb_gain: 256 + - maxIso: 3200 + DomainFilter: + g: [ 26, 22, 16, 10, 6, 3 ] + rb: [ 24, 22, 18, 12, 8, 4 ] + NoiseLevelFunction: + coeff: [ 0, 32, 64, 96, 130, 168, 210, 256, 306, 360, 418, 480, 546, 616, 690, 768, 850 ] + scale-mode: "linear" + FilterStrength: + r: 140 + g: 140 + b: 140 + Gain: + gain_mode: 5 # AWB+LSC gains + nf_r_gain: 256 + nf_b_gain: 256 + nf_gr_gain: 256 + nf_gb_gain: 256 ...