Patch Detail
Show a patch.
GET /api/patches/24864/?format=api
{ "id": 24864, "url": "https://patchwork.libcamera.org/api/patches/24864/?format=api", "web_url": "https://patchwork.libcamera.org/patch/24864/", "project": { "id": 1, "url": "https://patchwork.libcamera.org/api/projects/1/?format=api", "name": "libcamera", "link_name": "libcamera", "list_id": "libcamera_core", "list_email": "libcamera-devel@lists.libcamera.org", "web_url": "", "scm_url": "", "webscm_url": "" }, "msgid": "<20251028170847.2673396-12-rui.wang@ideasonboard.com>", "date": "2025-10-28T17:08:41", "name": "[v1,12/16] ipa: rkisp1: algorithms: dpf: manage DPF mode transitions", "commit_ref": null, "pull_url": null, "state": "superseded", "archived": false, "hash": "52fa112dfd15d2195c005f2226e640c8e56ebd47", "submitter": { "id": 241, "url": "https://patchwork.libcamera.org/api/people/241/?format=api", "name": "Rui Wang", "email": "rui.wang@ideasonboard.com" }, "delegate": null, "mbox": "https://patchwork.libcamera.org/patch/24864/mbox/", "series": [ { "id": 5539, "url": "https://patchwork.libcamera.org/api/series/5539/?format=api", "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=5539", "date": "2025-10-28T17:08:30", "name": "[v1,01/16] ipa: rkisp1: algorithms: add Denoise base class shell", "version": 1, "mbox": "https://patchwork.libcamera.org/series/5539/mbox/" } ], "comments": "https://patchwork.libcamera.org/api/patches/24864/comments/", "check": "pending", "checks": "https://patchwork.libcamera.org/api/patches/24864/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 2D622BE080\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 28 Oct 2025 17:09:26 +0000 (UTC)", "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id D31F860865;\n\tTue, 28 Oct 2025 18:09:25 +0100 (CET)", "from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id D097A6080D\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 28 Oct 2025 18:09:19 +0100 (CET)", "from rui-Precision-7560.local (unknown [209.216.122.90])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id E28CB16A7;\n\tTue, 28 Oct 2025 18:07:30 +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=\"Td07sbgS\"; dkim-atps=neutral", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1761671251;\n\tbh=VM7BJW0PIRTikYJfzWD7uCOHDDpHhwK0H4wJuK3onrQ=;\n\th=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n\tb=Td07sbgSA3yaofWjXCaZt8w2wLMnStzMmaNf0b0Spfo5p/6d0VlqPVp+SSZDd3/hs\n\tbcvrFNOYbnSolDhN5rLUgpP2igfg7iNwabfsjUKbQYqd9e2WpkO+bmTbFRufA+gwTY\n\tP6dyGCEF/VL8zxQPWXCY5b04WSrOQp9nHslp7HDE=", "From": "Rui Wang <rui.wang@ideasonboard.com>", "To": "libcamera-devel@lists.libcamera.org", "Cc": "Rui Wang <rui.wang@ideasonboard.com>", "Subject": "[PATCH v1 12/16] ipa: rkisp1: algorithms: dpf: manage DPF mode\n\ttransitions", "Date": "Tue, 28 Oct 2025 13:08:41 -0400", "Message-ID": "<20251028170847.2673396-12-rui.wang@ideasonboard.com>", "X-Mailer": "git-send-email 2.43.0", "In-Reply-To": "<20251028170847.2673396-1-rui.wang@ideasonboard.com>", "References": "<20251028170847.2673396-1-rui.wang@ideasonboard.com>", "MIME-Version": "1.0", "Content-Type": "text/plain; charset=UTF-8", "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": "Implement hysteresis-aware mode switching via processModeChange(), snapshot\nthe current configuration when entering manual mode, and restore base tuning\nwhen returning to auto mode.\n\nThe implementation includes:\n- processModeChange(): Detects DpfMode control changes with hysteresis to\n prevent rapid mode toggling (minimum 5-frame interval)\n- snapshotCurrentToOverrides(): Captures current config when entering manual\n mode so users can continue from current state\n- restoreAutoConfig(): Restores base or ISO-banded config when returning to\n auto mode, clearing all manual overrides\n\nUpdates queueRequest() to handle mode transitions with appropriate logging\nand config restoration.\n\nSigned-off-by: Rui Wang <rui.wang@ideasonboard.com>\n---\n src/ipa/rkisp1/algorithms/denoise.h | 14 +++++\n src/ipa/rkisp1/algorithms/dpf.cpp | 76 +++++++++++++++++++++++++++\n src/ipa/rkisp1/algorithms/dpf.h | 11 ++++\n src/libcamera/control_ids_rkisp1.yaml | 39 ++++++++++++++\n 4 files changed, 140 insertions(+)", "diff": "diff --git a/src/ipa/rkisp1/algorithms/denoise.h b/src/ipa/rkisp1/algorithms/denoise.h\nindex 1a874def..c4b5b0af 100644\n--- a/src/ipa/rkisp1/algorithms/denoise.h\n+++ b/src/ipa/rkisp1/algorithms/denoise.h\n@@ -20,10 +20,12 @@ class DenoiseBaseAlgorithm : public ipa::rkisp1::Algorithm\n protected:\n \tDenoiseBaseAlgorithm() = default;\n \t~DenoiseBaseAlgorithm() = default;\n+\n \tstruct EnableState {\n \t\tbool enabled = true; /**< Current enable state */\n \t\tbool lastEnabled = true; /**< Previous enable state for change detection */\n \t};\n+\n \tbool processEnableToggle(bool value, EnableState &state);\n \n \tvoid setManualMode(bool manual) { manualMode_ = manual; }\n@@ -31,15 +33,27 @@ protected:\n \tvoid setDevMode(bool dev) { devMode_ = dev; }\n \n \tbool isManualMode() const { return manualMode_; }\n+\n \tbool isDevMode() const { return devMode_; }\n+\n \tunsigned computeIso(const IPAContext &context,\n \t\t\t const IPAFrameContext &frameContext) const;\n+\n \ttemplate<typename LevelContainer>\n \tint selectIsoBand(unsigned iso, const LevelContainer &levels) const;\n+\n \tvirtual bool parseConfig(const YamlObject &tuningData) = 0;\n+\n \tvirtual void handleEnableControl(const ControlList &controls, IPAFrameContext &frameContext, IPAContext &context) = 0;\n+\n \tvirtual void collectManualOverrides(const ControlList &controls) = 0;\n \n+\tvirtual bool processModeChange(const ControlList &controls, uint32_t currentFrame) = 0;\n+\n+\tvirtual void snapshotCurrentToOverrides() = 0;\n+\n+\tvirtual void restoreAutoConfig(IPAContext &context, IPAFrameContext &frameContext) = 0;\n+\n private:\n \tbool manualMode_ = false; /**< Current manual/auto mode state */\n \tbool devMode_ = false; /**< Developer mode state for advanced controls */\ndiff --git a/src/ipa/rkisp1/algorithms/dpf.cpp b/src/ipa/rkisp1/algorithms/dpf.cpp\nindex cefa5da5..f6bbe3e4 100644\n--- a/src/ipa/rkisp1/algorithms/dpf.cpp\n+++ b/src/ipa/rkisp1/algorithms/dpf.cpp\n@@ -338,6 +338,71 @@ bool Dpf::checkDevModeOverridesChanged()\n \treturn changed;\n }\n \n+void Dpf::snapshotCurrentToOverrides()\n+{\n+\toverrides_.clear();\n+\toverrides_.strength = DpfStrengthSettings{ strengthConfig_.r, strengthConfig_.g, strengthConfig_.b };\n+\tif (isDevMode()) {\n+\t\tDpfSpatialGreenSettings green;\n+\t\tstd::copy_n(std::begin(config_.g_flt.spatial_coeff), RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS, green.coeffs.begin());\n+\t\toverrides_.spatialGreen = green;\n+\t\tDpfSpatialRbSettings rb;\n+\t\tstd::copy_n(std::begin(config_.rb_flt.spatial_coeff), RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS, rb.coeffs.begin());\n+\t\trb.size = (config_.rb_flt.fltsize == RKISP1_CIF_ISP_DPF_RB_FILTERSIZE_13x9) ? 1 : 0;\n+\t\toverrides_.spatialRb = rb;\n+\t\toverrides_.rbSize = rb.size;\n+\t\tDpfNllSettings nll;\n+\t\tstd::copy_n(std::begin(config_.nll.coeff), RKISP1_CIF_ISP_DPF_MAX_NLF_COEFFS, nll.coeffs.begin());\n+\t\tnll.scaleMode = (config_.nll.scale_mode == RKISP1_CIF_ISP_NLL_SCALE_LOGARITHMIC) ? 1 : 0;\n+\t\toverrides_.nll = nll;\n+\t}\n+}\n+\n+void Dpf::restoreAutoConfig(IPAContext &context, IPAFrameContext &frameContext)\n+{\n+\toverrides_.clear();\n+\tif (useIsoLevels_) {\n+\t\tunsigned iso = computeIso(context, frameContext);\n+\t\tint idx = DenoiseBaseAlgorithm::selectIsoBand(iso, isoLevels_);\n+\t\tif (idx >= 0) {\n+\t\t\tconfig_ = isoLevels_[idx].dpf;\n+\t\t\tstrengthConfig_ = isoLevels_[idx].strength;\n+\t\t\tlastIsoIndex_ = idx;\n+\t\t}\n+\t} else {\n+\t\tconfig_ = baseConfig_;\n+\t\tstrengthConfig_ = baseStrengthConfig_;\n+\t\tlastIsoIndex_ = -1;\n+\t}\n+\tframeContext.dpf.update = true;\n+}\n+\n+bool Dpf::processModeChange(const ControlList &controls, uint32_t currentFrame)\n+{\n+\tconst auto &cMode = controls.get(controls::rkisp1::DpfMode);\n+\tif (!cMode)\n+\t\treturn false;\n+\n+\tbool requested = (*cMode == controls::rkisp1::DpfModeManual);\n+\tif (requested == isManualMode())\n+\t\treturn false;\n+\n+\t// Prevent rapid mode changes (hysteresis to avoid application bugs)\n+\tuint32_t framesSinceLastChange = currentFrame - lastModeChangeFrame_;\n+\tif (framesSinceLastChange < kMinModeChangeInterval && lastModeChangeFrame_ != 0) {\n+\t\tLOG(RkISP1Dpf, Debug) << \"Ignoring rapid mode change (hysteresis): requested=\"\n+\t\t\t\t << (requested ? \"manual\" : \"auto\")\n+\t\t\t\t << \", current=\" << (isManualMode() ? \"manual\" : \"auto\")\n+\t\t\t\t << \", framesSinceLast=\" << framesSinceLastChange;\n+\t\treturn false;\n+\t}\n+\n+\tsetManualMode(requested);\n+\t// Reset overrides if switching to auto mode , make sure the config will apply to next frame\n+\tlastModeChangeFrame_ = currentFrame;\n+\treturn true;\n+}\n+\n /**\n * \\copydoc libcamera::ipa::Algorithm::queueRequest\n */\n@@ -348,6 +413,17 @@ void Dpf::queueRequest(IPAContext &context,\n {\n \tframeContext.dpf.update = false;\n \thandleEnableControl(controls, frameContext, context);\n+\tbool modeChanged = processModeChange(controls, frame);\n+\tif (modeChanged) {\n+\t\tif (isManualMode()) {\n+\t\t\tsnapshotCurrentToOverrides();\n+\t\t\tLOG(RkISP1Dpf, Info) << \"DPF mode=Manual (snapshot captured)\";\n+\t\t} else {\n+\t\t\trestoreAutoConfig(context, frameContext);\n+\t\t\tLOG(RkISP1Dpf, Info) << \"DPF mode=Auto (restored auto config)\";\n+\t\t}\n+\t\tframeContext.dpf.update = true;\n+\t}\n \n \tif (isManualMode()) {\n \t\tcollectManualOverrides(controls);\ndiff --git a/src/ipa/rkisp1/algorithms/dpf.h b/src/ipa/rkisp1/algorithms/dpf.h\nindex b971619b..b6676203 100644\n--- a/src/ipa/rkisp1/algorithms/dpf.h\n+++ b/src/ipa/rkisp1/algorithms/dpf.h\n@@ -78,6 +78,11 @@ private:\n \tstd::vector<IsoLevelConfig> isoLevels_;\n \tbool useIsoLevels_ = false;\n \tbool enableDpf_ = true; /* YAML master enable */\n+\tint lastIsoIndex_ = -1;\n+\n+\t/* Mode change protection */\n+\tuint32_t lastModeChangeFrame_ = 0;\n+\tstatic constexpr uint32_t kMinModeChangeInterval = 2; /* frames */\n \n \tvoid handleEnableControl(const ControlList &controls, IPAFrameContext &frameContext, IPAContext &context) override;\n \n@@ -90,6 +95,12 @@ private:\n \tbool parseSingleConfig(const YamlObject &config,\n \t\t\t rkisp1_cif_isp_dpf_config &cfg,\n \t\t\t rkisp1_cif_isp_dpf_strength_config &strength);\n+\n+\tbool processModeChange(const ControlList &controls, uint32_t currentFrame) override;\n+\n+\tvoid snapshotCurrentToOverrides() override;\n+\n+\tvoid restoreAutoConfig(IPAContext &context, IPAFrameContext &frameContext) override;\n };\n \n } /* namespace ipa::rkisp1::algorithms */\ndiff --git a/src/libcamera/control_ids_rkisp1.yaml b/src/libcamera/control_ids_rkisp1.yaml\nindex bf7875e9..78b95447 100644\n--- a/src/libcamera/control_ids_rkisp1.yaml\n+++ b/src/libcamera/control_ids_rkisp1.yaml\n@@ -82,5 +82,44 @@ controls:\n - name: DpfNoiseLevelLookupScaleLogarithmic\n value: 1\n description: Logarithmic scale.\n+ - DpfMode:\n+ type: int32_t\n+ direction: inout\n+ description: |\n+ Controls the operating mode of the Denoise Pre-Filter (DPF) algorithm.\n+\n+ In Auto mode the algorithm selects parameters automatically from the\n+ sensor tuning data and (if provided) the ISO level table. Changes in\n+ scene brightness (analogue gain / ISO) may cause the algorithm to\n+ re-evaluate and reprogram the hardware when an ISO band boundary is\n+ crossed.\n+\n+ In Manual mode the automatically selected parameters are frozen at\n+ the moment the mode switch occurs (a snapshot is taken). Subsequent\n+ per‑frame automatic ISO/tuning updates are disabled until the mode is\n+ set back to Auto. While in Manual mode the application may modify any\n+ of the override controls (e.g. DpfChannelStrengths, DpfGreenSpatialCoefficients,\n+ DpfRedBlueSpatialCoefficients, DpfRbFilterSize, DpfNoiseLevelLookupCoefficients,\n+ DpfNoiseLevelLookupScaleMode). Changes are applied immediately to hardware.\n+\n+ Transition Rules:\n+ * Auto -> Manual: The current effective (auto-selected) parameters\n+ are captured as the initial manual override values.\n+ * Manual -> Auto: All manual override state is discarded and the\n+ algorithm immediately reverts to automatic tuning selection,\n+ potentially reprogramming hardware that same frame.\n+\n+ If the application switches to Manual but supplies no overrides,\n+ the previously auto-derived parameters continue to be used unchanged.\n+\n+ \\\\sa DpfEnable\n+ \\\\sa DpfChannelStrengths\n+ enum:\n+ - name: DpfModeAuto\n+ value: 0\n+ description: Automatic mode - algorithm selects parameters based on tuning data.\n+ - name: DpfModeManual\n+ value: 1\n+ description: Manual mode - parameters are frozen and can be overridden.\n \n ...\n", "prefixes": [ "v1", "12/16" ] }