From patchwork Tue Oct 28 17: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: 24862 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 00FAFC3259 for ; Tue, 28 Oct 2025 17:09:22 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 196B26083A; Tue, 28 Oct 2025 18: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="S9Kw8by4"; 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 7532D60806 for ; Tue, 28 Oct 2025 18:09:17 +0100 (CET) Received: from rui-Precision-7560.local (unknown [209.216.122.90]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 8B23F16A7; Tue, 28 Oct 2025 18:07:28 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1761671248; bh=umoNTAq5Rg0Hhy6p7LhEHZo9ugpgiKdSfwh1KxILWj0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=S9Kw8by4xuJM9LiEbV8bOynW7phT1lHCYsscSB3eyKsPOXPPaTHk8xRBZN6HAFE3n WUMpEgDpayEEdVOTJTLMgPtEdem85bGH5Em3urNWFZm6mipI7l+9d1u5nxE0RyITdz jL7VlYVG4bFRB6OF4wGorAgWBNk0CopI62SE96rU= From: Rui Wang To: libcamera-devel@lists.libcamera.org Cc: Rui Wang Subject: [PATCH v1 10/16] ipa: rkisp1: algorithms: dpf: collect DPF manual overrides Date: Tue, 28 Oct 2025 13:08:39 -0400 Message-ID: <20251028170847.2673396-10-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 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 | 1 + src/ipa/rkisp1/algorithms/dpf.cpp | 58 +++++++++++++++++++++++++ src/ipa/rkisp1/algorithms/dpf.h | 30 +++++++++++++ src/libcamera/control_ids_rkisp1.yaml | 62 +++++++++++++++++++++++++++ 4 files changed, 151 insertions(+) diff --git a/src/ipa/rkisp1/algorithms/denoise.h b/src/ipa/rkisp1/algorithms/denoise.h index 5bc3f941..1a874def 100644 --- a/src/ipa/rkisp1/algorithms/denoise.h +++ b/src/ipa/rkisp1/algorithms/denoise.h @@ -38,6 +38,7 @@ protected: 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; private: bool manualMode_ = false; /**< Current manual/auto mode state */ diff --git a/src/ipa/rkisp1/algorithms/dpf.cpp b/src/ipa/rkisp1/algorithms/dpf.cpp index d0bed3e4..145f10b7 100644 --- a/src/ipa/rkisp1/algorithms/dpf.cpp +++ b/src/ipa/rkisp1/algorithms/dpf.cpp @@ -243,6 +243,53 @@ void Dpf::handleEnableControl(const ControlList &controls, IPAFrameContext &fram frameContext.dpf.denoise = enableDpf_; } +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()) { + 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 */ @@ -253,6 +300,17 @@ void Dpf::queueRequest(IPAContext &context, { frameContext.dpf.update = false; handleEnableControl(controls, frameContext, context); + + if (isManualMode()) { + collectManualOverrides(controls); + // Check if manual overrides have changed and trigger update + if (overrides_.strength && + (overrides_.strength->r != strengthConfig_.r || + overrides_.strength->g != strengthConfig_.g || + overrides_.strength->b != strengthConfig_.b)) { + frameContext.dpf.update = true; + } + } } /** diff --git a/src/ipa/rkisp1/algorithms/dpf.h b/src/ipa/rkisp1/algorithms/dpf.h index c01f711c..1a33a8c4 100644 --- a/src/ipa/rkisp1/algorithms/dpf.h +++ b/src/ipa/rkisp1/algorithms/dpf.h @@ -34,23 +34,53 @@ 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 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 IsoLevelConfig { unsigned int maxIso; /* inclusive upper bound */ 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 isoLevels_; bool useIsoLevels_ = false; bool enableDpf_ = true; /* YAML master enable */ void handleEnableControl(const ControlList &controls, IPAFrameContext &frameContext, IPAContext &context) override; + void collectManualOverrides(const ControlList &controls) override; bool parseConfig(const YamlObject &tuningData) override; bool parseSingleConfig(const YamlObject &config, rkisp1_cif_isp_dpf_config &cfg, diff --git a/src/libcamera/control_ids_rkisp1.yaml b/src/libcamera/control_ids_rkisp1.yaml index 2f29d508..bf7875e9 100644 --- a/src/libcamera/control_ids_rkisp1.yaml +++ b/src/libcamera/control_ids_rkisp1.yaml @@ -21,4 +21,66 @@ controls: Reported in metadata as a boolean. + - 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 / ISO 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. + ...