From patchwork Tue Oct 28 17:08:41 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Rui Wang X-Patchwork-Id: 24864 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 2D622BE080 for ; Tue, 28 Oct 2025 17:09:26 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id D31F860865; Tue, 28 Oct 2025 18:09:25 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="Td07sbgS"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D097A6080D for ; Tue, 28 Oct 2025 18:09:19 +0100 (CET) Received: from rui-Precision-7560.local (unknown [209.216.122.90]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id E28CB16A7; Tue, 28 Oct 2025 18:07:30 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1761671251; bh=VM7BJW0PIRTikYJfzWD7uCOHDDpHhwK0H4wJuK3onrQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Td07sbgSA3yaofWjXCaZt8w2wLMnStzMmaNf0b0Spfo5p/6d0VlqPVp+SSZDd3/hs bcvrFNOYbnSolDhN5rLUgpP2igfg7iNwabfsjUKbQYqd9e2WpkO+bmTbFRufA+gwTY P6dyGCEF/VL8zxQPWXCY5b04WSrOQp9nHslp7HDE= From: Rui Wang To: libcamera-devel@lists.libcamera.org Cc: Rui Wang Subject: [PATCH v1 12/16] ipa: rkisp1: algorithms: dpf: manage DPF mode transitions Date: Tue, 28 Oct 2025 13:08:41 -0400 Message-ID: <20251028170847.2673396-12-rui.wang@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251028170847.2673396-1-rui.wang@ideasonboard.com> References: <20251028170847.2673396-1-rui.wang@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Implement hysteresis-aware mode switching via processModeChange(), snapshot the current configuration when entering manual mode, and restore base tuning when returning to auto mode. The implementation includes: - processModeChange(): Detects DpfMode control changes with hysteresis to prevent rapid mode toggling (minimum 5-frame interval) - snapshotCurrentToOverrides(): Captures current config when entering manual mode so users can continue from current state - restoreAutoConfig(): Restores base or ISO-banded config when returning to auto mode, clearing all manual overrides Updates queueRequest() to handle mode transitions with appropriate logging and config restoration. Signed-off-by: Rui Wang --- src/ipa/rkisp1/algorithms/denoise.h | 14 +++++ src/ipa/rkisp1/algorithms/dpf.cpp | 76 +++++++++++++++++++++++++++ src/ipa/rkisp1/algorithms/dpf.h | 11 ++++ src/libcamera/control_ids_rkisp1.yaml | 39 ++++++++++++++ 4 files changed, 140 insertions(+) diff --git a/src/ipa/rkisp1/algorithms/denoise.h b/src/ipa/rkisp1/algorithms/denoise.h index 1a874def..c4b5b0af 100644 --- a/src/ipa/rkisp1/algorithms/denoise.h +++ b/src/ipa/rkisp1/algorithms/denoise.h @@ -20,10 +20,12 @@ class DenoiseBaseAlgorithm : public ipa::rkisp1::Algorithm protected: DenoiseBaseAlgorithm() = default; ~DenoiseBaseAlgorithm() = default; + struct EnableState { bool enabled = true; /**< Current enable state */ bool lastEnabled = true; /**< Previous enable state for change detection */ }; + bool processEnableToggle(bool value, EnableState &state); void setManualMode(bool manual) { manualMode_ = manual; } @@ -31,15 +33,27 @@ protected: void setDevMode(bool dev) { devMode_ = dev; } bool isManualMode() const { return manualMode_; } + bool isDevMode() const { return devMode_; } + unsigned computeIso(const IPAContext &context, const IPAFrameContext &frameContext) const; + template int selectIsoBand(unsigned iso, const LevelContainer &levels) const; + virtual bool parseConfig(const YamlObject &tuningData) = 0; + virtual void handleEnableControl(const ControlList &controls, IPAFrameContext &frameContext, IPAContext &context) = 0; + virtual void collectManualOverrides(const ControlList &controls) = 0; + virtual bool processModeChange(const ControlList &controls, uint32_t currentFrame) = 0; + + virtual void snapshotCurrentToOverrides() = 0; + + virtual void restoreAutoConfig(IPAContext &context, IPAFrameContext &frameContext) = 0; + private: bool manualMode_ = false; /**< Current manual/auto mode state */ bool devMode_ = false; /**< Developer mode state for advanced controls */ diff --git a/src/ipa/rkisp1/algorithms/dpf.cpp b/src/ipa/rkisp1/algorithms/dpf.cpp index cefa5da5..f6bbe3e4 100644 --- a/src/ipa/rkisp1/algorithms/dpf.cpp +++ b/src/ipa/rkisp1/algorithms/dpf.cpp @@ -338,6 +338,71 @@ bool Dpf::checkDevModeOverridesChanged() return changed; } +void Dpf::snapshotCurrentToOverrides() +{ + overrides_.clear(); + overrides_.strength = DpfStrengthSettings{ strengthConfig_.r, strengthConfig_.g, strengthConfig_.b }; + if (isDevMode()) { + DpfSpatialGreenSettings green; + std::copy_n(std::begin(config_.g_flt.spatial_coeff), RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS, green.coeffs.begin()); + overrides_.spatialGreen = green; + DpfSpatialRbSettings rb; + std::copy_n(std::begin(config_.rb_flt.spatial_coeff), RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS, rb.coeffs.begin()); + rb.size = (config_.rb_flt.fltsize == RKISP1_CIF_ISP_DPF_RB_FILTERSIZE_13x9) ? 1 : 0; + overrides_.spatialRb = rb; + overrides_.rbSize = rb.size; + DpfNllSettings nll; + std::copy_n(std::begin(config_.nll.coeff), RKISP1_CIF_ISP_DPF_MAX_NLF_COEFFS, nll.coeffs.begin()); + nll.scaleMode = (config_.nll.scale_mode == RKISP1_CIF_ISP_NLL_SCALE_LOGARITHMIC) ? 1 : 0; + overrides_.nll = nll; + } +} + +void Dpf::restoreAutoConfig(IPAContext &context, IPAFrameContext &frameContext) +{ + overrides_.clear(); + if (useIsoLevels_) { + unsigned iso = computeIso(context, frameContext); + int idx = DenoiseBaseAlgorithm::selectIsoBand(iso, isoLevels_); + if (idx >= 0) { + config_ = isoLevels_[idx].dpf; + strengthConfig_ = isoLevels_[idx].strength; + lastIsoIndex_ = idx; + } + } else { + config_ = baseConfig_; + strengthConfig_ = baseStrengthConfig_; + lastIsoIndex_ = -1; + } + frameContext.dpf.update = true; +} + +bool Dpf::processModeChange(const ControlList &controls, uint32_t currentFrame) +{ + const auto &cMode = controls.get(controls::rkisp1::DpfMode); + if (!cMode) + return false; + + bool requested = (*cMode == controls::rkisp1::DpfModeManual); + if (requested == isManualMode()) + return false; + + // Prevent rapid mode changes (hysteresis to avoid application bugs) + uint32_t framesSinceLastChange = currentFrame - lastModeChangeFrame_; + if (framesSinceLastChange < kMinModeChangeInterval && lastModeChangeFrame_ != 0) { + LOG(RkISP1Dpf, Debug) << "Ignoring rapid mode change (hysteresis): requested=" + << (requested ? "manual" : "auto") + << ", current=" << (isManualMode() ? "manual" : "auto") + << ", framesSinceLast=" << framesSinceLastChange; + return false; + } + + setManualMode(requested); + // Reset overrides if switching to auto mode , make sure the config will apply to next frame + lastModeChangeFrame_ = currentFrame; + return true; +} + /** * \copydoc libcamera::ipa::Algorithm::queueRequest */ @@ -348,6 +413,17 @@ void Dpf::queueRequest(IPAContext &context, { frameContext.dpf.update = false; handleEnableControl(controls, frameContext, context); + bool modeChanged = processModeChange(controls, frame); + if (modeChanged) { + if (isManualMode()) { + snapshotCurrentToOverrides(); + LOG(RkISP1Dpf, Info) << "DPF mode=Manual (snapshot captured)"; + } else { + restoreAutoConfig(context, frameContext); + LOG(RkISP1Dpf, Info) << "DPF mode=Auto (restored auto config)"; + } + frameContext.dpf.update = true; + } if (isManualMode()) { collectManualOverrides(controls); diff --git a/src/ipa/rkisp1/algorithms/dpf.h b/src/ipa/rkisp1/algorithms/dpf.h index b971619b..b6676203 100644 --- a/src/ipa/rkisp1/algorithms/dpf.h +++ b/src/ipa/rkisp1/algorithms/dpf.h @@ -78,6 +78,11 @@ private: std::vector isoLevels_; bool useIsoLevels_ = false; bool enableDpf_ = true; /* YAML master enable */ + int lastIsoIndex_ = -1; + + /* Mode change protection */ + uint32_t lastModeChangeFrame_ = 0; + static constexpr uint32_t kMinModeChangeInterval = 2; /* frames */ void handleEnableControl(const ControlList &controls, IPAFrameContext &frameContext, IPAContext &context) override; @@ -90,6 +95,12 @@ private: bool parseSingleConfig(const YamlObject &config, rkisp1_cif_isp_dpf_config &cfg, rkisp1_cif_isp_dpf_strength_config &strength); + + bool processModeChange(const ControlList &controls, uint32_t currentFrame) override; + + void snapshotCurrentToOverrides() override; + + void restoreAutoConfig(IPAContext &context, IPAFrameContext &frameContext) override; }; } /* namespace ipa::rkisp1::algorithms */ diff --git a/src/libcamera/control_ids_rkisp1.yaml b/src/libcamera/control_ids_rkisp1.yaml index bf7875e9..78b95447 100644 --- a/src/libcamera/control_ids_rkisp1.yaml +++ b/src/libcamera/control_ids_rkisp1.yaml @@ -82,5 +82,44 @@ controls: - name: DpfNoiseLevelLookupScaleLogarithmic value: 1 description: Logarithmic scale. + - DpfMode: + type: int32_t + direction: inout + description: | + Controls the operating mode of the Denoise Pre-Filter (DPF) algorithm. + + In Auto mode the algorithm selects parameters automatically from the + sensor tuning data and (if provided) the ISO level table. Changes in + scene brightness (analogue gain / ISO) may cause the algorithm to + re-evaluate and reprogram the hardware when an ISO band boundary is + crossed. + + In Manual mode the automatically selected parameters are frozen at + the moment the mode switch occurs (a snapshot is taken). Subsequent + per‑frame automatic ISO/tuning updates are disabled until the mode is + set back to Auto. While in Manual mode the application may modify any + of the override controls (e.g. DpfChannelStrengths, DpfGreenSpatialCoefficients, + DpfRedBlueSpatialCoefficients, DpfRbFilterSize, DpfNoiseLevelLookupCoefficients, + DpfNoiseLevelLookupScaleMode). Changes are applied immediately to hardware. + + Transition Rules: + * Auto -> Manual: The current effective (auto-selected) parameters + are captured as the initial manual override values. + * Manual -> Auto: All manual override state is discarded and the + algorithm immediately reverts to automatic tuning selection, + potentially reprogramming hardware that same frame. + + If the application switches to Manual but supplies no overrides, + the previously auto-derived parameters continue to be used unchanged. + + \\sa DpfEnable + \\sa DpfChannelStrengths + enum: + - name: DpfModeAuto + value: 0 + description: Automatic mode - algorithm selects parameters based on tuning data. + - name: DpfModeManual + value: 1 + description: Manual mode - parameters are frozen and can be overridden. ...