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 */