{"id":27067,"url":"https://patchwork.libcamera.org/api/patches/27067/?format=json","web_url":"https://patchwork.libcamera.org/patch/27067/","project":{"id":1,"url":"https://patchwork.libcamera.org/api/projects/1/?format=json","name":"libcamera","link_name":"libcamera","list_id":"libcamera_core","list_email":"libcamera-devel@lists.libcamera.org","web_url":"","scm_url":"","webscm_url":""},"msgid":"<20260626-ipu3-libipa-rework-v2-7-41546e23de3e@ideasonboard.com>","date":"2026-06-26T13:05:54","name":"[v2,07/12] ipa: ipu3: ToneMapping: Convert to use GammaAlgorithm","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"6193bff0632c6901b3b68bb85929a613e35c7a94","submitter":{"id":156,"url":"https://patchwork.libcamera.org/api/people/156/?format=json","name":"Dan Scally","email":"dan.scally@ideasonboard.com"},"delegate":null,"mbox":"https://patchwork.libcamera.org/patch/27067/mbox/","series":[{"id":6022,"url":"https://patchwork.libcamera.org/api/series/6022/?format=json","web_url":"https://patchwork.libcamera.org/project/libcamera/list/?series=6022","date":"2026-06-26T13:05:47","name":"libipa: Re-work IPU3 IPA to use libipa algorithms","version":2,"mbox":"https://patchwork.libcamera.org/series/6022/mbox/"}],"comments":"https://patchwork.libcamera.org/api/patches/27067/comments/","check":"pending","checks":"https://patchwork.libcamera.org/api/patches/27067/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 2683FC3306\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri, 26 Jun 2026 13:06:22 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id E9DD665F13;\n\tFri, 26 Jun 2026 15:06:15 +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 BDEF765EE7\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 26 Jun 2026 15:06:06 +0200 (CEST)","from [127.0.1.1]\n\t(chfd-03-b2-v4wan-176392-cust229.vm15.cable.virginm.net\n\t[82.19.20.230])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id C13AE1AE5;\n\tFri, 26 Jun 2026 15:05: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=\"EMMo9yl2\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1782479125;\n\tbh=MV1OudgVxwqKcw+PZWyvAFv5rAPA2Ey0KE5JXKGr7Os=;\n\th=From:Date:Subject:References:In-Reply-To:To:Cc:From;\n\tb=EMMo9yl2H4szF7oOGBEbJAWatIOJgI5OoNjD6ji9Tu2Ot1mgM24az32wbF6p9R8eH\n\toRV7ehQyROv7wZrT7velWu9ptDbSR9OlfBcVOQW66ObC541b9V+S9h3W7fMJZdKZ2O\n\tPO4g6q3GNPe64tFvm+tvopO8UEFOKL4PRFIdgR2Q=","From":"Daniel Scally <dan.scally@ideasonboard.com>","Date":"Fri, 26 Jun 2026 14:05:54 +0100","Subject":"[PATCH v2 07/12] ipa: ipu3: ToneMapping: Convert to use\n\tGammaAlgorithm","MIME-Version":"1.0","Content-Type":"text/plain; charset=\"utf-8\"","Content-Transfer-Encoding":"7bit","Message-Id":"<20260626-ipu3-libipa-rework-v2-7-41546e23de3e@ideasonboard.com>","References":"<20260626-ipu3-libipa-rework-v2-0-41546e23de3e@ideasonboard.com>","In-Reply-To":"<20260626-ipu3-libipa-rework-v2-0-41546e23de3e@ideasonboard.com>","To":"libcamera-devel@lists.libcamera.org","Cc":"Daniel Scally <dan.scally@ideasonboard.com>, \n\tJacopo Mondi <jacopo.mondi@ideasonboard.com>, \n\tKieran Bingham <kieran.bingham@ideasonboard.com>","X-Mailer":"b4 0.14.2","X-Developer-Signature":"v=1; a=openpgp-sha256; l=8593;\n\ti=dan.scally@ideasonboard.com; h=from:subject:message-id;\n\tbh=MV1OudgVxwqKcw+PZWyvAFv5rAPA2Ey0KE5JXKGr7Os=;\n\tb=owEBbQKS/ZANAwAKAchJV3psRXUyAcsmYgBqPnk62xG6GoNzv874hDnaI3WUNoRnQZZpoPcc5\n\tX+d3o6QHAyJAjMEAAEKAB0WIQQqyuwyDnZdb+mxmm/ISVd6bEV1MgUCaj55OgAKCRDISVd6bEV1\n\tMkBqD/441lIw/ISxUkps4lFW9fNmRwQ8pOUvU0rMLoFVn10kpKlA9hQ3CZTqPRYGGyvQqQUxy9J\n\tKdbSLZQWkHpi023zK/rv09oNgW16r7KGDBBLOGUOaRErhRS1zRhlZhhZgDCodeJ+FVbcQ8m085W\n\tcQ/B+C1VRNUUK0ZBVSfWKRwgkTyk/sPFWPOY3syoA9Qq3dKZPsizrLRlF15pWB9e4RHl+/MWVhq\n\tacac8/zhcj+4+KOh4LVbte/8Ud0zsOW70lGSoAjoGBlkMSvC/T2Co4PCt1i2ZPnjDDvKdZ3Smpj\n\tpeugQaoPPKTHN+zLu/Pl85DHA0ShZyrJ10omHgTNvjEa2CJtx81gMkYKbfF2BNvF7MtFr0MpHJP\n\tnsAjdVvodALZMJ5ebctPFHQ42eIvOd4ILsFoQeGOXpfT+wINV0mk/Nd7Xa/tsZk6ADrYEi5rgFO\n\tttcqEbQGLI5EVl/QwlPZeuCpzgOioA24WYUz8jVK55fYeerxbvZnQVYrZE9T974hMKug6MzoDGA\n\t2CgTWcHQ8qu7iggg3eGlZbAUgXMZS5oWgJRFCC/Fx6Z4e2zNp/YybzDz50TjFW2rb0+v6qaOo/y\n\t092cY24IvD2bI6jDAN5wcJ9bxAvS6Qbh+dJsQMFlZlyNey5BCbhxHwwdjGosl5yyE+EKd+cdClk\n\tvuBEYB44BQKHzUA==","X-Developer-Key":"i=dan.scally@ideasonboard.com; a=openpgp;\n\tfpr=EEC699ACA1B7CB5D31330C0BBD501C2A3546CCF6","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":"Convert the IPU3 ToneMapping algorithm to use the new GammaAlgorithm\nbase class. This gives us configurable gamma via the tuning files and\nat runtime using the Gamma control.\n\nReviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\nReviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\nSigned-off-by: Daniel Scally <dan.scally@ideasonboard.com>\n---\nChanges in v2:\n\n        - Fixed includes\n\t- Minor styling changes\n---\n src/ipa/ipu3/algorithms/tone_mapping.cpp | 73 +++++++++++++++++---------------\n src/ipa/ipu3/algorithms/tone_mapping.h   | 12 +++++-\n src/ipa/ipu3/ipa_context.cpp             | 24 +++++------\n src/ipa/ipu3/ipa_context.h               |  8 ++--\n 4 files changed, 63 insertions(+), 54 deletions(-)","diff":"diff --git a/src/ipa/ipu3/algorithms/tone_mapping.cpp b/src/ipa/ipu3/algorithms/tone_mapping.cpp\nindex 160338c139448cc9a0bc1fe2400c335a96f68f73..ea17abff8167238dfc5d65f6bb64754e8a7834ef 100644\n--- a/src/ipa/ipu3/algorithms/tone_mapping.cpp\n+++ b/src/ipa/ipu3/algorithms/tone_mapping.cpp\n@@ -10,6 +10,8 @@\n #include <cmath>\n #include <string.h>\n \n+#include <libcamera/base/span.h>\n+\n /**\n  * \\file tone_mapping.h\n  */\n@@ -27,10 +29,17 @@ namespace ipa::ipu3::algorithms {\n  */\n \n ToneMapping::ToneMapping()\n-\t: gamma_(1.0)\n {\n }\n \n+/**\n+ * \\copydoc libcamera::ipa::Algorithm::init\n+ */\n+int ToneMapping::init(IPAContext &context, const ValueNode &tuningData)\n+{\n+\treturn gammaAlgo_.init(context.ctrlMap, tuningData);\n+}\n+\n /**\n  * \\brief Configure the tone mapping given a configInfo\n  * \\param[in] context The shared IPA context\n@@ -41,12 +50,21 @@ ToneMapping::ToneMapping()\n int ToneMapping::configure(IPAContext &context,\n \t\t\t   [[maybe_unused]] const IPAConfigInfo &configInfo)\n {\n-\t/* Initialise tone mapping gamma value. */\n-\tcontext.activeState.toneMapping.gamma = 0.0;\n-\n+\tgammaAlgo_.configure(context.activeState.gamma);\n \treturn 0;\n }\n \n+/**\n+ * \\copydoc libcamera::ipa::Algorithm::queueRequest\n+ */\n+void ToneMapping::queueRequest(IPAContext &context, const uint32_t frame,\n+\t\t\t       IPAFrameContext &frameContext,\n+\t\t\t       const ControlList &controls)\n+{\n+\tgammaAlgo_.queueRequest(context.activeState.gamma, frame,\n+\t\t\t\tframeContext.gamma, controls);\n+}\n+\n /**\n  * \\brief Fill in the parameter structure, and enable gamma control\n  * \\param[in] context The shared IPA context\n@@ -59,14 +77,21 @@ int ToneMapping::configure(IPAContext &context,\n  */\n void ToneMapping::prepare([[maybe_unused]] IPAContext &context,\n \t\t\t  [[maybe_unused]] const uint32_t frame,\n-\t\t\t  [[maybe_unused]] IPAFrameContext &frameContext,\n+\t\t\t  IPAFrameContext &frameContext,\n \t\t\t  ipu3_uapi_params *params)\n {\n-\t/* Copy the calculated LUT into the parameters buffer. */\n-\tmemcpy(params->acc_param.gamma.gc_lut.lut,\n-\t       context.activeState.toneMapping.gammaCorrection.lut,\n-\t       IPU3_UAPI_GAMMA_CORR_LUT_ENTRIES *\n-\t       sizeof(params->acc_param.gamma.gc_lut.lut[0]));\n+\tif (!frameContext.gamma.update)\n+\t\treturn;\n+\n+\t/*\n+\t * Unfortunately necessary given the IPU3's gamma uAPI struct has the\n+\t * __packed attribute.\n+\t */\n+\tuint16_t *lutData = reinterpret_cast<uint16_t *>(\n+\t\t__builtin_assume_aligned(params->acc_param.gamma.gc_lut.lut, 16));\n+\tSpan<uint16_t> lut{ lutData, kNumLutNodes };\n+\n+\tgammaAlgo_.prepare(frameContext.gamma, lut);\n \n \t/* Enable the custom gamma table. */\n \tparams->use.acc_gamma = 1;\n@@ -84,33 +109,13 @@ void ToneMapping::prepare([[maybe_unused]] IPAContext &context,\n  * The tone mapping look up table is generated as an inverse power curve from\n  * our gamma setting.\n  */\n-void ToneMapping::process(IPAContext &context, [[maybe_unused]] const uint32_t frame,\n-\t\t\t  [[maybe_unused]] IPAFrameContext &frameContext,\n+void ToneMapping::process([[maybe_unused]] IPAContext &context,\n+\t\t\t  [[maybe_unused]] const uint32_t frame,\n+\t\t\t  IPAFrameContext &frameContext,\n \t\t\t  [[maybe_unused]] const ipu3_uapi_stats_3a *stats,\n \t\t\t  [[maybe_unused]] ControlList &metadata)\n {\n-\t/*\n-\t * Hardcode gamma to 1.1 as a default for now.\n-\t *\n-\t * \\todo Expose gamma control setting through the libcamera control API\n-\t */\n-\tgamma_ = 1.1;\n-\n-\tif (context.activeState.toneMapping.gamma == gamma_)\n-\t\treturn;\n-\n-\tstruct ipu3_uapi_gamma_corr_lut &lut =\n-\t\tcontext.activeState.toneMapping.gammaCorrection;\n-\n-\tfor (uint32_t i = 0; i < std::size(lut.lut); i++) {\n-\t\tdouble j = static_cast<double>(i) / (std::size(lut.lut) - 1);\n-\t\tdouble gamma = std::pow(j, 1.0 / gamma_);\n-\n-\t\t/* The output value is expressed on 13 bits. */\n-\t\tlut.lut[i] = gamma * 8191;\n-\t}\n-\n-\tcontext.activeState.toneMapping.gamma = gamma_;\n+\tgammaAlgo_.process(frameContext.gamma, metadata);\n }\n \n REGISTER_IPA_ALGORITHM(ToneMapping, \"ToneMapping\")\ndiff --git a/src/ipa/ipu3/algorithms/tone_mapping.h b/src/ipa/ipu3/algorithms/tone_mapping.h\nindex b2b380108e014b3d5ee7b93bcdd948dea4d2302d..3437b7fcbbb70c9bbc895b514b354d26c1d707c6 100644\n--- a/src/ipa/ipu3/algorithms/tone_mapping.h\n+++ b/src/ipa/ipu3/algorithms/tone_mapping.h\n@@ -7,6 +7,11 @@\n \n #pragma once\n \n+#include <linux/intel-ipu3.h>\n+\n+#include <libipa/fixedpoint.h>\n+#include <libipa/gamma.h>\n+\n #include \"algorithm.h\"\n \n namespace libcamera {\n@@ -18,7 +23,11 @@ class ToneMapping : public Algorithm\n public:\n \tToneMapping();\n \n+\tint init(IPAContext &context, const ValueNode &tuningData) override;\n \tint configure(IPAContext &context, const IPAConfigInfo &configInfo) override;\n+\tvoid queueRequest(IPAContext &context, const uint32_t frame,\n+\t\t\t  IPAFrameContext &frameContext,\n+\t\t\t  const ControlList &controls) override;\n \tvoid prepare(IPAContext &context, const uint32_t frame,\n \t\t     IPAFrameContext &frameContext, ipu3_uapi_params *params) override;\n \tvoid process(IPAContext &context, const uint32_t frame,\n@@ -27,7 +36,8 @@ public:\n \t\t     ControlList &metadata) override;\n \n private:\n-\tdouble gamma_;\n+\tstatic constexpr unsigned int kNumLutNodes = IPU3_UAPI_GAMMA_CORR_LUT_ENTRIES;\n+\tGammaAlgorithm<kNumLutNodes, UQ<0, 13>> gammaAlgo_;\n };\n \n } /* namespace ipa::ipu3::algorithms */\ndiff --git a/src/ipa/ipu3/ipa_context.cpp b/src/ipa/ipu3/ipa_context.cpp\nindex 469905a43c4300bfa7a7fee5777f4a51837cf4c6..d3bcd7a81fe010d17d1437bf7f6cedce83a9be5c 100644\n--- a/src/ipa/ipu3/ipa_context.cpp\n+++ b/src/ipa/ipu3/ipa_context.cpp\n@@ -119,6 +119,11 @@ namespace libcamera::ipa::ipu3 {\n  * \\brief Active colour Correction Matrix parameters for the IPA\n  */\n \n+/**\n+ * \\var IPAActiveState::gamma\n+ * \\brief Active gamma correction parameters for the IPA\n+ */\n+\n /**\n  * \\var IPASessionConfiguration::sensor\n  * \\brief Sensor-specific configuration of the IPA\n@@ -149,20 +154,6 @@ namespace libcamera::ipa::ipu3 {\n  * The gain should be adapted to the sensor specific gain code before applying.\n  */\n \n-/**\n- * \\var IPAActiveState::toneMapping\n- * \\brief Context for ToneMapping and Gamma control\n- *\n- * \\var IPAActiveState::toneMapping.gamma\n- * \\brief Gamma value for the LUT\n- *\n- * \\var IPAActiveState::toneMapping.gammaCorrection\n- * \\brief Per-pixel tone mapping implemented as a LUT\n- *\n- * The LUT structure is defined by the IPU3 kernel interface. See\n- * <linux/intel-ipu3.h> struct ipu3_uapi_gamma_corr_lut for further details.\n- */\n-\n /**\n  * \\struct IPAFrameContext\n  * \\brief IPU3-specific FrameContext\n@@ -187,4 +178,9 @@ namespace libcamera::ipa::ipu3 {\n  * \\brief Per-frame colour Correction Matrix parameters for the IPA\n  */\n \n+/**\n+ * \\var IPAFrameContext::gamma\n+ * \\brief Per-frame gamma correction parameters for the IPA\n+ */\n+\n } /* namespace libcamera::ipa::ipu3 */\ndiff --git a/src/ipa/ipu3/ipa_context.h b/src/ipa/ipu3/ipa_context.h\nindex 6445db2603645d804b6caa40cde65099c4e57511..ce496ed477f4cbe2653aedada3381258396d92c8 100644\n--- a/src/ipa/ipu3/ipa_context.h\n+++ b/src/ipa/ipu3/ipa_context.h\n@@ -18,6 +18,7 @@\n #include <libipa/awb.h>\n #include <libipa/ccm.h>\n #include <libipa/fc_queue.h>\n+#include <libipa/gamma.h>\n \n namespace libcamera {\n \n@@ -64,11 +65,7 @@ struct IPAActiveState {\n \n \tipa::awb::ActiveState awb;\n \tipa::ccm::ActiveState ccm;\n-\n-\tstruct {\n-\t\tdouble gamma;\n-\t\tstruct ipu3_uapi_gamma_corr_lut gammaCorrection;\n-\t} toneMapping;\n+\tipa::gamma::ActiveState gamma;\n };\n \n struct IPAFrameContext : public FrameContext {\n@@ -79,6 +76,7 @@ struct IPAFrameContext : public FrameContext {\n \n \tipa::awb::FrameContext awb;\n \tipa::ccm::FrameContext ccm;\n+\tipa::gamma::FrameContext gamma;\n };\n \n struct IPAContext {\n","prefixes":["v2","07/12"]}