Patch Detail
Show a patch.
GET /api/patches/27652/?format=api
{ "id": 27652, "url": "https://patchwork.libcamera.org/api/patches/27652/?format=api", "web_url": "https://patchwork.libcamera.org/patch/27652/", "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": "<20260805-libipa-algorithms-v7-27-7425b5b795d4@ideasonboard.com>", "date": "2026-08-05T16:13:09", "name": "[v7,27/32] ipa: libipa: lsc: Quantize gains in IPA", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "b6f0619ebad12505b4a694b80762e5b771223daa", "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/27652/mbox/", "series": [ { "id": 6110, "url": "https://patchwork.libcamera.org/api/series/6110/?format=api", "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=6110", "date": "2026-08-05T16:12:42", "name": "ipa: libipa: Introduce libipa algorithms", "version": 7, "mbox": "https://patchwork.libcamera.org/series/6110/mbox/" } ], "comments": "https://patchwork.libcamera.org/api/patches/27652/comments/", "check": "pending", "checks": "https://patchwork.libcamera.org/api/patches/27652/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 87C5CC334D\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 5 Aug 2026 16:14:01 +0000 (UTC)", "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 140706816D;\n\tWed, 5 Aug 2026 18:14:01 +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 4C61E68163\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 5 Aug 2026 18:13:42 +0200 (CEST)", "from [192.168.125.177] (mob-109-113-25-35.net.vodafone.it\n\t[109.113.25.35])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 88C4B981;\n\tWed, 5 Aug 2026 18:12:31 +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=\"KYDKyGBA\"; dkim-atps=neutral", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1785946351;\n\tbh=vDonS8TQg8+qGGtDqSm4kxg7JZ/OvVkZjmA0BUQhIOs=;\n\th=From:Date:Subject:References:In-Reply-To:To:Cc:From;\n\tb=KYDKyGBAl70pEvS31HZBJmCtNqL0sRubx3GR/VDK5p+zzvCvW5W2qnZzp0Wr1mWFJ\n\tXPgkCPZaDdD1MUKdg6qpwy/aQbwyIyVrXG7+KKmI3T5SDJbJ5jkm+LGKoxlqYJSUWZ\n\tErtR6nwbVIYQ0P9WBA0h3SlNQ6UeqalhGsBqcqws=", "From": "Jacopo Mondi <jacopo.mondi@ideasonboard.com>", "Date": "Wed, 05 Aug 2026 18:13:09 +0200", "Subject": "[PATCH v7 27/32] ipa: libipa: lsc: Quantize gains in IPA", "MIME-Version": "1.0", "Content-Type": "text/plain; charset=\"utf-8\"", "Content-Transfer-Encoding": "7bit", "Message-Id": "<20260805-libipa-algorithms-v7-27-7425b5b795d4@ideasonboard.com>", "References": "<20260805-libipa-algorithms-v7-0-7425b5b795d4@ideasonboard.com>", "In-Reply-To": "<20260805-libipa-algorithms-v7-0-7425b5b795d4@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.16-dev", "X-Developer-Signature": "v=1; a=openpgp-sha256; l=7176;\n\ti=jacopo.mondi@ideasonboard.com; h=from:subject:message-id;\n\tbh=vDonS8TQg8+qGGtDqSm4kxg7JZ/OvVkZjmA0BUQhIOs=;\n\tb=owEBbQKS/ZANAwAKAXI0Bo8WoVY8AcsmYgBqc2EiZ1l3BVAans4LNGssd6KgWb1lspup9Sv3j\n\tg2lhWWXZ0GJAjMEAAEKAB0WIQS1xD1IgJogio9YOMByNAaPFqFWPAUCanNhIgAKCRByNAaPFqFW\n\tPAKvD/9f+X0r1VKpnuXVzfWJY5Ubgr4G5Ez1rKKOalN8SJgxL0ZmCPwYHAKTKsoL4/yUQdWkmRE\n\tNx2TJMTCM/nHmK9GYpOowQMLt6dh8DiEMoDR3X8lsjlyrSui11J8dTuKSkZaZ8uumQ0mjXMMefJ\n\t8CTT5Tw4e6m4gHR+w4FpVX65VSpl3oIUUChZzPLbyqRwX7UsyFFEQIQXtBVo3WvNRGOL/fIbHUF\n\tAsO6ZCCqyPXm6j92cPEGvJbRXKoUbWj34YjjKq9902qmvg2GuiKXVcfoWZKmlPMf8f70r6ZzUR3\n\tCbztqLBnsm9vlCMDogSy1W/PwdzHUod5x11T+SVikcIH4YcpU0sX05WfGerdCpw1DEh1uU1PlGy\n\t7rIfG/a7CZg9XW1iTJjFl4ZccvcyNlsQzL/b1L7a+GOCd+iokB8unA6STv579K3vrWeZqPSxLsS\n\tm2O+41YbBo6jwsJ1+QRlz+Gdu/e+3rFRhDAH7FjahqthDw6vLBFLIMZs3Iz/u7w4NMoEkNtKrEB\n\tAAzqjgntsajGzOnZvFx63kLDbX750gyHAHZhWsjuagNmXTi16RZsg5j+LUo37PMoXUjWB3vRuFM\n\t/WcyQdrxtYE7lKw4pG7f92xZQFR8DqMnrGBZjiSNvIX3qMMTMOKDaVqjX7zw9gayf+ig4NMpqeg\n\tzRBDfamU+1fSisQ==", "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 libIPA Lsc algorithm currently assumes the register format of\nthe RkISP1 platform (16 bits Q2.10 format), as that's where the\nimplementation has been derived from.\n\nMake lsc::Components use floats as the default exchange type between the\nLscAlgorithm and the IPA module and move the gains quantization to the\nplaltform IPA module.\n\nSigned-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\n---\n src/ipa/libipa/lsc_base.h | 2 +-\n src/ipa/libipa/lsc_polynomial.cpp | 17 +++++------------\n src/ipa/libipa/lsc_polynomial.h | 8 ++++----\n src/ipa/libipa/lsc_table.cpp | 22 ++++++++++++++++------\n src/ipa/libipa/lsc_table.h | 2 +-\n src/ipa/rkisp1/algorithms/lsc.cpp | 23 +++++++++++++++--------\n 6 files changed, 42 insertions(+), 32 deletions(-)", "diff": "diff --git a/src/ipa/libipa/lsc_base.h b/src/ipa/libipa/lsc_base.h\nindex 4ad754b3727a..2cff34b32a2b 100644\n--- a/src/ipa/libipa/lsc_base.h\n+++ b/src/ipa/libipa/lsc_base.h\n@@ -26,7 +26,7 @@ namespace ipa {\n \n namespace lsc {\n \n-using Components = std::map<std::string, std::vector<uint16_t>, std::less<>>;\n+using Components = std::map<std::string, std::vector<float>, std::less<>>;\n using ComponentsMap = std::map<unsigned int, Components>;\n \n } /* namespace lsc */\ndiff --git a/src/ipa/libipa/lsc_polynomial.cpp b/src/ipa/libipa/lsc_polynomial.cpp\nindex 0eb017de6b50..419de2c12cf0 100644\n--- a/src/ipa/libipa/lsc_polynomial.cpp\n+++ b/src/ipa/libipa/lsc_polynomial.cpp\n@@ -212,7 +212,7 @@ LscPolynomial::sampleForCrop(const Rectangle &cropRectangle,\n \treturn components;\n }\n \n-std::vector<uint16_t>\n+std::vector<float>\n LscPolynomial::samplePolynomial(const lsc::Polynomial &poly,\n \t\t\t\tSpan<const double> xPositions,\n \t\t\t\tSpan<const double> yPositions,\n@@ -223,7 +223,7 @@ LscPolynomial::samplePolynomial(const lsc::Polynomial &poly,\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+\tstd::vector<float> samples;\n \n \tsamples.reserve(xPositions.size() * yPositions.size());\n \n@@ -231,16 +231,9 @@ LscPolynomial::samplePolynomial(const lsc::Polynomial &poly,\n \t\tfor (double x : xPositions) {\n \t\t\tdouble xp = x0 + x * w;\n \t\t\tdouble yp = y0 + 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::clamp(v, 1024, 4095);\n-\t\t\tsamples.push_back(v);\n+\n+\t\t\tsamples.push_back(static_cast<float>\n+\t\t\t\t\t (poly.sampleAtNormalizedPixelPos(xp, yp)));\n \t\t}\n \t}\n \treturn samples;\ndiff --git a/src/ipa/libipa/lsc_polynomial.h b/src/ipa/libipa/lsc_polynomial.h\nindex 548ed94b2461..24b216a1aa25 100644\n--- a/src/ipa/libipa/lsc_polynomial.h\n+++ b/src/ipa/libipa/lsc_polynomial.h\n@@ -65,10 +65,10 @@ public:\n \t\t std::vector<double> xPos, std::vector<double> yPos) override;\n \n private:\n-\tstd::vector<uint16_t> samplePolynomial(const lsc::Polynomial &poly,\n-\t\t\t\t\t Span<const double> xPositions,\n-\t\t\t\t\t Span<const double> yPositions,\n-\t\t\t\t\t const Rectangle &cropRectangle);\n+\tstd::vector<float> samplePolynomial(const lsc::Polynomial &poly,\n+\t\t\t\t\t Span<const double> xPositions,\n+\t\t\t\t\t Span<const double> yPositions,\n+\t\t\t\t\t const Rectangle &cropRectangle);\n \tPolynomialComponentsMap lscData_;\n };\n \ndiff --git a/src/ipa/libipa/lsc_table.cpp b/src/ipa/libipa/lsc_table.cpp\nindex 639f4f6aa8b0..3e8b1a060ce7 100644\n--- a/src/ipa/libipa/lsc_table.cpp\n+++ b/src/ipa/libipa/lsc_table.cpp\n@@ -30,6 +30,11 @@ namespace ipa {\n *\n * Parse the LSC data in tabular form from the \\a sets tuning data.\n *\n+ * \\todo Currently the gain values parsed from tuning file are expressed in the\n+ * platform fixed-point register format. Use gains in floating point\n+ * representation for tabular LSC data in order to facilitate re-use of LSC\n+ * tuning data across different platforms.\n+ *\n * \\return 0 on success or a negative error number otherwise\n */\n int LscTable::parseLscData(const ValueNode &sets,\n@@ -82,15 +87,20 @@ int LscTable::parseLscComponent(const ValueNode &yamlSet,\n \treturn 0;\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 unsigned int numHSamples,\n-\t\t\t\t\t unsigned int numVSamples)\n+std::vector<float> LscTable::parseTable(const ValueNode &tuningData,\n+\t\t\t\t\tconst char *prop,\n+\t\t\t\t\tunsigned int numHSamples,\n+\t\t\t\t\tunsigned int numVSamples)\n {\n \tunsigned int lscNumSamples = numHSamples * numVSamples;\n \n-\tstd::vector<uint16_t> table =\n-\t\ttuningData[prop].get<std::vector<uint16_t>>().value_or(utils::defopt);\n+\t/*\n+\t * Cast to float even if gains are expressed as fixed-point\n+\t * representations. This prepares to express gains in floating point\n+\t * formats in tuning files.\n+\t */\n+\tstd::vector<float> table =\n+\t\ttuningData[prop].get<std::vector<float>>().value_or(utils::defopt);\n \tif (table.size() != lscNumSamples) {\n \t\tLOG(LscTable, Error)\n \t\t\t<< \"Invalid '\" << prop << \"' values: expected \"\ndiff --git a/src/ipa/libipa/lsc_table.h b/src/ipa/libipa/lsc_table.h\nindex a33208761c15..6d9b0c692b7f 100644\n--- a/src/ipa/libipa/lsc_table.h\n+++ b/src/ipa/libipa/lsc_table.h\n@@ -42,7 +42,7 @@ public:\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+\tstd::vector<float> parseTable(const ValueNode &tuningData,\n \t\t\t\t\t const char *prop,\n \t\t\t\t\t unsigned int numHSamples,\n \t\t\t\t\t unsigned int numVSamples);\ndiff --git a/src/ipa/rkisp1/algorithms/lsc.cpp b/src/ipa/rkisp1/algorithms/lsc.cpp\nindex 7a95bfcfb93a..911ac6895a14 100644\n--- a/src/ipa/rkisp1/algorithms/lsc.cpp\n+++ b/src/ipa/rkisp1/algorithms/lsc.cpp\n@@ -177,14 +177,21 @@ 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-\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+\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+\tconst auto quantizeSet = [&](const std::string &key, uint16_t *dst) {\n+\t\tconst auto &s = set.at(key);\n+\t\tstd::transform(s.begin(), s.end(), dst, [](float f) {\n+\t\t\t\treturn std::clamp<uint16_t>(f * 1024, 1024, 4095);\n+\t\t\t\t});\n+\t};\n+\n+\tquantizeSet(\"r\", &config.r_data_tbl[0][0]);\n+\tquantizeSet(\"gr\", &config.gr_data_tbl[0][0]);\n+\tquantizeSet(\"gb\", &config.gb_data_tbl[0][0]);\n+\tquantizeSet(\"b\", &config.b_data_tbl[0][0]);\n }\n \n /**\n", "prefixes": [ "v7", "27/32" ] }