Show a patch.

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

{
    "id": 20296,
    "url": "https://patchwork.libcamera.org/api/patches/20296/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/20296/",
    "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": "<20240613132602.1021721-10-dan.scally@ideasonboard.com>",
    "date": "2024-06-13T13:26:01",
    "name": "[09/10] ipa: mali-c55: Add Lens Shading Correction algorithm",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": false,
    "hash": "0102548692d327ef0f95eca82d42a746faeb4086",
    "submitter": {
        "id": 156,
        "url": "https://patchwork.libcamera.org/api/people/156/?format=api",
        "name": "Dan Scally",
        "email": "dan.scally@ideasonboard.com"
    },
    "delegate": null,
    "mbox": "https://patchwork.libcamera.org/patch/20296/mbox/",
    "series": [
        {
            "id": 4388,
            "url": "https://patchwork.libcamera.org/api/series/4388/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=4388",
            "date": "2024-06-13T13:25:52",
            "name": "Add Mali-C55 IPA Module and Algorithms",
            "version": 1,
            "mbox": "https://patchwork.libcamera.org/series/4388/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/20296/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/20296/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 778D7C32CF\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu, 13 Jun 2024 13:26:50 +0000 (UTC)",
            "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id E03EC654A8;\n\tThu, 13 Jun 2024 15:26:45 +0200 (CEST)",
            "from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 7D2D0654A1\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 13 Jun 2024 15:26:31 +0200 (CEST)",
            "from mail.ideasonboard.com\n\t(cpc141996-chfd3-2-0-cust928.12-3.cable.virginm.net [86.13.91.161])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 44D46114D;\n\tThu, 13 Jun 2024 15:26:17 +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=\"MqH4aDgr\"; dkim-atps=neutral",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1718285177;\n\tbh=SW/Bc71D7wO94TAos07eWlZ7nOGhHqcoh8lJ+reYuS0=;\n\th=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n\tb=MqH4aDgrMjK42ZdAeGLzCKiWK5v+sC1KVwNsAtLgd7ooRjAkpLZqrbTTfphiwk6f0\n\tcdbrOwFxHvKRQNdq3y0NEJFcK+gCS3oMCL6gUL5wmiRsl2fIIm3L220eHAqPGW/ewC\n\tyl1HPQk64PEN6Mg2sYdF9X+2X+JH73LKxqpx8Ak4=",
        "From": "Daniel Scally <dan.scally@ideasonboard.com>",
        "To": "libcamera-devel@lists.libcamera.org",
        "Cc": "dan.scally@ideasonboard.com, nayden.kanchev@arm.com,\n\tjacopo.mondi@ideasonboard.com",
        "Subject": "[PATCH 09/10] ipa: mali-c55: Add Lens Shading Correction algorithm",
        "Date": "Thu, 13 Jun 2024 14:26:01 +0100",
        "Message-Id": "<20240613132602.1021721-10-dan.scally@ideasonboard.com>",
        "X-Mailer": "git-send-email 2.34.1",
        "In-Reply-To": "<20240613132602.1021721-1-dan.scally@ideasonboard.com>",
        "References": "<20240613132602.1021721-1-dan.scally@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": "Add a lens shading correction algorithm to the mali-c55 IPA. This\nalgorithm parses tables from Yaml in a easy to follow format before\nmunging them into Arm's interleaved mesh to be copied to the ISP.\nA colour temperature estimate from the AGC statistics is used to\nselect the appropriate table to apply; this can be some interpolation\nof two tables, in which case the colour temperature estimate is also\nused to derive the coefficient that does the blending.\n\nAcked-by: Nayden Kanchev <nayden.kanchev@arm.com>\nCo-developed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\nSigned-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\nSigned-off-by: Daniel Scally <dan.scally@ideasonboard.com>\n---\n src/ipa/mali-c55/algorithms/lsc.cpp     | 218 ++++++++++++++++++++++++\n src/ipa/mali-c55/algorithms/lsc.h       |  45 +++++\n src/ipa/mali-c55/algorithms/meson.build |   1 +\n 3 files changed, 264 insertions(+)\n create mode 100644 src/ipa/mali-c55/algorithms/lsc.cpp\n create mode 100644 src/ipa/mali-c55/algorithms/lsc.h",
    "diff": "diff --git a/src/ipa/mali-c55/algorithms/lsc.cpp b/src/ipa/mali-c55/algorithms/lsc.cpp\nnew file mode 100644\nindex 00000000..4b4a4c6e\n--- /dev/null\n+++ b/src/ipa/mali-c55/algorithms/lsc.cpp\n@@ -0,0 +1,218 @@\n+/* SPDX-License-Identifier: LGPL-2.1-or-later */\n+/*\n+ * Copyright (C) 2024, Ideas On Board Oy\n+ *\n+ * lsc.cpp - Mali-C55 Lens shading correction algorithm\n+ */\n+\n+#include \"lsc.h\"\n+\n+#include \"libcamera/internal/yaml_parser.h\"\n+\n+namespace libcamera {\n+\n+namespace ipa::mali_c55::algorithms {\n+\n+LOG_DEFINE_CATEGORY(MaliC55Lsc)\n+\n+Lsc::Lsc()\n+{\n+}\n+\n+int Lsc::init([[maybe_unused]] IPAContext &context, const YamlObject &tuningData)\n+{\n+\tif (!tuningData.contains(\"meshScale\")) {\n+\t\tLOG(MaliC55Lsc, Error) << \"meshScale missing from tuningData\";\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tmeshScale_ = tuningData[\"meshScale\"].get<uint32_t>(0);\n+\n+\tconst YamlObject &yamlSets = tuningData[\"sets\"];\n+\tif (!yamlSets.isList()) {\n+\t\tLOG(MaliC55Lsc, Error) << \"LSC tables missing or invalid\";\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tsize_t tableSize = 0;\n+\tconst auto &sets = yamlSets.asList();\n+\tfor (const auto &yamlSet : sets) {\n+\t\tuint32_t ct = yamlSet[\"ct\"].get<uint32_t>(0);\n+\n+\t\tif (!ct) {\n+\t\t\tLOG(MaliC55Lsc, Error) << \"Invalid colour temperature\";\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\n+\t\tif (std::count(colourTemperatures_.begin(),\n+\t\t\t       colourTemperatures_.end(), ct)) {\n+\t\t\tLOG(MaliC55Lsc, Error)\n+\t\t\t\t<< \"Multiple sets found for colour temperature\";\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\n+\t\tstd::vector<uint8_t> rTable =\n+\t\t\tyamlSet[\"r\"].getList<uint8_t>().value_or(std::vector<uint8_t>{});\n+\t\tstd::vector<uint8_t> gTable =\n+\t\t\tyamlSet[\"g\"].getList<uint8_t>().value_or(std::vector<uint8_t>{});\n+\t\tstd::vector<uint8_t> bTable =\n+\t\t\tyamlSet[\"b\"].getList<uint8_t>().value_or(std::vector<uint8_t>{});\n+\n+\t\t/*\n+\t\t * Some validation to do; only 16x16 and 32x32 tables of\n+\t\t * coefficients are acceptable, and all tables across all of the\n+\t\t * sets must be the same size. The first time we encounter a\n+\t\t * table we check that it is an acceptable size and if so make\n+\t\t * sure all other tables are of equal size.\n+\t\t */\n+\t\tif (!tableSize) {\n+\t\t\tif (rTable.size() != 256 && rTable.size() != 1024) {\n+\t\t\t\tLOG(MaliC55Lsc, Error)\n+\t\t\t\t\t<< \"Invalid table size for colour temperature \" << ct;\n+\t\t\t\treturn -EINVAL;\n+\t\t\t}\n+\t\t\ttableSize = rTable.size();\n+\t\t}\n+\n+\t\tif (rTable.size() != tableSize ||\n+\t\t    gTable.size() != tableSize ||\n+\t\t    bTable.size() != tableSize) {\n+\t\t\tLOG(MaliC55Lsc, Error)\n+\t\t\t\t<< \"Invalid or mismatched table size for colour temperature \" << ct;\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\n+\t\tif (colourTemperatures_.size() >= 3) {\n+\t\t\tLOG(MaliC55Lsc, Error)\n+\t\t\t\t<< \"A maximum of 3 colour temperatures are supported\";\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\n+\t\tfor (unsigned int i = 0; i < tableSize; i++) {\n+\t\t\tmesh_[kRedOffset + i] |=\n+\t\t\t\t(rTable[i] << (colourTemperatures_.size() * 8));\n+\t\t\tmesh_[kGreenOffset + i] |=\n+\t\t\t\t(gTable[i] << (colourTemperatures_.size() * 8));\n+\t\t\tmesh_[kBlueOffset + i] |=\n+\t\t\t\t(bTable[i] << (colourTemperatures_.size() * 8));\n+\t\t}\n+\n+\t\tcolourTemperatures_.push_back(ct);\n+\t}\n+\n+\tif (tableSize == 256)\n+\t\tmeshSize_ = 15;\n+\telse\n+\t\tmeshSize_ = 31;\n+\n+\treturn 0;\n+}\n+\n+void Lsc::fillConfigParamsBlock(mali_c55_params_block_header *block) const\n+{\n+\tstruct mali_c55_params_mesh_shading_config *config =\n+\t\treinterpret_cast<struct mali_c55_params_mesh_shading_config *>(block);\n+\n+\tconfig->header.type = MALI_C55_PARAM_MESH_SHADING_CONFIG;\n+\tconfig->header.enabled = true;\n+\tconfig->header.size = sizeof(struct mali_c55_params_mesh_shading_config);\n+\n+\tconfig->mesh_show = false;\n+\tconfig->mesh_scale = meshScale_;\n+\tconfig->mesh_page_r = 0;\n+\tconfig->mesh_page_g = 1;\n+\tconfig->mesh_page_b = 2;\n+\tconfig->mesh_width = meshSize_;\n+\tconfig->mesh_height = meshSize_;\n+\n+\tstd::copy(mesh_.begin(), mesh_.end(), config->mesh);\n+}\n+\n+void Lsc::fillSelectionParamsBlock(mali_c55_params_block_header *block,\n+\t\t\t\t   uint8_t bank, uint8_t alpha) const\n+{\n+\tstruct mali_c55_params_mesh_shading_selection *config =\n+\t\treinterpret_cast<struct mali_c55_params_mesh_shading_selection *>(block);\n+\n+\tconfig->header.type = MALI_C55_PARAM_MESH_SHADING_SELECTION;\n+\tconfig->header.enabled = true;\n+\tconfig->header.size = sizeof(struct mali_c55_params_mesh_shading_selection);\n+\n+\tconfig->mesh_alpha_bank_r = bank;\n+\tconfig->mesh_alpha_bank_g = bank;\n+\tconfig->mesh_alpha_bank_b = bank;\n+\tconfig->mesh_alpha_r = alpha;\n+\tconfig->mesh_alpha_g = alpha;\n+\tconfig->mesh_alpha_b = alpha;\n+\tconfig->mesh_strength = 0x1000; /* Otherwise known as 1.0 */\n+}\n+\n+std::tuple<uint8_t, uint8_t> Lsc::findBankAndAlpha(uint32_t ct) const\n+{\n+\tunsigned int i;\n+\n+\tct = std::clamp<uint32_t>(ct, colourTemperatures_.front(),\n+\t\t\t\t  colourTemperatures_.back());\n+\n+\tfor (i = 0; i < colourTemperatures_.size() - 1; i++) {\n+\t\tif (ct >= colourTemperatures_[i] &&\n+\t\t    ct <= colourTemperatures_[i + 1])\n+\t\t\tbreak;\n+\t}\n+\n+\t/*\n+\t * With the clamping, we're guaranteed an index into colourTemperatures_\n+\t * that's <= colourTemperatures_.size() - 1.\n+\t */\n+\tuint8_t alpha = (255 * (ct - colourTemperatures_[i])) /\n+\t\t\t(colourTemperatures_[i + 1] - colourTemperatures_[i]);\n+\n+\treturn { i, alpha };\n+}\n+\n+void Lsc::prepare(IPAContext &context, [[maybe_unused]] const uint32_t frame,\n+\t\t  [[maybe_unused]] IPAFrameContext &frameContext,\n+\t\t  mali_c55_params_block_header *block)\n+{\n+\t/*\n+\t * For each frame we assess the colour temperature of the **last** frame\n+\t * and then select an appropriately blended table of coefficients based\n+\t * on that ct. As a bit of a shortcut, if we've only a single table the\n+\t * handling is somewhat simpler; if it's the first frame we just select\n+\t * that table and if we're past the first frame then we can just do\n+\t * nothing - the config will never change.\n+\t */\n+\tuint32_t temperatureK = context.activeState.agc.temperatureK;\n+\tuint8_t bank, alpha;\n+\n+\tif (colourTemperatures_.size() == 1) {\n+\t\tif (frame > 0)\n+\t\t\treturn;\n+\n+\t\tbank = 0;\n+\t\talpha = 0;\n+\t} else {\n+\t\tstd::tie(bank, alpha) = findBankAndAlpha(temperatureK);\n+\t}\n+\n+\tfillSelectionParamsBlock(block, bank, alpha);\n+\n+\tif (frame > 0)\n+\t\treturn;\n+\n+\tchar *params = reinterpret_cast<char *>(block);\n+\tblock = reinterpret_cast<mali_c55_params_block_header *>\n+\t\t(params + sizeof(struct mali_c55_params_mesh_shading_selection));\n+\n+\t/*\n+\t * If this is the first frame, we need to load the parsed coefficient\n+\t * tables from tuning data to the ISP.\n+\t */\n+\tfillConfigParamsBlock(block);\n+}\n+\n+REGISTER_IPA_ALGORITHM(Lsc, \"Lsc\")\n+\n+} /* namespace ipa::mali_c55::algorithms */\n+\n+} /* namespace libcamera */\ndiff --git a/src/ipa/mali-c55/algorithms/lsc.h b/src/ipa/mali-c55/algorithms/lsc.h\nnew file mode 100644\nindex 00000000..9a47c5ab\n--- /dev/null\n+++ b/src/ipa/mali-c55/algorithms/lsc.h\n@@ -0,0 +1,45 @@\n+/* SPDX-License-Identifier: LGPL-2.1-or-later */\n+/*\n+ * Copyright (C) 2024, Ideas On Board Oy\n+ *\n+ * lsc.h - Mali-C55 Lens shading correction algorithm\n+ */\n+\n+#include <map>\n+#include <tuple>\n+\n+#include \"algorithm.h\"\n+\n+namespace libcamera {\n+\n+namespace ipa::mali_c55::algorithms {\n+\n+class Lsc : public Algorithm\n+{\n+public:\n+\tLsc();\n+\t~Lsc() = default;\n+\n+\tint init(IPAContext &context, const YamlObject &tuningData) override;\n+\tvoid prepare(IPAContext &context, const uint32_t frame,\n+\t\t     IPAFrameContext &frameContext,\n+\t\t     mali_c55_params_block_header *block) override;\n+private:\n+\tstatic constexpr unsigned int kRedOffset = 0;\n+\tstatic constexpr unsigned int kGreenOffset = 1024;\n+\tstatic constexpr unsigned int kBlueOffset = 2048;\n+\n+\tvoid fillConfigParamsBlock(mali_c55_params_block_header *block) const;\n+\tvoid fillSelectionParamsBlock(mali_c55_params_block_header *block,\n+\t\t\t\t      uint8_t bank, uint8_t alpha) const;\n+\tstd::tuple<uint8_t, uint8_t> findBankAndAlpha(uint32_t ct) const;\n+\n+\tstd::vector<uint32_t> mesh_ = std::vector<uint32_t>(3072);\n+\tstd::vector<uint32_t> colourTemperatures_;\n+\tuint32_t meshScale_;\n+\tuint32_t meshSize_;\n+};\n+\n+} /* namespace ipa::mali_c55::algorithms */\n+\n+} /* namespace libcamera */\ndiff --git a/src/ipa/mali-c55/algorithms/meson.build b/src/ipa/mali-c55/algorithms/meson.build\nindex f11791aa..1665da07 100644\n--- a/src/ipa/mali-c55/algorithms/meson.build\n+++ b/src/ipa/mali-c55/algorithms/meson.build\n@@ -4,4 +4,5 @@ mali_c55_ipa_algorithms = files([\n     'agc.cpp',\n     'awb.cpp',\n     'blc.cpp',\n+    'lsc.cpp',\n ])\n",
    "prefixes": [
        "09/10"
    ]
}