Show a patch.

GET /api/1.1/patches/24880/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 24880,
    "url": "https://patchwork.libcamera.org/api/1.1/patches/24880/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/24880/",
    "project": {
        "id": 1,
        "url": "https://patchwork.libcamera.org/api/1.1/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": "<20251028211751.2761420-10-rui.wang@ideasonboard.com>",
    "date": "2025-10-28T21:17:43",
    "name": "[v1,10/17] ipa: rkisp1: algorithms: dpf: collect DPF manual overrides",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": false,
    "hash": "0ac01643b1127dd1df8f30a52a751482eb387376",
    "submitter": {
        "id": 241,
        "url": "https://patchwork.libcamera.org/api/1.1/people/241/?format=api",
        "name": "Rui Wang",
        "email": "rui.wang@ideasonboard.com"
    },
    "delegate": null,
    "mbox": "https://patchwork.libcamera.org/patch/24880/mbox/",
    "series": [
        {
            "id": 5542,
            "url": "https://patchwork.libcamera.org/api/1.1/series/5542/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=5542",
            "date": "2025-10-28T21:17:34",
            "name": "[v1,01/17] ipa: rkisp1: algorithms: add Denoise base class shell",
            "version": 1,
            "mbox": "https://patchwork.libcamera.org/series/5542/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/24880/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/24880/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 9F631BE080\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 28 Oct 2025 21:18:50 +0000 (UTC)",
            "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 2FBA160859;\n\tTue, 28 Oct 2025 22:18:50 +0100 (CET)",
            "from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 4F8916086F\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 28 Oct 2025 22:18:48 +0100 (CET)",
            "from rui-Precision-7560.local (unknown [209.216.122.90])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 17E1AAD0;\n\tTue, 28 Oct 2025 22:16:58 +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=\"dfG9Jt8B\"; dkim-atps=neutral",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1761686219;\n\tbh=umoNTAq5Rg0Hhy6p7LhEHZo9ugpgiKdSfwh1KxILWj0=;\n\th=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n\tb=dfG9Jt8BSXhjKRarWSq0jpa4zCumtgz9mE+J5Cesw18TeGqySHd/2Gjt/4/oaW+Xp\n\t5eFUeFICMbCN1Q17b7tnEIR/oL5Bx5JTRuDcPsT8IeQ00AXZxmxzyMj+bTtne/WNpJ\n\tXHFIHbu1yv2KaMSCR+/keLRkXpgy5sCw6HLupkdw=",
        "From": "Rui Wang <rui.wang@ideasonboard.com>",
        "To": "libcamera-devel@lists.libcamera.org",
        "Cc": "Rui Wang <rui.wang@ideasonboard.com>",
        "Subject": "[PATCH v1 10/17] ipa: rkisp1: algorithms: dpf: collect DPF manual\n\toverrides",
        "Date": "Tue, 28 Oct 2025 17:17:43 -0400",
        "Message-ID": "<20251028211751.2761420-10-rui.wang@ideasonboard.com>",
        "X-Mailer": "git-send-email 2.43.0",
        "In-Reply-To": "<20251028211751.2761420-1-rui.wang@ideasonboard.com>",
        "References": "<20251028211751.2761420-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": "Implement collectManualOverrides() to capture strength and developer-mode\noverride arrays from control requests. Extend queueRequest() to collect\noverrides in manual mode and mark frames dirty when strength values differ\nfrom the active configuration.\n\nDeveloper mode controls (spatial coefficients, filter size, NLL tables)\nare only collected when devmode is enabled. The function populates the\noverrides_ structure which will be applied during prepare().\n\nSigned-off-by: Rui Wang <rui.wang@ideasonboard.com>\n---\n src/ipa/rkisp1/algorithms/denoise.h   |  1 +\n src/ipa/rkisp1/algorithms/dpf.cpp     | 58 +++++++++++++++++++++++++\n src/ipa/rkisp1/algorithms/dpf.h       | 30 +++++++++++++\n src/libcamera/control_ids_rkisp1.yaml | 62 +++++++++++++++++++++++++++\n 4 files changed, 151 insertions(+)",
    "diff": "diff --git a/src/ipa/rkisp1/algorithms/denoise.h b/src/ipa/rkisp1/algorithms/denoise.h\nindex 5bc3f941..1a874def 100644\n--- a/src/ipa/rkisp1/algorithms/denoise.h\n+++ b/src/ipa/rkisp1/algorithms/denoise.h\n@@ -38,6 +38,7 @@ protected:\n \tint selectIsoBand(unsigned iso, const LevelContainer &levels) const;\n \tvirtual bool parseConfig(const YamlObject &tuningData) = 0;\n \tvirtual void handleEnableControl(const ControlList &controls, IPAFrameContext &frameContext, IPAContext &context) = 0;\n+\tvirtual void collectManualOverrides(const ControlList &controls) = 0;\n \n private:\n \tbool manualMode_ = false; /**< Current manual/auto mode state */\ndiff --git a/src/ipa/rkisp1/algorithms/dpf.cpp b/src/ipa/rkisp1/algorithms/dpf.cpp\nindex d0bed3e4..145f10b7 100644\n--- a/src/ipa/rkisp1/algorithms/dpf.cpp\n+++ b/src/ipa/rkisp1/algorithms/dpf.cpp\n@@ -243,6 +243,53 @@ void Dpf::handleEnableControl(const ControlList &controls, IPAFrameContext &fram\n \tframeContext.dpf.denoise = enableDpf_;\n }\n \n+void Dpf::collectManualOverrides(const ControlList &controls)\n+{\n+\tif (const auto &c = controls.get(controls::rkisp1::DpfChannelStrengths); c) {\n+\t\tif (c->size() == 3) {\n+\t\t\toverrides_.strength = DpfStrengthSettings{ static_cast<uint16_t>((*c)[0]), static_cast<uint16_t>((*c)[1]), static_cast<uint16_t>((*c)[2]) };\n+\t\t}\n+\t}\n+\tif (isDevMode()) {\n+\t\tif (const auto &c = controls.get(controls::rkisp1::DpfGreenSpatialCoefficients); c) {\n+\t\t\tif (c->size() == RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS) {\n+\t\t\t\tDpfSpatialGreenSettings green;\n+\t\t\t\tstd::copy_n(c->begin(), RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS, green.coeffs.begin());\n+\t\t\t\toverrides_.spatialGreen = green;\n+\t\t\t}\n+\t\t}\n+\t\tif (const auto &c = controls.get(controls::rkisp1::DpfRedBlueSpatialCoefficients); c) {\n+\t\t\tif (c->size() == RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS) {\n+\t\t\t\tDpfSpatialRbSettings rb;\n+\t\t\t\tstd::copy_n(c->begin(), RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS, rb.coeffs.begin());\n+\t\t\t\trb.size = (config_.rb_flt.fltsize == RKISP1_CIF_ISP_DPF_RB_FILTERSIZE_13x9) ? 1 : 0;\n+\t\t\t\toverrides_.spatialRb = rb;\n+\t\t\t}\n+\t\t}\n+\t\tif (const auto &c = controls.get(controls::rkisp1::DpfRbFilterSize); c) {\n+\t\t\toverrides_.rbSize = *c ? 1 : 0;\n+\t\t}\n+\t\tif (const auto &c = controls.get(controls::rkisp1::DpfNoiseLevelLookupCoefficients); c) {\n+\t\t\tif (c->size() == RKISP1_CIF_ISP_DPF_MAX_NLF_COEFFS) {\n+\t\t\t\tDpfNllSettings nll;\n+\t\t\t\tstd::copy_n(c->begin(), RKISP1_CIF_ISP_DPF_MAX_NLF_COEFFS, nll.coeffs.begin());\n+\t\t\t\tnll.scaleMode = (config_.nll.scale_mode == RKISP1_CIF_ISP_NLL_SCALE_LOGARITHMIC) ? 1 : 0;\n+\t\t\t\toverrides_.nll = nll;\n+\t\t\t}\n+\t\t}\n+\t\tif (const auto &c = controls.get(controls::rkisp1::DpfNoiseLevelLookupScaleMode); c) {\n+\t\t\tif (overrides_.nll) {\n+\t\t\t\toverrides_.nll->scaleMode = *c ? 1 : 0;\n+\t\t\t} else {\n+\t\t\t\tDpfNllSettings nll;\n+\t\t\t\tstd::copy_n(std::begin(config_.nll.coeff), RKISP1_CIF_ISP_DPF_MAX_NLF_COEFFS, nll.coeffs.begin());\n+\t\t\t\tnll.scaleMode = *c ? 1 : 0;\n+\t\t\t\toverrides_.nll = nll;\n+\t\t\t}\n+\t\t}\n+\t}\n+}\n+\n /**\n  * \\copydoc libcamera::ipa::Algorithm::queueRequest\n  */\n@@ -253,6 +300,17 @@ void Dpf::queueRequest(IPAContext &context,\n {\n \tframeContext.dpf.update = false;\n \thandleEnableControl(controls, frameContext, context);\n+\n+\tif (isManualMode()) {\n+\t\tcollectManualOverrides(controls);\n+\t\t// Check if manual overrides have changed and trigger update\n+\t\tif (overrides_.strength &&\n+\t\t    (overrides_.strength->r != strengthConfig_.r ||\n+\t\t     overrides_.strength->g != strengthConfig_.g ||\n+\t\t     overrides_.strength->b != strengthConfig_.b)) {\n+\t\t\tframeContext.dpf.update = true;\n+\t\t}\n+\t}\n }\n \n /**\ndiff --git a/src/ipa/rkisp1/algorithms/dpf.h b/src/ipa/rkisp1/algorithms/dpf.h\nindex c01f711c..1a33a8c4 100644\n--- a/src/ipa/rkisp1/algorithms/dpf.h\n+++ b/src/ipa/rkisp1/algorithms/dpf.h\n@@ -34,23 +34,53 @@ public:\n private:\n \tstruct rkisp1_cif_isp_dpf_config config_ {\n \t};\n+\n \tstruct rkisp1_cif_isp_dpf_strength_config strengthConfig_ {\n \t};\n+\n \tstruct rkisp1_cif_isp_dpf_config baseConfig_ {\n \t};\n+\n \tstruct rkisp1_cif_isp_dpf_strength_config baseStrengthConfig_ {\n \t};\n+\n+\tstruct DpfStrengthSettings {\n+\t\tuint16_t r, g, b;\n+\t};\n+\n+\tstruct DpfSpatialGreenSettings {\n+\t\tstd::array<uint8_t, RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS> coeffs;\n+\t};\n+\n+\tstruct DpfSpatialRbSettings {\n+\t\tstd::array<uint8_t, RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS> coeffs;\n+\t\tuint8_t size; // 0=9x9, 1=13x9\n+\t};\n+\n+\tstruct DpfNllSettings {\n+\t\tstd::array<uint16_t, RKISP1_CIF_ISP_DPF_MAX_NLF_COEFFS> coeffs;\n+\t\tuint8_t scaleMode; // 0 linear, 1 log\n+\t};\n \tstruct IsoLevelConfig {\n \t\tunsigned int maxIso; /* inclusive upper bound */\n \t\tstruct rkisp1_cif_isp_dpf_config dpf;\n \t\tstruct rkisp1_cif_isp_dpf_strength_config strength;\n \t};\n+\tstruct Overrides {\n+\t\tstd::optional<DpfStrengthSettings> strength;\n+\t\tstd::optional<DpfSpatialGreenSettings> spatialGreen;\n+\t\tstd::optional<DpfSpatialRbSettings> spatialRb;\n+\t\tstd::optional<uint8_t> rbSize;\n+\t\tstd::optional<DpfNllSettings> nll;\n+\t\tvoid clear() { *this = Overrides{}; }\n+\t} overrides_;\n \n \tstd::vector<IsoLevelConfig> isoLevels_;\n \tbool useIsoLevels_ = false;\n \tbool enableDpf_ = true; /* YAML master enable */\n \n \tvoid handleEnableControl(const ControlList &controls, IPAFrameContext &frameContext, IPAContext &context) override;\n+\tvoid collectManualOverrides(const ControlList &controls) override;\n \tbool parseConfig(const YamlObject &tuningData) override;\n \tbool parseSingleConfig(const YamlObject &config,\n \t\t\t       rkisp1_cif_isp_dpf_config &cfg,\ndiff --git a/src/libcamera/control_ids_rkisp1.yaml b/src/libcamera/control_ids_rkisp1.yaml\nindex 2f29d508..bf7875e9 100644\n--- a/src/libcamera/control_ids_rkisp1.yaml\n+++ b/src/libcamera/control_ids_rkisp1.yaml\n@@ -21,4 +21,66 @@ controls:\n \n         Reported in metadata as a boolean.\n \n+  - DpfChannelStrengths:\n+      type: int32_t\n+      direction: inout\n+      description: |\n+        Override filter strength for R,G,B channels. Values map to hardware\n+        strength registers (0..255 typical). Size must be exactly 3 when set.\n+        Order: R,G,B. If unset the tuning / ISO level derived strengths apply.\n+      size: [3]\n+\n+  - DpfGreenSpatialCoefficients:\n+      type: int32_t\n+      direction: inout\n+      description: |\n+        Override 9x9 green spatial kernel coefficients (6 values). Order must\n+        follow tuning file convention. Each value 0..63 typical. All 6 required\n+        when provided; otherwise ignored.\n+      size: [6]\n+\n+  - DpfRedBlueSpatialCoefficients:\n+      type: int32_t\n+      direction: inout\n+      description: |\n+        Override Red/Blue spatial kernel coefficients (6 values). Applies to\n+        either 9x9 or 13x9 depending on DpfRbFilterSize. For 9x9 the last\n+        column pair is dropped in hardware. Values 0..63 typical.\n+      size: [6]\n+\n+  - DpfRbFilterSize:\n+      type: int32_t\n+      direction: inout\n+      description: |\n+        Override RB spatial filter size selection.\n+      enum:\n+        - name: DpfRbFilterSize9x9\n+          value: 0\n+          description: Use 9x9 RB domain filter.\n+        - name: DpfRbFilterSize13x9\n+          value: 1\n+          description: Use 13x9 RB domain filter (if coefficients valid).\n+\n+  - DpfNoiseLevelLookupCoefficients:\n+      type: int32_t\n+      direction: inout\n+      description: |\n+        Override Noise Level Lookup (NLL) piecewise-linear coefficients\n+        (17 values). Must supply full set when used or override is ignored.\n+      size: [17]\n+\n+  - DpfNoiseLevelLookupScaleMode:\n+      type: int32_t\n+      direction: inout\n+      description: |\n+        Override NLL scale mode (0=linear,1=logarithmic). Matches hardware\n+        RKISP1_CIF_ISP_NLL_SCALE_* constants.\n+      enum:\n+        - name: DpfNoiseLevelLookupScaleLinear\n+          value: 0\n+          description: Linear scale.\n+        - name: DpfNoiseLevelLookupScaleLogarithmic\n+          value: 1\n+          description: Logarithmic scale.\n+\n ...\n",
    "prefixes": [
        "v1",
        "10/17"
    ]
}