Show a patch.

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

{
    "id": 27226,
    "url": "https://patchwork.libcamera.org/api/1.1/patches/27226/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/27226/",
    "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": "<20260706-libipa-algorithms-v3-25-968757b038bb@ideasonboard.com>",
    "date": "2026-07-06T08:01:45",
    "name": "[v3,25/35] ipa: libipa: lsc: Make Components a map<>",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "1dc1ecc7b000cd5b9b2bb4473c90ba7ff31bfc37",
    "submitter": {
        "id": 143,
        "url": "https://patchwork.libcamera.org/api/1.1/people/143/?format=api",
        "name": "Jacopo Mondi",
        "email": "jacopo.mondi@ideasonboard.com"
    },
    "delegate": null,
    "mbox": "https://patchwork.libcamera.org/patch/27226/mbox/",
    "series": [
        {
            "id": 6038,
            "url": "https://patchwork.libcamera.org/api/1.1/series/6038/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=6038",
            "date": "2026-07-06T08:01:20",
            "name": "ipa: libipa: Introduce libipa algorithms",
            "version": 3,
            "mbox": "https://patchwork.libcamera.org/series/6038/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/27226/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/27226/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 1C027C330A\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon,  6 Jul 2026 08:02:35 +0000 (UTC)",
            "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id CA32466060;\n\tMon,  6 Jul 2026 10:02:34 +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 B2E426601E\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon,  6 Jul 2026 10:02:13 +0200 (CEST)",
            "from [192.168.125.177] (mob-109-113-60-81.net.vodafone.it\n\t[109.113.60.81])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 5969316F9;\n\tMon,  6 Jul 2026 10:01:25 +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=\"Z1ahdnU3\"; dkim-atps=neutral",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1783324885;\n\tbh=rQNQ1vsGDE7PAsPQfl1To2b5CQlmApEmLmHW5x+0GTU=;\n\th=From:Date:Subject:References:In-Reply-To:To:Cc:From;\n\tb=Z1ahdnU3hitVqu/CEY/1nscxzA7c8pd1zjPFb5RtpBUSduR4dqqiCIQXceujY2PY3\n\t5s+LTQnAT24pxlMJ0K/3qK7wD3jHqIjQPux/BhjKNaHPedY5kMCtLlLm6qD607nFj3\n\t2IuWB4gW8e4u96mBTKXd9Jnn1cXXdF6ujSrGRguE=",
        "From": "Jacopo Mondi <jacopo.mondi@ideasonboard.com>",
        "Date": "Mon, 06 Jul 2026 10:01:45 +0200",
        "Subject": "[PATCH v3 25/35] ipa: libipa: lsc: Make Components a map<>",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain; charset=\"utf-8\"",
        "Content-Transfer-Encoding": "7bit",
        "Message-Id": "<20260706-libipa-algorithms-v3-25-968757b038bb@ideasonboard.com>",
        "References": "<20260706-libipa-algorithms-v3-0-968757b038bb@ideasonboard.com>",
        "In-Reply-To": "<20260706-libipa-algorithms-v3-0-968757b038bb@ideasonboard.com>",
        "To": "libcamera-devel@lists.libcamera.org, \n\tStefan Klug <stefan.klug@ideasonboard.com>",
        "Cc": "Jacopo Mondi <jacopo.mondi@ideasonboard.com>",
        "X-Mailer": "b4 0.14.3",
        "X-Developer-Signature": "v=1; a=openpgp-sha256; l=17939;\n\ti=jacopo.mondi@ideasonboard.com; h=from:subject:message-id;\n\tbh=rQNQ1vsGDE7PAsPQfl1To2b5CQlmApEmLmHW5x+0GTU=;\n\tb=owEBbQKS/ZANAwAKAXI0Bo8WoVY8AcsmYgBqS2Dy7K1H+WgwuhzQUjeNTPbV5Fh9PoDGRF6HC\n\tTJL5f8LK+6JAjMEAAEKAB0WIQS1xD1IgJogio9YOMByNAaPFqFWPAUCaktg8gAKCRByNAaPFqFW\n\tPOFhEACtBGeOYpvyukDW5/CEStoCuIsthleahNu2Y+TtmfYj/Obg6OH5BAidErYJq8YRjmwzL8Q\n\tlS4biqbKVptDKTVj6DdFJTBkq0ZHZVn8iYxpnJhySOv9hCiWCyVQR+6TNASstDybBuK+P2XfHaV\n\tEI70cPGyHfFzjnc4yEs1TwGJq7LNApLNuDhZ2akZtWPUJmtiLBdvPHrBsTXVuTfBF042gxmEPQw\n\tq9mK2WDbRss/8ZBcmUWFfL404gJ1p/yxDUWWobPb2RNw583MTmcMoWpbdJlkXTXjvLZ+migjisU\n\tFAYuL+8fK3643KNCePb0vIs85IVBYKDe3lXPhNs8WIvpD9QALGjDs05Jd5xnnCn2YePIEiS6BzW\n\t1pNYd1gF33cKzTYby/MQqzeI5W70loKDbk/wAUJ12Sok0WUAdd2FTrjlsOwNbeiSudTlgHUDIu/\n\tET9SGFXhsjBEe1+w3rEV0Vaqm2oJcfCFT9xeA4CsSNodGlJw87fLQ98KWA7IQeHoUw+MLAnAxsM\n\tmEFsxkKrx09WwS+oWSKmMD4LL4L9ZIc5xnjCaLalX+z0AZ/MaR6hsJke7E14XJbnqPjuwV1SbrF\n\tCjV06OtUfoPv9xHwugyKvKuKMES+2rR3mLr5xQ4DX6W5mIlvJdK/aCV5kfoGJvCYwv78RuzsVvz\n\t6/qKjWOCnUjCXVQ==",
        "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": "The current definition of lsc::Components assumes 4 gain vectors named\nafter the colour components supported by the RkISP1 ISP (r, gr, gb and\nb).\n\nAs different ISP support different colour channels for their Lsc tables\nmake lsc::Components a map that associates the name of the colour\nchannel to the vector of gains.\n\nThe use of strings as index for the map comes from the requirement of\nparsing the tuning file using string identifiers. Pass the strings to\nuse for tuning file parsing to the LscAlgorithm::init() function as part\nof a newly introduced LscDescriptor type and use the same strings for\nindexing the gain arrays.\n\nThe newly introduced LscDescriptor type also provides to the\nLscAlgorithm class the expected size of the Lsc grid, allowing to remove\nRkISP1 specific values from the libipa generic implementation.\n\nSigned-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\n---\n src/ipa/libipa/lsc.cpp            | 10 +++---\n src/ipa/libipa/lsc.h              |  4 +--\n src/ipa/libipa/lsc_base.cpp       | 49 ++++++++++++++++++++--------\n src/ipa/libipa/lsc_base.h         | 18 ++++++-----\n src/ipa/libipa/lsc_polynomial.cpp | 65 +++++++++++++++++++------------------\n src/ipa/libipa/lsc_polynomial.h   | 10 ++----\n src/ipa/libipa/lsc_table.cpp      | 68 +++++++++++++++++++++++----------------\n src/ipa/libipa/lsc_table.h        |  9 ++++--\n src/ipa/rkisp1/algorithms/lsc.cpp | 20 ++++++++----\n 9 files changed, 150 insertions(+), 103 deletions(-)",
    "diff": "diff --git a/src/ipa/libipa/lsc.cpp b/src/ipa/libipa/lsc.cpp\nindex 66d33a2dd796..9bc71e3c73ae 100644\n--- a/src/ipa/libipa/lsc.cpp\n+++ b/src/ipa/libipa/lsc.cpp\n@@ -86,16 +86,16 @@ namespace lsc {\n \n /**\n  * \\param[in] tuningData The tuning data\n- * \\param[in] sensorSize The physical sensor size\n  * \\param[in] controls The IPA list of supported controls\n+ * \\param[in] descriptor The lsc engine descriptor\n  *\n  * Parse \\a tuningData according to the settings specified in \\a descriptor to\n  * populate the lsc data and registers lsc controls in \\a controls.\n  *\n  * \\return 0 on success, a negative error code otherwise\n  */\n-int LscAlgorithm::init(const ValueNode &tuningData, const Size &sensorSize,\n-\t\t       ControlInfoMap::Map &controls)\n+int LscAlgorithm::init(const ValueNode &tuningData, ControlInfoMap::Map &controls,\n+\t\t       const LscDescriptor &descriptor)\n {\n \tpolynomial_ = false;\n \n@@ -108,7 +108,7 @@ int LscAlgorithm::init(const ValueNode &tuningData, const Size &sensorSize,\n \t\t * \\todo: Most likely the reference frame should be native_size.\n \t\t * Let's wait how the internal discussions progress.\n \t\t */\n-\t\timpl_ = std::make_unique<LscPolynomial>(sensorSize);\n+\t\timpl_ = std::make_unique<LscPolynomial>(descriptor.sensorSize);\n \t\tpolynomial_ = true;\n \t\tLOG(Lsc, Debug) << \"Using polynomial Lsc\";\n \t} else {\n@@ -123,7 +123,7 @@ int LscAlgorithm::init(const ValueNode &tuningData, const Size &sensorSize,\n \t\treturn -EINVAL;\n \t}\n \n-\tint ret = impl_->parseLscData(yamlSets);\n+\tint ret = impl_->parseLscData(yamlSets, descriptor);\n \tif (ret)\n \t\treturn ret;\n \ndiff --git a/src/ipa/libipa/lsc.h b/src/ipa/libipa/lsc.h\nindex 9a51d32c3464..9fe8ad67ea33 100644\n--- a/src/ipa/libipa/lsc.h\n+++ b/src/ipa/libipa/lsc.h\n@@ -38,8 +38,8 @@ struct FrameContext {\n class LscAlgorithm\n {\n public:\n-\tint init(const ValueNode &tuningData, const Size &sensorSize,\n-\t\t ControlInfoMap::Map &controls);\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,\ndiff --git a/src/ipa/libipa/lsc_base.cpp b/src/ipa/libipa/lsc_base.cpp\nindex 7b0216b689c4..30af8d970a12 100644\n--- a/src/ipa/libipa/lsc_base.cpp\n+++ b/src/ipa/libipa/lsc_base.cpp\n@@ -19,23 +19,20 @@ namespace ipa {\n namespace lsc {\n \n /**\n- * \\struct Components\n+ * \\typedef Components\n  * \\brief Associate a colour components with a list of gains\n  *\n  * Lsc tables are defined as a list of gain values associated to a colour\n  * component.\n  *\n- * \\var Components::r\n- * \\brief The list of gains for the Red colour component\n+ * As different ISP support different colour components (usually 'r', 'gr',\n+ * 'gb', 'b' or just 'r', 'g', 'b') this class associates a string\n+ * identifier for the colour component to a list of gains.\n  *\n- * \\var Components::gr\n- * \\brief The list of gains for the Green/Red colour component\n+ * Each key name shall match an entry in the tuning file.\n  *\n- * \\var Components::gb\n- * \\brief The list of gains for the Green/Blue colour component\n- *\n- * \\var Components::b\n- * \\brief The list of gains for the Blue colour component\n+ * The list of keys is provided to the LscAlgorithm class using \\a\n+ * LscDescriptor::keys.\n  */\n \n /**\n@@ -57,13 +54,32 @@ void Interpolator<lsc::Components>::\n \t\t    lsc::Components &dest,\n \t\t    double lambda)\n {\n-\tinterpolateVector(a.r, b.r, dest.r, lambda);\n-\tinterpolateVector(a.gr, b.gr, dest.gr, lambda);\n-\tinterpolateVector(a.gb, b.gb, dest.gb, lambda);\n-\tinterpolateVector(a.b, b.b, dest.b, lambda);\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\n+ *\n+ * \\var LscDescriptor::keys\n+ * \\brief The list of colour components to which a list of gains is associated\n+ * with in the tuning file. Used for parsing the tuning file\n+ *\n+ * \\var LscDescriptor::numHCells\n+ * \\brief Number of horizontal cells of the ISP lsc grid. Used for validating\n+ * the list of gains parsed from tuning file\n+ *\n+ * \\var LscDescriptor::numVCells\n+ * \\brief Number of vertical cells of the ISP lsc grid. Used for validating\n+ * the list of gains parsed from tuning file\n+ *\n+ * \\var LscDescriptor::sensorSize\n+ * \\brief The physical sensor size. This is the largest frame size used to\n+ * generate the lsc table. Only used by the polynomial lsc algorithm\n+ */\n+\n /**\n  * \\class LscImplementation\n  * \\brief Pure virtual base class for lsc algorithm implementations\n@@ -80,6 +96,11 @@ void Interpolator<lsc::Components>::\n  * \\fn LscImplementation::parseLscData\n  * \\brief Parse \\a tuningData\n  * \\param[in] tuningData The tuning data\n+ * \\param[in] descriptor The lsc engine descriptor\n+ *\n+ * Parse the tuning file using the \\a descriptor to identify the colour\n+ * components in the tuning data and validate the size of the loaded gains\n+ * tables.\n  *\n  * \\return 0 on success, a negative error number otherwise\n  */\ndiff --git a/src/ipa/libipa/lsc_base.h b/src/ipa/libipa/lsc_base.h\nindex 8d1843a5d4fd..48307455362a 100644\n--- a/src/ipa/libipa/lsc_base.h\n+++ b/src/ipa/libipa/lsc_base.h\n@@ -26,13 +26,7 @@ namespace ipa {\n \n namespace lsc {\n \n-struct Components {\n-\tstd::vector<uint16_t> r;\n-\tstd::vector<uint16_t> gr;\n-\tstd::vector<uint16_t> gb;\n-\tstd::vector<uint16_t> b;\n-};\n-\n+using Components = std::map<std::string, std::vector<uint16_t>>;\n using ComponentsMap = std::map<unsigned int, Components>;\n \n } /* namespace lsc */\n@@ -56,12 +50,20 @@ void Interpolator<lsc::Components>::\n \t\t    double lambda);\n #endif /* __DOXYGEN__ */\n \n+struct LscDescriptor {\n+\tstd::vector<std::string> keys;\n+\tunsigned int numHCells;\n+\tunsigned int numVCells;\n+\tSize sensorSize;\n+};\n+\n class LscImplementation\n {\n public:\n \tvirtual ~LscImplementation() {}\n \n-\tvirtual int parseLscData(const ValueNode &tuningData) = 0;\n+\tvirtual int parseLscData(const ValueNode &tuningData,\n+\t\t\t\t const LscDescriptor &descriptor) = 0;\n \n \tvirtual lsc::ComponentsMap\n \tsampleForCrop(const Rectangle &cropRectangle,\ndiff --git a/src/ipa/libipa/lsc_polynomial.cpp b/src/ipa/libipa/lsc_polynomial.cpp\nindex f39122963019..0550229b5152 100644\n--- a/src/ipa/libipa/lsc_polynomial.cpp\n+++ b/src/ipa/libipa/lsc_polynomial.cpp\n@@ -133,44 +133,43 @@ void Polynomial::setReferenceImageSize(const Size &size)\n /**\n  * \\brief Parse polynomial lsc data\n  * \\param[in] sets The tuning file content\n+ * \\param[in] descriptor The lsc engine descriptor\n  *\n  * Parse the lsc data in polyomial form from the \\a sets tuning data.\n  *\n  * \\return 0 on success or a negative error number otherwise\n  */\n-int LscPolynomial::parseLscData(const ValueNode &sets)\n+int LscPolynomial::parseLscData(const ValueNode &sets,\n+\t\t\t\tconst LscDescriptor &descriptor)\n {\n \tfor (const auto &set : sets.asList()) {\n-\t\tstd::optional<lsc::Polynomial> pr, pgr, pgb, pb;\n \t\tuint32_t ct = set[\"ct\"].get<uint32_t>(0);\n \n-\t\tif (lscData_.count(ct)) {\n-\t\t\tLOG(LscPolynomial, Error)\n-\t\t\t\t<< \"Multiple sets found for \"\n-\t\t\t\t<< \"color temperature \" << ct;\n-\t\t\treturn -EINVAL;\n+\t\tPolynomialComponents components;\n+\t\tfor (auto &k : descriptor.keys) {\n+\t\t\tauto polynomial = set[k.c_str()].get<lsc::Polynomial>();\n+\t\t\tif (!polynomial) {\n+\t\t\t\tLOG(LscPolynomial, Error)\n+\t\t\t\t\t<< \"Missing polynomial for component \"\n+\t\t\t\t\t<< k;\n+\t\t\t\treturn -EINVAL;\n+\t\t\t}\n+\n+\t\t\tauto [it, inserted] =\n+\t\t\t\tcomponents.emplace(std::piecewise_construct,\n+\t\t\t\t\t\t   std::forward_as_tuple(k.c_str()),\n+\t\t\t\t\t\t   std::forward_as_tuple(*polynomial));\n+\n+\t\t\tit->second.setReferenceImageSize(descriptor.sensorSize);\n \t\t}\n \n-\t\tpr = set[\"r\"].get<lsc::Polynomial>();\n-\t\tpgr = set[\"gr\"].get<lsc::Polynomial>();\n-\t\tpgb = set[\"gb\"].get<lsc::Polynomial>();\n-\t\tpb = set[\"b\"].get<lsc::Polynomial>();\n-\n-\t\tif (!(pr || pgr || pgb || pb)) {\n+\t\tauto [it, inserted] = lscData_.emplace(ct, components);\n+\t\tif (!inserted) {\n \t\t\tLOG(LscPolynomial, Error)\n-\t\t\t\t<< \"Failed to parse polynomial for \"\n-\t\t\t\t<< \"colour temperature \" << ct;\n+\t\t\t\t<< \"Multiple sets found for \"\n+\t\t\t\t<< \"color temperature \" << ct;\n \t\t\treturn -EINVAL;\n \t\t}\n-\n-\t\tpr->setReferenceImageSize(sensorSize_);\n-\t\tpgr->setReferenceImageSize(sensorSize_);\n-\t\tpgb->setReferenceImageSize(sensorSize_);\n-\t\tpb->setReferenceImageSize(sensorSize_);\n-\n-\t\tlscData_.emplace(std::piecewise_construct,\n-\t\t\t\t std::forward_as_tuple(ct),\n-\t\t\t\t std::forward_as_tuple(PolynomialComponents{ *pr, *pgr, *pgb, *pb }));\n \t}\n \n \tif (lscData_.empty()) {\n@@ -210,13 +209,17 @@ LscPolynomial::sampleForCrop(const Rectangle &cropRectangle,\n \n \tlsc::ComponentsMap components;\n \n-\tfor (const auto &[k, p] : lscData_) {\n-\t\tcomponents[k] = {\n-\t\t\tsamplePolynomial(p.pr, xPos, yPos, cropRectangle),\n-\t\t\tsamplePolynomial(p.pgr, xPos, yPos, cropRectangle),\n-\t\t\tsamplePolynomial(p.pgb, xPos, yPos, cropRectangle),\n-\t\t\tsamplePolynomial(p.pb, xPos, yPos, cropRectangle)\n-\t\t};\n+\tfor (const auto &[t, c] : lscData_) {\n+\t\tlsc::Components comp;\n+\n+\t\tfor (const auto &[k, p] : c) {\n+\t\t\tcomp.emplace(std::piecewise_construct,\n+\t\t\t\t     std::forward_as_tuple(k),\n+\t\t\t\t     std::forward_as_tuple(samplePolynomial(p, xPos, yPos,\n+\t\t\t\t\t\t\t\t\t    cropRectangle)));\n+\t\t}\n+\n+\t\tcomponents[t] = comp;\n \t}\n \n \treturn components;\ndiff --git a/src/ipa/libipa/lsc_polynomial.h b/src/ipa/libipa/lsc_polynomial.h\nindex d2276ecc6f6b..2a26db499d68 100644\n--- a/src/ipa/libipa/lsc_polynomial.h\n+++ b/src/ipa/libipa/lsc_polynomial.h\n@@ -53,12 +53,7 @@ private:\n class LscPolynomial : public LscImplementation\n {\n private:\n-\tstruct PolynomialComponents {\n-\t\tlsc::Polynomial pr;\n-\t\tlsc::Polynomial pgr;\n-\t\tlsc::Polynomial pgb;\n-\t\tlsc::Polynomial pb;\n-\t};\n+\tusing PolynomialComponents = std::map<std::string, lsc::Polynomial>;\n \tusing PolynomialComponentsMap = std::map<unsigned int, PolynomialComponents>;\n \n public:\n@@ -67,7 +62,8 @@ public:\n \t{\n \t}\n \n-\tint parseLscData(const ValueNode &sets) override;\n+\tint parseLscData(const ValueNode &sets,\n+\t\t\t const LscDescriptor &descriptor) override;\n \n \tlsc::ComponentsMap\n \tsampleForCrop(const Rectangle &cropRectangle,\ndiff --git a/src/ipa/libipa/lsc_table.cpp b/src/ipa/libipa/lsc_table.cpp\nindex 41a862b92e88..415c1cc0ccd4 100644\n--- a/src/ipa/libipa/lsc_table.cpp\n+++ b/src/ipa/libipa/lsc_table.cpp\n@@ -7,9 +7,6 @@\n \n #include \"lsc_table.h\"\n \n-/* \\todo Remove RkISP1 from libipa. */\n-#include \"linux/rkisp1-config.h\"\n-\n namespace libcamera {\n \n LOG_DEFINE_CATEGORY(LscTable)\n@@ -29,42 +26,56 @@ namespace ipa {\n /**\n  * \\brief Parse tabular lsc data\n  * \\param[in] sets The tuning file content\n+ * \\param[in] descriptor The lsc engine descriptor\n  *\n  * Parse the lsc data in tabular form from the \\a sets tuning data.\n  *\n  * \\return 0 on success or a negative error number otherwise\n  */\n-int LscTable::parseLscData(const ValueNode &sets)\n+int LscTable::parseLscData(const ValueNode &sets,\n+\t\t\t   const LscDescriptor &descriptor)\n {\n \tfor (const auto &set : sets.asList()) {\n \t\tuint32_t ct = set[\"ct\"].get<uint32_t>(0);\n \n-\t\tif (lscData_.count(ct)) {\n-\t\t\tLOG(LscTable, Error)\n-\t\t\t\t<< \"Multiple sets found for color temperature \"\n-\t\t\t\t<< ct;\n-\t\t\treturn -EINVAL;\n-\t\t}\n+\t\tint ret = parseLscComponent(set, ct, descriptor);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\t}\n \n-\t\tlsc::Components components;\n-\t\tcomponents.r = parseTable(set, \"r\");\n-\t\tcomponents.gr = parseTable(set, \"gr\");\n-\t\tcomponents.gb = parseTable(set, \"gb\");\n-\t\tcomponents.b = parseTable(set, \"b\");\n+\tif (lscData_.empty()) {\n+\t\tLOG(LscTable, Error) << \"Failed to load any sets\";\n+\t\treturn -EINVAL;\n+\t}\n \n-\t\tif (components.r.empty() || components.gr.empty() ||\n-\t\t    components.gb.empty() || components.b.empty()) {\n+\treturn 0;\n+}\n+\n+int LscTable::parseLscComponent(const ValueNode &yamlSet,\n+\t\t\t\tunsigned int ct, const LscDescriptor &descriptor)\n+{\n+\tlsc::Components component;\n+\tfor (auto &k : descriptor.keys) {\n+\t\tauto [it, inserted] = component.emplace(\n+\t\t\tstd::piecewise_construct,\n+\t\t\tstd::forward_as_tuple(k.c_str()),\n+\t\t\tstd::forward_as_tuple(parseTable(yamlSet,\n+\t\t\t\t\t\t\t k.c_str(),\n+\t\t\t\t\t\t\t descriptor.numHCells,\n+\t\t\t\t\t\t\t descriptor.numVCells)));\n+\t\tif (!inserted || it->second.empty()) {\n \t\t\tLOG(LscTable, Error)\n-\t\t\t\t<< \"Set for color temperature \" << ct\n-\t\t\t\t<< \" is missing tables\";\n+\t\t\t\t<< \"Set \" << k << \" for color temperature \"\n+\t\t\t\t<< ct << \" is missing\";\n \t\t\treturn -EINVAL;\n \t\t}\n-\n-\t\tlscData_.emplace(ct, std::move(components));\n \t}\n \n-\tif (lscData_.empty()) {\n-\t\tLOG(LscTable, Error) << \"Failed to load any sets\";\n+\tauto [it, inserted] = lscData_.emplace(ct, component);\n+\tif (!inserted) {\n+\t\tLOG(LscTable, Error)\n+\t\t\t<< \"Multiple sets found for color temperature \"\n+\t\t\t<< ct;\n \t\treturn -EINVAL;\n \t}\n \n@@ -72,17 +83,18 @@ int LscTable::parseLscData(const ValueNode &sets)\n }\n \n std::vector<uint16_t> LscTable::parseTable(const ValueNode &tuningData,\n-\t\t\t\t\t   const char *prop)\n+\t\t\t\t\t   const char *prop,\n+\t\t\t\t\t   unsigned int numHCells,\n+\t\t\t\t\t   unsigned int numVCells)\n {\n-\tstatic constexpr unsigned int kLscNumSamples =\n-\t\tRKISP1_CIF_ISP_LSC_SAMPLES_MAX * RKISP1_CIF_ISP_LSC_SAMPLES_MAX;\n+\tunsigned int lscNumSamples = numHCells * numVCells;\n \n \tstd::vector<uint16_t> table =\n \t\ttuningData[prop].get<std::vector<uint16_t>>().value_or(utils::defopt);\n-\tif (table.size() != kLscNumSamples) {\n+\tif (table.size() != lscNumSamples) {\n \t\tLOG(LscTable, Error)\n \t\t\t<< \"Invalid '\" << prop << \"' values: expected \"\n-\t\t\t<< kLscNumSamples\n+\t\t\t<< lscNumSamples\n \t\t\t<< \" elements, got \" << table.size();\n \t\treturn {};\n \t}\ndiff --git a/src/ipa/libipa/lsc_table.h b/src/ipa/libipa/lsc_table.h\nindex 67c7464ea5b6..3fe52afbad7b 100644\n--- a/src/ipa/libipa/lsc_table.h\n+++ b/src/ipa/libipa/lsc_table.h\n@@ -26,7 +26,8 @@ namespace ipa {\n class LscTable : public LscImplementation\n {\n public:\n-\tint parseLscData(const ValueNode &sets) override;\n+\tint parseLscData(const ValueNode &sets,\n+\t\t\t const LscDescriptor &descriptor) override;\n \n \tlsc::ComponentsMap\n \tsampleForCrop([[maybe_unused]] const Rectangle &cropRectangle,\n@@ -39,8 +40,12 @@ public:\n \t}\n \n private:\n+\tint parseLscComponent(const ValueNode &yamlSet,\n+\t\t\t      unsigned int ct, const LscDescriptor &descriptor);\n \tstd::vector<uint16_t> parseTable(const ValueNode &tuningData,\n-\t\t\t\t\t const char *prop);\n+\t\t\t\t\t const char *prop,\n+\t\t\t\t\t unsigned int numHCells,\n+\t\t\t\t\t unsigned int numVCells);\n \n \tlsc::ComponentsMap lscData_;\n };\ndiff --git a/src/ipa/rkisp1/algorithms/lsc.cpp b/src/ipa/rkisp1/algorithms/lsc.cpp\nindex 828ab2f32fcc..79d68ac7d6dd 100644\n--- a/src/ipa/rkisp1/algorithms/lsc.cpp\n+++ b/src/ipa/rkisp1/algorithms/lsc.cpp\n@@ -67,8 +67,12 @@ int LensShadingCorrection::init([[maybe_unused]] IPAContext &context,\n \txPos_ = sizesListToPositions(xSize_);\n \tyPos_ = sizesListToPositions(ySize_);\n \n-\treturn lscAlgo_.init(tuningData, context.sensorInfo.activeAreaSize,\n-\t\t\t     context.ctrlMap);\n+\treturn lscAlgo_.init(tuningData,  context.ctrlMap, {\n+\t\t\t\t.keys = { \"r\", \"gr\", \"gb\", \"b\" },\n+\t\t\t\t.numHCells = RKISP1_CIF_ISP_LSC_SAMPLES_MAX,\n+\t\t\t\t.numVCells = RKISP1_CIF_ISP_LSC_SAMPLES_MAX,\n+\t\t\t\t.sensorSize = context.sensorInfo.activeAreaSize\n+\t\t\t     });\n }\n \n std::vector<double> LensShadingCorrection::parseSizes(const ValueNode &tuningData,\n@@ -174,10 +178,14 @@ void LensShadingCorrection::setParameters(rkisp1_cif_isp_lsc_config &config)\n void LensShadingCorrection::copyTable(rkisp1_cif_isp_lsc_config &config,\n \t\t\t\t      const lsc::Components &set)\n {\n-\tstd::copy(set.r.begin(), set.r.end(), &config.r_data_tbl[0][0]);\n-\tstd::copy(set.gr.begin(), set.gr.end(), &config.gr_data_tbl[0][0]);\n-\tstd::copy(set.gb.begin(), set.gb.end(), &config.gb_data_tbl[0][0]);\n-\tstd::copy(set.b.begin(), set.b.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",
    "prefixes": [
        "v3",
        "25/35"
    ]
}