[{"id":37800,"web_url":"https://patchwork.libcamera.org/comment/37800/","msgid":"<9dca90ab-1da3-4710-a0f4-bd4c187111dd@ideasonboard.com>","date":"2026-01-21T15:21:13","subject":"Re: [PATCH v3 13/14] libcamera: ipa: simple: Remove Lut algorithm","submitter":{"id":216,"url":"https://patchwork.libcamera.org/api/people/216/","name":"Barnabás Pőcze","email":"barnabas.pocze@ideasonboard.com"},"content":"Hi\n\n\n2026. 01. 14. 12:30 keltezéssel, Milan Zamazal írta:\n> The Lut algorithm is not really an algorithm.  Moreover, algorithms may\n> be enabled or disabled but with Lut disabled, nothing will work.\n> \n> Let's move the construction of lookup tables to CPU debayering, where it\n> is used.  The implied and related changes are:\n> \n> - DebayerParams is changed to contain the real params rather than lookup\n>    tables.\n> - contrastExp parameter introduced by GPU ISP is used for CPU ISP too.\n> - The params must be initialised so that debayering gets meaningful\n>    parameter values even when some algorithms are disabled.\n> - combinedMatrix must be put to params everywhere where it is modified.\n> - Matrix changes needn't be tracked in the algorithms any more.\n> - CPU debayering must watch for changes of the corresponding parameters\n>    to update the lookup tables when and only when needed.\n> - Swapping red and blue is integrated into lookup table constructions.\n> \n> Signed-off-by: Milan Zamazal <mzamazal@redhat.com>\n> ---\n>   .../internal/software_isp/debayer_params.h    |  43 +----\n>   src/ipa/simple/algorithms/adjust.cpp          |  20 +-\n>   src/ipa/simple/algorithms/adjust.h            |   2 -\n>   src/ipa/simple/algorithms/awb.cpp             |   7 +-\n>   src/ipa/simple/algorithms/ccm.cpp             |   4 +-\n>   src/ipa/simple/algorithms/lut.cpp             | 141 --------------\n>   src/ipa/simple/algorithms/lut.h               |  35 ----\n>   src/ipa/simple/algorithms/meson.build         |   1 -\n>   src/ipa/simple/data/uncalibrated.yaml         |   1 -\n>   src/ipa/simple/ipa_context.h                  |  10 -\n>   src/ipa/simple/soft_simple.cpp                |  10 +-\n>   src/libcamera/software_isp/debayer.cpp        | 172 +-----------------\n>   src/libcamera/software_isp/debayer.h          |   8 -\n>   src/libcamera/software_isp/debayer_cpu.cpp    | 141 ++++++++++++--\n>   src/libcamera/software_isp/debayer_cpu.h      |  26 ++-\n>   src/libcamera/software_isp/debayer_egl.cpp    |  22 +--\n>   src/libcamera/software_isp/software_isp.cpp   |  17 --\n>   17 files changed, 195 insertions(+), 465 deletions(-)\n>   delete mode 100644 src/ipa/simple/algorithms/lut.cpp\n>   delete mode 100644 src/ipa/simple/algorithms/lut.h\n> \n> [...]\n> diff --git a/src/ipa/simple/algorithms/lut.cpp b/src/ipa/simple/algorithms/lut.cpp\n> deleted file mode 100644\n> index f31a7e631..000000000\n> --- a/src/ipa/simple/algorithms/lut.cpp\n> +++ /dev/null\n> @@ -1,141 +0,0 @@\n> -/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> -/*\n> - * Copyright (C) 2024-2026, Red Hat Inc.\n> - *\n> - * Color lookup tables construction\n> - */\n> -\n> -#include \"lut.h\"\n> -\n> -#include <algorithm>\n> -#include <cmath>\n> -#include <optional>\n> -#include <stdint.h>\n> -\n> -#include <libcamera/base/log.h>\n> -\n> -#include <libcamera/control_ids.h>\n> -\n> -#include \"simple/ipa_context.h\"\n> -\n> -#include \"adjust.h\"\n> -\n> -namespace libcamera {\n> -\n> -LOG_DEFINE_CATEGORY(IPASoftLut)\n> -\n> -namespace ipa::soft::algorithms {\n> -\n> -int Lut::configure(IPAContext &context,\n> -\t\t   [[maybe_unused]] const IPAConfigInfo &configInfo)\n> -{\n> -\tupdateGammaTable(context);\n> -\n> -\treturn 0;\n> -}\n> -\n> -void Lut::updateGammaTable(IPAContext &context)\n> -{\n> -\tconst auto blackLevel = context.activeState.blc.level;\n> -\tconst auto gamma =\n> -\t\t1.0 / context.activeState.knobs.gamma.value_or(kDefaultGamma);\n> -\tconst auto contrast = context.activeState.knobs.contrast.value_or(1.0);\n> -\t/* Convert 0..2 to 0..infinity; avoid actual inifinity at tan(pi/2) */\n> -\tfloat contrastExp = tan(std::clamp(contrast * M_PI_4, 0.0, M_PI_2 - 0.00001));\n> -\n> -\tif (!context.gpuIspEnabled) {\n\nCan `gpuIspEnabled` be removed altogether from `soft.mojom`, etc?\n\n\n\n> -\t\tauto &gammaTable = context.activeState.gamma.gammaTable;\n> -\t\tconst unsigned int blackIndex = blackLevel * gammaTable.size() / 256;\n> -\t\tconst float divisor = gammaTable.size() - blackIndex - 1.0;\n> -\t\tfor (unsigned int i = blackIndex; i < gammaTable.size(); i++) {\n> -\t\t\tdouble normalized = (i - blackIndex) / divisor;\n> -\t\t\t/* Apply simple S-curve */\n> -\t\t\tif (normalized < 0.5)\n> -\t\t\t\tnormalized = 0.5 * std::pow(normalized / 0.5, contrastExp);\n> -\t\t\telse\n> -\t\t\t\tnormalized = 1.0 - 0.5 * std::pow((1.0 - normalized) / 0.5, contrastExp);\n> -\t\t\tgammaTable[i] = UINT8_MAX * std::pow(normalized, gamma);\n> -\t\t}\n> -\t\t/*\n> -\t\t * Due to CCM operations, the table lookup may reach indices below the black\n> -\t\t * level. Let's set the table values below black level to the minimum\n> -\t\t * non-black value to prevent problems when the minimum value is\n> -\t\t * significantly non-zero (for example, when the image should be all grey).\n> -\t\t */\n> -\t\tstd::fill(gammaTable.begin(), gammaTable.begin() + blackIndex,\n> -\t\t\t  gammaTable[blackIndex]);\n> -\t}\n> -\n> -\tcontext.activeState.gamma.gamma = gamma;\n> -\tcontext.activeState.gamma.blackLevel = blackLevel;\n> -\tcontext.activeState.gamma.contrastExp = contrastExp;\n> -}\n> [...]\n> diff --git a/src/libcamera/software_isp/debayer_cpu.cpp b/src/libcamera/software_isp/debayer_cpu.cpp\n> index 00738c56b..dcd931d2d 100644\n> --- a/src/libcamera/software_isp/debayer_cpu.cpp\n> +++ b/src/libcamera/software_isp/debayer_cpu.cpp\n> @@ -1,7 +1,7 @@\n> [...]\n> +void DebayerCpu::updateLookupTables(DebayerParams &params)\n> +{\n> +\tconst bool gammaUpdateNeeded =\n> +\t\tparams.gamma != params_.gamma ||\n> +\t\tparams.blackLevel != params_.blackLevel ||\n> +\t\tparams.contrastExp != params_.contrastExp;\n> +\tif (gammaUpdateNeeded)\n> +\t\tupdateGammaTable(params);\n> +\n> +\tauto matrixChanged = [](Matrix<float, 3, 3> m1, Matrix<float, 3, 3> m2) -> bool {\n> +\t\tfor (unsigned int i = 0; i < 3; i++)\n> +\t\t\tfor (unsigned int j = 0; j < 3; j++)\n> +\t\t\t\tif (m1[i][j] != m2[i][j])\n> +\t\t\t\t\treturn true;\n> +\t\treturn false;\n> +\t};\n\nI'd suggest std::equal from <algorithm> + using const ref, something like:\n\n   auto matrixChanged = [](const Matrix<float, 3, 3> &m1, const Matrix<float, 3, 3> &m2) {\n     return !std::equal(m1.data().begin(), m1.data().end(),\n                        m2.data().begin());\n   };\n\n\nRegards,\nBarnabás Pőcze\n\n> +\n> +\tconst unsigned int gammaTableSize = gammaTable_.size();\n> +\tconst double div = static_cast<double>(kRGBLookupSize) / gammaTableSize;\n> +\tif (ccmEnabled_) {\n> +\t\tif (gammaUpdateNeeded ||\n> +\t\t    matrixChanged(params.combinedMatrix, params_.combinedMatrix)) {\n> +\t\t\tauto &red = swapRedBlueGains_ ? blueCcm_ : redCcm_;\n> +\t\t\tauto &green = greenCcm_;\n> +\t\t\tauto &blue = swapRedBlueGains_ ? redCcm_ : blueCcm_;\n> +\t\t\tconst unsigned int redIndex = swapRedBlueGains_ ? 2 : 0;\n> +\t\t\tconst unsigned int greenIndex = 1;\n> +\t\t\tconst unsigned int blueIndex = swapRedBlueGains_ ? 0 : 2;\n> +\t\t\tfor (unsigned int i = 0; i < kRGBLookupSize; i++) {\n> +\t\t\t\tred[i].r = std::round(i * params.combinedMatrix[redIndex][0]);\n> +\t\t\t\tred[i].g = std::round(i * params.combinedMatrix[greenIndex][0]);\n> +\t\t\t\tred[i].b = std::round(i * params.combinedMatrix[blueIndex][0]);\n> +\t\t\t\tgreen[i].r = std::round(i * params.combinedMatrix[redIndex][1]);\n> +\t\t\t\tgreen[i].g = std::round(i * params.combinedMatrix[greenIndex][1]);\n> +\t\t\t\tgreen[i].b = std::round(i * params.combinedMatrix[blueIndex][1]);\n> +\t\t\t\tblue[i].r = std::round(i * params.combinedMatrix[redIndex][2]);\n> +\t\t\t\tblue[i].g = std::round(i * params.combinedMatrix[greenIndex][2]);\n> +\t\t\t\tblue[i].b = std::round(i * params.combinedMatrix[blueIndex][2]);\n> +\t\t\t\tgammaLut_[i] = gammaTable_[i / div];\n> +\t\t\t}\n> +\t\t}\n> +\t} else {\n> +\t\tif (gammaUpdateNeeded || params.gains != params_.gains) {\n> +\t\t\tauto &gains = params.gains;\n> +\t\t\tauto &red = swapRedBlueGains_ ? blue_ : red_;\n> +\t\t\tauto &green = green_;\n> +\t\t\tauto &blue = swapRedBlueGains_ ? red_ : blue_;\n> +\t\t\tfor (unsigned int i = 0; i < kRGBLookupSize; i++) {\n> +\t\t\t\t/* Apply gamma after gain! */\n> +\t\t\t\tconst RGB<float> lutGains = (gains * i / div).min(gammaTableSize - 1);\n> +\t\t\t\tred[i] = gammaTable_[static_cast<unsigned int>(lutGains.r())];\n> +\t\t\t\tgreen[i] = gammaTable_[static_cast<unsigned int>(lutGains.g())];\n> +\t\t\t\tblue[i] = gammaTable_[static_cast<unsigned int>(lutGains.b())];\n> +\t\t\t}\n> +\t\t}\n> +\t}\n> +\n> +\tLOG(Debayer, Debug)\n> +\t\t<< \"Debayer parameters: blackLevel=\" << params.blackLevel\n> +\t\t<< \"; gamma=\" << params.gamma\n> +\t\t<< \"; contrastExp=\" << params.contrastExp\n> +\t\t<< \"; gains=\" << params.gains\n> +\t\t<< \"; matrix=\" << params.combinedMatrix;\n> +\n> +\tparams_ = params;\n> +}\n> [...]","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 C40A1BDCBF\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 21 Jan 2026 15:21:19 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id EAA3F61FC9;\n\tWed, 21 Jan 2026 16:21:18 +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 E561E61F9F\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 21 Jan 2026 16:21:16 +0100 (CET)","from [192.168.33.24] (185.221.143.114.nat.pool.zt.hu\n\t[185.221.143.114])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id C125E1C6;\n\tWed, 21 Jan 2026 16:20:44 +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=\"NvZ/3NMR\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1769008844;\n\tbh=PSDPgbSiC9g9XV0yvlxxm6VFIIGmvSF7uOdQBDuT8w4=;\n\th=Date:Subject:To:Cc:References:From:In-Reply-To:From;\n\tb=NvZ/3NMRIBuiSKKA5msb7rKDdaIGnulLYZ+JM6RGkMlSY0+bIZYqp1fUWy3FIeYKd\n\tV22dknEi7Ir0wj+GTJ1rgGVkYjyfLTn3nKG0+BWQg9QmtewBDb/Qv/C9qPP11aDdqF\n\tKjEj/L5Phqy1RVX0B2kG8p0i3wPeXkPrwzFh+fOU=","Message-ID":"<9dca90ab-1da3-4710-a0f4-bd4c187111dd@ideasonboard.com>","Date":"Wed, 21 Jan 2026 16:21:13 +0100","MIME-Version":"1.0","User-Agent":"Mozilla Thunderbird","Subject":"Re: [PATCH v3 13/14] libcamera: ipa: simple: Remove Lut algorithm","To":"Milan Zamazal <mzamazal@redhat.com>, libcamera-devel@lists.libcamera.org","Cc":"Kieran Bingham <kieran.bingham@ideasonboard.com>","References":"<20260114113016.25162-1-mzamazal@redhat.com>\n\t<20260114113016.25162-14-mzamazal@redhat.com>","From":"=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <barnabas.pocze@ideasonboard.com>","Content-Language":"en-US, hu-HU","In-Reply-To":"<20260114113016.25162-14-mzamazal@redhat.com>","Content-Type":"text/plain; charset=UTF-8; format=flowed","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>"}},{"id":37807,"web_url":"https://patchwork.libcamera.org/comment/37807/","msgid":"<85tswf7xzn.fsf@mzamazal-thinkpadp1gen7.tpbc.csb>","date":"2026-01-21T16:05:00","subject":"Re: [PATCH v3 13/14] libcamera: ipa: simple: Remove Lut algorithm","submitter":{"id":177,"url":"https://patchwork.libcamera.org/api/people/177/","name":"Milan Zamazal","email":"mzamazal@redhat.com"},"content":"Hi Barnabás,\n\nthank you for review.\n\nBarnabás Pőcze <barnabas.pocze@ideasonboard.com> writes:\n\n> Hi\n>\n>\n> 2026. 01. 14. 12:30 keltezéssel, Milan Zamazal írta:\n>> The Lut algorithm is not really an algorithm.  Moreover, algorithms may\n>> be enabled or disabled but with Lut disabled, nothing will work.\n>> Let's move the construction of lookup tables to CPU debayering, where it\n>> is used.  The implied and related changes are:\n>> - DebayerParams is changed to contain the real params rather than lookup\n>>    tables.\n>> - contrastExp parameter introduced by GPU ISP is used for CPU ISP too.\n>> - The params must be initialised so that debayering gets meaningful\n>>    parameter values even when some algorithms are disabled.\n>> - combinedMatrix must be put to params everywhere where it is modified.\n>> - Matrix changes needn't be tracked in the algorithms any more.\n>> - CPU debayering must watch for changes of the corresponding parameters\n>>    to update the lookup tables when and only when needed.\n>> - Swapping red and blue is integrated into lookup table constructions.\n>> Signed-off-by: Milan Zamazal <mzamazal@redhat.com>\n>> ---\n>>   .../internal/software_isp/debayer_params.h    |  43 +----\n>>   src/ipa/simple/algorithms/adjust.cpp          |  20 +-\n>>   src/ipa/simple/algorithms/adjust.h            |   2 -\n>>   src/ipa/simple/algorithms/awb.cpp             |   7 +-\n>>   src/ipa/simple/algorithms/ccm.cpp             |   4 +-\n>>   src/ipa/simple/algorithms/lut.cpp             | 141 --------------\n>>   src/ipa/simple/algorithms/lut.h               |  35 ----\n>>   src/ipa/simple/algorithms/meson.build         |   1 -\n>>   src/ipa/simple/data/uncalibrated.yaml         |   1 -\n>>   src/ipa/simple/ipa_context.h                  |  10 -\n>>   src/ipa/simple/soft_simple.cpp                |  10 +-\n>>   src/libcamera/software_isp/debayer.cpp        | 172 +-----------------\n>>   src/libcamera/software_isp/debayer.h          |   8 -\n>>   src/libcamera/software_isp/debayer_cpu.cpp    | 141 ++++++++++++--\n>>   src/libcamera/software_isp/debayer_cpu.h      |  26 ++-\n>>   src/libcamera/software_isp/debayer_egl.cpp    |  22 +--\n>>   src/libcamera/software_isp/software_isp.cpp   |  17 --\n>>   17 files changed, 195 insertions(+), 465 deletions(-)\n>>   delete mode 100644 src/ipa/simple/algorithms/lut.cpp\n>>   delete mode 100644 src/ipa/simple/algorithms/lut.h\n>> [...]\n>> diff --git a/src/ipa/simple/algorithms/lut.cpp b/src/ipa/simple/algorithms/lut.cpp\n>> deleted file mode 100644\n>> index f31a7e631..000000000\n>> --- a/src/ipa/simple/algorithms/lut.cpp\n>> +++ /dev/null\n>> @@ -1,141 +0,0 @@\n>> -/* SPDX-License-Identifier: LGPL-2.1-or-later */\n>> -/*\n>> - * Copyright (C) 2024-2026, Red Hat Inc.\n>> - *\n>> - * Color lookup tables construction\n>> - */\n>> -\n>> -#include \"lut.h\"\n>> -\n>> -#include <algorithm>\n>> -#include <cmath>\n>> -#include <optional>\n>> -#include <stdint.h>\n>> -\n>> -#include <libcamera/base/log.h>\n>> -\n>> -#include <libcamera/control_ids.h>\n>> -\n>> -#include \"simple/ipa_context.h\"\n>> -\n>> -#include \"adjust.h\"\n>> -\n>> -namespace libcamera {\n>> -\n>> -LOG_DEFINE_CATEGORY(IPASoftLut)\n>> -\n>> -namespace ipa::soft::algorithms {\n>> -\n>> -int Lut::configure(IPAContext &context,\n>> -\t\t   [[maybe_unused]] const IPAConfigInfo &configInfo)\n>> -{\n>> -\tupdateGammaTable(context);\n>> -\n>> -\treturn 0;\n>> -}\n>> -\n>> -void Lut::updateGammaTable(IPAContext &context)\n>> -{\n>> -\tconst auto blackLevel = context.activeState.blc.level;\n>> -\tconst auto gamma =\n>> -\t\t1.0 / context.activeState.knobs.gamma.value_or(kDefaultGamma);\n>> -\tconst auto contrast = context.activeState.knobs.contrast.value_or(1.0);\n>> -\t/* Convert 0..2 to 0..infinity; avoid actual inifinity at tan(pi/2) */\n>> -\tfloat contrastExp = tan(std::clamp(contrast * M_PI_4, 0.0, M_PI_2 - 0.00001));\n>> -\n>> -\tif (!context.gpuIspEnabled) {\n>\n> Can `gpuIspEnabled` be removed altogether from `soft.mojom`, etc?\n\nYes, it's not needed any more, I'll remove it completely.\n\n>\n>> -\t\tauto &gammaTable = context.activeState.gamma.gammaTable;\n>> -\t\tconst unsigned int blackIndex = blackLevel * gammaTable.size() / 256;\n>> -\t\tconst float divisor = gammaTable.size() - blackIndex - 1.0;\n>> -\t\tfor (unsigned int i = blackIndex; i < gammaTable.size(); i++) {\n>> -\t\t\tdouble normalized = (i - blackIndex) / divisor;\n>> -\t\t\t/* Apply simple S-curve */\n>> -\t\t\tif (normalized < 0.5)\n>> -\t\t\t\tnormalized = 0.5 * std::pow(normalized / 0.5, contrastExp);\n>> -\t\t\telse\n>> -\t\t\t\tnormalized = 1.0 - 0.5 * std::pow((1.0 - normalized) / 0.5, contrastExp);\n>> -\t\t\tgammaTable[i] = UINT8_MAX * std::pow(normalized, gamma);\n>> -\t\t}\n>> -\t\t/*\n>> -\t\t * Due to CCM operations, the table lookup may reach indices below the black\n>> -\t\t * level. Let's set the table values below black level to the minimum\n>> -\t\t * non-black value to prevent problems when the minimum value is\n>> -\t\t * significantly non-zero (for example, when the image should be all grey).\n>> -\t\t */\n>> -\t\tstd::fill(gammaTable.begin(), gammaTable.begin() + blackIndex,\n>> -\t\t\t  gammaTable[blackIndex]);\n>> -\t}\n>> -\n>> -\tcontext.activeState.gamma.gamma = gamma;\n>> -\tcontext.activeState.gamma.blackLevel = blackLevel;\n>> -\tcontext.activeState.gamma.contrastExp = contrastExp;\n>> -}\n>> [...]\n>> diff --git a/src/libcamera/software_isp/debayer_cpu.cpp b/src/libcamera/software_isp/debayer_cpu.cpp\n>> index 00738c56b..dcd931d2d 100644\n>> --- a/src/libcamera/software_isp/debayer_cpu.cpp\n>> +++ b/src/libcamera/software_isp/debayer_cpu.cpp\n>> @@ -1,7 +1,7 @@\n>> [...]\n>> +void DebayerCpu::updateLookupTables(DebayerParams &params)\n>> +{\n>> +\tconst bool gammaUpdateNeeded =\n>> +\t\tparams.gamma != params_.gamma ||\n>> +\t\tparams.blackLevel != params_.blackLevel ||\n>> +\t\tparams.contrastExp != params_.contrastExp;\n>> +\tif (gammaUpdateNeeded)\n>> +\t\tupdateGammaTable(params);\n>> +\n>> +\tauto matrixChanged = [](Matrix<float, 3, 3> m1, Matrix<float, 3, 3> m2) -> bool {\n>> +\t\tfor (unsigned int i = 0; i < 3; i++)\n>> +\t\t\tfor (unsigned int j = 0; j < 3; j++)\n>> +\t\t\t\tif (m1[i][j] != m2[i][j])\n>> +\t\t\t\t\treturn true;\n>> +\t\treturn false;\n>> +\t};\n>\n> I'd suggest std::equal from <algorithm> + using const ref, something like:\n>\n>   auto matrixChanged = [](const Matrix<float, 3, 3> &m1, const Matrix<float, 3, 3> &m2) {\n>     return !std::equal(m1.data().begin(), m1.data().end(),\n>                        m2.data().begin());\n>   };\n\nGood idea, thanks.\n\n> Regards,\n> Barnabás Pőcze\n>\n>> +\n>> +\tconst unsigned int gammaTableSize = gammaTable_.size();\n>> +\tconst double div = static_cast<double>(kRGBLookupSize) / gammaTableSize;\n>> +\tif (ccmEnabled_) {\n>> +\t\tif (gammaUpdateNeeded ||\n>> +\t\t    matrixChanged(params.combinedMatrix, params_.combinedMatrix)) {\n>> +\t\t\tauto &red = swapRedBlueGains_ ? blueCcm_ : redCcm_;\n>> +\t\t\tauto &green = greenCcm_;\n>> +\t\t\tauto &blue = swapRedBlueGains_ ? redCcm_ : blueCcm_;\n>> +\t\t\tconst unsigned int redIndex = swapRedBlueGains_ ? 2 : 0;\n>> +\t\t\tconst unsigned int greenIndex = 1;\n>> +\t\t\tconst unsigned int blueIndex = swapRedBlueGains_ ? 0 : 2;\n>> +\t\t\tfor (unsigned int i = 0; i < kRGBLookupSize; i++) {\n>> +\t\t\t\tred[i].r = std::round(i * params.combinedMatrix[redIndex][0]);\n>> +\t\t\t\tred[i].g = std::round(i * params.combinedMatrix[greenIndex][0]);\n>> +\t\t\t\tred[i].b = std::round(i * params.combinedMatrix[blueIndex][0]);\n>> +\t\t\t\tgreen[i].r = std::round(i * params.combinedMatrix[redIndex][1]);\n>> +\t\t\t\tgreen[i].g = std::round(i * params.combinedMatrix[greenIndex][1]);\n>> +\t\t\t\tgreen[i].b = std::round(i * params.combinedMatrix[blueIndex][1]);\n>> +\t\t\t\tblue[i].r = std::round(i * params.combinedMatrix[redIndex][2]);\n>> +\t\t\t\tblue[i].g = std::round(i * params.combinedMatrix[greenIndex][2]);\n>> +\t\t\t\tblue[i].b = std::round(i * params.combinedMatrix[blueIndex][2]);\n>> +\t\t\t\tgammaLut_[i] = gammaTable_[i / div];\n>> +\t\t\t}\n>> +\t\t}\n>> +\t} else {\n>> +\t\tif (gammaUpdateNeeded || params.gains != params_.gains) {\n>> +\t\t\tauto &gains = params.gains;\n>> +\t\t\tauto &red = swapRedBlueGains_ ? blue_ : red_;\n>> +\t\t\tauto &green = green_;\n>> +\t\t\tauto &blue = swapRedBlueGains_ ? red_ : blue_;\n>> +\t\t\tfor (unsigned int i = 0; i < kRGBLookupSize; i++) {\n>> +\t\t\t\t/* Apply gamma after gain! */\n>> +\t\t\t\tconst RGB<float> lutGains = (gains * i / div).min(gammaTableSize - 1);\n>> +\t\t\t\tred[i] = gammaTable_[static_cast<unsigned int>(lutGains.r())];\n>> +\t\t\t\tgreen[i] = gammaTable_[static_cast<unsigned int>(lutGains.g())];\n>> +\t\t\t\tblue[i] = gammaTable_[static_cast<unsigned int>(lutGains.b())];\n>> +\t\t\t}\n>> +\t\t}\n>> +\t}\n>> +\n>> +\tLOG(Debayer, Debug)\n>> +\t\t<< \"Debayer parameters: blackLevel=\" << params.blackLevel\n>> +\t\t<< \"; gamma=\" << params.gamma\n>> +\t\t<< \"; contrastExp=\" << params.contrastExp\n>> +\t\t<< \"; gains=\" << params.gains\n>> +\t\t<< \"; matrix=\" << params.combinedMatrix;\n>> +\n>> +\tparams_ = params;\n>> +}\n>> [...]","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 41281BDCBF\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 21 Jan 2026 16:05:09 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 48B3E61FC4;\n\tWed, 21 Jan 2026 17:05:08 +0100 (CET)","from us-smtp-delivery-124.mimecast.com\n\t(us-smtp-delivery-124.mimecast.com [170.10.129.124])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 2C45961F9F\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 21 Jan 2026 17:05:06 +0100 (CET)","from mail-wr1-f70.google.com (mail-wr1-f70.google.com\n\t[209.85.221.70]) by relay.mimecast.com with ESMTP with STARTTLS\n\t(version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id\n\tus-mta-397-O0c418YEOdmcZLgsnMn6tA-1; Wed, 21 Jan 2026 11:05:03 -0500","by mail-wr1-f70.google.com with SMTP id\n\tffacd0b85a97d-430fdaba167so4622039f8f.3\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 21 Jan 2026 08:05:03 -0800 (PST)","from mzamazal-thinkpadp1gen7.tpbc.csb ([213.175.37.14])\n\tby smtp.gmail.com with ESMTPSA id\n\tffacd0b85a97d-43597ae9f37sm8026566f8f.8.2026.01.21.08.05.00\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tWed, 21 Jan 2026 08:05:00 -0800 (PST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=redhat.com header.i=@redhat.com\n\theader.b=\"G8scU2l5\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n\ts=mimecast20190719; t=1769011505;\n\th=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n\tto:to:cc:cc:mime-version:mime-version:content-type:content-type:\n\tcontent-transfer-encoding:content-transfer-encoding:\n\tin-reply-to:in-reply-to:references:references;\n\tbh=3Wr8cZmwPTPeOdwozDZgMcmUbYDa2QVCCV9guaoGdM4=;\n\tb=G8scU2l5M0IlDrQsIOkDFyvwvaFZVcQ4LODnfEBINKlnwa4uuX/7oc0L/pcCT3/vD+hSpZ\n\tOmE27VG9kyo6yWfNsvGdcUrOBwQYBecTc+SskTYytOj20rXYT5AuXsdU5zZP1A+edpiWG5\n\t9J1cm6VX/fgoXJX66o7gOA0tCSB9mRk=","X-MC-Unique":"O0c418YEOdmcZLgsnMn6tA-1","X-Mimecast-MFC-AGG-ID":"O0c418YEOdmcZLgsnMn6tA_1769011502","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20230601; t=1769011502; x=1769616302;\n\th=content-transfer-encoding:mime-version:user-agent:message-id:date\n\t:references:in-reply-to:subject:cc:to:from:x-gm-gg\n\t:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to;\n\tbh=MOc8Cx5dyGmEtn2Oxa9TaWdzXJp57t4UySf7jTGI8W0=;\n\tb=ekCaLM5iDUvIhyUmrAQRwJ0oLRV1QzF3bCntGTC7bkJp2/eJFrXdom2cMXqZJ8TxN4\n\t36p21XpEDVMFFglj3Txx7xtuyajsB4tuZi+DOi2Dl5pgMpT6I6t8uxf88ounyiFY7HJ9\n\tLvDGfGqUDqAJdMkS4AsY3MbE+rduNJKViqPBHsuY74qLhAsfv1Vq8nNi7JtAkWFyDvvl\n\tycH3jTWOIXdo3x14f1gvG8LLwqKVN0vDwsf3deX+fB3R9ajwPqfVy4MONynYlX9tW2GF\n\t1LAvW7+mjIgCiSZhoj+cgk2PASxq6spxGF9B05ME1RxJIQNdK1INktwXxUK9IFwMcZKq\n\tzXkg==","X-Gm-Message-State":"AOJu0YzBXJSJu8o3SKyQIF/ny642GTwJPSaSaMRBTCB08GudxNHjPd++\n\tMwRfXbqCtGyVE8q1qG2ibVdSffjLBoTI/ovqvWlr70wwpeBSWlnxnMavH0UqtCC9n87m9U5jIzy\n\t9GruCitH+/nmVO8t8fCvQe6O7Y0/xuGTMrxZIJPMTVnFcX8fYI9osbPSNkfHVVxM5raORZ1U4j1\n\tNUyF9mSUQ=","X-Gm-Gg":"AZuq6aIEnpwiVC13fjwT0zkPwlylv+0hg3KTjcj4mEYcf20Yu+j4OhTfD2HLmMSSt6h\n\tea/rdXC75vNnGCq4RgFKlssgvxo/O6INCubLc71Wc7jdHdwWBlaTWmuImDIodNJmDMsVNvrZx/b\n\tgt3nC6pHWiH9l8DMsbpcN7dZSx56n7WxHsksk2JJXyUisu/9NOq6Tz49y8pjBjlcXkc2XdbIDG1\n\tu/sD75EZjQNcY2BM5huLeNvtUs6wOnoZl1Mjpn+pgUyXjME6HHbBxYrkAxxW/alN2H4jKCVuXRt\n\trJIj103W4GiRNWo2w5lqTXLDwBmi42q40O6HKLeFXgkoSWXs8dtIUT5H4bXxjp5o66JKudfUxhD\n\ts7poCvjz2T99ICF8Sf9lnRi/Q/Q==","X-Received":["by 2002:a5d:5887:0:b0:432:8504:8d5b with SMTP id\n\tffacd0b85a97d-43569bcb816mr24468474f8f.50.1769011501967; \n\tWed, 21 Jan 2026 08:05:01 -0800 (PST)","by 2002:a5d:5887:0:b0:432:8504:8d5b with SMTP id\n\tffacd0b85a97d-43569bcb816mr24468409f8f.50.1769011501407; \n\tWed, 21 Jan 2026 08:05:01 -0800 (PST)"],"From":"Milan Zamazal <mzamazal@redhat.com>","To":"=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <barnabas.pocze@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org,  Kieran Bingham\n\t<kieran.bingham@ideasonboard.com>","Subject":"Re: [PATCH v3 13/14] libcamera: ipa: simple: Remove Lut algorithm","In-Reply-To":"<9dca90ab-1da3-4710-a0f4-bd4c187111dd@ideasonboard.com> (\n\t=?utf-8?b?IkJhcm5hYsOhcyBQxZFjemUiJ3M=?= message of \"Wed,\n\t21 Jan 2026  16:21:13 +0100\")","References":"<20260114113016.25162-1-mzamazal@redhat.com>\n\t<20260114113016.25162-14-mzamazal@redhat.com>\n\t<9dca90ab-1da3-4710-a0f4-bd4c187111dd@ideasonboard.com>","Date":"Wed, 21 Jan 2026 17:05:00 +0100","Message-ID":"<85tswf7xzn.fsf@mzamazal-thinkpadp1gen7.tpbc.csb>","User-Agent":"Gnus/5.13 (Gnus v5.13)","MIME-Version":"1.0","X-Mimecast-Spam-Score":"0","X-Mimecast-MFC-PROC-ID":"q9f1U1tXA9eGM41h-mQVUGmWovTzbyIs6VhV-RCxD20_1769011502","X-Mimecast-Originator":"redhat.com","Content-Type":"text/plain; charset=utf-8","Content-Transfer-Encoding":"quoted-printable","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>"}},{"id":37815,"web_url":"https://patchwork.libcamera.org/comment/37815/","msgid":"<861c3eff-4d52-49e5-87e6-870c03676b4f@ideasonboard.com>","date":"2026-01-21T16:37:22","subject":"Re: [PATCH v3 13/14] libcamera: ipa: simple: Remove Lut algorithm","submitter":{"id":216,"url":"https://patchwork.libcamera.org/api/people/216/","name":"Barnabás Pőcze","email":"barnabas.pocze@ideasonboard.com"},"content":"2026. 01. 14. 12:30 keltezéssel, Milan Zamazal írta:\n> The Lut algorithm is not really an algorithm.  Moreover, algorithms may\n> be enabled or disabled but with Lut disabled, nothing will work.\n> \n> Let's move the construction of lookup tables to CPU debayering, where it\n> is used.  The implied and related changes are:\n> \n> - DebayerParams is changed to contain the real params rather than lookup\n>    tables.\n> - contrastExp parameter introduced by GPU ISP is used for CPU ISP too.\n> - The params must be initialised so that debayering gets meaningful\n>    parameter values even when some algorithms are disabled.\n> - combinedMatrix must be put to params everywhere where it is modified.\n> - Matrix changes needn't be tracked in the algorithms any more.\n> - CPU debayering must watch for changes of the corresponding parameters\n>    to update the lookup tables when and only when needed.\n> - Swapping red and blue is integrated into lookup table constructions.\n> \n> Signed-off-by: Milan Zamazal <mzamazal@redhat.com>\n> ---\n>   .../internal/software_isp/debayer_params.h    |  43 +----\n>   src/ipa/simple/algorithms/adjust.cpp          |  20 +-\n>   src/ipa/simple/algorithms/adjust.h            |   2 -\n>   src/ipa/simple/algorithms/awb.cpp             |   7 +-\n>   src/ipa/simple/algorithms/ccm.cpp             |   4 +-\n>   src/ipa/simple/algorithms/lut.cpp             | 141 --------------\n>   src/ipa/simple/algorithms/lut.h               |  35 ----\n>   src/ipa/simple/algorithms/meson.build         |   1 -\n>   src/ipa/simple/data/uncalibrated.yaml         |   1 -\n>   src/ipa/simple/ipa_context.h                  |  10 -\n>   src/ipa/simple/soft_simple.cpp                |  10 +-\n>   src/libcamera/software_isp/debayer.cpp        | 172 +-----------------\n>   src/libcamera/software_isp/debayer.h          |   8 -\n>   src/libcamera/software_isp/debayer_cpu.cpp    | 141 ++++++++++++--\n>   src/libcamera/software_isp/debayer_cpu.h      |  26 ++-\n>   src/libcamera/software_isp/debayer_egl.cpp    |  22 +--\n>   src/libcamera/software_isp/software_isp.cpp   |  17 --\n>   17 files changed, 195 insertions(+), 465 deletions(-)\n>   delete mode 100644 src/ipa/simple/algorithms/lut.cpp\n>   delete mode 100644 src/ipa/simple/algorithms/lut.h\n> \n> [...]\n> diff --git a/src/ipa/simple/algorithms/adjust.cpp b/src/ipa/simple/algorithms/adjust.cpp\n> index 60a191380..8e2230164 100644\n> --- a/src/ipa/simple/algorithms/adjust.cpp\n> +++ b/src/ipa/simple/algorithms/adjust.cpp\n> @@ -1,7 +1,7 @@\n>   /* SPDX-License-Identifier: LGPL-2.1-or-later */\n>   /*\n>    * Copyright (C) 2024, Ideas On Board\n> - * Copyright (C) 2024-2025, Red Hat Inc.\n> + * Copyright (C) 2024-2026, Red Hat Inc.\n>    *\n>    * Common image adjustments\n>    */\n> @@ -92,22 +92,20 @@ void Adjust::applySaturation(Matrix<float, 3, 3> &matrix, float saturation)\n>   void Adjust::prepare(IPAContext &context,\n>   \t\t     [[maybe_unused]] const uint32_t frame,\n>   \t\t     IPAFrameContext &frameContext,\n> -\t\t     [[maybe_unused]] DebayerParams *params)\n> +\t\t     DebayerParams *params)\n>   {\n>   \tframeContext.contrast = context.activeState.knobs.contrast;\n>   \n> -\tif (!context.ccmEnabled)\n> -\t\treturn;\n> -\n>   \tauto &saturation = context.activeState.knobs.saturation;\n> -\tframeContext.saturation = saturation;\n> -\tif (saturation)\n> +\tif (context.ccmEnabled && saturation) {\n>   \t\tapplySaturation(context.activeState.combinedMatrix, saturation.value());\n> -\n> -\tif (saturation != lastSaturation_) {\n> -\t\tcontext.activeState.matrixChanged = true;\n> -\t\tlastSaturation_ = saturation;\n> +\t\tframeContext.saturation = saturation;\n>   \t}\n> +\n> +\tparams->gamma = 1.0 / context.activeState.knobs.gamma.value_or(kDefaultGamma);\n> +\tconst float contrast = context.activeState.knobs.contrast.value_or(kDefaultContrast);\n> +\tparams->contrastExp = tan(std::clamp(contrast * M_PI_4, 0.0, M_PI_2 - 0.00001));\n> +\tparams->combinedMatrix = context.activeState.combinedMatrix;\n\nI see that this line is repeated for three algorithms in total (adjust, awb, ccm).\nWouldn't it be enough to do this at the end of `computeParams()` or similar?\nOr use `params->combinedMatrix` and remove `context.activeState.combinedMatrix`?\n\n(See below)\n\n\n>   }\n>   \n>   void Adjust::process([[maybe_unused]] IPAContext &context,\n> [...]\n> diff --git a/src/ipa/simple/soft_simple.cpp b/src/ipa/simple/soft_simple.cpp\n> index 732e82510..b85e09501 100644\n> --- a/src/ipa/simple/soft_simple.cpp\n> +++ b/src/ipa/simple/soft_simple.cpp\n> @@ -26,6 +26,7 @@\n>   #include \"libcamera/internal/software_isp/swisp_stats.h\"\n>   #include \"libcamera/internal/yaml_parser.h\"\n>   \n> +#include \"algorithms/adjust.h\"\n>   #include \"libipa/camera_sensor_helper.h\"\n>   \n>   #include \"module.h\"\n> @@ -161,6 +162,11 @@ int IPASoftSimple::init(const IPASettings &settings,\n>   \t\t}\n>   \n>   \t\tparams_ = static_cast<DebayerParams *>(mem);\n> +\t\tparams_->blackLevel = { { 0.0, 0.0, 0.0 } };\n> +\t\tparams_->gamma = 1.0 / algorithms::kDefaultGamma;\n> +\t\tparams_->contrastExp = 1.0;\n> +\t\tparams_->gains = { { 1.0, 1.0, 1.0 } };\n> +\t\t/* combinedMatrix is reset for each frame. */\n>   \t}\n>   \n>   \t{\n> @@ -282,7 +288,9 @@ void IPASoftSimple::queueRequest(const uint32_t frame, const ControlList &contro\n>   \n>   void IPASoftSimple::computeParams(const uint32_t frame)\n>   {\n> -\tcontext_.activeState.combinedMatrix = Matrix<float, 3, 3>::identity();\n> +\tMatrix<float, 3, 3> combinedMatrix = Matrix<float, 3, 3>::identity();\n> +\tcontext_.activeState.combinedMatrix = combinedMatrix;\n> +\tparams_->combinedMatrix = combinedMatrix;\n\nJust:\n\n   context_.activeState.combinedMatrix = Matrix<float, 3, 3>::identity();\n\n\n>   \n>   \tIPAFrameContext &frameContext = context_.frameContexts.get(frame);\n>   \tfor (auto const &algo : algorithms())\n\nthen after the loop:\n\n   params_->combinedMatrix = context_.activeState.combinedMatrix;\n\nor did I miss anything?\n\n\n> [...]","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 7D649C3220\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 21 Jan 2026 16:37:29 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 9D7B761FC9;\n\tWed, 21 Jan 2026 17:37:28 +0100 (CET)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id C599161F9F\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 21 Jan 2026 17:37:26 +0100 (CET)","from [192.168.33.24] (185.221.143.114.nat.pool.zt.hu\n\t[185.221.143.114])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id A8032833;\n\tWed, 21 Jan 2026 17:36:54 +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=\"On/ihIW4\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1769013414;\n\tbh=Oxp6OZM4RQNSXBPgKzp47qPX8OPoWEwauvhLjH9ezLQ=;\n\th=Date:Subject:To:Cc:References:From:In-Reply-To:From;\n\tb=On/ihIW40hsK4AvmFhUjv8rinrfUUbLNlaSk61Cb7g2ClZsWZ7WgGc7oWtxEJ8Jn2\n\tNe1ZaCFQkge6Rmf7Joxsj7Mh92Wrz149etsZbiAZ8+2Z1h0fqCFGbR7FBNPVrelYjq\n\t1/xLuWuOqnmKNO0LOJmwy/W8hhJl9TYUGScVeSZc=","Message-ID":"<861c3eff-4d52-49e5-87e6-870c03676b4f@ideasonboard.com>","Date":"Wed, 21 Jan 2026 17:37:22 +0100","MIME-Version":"1.0","User-Agent":"Mozilla Thunderbird","Subject":"Re: [PATCH v3 13/14] libcamera: ipa: simple: Remove Lut algorithm","To":"Milan Zamazal <mzamazal@redhat.com>, libcamera-devel@lists.libcamera.org","Cc":"Kieran Bingham <kieran.bingham@ideasonboard.com>","References":"<20260114113016.25162-1-mzamazal@redhat.com>\n\t<20260114113016.25162-14-mzamazal@redhat.com>","From":"=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <barnabas.pocze@ideasonboard.com>","Content-Language":"en-US, hu-HU","In-Reply-To":"<20260114113016.25162-14-mzamazal@redhat.com>","Content-Type":"text/plain; charset=UTF-8; format=flowed","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>"}},{"id":37819,"web_url":"https://patchwork.libcamera.org/comment/37819/","msgid":"<85pl7299k3.fsf@mzamazal-thinkpadp1gen7.tpbc.csb>","date":"2026-01-21T17:09:48","subject":"Re: [PATCH v3 13/14] libcamera: ipa: simple: Remove Lut algorithm","submitter":{"id":177,"url":"https://patchwork.libcamera.org/api/people/177/","name":"Milan Zamazal","email":"mzamazal@redhat.com"},"content":"Barnabás Pőcze <barnabas.pocze@ideasonboard.com> writes:\n\n> 2026. 01. 14. 12:30 keltezéssel, Milan Zamazal írta:\n>> The Lut algorithm is not really an algorithm.  Moreover, algorithms may\n>> be enabled or disabled but with Lut disabled, nothing will work.\n>> Let's move the construction of lookup tables to CPU debayering, where it\n>> is used.  The implied and related changes are:\n>> - DebayerParams is changed to contain the real params rather than lookup\n>>    tables.\n>> - contrastExp parameter introduced by GPU ISP is used for CPU ISP too.\n>> - The params must be initialised so that debayering gets meaningful\n>>    parameter values even when some algorithms are disabled.\n>> - combinedMatrix must be put to params everywhere where it is modified.\n>> - Matrix changes needn't be tracked in the algorithms any more.\n>> - CPU debayering must watch for changes of the corresponding parameters\n>>    to update the lookup tables when and only when needed.\n>> - Swapping red and blue is integrated into lookup table constructions.\n>> Signed-off-by: Milan Zamazal <mzamazal@redhat.com>\n>> ---\n>>   .../internal/software_isp/debayer_params.h    |  43 +----\n>>   src/ipa/simple/algorithms/adjust.cpp          |  20 +-\n>>   src/ipa/simple/algorithms/adjust.h            |   2 -\n>>   src/ipa/simple/algorithms/awb.cpp             |   7 +-\n>>   src/ipa/simple/algorithms/ccm.cpp             |   4 +-\n>>   src/ipa/simple/algorithms/lut.cpp             | 141 --------------\n>>   src/ipa/simple/algorithms/lut.h               |  35 ----\n>>   src/ipa/simple/algorithms/meson.build         |   1 -\n>>   src/ipa/simple/data/uncalibrated.yaml         |   1 -\n>>   src/ipa/simple/ipa_context.h                  |  10 -\n>>   src/ipa/simple/soft_simple.cpp                |  10 +-\n>>   src/libcamera/software_isp/debayer.cpp        | 172 +-----------------\n>>   src/libcamera/software_isp/debayer.h          |   8 -\n>>   src/libcamera/software_isp/debayer_cpu.cpp    | 141 ++++++++++++--\n>>   src/libcamera/software_isp/debayer_cpu.h      |  26 ++-\n>>   src/libcamera/software_isp/debayer_egl.cpp    |  22 +--\n>>   src/libcamera/software_isp/software_isp.cpp   |  17 --\n>>   17 files changed, 195 insertions(+), 465 deletions(-)\n>>   delete mode 100644 src/ipa/simple/algorithms/lut.cpp\n>>   delete mode 100644 src/ipa/simple/algorithms/lut.h\n>> [...]\n>> diff --git a/src/ipa/simple/algorithms/adjust.cpp b/src/ipa/simple/algorithms/adjust.cpp\n>> index 60a191380..8e2230164 100644\n>> --- a/src/ipa/simple/algorithms/adjust.cpp\n>> +++ b/src/ipa/simple/algorithms/adjust.cpp\n>> @@ -1,7 +1,7 @@\n>>   /* SPDX-License-Identifier: LGPL-2.1-or-later */\n>>   /*\n>>    * Copyright (C) 2024, Ideas On Board\n>> - * Copyright (C) 2024-2025, Red Hat Inc.\n>> + * Copyright (C) 2024-2026, Red Hat Inc.\n>>    *\n>>    * Common image adjustments\n>>    */\n>> @@ -92,22 +92,20 @@ void Adjust::applySaturation(Matrix<float, 3, 3> &matrix, float saturation)\n>>   void Adjust::prepare(IPAContext &context,\n>>   \t\t     [[maybe_unused]] const uint32_t frame,\n>>   \t\t     IPAFrameContext &frameContext,\n>> -\t\t     [[maybe_unused]] DebayerParams *params)\n>> +\t\t     DebayerParams *params)\n>>   {\n>>   \tframeContext.contrast = context.activeState.knobs.contrast;\n>>   -\tif (!context.ccmEnabled)\n>> -\t\treturn;\n>> -\n>>   \tauto &saturation = context.activeState.knobs.saturation;\n>> -\tframeContext.saturation = saturation;\n>> -\tif (saturation)\n>> +\tif (context.ccmEnabled && saturation) {\n>>   \t\tapplySaturation(context.activeState.combinedMatrix, saturation.value());\n>> -\n>> -\tif (saturation != lastSaturation_) {\n>> -\t\tcontext.activeState.matrixChanged = true;\n>> -\t\tlastSaturation_ = saturation;\n>> +\t\tframeContext.saturation = saturation;\n>>   \t}\n>> +\n>> +\tparams->gamma = 1.0 / context.activeState.knobs.gamma.value_or(kDefaultGamma);\n>> +\tconst float contrast = context.activeState.knobs.contrast.value_or(kDefaultContrast);\n>> +\tparams->contrastExp = tan(std::clamp(contrast * M_PI_4, 0.0, M_PI_2 - 0.00001));\n>> +\tparams->combinedMatrix = context.activeState.combinedMatrix;\n>\n> I see that this line is repeated for three algorithms in total (adjust, awb, ccm).\n> Wouldn't it be enough to do this at the end of `computeParams()` or similar?\n> Or use `params->combinedMatrix` and remove `context.activeState.combinedMatrix`?\n>\n> (See below)\n>\n>\n>>   }\n>>     void Adjust::process([[maybe_unused]] IPAContext &context,\n>> [...]\n>> diff --git a/src/ipa/simple/soft_simple.cpp b/src/ipa/simple/soft_simple.cpp\n>> index 732e82510..b85e09501 100644\n>> --- a/src/ipa/simple/soft_simple.cpp\n>> +++ b/src/ipa/simple/soft_simple.cpp\n>> @@ -26,6 +26,7 @@\n>>   #include \"libcamera/internal/software_isp/swisp_stats.h\"\n>>   #include \"libcamera/internal/yaml_parser.h\"\n>>   +#include \"algorithms/adjust.h\"\n>>   #include \"libipa/camera_sensor_helper.h\"\n>>     #include \"module.h\"\n>> @@ -161,6 +162,11 @@ int IPASoftSimple::init(const IPASettings &settings,\n>>   \t\t}\n>>     \t\tparams_ = static_cast<DebayerParams *>(mem);\n>> +\t\tparams_->blackLevel = { { 0.0, 0.0, 0.0 } };\n>> +\t\tparams_->gamma = 1.0 / algorithms::kDefaultGamma;\n>> +\t\tparams_->contrastExp = 1.0;\n>> +\t\tparams_->gains = { { 1.0, 1.0, 1.0 } };\n>> +\t\t/* combinedMatrix is reset for each frame. */\n>>   \t}\n>>     \t{\n>> @@ -282,7 +288,9 @@ void IPASoftSimple::queueRequest(const uint32_t frame, const ControlList &contro\n>>     void IPASoftSimple::computeParams(const uint32_t frame)\n>>   {\n>> -\tcontext_.activeState.combinedMatrix = Matrix<float, 3, 3>::identity();\n>> +\tMatrix<float, 3, 3> combinedMatrix = Matrix<float, 3, 3>::identity();\n>> +\tcontext_.activeState.combinedMatrix = combinedMatrix;\n>> +\tparams_->combinedMatrix = combinedMatrix;\n>\n> Just:\n>\n>   context_.activeState.combinedMatrix = Matrix<float, 3, 3>::identity();\n>\n>\n>>     \tIPAFrameContext &frameContext = context_.frameContexts.get(frame);\n>>   \tfor (auto const &algo : algorithms())\n>\n> then after the loop:\n>\n>   params_->combinedMatrix = context_.activeState.combinedMatrix;\n>\n> or did I miss anything?\n\nI think it should work as you suggest, I'll change it this way.\n\n>> [...]","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 DC821BDCBF\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 21 Jan 2026 17:09:59 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 0BFBA61FC9;\n\tWed, 21 Jan 2026 18:09:59 +0100 (CET)","from us-smtp-delivery-124.mimecast.com\n\t(us-smtp-delivery-124.mimecast.com [170.10.129.124])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id F414761F9F\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 21 Jan 2026 18:09:56 +0100 (CET)","from mail-lf1-f69.google.com (mail-lf1-f69.google.com\n\t[209.85.167.69]) by relay.mimecast.com with ESMTP with STARTTLS\n\t(version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id\n\tus-mta-425-x0ouANiiOl2Ye4AgQGQy6g-1; Wed, 21 Jan 2026 12:09:54 -0500","by mail-lf1-f69.google.com with SMTP id\n\t2adb3069b0e04-59b6ab3cceeso644e87.0\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 21 Jan 2026 09:09:53 -0800 (PST)","from mzamazal-thinkpadp1gen7.tpbc.csb ([213.175.37.14])\n\tby smtp.gmail.com with ESMTPSA id\n\t2adb3069b0e04-59baf34e83bsm4929202e87.30.2026.01.21.09.09.48\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tWed, 21 Jan 2026 09:09:50 -0800 (PST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=redhat.com header.i=@redhat.com\n\theader.b=\"fmXk4Wju\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n\ts=mimecast20190719; t=1769015395;\n\th=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n\tto:to:cc:cc:mime-version:mime-version:content-type:content-type:\n\tcontent-transfer-encoding:content-transfer-encoding:\n\tin-reply-to:in-reply-to:references:references;\n\tbh=Uem+NkYyQH3ADLeFzKt87TIgGVo/i01+90DImrUVY6U=;\n\tb=fmXk4Wjule/JjIlapCl0H6pqXeWrY1TEFmvQLQyXRvJ3rhZXikaJTpyy+OuCkTLBwhR65q\n\t3jvHLpet/w6bFR69+esouF9nZGC1jon8xkh9qQ7w4QagcwNki2jvSuoMfsnMfqFstE76Ss\n\t75T+aXvSu7iwaDCrg8GX3l6J9AsYki4=","X-MC-Unique":"x0ouANiiOl2Ye4AgQGQy6g-1","X-Mimecast-MFC-AGG-ID":"x0ouANiiOl2Ye4AgQGQy6g_1769015393","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20230601; t=1769015392; x=1769620192;\n\th=content-transfer-encoding:mime-version:user-agent:message-id:date\n\t:references:in-reply-to:subject:cc:to:from:x-gm-gg\n\t:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to;\n\tbh=hVuC72Etnsz8KefVbKbRjMXVjHqyjzZNps7QmWTcrU0=;\n\tb=mGwQvs6VewQWRGqIs9i3/Ltanh3FzRCLOagbtqk6E6/OnAkVT1KI5+280Tu67RFUlU\n\trBZpIgunZSMTxNzbYqx426Kl5Lr3fAd6n8qLOhAHjmjwg7dossWzLsFiUAv8fizCGweW\n\ti1pPKhbNDjvt+MeZ+HeV2K4t9CNGKrEHE6yp1oh6hVbmgJ1e/MHLzSM8LmGbhs7xy3Q9\n\txwzYmZ5k4p3J11lgJ86oFPEk1Qw5q9h1RyM0us8C896WxC2IH5HtaW9il9ny5G7RKkYq\n\tCcd9VFqOQodSk3M6b6XylgDKeSySFtYfXs/tiNIJDFBgTLcNPxZ/5DuQMLhfpf2yRr0c\n\toaew==","X-Gm-Message-State":"AOJu0Yxgfv5nKq1EkHbpEx5XVz5iJNzOdFVpSHu3uARyoYp/Z2PPilX4\n\tD8gjYRGZH6LDC++d5tQrqCByTzGyDJmRkIVsMtsvQsJFXbt0qk6wAwYjDl/uY/mY/BbZuF+AQnj\n\t3foAT4XAVyXRhgigdznpkBpvT/uAH6z4J5kBk1uROTzY9MtqczCrVoa1biLUsYKqC/oo5kJqdE4\n\tcaaXgzRsI=","X-Gm-Gg":"AZuq6aKrDXHR2Q+JZtIdt9/eYWLU8KlYYdLhP4+8ygZ2PSTaq9GI2L9qf9r1Vx/VqI+\n\tSrOgxu3iuGJrlodEr8pZsC469MkqXfINuecay40FcFywu9OpvIN1JOAH22hzwy0fVOYsCLsb1FM\n\tTGVV8tQvNiwgdSjB7qy2Ji5rNce7qgicfOdrWMYMdhSzq/3WYwnPPUypOrCb7H0bGY6VQs8h8ZN\n\tF7fKsMg1zIDHHirc0+X4njmXf5esmAjhteq/7SIVKBBGypEyRKd67BXh3Vm8b30yWO2I+XyaKyl\n\tD7WGWaN95MMagbZYBOjW3XEO2YQClJEtl309KazWXEZHhrgBpr0By/nPNfqWgkolZZSZQbyZDIp\n\tYvHuzZl2wufItxIh6g62eJvcvsQ==","X-Received":["by 2002:a05:6512:3ca8:b0:59b:730d:4a56 with SMTP id\n\t2adb3069b0e04-59dc9366b79mr2311480e87.49.1769015391900; \n\tWed, 21 Jan 2026 09:09:51 -0800 (PST)","by 2002:a05:6512:3ca8:b0:59b:730d:4a56 with SMTP id\n\t2adb3069b0e04-59dc9366b79mr2311473e87.49.1769015391351; \n\tWed, 21 Jan 2026 09:09:51 -0800 (PST)"],"From":"Milan Zamazal <mzamazal@redhat.com>","To":"=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <barnabas.pocze@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org,  Kieran Bingham\n\t<kieran.bingham@ideasonboard.com>","Subject":"Re: [PATCH v3 13/14] libcamera: ipa: simple: Remove Lut algorithm","In-Reply-To":"<861c3eff-4d52-49e5-87e6-870c03676b4f@ideasonboard.com> (\n\t=?utf-8?b?IkJhcm5hYsOhcyBQxZFjemUiJ3M=?= message of \"Wed,\n\t21 Jan 2026  17:37:22 +0100\")","References":"<20260114113016.25162-1-mzamazal@redhat.com>\n\t<20260114113016.25162-14-mzamazal@redhat.com>\n\t<861c3eff-4d52-49e5-87e6-870c03676b4f@ideasonboard.com>","Date":"Wed, 21 Jan 2026 18:09:48 +0100","Message-ID":"<85pl7299k3.fsf@mzamazal-thinkpadp1gen7.tpbc.csb>","User-Agent":"Gnus/5.13 (Gnus v5.13)","MIME-Version":"1.0","X-Mimecast-Spam-Score":"0","X-Mimecast-MFC-PROC-ID":"Z7Lu0h-X9sESOBwypTFN3PlFfkn9Oufb1ev1h0AUQRE_1769015393","X-Mimecast-Originator":"redhat.com","Content-Type":"text/plain; charset=utf-8","Content-Transfer-Encoding":"quoted-printable","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>"}}]