{"id":25826,"url":"https://patchwork.libcamera.org/api/1.1/patches/25826/?format=json","web_url":"https://patchwork.libcamera.org/patch/25826/","project":{"id":1,"url":"https://patchwork.libcamera.org/api/1.1/projects/1/?format=json","name":"libcamera","link_name":"libcamera","list_id":"libcamera_core","list_email":"libcamera-devel@lists.libcamera.org","web_url":"","scm_url":"","webscm_url":""},"msgid":"<20260118202953.1554892-2-rui.wang@ideasonboard.com>","date":"2026-01-18T20:29:50","name":"[v1,1/4] ipa: rkisp1: algorithms: filter: Implement noise reduction mode switching","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"0823c27e153b6e37e35eaf9a90291e5c83742241","submitter":{"id":241,"url":"https://patchwork.libcamera.org/api/1.1/people/241/?format=json","name":"Rui Wang","email":"rui.wang@ideasonboard.com"},"delegate":null,"mbox":"https://patchwork.libcamera.org/patch/25826/mbox/","series":[{"id":5712,"url":"https://patchwork.libcamera.org/api/1.1/series/5712/?format=json","web_url":"https://patchwork.libcamera.org/project/libcamera/list/?series=5712","date":"2026-01-18T20:29:49","name":"Filter algorithm refactoring and mode switching","version":1,"mbox":"https://patchwork.libcamera.org/series/5712/mbox/"}],"comments":"https://patchwork.libcamera.org/api/patches/25826/comments/","check":"pending","checks":"https://patchwork.libcamera.org/api/patches/25826/checks/","tags":{},"headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 0C92BBDCBE\n\tfor <parsemail@patchwork.libcamera.org>;\n\tSun, 18 Jan 2026 20:30:43 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id C8B0161FB9;\n\tSun, 18 Jan 2026 21:30:42 +0100 (CET)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id EEC3661FB9\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSun, 18 Jan 2026 21:30:40 +0100 (CET)","from rui-Precision-7560.local (unknown [209.216.103.65])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id BFEB51BA;\n\tSun, 18 Jan 2026 21:30:10 +0100 (CET)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"skJ70AEK\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1768768211;\n\tbh=fY8F3AL+hPMykr4ZGbXKshuzs571yQFx8yt80SPlZeg=;\n\th=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n\tb=skJ70AEKQKmaOQs/1BMCgHadLA6QScRe0dHzPixOAaAaPQIR5aM9HCvE1lVPncpWk\n\tUn/UYWqDxq39i6IBcBL6+rAdZrp91tBv+mt02t9csCXW1QkVg3noXeo6wTPISeawoS\n\t6mIYRfh4gN1EPPzWfDzHtAXxC1JXI4/ln5GW+aw8=","From":"Rui Wang <rui.wang@ideasonboard.com>","To":"libcamera-devel@lists.libcamera.org","Cc":"Rui Wang <rui.wang@ideasonboard.com>","Subject":"[PATCH v1 1/4] ipa: rkisp1: algorithms: filter: Implement noise\n\treduction mode switching","Date":"Sun, 18 Jan 2026 15:29:50 -0500","Message-ID":"<20260118202953.1554892-2-rui.wang@ideasonboard.com>","X-Mailer":"git-send-email 2.43.0","In-Reply-To":"<20260118202953.1554892-1-rui.wang@ideasonboard.com>","References":"<20260118202953.1554892-1-rui.wang@ideasonboard.com>","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"},"content":"Add support for switching between different noise reduction modes in the\nFilter algorithm, mirroring the implementation approach used in the DPF\nalgorithm.\n\nThis allows the Filter to be configured with multiple mode-specific\nparameter sets, enabling runtime switching between different filtering\nstrengths via the NoiseReductionMode control.\n\nKey changes:\n- Introduce ModeConfig structure to store mode-specific filter configurations.\n- Implement parseConfig() to parse NoiseReductionModes from tuning data.\n- Add parseSingleConfig() to parse individual mode configurations with\n  inheritance support (modes can override base config values).\n- Implement loadConfig() to switch between configured modes at runtime.\n- Add kModesMap for string-to-int mode name mapping.\n- Support optional ActiveMode tuning parameter to set default mode.\n- Add modeName() helper for reverse lookup (int to string) for logging.\n\nThe implementation follows the same pattern as the DPF algorithm,\nensuring consistency across the rkisp1 IPA module.\n\nExample YAML configuration for Filter:\n- Filter:\n      NoiseReductionModes:\n        - type: \"ReductionMinimal\"\n          mode: 1266           # 0x000004f2 in decimal\n          lum_weight: 139328   # 0x00022040 in decimal\n          grn_stage1: 6\n          chr_h_mode: 3\n          chr_v_mode: 3\n          thresh_bl0: 8\n          thresh_bl1: 2\n          thresh_sh0: 18\n          thresh_sh1: 33\n          fac_sh0: 4\n          fac_sh1: 4\n          fac_mid: 4\n          fac_bl0: 2\n          fac_bl1: 0\n\t- type: \"fast\"\n          ...\n      ActiveMode: \"ReductionMinimal\"\n\nSigned-off-by: Rui Wang <rui.wang@ideasonboard.com>\n---\n src/ipa/rkisp1/algorithms/filter.cpp | 149 ++++++++++++++++++++++++++-\n src/ipa/rkisp1/algorithms/filter.h   |  16 ++-\n 2 files changed, 163 insertions(+), 2 deletions(-)","diff":"diff --git a/src/ipa/rkisp1/algorithms/filter.cpp b/src/ipa/rkisp1/algorithms/filter.cpp\nindex 8ad79801..321e4122 100644\n--- a/src/ipa/rkisp1/algorithms/filter.cpp\n+++ b/src/ipa/rkisp1/algorithms/filter.cpp\n@@ -8,11 +8,17 @@\n #include \"filter.h\"\n \n #include <cmath>\n+#include <map>\n+#include <optional>\n+#include <string>\n+#include <vector>\n \n #include <libcamera/base/log.h>\n \n #include <libcamera/control_ids.h>\n \n+#include \"linux/rkisp1-config.h\"\n+\n /**\n  * \\file filter.h\n  */\n@@ -36,20 +42,161 @@ namespace ipa::rkisp1::algorithms {\n \n LOG_DEFINE_CATEGORY(RkISP1Filter)\n \n+namespace {\n+\n static constexpr uint32_t kFiltLumWeightDefault = 0x00022040;\n static constexpr uint32_t kFiltModeDefault = 0x000004f2;\n \n+const std::map<std::string, int32_t> kModesMap = {\n+\t{ \"ReductionMinimal\", controls::draft::NoiseReductionModeMinimal },\n+\t{ \"ReductionFast\", controls::draft::NoiseReductionModeFast },\n+\t{ \"ReductionHighQuality\", controls::draft::NoiseReductionModeHighQuality },\n+\t{ \"ReductionZSL\", controls::draft::NoiseReductionModeZSL },\n+\t{ \"ReductionOff\", controls::draft::NoiseReductionModeOff },\n+};\n+\n+std::string modeName(int32_t mode)\n+{\n+\tauto it = std::find_if(kModesMap.begin(), kModesMap.end(),\n+\t\t\t       [mode](const auto &pair) {\n+\t\t\t\t       return pair.second == mode;\n+\t\t\t       });\n+\n+\tif (it != kModesMap.end())\n+\t\treturn it->first;\n+\n+\treturn \"ReductionUnknown\";\n+}\n+} /* namespace */\n+\n+Filter::Filter()\n+\t: noiseReductionModes_({}),\n+\t  activeMode_(noiseReductionModes_.end())\n+{\n+}\n+\n /**\n  * \\copydoc libcamera::ipa::Algorithm::init\n  */\n int Filter::init(IPAContext &context,\n-\t\t [[maybe_unused]] const YamlObject &tuningData)\n+\t\t const YamlObject &tuningData)\n {\n \tauto &cmap = context.ctrlMap;\n \tcmap[&controls::Sharpness] = ControlInfo(0.0f, 10.0f, 1.0f);\n \n+\t/* Parse tuning block. */\n+\tint ret = parseConfig(tuningData);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\treturn 0;\n+}\n+\n+int Filter::parseConfig(const YamlObject &tuningData)\n+{\n+\t/* Parse noise reduction modes. */\n+\tif (!tuningData.contains(\"NoiseReductionModes\")) {\n+\t\tLOG(RkISP1Filter, Error) << \"Missing modes in Filter tuning data\";\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tnoiseReductionModes_.clear();\n+\tfor (const auto &entry : tuningData[\"NoiseReductionModes\"].asList()) {\n+\t\tstd::optional<std::string> typeOpt =\n+\t\t\tentry[\"type\"].get<std::string>();\n+\t\tif (!typeOpt) {\n+\t\t\tLOG(RkISP1Filter, Error) << \"Modes entry missing type\";\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\n+\t\tModeConfig mode;\n+\t\tauto it = kModesMap.find(*typeOpt);\n+\t\tif (it == kModesMap.end()) {\n+\t\t\tLOG(RkISP1Filter, Error) << \"Unknown mode type: \" << *typeOpt;\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\n+\t\tmode.modeValue = it->second;\n+\t\tint ret = parseSingleConfig(entry, mode.config);\n+\t\tif (ret) {\n+\t\t\tLOG(RkISP1Filter, Error) << \"Failed to parse mode: \" << *typeOpt;\n+\t\t\treturn ret;\n+\t\t}\n+\n+\t\tnoiseReductionModes_.push_back(mode);\n+\t}\n+\n+\t/*\n+\t * Parse the optional ActiveMode.\n+\t * If not present, default to \"ReductionOff\".\n+\t */\n+\tstd::string activeMode = tuningData[\"ActiveMode\"].get<std::string>().value_or(\"ReductionOff\");\n+\tauto it = kModesMap.find(activeMode);\n+\tif (it == kModesMap.end()) {\n+\t\tLOG(RkISP1Filter, Warning) << \"Invalid ActiveMode: \" << activeMode;\n+\t\tactiveMode_ = noiseReductionModes_.end();\n+\t\treturn 0;\n+\t}\n+\n+\tif (!loadConfig(it->second)) {\n+\t\t/* If the default \"ReductionOff\" mode is requested but not configured, disable Filter. */\n+\t\tif (it->second == controls::draft::NoiseReductionModeOff)\n+\t\t\tactiveMode_ = noiseReductionModes_.end();\n+\t\telse\n+\t\t\treturn -EINVAL;\n+\t}\n+\n+\treturn 0;\n+}\n+int Filter::parseSingleConfig(const YamlObject &tuningData,\n+\t\t\t      struct rkisp1_cif_isp_flt_config &config)\n+{\n+\tif (!tuningData.contains(\"mode\") || !tuningData.contains(\"lum_weight\")) {\n+\t\tLOG(RkISP1Filter, Error) << \"Modes entry missing mode or lum_weight\";\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tconfig.mode = tuningData[\"mode\"].get<uint32_t>().value_or(kFiltModeDefault);\n+\tconfig.lum_weight = tuningData[\"lum_weight\"].get<uint32_t>().value_or(kFiltLumWeightDefault);\n+\tconfig.grn_stage1 = tuningData[\"grn_stage1\"].get<uint8_t>().value_or(config.grn_stage1);\n+\tconfig.chr_h_mode = tuningData[\"chr_h_mode\"].get<uint8_t>().value_or(config.chr_h_mode);\n+\tconfig.chr_v_mode = tuningData[\"chr_v_mode\"].get<uint8_t>().value_or(config.chr_v_mode);\n+\n+\tconfig.thresh_bl0 = tuningData[\"thresh_bl0\"].get<uint32_t>().value_or(config.thresh_bl0);\n+\tconfig.thresh_bl1 = tuningData[\"thresh_bl1\"].get<uint32_t>().value_or(config.thresh_bl1);\n+\tconfig.thresh_sh0 = tuningData[\"thresh_sh0\"].get<uint32_t>().value_or(config.thresh_sh0);\n+\tconfig.thresh_sh1 = tuningData[\"thresh_sh1\"].get<uint32_t>().value_or(config.thresh_sh1);\n+\n+\tconfig.fac_sh0 = tuningData[\"fac_sh0\"].get<uint32_t>().value_or(config.fac_sh0);\n+\tconfig.fac_sh1 = tuningData[\"fac_sh1\"].get<uint32_t>().value_or(config.fac_sh1);\n+\tconfig.fac_mid = tuningData[\"fac_mid\"].get<uint32_t>().value_or(config.fac_mid);\n+\tconfig.fac_bl0 = tuningData[\"fac_bl0\"].get<uint32_t>().value_or(config.fac_bl0);\n+\tconfig.fac_bl1 = tuningData[\"fac_bl1\"].get<uint32_t>().value_or(config.fac_bl1);\n+\n \treturn 0;\n }\n+\n+bool Filter::loadConfig(int32_t mode)\n+{\n+\tauto it = std::find_if(noiseReductionModes_.begin(), noiseReductionModes_.end(),\n+\t\t\t       [mode](const ModeConfig &m) {\n+\t\t\t\t       return m.modeValue == mode;\n+\t\t\t       });\n+\tif (it == noiseReductionModes_.end()) {\n+\t\tLOG(RkISP1Filter, Warning)\n+\t\t\t<< \"No Filter config for reduction mode: \" << modeName(mode);\n+\t\treturn false;\n+\t}\n+\n+\tactiveMode_ = it;\n+\n+\tLOG(RkISP1Filter, Debug)\n+\t\t<< \"Filter mode=Reduction (config loaded)\"\n+\t\t<< \" mode= \" << modeName(mode);\n+\n+\treturn true;\n+}\n+\n /**\n  * \\copydoc libcamera::ipa::Algorithm::queueRequest\n  */\ndiff --git a/src/ipa/rkisp1/algorithms/filter.h b/src/ipa/rkisp1/algorithms/filter.h\nindex 37d8938d..3860adfd 100644\n--- a/src/ipa/rkisp1/algorithms/filter.h\n+++ b/src/ipa/rkisp1/algorithms/filter.h\n@@ -18,7 +18,7 @@ namespace ipa::rkisp1::algorithms {\n class Filter : public Algorithm\n {\n public:\n-\tFilter() = default;\n+\tFilter();\n \t~Filter() = default;\n \n \tint init(IPAContext &context, const YamlObject &tuningData) override;\n@@ -28,6 +28,20 @@ public:\n \tvoid prepare(IPAContext &context, const uint32_t frame,\n \t\t     IPAFrameContext &frameContext,\n \t\t     RkISP1Params *params) override;\n+\n+private:\n+\tstruct ModeConfig {\n+\t\tint32_t modeValue;\n+\t\trkisp1_cif_isp_flt_config config;\n+\t};\n+\n+\tint parseConfig(const YamlObject &tuningData);\n+\tint parseSingleConfig(const YamlObject &tuningData,\n+\t\t\t      struct rkisp1_cif_isp_flt_config &config);\n+\n+\tbool loadConfig(int32_t mode);\n+\tstd::vector<ModeConfig> noiseReductionModes_;\n+\tstd::vector<ModeConfig>::const_iterator activeMode_;\n };\n \n } /* namespace ipa::rkisp1::algorithms */\n","prefixes":["v1","1/4"]}