From patchwork Tue Oct 28 17:08:30 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rui Wang X-Patchwork-Id: 24853 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 6C075BE080 for ; Tue, 28 Oct 2025 17:09:05 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 86291606DE; Tue, 28 Oct 2025 18:09:04 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="A12dPCmH"; 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 42F26606DE for ; Tue, 28 Oct 2025 18:09:02 +0100 (CET) Received: from rui-Precision-7560.local (unknown [209.216.122.90]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 346A716A7; Tue, 28 Oct 2025 18:07:13 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1761671233; bh=/XZgJDbVY0HfCPhaQ4pLnEGwoVRoIu1I+Hn5f1+ysJg=; h=From:To:Cc:Subject:Date:From; b=A12dPCmH43qPOlHrFPlVoghT26iaYP7YsP/I+tSjyTGe8VbOIZ+LKa+zKBnNPL6cb WkVoA7JQWLmBKi+b4QOESK1qlk8wpK4aP+I/ePTYVm52BBBE9T7qT+7Whj5jGoC1m8 RGIeWdIRoV2+pPIAVh7DPAKtBUZSqTFW+GIjh/Tg= From: Rui Wang To: libcamera-devel@lists.libcamera.org Cc: Rui Wang Subject: [PATCH v1 01/16] ipa: rkisp1: algorithms: add Denoise base class shell Date: Tue, 28 Oct 2025 13:08:30 -0400 Message-ID: <20251028170847.2673396-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 17:08:31 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rui Wang X-Patchwork-Id: 24854 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 7183DC32CE for ; Tue, 28 Oct 2025 17:09:07 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 18E93607F4; Tue, 28 Oct 2025 18:09:07 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="nErLtTwr"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 39D18607E5 for ; Tue, 28 Oct 2025 18:09:05 +0100 (CET) Received: from rui-Precision-7560.local (unknown [209.216.122.90]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 6220A16A7; Tue, 28 Oct 2025 18:07:16 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1761671236; bh=c4T8Q10S0W1EbJ7ObczOLcOiIE/Idualcu82YoHQtPk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=nErLtTwr20e3f9Ga2dFzW+YDQPPgfiFKN13C9Ax5dXbz2Zh1aJBWjG/Y8jnEsOBcx H4vzVsbjs/gBdM1BSioupmh05gkrBqOdfOWlio8Yk7mOfdBgU6S2dbR9BWfjiV7pX4 tVtOqMiBWxI/n8pwy3zxcXAJizJNnNNYHmQ58oYY= From: Rui Wang To: libcamera-devel@lists.libcamera.org Cc: Rui Wang Subject: [PATCH v1 02/16] ipa: rkisp1: algorithms: add Denoise ISO helpers Date: Tue, 28 Oct 2025 13:08:31 -0400 Message-ID: <20251028170847.2673396-2-rui.wang@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251028170847.2673396-1-rui.wang@ideasonboard.com> References: <20251028170847.2673396-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 17:08:32 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rui Wang X-Patchwork-Id: 24855 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 3D218BE080 for ; Tue, 28 Oct 2025 17:09:10 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id C8B75607F9; Tue, 28 Oct 2025 18:09:09 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="q9fZfeUd"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 569A0607F9 for ; Tue, 28 Oct 2025 18:09:07 +0100 (CET) Received: from rui-Precision-7560.local (unknown [209.216.122.90]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 50FEB16CD; Tue, 28 Oct 2025 18:07:18 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1761671238; bh=SsvWV+xB3JRGT/WULtXjRSmec9iz3gykbMx1sCx7sMg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=q9fZfeUd2LjzQIwOw/zso8WqbGz9MnZw6n0hPKCiAhvDO+QQY3cU47FYut6Ae022z algfT4q31DigwJar7Nn2YYY32GWkqOWRZd3r/W6SKABDP+SAInoOrFo2qk+4LYqbyr 7ZVOUKtUkfmHZzbapTaYlbzmqqWFT8dAykTTMyNk= From: Rui Wang To: libcamera-devel@lists.libcamera.org Cc: Rui Wang Subject: [PATCH v1 03/16] ipa: rkisp1: algorithms: add Denoise state toggles Date: Tue, 28 Oct 2025 13:08:32 -0400 Message-ID: <20251028170847.2673396-3-rui.wang@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251028170847.2673396-1-rui.wang@ideasonboard.com> References: <20251028170847.2673396-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 17:08:33 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rui Wang X-Patchwork-Id: 24856 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 AC8CCBE080 for ; Tue, 28 Oct 2025 17:09:12 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 5FA3B60818; Tue, 28 Oct 2025 18:09:12 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="qbQGOM36"; 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 ED32860805 for ; Tue, 28 Oct 2025 18:09:09 +0100 (CET) Received: from rui-Precision-7560.local (unknown [209.216.122.90]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 0925B1AED; Tue, 28 Oct 2025 18:07:20 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1761671241; bh=+eyGqc5p9uACWenOcU/Wnu+Z5BE8b3Mww6kmViso+Wk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=qbQGOM3668kAd1A6/r9n3b7l5VA1vJkuVJAIzJktR6fHM9SKsHj7G3T6+DsAFEbdk Ra9zqUD9LpsvLWh+s0vJ9DKT0qulVS7k4c0DkH8l3ApDhGjvnL65ZPksjaT9ZsuImJ GXxzkworPGUmFGeqcjs4AVoF/M6QxE3oozMUmhM0= From: Rui Wang To: libcamera-devel@lists.libcamera.org Cc: Rui Wang Subject: [PATCH v1 04/16] ipa: rkisp1: algorithms: Add YAML parsing helper utilities Date: Tue, 28 Oct 2025 13:08:33 -0400 Message-ID: <20251028170847.2673396-4-rui.wang@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251028170847.2673396-1-rui.wang@ideasonboard.com> References: <20251028170847.2673396-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 17:08: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: 24857 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 2115CBE080 for ; Tue, 28 Oct 2025 17:09:15 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id A2AA360821; Tue, 28 Oct 2025 18:09:13 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="XKqhKvKH"; 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 4722C607F1 for ; Tue, 28 Oct 2025 18:09:11 +0100 (CET) Received: from rui-Precision-7560.local (unknown [209.216.122.90]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 5CB4416CD; Tue, 28 Oct 2025 18:07:22 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1761671242; bh=eeCBzBL8knMj7SOHL8cPG4cTxQ4Q8BekHEC9qDqMWqo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=XKqhKvKH+Fs8M023MryMCDmt3/2nre5VGC/xYM2aW+DbBIRVsYbnr711KRkb5GbCM 2ILEoNpCXa5kY5Hm1MFKXR7VIigKxM11bsFK8AlBsi14CIsht38yyg1YXcwQSELbF7 yxqzT6aFyxvogf9qr25Qfw52yhW/YIJmzvJV6YQs= From: Rui Wang To: libcamera-devel@lists.libcamera.org Cc: Rui Wang Subject: [PATCH v1 05/16] ipa: rkisp1: algorithms: dpf: add Dpf parseSingleConfig helper Date: Tue, 28 Oct 2025 13:08:34 -0400 Message-ID: <20251028170847.2673396-5-rui.wang@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251028170847.2673396-1-rui.wang@ideasonboard.com> References: <20251028170847.2673396-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 17:08: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: 24858 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 3D8B2C32CE for ; Tue, 28 Oct 2025 17:09:16 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id B412860831; Tue, 28 Oct 2025 18:09:15 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="DisJxvO/"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id B29C06081F for ; Tue, 28 Oct 2025 18:09:12 +0100 (CET) Received: from rui-Precision-7560.local (unknown [209.216.122.90]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id C608616CD; Tue, 28 Oct 2025 18:07:23 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1761671244; bh=Trv+AgvvlCtuEhbgOacWmb+5oWJPm9tv6x2/CUl7rp8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=DisJxvO/THpsIpaJVcQOOmkJRImy/ceaA84NV1k/9h/JBOfR/hju+i4MDZjdHxJi7 8x3WBmkjgSvYhe3I3zmXctgoWbyh+83f2fKnI4b55hJ2agdrOWnN1AIgE159qSBTuR 7r9dWC5vJVAeHR4qMNnr/MzbWt/bfBDatoZu6ZeM= From: Rui Wang To: libcamera-devel@lists.libcamera.org Cc: Rui Wang Subject: [PATCH v1 06/16] ipa: rkisp1: algorithms: dpf: add Dpf parseConfig Date: Tue, 28 Oct 2025 13:08:35 -0400 Message-ID: <20251028170847.2673396-6-rui.wang@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251028170847.2673396-1-rui.wang@ideasonboard.com> References: <20251028170847.2673396-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 17:08: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: 24859 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 40F08BE080 for ; Tue, 28 Oct 2025 17:09:18 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id C492360841; Tue, 28 Oct 2025 18:09:17 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="oquti6Uy"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 008A46082B for ; Tue, 28 Oct 2025 18:09:14 +0100 (CET) Received: from rui-Precision-7560.local (unknown [209.216.122.90]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 1032116CD; Tue, 28 Oct 2025 18:07:24 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1761671245; bh=FSFjx2+KBC3XX1PCsgKL4Mp1WBBisM+Ozsd5gNs4tsw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=oquti6UyYtkkmA1vWz1S7gaAw2naDfOaB9lTT/G6qB6Z8SXVUeSJYwe/F+qE5fiYS sm+HhM/OT3S7HydAx62SizfvTOlKhl+htrC1nsYzGYBzpmKNtsc+LaTscL+rheHzi6 wV8NN2BN7i+iG6OS49mx/dX9X5pKwtAV9X9iB+n0= From: Rui Wang To: libcamera-devel@lists.libcamera.org Cc: Rui Wang Subject: [PATCH v1 07/16] ipa: rkisp1: algorithms: dpf: refactor Dpf init for tuning Date: Tue, 28 Oct 2025 13:08:36 -0400 Message-ID: <20251028170847.2673396-7-rui.wang@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251028170847.2673396-1-rui.wang@ideasonboard.com> References: <20251028170847.2673396-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 17:08: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: 24860 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 73E1DC32CE for ; Tue, 28 Oct 2025 17:09:19 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 0925E60844; Tue, 28 Oct 2025 18:09:19 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="PAdCTdBY"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 27B086080D for ; Tue, 28 Oct 2025 18:09:15 +0100 (CET) Received: from rui-Precision-7560.local (unknown [209.216.122.90]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 4638316CD; Tue, 28 Oct 2025 18:07:26 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1761671246; bh=jV7eEV2O6t6DQUr2PmLI8Lue2KoK1wOeHnNaSiDF37A=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=PAdCTdBYed5eb4nFTTyAlV9LC5u5wxp2WrZwFeZxjSurMtvGlmrJl2Aziw19ztzCU KkRxL3neMQLmlw1YuL3uHD/HN0itswDzkgfelT39RkBWmxOK36NUT9Hwj3U7K0FgVv UgTYyUcbeYheub+22CGFre9v9UD7nhLzZUAULkSs= From: Rui Wang To: libcamera-devel@lists.libcamera.org Cc: Rui Wang Subject: [PATCH v1 08/16] ipa: rkisp1: controls: define control block Date: Tue, 28 Oct 2025 13:08:37 -0400 Message-ID: <20251028170847.2673396-8-rui.wang@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251028170847.2673396-1-rui.wang@ideasonboard.com> References: <20251028170847.2673396-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 17:08: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: 24861 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 E11A6BE080 for ; Tue, 28 Oct 2025 17:09:20 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 740F660840; Tue, 28 Oct 2025 18:09:20 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="HF7coTxD"; 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 440286080D for ; Tue, 28 Oct 2025 18:09:16 +0100 (CET) Received: from rui-Precision-7560.local (unknown [209.216.122.90]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 61DDE16CD; Tue, 28 Oct 2025 18:07:27 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1761671247; bh=zNy83JNJ07WUcf2XuDb7bWd83wJfMp4DWSgffFPJik8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=HF7coTxD0ryjE46O1YkufM6TKI3gm+iDcgg81e+lQtGWUn3bKq5R7OzSfnkdgdhcM 0AVOqJzGnEBB7k3Le1rfrbTcIL1K14kVFmkX8ggrtpeSd8v/x0/Aa0I8x5uX4jKZ4H RP74bJTNaJ44Wgxd88PW2GtdUFREAHmYr246BCVY= From: Rui Wang To: libcamera-devel@lists.libcamera.org Cc: Rui Wang Subject: [PATCH v1 09/16] ipa: rkisp1: algorithms: dpf: handle DPF enable toggle Date: Tue, 28 Oct 2025 13:08:38 -0400 Message-ID: <20251028170847.2673396-9-rui.wang@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251028170847.2673396-1-rui.wang@ideasonboard.com> References: <20251028170847.2673396-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 17:08: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: 24862 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 00FAFC3259 for ; Tue, 28 Oct 2025 17:09:22 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 196B26083A; Tue, 28 Oct 2025 18:09:21 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="S9Kw8by4"; 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 7532D60806 for ; Tue, 28 Oct 2025 18:09:17 +0100 (CET) Received: from rui-Precision-7560.local (unknown [209.216.122.90]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 8B23F16A7; Tue, 28 Oct 2025 18:07:28 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1761671248; bh=umoNTAq5Rg0Hhy6p7LhEHZo9ugpgiKdSfwh1KxILWj0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=S9Kw8by4xuJM9LiEbV8bOynW7phT1lHCYsscSB3eyKsPOXPPaTHk8xRBZN6HAFE3n WUMpEgDpayEEdVOTJTLMgPtEdem85bGH5Em3urNWFZm6mipI7l+9d1u5nxE0RyITdz jL7VlYVG4bFRB6OF4wGorAgWBNk0CopI62SE96rU= From: Rui Wang To: libcamera-devel@lists.libcamera.org Cc: Rui Wang Subject: [PATCH v1 10/16] ipa: rkisp1: algorithms: dpf: collect DPF manual overrides Date: Tue, 28 Oct 2025 13:08:39 -0400 Message-ID: <20251028170847.2673396-10-rui.wang@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251028170847.2673396-1-rui.wang@ideasonboard.com> References: <20251028170847.2673396-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 17:08: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: 24863 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 EAF44BE080 for ; Tue, 28 Oct 2025 17:09:22 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 2560F6085B; Tue, 28 Oct 2025 18:09:22 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="RxZT9WRz"; 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 A966760840 for ; Tue, 28 Oct 2025 18:09:18 +0100 (CET) Received: from rui-Precision-7560.local (unknown [209.216.122.90]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id B97D016A7; Tue, 28 Oct 2025 18:07:29 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1761671250; bh=QPqeJ3qV3kxcVH0Yz7W/FsO3VOQKFjM7mgOFJmo0700=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=RxZT9WRznN5vs+QKLowacY6Sz4M8qrbxNjL+VgV+t8vpZT1WMsjLZh2dMcXBvp6Wt Xc4tWJLG/WJPI+qFh4tFq9I2xvIULnyjCWnfPcVlJiCkde2n/5jyXfCHi+yRcLsX9v ZjcN6jtQqfewy1e8PU8qCJ08YfZ5yrBgIJNebmpY= From: Rui Wang To: libcamera-devel@lists.libcamera.org Cc: Rui Wang Subject: [PATCH v1 11/16] ipa: rkisp1: algorithms: dpf: detect DPF dev overrides Date: Tue, 28 Oct 2025 13:08:40 -0400 Message-ID: <20251028170847.2673396-11-rui.wang@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251028170847.2673396-1-rui.wang@ideasonboard.com> References: <20251028170847.2673396-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 17:08:41 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Rui Wang X-Patchwork-Id: 24864 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 2D622BE080 for ; Tue, 28 Oct 2025 17:09:26 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id D31F860865; Tue, 28 Oct 2025 18:09:25 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="Td07sbgS"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D097A6080D for ; Tue, 28 Oct 2025 18:09:19 +0100 (CET) Received: from rui-Precision-7560.local (unknown [209.216.122.90]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id E28CB16A7; Tue, 28 Oct 2025 18:07:30 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1761671251; bh=VM7BJW0PIRTikYJfzWD7uCOHDDpHhwK0H4wJuK3onrQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Td07sbgSA3yaofWjXCaZt8w2wLMnStzMmaNf0b0Spfo5p/6d0VlqPVp+SSZDd3/hs bcvrFNOYbnSolDhN5rLUgpP2igfg7iNwabfsjUKbQYqd9e2WpkO+bmTbFRufA+gwTY P6dyGCEF/VL8zxQPWXCY5b04WSrOQp9nHslp7HDE= From: Rui Wang To: libcamera-devel@lists.libcamera.org Cc: Rui Wang Subject: [PATCH v1 12/16] ipa: rkisp1: algorithms: dpf: manage DPF mode transitions Date: Tue, 28 Oct 2025 13:08:41 -0400 Message-ID: <20251028170847.2673396-12-rui.wang@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251028170847.2673396-1-rui.wang@ideasonboard.com> References: <20251028170847.2673396-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 17:08: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: 24865 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 04F51BE080 for ; Tue, 28 Oct 2025 17:09:28 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 82FA16086D; Tue, 28 Oct 2025 18:09:27 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="STAh135q"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id DCF1B60831 for ; Tue, 28 Oct 2025 18:09:20 +0100 (CET) Received: from rui-Precision-7560.local (unknown [209.216.122.90]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 074981AED; Tue, 28 Oct 2025 18:07:31 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1761671252; bh=UayJ33sCZKLJm8XhFu0HRt1O7AxezNxr4NJvV45GOW8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=STAh135q+Ws+ZNNbP/DigkBHg7jZugz13qIROKJR51FvpBKUFR4BwoL/XwJSglAs0 X3L3YYKl7xmCJH1EWdb4PHxOXGXx+6ypT+KlcZp+oHUxTT4oeni1SBVTf6+lL7zJcL UQ/tKxb1nDc/2GY9RIGbpyAL1YcPyfYaJ03fLauc= From: Rui Wang To: libcamera-devel@lists.libcamera.org Cc: Rui Wang Subject: [PATCH v1 13/16] ipa: rkisp1: algorithms: dpf: apply DPF overrides Date: Tue, 28 Oct 2025 13:08:42 -0400 Message-ID: <20251028170847.2673396-13-rui.wang@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251028170847.2673396-1-rui.wang@ideasonboard.com> References: <20251028170847.2673396-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 17:08:43 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Rui Wang X-Patchwork-Id: 24866 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 B6D04C3259 for ; Tue, 28 Oct 2025 17:09:28 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 5DB586086B; Tue, 28 Oct 2025 18:09:28 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="BC3PP+Z9"; 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 0BC8C6081F for ; Tue, 28 Oct 2025 18:09:22 +0100 (CET) Received: from rui-Precision-7560.local (unknown [209.216.122.90]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 2B75A1AED; Tue, 28 Oct 2025 18:07:33 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1761671253; bh=Npt5a9rbsw83U7S/mpp/5ebkIYCc8pz+R6JnxrlzhRE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=BC3PP+Z9FlXzKMG8cQBCWVfto7Ciy9PLThHPHAzjGFhjlnNuXTBxehbhDZPjvC5Ta t+5UaTQztKB5ko7qhE0qkDneGBE/IAohytYwhaAQqUuP+21QECc14g+hgmufdlM9es m7KRVvSnMFdi7gy0A4/pPzwd5Vh69yGHDWyIBDz0= From: Rui Wang To: libcamera-devel@lists.libcamera.org Cc: Rui Wang Subject: [PATCH v1 14/16] ipa: rkisp1: algorithms: dpf: refactor DPF prepare flow Date: Tue, 28 Oct 2025 13:08:43 -0400 Message-ID: <20251028170847.2673396-14-rui.wang@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251028170847.2673396-1-rui.wang@ideasonboard.com> References: <20251028170847.2673396-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..dfef2f91 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 (frame == 0 || 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 17:08: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: 24867 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 E0C96BE080 for ; Tue, 28 Oct 2025 17:09:29 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 7973B60869; Tue, 28 Oct 2025 18:09:29 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="eDDB3MAB"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 2972D6082B for ; Tue, 28 Oct 2025 18:09:23 +0100 (CET) Received: from rui-Precision-7560.local (unknown [209.216.122.90]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 39EF01AED; Tue, 28 Oct 2025 18:07:34 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1761671254; bh=d0nvt/XBK0ElIAIDPInJJPHFSpfeojs94gqBvNzvrqs=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=eDDB3MABaKAm63IL3X5lYOJO9ZqXBaBO//WTWvB3uLf7S/rWRMdSRkqLiNl3bJplq srdhxhCFupOTzCqX+L5tuBzVhPX9YZjgE6VouRNXyRHFY/X61zy775t2EGtlMaLG1S AorMDUA10dhaTbVU9LXRVS3KuoFIfMRyAxYwq47Y= From: Rui Wang To: libcamera-devel@lists.libcamera.org Cc: Rui Wang Subject: [PATCH v1 15/16] ipa: rkisp1: algorithms: dpf: expose DPF control map Date: Tue, 28 Oct 2025 13:08:44 -0400 Message-ID: <20251028170847.2673396-15-rui.wang@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251028170847.2673396-1-rui.wang@ideasonboard.com> References: <20251028170847.2673396-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 dfef2f91..0bbcc9be 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 17:08:45 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rui Wang X-Patchwork-Id: 24868 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 F0BDDC32CE for ; Tue, 28 Oct 2025 17:09:30 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 9E54E60877; Tue, 28 Oct 2025 18:09:30 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="ZNg9YMuK"; 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 2744560821 for ; Tue, 28 Oct 2025 18:09:24 +0100 (CET) Received: from rui-Precision-7560.local (unknown [209.216.122.90]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 43AF11AED; Tue, 28 Oct 2025 18:07:35 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1761671255; bh=Q9EXH0Yz80bsWfDWXc01Hxmb2t+2I36tSbPPbbRbnuw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ZNg9YMuK7PuqZCBL1zJsiIkuASndOEQjcLvKsmdlb3mw98OaLo2N2qlfpYri7gUXW NHLAneThQd+txwnpAJIOzmZC+nziDDrfDQyOq4R1oi4qOBzQ1FScDdW2RvAQXrusSR yLxcHv4fbBqihz0FPBx/SM1RAmAG3VAmpGxYfFBo= From: Rui Wang To: libcamera-devel@lists.libcamera.org Cc: Rui Wang Subject: [PATCH v1 16/16] ipa: rkisp1: algorithms: dpf: publish DPF metadata Date: Tue, 28 Oct 2025 13:08:45 -0400 Message-ID: <20251028170847.2673396-16-rui.wang@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251028170847.2673396-1-rui.wang@ideasonboard.com> References: <20251028170847.2673396-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 0bbcc9be..734f751e 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 */