{"id":26897,"url":"https://patchwork.libcamera.org/api/patches/26897/?format=json","web_url":"https://patchwork.libcamera.org/patch/26897/","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":"<20260616-ipu3-libipa-rework-v1-6-d4448b54f1d8@ideasonboard.com>","date":"2026-06-16T06:41:40","name":"[06/10] ipa: ipu3: ToneMapping: Convert to use GammaAlgorithm","commit_ref":null,"pull_url":null,"state":"superseded","archived":false,"hash":"d4f95c6a3bea237f90213257b1581cb00bb4792f","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/26897/mbox/","series":[{"id":5995,"url":"https://patchwork.libcamera.org/api/series/5995/?format=json","web_url":"https://patchwork.libcamera.org/project/libcamera/list/?series=5995","date":"2026-06-16T06:41:34","name":"libipa: Re-work IPU3 IPA to use libipa algorithms","version":1,"mbox":"https://patchwork.libcamera.org/series/5995/mbox/"}],"comments":"https://patchwork.libcamera.org/api/patches/26897/comments/","check":"pending","checks":"https://patchwork.libcamera.org/api/patches/26897/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 B7531C3302\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 16 Jun 2026 06:42:03 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 04BC9625BB;\n\tTue, 16 Jun 2026 08:41:57 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 1C73A623F5\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 16 Jun 2026 08:41:50 +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 D21F1166C;\n\tTue, 16 Jun 2026 08:41:16 +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=\"ZUfdUrd9\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1781592076;\n\tbh=sAflhLA91ZjuiM83DPI+H8xZ3xvJUxxNg+0tqw96N5M=;\n\th=From:Date:Subject:References:In-Reply-To:To:Cc:From;\n\tb=ZUfdUrd9oFWfUSr4MI91v6GdZCDN6ziOlm8x6yTRNDkHfKICw06pDc6TS9C3TxaQX\n\tI/hU8wKcybDMLdWIjJmNO0pW+hgkW/C2p7UAMSVoxtefqiAKyXiXcB6Ao6MLue7HHh\n\tnldDOAR80qqpSet+myYzqmUCsNuTPeJ3+R8g+QYY=","From":"Daniel Scally <dan.scally@ideasonboard.com>","Date":"Tue, 16 Jun 2026 07:41:40 +0100","Subject":"[PATCH 06/10] ipa: ipu3: ToneMapping: Convert to use GammaAlgorithm","MIME-Version":"1.0","Content-Type":"text/plain; charset=\"utf-8\"","Content-Transfer-Encoding":"7bit","Message-Id":"<20260616-ipu3-libipa-rework-v1-6-d4448b54f1d8@ideasonboard.com>","References":"<20260616-ipu3-libipa-rework-v1-0-d4448b54f1d8@ideasonboard.com>","In-Reply-To":"<20260616-ipu3-libipa-rework-v1-0-d4448b54f1d8@ideasonboard.com>","To":"libcamera-devel@lists.libcamera.org","Cc":"Daniel Scally <dan.scally@ideasonboard.com>","X-Mailer":"b4 0.14.2","X-Developer-Signature":"v=1; a=openpgp-sha256; l=8324;\n\ti=dan.scally@ideasonboard.com; h=from:subject:message-id;\n\tbh=sAflhLA91ZjuiM83DPI+H8xZ3xvJUxxNg+0tqw96N5M=;\n\tb=owEBbQKS/ZANAwAKAchJV3psRXUyAcsmYgBqMPAqlYyVaISm7jnN4T8x7D5FpCb1feWMutMc6\n\tLyakDfa1wKJAjMEAAEKAB0WIQQqyuwyDnZdb+mxmm/ISVd6bEV1MgUCajDwKgAKCRDISVd6bEV1\n\tMsJTEACzBdHozM3of4+7cgyMiKcNqtMN/VaaVWVEFBNoD5aKHXr+mD8lQUWY9aif1r2d9X/tfQ9\n\tgj1mZ2hgG3Xy7mktf2WsuWnXBBCby+geD5uss/oBhroTb44l86KYRE5PHwd38Dx+N92Byfzmjis\n\tJizN5VEoNFL2hrxq//tejm5PTPG3YTkp0E248as4hG5rHCIGVplHfKnkxX9Hp0d6mFORDvG6Drf\n\tQvYlOyPgoHokWsq4pEXIKJPGRqs1NMSqnnKkKlIOj0HIBLcJpxzU4gGnrRDSCoLmzStPxk9CpPT\n\tM/vyPvvgAJtzi2FvfdzAD6+tSt592mcdHbMYA3c6QTrVc5G96KEjfmEdn3NNbE6j/7jQu14NePB\n\tVlYw4AF/+R+y6rNZ8bb5/QV5o//gVG1G+RH6DCcYhkZ/GjAm/zZ6gkQX4IUftGH6ZrlMsEvgfXV\n\tUEbaa0fDshO6kQXRlsR/ZumnzgaMfM75H/ZhWaHtdPLT7sqIS0XNOStQWUiflKR6lQTljEMO0zz\n\towCie7q+eWopWaaWGj54LlX3aqiv/mT+t9CliUZxGCwxbXVQ1YCvnH2PPIecD9Q3bybV5OZ06G2\n\tdViyDO84SIU+i9qtdYacsfmqzZaSD/bNinpUHO1gEI5OzraI/s2KnxvHsvUh+JR3IUNo37y3q6o\n\t6lzD2W9Blc+PQvA==","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\nSigned-off-by: Daniel Scally <dan.scally@ideasonboard.com>\n---\n src/ipa/ipu3/algorithms/tone_mapping.cpp | 73 +++++++++++++++++---------------\n src/ipa/ipu3/algorithms/tone_mapping.h   |  9 +++-\n src/ipa/ipu3/ipa_context.cpp             | 24 +++++------\n src/ipa/ipu3/ipa_context.h               |  8 ++--\n 4 files changed, 60 insertions(+), 54 deletions(-)","diff":"diff --git a/src/ipa/ipu3/algorithms/tone_mapping.cpp b/src/ipa/ipu3/algorithms/tone_mapping.cpp\nindex 160338c139448cc9a0bc1fe2400c335a96f68f73..2bc29bb9124dd8bd327ca3064b52c55637f56e7b 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..db351a32b4383c4d607a2d6ee6a8fa3994a1d436 100644\n--- a/src/ipa/ipu3/algorithms/tone_mapping.h\n+++ b/src/ipa/ipu3/algorithms/tone_mapping.h\n@@ -7,6 +7,8 @@\n \n #pragma once\n \n+#include <libipa/gamma.h>\n+\n #include \"algorithm.h\"\n \n namespace libcamera {\n@@ -18,7 +20,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 +33,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 dc43bc0877ed5c2e7287414e12667374f5ee1c80..7152d070d3ab1bc463fdaad437d5e1c1b87ce25c 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@@ -154,20 +159,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@@ -192,4 +183,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 be626d30d966b1bdaa322e5154f95f745f799976..1eaaac82da0e3ad5bed0749c39d9dad8c585cab0 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@@ -66,11 +67,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@@ -81,6 +78,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":["06/10"]}