Show a patch.

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

{
    "id": 27420,
    "url": "https://patchwork.libcamera.org/api/patches/27420/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/27420/",
    "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": "<20260720-libipa-algorithms-v6-28-ececb73f97cb@ideasonboard.com>",
    "date": "2026-07-20T14:59:46",
    "name": "[v6,28/31] ipa: libipa: lsc: Quantize gains in LscAlgorithm",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "7b071bcf187da55d878b39cc49b6f3638a989e45",
    "submitter": {
        "id": 143,
        "url": "https://patchwork.libcamera.org/api/people/143/?format=api",
        "name": "Jacopo Mondi",
        "email": "jacopo.mondi@ideasonboard.com"
    },
    "delegate": null,
    "mbox": "https://patchwork.libcamera.org/patch/27420/mbox/",
    "series": [
        {
            "id": 6067,
            "url": "https://patchwork.libcamera.org/api/series/6067/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=6067",
            "date": "2026-07-20T14:59:18",
            "name": "ipa: libipa: Introduce libipa algorithms",
            "version": 6,
            "mbox": "https://patchwork.libcamera.org/series/6067/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/27420/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/27420/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 745EBC3301\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 20 Jul 2026 15:00:22 +0000 (UTC)",
            "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id E166667EBB;\n\tMon, 20 Jul 2026 17:00:21 +0200 (CEST)",
            "from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id C7E4D67E54\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 20 Jul 2026 16:59:56 +0200 (CEST)",
            "from [192.168.1.106] (mob-5-90-63-152.net.vodafone.it\n\t[5.90.63.152])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id E5A5233A1;\n\tMon, 20 Jul 2026 16:58:57 +0200 (CEST)"
        ],
        "Authentication-Results": "lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"OEkMwFKO\"; dkim-atps=neutral",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1784559538;\n\tbh=Ue8WFFWwwNU/78Yj2z4SyG8waebc1pheVFmlqj1Cy+4=;\n\th=From:Date:Subject:References:In-Reply-To:To:Cc:From;\n\tb=OEkMwFKOtoSlOOJAfi4F8CAHr8QzS/Wydb1mmeptEpQr/mnp4SSu0MiJaFBMcglcB\n\tUSHxkd+k2bnfJYbTHLcQltARm/UVxIEXsZfksydX5y/7cq16YjjK1O31jUV7SMg56W\n\tv8GjTgGTbEXDM36VO1SmFvdjw3BlbDT06ZcAFUHs=",
        "From": "Jacopo Mondi <jacopo.mondi@ideasonboard.com>",
        "Date": "Mon, 20 Jul 2026 16:59:46 +0200",
        "Subject": "[PATCH v6 28/31] ipa: libipa: lsc: Quantize gains in LscAlgorithm",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain; charset=\"utf-8\"",
        "Content-Transfer-Encoding": "7bit",
        "Message-Id": "<20260720-libipa-algorithms-v6-28-ececb73f97cb@ideasonboard.com>",
        "References": "<20260720-libipa-algorithms-v6-0-ececb73f97cb@ideasonboard.com>",
        "In-Reply-To": "<20260720-libipa-algorithms-v6-0-ececb73f97cb@ideasonboard.com>",
        "To": "libcamera-devel@lists.libcamera.org, \n\tStefan Klug <stefan.klug@ideasonboard.com>, \n\tMilan Zamazal <mzamazal@redhat.com>",
        "Cc": "Jacopo Mondi <jacopo.mondi@ideasonboard.com>",
        "X-Mailer": "b4 0.14.3",
        "X-Developer-Signature": "v=1; a=openpgp-sha256; l=15810;\n\ti=jacopo.mondi@ideasonboard.com; h=from:subject:message-id;\n\tbh=Ue8WFFWwwNU/78Yj2z4SyG8waebc1pheVFmlqj1Cy+4=;\n\tb=owEBbQKS/ZANAwAKAXI0Bo8WoVY8AcsmYgBqXjfbp52volV3i7QIAFmnEYey79eWMvv17yLQw\n\tkqErzrBx8GJAjMEAAEKAB0WIQS1xD1IgJogio9YOMByNAaPFqFWPAUCal432wAKCRByNAaPFqFW\n\tPBzCD/9i9Y36FRglymkhYNhi8ELqHmaySRRRDryLNdxfKLeu5R8r35CzeaoBYIbjgBLnZrI7gAa\n\tTZ0M3P8y5dwySRfHxKQpXB4/iLaFGZNJgyBGUoyBsqpdzPXUUM/OKIeDYE6RxceZPrP52MqYFmE\n\ts8vk7sZcXpUi4uefuwVkWuIgRPDkqFckYYHIfv2QtNOXmbRQBudWI7KWTml8GJGMf8gs5ZbQ1t6\n\tszdohvpCuMyOIOMRfVC2Ml+RivAL12xfnAyCzQZuxAra43eijJWgEg44sE/5K9AlaTt6+8sNi4P\n\tu54tOdrrgP5LyAfZeu8YRyl1fGNLu4GzXrj5AxnxPIk7JtmJASD7lxq9sEk/1rJCobuya6En9DP\n\tFC3Z7JwAwCKxXyuX7bq2QrKuujjVfVpRIqwXUK6saW84Q47N2gntH5I+MvRPYy4/93OfatkrMk6\n\tZDITbmdx6KYsBNenWVaae0bHMk6kMibhgXI27DlJu9og1DsGbPjfiIQAg0IVxb1H6j2192XM4V9\n\tbsHkdPwcUz1FPBqPolSc1Dh3/mZFYCTLt3n8WA9DZMHz5EPRST3IW7dNqYa0hg/1vnAW7bdmB18\n\t0qyt/igXPkG5jrZm8hU413RsnorZQ3gw1KmNE99nigROQ1w+nxN6OJphsl5SBXvxyk0ryP+PCSb\n\tLT82prK7yiY8R6Q==",
        "X-Developer-Key": "i=jacopo.mondi@ideasonboard.com; a=openpgp;\n\tfpr=72392EDC88144A65C701EA9BA5826A2587AD026B",
        "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": "Template the LscAlgorithm class with the LSC engine register format.\n\nThis allows to quantize gains in the LscAlgorithm class and not in the\nIPA modules.\n\nSplit the LscAlgorithm class in two, one LscAlgorithmBase one for\nnon-templated function implementations and one for the templated\nconfigure() implementation and for templated data members and accessor.\n\nModify the LscAlgorithm interpolator interface. As now the returned list\nof gains is in register format, a dedicated Interpolator::interpolate()\noverload has to be defined for each IPA module.\n\nSigned-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\n---\n src/ipa/libipa/lsc.cpp            | 88 +++++++++++++++++++++-----------------\n src/ipa/libipa/lsc.h              | 90 +++++++++++++++++++++++++++++++++------\n src/ipa/libipa/lsc_base.cpp       | 13 ------\n src/ipa/libipa/lsc_base.h         | 19 ---------\n src/ipa/rkisp1/algorithms/lsc.cpp | 40 +++++------------\n src/ipa/rkisp1/algorithms/lsc.h   | 44 +++++++++++++++++--\n 6 files changed, 177 insertions(+), 117 deletions(-)",
    "diff": "diff --git a/src/ipa/libipa/lsc.cpp b/src/ipa/libipa/lsc.cpp\nindex 8c5c28077cce..8f881edef94c 100644\n--- a/src/ipa/libipa/lsc.cpp\n+++ b/src/ipa/libipa/lsc.cpp\n@@ -48,6 +48,29 @@ namespace lsc {\n \n } /* namespace lsc */\n \n+/**\n+ * \\class LscAlgorithmBase\n+ * \\brief Base class for LscAlgorithm\n+ *\n+ * Base class for LscAlgorithm for non-templated functions implementation\n+ */\n+\n+/**\n+ * \\var LscAlgorithmBase::impl_\n+ * \\brief The LSC algorithm implementation\n+ *\n+ * There are two classes derived from LscImplementation, the LscTable and\n+ * LscPolynomial ones. Which one to instantiate is decided by parsing the tuning\n+ * file.\n+ */\n+\n+/**\n+ * \\var LscAlgorithmBase::polynomial_\n+ * \\brief Boolean flag for polynomial LSC\n+ *\n+ * Set to true if polynomial LSC is in use.\n+ */\n+\n /**\n  * \\class LscAlgorithm\n  * \\brief libIPA LSC algorithm implementation\n@@ -199,6 +222,16 @@ namespace lsc {\n  * can retrieve them using LscAlgorithm::getComponents().\n  */\n \n+/**\n+ * \\typedef LscAlgorithm::Components\n+ * \\brief Map a colour component to a list of gains\n+ */\n+\n+/**\n+ * \\typedef LscAlgorithm::ComponentsMap\n+ * \\brief Map a colour temperature to an LSC componenet\n+ */\n+\n /**\n  * \\param[in] tuningData The tuning data\n  * \\param[in] controls The IPA list of supported controls\n@@ -209,8 +242,8 @@ namespace lsc {\n  *\n  * \\return 0 on success, a negative error code otherwise\n  */\n-int LscAlgorithm::init(const ValueNode &tuningData, ControlInfoMap::Map &controls,\n-\t\t       const LscDescriptor &descriptor)\n+int LscAlgorithmBase::init(const ValueNode &tuningData, ControlInfoMap::Map &controls,\n+\t\t\t   const LscDescriptor &descriptor)\n {\n \tpolynomial_ = false;\n \n@@ -245,6 +278,7 @@ int LscAlgorithm::init(const ValueNode &tuningData, ControlInfoMap::Map &control\n }\n \n /**\n+ * \\fn LscAlgorithm::configure()\n  * \\param[in] state The LSC active state\n  * \\param[in] analogCrop The current sensor analog crop rectangle\n  * \\param[in] xPos List of horizontal positions of the LSC grid nodes\n@@ -265,28 +299,6 @@ int LscAlgorithm::init(const ValueNode &tuningData, ControlInfoMap::Map &control\n  *\n  * \\return 0 on success, a negative error code otherwise\n  */\n-int LscAlgorithm::configure(lsc::ActiveState &state, const Rectangle &analogCrop,\n-\t\t\t    const std::vector<double> &xPos,\n-\t\t\t    const std::vector<double> &yPos)\n-{\n-\tLOG(Lsc, Debug) << \"Sample Lsc data for \" << analogCrop;\n-\tlsc::ComponentsMap lscData =\n-\t\timpl_->sampleForCrop(analogCrop, xPos, yPos);\n-\n-\t/*\n-\t * Retain a copy of the components table.\n-\t *\n-\t * We could avoid a copy here if getComponents() could\n-\t * return sets_.data() but I wasn't able to work around the\n-\t * compiler refusing it.\n-\t */\n-\tlscData_ = lscData;\n-\n-\tsets_.setData(std::move(lscData));\n-\tstate.enabled = true;\n-\n-\treturn 0;\n-}\n \n /**\n  * \\brief Queue a request to the lsc algorithm\n@@ -297,9 +309,9 @@ int LscAlgorithm::configure(lsc::ActiveState &state, const Rectangle &analogCrop\n  * Queue a new list of \\a controls to the lsc algorithm.\n  * The only supported control is controls::LensShadingCorrectionEnable.\n  */\n-void LscAlgorithm::queueRequest(lsc::ActiveState &state,\n-\t\t\t\tlsc::FrameContext &context,\n-\t\t\t\tconst ControlList &controls)\n+void LscAlgorithmBase::queueRequest(lsc::ActiveState &state,\n+\t\t\t\t    lsc::FrameContext &context,\n+\t\t\t\t    const ControlList &controls)\n {\n \tconst auto &lscEnable = controls.get(controls::LensShadingCorrectionEnable);\n \tif (lscEnable && *lscEnable != state.enabled) {\n@@ -322,25 +334,22 @@ void LscAlgorithm::queueRequest(lsc::ActiveState &state,\n  * Populates the list of \\a metadata with controls handled by the LscAlgorithm\n  * class. The only supported metadata is controls::LensShadingCorrectionEnable.\n  */\n-void LscAlgorithm::process(lsc::FrameContext &context, ControlList &metadata)\n+void LscAlgorithmBase::process(lsc::FrameContext &context, ControlList &metadata)\n {\n \tmetadata.set(controls::LensShadingCorrectionEnable, context.enabled);\n }\n \n /**\n- * \\fn LscAlgorithm::interpolateComponents\n- * \\brief Interpolate the LSC tables for a given colour temperature\n- * \\param[in] ct The colour temperature\n+ * \\fn LscAlgorithm::getInterpolator\n+ * \\brief Retrieve the LSC tables interpolator\n  *\n  * LSC tables are generated using different colour temperatures during the\n- * tuning phase.\n- *\n- * This function returns the interpolated LSC data for a given \\a ct\n- * colour temperature.\n+ * tuning phase. This function returns the interpolator for the LSC data.\n  *\n- * IPA algorithm can use this function to obtain a list of per-colour-component\n- * gains to program their LSC engines with every time a significant enough\n- * change in colour temperature is detected.\n+ * IPA algorithm can use the interpolator to obtain a list of\n+ * per-colour-component gains to program their LSC engines with every time a\n+ * significant enough change in colour temperature is detected by calling the\n+ * Interpolator::getInterpolated() function.\n  *\n  * Calling this function is only valid after LscAlgorithm::configure() has been\n  * called. An empty components list is returned otherwise.\n@@ -350,8 +359,7 @@ void LscAlgorithm::process(lsc::FrameContext &context, ControlList &metadata)\n \n /**\n  * \\fn LscAlgorithm::getComponents\n- *\n- * Return the map of LSC data per-colour-temperature.\n+ * \\brief Return the map of LSC data per-colour-temperature\n  *\n  * Calling this function is only valid after LscAlgorithm::configure() has been\n  * called. An empty components list is returned otherwise.\ndiff --git a/src/ipa/libipa/lsc.h b/src/ipa/libipa/lsc.h\nindex 9fe8ad67ea33..15c8a9cb7b9c 100644\n--- a/src/ipa/libipa/lsc.h\n+++ b/src/ipa/libipa/lsc.h\n@@ -35,35 +35,101 @@ struct FrameContext {\n \n } /* namespace lsc */\n \n-class LscAlgorithm\n+class LscAlgorithmBase\n {\n public:\n \tint init(const ValueNode &tuningData, ControlInfoMap::Map &controls,\n \t\t const LscDescriptor &descriptor);\n \n-\tint configure(lsc::ActiveState &state, const Rectangle &analogCrop,\n-\t\t      const std::vector<double> &xPos,\n-\t\t      const std::vector<double> &yPos);\n-\n \tvoid queueRequest(lsc::ActiveState &state, lsc::FrameContext &context,\n \t\t\t  const ControlList &controls);\n \tvoid process(lsc::FrameContext &context, ControlList &metadata);\n \n-\tconst lsc::Components interpolateComponents(unsigned int ct)\n+protected:\n+\tLscAlgorithmBase() = default;\n+\n+\tstd::unique_ptr<LscImplementation> impl_;\n+\tbool polynomial_;\n+};\n+\n+template<typename U>\n+class LscAlgorithm : public LscAlgorithmBase\n+{\n+private:\n+\tusing T = typename U::QuantizedType;\n+\n+\ttemplate<typename V>\n+\tclass _Components : public std::map<std::string, std::vector<V>>\n+\t{\n+\t};\n+\n+\ttemplate<typename V>\n+\tclass _ComponentsMap : public std::map<unsigned int, _Components<V>>\n \t{\n-\t\treturn sets_.getInterpolated(ct);\n+\t};\n+\n+public:\n+\tusing Components = _Components<T>;\n+\tusing ComponentsMap = _ComponentsMap<T>;\n+\n+\tLscAlgorithm() = default;\n+\n+\tint configure(lsc::ActiveState &state, const Rectangle &analogCrop,\n+\t\t      const std::vector<double> &xPos,\n+\t\t      const std::vector<double> &yPos)\n+\t{\n+\t\tlsc::ComponentsMap data =\n+\t\t\timpl_->sampleForCrop(analogCrop, xPos, yPos);\n+\n+\t\tComponentsMap lscData;\n+\t\tfor (const auto &[t, c] : data) {\n+\t\t\tComponents comp;\n+\n+\t\t\tfor (const auto &[k, gains] : c) {\n+\t\t\t\tstd::vector<T> quantizedGains;\n+\t\t\t\tquantizedGains.reserve(gains.size());\n+\n+\t\t\t\tfor (const float &gain : gains) {\n+\t\t\t\t\tif (polynomial_)\n+\t\t\t\t\t\tquantizedGains.push_back(U(gain).quantized());\n+\t\t\t\t\telse\n+\t\t\t\t\t\tquantizedGains.push_back(gain);\n+\t\t\t\t}\n+\n+\t\t\t\tcomp[k] = std::move(quantizedGains);\n+\t\t\t}\n+\n+\t\t\tlscData[t] = comp;\n+\t\t}\n+\n+\t\t/*\n+\t\t * Retain a copy of the components table.\n+\t\t *\n+\t\t * We could avoid a copy here if getComponents() could\n+\t\t * return sets_.data() but I wasn't able to work around the\n+\t\t * compiler refusing it.\n+\t\t */\n+\t\tlscData_ = lscData;\n+\n+\t\tsets_.setData(std::move(lscData));\n+\t\tstate.enabled = true;\n+\n+\t\treturn 0;\n+\t}\n+\n+\tInterpolator<Components> &getInterpolator()\n+\t{\n+\t\treturn sets_;\n \t}\n \n-\tconst lsc::ComponentsMap getComponents()\n+\tconst ComponentsMap &getComponents() const\n \t{\n \t\treturn lscData_;\n \t}\n \n private:\n-\tstd::unique_ptr<LscImplementation> impl_;\n-\tInterpolator<lsc::Components> sets_;\n-\tlsc::ComponentsMap lscData_;\n-\tbool polynomial_;\n+\tComponentsMap lscData_;\n+\tInterpolator<Components> sets_;\n };\n \n } /* namespace ipa */\ndiff --git a/src/ipa/libipa/lsc_base.cpp b/src/ipa/libipa/lsc_base.cpp\nindex cf2c3bfc382f..a98358daf4ec 100644\n--- a/src/ipa/libipa/lsc_base.cpp\n+++ b/src/ipa/libipa/lsc_base.cpp\n@@ -46,19 +46,6 @@ namespace lsc {\n \n } /* namespace lsc */\n \n-#ifndef __DOXYGEN__\n-template<>\n-void Interpolator<lsc::Components>::\n-\tinterpolate(const lsc::Components &a,\n-\t\t    const lsc::Components &b,\n-\t\t    lsc::Components &dest,\n-\t\t    double lambda)\n-{\n-\tfor (auto const &[k, v] : a)\n-\t\tinterpolateVector(v, b.at(k), dest[k], lambda);\n-}\n-#endif\n-\n /**\n  * \\struct LscDescriptor\n  * \\brief Describe the ISP LSC engine\ndiff --git a/src/ipa/libipa/lsc_base.h b/src/ipa/libipa/lsc_base.h\nindex 386cac55be34..8053de7d2edb 100644\n--- a/src/ipa/libipa/lsc_base.h\n+++ b/src/ipa/libipa/lsc_base.h\n@@ -31,25 +31,6 @@ using ComponentsMap = std::map<unsigned int, Components>;\n \n } /* namespace lsc */\n \n-#ifndef __DOXYGEN__\n-template<typename T>\n-void interpolateVector(const std::vector<T> &a, const std::vector<T> &b,\n-\t\t       std::vector<T> &dest, double lambda)\n-{\n-\tASSERT(a.size() == b.size());\n-\tdest.resize(a.size());\n-\tfor (size_t i = 0; i < a.size(); i++)\n-\t\tdest[i] = a[i] * (1.0 - lambda) + b[i] * lambda;\n-}\n-\n-template<>\n-void Interpolator<lsc::Components>::\n-\tinterpolate(const lsc::Components &a,\n-\t\t    const lsc::Components &b,\n-\t\t    lsc::Components &dest,\n-\t\t    double lambda);\n-#endif /* __DOXYGEN__ */\n-\n struct LscDescriptor {\n \tstd::vector<std::string> keys;\n \tunsigned int numHSamples;\ndiff --git a/src/ipa/rkisp1/algorithms/lsc.cpp b/src/ipa/rkisp1/algorithms/lsc.cpp\nindex dba1a01118ee..157403691ffc 100644\n--- a/src/ipa/rkisp1/algorithms/lsc.cpp\n+++ b/src/ipa/rkisp1/algorithms/lsc.cpp\n@@ -175,34 +175,16 @@ void LensShadingCorrection::setParameters(rkisp1_cif_isp_lsc_config &config)\n }\n \n void LensShadingCorrection::copyTable(rkisp1_cif_isp_lsc_config &config,\n-\t\t\t\t      const lsc::Components &set)\n+\t\t\t\t      const RkISP1Components &set)\n {\n-\t/*\n-\t * The hardware uses 2.10 fixed point format and limits the legal values\n-\t * to [1..3.999]. Scale and clamp the sampled values accordingly.\n-\t */\n-\tstd::vector<uint16_t> regs;\n-\tregs.reserve(RKISP1_CIF_ISP_LSC_SAMPLES_MAX *\n-\t\t     RKISP1_CIF_ISP_LSC_SAMPLES_MAX);\n-\n-\tfor (const float &f : set.at(\"r\"))\n-\t\tregs.emplace_back(std::clamp(static_cast<int>(f * 1024), 1024, 4095));\n-\tstd::copy(regs.begin(), regs.end(), &config.r_data_tbl[0][0]);\n-\n-\tregs = {};\n-\tfor (const float &f : set.at(\"gr\"))\n-\t\tregs.emplace_back(std::clamp(static_cast<int>(f * 1024), 1024, 4095));\n-\tstd::copy(regs.begin(), regs.end(), &config.gr_data_tbl[0][0]);\n-\n-\tregs = {};\n-\tfor (const float &f : set.at(\"gb\"))\n-\t\tregs.emplace_back(std::clamp(static_cast<int>(f * 1024), 1024, 4095));\n-\tstd::copy(regs.begin(), regs.end(), &config.gb_data_tbl[0][0]);\n-\n-\tregs = {};\n-\tfor (const float &f : set.at(\"b\"))\n-\t\tregs.emplace_back(std::clamp(static_cast<int>(f * 1024), 1024, 4095));\n-\tstd::copy(regs.begin(), regs.end(), &config.b_data_tbl[0][0]);\n+\tconst auto &r = set.at(\"r\");\n+\tstd::copy(r.begin(), r.end(), &config.r_data_tbl[0][0]);\n+\tconst auto &gr = set.at(\"gr\");\n+\tstd::copy(gr.begin(), gr.end(), &config.gr_data_tbl[0][0]);\n+\tconst auto &gb = set.at(\"gb\");\n+\tstd::copy(gb.begin(), gb.end(), &config.gb_data_tbl[0][0]);\n+\tconst auto &b = set.at(\"b\");\n+\tstd::copy(b.begin(), b.end(), &config.b_data_tbl[0][0]);\n }\n \n /**\n@@ -252,8 +234,8 @@ void LensShadingCorrection::prepare([[maybe_unused]] IPAContext &context,\n \n \tsetParameters(*config);\n \n-\tconst lsc::Components &set = lscAlgo_.interpolateComponents(quantizedCt);\n-\tcopyTable(*config, set);\n+\tauto &lscData = lscAlgo_.getInterpolator();\n+\tcopyTable(*config, lscData.getInterpolated(quantizedCt));\n \n \tlastAppliedCt_ = ct;\n \tlastAppliedQuantizedCt_ = quantizedCt;\ndiff --git a/src/ipa/rkisp1/algorithms/lsc.h b/src/ipa/rkisp1/algorithms/lsc.h\nindex 63f0887f0838..55a6980014f2 100644\n--- a/src/ipa/rkisp1/algorithms/lsc.h\n+++ b/src/ipa/rkisp1/algorithms/lsc.h\n@@ -12,6 +12,7 @@\n #include <linux/rkisp1-config.h>\n \n #include \"libcamera/internal/value_node.h\"\n+#include \"libipa/fixedpoint.h\"\n \n #include \"libipa/lsc.h\"\n \n@@ -19,7 +20,13 @@\n \n namespace libcamera {\n \n-namespace ipa::rkisp1::algorithms {\n+namespace ipa {\n+\n+namespace rkisp1::algorithms {\n+\n+using RkISP1LscAlgorithm = LscAlgorithm<UQ<2, 10>>;\n+using RkISP1Components = RkISP1LscAlgorithm::Components;\n+using RkISP1ComponentsMap = RkISP1LscAlgorithm::ComponentsMap;\n \n class LensShadingCorrection : public Algorithm\n {\n@@ -39,9 +46,11 @@ public:\n \t\t     IPAFrameContext &frameContext,\n \t\t     const rkisp1_stat_buffer *stats,\n \t\t     ControlList &metadata) override;\n+\n private:\n \tvoid setParameters(rkisp1_cif_isp_lsc_config &config);\n-\tvoid copyTable(rkisp1_cif_isp_lsc_config &config, const lsc::Components &set0);\n+\tvoid copyTable(rkisp1_cif_isp_lsc_config &config,\n+\t\t       const RkISP1Components &set);\n \n \tstd::vector<double> xSize_;\n \tstd::vector<double> ySize_;\n@@ -55,8 +64,35 @@ private:\n \tunsigned int lastAppliedCt_;\n \tunsigned int lastAppliedQuantizedCt_;\n \n-\tLscAlgorithm lscAlgo_;\n+\tRkISP1LscAlgorithm lscAlgo_;\n };\n \n-} /* namespace ipa::rkisp1::algorithms */\n+} /* namespace rkisp1::algorithms */\n+\n+#ifndef __DOXYGEN__\n+template<typename T>\n+void interpolateVector(const std::vector<T> &a,\n+\t\t       const std::vector<T> &b,\n+\t\t       std::vector<T> &dest, double lambda)\n+{\n+\tASSERT(a.size() == b.size());\n+\tdest.resize(a.size());\n+\tfor (size_t i = 0; i < a.size(); i++)\n+\t\tdest[i] = a[i] * (1.0 - lambda) + b[i] * lambda;\n+}\n+\n+template<>\n+void Interpolator<rkisp1::algorithms::RkISP1Components>::\n+\tinterpolate(const rkisp1::algorithms::RkISP1Components &a,\n+\t\t    const rkisp1::algorithms::RkISP1Components &b,\n+\t\t    rkisp1::algorithms::RkISP1Components &dest,\n+\t\t    double lambda)\n+{\n+\tfor (auto const &[k, v] : a)\n+\t\tinterpolateVector(v, b.at(k), dest[k], lambda);\n+}\n+#endif /* __DOXYGEN__ */\n+\n+} /* namespace ipa */\n+\n } /* namespace libcamera */\n",
    "prefixes": [
        "v6",
        "28/31"
    ]
}