Show a patch.

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

{
    "id": 25787,
    "url": "https://patchwork.libcamera.org/api/patches/25787/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/25787/",
    "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": "<20260114-sklug-lsc-resampling-v2-dev-v3-7-80cd24f4dd61@ideasonboard.com>",
    "date": "2026-01-14T11:58:00",
    "name": "[v3,07/15] ipa: rksip1: lsc: Move function definitions out of class",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": false,
    "hash": "2985ee03fb25fcd564e0ed317da93a0e42bd4b60",
    "submitter": {
        "id": 184,
        "url": "https://patchwork.libcamera.org/api/people/184/?format=api",
        "name": "Stefan Klug",
        "email": "stefan.klug@ideasonboard.com"
    },
    "delegate": null,
    "mbox": "https://patchwork.libcamera.org/patch/25787/mbox/",
    "series": [
        {
            "id": 5707,
            "url": "https://patchwork.libcamera.org/api/series/5707/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=5707",
            "date": "2026-01-14T11:57:53",
            "name": "Add resampling support for polynomial LSC data",
            "version": 3,
            "mbox": "https://patchwork.libcamera.org/series/5707/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/25787/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/25787/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 DDAA3C3226\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 14 Jan 2026 11:58:21 +0000 (UTC)",
            "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 9282161FC1;\n\tWed, 14 Jan 2026 12:58:21 +0100 (CET)",
            "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 D194D61FB9\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 14 Jan 2026 12:58:19 +0100 (CET)",
            "from ideasonboard.com (unknown\n\t[IPv6:2a00:6020:448c:6c00:b781:dff2:957:7831])\n\tby perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 1F3914BB;\n\tWed, 14 Jan 2026 12:57:53 +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=\"TSVOv5HP\"; dkim-atps=neutral",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1768391873;\n\tbh=FZ8GonHX/9GBtesyrRJ6bQHXD74/oO2vTKfx8iChULw=;\n\th=From:Date:Subject:References:In-Reply-To:To:Cc:From;\n\tb=TSVOv5HP/WWFuBWoS/GVl/NxJy6Y9ozkY0JK5byZIliFIw3dWF/Subgki5o+Ntny+\n\tDXh3eihfjzeoh+FbUxk6vmrENG/4utmN0GRcoI8kHgAXzhdLZFmc2VzgU5cq2aHrGL\n\tCcyoHhpnWSa4FbjDDuKR4fzOJlb/gfCJpCH6UTWw=",
        "From": "Stefan Klug <stefan.klug@ideasonboard.com>",
        "Date": "Wed, 14 Jan 2026 12:58:00 +0100",
        "Subject": "[PATCH v3 07/15] ipa: rksip1: lsc: Move function definitions out\n\tof class",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain; charset=\"utf-8\"",
        "Content-Transfer-Encoding": "8bit",
        "Message-Id": "<20260114-sklug-lsc-resampling-v2-dev-v3-7-80cd24f4dd61@ideasonboard.com>",
        "References": "<20260114-sklug-lsc-resampling-v2-dev-v3-0-80cd24f4dd61@ideasonboard.com>",
        "In-Reply-To": "<20260114-sklug-lsc-resampling-v2-dev-v3-0-80cd24f4dd61@ideasonboard.com>",
        "To": "libcamera-devel@lists.libcamera.org",
        "Cc": "Stefan Klug <stefan.klug@ideasonboard.com>, =?utf-8?q?Barnab=C3=A1s_P?=\n\t=?utf-8?b?xZFjemU=?= <barnabas.pocze@ideasonboard.com>,\n\tRui Wang <rui.wang@ideasonboard.com>",
        "X-Mailer": "b4 0.14.2",
        "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": "Move the function definitions out of the related classes. This was noted\nin review after the series was already merged. After trying it out I\nmust admit that it really improves readability and reduces the\nindentation level by one.\n\nSigned-off-by: Stefan Klug <stefan.klug@ideasonboard.com>\nReviewed-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>\nReviewed-by: Rui Wang <rui.wang@ideasonboard.com>\n\n---\n\nNote: This patch contains no functional changes. `git diff\n--ignore-space-change` helps in verifying that.\n\nChanges in v2:\n- Collected tags\n---\n src/ipa/rkisp1/algorithms/lsc.cpp | 314 ++++++++++++++++++++------------------\n 1 file changed, 163 insertions(+), 151 deletions(-)",
    "diff": "diff --git a/src/ipa/rkisp1/algorithms/lsc.cpp b/src/ipa/rkisp1/algorithms/lsc.cpp\nindex 1b15c11093cfd63bf740558da9450ac836b12004..1962d18d148b4abac6e601ec36e0c68944a6191c 100644\n--- a/src/ipa/rkisp1/algorithms/lsc.cpp\n+++ b/src/ipa/rkisp1/algorithms/lsc.cpp\n@@ -85,184 +85,196 @@ public:\n \t}\n \n \tint parseLscData(const YamlObject &yamlSets,\n-\t\t\t std::map<unsigned int, LensShadingCorrection::Components> &lscData)\n-\t{\n-\t\tconst auto &sets = yamlSets.asList();\n-\t\tfor (const auto &yamlSet : sets) {\n-\t\t\tstd::optional<LscPolynomial> pr, pgr, pgb, pb;\n-\t\t\tuint32_t ct = yamlSet[\"ct\"].get<uint32_t>(0);\n-\n-\t\t\tif (lscData.count(ct)) {\n-\t\t\t\tLOG(RkISP1Lsc, Error)\n-\t\t\t\t\t<< \"Multiple sets found for \"\n-\t\t\t\t\t<< \"color temperature \" << ct;\n-\t\t\t\treturn -EINVAL;\n-\t\t\t}\n-\n-\t\t\tLensShadingCorrection::Components &set = lscData[ct];\n-\t\t\tpr = yamlSet[\"r\"].get<LscPolynomial>();\n-\t\t\tpgr = yamlSet[\"gr\"].get<LscPolynomial>();\n-\t\t\tpgb = yamlSet[\"gb\"].get<LscPolynomial>();\n-\t\t\tpb = yamlSet[\"b\"].get<LscPolynomial>();\n-\n-\t\t\tif (!(pr || pgr || pgb || pb)) {\n-\t\t\t\tLOG(RkISP1Lsc, Error)\n-\t\t\t\t\t<< \"Failed to parse polynomial for \"\n-\t\t\t\t\t<< \"colour temperature \" << ct;\n-\t\t\t\treturn -EINVAL;\n-\t\t\t}\n-\n-\t\t\tpr->setReferenceImageSize(sensorSize_);\n-\t\t\tpgr->setReferenceImageSize(sensorSize_);\n-\t\t\tpgb->setReferenceImageSize(sensorSize_);\n-\t\t\tpb->setReferenceImageSize(sensorSize_);\n-\t\t\tset.r = samplePolynomial(*pr);\n-\t\t\tset.gr = samplePolynomial(*pgr);\n-\t\t\tset.gb = samplePolynomial(*pgb);\n-\t\t\tset.b = samplePolynomial(*pb);\n+\t\t\t std::map<unsigned int, LensShadingCorrection::Components> &lscData);\n+\n+private:\n+\tstd::vector<double> sizesListToPositions(const std::vector<double> &sizes);\n+\tstd::vector<uint16_t> samplePolynomial(const LscPolynomial &poly);\n+\n+\tSize sensorSize_;\n+\tRectangle cropRectangle_;\n+\tconst std::vector<double> &xSizes_;\n+\tconst std::vector<double> &ySizes_;\n+};\n+\n+int LscPolynomialLoader::parseLscData(const YamlObject &yamlSets,\n+\t\t\t\t      std::map<unsigned int, LensShadingCorrection::Components> &lscData)\n+{\n+\tconst auto &sets = yamlSets.asList();\n+\tfor (const auto &yamlSet : sets) {\n+\t\tstd::optional<LscPolynomial> pr, pgr, pgb, pb;\n+\t\tuint32_t ct = yamlSet[\"ct\"].get<uint32_t>(0);\n+\n+\t\tif (lscData.count(ct)) {\n+\t\t\tLOG(RkISP1Lsc, 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\t}\n \n-\t\tif (lscData.empty()) {\n-\t\t\tLOG(RkISP1Lsc, Error) << \"Failed to load any sets\";\n+\t\tLensShadingCorrection::Components &set = lscData[ct];\n+\t\tpr = yamlSet[\"r\"].get<LscPolynomial>();\n+\t\tpgr = yamlSet[\"gr\"].get<LscPolynomial>();\n+\t\tpgb = yamlSet[\"gb\"].get<LscPolynomial>();\n+\t\tpb = yamlSet[\"b\"].get<LscPolynomial>();\n+\n+\t\tif (!(pr || pgr || pgb || pb)) {\n+\t\t\tLOG(RkISP1Lsc, Error)\n+\t\t\t\t<< \"Failed to parse polynomial for \"\n+\t\t\t\t<< \"colour temperature \" << ct;\n \t\t\treturn -EINVAL;\n \t\t}\n \n-\t\treturn 0;\n+\t\tpr->setReferenceImageSize(sensorSize_);\n+\t\tpgr->setReferenceImageSize(sensorSize_);\n+\t\tpgb->setReferenceImageSize(sensorSize_);\n+\t\tpb->setReferenceImageSize(sensorSize_);\n+\t\tset.r = samplePolynomial(*pr);\n+\t\tset.gr = samplePolynomial(*pgr);\n+\t\tset.gb = samplePolynomial(*pgb);\n+\t\tset.b = samplePolynomial(*pb);\n \t}\n \n-private:\n-\t/*\n-\t * The rkisp1 LSC grid spacing is defined by the cell sizes on the first\n-\t * half of the grid. This is then mirrored in hardware to the other\n-\t * half. See parseSizes() for further details. For easier handling, this\n-\t * function converts the cell sizes of half the grid to a list of\n-\t * position of the whole grid (on one axis). Example:\n-\t *\n-\t * input:   | 0.2 | 0.3 |\n-\t * output: 0.0   0.2   0.5   0.8   1.0\n-\t */\n-\tstd::vector<double> sizesListToPositions(const std::vector<double> &sizes)\n-\t{\n-\t\tconst int half = sizes.size();\n-\t\tstd::vector<double> positions(half * 2 + 1);\n-\t\tdouble x = 0.0;\n-\n-\t\tpositions[half] = 0.5;\n-\t\tfor (int i = 1; i <= half; i++) {\n-\t\t\tx += sizes[half - i];\n-\t\t\tpositions[half - i] = 0.5 - x;\n-\t\t\tpositions[half + i] = 0.5 + x;\n-\t\t}\n+\tif (lscData.empty()) {\n+\t\tLOG(RkISP1Lsc, Error) << \"Failed to load any sets\";\n+\t\treturn -EINVAL;\n+\t}\n \n-\t\treturn positions;\n+\treturn 0;\n+}\n+\n+/*\n+ * The rkisp1 LSC grid spacing is defined by the cell sizes on the first half of\n+ * the grid. This is then mirrored in hardware to the other half. See\n+ * parseSizes() for further details. For easier handling, this function converts\n+ * the cell sizes of half the grid to a list of position of the whole grid (on\n+ * one axis). Example:\n+ *\n+ * input:   | 0.2 | 0.3 |\n+ * output: 0.0   0.2   0.5   0.8   1.0\n+ */\n+std::vector<double> LscPolynomialLoader::sizesListToPositions(const std::vector<double> &sizes)\n+{\n+\tconst int half = sizes.size();\n+\tstd::vector<double> positions(half * 2 + 1);\n+\tdouble x = 0.0;\n+\n+\tpositions[half] = 0.5;\n+\tfor (int i = 1; i <= half; i++) {\n+\t\tx += sizes[half - i];\n+\t\tpositions[half - i] = 0.5 - x;\n+\t\tpositions[half + i] = 0.5 + x;\n \t}\n \n-\tstd::vector<uint16_t> samplePolynomial(const LscPolynomial &poly)\n-\t{\n-\t\tconstexpr int k = RKISP1_CIF_ISP_LSC_SAMPLES_MAX;\n-\n-\t\tdouble m = poly.getM();\n-\t\tdouble x0 = cropRectangle_.x / m;\n-\t\tdouble y0 = cropRectangle_.y / m;\n-\t\tdouble w = cropRectangle_.width / m;\n-\t\tdouble h = cropRectangle_.height / m;\n-\t\tstd::vector<uint16_t> samples;\n-\n-\t\tASSERT(xSizes_.size() * 2 + 1 == k);\n-\t\tASSERT(ySizes_.size() * 2 + 1 == k);\n-\n-\t\tsamples.reserve(k * k);\n-\n-\t\tstd::vector<double> xPos(sizesListToPositions(xSizes_));\n-\t\tstd::vector<double> yPos(sizesListToPositions(ySizes_));\n-\n-\t\tfor (int y = 0; y < k; y++) {\n-\t\t\tfor (int x = 0; x < k; x++) {\n-\t\t\t\tdouble xp = x0 + xPos[x] * w;\n-\t\t\t\tdouble yp = y0 + yPos[y] * h;\n-\t\t\t\t/*\n-\t\t\t\t * The hardware uses 2.10 fixed point format and\n-\t\t\t\t * limits the legal values to [1..3.999]. Scale\n-\t\t\t\t * and clamp the sampled value accordingly.\n-\t\t\t\t */\n-\t\t\t\tint v = static_cast<int>(\n-\t\t\t\t\tpoly.sampleAtNormalizedPixelPos(xp, yp) *\n-\t\t\t\t\t1024);\n-\t\t\t\tv = std::min(std::max(v, 1024), 4095);\n-\t\t\t\tsamples.push_back(v);\n-\t\t\t}\n+\treturn positions;\n+}\n+\n+std::vector<uint16_t> LscPolynomialLoader::samplePolynomial(const LscPolynomial &poly)\n+{\n+\tconstexpr int k = RKISP1_CIF_ISP_LSC_SAMPLES_MAX;\n+\n+\tdouble m = poly.getM();\n+\tdouble x0 = cropRectangle_.x / m;\n+\tdouble y0 = cropRectangle_.y / m;\n+\tdouble w = cropRectangle_.width / m;\n+\tdouble h = cropRectangle_.height / m;\n+\tstd::vector<uint16_t> samples;\n+\n+\tASSERT(xSizes_.size() * 2 + 1 == k);\n+\tASSERT(ySizes_.size() * 2 + 1 == k);\n+\n+\tsamples.reserve(k * k);\n+\n+\tstd::vector<double> xPos(sizesListToPositions(xSizes_));\n+\tstd::vector<double> yPos(sizesListToPositions(ySizes_));\n+\n+\tfor (int y = 0; y < k; y++) {\n+\t\tfor (int x = 0; x < k; x++) {\n+\t\t\tdouble xp = x0 + xPos[x] * w;\n+\t\t\tdouble yp = y0 + yPos[y] * h;\n+\t\t\t/*\n+\t\t\t * The hardware uses 2.10 fixed point format and limits\n+\t\t\t * the legal values to [1..3.999]. Scale and clamp the\n+\t\t\t * sampled value accordingly.\n+\t\t\t */\n+\t\t\tint v = static_cast<int>(\n+\t\t\t\tpoly.sampleAtNormalizedPixelPos(xp, yp) *\n+\t\t\t\t1024);\n+\t\t\tv = std::min(std::max(v, 1024), 4095);\n+\t\t\tsamples.push_back(v);\n \t\t}\n-\t\treturn samples;\n \t}\n-\n-\tSize sensorSize_;\n-\tRectangle cropRectangle_;\n-\tconst std::vector<double> &xSizes_;\n-\tconst std::vector<double> &ySizes_;\n-};\n+\treturn samples;\n+}\n \n class LscTableLoader\n {\n public:\n \tint parseLscData(const YamlObject &yamlSets,\n-\t\t\t std::map<unsigned int, LensShadingCorrection::Components> &lscData)\n-\t{\n-\t\tconst auto &sets = yamlSets.asList();\n-\n-\t\tfor (const auto &yamlSet : sets) {\n-\t\t\tuint32_t ct = yamlSet[\"ct\"].get<uint32_t>(0);\n-\n-\t\t\tif (lscData.count(ct)) {\n-\t\t\t\tLOG(RkISP1Lsc, Error)\n-\t\t\t\t\t<< \"Multiple sets found for color temperature \"\n-\t\t\t\t\t<< ct;\n-\t\t\t\treturn -EINVAL;\n-\t\t\t}\n-\n-\t\t\tLensShadingCorrection::Components &set = lscData[ct];\n-\n-\t\t\tset.r = parseTable(yamlSet, \"r\");\n-\t\t\tset.gr = parseTable(yamlSet, \"gr\");\n-\t\t\tset.gb = parseTable(yamlSet, \"gb\");\n-\t\t\tset.b = parseTable(yamlSet, \"b\");\n-\n-\t\t\tif (set.r.empty() || set.gr.empty() ||\n-\t\t\t    set.gb.empty() || set.b.empty()) {\n-\t\t\t\tLOG(RkISP1Lsc, Error)\n-\t\t\t\t\t<< \"Set for color temperature \" << ct\n-\t\t\t\t\t<< \" is missing tables\";\n-\t\t\t\treturn -EINVAL;\n-\t\t\t}\n-\t\t}\n+\t\t\t std::map<unsigned int, LensShadingCorrection::Components> &lscData);\n+\n+private:\n+\tstd::vector<uint16_t> parseTable(const YamlObject &tuningData,\n+\t\t\t\t\t const char *prop);\n+};\n+\n+int LscTableLoader::parseLscData(const YamlObject &yamlSets,\n+\t\t\t\t std::map<unsigned int, LensShadingCorrection::Components> &lscData)\n+{\n+\tconst auto &sets = yamlSets.asList();\n+\n+\tfor (const auto &yamlSet : sets) {\n+\t\tuint32_t ct = yamlSet[\"ct\"].get<uint32_t>(0);\n \n-\t\tif (lscData.empty()) {\n-\t\t\tLOG(RkISP1Lsc, Error) << \"Failed to load any sets\";\n+\t\tif (lscData.count(ct)) {\n+\t\t\tLOG(RkISP1Lsc, 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 \n-\t\treturn 0;\n-\t}\n+\t\tLensShadingCorrection::Components &set = lscData[ct];\n \n-private:\n-\tstd::vector<uint16_t> parseTable(const YamlObject &tuningData,\n-\t\t\t\t\t const char *prop)\n-\t{\n-\t\tstatic constexpr unsigned int kLscNumSamples =\n-\t\t\tRKISP1_CIF_ISP_LSC_SAMPLES_MAX * RKISP1_CIF_ISP_LSC_SAMPLES_MAX;\n+\t\tset.r = parseTable(yamlSet, \"r\");\n+\t\tset.gr = parseTable(yamlSet, \"gr\");\n+\t\tset.gb = parseTable(yamlSet, \"gb\");\n+\t\tset.b = parseTable(yamlSet, \"b\");\n \n-\t\tstd::vector<uint16_t> table =\n-\t\t\ttuningData[prop].getList<uint16_t>().value_or(std::vector<uint16_t>{});\n-\t\tif (table.size() != kLscNumSamples) {\n+\t\tif (set.r.empty() || set.gr.empty() ||\n+\t\t    set.gb.empty() || set.b.empty()) {\n \t\t\tLOG(RkISP1Lsc, Error)\n-\t\t\t\t<< \"Invalid '\" << prop << \"' values: expected \"\n-\t\t\t\t<< kLscNumSamples\n-\t\t\t\t<< \" elements, got \" << table.size();\n-\t\t\treturn {};\n+\t\t\t\t<< \"Set for color temperature \" << ct\n+\t\t\t\t<< \" is missing tables\";\n+\t\t\treturn -EINVAL;\n \t\t}\n+\t}\n \n-\t\treturn table;\n+\tif (lscData.empty()) {\n+\t\tLOG(RkISP1Lsc, Error) << \"Failed to load any sets\";\n+\t\treturn -EINVAL;\n \t}\n-};\n+\n+\treturn 0;\n+}\n+\n+std::vector<uint16_t> LscTableLoader::parseTable(const YamlObject &tuningData,\n+\t\t\t\t\t\t const char *prop)\n+{\n+\tstatic constexpr unsigned int kLscNumSamples =\n+\t\tRKISP1_CIF_ISP_LSC_SAMPLES_MAX * RKISP1_CIF_ISP_LSC_SAMPLES_MAX;\n+\n+\tstd::vector<uint16_t> table =\n+\t\ttuningData[prop].getList<uint16_t>().value_or(std::vector<uint16_t>{});\n+\tif (table.size() != kLscNumSamples) {\n+\t\tLOG(RkISP1Lsc, Error)\n+\t\t\t<< \"Invalid '\" << prop << \"' values: expected \"\n+\t\t\t<< kLscNumSamples\n+\t\t\t<< \" elements, got \" << table.size();\n+\t\treturn {};\n+\t}\n+\n+\treturn table;\n+}\n \n static std::vector<double> parseSizes(const YamlObject &tuningData,\n \t\t\t\t      const char *prop)\n",
    "prefixes": [
        "v3",
        "07/15"
    ]
}