From patchwork Tue Nov 25 00: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: 25168 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 1AC4BC3257 for ; Tue, 25 Nov 2025 00:09:03 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 95C2060A8A; Tue, 25 Nov 2025 01:09:02 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="ekordYg9"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 0FCA4608CF for ; Tue, 25 Nov 2025 01:09:01 +0100 (CET) Received: from rui-Precision-7560.local (unknown [IPv6:2607:fea8:935b:7220:cb34:a7b8:53d:5466]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 068FAC75; Tue, 25 Nov 2025 01:06:51 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1764029212; bh=c9z/FY4uG8M2ilmBF1G6vgwpSHEjI/ddJW8v9kh5h70=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ekordYg9aV6bWrcVLgxrrDWpz0yBF3AUScMXBKa4sTO+rRucl6SLxYvE7U72VvBdQ YnguZVHlsMf0HhjaTjdcCXiVRnboDkQHwWGFTLPbjGZrpizRCma57WVN83rXeE+78Q He2pQIiS5o5lsy/S1CvV6nNZAMsVy9HVW/IHFU6U= From: Rui Wang To: libcamera-devel@lists.libcamera.org Cc: Rui Wang Subject: [PATCH v1 01/11] ipa: rkisp1: algorithms: Add exposure index computation helpers Date: Mon, 24 Nov 2025 19:08:38 -0500 Message-ID: <20251125000848.4103786-2-rui.wang@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251125000848.4103786-1-rui.wang@ideasonboard.com> References: <20251125000848.4103786-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 computeExposureIndex() to derive an exposure index value from the AGC gain (approximately exposureIndex = gain * 100), and selectExposureIndexBand() to search through a container of exposure index levels and select the appropriate tuning band for the current exposure index. These helpers provide reusable functionality for exposure-index-banded tuning in denoising algorithms, enabling more precise algorithm configuration based on lighting conditions. Signed-off-by: Rui Wang --- src/ipa/rkisp1/algorithms/denoise.h | 55 +++++++++++++++++++++++++++++ 1 file changed, 55 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..8907dc4e --- /dev/null +++ b/src/ipa/rkisp1/algorithms/denoise.h @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2025, Ideas On Board + * + * RkISP1 Denoising Algorithms Base Class + */ + +#pragma once + +#include "../ipa_context.h" + +#include "algorithm.h" + +namespace libcamera { + +namespace ipa::rkisp1::algorithms { + +class DenoiseBaseAlgorithm : public ipa::rkisp1::Algorithm +{ +protected: + DenoiseBaseAlgorithm() = default; + ~DenoiseBaseAlgorithm() = default; + + virtual uint32_t computeExposureIndex(const IPAContext &context, + const IPAFrameContext &frameContext) const; + template + uint32_t selectExposureIndexBand(unsigned exposureIndex, + const LevelContainer &levels) const; +}; + +inline unsigned DenoiseBaseAlgorithm::computeExposureIndex(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 +uint32_t DenoiseBaseAlgorithm::selectExposureIndexBand(unsigned exposureIndex, + const LevelContainer &levels) const +{ + if (levels.empty()) + return -1; + uint32_t idx = 0; + while (idx < static_cast(levels.size()) && exposureIndex > levels[idx].maxExposureIndex) + ++idx; + if (idx >= static_cast(levels.size())) + idx = static_cast(levels.size()) - 1; + return idx; +} + +} /* namespace ipa::rkisp1::algorithms */ + +} /* namespace libcamera */ From patchwork Tue Nov 25 00: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: 25169 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 01580C3257 for ; Tue, 25 Nov 2025 00:09:06 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 99B5A60A80; Tue, 25 Nov 2025 01:09:06 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="dsPn0jdT"; 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 38D2D608CF for ; Tue, 25 Nov 2025 01:09:05 +0100 (CET) Received: from rui-Precision-7560.local (unknown [IPv6:2607:fea8:935b:7220:cb34:a7b8:53d:5466]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 3482D1648; Tue, 25 Nov 2025 01:06:56 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1764029216; bh=IMB0LPoQqYANqR/0AvPU4uc9w6SsnqDnZqhk1APmWQk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=dsPn0jdTT3Q3FVwWQXYJArNtQkwpI4ZxiBE9KdUyOTbTh/yq3tGVRf0SVmDQIXgVE jLWtzj33SIA1MPmDaFVNIBrm1lGqxqAXnwTtJUueaZ2B0AnDC55lmUa9LMwxjfK8az bSFab+k55gj7yFi1Gf0ecqtga88XjmtEdzShfrZ0= From: Rui Wang To: libcamera-devel@lists.libcamera.org Cc: Rui Wang Subject: [PATCH v1 02/11] ipa: rkisp1: algorithms: dpf: init Dpf tuning config Date: Mon, 24 Nov 2025 19:08:39 -0500 Message-ID: <20251125000848.4103786-3-rui.wang@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251125000848.4103786-1-rui.wang@ideasonboard.com> References: <20251125000848.4103786-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 gain 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 exposure index -banded overrides. 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. 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-exposure-gain-level configuration blocks. The init method now: - Calls parseConfig() to load tuning data - Logs the parsed base configuration - Caches base config for manual mode restore - exposure levels are sorted by exposure index threshold for efficient band selection at runtime. Signed-off-by: Rui Wang --- src/ipa/rkisp1/algorithms/denoise.h | 11 +- src/ipa/rkisp1/algorithms/dpf.cpp | 186 ++++++++++++++++++++++++---- src/ipa/rkisp1/algorithms/dpf.h | 24 +++- 3 files changed, 195 insertions(+), 26 deletions(-) diff --git a/src/ipa/rkisp1/algorithms/denoise.h b/src/ipa/rkisp1/algorithms/denoise.h index 8907dc4e..abd08cba 100644 --- a/src/ipa/rkisp1/algorithms/denoise.h +++ b/src/ipa/rkisp1/algorithms/denoise.h @@ -20,12 +20,21 @@ class DenoiseBaseAlgorithm : public ipa::rkisp1::Algorithm protected: DenoiseBaseAlgorithm() = default; ~DenoiseBaseAlgorithm() = default; - + virtual void setDevMode(bool dev) { devMode_ = dev; } + virtual bool isDevMode() const { return devMode_; } virtual uint32_t computeExposureIndex(const IPAContext &context, const IPAFrameContext &frameContext) const; template uint32_t selectExposureIndexBand(unsigned exposureIndex, const LevelContainer &levels) const; + virtual bool parseConfig([[maybe_unused]] const YamlObject &tuningData) + { + return true; + } + +private: + /**< Developer mode state for advanced controls */ + bool devMode_ = false; }; inline unsigned DenoiseBaseAlgorithm::computeExposureIndex(const IPAContext &context, diff --git a/src/ipa/rkisp1/algorithms/dpf.cpp b/src/ipa/rkisp1/algorithms/dpf.cpp index 39f3e461..dc0a361c 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 @@ -37,7 +38,7 @@ namespace ipa::rkisp1::algorithms { LOG_DEFINE_CATEGORY(RkISP1Dpf) Dpf::Dpf() - : config_({}), strengthConfig_({}) + : config_({}), strengthConfig_({}), baseConfig_({}), baseStrengthConfig_({}) { } @@ -47,14 +48,130 @@ Dpf::Dpf() int Dpf::init([[maybe_unused]] IPAContext &context, const YamlObject &tuningData) { - std::vector values; + /* Parse tuning block */ + if (!parseConfig(tuningData)) + 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-exposure index) YAML configuration for restoration after manual mode. */ + baseConfig_ = config_; + baseStrengthConfig_ = strengthConfig_; + + /* Optional exposure index-banded tuning */ + if (useExposureIndexLevels_) { + LOG(RkISP1Dpf, Info) + << "DPF init: loaded " << exposureIndexLevels_.size() + << " exposureIndex level(s) from tuning"; + } + + /* Optional mode tuning */ + if (!modes_.empty()) { + LOG(RkISP1Dpf, Info) + << "DPF init: loaded " << modes_.size() + << " mode(s) from tuning"; + } + + return 0; +} + +bool Dpf::parseConfig(const YamlObject &tuningData) +{ + /* Parse base config */ + if (!parseSingleConfig(tuningData, config_, strengthConfig_)) + return false; + + baseConfig_ = config_; + baseStrengthConfig_ = strengthConfig_; + + /* Optional developer mode flag (default true). If false, only basic manual controls available. */ + bool devMode = tuningData["devmode"].get().value_or(true); + setDevMode(devMode); + + /* Parse exposure index levels */ + if (tuningData.contains("ExposureIndexLevels")) { + useExposureIndexLevels_ = true; + exposureIndexLevels_.clear(); + for (const auto &entry : tuningData["ExposureIndexLevels"].asList()) { + std::optional maxExposureIndexOpt = + entry["maxExposureIndex"].get(); + if (!maxExposureIndexOpt) { + LOG(RkISP1Dpf, Error) << "ExposureIndexLevels entry missing maxExposureIndex"; + continue; + } + ExposureIndexLevelConfig lvl{}; + lvl.maxExposureIndex = *maxExposureIndexOpt; + if (!parseSingleConfig(entry, lvl.dpf, lvl.strength)) + continue; + exposureIndexLevels_.push_back(lvl); + } + std::sort(exposureIndexLevels_.begin(), exposureIndexLevels_.end(), + [](const ExposureIndexLevelConfig &a, const ExposureIndexLevelConfig &b) { + return a.maxExposureIndex < b.maxExposureIndex; + }); + } + + /* Parse modes */ + if (tuningData.contains("NoiseReductionMode")) { + modes_.clear(); + for (const auto &entry : tuningData["NoiseReductionMode"].asList()) { + std::optional typeOpt = + entry["type"].get(); + if (!typeOpt) { + LOG(RkISP1Dpf, Error) << "Modes entry missing type"; + continue; + } + + int32_t modeValue; + if (*typeOpt == "minimal") { + modeValue = controls::draft::NoiseReductionModeMinimal; + } else if (*typeOpt == "highquality") { + modeValue = controls::draft::NoiseReductionModeHighQuality; + } else if (*typeOpt == "fast") { + modeValue = controls::draft::NoiseReductionModeFast; + } else if (*typeOpt == "zsl") { + modeValue = controls::draft::NoiseReductionModeZSL; + } else { + LOG(RkISP1Dpf, Error) << "Unknown mode type: " << *typeOpt; + continue; + } + ModeConfig mode{}; + mode.modeValue = modeValue; + if (!parseSingleConfig(entry, mode.dpf, mode.strength)) + continue; + modes_.push_back(mode); + } + } + + return true; +} + +bool Dpf::parseSingleConfig(const YamlObject &tuningData, + rkisp1_cif_isp_dpf_config &config, + rkisp1_cif_isp_dpf_strength_config &strengthConfig) +{ + 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. */ + if (!tuningData.contains("DomainFilter")) { + LOG(RkISP1Dpf, Error) << "DomainFilter section missing"; + return false; + } const YamlObject &dFObject = tuningData["DomainFilter"]; - /* * For the green component, we have the 9x9 kernel specified * as 6 coefficients: @@ -78,14 +195,14 @@ int Dpf::init([[maybe_unused]] IPAContext &context, << "Invalid 'DomainFilter:g': expected " << RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS << " elements, got " << values.size(); - return -EINVAL; + return false; } std::copy_n(values.begin(), values.size(), - std::begin(config_.g_flt.spatial_coeff)); + std::begin(config.g_flt.spatial_coeff)); - config_.g_flt.gr_enable = true; - config_.g_flt.gb_enable = true; + config.g_flt.gr_enable = true; + config.g_flt.gb_enable = true; /* * For the red and blue components, we have the 13x9 kernel specified @@ -116,24 +233,28 @@ int Dpf::init([[maybe_unused]] IPAContext &context, << RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS - 1 << " or " << RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS << " elements, got " << values.size(); - return -EINVAL; + return false; } - 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; + 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)); + std::begin(config.rb_flt.spatial_coeff)); - config_.rb_flt.r_enable = true; - config_.rb_flt.b_enable = true; + 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). */ + if (!tuningData.contains("NoiseLevelFunction")) { + LOG(RkISP1Dpf, Error) << "NoiseLevelFunction section missing"; + return false; + } const YamlObject &rFObject = tuningData["NoiseLevelFunction"]; std::vector nllValues; @@ -143,32 +264,49 @@ int Dpf::init([[maybe_unused]] IPAContext &context, << "Invalid 'RangeFilter:coeff': expected " << RKISP1_CIF_ISP_DPF_MAX_NLF_COEFFS << " elements, got " << nllValues.size(); - return -EINVAL; + return false; } std::copy_n(nllValues.begin(), nllValues.size(), - std::begin(config_.nll.coeff)); + 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; + config.nll.scale_mode = RKISP1_CIF_ISP_NLL_SCALE_LINEAR; } else if (scaleMode == "logarithmic") { - config_.nll.scale_mode = RKISP1_CIF_ISP_NLL_SCALE_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; + return false; } + if (!tuningData.contains("Gain")) { + LOG(RkISP1Dpf, Error) << "Gain section missing"; + return false; + } + const YamlObject &gObject = tuningData["Gain"]; + + config.gain.mode = + gObject["gain_mode"].get().value_or( + RKISP1_CIF_ISP_DPF_GAIN_USAGE_AWB_LSC_GAINS); + config.gain.nf_r_gain = gObject["nf_r_gain"].get().value_or(256); + config.gain.nf_b_gain = gObject["nf_b_gain"].get().value_or(256); + config.gain.nf_gr_gain = gObject["nf_gr_gain"].get().value_or(256); + config.gain.nf_gb_gain = gObject["nf_gb_gain"].get().value_or(256); + + if (!tuningData.contains("FilterStrength")) { + LOG(RkISP1Dpf, Error) << "FilterStrength section missing"; + return false; + } 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; + strengthConfig.r = fSObject["r"].get().value_or(64); + strengthConfig.g = fSObject["g"].get().value_or(64); + strengthConfig.b = fSObject["b"].get().value_or(64); + return true; } /** diff --git a/src/ipa/rkisp1/algorithms/dpf.h b/src/ipa/rkisp1/algorithms/dpf.h index 2dd8cd36..8691932d 100644 --- a/src/ipa/rkisp1/algorithms/dpf.h +++ b/src/ipa/rkisp1/algorithms/dpf.h @@ -10,12 +10,13 @@ #include #include "algorithm.h" +#include "denoise.h" namespace libcamera { namespace ipa::rkisp1::algorithms { -class Dpf : public Algorithm +class Dpf : public DenoiseBaseAlgorithm { public: Dpf(); @@ -32,6 +33,27 @@ 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 ExposureIndexLevelConfig { + uint32_t maxExposureIndex; /* inclusive upper bound */ + struct rkisp1_cif_isp_dpf_config dpf; + struct rkisp1_cif_isp_dpf_strength_config strength; + }; + struct ModeConfig { + int32_t modeValue; + struct rkisp1_cif_isp_dpf_config dpf; + struct rkisp1_cif_isp_dpf_strength_config strength; + }; + + std::vector exposureIndexLevels_; + std::vector modes_; + bool useExposureIndexLevels_ = false; + + bool parseConfig(const YamlObject &tuningData) override; + bool parseSingleConfig(const YamlObject &tuningData, + rkisp1_cif_isp_dpf_config &config, + rkisp1_cif_isp_dpf_strength_config &strengthConfig); }; } /* namespace ipa::rkisp1::algorithms */ From patchwork Tue Nov 25 00: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: 25170 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 01AF2C3257 for ; Tue, 25 Nov 2025 00:09:10 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id B653460A8B; Tue, 25 Nov 2025 01:09:10 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="oRmjqTgL"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 489BC608CF for ; Tue, 25 Nov 2025 01:09:09 +0100 (CET) Received: from rui-Precision-7560.local (unknown [IPv6:2607:fea8:935b:7220:cb34:a7b8:53d:5466]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 735ED1785; Tue, 25 Nov 2025 01:07:00 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1764029220; bh=UkCapkV5odQxTizNmJzAW0W4EduQbmEB8OJC9PPaCu8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=oRmjqTgLfHAobqYV0qdCiVGfsl6qJbda7XUXC2VV9h8hUIm1yGFTxj3IaX07Fln8q my+21rjM0irJQsu85afoR02lox0WxiYQp/sM3+nTPKO2xWTBTGvRB4l8pxceUU3uZ/ 1OZO2db2ivqner9/ZeSe7Ii95H4zCc41Fi7GCg4k= From: Rui Wang To: libcamera-devel@lists.libcamera.org Cc: Rui Wang Subject: [PATCH v1 03/11] ipa: rkisp1: controls: define control block Date: Mon, 24 Nov 2025 19:08:40 -0500 Message-ID: <20251125000848.4103786-4-rui.wang@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251125000848.4103786-1-rui.wang@ideasonboard.com> References: <20251125000848.4103786-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 | 73 +++++++++++++++++++++++++++ src/libcamera/control_ranges.yaml | 4 +- 3 files changed, 77 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..3e008ee4 --- /dev/null +++ b/src/libcamera/control_ids_rkisp1.yaml @@ -0,0 +1,73 @@ +# 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 --- + - DenoiseMode: + type: int32_t + direction: inout + description: | + Controls the operating mode of the rkisp1 denoise pipeline. This setting is + consumed by the DPF module and any additional denoise algorithms that honour + the common mode state exposed here. + + In Disabled mode (default) all denoise processing stages are disabled. This + bypasses noise reduction and surfaces raw sensor data. Other denoise-related + controls are ignored in this mode. + + In Auto mode each denoise algorithm selects parameters automatically from the + sensor tuning data and (if provided) the exposure index level table. Changes in + scene brightness (analogue gain / exposure index) may cause algorithms to + re-evaluate and reprogram hardware when an exposure index 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 + updates are disabled until the mode is set back to Auto. While in Manual mode + the application may modify any algorithm-specific override controls (for DPF: + DpfChannelStrengths, DpfGreenSpatialCoefficients, DpfRedBlueSpatialCoefficients, + DpfRbFilterSize, DpfNoiseLevelLookupCoefficients, DpfNoiseLevelLookupScaleMode). + Individual denoise modules apply changes immediately to hardware. + + In Reduction mode the algorithms use predefined noise reduction settings based + on the active NoiseReductionMode control. This provides optimized presets for + different noise reduction levels (e.g., minimal, high-quality, fast) without + manual parameter tuning. + + 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. + * Auto/Manual -> Reduction: Switches to using reduction mode configs + based on the current NoiseReductionMode setting. + * Reduction -> Auto/Manual: Reverts to the specified mode, discarding + reduction-specific state. + + If the application switches to Manual but supplies no overrides, + the previously auto-derived parameters continue to be used unchanged. + enum: + - name: DenoiseModeDisabled + value: 0 + description: | + Disabled mode - DPF processing is completely disabled. + - name: DenoiseModeAuto + value: 1 + description: | + Automatic mode - algorithm selects parameters based on tuning data. + - name: DenoiseModeManual + value: 2 + description: | + Manual mode - parameters are frozen and can be overridden. + - name: DenoiseModeReduction + value: 3 + description: | + Reduction mode - uses predefined noise reduction settings from tuning data. +... 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 Nov 25 00:08:41 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rui Wang X-Patchwork-Id: 25171 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 F1C73C3257 for ; Tue, 25 Nov 2025 00:09:13 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id A27F260A9D; Tue, 25 Nov 2025 01: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="W+FJpiLR"; 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 B80E7608CF for ; Tue, 25 Nov 2025 01:09:11 +0100 (CET) Received: from rui-Precision-7560.local (unknown [IPv6:2607:fea8:935b:7220:cb34:a7b8:53d:5466]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 959A61785; Tue, 25 Nov 2025 01:07:02 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1764029223; bh=cmhCEGrYfDDYOVEx/zoAkyOMTLK65P3DpKgjRdVMscc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=W+FJpiLR5dYnB8tLYVxK9+De5DR0l7Qyhqzw0jxBsRqhhV2IDDn7aFSHVoGebbILw YdooedLP+p/+nKb3WQZQV9tFC/JgvwqRAZIcJpEBEBCYqSpIqd9/70iNvmCa7E5vIW nS6g4IMFGobL+phTI/d1QP3aqSFXdEL/xgXj1n64= From: Rui Wang To: libcamera-devel@lists.libcamera.org Cc: Rui Wang Subject: [PATCH v1 04/11] ipa: rkisp1: algorithms: Add reduction mode support to DPF Date: Mon, 24 Nov 2025 19:08:41 -0500 Message-ID: <20251125000848.4103786-5-rui.wang@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251125000848.4103786-1-rui.wang@ideasonboard.com> References: <20251125000848.4103786-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 DenoiseMode enum in DenoiseBaseAlgorithm with values: Auto, Manual, Reduction, Disabled - Add virtual getRunningMode() and setRunningMode() methods to the base class - Implement handleReductionModeControl() in Dpf class to process draft::NoiseReductionMode controls - Map control values to ReductionMode enum (Off, Minimal, HighQuality, Fast, ZSL) - Add currentReductionMode_ member to track the active reduction mode - Set running mode to controls::rkisp1::DenoiseModeReduction when reduction mode is engaged Signed-off-by: Rui Wang --- src/ipa/rkisp1/algorithms/denoise.h | 10 ++++ src/ipa/rkisp1/algorithms/dpf.cpp | 85 +++++++++++++++++++---------- src/ipa/rkisp1/algorithms/dpf.h | 6 ++ 3 files changed, 71 insertions(+), 30 deletions(-) diff --git a/src/ipa/rkisp1/algorithms/denoise.h b/src/ipa/rkisp1/algorithms/denoise.h index abd08cba..660f648b 100644 --- a/src/ipa/rkisp1/algorithms/denoise.h +++ b/src/ipa/rkisp1/algorithms/denoise.h @@ -31,10 +31,20 @@ protected: { return true; } + virtual void handleReductionModeControl([[maybe_unused]] const ControlList &controls, + [[maybe_unused]] IPAFrameContext &frameContext, + [[maybe_unused]] IPAContext &context, + [[maybe_unused]] uint32_t frame) + { + } + virtual int32_t getRunningMode() const { return currentRunMode_; } + virtual void setRunningMode(int32_t mode) { currentRunMode_ = mode; } private: /**< Developer mode state for advanced controls */ bool devMode_ = false; + /**< Current denoise running mode */ + int32_t currentRunMode_ = controls::rkisp1::DenoiseModeDisabled; }; inline unsigned DenoiseBaseAlgorithm::computeExposureIndex(const IPAContext &context, diff --git a/src/ipa/rkisp1/algorithms/dpf.cpp b/src/ipa/rkisp1/algorithms/dpf.cpp index dc0a361c..c006fb5c 100644 --- a/src/ipa/rkisp1/algorithms/dpf.cpp +++ b/src/ipa/rkisp1/algorithms/dpf.cpp @@ -309,6 +309,55 @@ bool Dpf::parseSingleConfig(const YamlObject &tuningData, return true; } +void Dpf::handleReductionModeControl(const ControlList &controls, + IPAFrameContext &frameContext, + IPAContext &context, + [[maybe_unused]] uint32_t frame) +{ + auto &dpf = context.activeState.dpf; + const auto &denoise = controls.get(controls::draft::NoiseReductionMode); + if (!denoise) { + frameContext.dpf.denoise = dpf.denoise; + return; + } + LOG(RkISP1Dpf, Debug) << "Set denoise mode to " << *denoise; + + const auto requestedMode = static_cast(*denoise); + if (requestedMode == currentReductionMode_) { + frameContext.dpf.denoise = dpf.denoise; + return; + } + + currentReductionMode_ = requestedMode; + if (requestedMode == controls::draft::NoiseReductionModeOff) { + dpf.denoise = false; + frameContext.dpf.denoise = false; + return; + } + + dpf.denoise = true; + frameContext.dpf.denoise = true; + frameContext.dpf.update = true; +} +void Dpf::loadReductionModeConfig(IPAFrameContext &frameContext) +{ + /* Find mode config */ + auto it = std::find_if(modes_.begin(), modes_.end(), + [this](const ModeConfig &mode) { + return mode.modeValue == currentReductionMode_; + }); + if (it == modes_.end()) { + LOG(RkISP1Dpf, Warning) + << "No DPF config for reduction mode " + << static_cast(currentReductionMode_); + return; + } + + /* Apply mode config */ + config_ = it->dpf; + strengthConfig_ = it->strength; + frameContext.dpf.update = true; +} /** * \copydoc libcamera::ipa::Algorithm::queueRequest */ @@ -317,38 +366,14 @@ void Dpf::queueRequest(IPAContext &context, IPAFrameContext &frameContext, const ControlList &controls) { - auto &dpf = context.activeState.dpf; - bool update = false; + frameContext.dpf.update = false; + auto currentRunnungMode = getRunningMode(); + handleReductionModeControl(controls, frameContext, context, frame); - 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; - } + if (currentRunnungMode == controls::rkisp1::DenoiseModeReduction && currentReductionMode_ != controls::draft::NoiseReductionModeOff) { + loadReductionModeConfig(frameContext); + return; } - - frameContext.dpf.denoise = dpf.denoise; - frameContext.dpf.update = update; } /** diff --git a/src/ipa/rkisp1/algorithms/dpf.h b/src/ipa/rkisp1/algorithms/dpf.h index 8691932d..928e79d9 100644 --- a/src/ipa/rkisp1/algorithms/dpf.h +++ b/src/ipa/rkisp1/algorithms/dpf.h @@ -49,7 +49,13 @@ private: std::vector exposureIndexLevels_; std::vector modes_; bool useExposureIndexLevels_ = false; + int32_t currentReductionMode_ = controls::draft::NoiseReductionModeOff; + void handleReductionModeControl(const ControlList &controls, + IPAFrameContext &frameContext, + IPAContext &context, + uint32_t frame) override; + void loadReductionModeConfig(IPAFrameContext &frameContext); bool parseConfig(const YamlObject &tuningData) override; bool parseSingleConfig(const YamlObject &tuningData, rkisp1_cif_isp_dpf_config &config, From patchwork Tue Nov 25 00: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: 25172 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 0681CC3257 for ; Tue, 25 Nov 2025 00:09:16 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id A103860A9E; Tue, 25 Nov 2025 01: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="jovDiWaF"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 0EC55609D8 for ; Tue, 25 Nov 2025 01:09:13 +0100 (CET) Received: from rui-Precision-7560.local (unknown [IPv6:2607:fea8:935b:7220:cb34:a7b8:53d:5466]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 4599F1785; Tue, 25 Nov 2025 01:07:04 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1764029224; bh=thdNjgp4sS/RLvisnBqyFOT/NN/VVpzP0EaqUwophK0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=jovDiWaFTj/bq34xj3xNR3C68xtCBIeuhj7bxUilZVOtxazhYIVNyN1Ya+vVhJ/ft NUazNAH7tJwkj3clRKFc+ajnPW+uKjt5qcx+eR6tdsMWZjuA+kYbtOf3q3u8AJAG6S r1KeFT5FJ9rVWNAqBJDre1eGktx7t2/7zPrIRy+0= From: Rui Wang To: libcamera-devel@lists.libcamera.org Cc: Rui Wang Subject: [PATCH v1 05/11] ipa: rkisp1: algorithms: dpf: collect DPF manual overrides Date: Mon, 24 Nov 2025 19:08:42 -0500 Message-ID: <20251125000848.4103786-6-rui.wang@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251125000848.4103786-1-rui.wang@ideasonboard.com> References: <20251125000848.4103786-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 | 5 +- src/ipa/rkisp1/algorithms/dpf.cpp | 66 +++++++++++++++++++++++++ src/ipa/rkisp1/algorithms/dpf.h | 23 +++++++++ src/libcamera/control_ids_rkisp1.yaml | 71 +++++++++++++++++++++++++++ 4 files changed, 164 insertions(+), 1 deletion(-) diff --git a/src/ipa/rkisp1/algorithms/denoise.h b/src/ipa/rkisp1/algorithms/denoise.h index 660f648b..ffe27af8 100644 --- a/src/ipa/rkisp1/algorithms/denoise.h +++ b/src/ipa/rkisp1/algorithms/denoise.h @@ -22,6 +22,7 @@ protected: ~DenoiseBaseAlgorithm() = default; virtual void setDevMode(bool dev) { devMode_ = dev; } virtual bool isDevMode() const { return devMode_; } + virtual uint32_t computeExposureIndex(const IPAContext &context, const IPAFrameContext &frameContext) const; template @@ -31,6 +32,9 @@ protected: { return true; } + virtual void collectManualOverrides([[maybe_unused]] const ControlList &controls) + { + } virtual void handleReductionModeControl([[maybe_unused]] const ControlList &controls, [[maybe_unused]] IPAFrameContext &frameContext, [[maybe_unused]] IPAContext &context, @@ -39,7 +43,6 @@ protected: } virtual int32_t getRunningMode() const { return currentRunMode_; } virtual void setRunningMode(int32_t mode) { currentRunMode_ = mode; } - private: /**< Developer mode state for advanced controls */ bool devMode_ = false; diff --git a/src/ipa/rkisp1/algorithms/dpf.cpp b/src/ipa/rkisp1/algorithms/dpf.cpp index c006fb5c..2d7d6414 100644 --- a/src/ipa/rkisp1/algorithms/dpf.cpp +++ b/src/ipa/rkisp1/algorithms/dpf.cpp @@ -358,6 +358,72 @@ void Dpf::loadReductionModeConfig(IPAFrameContext &frameContext) strengthConfig_ = it->strength; frameContext.dpf.update = true; } + +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()) + return; + + 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 */ diff --git a/src/ipa/rkisp1/algorithms/dpf.h b/src/ipa/rkisp1/algorithms/dpf.h index 928e79d9..4cbd7414 100644 --- a/src/ipa/rkisp1/algorithms/dpf.h +++ b/src/ipa/rkisp1/algorithms/dpf.h @@ -35,6 +35,20 @@ private: 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 ExposureIndexLevelConfig { uint32_t maxExposureIndex; /* inclusive upper bound */ struct rkisp1_cif_isp_dpf_config dpf; @@ -45,6 +59,14 @@ private: 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 exposureIndexLevels_; std::vector modes_; @@ -56,6 +78,7 @@ private: IPAContext &context, uint32_t frame) override; void loadReductionModeConfig(IPAFrameContext &frameContext); + void collectManualOverrides(const ControlList &controls) override; bool parseConfig(const YamlObject &tuningData) override; bool parseSingleConfig(const YamlObject &tuningData, rkisp1_cif_isp_dpf_config &config, diff --git a/src/libcamera/control_ids_rkisp1.yaml b/src/libcamera/control_ids_rkisp1.yaml index 3e008ee4..bfd59925 100644 --- a/src/libcamera/control_ids_rkisp1.yaml +++ b/src/libcamera/control_ids_rkisp1.yaml @@ -70,4 +70,75 @@ controls: value: 3 description: | Reduction mode - uses predefined noise reduction settings from tuning data. + + - 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 / exposure index 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. + + - ExposureGainIndex: + type: int32_t + direction: out + description: | + Estimated scene exposure gain index used for Denoise tuning selection. Derived + from analogue gain (approx index = gain * 100). Provided each frame + for client awareness and debugging. Range 0..409600. + ... From patchwork Tue Nov 25 00:08:43 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rui Wang X-Patchwork-Id: 25173 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 88AF9C3257 for ; Tue, 25 Nov 2025 00:09:18 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 413EE60AAE; Tue, 25 Nov 2025 01:09:18 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="NM2AyiEK"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 4B0E960A8B for ; Tue, 25 Nov 2025 01:09:14 +0100 (CET) Received: from rui-Precision-7560.local (unknown [IPv6:2607:fea8:935b:7220:cb34:a7b8:53d:5466]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 7F9041785; Tue, 25 Nov 2025 01:07:05 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1764029225; bh=+a+kr1XhxCJeDB+hUFWNDEQC0gKZhoIYYErNDTALa5A=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=NM2AyiEK3xJ/8M3xEL+av3qlKXxQe9853hvA3b0wK6GHjZYCuL5t558sulYB3Wnh/ D6thvnpbYvYcbXk8cjyHK9SLZL0IYCrSTjj+eCFW/LOxDziaOSfcqciS9/0sY0F/Bt QezMrZ2p1xt1zlWATZesThSKuq/yU8TpQJeaqM/8= From: Rui Wang To: libcamera-devel@lists.libcamera.org Cc: Rui Wang Subject: [PATCH v1 06/11] ipa: rkisp1: algorithms: dpf: detect DPF dev overrides Date: Mon, 24 Nov 2025 19:08:43 -0500 Message-ID: <20251125000848.4103786-7-rui.wang@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251125000848.4103786-1-rui.wang@ideasonboard.com> References: <20251125000848.4103786-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 | 50 +++++++++++++++++++++++++++++++ src/ipa/rkisp1/algorithms/dpf.h | 1 + 2 files changed, 51 insertions(+) diff --git a/src/ipa/rkisp1/algorithms/dpf.cpp b/src/ipa/rkisp1/algorithms/dpf.cpp index 2d7d6414..0b070206 100644 --- a/src/ipa/rkisp1/algorithms/dpf.cpp +++ b/src/ipa/rkisp1/algorithms/dpf.cpp @@ -424,6 +424,56 @@ void Dpf::collectManualOverrides(const ControlList &controls) } } +bool Dpf::checkOverridesChanged() +{ + /* Check strength always (not dev-mode specific) */ + if (overrides_.strength) { + if (overrides_.strength->r != strengthConfig_.r || + overrides_.strength->g != strengthConfig_.g || + overrides_.strength->b != strengthConfig_.b) { + return true; + } + } + + if (!isDevMode()) + return false; + + if (overrides_.spatialGreen && + !std::equal(overrides_.spatialGreen->coeffs.begin(), overrides_.spatialGreen->coeffs.end(), + config_.g_flt.spatial_coeff)) { + return true; + } + if (overrides_.spatialRb && + !std::equal(overrides_.spatialRb->coeffs.begin(), overrides_.spatialRb->coeffs.end(), + config_.rb_flt.spatial_coeff)) { + return true; + } + if (overrides_.rbSize) { + bool currentRbSize = + (config_.rb_flt.fltsize == RKISP1_CIF_ISP_DPF_RB_FILTERSIZE_13x9) + ? 1 + : 0; + if (*overrides_.rbSize != currentRbSize) { + return true; + } + } + if (overrides_.nll) { + bool coeffsChanged = + !std::equal(overrides_.nll->coeffs.begin(), + overrides_.nll->coeffs.end(), + config_.nll.coeff); + bool scaleChanged = + overrides_.nll->scaleMode != + (config_.nll.scale_mode == RKISP1_CIF_ISP_NLL_SCALE_LOGARITHMIC + ? 1 + : 0); + if (coeffsChanged || scaleChanged) { + return true; + } + } + return false; +} + /** * \copydoc libcamera::ipa::Algorithm::queueRequest */ diff --git a/src/ipa/rkisp1/algorithms/dpf.h b/src/ipa/rkisp1/algorithms/dpf.h index 4cbd7414..d6707d34 100644 --- a/src/ipa/rkisp1/algorithms/dpf.h +++ b/src/ipa/rkisp1/algorithms/dpf.h @@ -79,6 +79,7 @@ private: uint32_t frame) override; void loadReductionModeConfig(IPAFrameContext &frameContext); void collectManualOverrides(const ControlList &controls) override; + bool checkOverridesChanged(); bool parseConfig(const YamlObject &tuningData) override; bool parseSingleConfig(const YamlObject &tuningData, rkisp1_cif_isp_dpf_config &config, From patchwork Tue Nov 25 00: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: 25174 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 E20F6C32EF for ; Tue, 25 Nov 2025 00:09:19 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 5B56E60A8B; Tue, 25 Nov 2025 01: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="tJdhfQXv"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 9FD9E60A8B for ; Tue, 25 Nov 2025 01:09:15 +0100 (CET) Received: from rui-Precision-7560.local (unknown [IPv6:2607:fea8:935b:7220:cb34:a7b8:53d:5466]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id D25731785; Tue, 25 Nov 2025 01:07:06 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1764029227; bh=llQFiwM+wwa3hU9mE860NtaMHskSZpg7bThCsF1SPeA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=tJdhfQXv7IC1jtF5dSNovpAgWQQauohBK6/uD/uTfVDEvqn33ZaSYLvChCJxdyr6h VTZPuKuVxgNYfYbT/ycYtMRNqP0u4AT3dVCo4sFbctGZG/BUUe742j+HLncZz03OlB vgz1KSz2c1wVRcxrRF7y0FpBZbuiyhsjxBfUvX4M= From: Rui Wang To: libcamera-devel@lists.libcamera.org Cc: Rui Wang Subject: [PATCH v1 07/11] ipa: rkisp1: algorithms: dpf: manage DPF mode transitions Date: Mon, 24 Nov 2025 19:08:44 -0500 Message-ID: <20251125000848.4103786-8-rui.wang@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251125000848.4103786-1-rui.wang@ideasonboard.com> References: <20251125000848.4103786-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 - snapshotCurrentToOverrides(): Captures current config when entering manual mode so users can continue from current state - restoreAutoConfig(): Restores base or exposure gain 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 | 15 ++++ src/ipa/rkisp1/algorithms/dpf.cpp | 121 +++++++++++++++++++++++++++- src/ipa/rkisp1/algorithms/dpf.h | 8 ++ 3 files changed, 140 insertions(+), 4 deletions(-) diff --git a/src/ipa/rkisp1/algorithms/denoise.h b/src/ipa/rkisp1/algorithms/denoise.h index ffe27af8..4c917c1a 100644 --- a/src/ipa/rkisp1/algorithms/denoise.h +++ b/src/ipa/rkisp1/algorithms/denoise.h @@ -35,12 +35,27 @@ protected: virtual void collectManualOverrides([[maybe_unused]] const ControlList &controls) { } + virtual bool processModeChange([[maybe_unused]] const ControlList &controls, + [[maybe_unused]] uint32_t currentFrame) + { + return false; + } + virtual void snapshotCurrentToOverrides() + { + } + virtual void restoreAutoConfig([[maybe_unused]] IPAContext &context, [[maybe_unused]] IPAFrameContext &frameContext) + { + } virtual void handleReductionModeControl([[maybe_unused]] const ControlList &controls, [[maybe_unused]] IPAFrameContext &frameContext, [[maybe_unused]] IPAContext &context, [[maybe_unused]] uint32_t frame) { } + virtual void handleDisableMode([[maybe_unused]] IPAFrameContext &frameContext, + [[maybe_unused]] IPAContext &context) + { + } virtual int32_t getRunningMode() const { return currentRunMode_; } virtual void setRunningMode(int32_t mode) { currentRunMode_ = mode; } private: diff --git a/src/ipa/rkisp1/algorithms/dpf.cpp b/src/ipa/rkisp1/algorithms/dpf.cpp index 0b070206..91bcd503 100644 --- a/src/ipa/rkisp1/algorithms/dpf.cpp +++ b/src/ipa/rkisp1/algorithms/dpf.cpp @@ -339,6 +339,17 @@ void Dpf::handleReductionModeControl(const ControlList &controls, frameContext.dpf.denoise = true; frameContext.dpf.update = true; } + +void Dpf::handleDisableMode(IPAFrameContext &frameContext, IPAContext &context) +{ + /* Reset reduction mode to Off when DPF is disabled */ + currentReductionMode_ = controls::draft::NoiseReductionModeOff; + + /* Ensure denoise is disabled */ + context.activeState.dpf.denoise = false; + frameContext.dpf.denoise = false; +} + void Dpf::loadReductionModeConfig(IPAFrameContext &frameContext) { /* Find mode config */ @@ -474,6 +485,76 @@ bool Dpf::checkOverridesChanged() return false; } +void Dpf::snapshotCurrentToOverrides() +{ + /* clear previous overrides */ + overrides_.clear(); + overrides_.strength = DpfStrengthSettings{ + strengthConfig_.r, + strengthConfig_.g, + strengthConfig_.b + }; + if (!isDevMode()) + return; + /* Snapshot current config to overrides */ + 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) +{ + /* clear previous overrides */ + overrides_.clear(); + if (useExposureIndexLevels_) { + uint32_t exposureIndex = computeExposureIndex(context, frameContext); + int32_t idx = + DenoiseBaseAlgorithm::selectExposureIndexBand(exposureIndex, + exposureIndexLevels_); + if (idx >= 0) { + config_ = exposureIndexLevels_[idx].dpf; + strengthConfig_ = exposureIndexLevels_[idx].strength; + lastExposureGainIndex_ = idx; + } + } else { + config_ = baseConfig_; + strengthConfig_ = baseStrengthConfig_; + lastExposureGainIndex_ = -1; + } + frameContext.dpf.update = true; +} + +bool Dpf::processModeChange(const ControlList &controls, [[maybe_unused]] uint32_t currentFrame) +{ + const auto &cMode = controls.get(controls::rkisp1::DenoiseMode); + if (!cMode) + return false; + int32_t requestedMode = static_cast(*cMode); + auto currentMode = getRunningMode(); + + setRunningMode(requestedMode); + return (currentMode != getRunningMode()); +} + /** * \copydoc libcamera::ipa::Algorithm::queueRequest */ @@ -483,13 +564,45 @@ void Dpf::queueRequest(IPAContext &context, const ControlList &controls) { frameContext.dpf.update = false; - auto currentRunnungMode = getRunningMode(); - handleReductionModeControl(controls, frameContext, context, frame); - if (currentRunnungMode == controls::rkisp1::DenoiseModeReduction && currentReductionMode_ != controls::draft::NoiseReductionModeOff) { - loadReductionModeConfig(frameContext); + auto modeChanged = processModeChange(controls, frame); + switch (getRunningMode()) { + case controls::rkisp1::DenoiseModeManual: + snapshotCurrentToOverrides(); + collectManualOverrides(controls); + if (checkOverridesChanged()) { + frameContext.dpf.update = true; + } + LOG(RkISP1Dpf, Debug) << "DPF mode=Manual (snapshot captured)"; + break; + case controls::rkisp1::DenoiseModeAuto: + restoreAutoConfig(context, frameContext); + LOG(RkISP1Dpf, Debug) << "DPF mode=Auto (restored auto config)"; + break; + case controls::rkisp1::DenoiseModeReduction: + handleReductionModeControl(controls, + frameContext, + context, + frame); /* Check reduction mode first */ + if (currentReductionMode_ != controls::draft::NoiseReductionModeOff) { + loadReductionModeConfig(frameContext); + } + LOG(RkISP1Dpf, Debug) << "DPF mode=Reduction (config loaded)"; + break; + case controls::rkisp1::DenoiseModeDisabled: + handleDisableMode(frameContext, context); + break; + default: + LOG(RkISP1Dpf, Warning) << "DPF mode=Disabled"; return; } + /* Set denoise based on mode */ + + if (modeChanged) + frameContext.dpf.update = true; + bool denoise = (getRunningMode() != controls::rkisp1::DenoiseModeDisabled); + context.activeState.dpf.denoise = denoise; + frameContext.dpf.denoise = denoise; } /** diff --git a/src/ipa/rkisp1/algorithms/dpf.h b/src/ipa/rkisp1/algorithms/dpf.h index d6707d34..c63d1558 100644 --- a/src/ipa/rkisp1/algorithms/dpf.h +++ b/src/ipa/rkisp1/algorithms/dpf.h @@ -71,12 +71,14 @@ private: std::vector exposureIndexLevels_; std::vector modes_; bool useExposureIndexLevels_ = false; + int32_t lastExposureGainIndex_ = -1; int32_t currentReductionMode_ = controls::draft::NoiseReductionModeOff; void handleReductionModeControl(const ControlList &controls, IPAFrameContext &frameContext, IPAContext &context, uint32_t frame) override; + void handleDisableMode(IPAFrameContext &frameContext, IPAContext &context) override; void loadReductionModeConfig(IPAFrameContext &frameContext); void collectManualOverrides(const ControlList &controls) override; bool checkOverridesChanged(); @@ -84,6 +86,12 @@ private: bool parseSingleConfig(const YamlObject &tuningData, rkisp1_cif_isp_dpf_config &config, rkisp1_cif_isp_dpf_strength_config &strengthConfig); + + bool processModeChange(const ControlList &controls, uint32_t currentFrame) override; + + void snapshotCurrentToOverrides() override; + + void restoreAutoConfig(IPAContext &context, IPAFrameContext &frameContext) override; }; } /* namespace ipa::rkisp1::algorithms */ From patchwork Tue Nov 25 00: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: 25175 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 373E9C3257 for ; Tue, 25 Nov 2025 00:09:21 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 0C87B60AB5; Tue, 25 Nov 2025 01: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="gPIAQ+jE"; 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 D2C13608CF for ; Tue, 25 Nov 2025 01:09:16 +0100 (CET) Received: from rui-Precision-7560.local (unknown [IPv6:2607:fea8:935b:7220:cb34:a7b8:53d:5466]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 097E41785; Tue, 25 Nov 2025 01:07:07 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1764029228; bh=VJCQePz+9Lhqe9GTyMtTSklznvMT0HOuuL/2HWrfeb0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=gPIAQ+jEIytSkbJHJnmZBG7Q6mznviTKWWg7QjvCDvoyKq3gbDuWNSKYkzwacfEHe 9peEkrCLB9cvy9KFbAtaFZwYNkO77hHE2umbEfnX3HoAWzQuZEi2SxiQQRQJk16Tu7 HDmotj3EDnfNmdmhyO+bgN513/qu4+SqwOFhTgfQ= From: Rui Wang To: libcamera-devel@lists.libcamera.org Cc: Rui Wang Subject: [PATCH v1 08/11] ipa: rkisp1: algorithms: dpf: apply DPF overrides Date: Mon, 24 Nov 2025 19:08:45 -0500 Message-ID: <20251125000848.4103786-9-rui.wang@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251125000848.4103786-1-rui.wang@ideasonboard.com> References: <20251125000848.4103786-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, gain band selection, and control mode. Uses static state tracking to log only when changes occur. Signed-off-by: Rui Wang --- src/ipa/rkisp1/algorithms/dpf.cpp | 135 ++++++++++++++++++++++++++++++ src/ipa/rkisp1/algorithms/dpf.h | 9 +- 2 files changed, 142 insertions(+), 2 deletions(-) diff --git a/src/ipa/rkisp1/algorithms/dpf.cpp b/src/ipa/rkisp1/algorithms/dpf.cpp index 91bcd503..c88f5c69 100644 --- a/src/ipa/rkisp1/algorithms/dpf.cpp +++ b/src/ipa/rkisp1/algorithms/dpf.cpp @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -555,6 +556,140 @@ bool Dpf::processModeChange(const ControlList &controls, [[maybe_unused]] uint32 return (currentMode != getRunningMode()); } +void Dpf::applyOverridesTo(rkisp1_cif_isp_dpf_config &config, + rkisp1_cif_isp_dpf_strength_config &strengthConfig, + bool &anyOverride) +{ + if (getRunningMode() != controls::rkisp1::DenoiseModeManual) + return; + /* only apply overrides in manual mode */ + if (overrides_.strength) { + strengthConfig.r = overrides_.strength->r; + strengthConfig.g = overrides_.strength->g; + strengthConfig.b = overrides_.strength->b; + anyOverride = true; + } + if (overrides_.spatialGreen) { + std::copy(overrides_.spatialGreen->coeffs.begin(), overrides_.spatialGreen->coeffs.end(), + config.g_flt.spatial_coeff); + anyOverride = true; + } + if (overrides_.spatialRb) { + std::copy(overrides_.spatialRb->coeffs.begin(), overrides_.spatialRb->coeffs.end(), + config.rb_flt.spatial_coeff); + anyOverride = true; + config.rb_flt.fltsize = *overrides_.rbSize + ? RKISP1_CIF_ISP_DPF_RB_FILTERSIZE_13x9 + : RKISP1_CIF_ISP_DPF_RB_FILTERSIZE_9x9; + anyOverride = true; + } + if (overrides_.nll) { + std::copy(overrides_.nll->coeffs.begin(), overrides_.nll->coeffs.end(), + config.nll.coeff); + config.nll.scale_mode = overrides_.nll->scaleMode + ? RKISP1_CIF_ISP_NLL_SCALE_LOGARITHMIC + : RKISP1_CIF_ISP_NLL_SCALE_LINEAR; + anyOverride = true; + } + if (!anyOverride) + return; + /* Log applied overrides */ + config_ = config; + strengthConfig_ = strengthConfig; + 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(uint32_t exposureGainIndex, + int32_t exposureBandIndex, + bool anyOverride, + const IPAFrameContext &frameContext) +{ + static rkisp1_cif_isp_dpf_config lastCfg{}; + static rkisp1_cif_isp_dpf_strength_config lastStr{}; + static bool haveLast = false; + + /* Check if the DPF configuration or strength settings have changed since the last log */ + /* Use memcmp for byte-wise comparison of the C structs (no operator== defined) */ + bool cfgChanged = !haveLast || memcmp(&lastCfg, &config_, sizeof(config_)) != 0; + bool strChanged = !haveLast || memcmp(&lastStr, &strengthConfig_, sizeof(strengthConfig_)) != 0; + + if (!cfgChanged && !strChanged) + return; + + std::string gCoeffsStr = "["; + for (size_t i = 0; i < RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS; ++i) { + if (i > 0) + gCoeffsStr += ","; + gCoeffsStr += std::to_string(static_cast(config_.g_flt.spatial_coeff[i])); + } + gCoeffsStr += "]"; + + std::string rbCoeffsStr = "["; + for (size_t i = 0; i < RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS; ++i) { + if (i > 0) + rbCoeffsStr += ","; + rbCoeffsStr += std::to_string(static_cast(config_.rb_flt.spatial_coeff[i])); + } + rbCoeffsStr += "]"; + + std::string nllCoeffsStr = "["; + for (size_t i = 0; i < RKISP1_CIF_ISP_DPF_MAX_NLF_COEFFS; ++i) { + if (i > 0) + nllCoeffsStr += ","; + nllCoeffsStr += std::to_string(config_.nll.coeff[i]); + } + nllCoeffsStr += "]"; + + std::string rbFilterSizeStr = + config_.rb_flt.fltsize == RKISP1_CIF_ISP_DPF_RB_FILTERSIZE_13x9 + ? "13x9" + : "9x9"; + std::string nllScaleStr = + config_.nll.scale_mode == RKISP1_CIF_ISP_NLL_SCALE_LOGARITHMIC + ? "log" + : "linear"; + std::string denoiseStr = (frameContext.dpf.denoise ? "enabled" : "disabled"); + std::string overrideStr = (anyOverride ? " (overrides applied)" : ""); + + std::string exposureIndexBandStr; + if (useExposureIndexLevels_ && exposureBandIndex >= 0) { + exposureIndexBandStr = + ", exposureIndex_band=" + std::to_string(exposureBandIndex); + if (lastExposureGainIndex_ != exposureBandIndex) { + exposureIndexBandStr += "(new)"; + } + } + + LOG(RkISP1Dpf, Info) + << "DPF config update: rb_fltsize=" << rbFilterSizeStr + << ", nll_scale=" << nllScaleStr + << ", gain_mode=" << config_.gain.mode + << ", strength=" << (int)strengthConfig_.r << "," + << (int)strengthConfig_.g << "," + << (int)strengthConfig_.b + << ", g=" << gCoeffsStr + << ", rb=" << rbCoeffsStr + << ", nll=" << nllCoeffsStr + << ", exposureIndex=" << exposureGainIndex + << exposureIndexBandStr + << ", control mode=" << static_cast(getRunningMode()) + << ", reduction mode=" << static_cast(currentReductionMode_) + << ", denoise=" << denoiseStr + << overrideStr; + + 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 c63d1558..abcdf8ee 100644 --- a/src/ipa/rkisp1/algorithms/dpf.h +++ b/src/ipa/rkisp1/algorithms/dpf.h @@ -88,10 +88,15 @@ private: rkisp1_cif_isp_dpf_strength_config &strengthConfig); bool processModeChange(const ControlList &controls, uint32_t currentFrame) override; - void snapshotCurrentToOverrides() override; - void restoreAutoConfig(IPAContext &context, IPAFrameContext &frameContext) override; + void applyOverridesTo(rkisp1_cif_isp_dpf_config &config, + rkisp1_cif_isp_dpf_strength_config &strengthConfig, + bool &anyOverride); + void logConfigIfChanged(uint32_t exposureGainIndex, + int32_t exposureBandIndex, + bool anyOverride, + const IPAFrameContext &frameContext); }; } /* namespace ipa::rkisp1::algorithms */ From patchwork Tue Nov 25 00:08:46 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rui Wang X-Patchwork-Id: 25176 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 65AECC32EF for ; Tue, 25 Nov 2025 00:09:22 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id EC21F60AB4; Tue, 25 Nov 2025 01: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="WNndxMjw"; 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 55BD960AAF for ; Tue, 25 Nov 2025 01:09:18 +0100 (CET) Received: from rui-Precision-7560.local (unknown [IPv6:2607:fea8:935b:7220:cb34:a7b8:53d:5466]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 6B9DD17EB; Tue, 25 Nov 2025 01:07:09 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1764029229; bh=p9snf8mTJT/16VHTZjuDYk8EWD3+ktBVRGJUPKtlsHE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=WNndxMjwHRe+fMWKlTHY6kcXp9UUw/GjtqPqfCce8VDEj4fh2dPtKVIBGmCVu8s5X mkmguEscVGVF+ingIKZK391TBds7OV/6tAN6cOdb2QBVYeDxJZAT/jX0rkIqDZU9eG 4jNNhcKMd9z6vBefp6bHv1oYYjgcT+2olqhoznW8= From: Rui Wang To: libcamera-devel@lists.libcamera.org Cc: Rui Wang Subject: [PATCH v1 09/11] ipa: rkisp1: algorithms: dpf: refactor DPF prepare flow Date: Mon, 24 Nov 2025 19:08:46 -0500 Message-ID: <20251125000848.4103786-10-rui.wang@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251125000848.4103786-1-rui.wang@ideasonboard.com> References: <20251125000848.4103786-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 exposure index bands while the manual path applies user overrides before programming hardware. Key changes: - prepare() now branches to prepareAutoMode or prepareManualMode - Added debug logging to queueRequest() Signed-off-by: Rui Wang --- src/ipa/rkisp1/algorithms/denoise.h | 12 +++ src/ipa/rkisp1/algorithms/dpf.cpp | 127 +++++++++++++++++++++------- src/ipa/rkisp1/algorithms/dpf.h | 5 ++ 3 files changed, 113 insertions(+), 31 deletions(-) diff --git a/src/ipa/rkisp1/algorithms/denoise.h b/src/ipa/rkisp1/algorithms/denoise.h index 4c917c1a..f07c14fe 100644 --- a/src/ipa/rkisp1/algorithms/denoise.h +++ b/src/ipa/rkisp1/algorithms/denoise.h @@ -58,6 +58,18 @@ protected: } virtual int32_t getRunningMode() const { return currentRunMode_; } virtual void setRunningMode(int32_t mode) { currentRunMode_ = mode; } + virtual void prepareDisabledMode([[maybe_unused]] IPAContext &context, + [[maybe_unused]] const uint32_t frame, + [[maybe_unused]] IPAFrameContext &frameContext, + [[maybe_unused]] RkISP1Params *params) + { + } + virtual void prepareEnabledMode([[maybe_unused]] IPAContext &context, + [[maybe_unused]] const uint32_t frame, + [[maybe_unused]] IPAFrameContext &frameContext, + [[maybe_unused]] RkISP1Params *params) + { + } private: /**< Developer mode state for advanced controls */ bool devMode_ = false; diff --git a/src/ipa/rkisp1/algorithms/dpf.cpp b/src/ipa/rkisp1/algorithms/dpf.cpp index c88f5c69..e3293241 100644 --- a/src/ipa/rkisp1/algorithms/dpf.cpp +++ b/src/ipa/rkisp1/algorithms/dpf.cpp @@ -748,41 +748,106 @@ void Dpf::prepare(IPAContext &context, const uint32_t frame, { if (!frameContext.dpf.update && frame > 0) return; + /* Check if denoise toggle off */ + if (!frameContext.dpf.denoise) { + auto cfg = params->block(); + cfg.setEnabled(false); + auto str = params->block(); + str.setEnabled(false); + setRunningMode(controls::rkisp1::DenoiseModeDisabled); + return; + } - auto config = params->block(); - config.setEnabled(frameContext.dpf.denoise); - - auto strengthConfig = params->block(); - strengthConfig.setEnabled(frameContext.dpf.denoise); - - if (frameContext.dpf.denoise) { - *config = config_; - *strengthConfig = strengthConfig_; - - 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; + switch (getRunningMode()) { + case controls::rkisp1::DenoiseModeDisabled: + prepareDisabledMode(context, frame, frameContext, params); + break; + case controls::rkisp1::DenoiseModeAuto: + case controls::rkisp1::DenoiseModeManual: + case controls::rkisp1::DenoiseModeReduction: + prepareEnabledMode(context, frame, frameContext, params); + break; + default: + LOG(RkISP1Dpf, Warning) << "DPF in unknown mode"; + break; } } +void Dpf::prepareEnabledMode(IPAContext &context, const uint32_t frame, + IPAFrameContext &frameContext, RkISP1Params *params) +{ + uint32_t exposureGainIndex = computeExposureIndex(context, frameContext); + + if (!frameContext.dpf.update && frame > 0) + return; + + /* Select different DPF config determined by exposure index level for Auto mode */ + if (getRunningMode() == controls::rkisp1::DenoiseModeAuto && useExposureIndexLevels_) { + int32_t idx = + DenoiseBaseAlgorithm::selectExposureIndexBand( + exposureGainIndex, exposureIndexLevels_); + if (idx >= 0 && idx != lastExposureGainIndex_) { + config_ = exposureIndexLevels_[idx].dpf; + strengthConfig_ = exposureIndexLevels_[idx].strength; + frameContext.dpf.update = true; + lastExposureGainIndex_ = idx; + } + } + + auto cfgBlock = params->block(); + cfgBlock.setEnabled(true); + *cfgBlock = config_; + + /* + * 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. + */ + const auto &awb = context.configuration.awb; + const auto &lsc = context.configuration.lsc; + auto &mode = cfgBlock->gain.mode; + + 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; + + config_.gain.mode = mode; + + auto strBlock = params->block(); + strBlock.setEnabled(true); + + *strBlock = strengthConfig_; + bool anyOverride = false; + if (getRunningMode() == controls::rkisp1::DenoiseModeManual) + applyOverridesTo(*cfgBlock, *strBlock, anyOverride); + + int32_t exposureGainIdx = lastExposureGainIndex_; + if (getRunningMode() == controls::rkisp1::DenoiseModeReduction) + exposureGainIdx = -1; + + logConfigIfChanged(exposureGainIndex, exposureGainIdx, anyOverride, frameContext); +} + +void Dpf::prepareDisabledMode([[maybe_unused]] IPAContext &context, + [[maybe_unused]] const uint32_t frame, + [[maybe_unused]] IPAFrameContext &frameContext, + RkISP1Params *params) +{ + frameContext.dpf.denoise = false; + auto cfg = params->block(); + cfg.setEnabled(false); + auto str = params->block(); + str.setEnabled(false); +} + 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 abcdf8ee..86085cf9 100644 --- a/src/ipa/rkisp1/algorithms/dpf.h +++ b/src/ipa/rkisp1/algorithms/dpf.h @@ -97,6 +97,11 @@ private: int32_t exposureBandIndex, bool anyOverride, const IPAFrameContext &frameContext); + void prepareDisabledMode(IPAContext &context, const uint32_t frame, + IPAFrameContext &frameContext, + RkISP1Params *params) override; + void prepareEnabledMode(IPAContext &context, const uint32_t frame, + IPAFrameContext &frameContext, RkISP1Params *params) override; }; } /* namespace ipa::rkisp1::algorithms */ From patchwork Tue Nov 25 00:08:47 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rui Wang X-Patchwork-Id: 25177 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 354E8C3257 for ; Tue, 25 Nov 2025 00:09:24 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id C177660AAF; Tue, 25 Nov 2025 01:09:23 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="F+3PjRHh"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 0A92160AB3 for ; Tue, 25 Nov 2025 01:09:20 +0100 (CET) Received: from rui-Precision-7560.local (unknown [IPv6:2607:fea8:935b:7220:cb34:a7b8:53d:5466]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 3B0E317EB; Tue, 25 Nov 2025 01:07:11 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1764029231; bh=cUkuco0HyARjPcIJhprL+7A1ioaxF2RRM0C2yQDtPxE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=F+3PjRHh7OcM+nVUvo7WP3CM1jckwLLvIkz8hC4RjcufXdZrHLO5LKVCA8a+0tumX 7WIDhMEfb2IrUzaNRIfrYzMaoVnl4wJgbQdRYr4Dg8G62epGoANrS1c7OlTvpzdJFF vAHB/zRM7yFYqpy/zYiNd1dFHd3XY4rQAxJlJk4U= From: Rui Wang To: libcamera-devel@lists.libcamera.org Cc: Rui Wang Subject: [PATCH v1 10/11] ipa: rkisp1: algorithms: dpf: expose DPF control map Date: Mon, 24 Nov 2025 19:08:47 -0500 Message-ID: <20251125000848.4103786-11-rui.wang@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251125000848.4103786-1-rui.wang@ideasonboard.com> References: <20251125000848.4103786-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: - DpfMode (auto/manual/disable/reduction 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 - DpfExposure (read-only exposure 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 | 9 +++++ src/ipa/rkisp1/algorithms/dpf.cpp | 63 +++++++++++++++++++++++++++++ src/ipa/rkisp1/algorithms/dpf.h | 1 + 3 files changed, 73 insertions(+) diff --git a/src/ipa/rkisp1/algorithms/denoise.h b/src/ipa/rkisp1/algorithms/denoise.h index f07c14fe..c532b7eb 100644 --- a/src/ipa/rkisp1/algorithms/denoise.h +++ b/src/ipa/rkisp1/algorithms/denoise.h @@ -70,6 +70,7 @@ protected: [[maybe_unused]] RkISP1Params *params) { } + virtual ControlInfoMap::Map getControlMap() const; private: /**< Developer mode state for advanced controls */ bool devMode_ = false; @@ -99,6 +100,14 @@ uint32_t DenoiseBaseAlgorithm::selectExposureIndexBand(unsigned exposureIndex, return idx; } +inline ControlInfoMap::Map DenoiseBaseAlgorithm::getControlMap() const +{ + ControlInfoMap::Map map; + map[&controls::rkisp1::DenoiseMode] = + ControlInfo(controls::rkisp1::DenoiseModeValues); + map[&controls::rkisp1::ExposureGainIndex] = ControlInfo(0, 6400, 0); + return map; +} } /* namespace ipa::rkisp1::algorithms */ } /* namespace libcamera */ diff --git a/src/ipa/rkisp1/algorithms/dpf.cpp b/src/ipa/rkisp1/algorithms/dpf.cpp index e3293241..a3a8e789 100644 --- a/src/ipa/rkisp1/algorithms/dpf.cpp +++ b/src/ipa/rkisp1/algorithms/dpf.cpp @@ -84,6 +84,9 @@ int Dpf::init([[maybe_unused]] IPAContext &context, << " mode(s) from tuning"; } + /* Init controls value from YAML */ + auto dpfMap = getControlMap(); + context.ctrlMap.insert(dpfMap.begin(), dpfMap.end()); return 0; } @@ -690,6 +693,66 @@ void Dpf::logConfigIfChanged(uint32_t exposureGainIndex, haveLast = true; } +ControlInfoMap::Map Dpf::getControlMap() const +{ + ControlInfoMap::Map map = DenoiseBaseAlgorithm::getControlMap(); + + 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()) + return map; + + const auto copyCoefficients = [](const auto &src, auto &dest) { + for (size_t i = 0; i < dest.size(); ++i) + dest[i] = static_cast(src[i]); + }; + + std::array greenCoeffs{}; + copyCoefficients(baseConfig_.g_flt.spatial_coeff, greenCoeffs); + map[&controls::rkisp1::DpfGreenSpatialCoefficients] = + ControlInfo(0, 63, + Span(greenCoeffs)); + + std::array rbCoeffs{}; + copyCoefficients(baseConfig_.rb_flt.spatial_coeff, rbCoeffs); + 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{}; + copyCoefficients(baseConfig_.nll.coeff, nllCoeffs); + 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)); + + return map; +} + /** * \copydoc libcamera::ipa::Algorithm::queueRequest */ diff --git a/src/ipa/rkisp1/algorithms/dpf.h b/src/ipa/rkisp1/algorithms/dpf.h index 86085cf9..e62882f2 100644 --- a/src/ipa/rkisp1/algorithms/dpf.h +++ b/src/ipa/rkisp1/algorithms/dpf.h @@ -102,6 +102,7 @@ private: RkISP1Params *params) override; void prepareEnabledMode(IPAContext &context, const uint32_t frame, IPAFrameContext &frameContext, RkISP1Params *params) override; + ControlInfoMap::Map getControlMap() const override; }; } /* namespace ipa::rkisp1::algorithms */ From patchwork Tue Nov 25 00:08:48 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rui Wang X-Patchwork-Id: 25178 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 3B184C32EF for ; Tue, 25 Nov 2025 00:09:25 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id D02A060AA9; Tue, 25 Nov 2025 01:09:24 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="roEgZwme"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id CE4A560AB2 for ; Tue, 25 Nov 2025 01:09:21 +0100 (CET) Received: from rui-Precision-7560.local (unknown [IPv6:2607:fea8:935b:7220:cb34:a7b8:53d:5466]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id C63DE17EB; Tue, 25 Nov 2025 01:07:12 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1764029233; bh=ovL0wjZY8E6+vr8e/kGetsg/IUbZrJMEp1uOplzTMHM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=roEgZwmeb4uCvm1e6CPymU5T45KGPUhRPD0RWJrKKVa8VtL/oFfpkYH/7RzLLTDE0 igrJWzjzdx2hcuJhiK9+te7nwKWbMvEk4V4g0dpVDjIkvY/kxOB14KwEOd2VLfn6eN bsUwD5wlirGlr/YOXiMglaIpsZszpznd7G++MgcY= From: Rui Wang To: libcamera-devel@lists.libcamera.org Cc: Rui Wang Subject: [PATCH v1 11/11] ipa: rkisp1: algorithms: dpf: publish DPF metadata Date: Mon, 24 Nov 2025 19:08:48 -0500 Message-ID: <20251125000848.4103786-12-rui.wang@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251125000848.4103786-1-rui.wang@ideasonboard.com> References: <20251125000848.4103786-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: - DpfExposeIndex: Current index 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) Signed-off-by: Rui Wang --- src/ipa/rkisp1/algorithms/denoise.h | 16 +++++++++ src/ipa/rkisp1/algorithms/dpf.cpp | 56 +++++++++++++++++++++++++++++ src/ipa/rkisp1/algorithms/dpf.h | 7 ++++ 3 files changed, 79 insertions(+) diff --git a/src/ipa/rkisp1/algorithms/denoise.h b/src/ipa/rkisp1/algorithms/denoise.h index c532b7eb..a54e3c43 100644 --- a/src/ipa/rkisp1/algorithms/denoise.h +++ b/src/ipa/rkisp1/algorithms/denoise.h @@ -71,6 +71,10 @@ protected: { } virtual ControlInfoMap::Map getControlMap() const; + virtual void fillMetadata(IPAContext &context, + IPAFrameContext &frameContext, + ControlList &metadata); + private: /**< Developer mode state for advanced controls */ bool devMode_ = false; @@ -108,6 +112,18 @@ inline ControlInfoMap::Map DenoiseBaseAlgorithm::getControlMap() const map[&controls::rkisp1::ExposureGainIndex] = ControlInfo(0, 6400, 0); return map; } + +inline void DenoiseBaseAlgorithm::fillMetadata(IPAContext &context, + IPAFrameContext &frameContext, + ControlList &metadata) +{ + uint32_t exposureIndex = computeExposureIndex(context, frameContext); + metadata.set(controls::rkisp1::ExposureGainIndex, static_cast(exposureIndex)); + + auto currentMode = getRunningMode(); + metadata.set(controls::rkisp1::DenoiseMode, currentMode); +} + } /* namespace ipa::rkisp1::algorithms */ } /* namespace libcamera */ diff --git a/src/ipa/rkisp1/algorithms/dpf.cpp b/src/ipa/rkisp1/algorithms/dpf.cpp index a3a8e789..b3880d41 100644 --- a/src/ipa/rkisp1/algorithms/dpf.cpp +++ b/src/ipa/rkisp1/algorithms/dpf.cpp @@ -911,6 +911,62 @@ void Dpf::prepareDisabledMode([[maybe_unused]] IPAContext &context, str.setEnabled(false); } +/** + * \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) +{ + DenoiseBaseAlgorithm::fillMetadata(context, frameContext, metadata); + /* 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()) + return; + + /* 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 (uint32_t 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 (uint32_t 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 e62882f2..64b80556 100644 --- a/src/ipa/rkisp1/algorithms/dpf.h +++ b/src/ipa/rkisp1/algorithms/dpf.h @@ -29,6 +29,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_; @@ -103,6 +107,9 @@ private: void prepareEnabledMode(IPAContext &context, const uint32_t frame, IPAFrameContext &frameContext, RkISP1Params *params) override; ControlInfoMap::Map getControlMap() const override; + void fillMetadata(IPAContext &context, + IPAFrameContext &frameContext, + ControlList &metadata) override; }; } /* namespace ipa::rkisp1::algorithms */