[{"id":37991,"web_url":"https://patchwork.libcamera.org/comment/37991/","msgid":"<176960512266.3376561.8957030056680826249@ping.linuxembedded.co.uk>","date":"2026-01-28T12:58:42","subject":"Re: [PATCH v5 14/15] libcamera: ipa: simple: Remove Lut algorithm","submitter":{"id":4,"url":"https://patchwork.libcamera.org/api/people/4/","name":"Kieran Bingham","email":"kieran.bingham@ideasonboard.com"},"content":"Quoting Milan Zamazal (2026-01-28 11:44:01)\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> - gpuIspEnabled flags are removed as they are not needed any more.\n\nThere's a lot going on in there... but I think this is all helping\nprogress the development, and CI is green so:\n\nAcked-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n\n> \n> Reviewed-by: Robert Mader <robert.mader@collabora.com>\n> Signed-off-by: Milan Zamazal <mzamazal@redhat.com>\n> ---\n>  .../internal/software_isp/debayer_params.h    |  43 +----\n>  include/libcamera/ipa/soft.mojom              |   3 +-\n>  src/ipa/simple/algorithms/adjust.cpp          |  17 +-\n>  src/ipa/simple/algorithms/adjust.h            |   4 -\n>  src/ipa/simple/algorithms/awb.cpp             |   6 +-\n>  src/ipa/simple/algorithms/ccm.cpp             |   1 -\n>  src/ipa/simple/algorithms/lut.cpp             | 140 --------------\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                  |  11 --\n>  src/ipa/simple/soft_simple.cpp                |  11 +-\n>  src/libcamera/software_isp/debayer.cpp        | 172 +-----------------\n>  src/libcamera/software_isp/debayer.h          |   8 -\n>  src/libcamera/software_isp/debayer_cpu.cpp    | 136 ++++++++++++--\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   |  29 +--\n>  18 files changed, 188 insertions(+), 478 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/include/libcamera/internal/software_isp/debayer_params.h b/include/libcamera/internal/software_isp/debayer_params.h\n> index 2d69bd295..1c0412d75 100644\n> --- a/include/libcamera/internal/software_isp/debayer_params.h\n> +++ b/include/libcamera/internal/software_isp/debayer_params.h\n> @@ -1,6 +1,6 @@\n>  /* SPDX-License-Identifier: LGPL-2.1-or-later */\n>  /*\n> - * Copyright (C) 2023-2025 Red Hat Inc.\n> + * Copyright (C) 2023-2026 Red Hat Inc.\n>   *\n>   * Authors:\n>   * Hans de Goede <hdegoede@redhat.com>\n> @@ -10,7 +10,6 @@\n>  \n>  #pragma once\n>  \n> -#include <array>\n>  #include <stdint.h>\n>  \n>  #include \"libcamera/internal/matrix.h\"\n> @@ -19,47 +18,11 @@\n>  namespace libcamera {\n>  \n>  struct DebayerParams {\n> -       static constexpr unsigned int kRGBLookupSize = 256;\n> -\n> -       struct CcmColumn {\n> -               int16_t r;\n> -               int16_t g;\n> -               int16_t b;\n> -       };\n> -\n> -       using LookupTable = std::array<uint8_t, kRGBLookupSize>;\n> -       using CcmLookupTable = std::array<CcmColumn, kRGBLookupSize>;\n> -\n> -       /*\n> -        * Color lookup tables when CCM is not used.\n> -        *\n> -        * Each color of a debayered pixel is amended by the corresponding\n> -        * value in the given table.\n> -        */\n> -       LookupTable red;\n> -       LookupTable green;\n> -       LookupTable blue;\n> -\n> -       /*\n> -        * Color and gamma lookup tables when CCM is used.\n> -        *\n> -        * Each of the CcmLookupTable's corresponds to a CCM column; together they\n> -        * make a complete 3x3 CCM lookup table. The CCM is applied on debayered\n> -        * pixels and then the gamma lookup table is used to set the resulting\n> -        * values of all the three colors.\n> -        */\n> -       CcmLookupTable redCcm;\n> -       CcmLookupTable greenCcm;\n> -       CcmLookupTable blueCcm;\n> -       LookupTable gammaLut;\n> -\n> -       /*\n> -        * Per frame corrections as calculated by the IPA\n> -        */\n> -       Matrix<float, 3, 3> ccm;\n> +       Matrix<float, 3, 3> combinedMatrix;\n>         RGB<float> blackLevel;\n>         float gamma;\n>         float contrastExp;\n> +       RGB<float> gains;\n>  };\n>  \n>  } /* namespace libcamera */\n> diff --git a/include/libcamera/ipa/soft.mojom b/include/libcamera/ipa/soft.mojom\n> index aff8fcbd3..77328c5fd 100644\n> --- a/include/libcamera/ipa/soft.mojom\n> +++ b/include/libcamera/ipa/soft.mojom\n> @@ -17,8 +17,7 @@ interface IPASoftInterface {\n>              libcamera.SharedFD fdStats,\n>              libcamera.SharedFD fdParams,\n>              libcamera.IPACameraSensorInfo sensorInfo,\n> -            libcamera.ControlInfoMap sensorControls,\n> -            bool gpuIspEnabled)\n> +            libcamera.ControlInfoMap sensorControls)\n>                 => (int32 ret, libcamera.ControlInfoMap ipaControls, bool ccmEnabled);\n>         start() => (int32 ret);\n>         stop();\n> diff --git a/src/ipa/simple/algorithms/adjust.cpp b/src/ipa/simple/algorithms/adjust.cpp\n> index acdd3f741..068e98404 100644\n> --- a/src/ipa/simple/algorithms/adjust.cpp\n> +++ b/src/ipa/simple/algorithms/adjust.cpp\n> @@ -95,23 +95,20 @@ void Adjust::applySaturation(Matrix<float, 3, 3> &matrix, float saturation)\n>  void Adjust::prepare(IPAContext &context,\n>                      [[maybe_unused]] const uint32_t frame,\n>                      IPAFrameContext &frameContext,\n> -                    [[maybe_unused]] DebayerParams *params)\n> +                    DebayerParams *params)\n>  {\n>         frameContext.gamma = context.activeState.knobs.gamma;\n>         frameContext.contrast = context.activeState.knobs.contrast;\n>  \n> -       if (!context.ccmEnabled)\n> -               return;\n> -\n>         auto &saturation = context.activeState.knobs.saturation;\n> -       frameContext.saturation = saturation;\n> -       if (saturation)\n> +       if (context.ccmEnabled && saturation) {\n>                 applySaturation(context.activeState.combinedMatrix, saturation.value());\n> -\n> -       if (saturation != lastSaturation_) {\n> -               context.activeState.matrixChanged = true;\n> -               lastSaturation_ = saturation;\n> +               frameContext.saturation = saturation;\n>         }\n> +\n> +       params->gamma = 1.0 / context.activeState.knobs.gamma;\n> +       const float contrast = context.activeState.knobs.contrast.value_or(kDefaultContrast);\n> +       params->contrastExp = tan(std::clamp(contrast * M_PI_4, 0.0, M_PI_2 - 0.00001));\n>  }\n>  \n>  void Adjust::process([[maybe_unused]] IPAContext &context,\n> diff --git a/src/ipa/simple/algorithms/adjust.h b/src/ipa/simple/algorithms/adjust.h\n> index 7644138ff..fb133b140 100644\n> --- a/src/ipa/simple/algorithms/adjust.h\n> +++ b/src/ipa/simple/algorithms/adjust.h\n> @@ -7,8 +7,6 @@\n>  \n>  #pragma once\n>  \n> -#include <optional>\n> -\n>  #include \"libcamera/internal/matrix.h\"\n>  \n>  #include <libipa/interpolator.h>\n> @@ -45,8 +43,6 @@ public:\n>  \n>  private:\n>         void applySaturation(Matrix<float, 3, 3> &ccm, float saturation);\n> -\n> -       std::optional<float> lastSaturation_;\n>  };\n>  \n>  } /* namespace ipa::soft::algorithms */\n> diff --git a/src/ipa/simple/algorithms/awb.cpp b/src/ipa/simple/algorithms/awb.cpp\n> index 31726658a..6fdaacaba 100644\n> --- a/src/ipa/simple/algorithms/awb.cpp\n> +++ b/src/ipa/simple/algorithms/awb.cpp\n> @@ -37,7 +37,7 @@ int Awb::configure(IPAContext &context,\n>  void Awb::prepare(IPAContext &context,\n>                   [[maybe_unused]] const uint32_t frame,\n>                   IPAFrameContext &frameContext,\n> -                 [[maybe_unused]] DebayerParams *params)\n> +                 DebayerParams *params)\n>  {\n>         auto &gains = context.activeState.awb.gains;\n>         Matrix<float, 3, 3> gainMatrix = { { gains.r(), 0, 0,\n> @@ -45,9 +45,11 @@ void Awb::prepare(IPAContext &context,\n>                                              0, 0, gains.b() } };\n>         context.activeState.combinedMatrix =\n>                 context.activeState.combinedMatrix * gainMatrix;\n> -       /* Just report, the gains are applied in LUT algorithm. */\n> +\n>         frameContext.gains.red = gains.r();\n>         frameContext.gains.blue = gains.b();\n> +\n> +       params->gains = gains;\n>  }\n>  \n>  void Awb::process(IPAContext &context,\n> diff --git a/src/ipa/simple/algorithms/ccm.cpp b/src/ipa/simple/algorithms/ccm.cpp\n> index 5576a301f..911a5af2c 100644\n> --- a/src/ipa/simple/algorithms/ccm.cpp\n> +++ b/src/ipa/simple/algorithms/ccm.cpp\n> @@ -51,7 +51,6 @@ void Ccm::prepare(IPAContext &context, [[maybe_unused]] const uint32_t frame,\n>             utils::abs_diff(ct, lastCt_) >= kTemperatureThreshold) {\n>                 currentCcm_ = ccm_.getInterpolated(ct);\n>                 lastCt_ = ct;\n> -               context.activeState.matrixChanged = true;\n>         }\n>  \n>         context.activeState.combinedMatrix =\n> diff --git a/src/ipa/simple/algorithms/lut.cpp b/src/ipa/simple/algorithms/lut.cpp\n> deleted file mode 100644\n> index fd442259a..000000000\n> --- a/src/ipa/simple/algorithms/lut.cpp\n> +++ /dev/null\n> @@ -1,140 +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> -                  [[maybe_unused]] const IPAConfigInfo &configInfo)\n> -{\n> -       updateGammaTable(context);\n> -\n> -       return 0;\n> -}\n> -\n> -void Lut::updateGammaTable(IPAContext &context)\n> -{\n> -       const auto blackLevel = context.activeState.blc.level;\n> -       const auto gamma = 1.0 / context.activeState.knobs.gamma;\n> -       const auto contrast = context.activeState.knobs.contrast.value_or(1.0);\n> -       /* Convert 0..2 to 0..infinity; avoid actual inifinity at tan(pi/2) */\n> -       float contrastExp = tan(std::clamp(contrast * M_PI_4, 0.0, M_PI_2 - 0.00001));\n> -\n> -       if (!context.gpuIspEnabled) {\n> -               auto &gammaTable = context.activeState.gamma.gammaTable;\n> -               const unsigned int blackIndex = blackLevel * gammaTable.size() / 256;\n> -               const float divisor = gammaTable.size() - blackIndex - 1.0;\n> -               for (unsigned int i = blackIndex; i < gammaTable.size(); i++) {\n> -                       double normalized = (i - blackIndex) / divisor;\n> -                       /* Apply simple S-curve */\n> -                       if (normalized < 0.5)\n> -                               normalized = 0.5 * std::pow(normalized / 0.5, contrastExp);\n> -                       else\n> -                               normalized = 1.0 - 0.5 * std::pow((1.0 - normalized) / 0.5, contrastExp);\n> -                       gammaTable[i] = UINT8_MAX * std::pow(normalized, gamma);\n> -               }\n> -               /*\n> -                * Due to CCM operations, the table lookup may reach indices below the black\n> -                * level. Let's set the table values below black level to the minimum\n> -                * non-black value to prevent problems when the minimum value is\n> -                * significantly non-zero (for example, when the image should be all grey).\n> -                */\n> -               std::fill(gammaTable.begin(), gammaTable.begin() + blackIndex,\n> -                         gammaTable[blackIndex]);\n> -       }\n> -\n> -       context.activeState.gamma.gamma = gamma;\n> -       context.activeState.gamma.blackLevel = blackLevel;\n> -       context.activeState.gamma.contrastExp = contrastExp;\n> -}\n> -\n> -int16_t Lut::matrixValue(unsigned int i, float ccm) const\n> -{\n> -       return std::round(i * ccm);\n> -}\n> -\n> -void Lut::prepare(IPAContext &context,\n> -                 [[maybe_unused]] const uint32_t frame,\n> -                 [[maybe_unused]] IPAFrameContext &frameContext,\n> -                 DebayerParams *params)\n> -{\n> -       /*\n> -        * Update the gamma table if needed. This means if black level changes\n> -        * and since the black level gets updated only if a lower value is\n> -        * observed, it's not permanently prone to minor fluctuations or\n> -        * rounding errors.\n> -        */\n> -       const bool gammaUpdateNeeded =\n> -               context.activeState.gamma.blackLevel != context.activeState.blc.level ||\n> -               context.activeState.gamma.contrast != context.activeState.knobs.contrast;\n> -       if (gammaUpdateNeeded)\n> -               updateGammaTable(context);\n> -\n> -       auto &gains = context.activeState.awb.gains;\n> -       auto &gammaTable = context.activeState.gamma.gammaTable;\n> -       const unsigned int gammaTableSize = gammaTable.size();\n> -       const double div = static_cast<double>(DebayerParams::kRGBLookupSize) /\n> -                          gammaTableSize;\n> -\n> -       if (!context.ccmEnabled) {\n> -               for (unsigned int i = 0; i < DebayerParams::kRGBLookupSize; i++) {\n> -                       /* Apply gamma after gain! */\n> -                       const RGB<float> lutGains = (gains * i / div).min(gammaTableSize - 1);\n> -                       params->red[i] = gammaTable[static_cast<unsigned int>(lutGains.r())];\n> -                       params->green[i] = gammaTable[static_cast<unsigned int>(lutGains.g())];\n> -                       params->blue[i] = gammaTable[static_cast<unsigned int>(lutGains.b())];\n> -               }\n> -       } else if (context.activeState.matrixChanged || gammaUpdateNeeded) {\n> -               auto &matrix = context.activeState.combinedMatrix;\n> -               auto &red = params->redCcm;\n> -               auto &green = params->greenCcm;\n> -               auto &blue = params->blueCcm;\n> -               params->ccm = matrix;\n> -               if (!context.gpuIspEnabled) {\n> -                       for (unsigned int i = 0; i < DebayerParams::kRGBLookupSize; i++) {\n> -                               red[i].r = matrixValue(i, matrix[0][0]);\n> -                               red[i].g = matrixValue(i, matrix[1][0]);\n> -                               red[i].b = matrixValue(i, matrix[2][0]);\n> -                               green[i].r = matrixValue(i, matrix[0][1]);\n> -                               green[i].g = matrixValue(i, matrix[1][1]);\n> -                               green[i].b = matrixValue(i, matrix[2][1]);\n> -                               blue[i].r = matrixValue(i, matrix[0][2]);\n> -                               blue[i].g = matrixValue(i, matrix[1][2]);\n> -                               blue[i].b = matrixValue(i, matrix[2][2]);\n> -                               params->gammaLut[i] = gammaTable[i / div];\n> -                       }\n> -               }\n> -               context.activeState.matrixChanged = false;\n> -       }\n> -\n> -       params->gamma = context.activeState.gamma.gamma;\n> -       params->contrastExp = context.activeState.gamma.contrastExp;\n> -}\n> -\n> -REGISTER_IPA_ALGORITHM(Lut, \"Lut\")\n> -\n> -} /* namespace ipa::soft::algorithms */\n> -\n> -} /* namespace libcamera */\n> diff --git a/src/ipa/simple/algorithms/lut.h b/src/ipa/simple/algorithms/lut.h\n> deleted file mode 100644\n> index ad16d1e8e..000000000\n> --- a/src/ipa/simple/algorithms/lut.h\n> +++ /dev/null\n> @@ -1,35 +0,0 @@\n> -/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> -/*\n> - * Copyright (C) 2024, Red Hat Inc.\n> - *\n> - * Color lookup tables construction\n> - */\n> -\n> -#pragma once\n> -\n> -#include \"algorithm.h\"\n> -\n> -namespace libcamera {\n> -\n> -namespace ipa::soft::algorithms {\n> -\n> -class Lut : public Algorithm\n> -{\n> -public:\n> -       Lut() = default;\n> -       ~Lut() = default;\n> -\n> -       int configure(IPAContext &context, const IPAConfigInfo &configInfo) override;\n> -       void prepare(IPAContext &context,\n> -                    const uint32_t frame,\n> -                    IPAFrameContext &frameContext,\n> -                    DebayerParams *params) override;\n> -\n> -private:\n> -       void updateGammaTable(IPAContext &context);\n> -       int16_t matrixValue(unsigned int i, float ccm) const;\n> -};\n> -\n> -} /* namespace ipa::soft::algorithms */\n> -\n> -} /* namespace libcamera */\n> diff --git a/src/ipa/simple/algorithms/meson.build b/src/ipa/simple/algorithms/meson.build\n> index ebe9f20dd..73c637220 100644\n> --- a/src/ipa/simple/algorithms/meson.build\n> +++ b/src/ipa/simple/algorithms/meson.build\n> @@ -6,5 +6,4 @@ soft_simple_ipa_algorithms = files([\n>      'agc.cpp',\n>      'blc.cpp',\n>      'ccm.cpp',\n> -    'lut.cpp',\n>  ])\n> diff --git a/src/ipa/simple/data/uncalibrated.yaml b/src/ipa/simple/data/uncalibrated.yaml\n> index e389e0588..c6feda36d 100644\n> --- a/src/ipa/simple/data/uncalibrated.yaml\n> +++ b/src/ipa/simple/data/uncalibrated.yaml\n> @@ -15,6 +15,5 @@ algorithms:\n>                   0, 1, 0,\n>                   0, 0, 1]\n>    - Adjust:\n> -  - Lut:\n>    - Agc:\n>  ...\n> diff --git a/src/ipa/simple/ipa_context.h b/src/ipa/simple/ipa_context.h\n> index 293e35b71..34f7403a4 100644\n> --- a/src/ipa/simple/ipa_context.h\n> +++ b/src/ipa/simple/ipa_context.h\n> @@ -53,17 +53,7 @@ struct IPAActiveState {\n>                 unsigned int temperatureK;\n>         } awb;\n>  \n> -       static constexpr unsigned int kGammaLookupSize = 1024;\n> -       struct {\n> -               std::array<double, kGammaLookupSize> gammaTable;\n> -               uint8_t blackLevel;\n> -               float gamma;\n> -               float contrast;\n> -               float contrastExp;\n> -       } gamma;\n> -\n>         Matrix<float, 3, 3> combinedMatrix;\n> -       bool matrixChanged = false;\n>  \n>         struct {\n>                 float gamma;\n> @@ -103,7 +93,6 @@ struct IPAContext {\n>         FCQueue<IPAFrameContext> frameContexts;\n>         ControlInfoMap::Map ctrlMap;\n>         bool ccmEnabled = false;\n> -       bool gpuIspEnabled = false;\n>  };\n>  \n>  } /* namespace ipa::soft */\n> diff --git a/src/ipa/simple/soft_simple.cpp b/src/ipa/simple/soft_simple.cpp\n> index 732e82510..6bef597c8 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> @@ -55,7 +56,6 @@ public:\n>                  const SharedFD &fdParams,\n>                  const IPACameraSensorInfo &sensorInfo,\n>                  const ControlInfoMap &sensorControls,\n> -                bool gpuIspEnabled,\n>                  ControlInfoMap *ipaControls,\n>                  bool *ccmEnabled) override;\n>         int configure(const IPAConfigInfo &configInfo) override;\n> @@ -96,7 +96,6 @@ int IPASoftSimple::init(const IPASettings &settings,\n>                         const SharedFD &fdParams,\n>                         const IPACameraSensorInfo &sensorInfo,\n>                         const ControlInfoMap &sensorControls,\n> -                       bool gpuIspEnabled,\n>                         ControlInfoMap *ipaControls,\n>                         bool *ccmEnabled)\n>  {\n> @@ -108,7 +107,6 @@ int IPASoftSimple::init(const IPASettings &settings,\n>         }\n>  \n>         context_.sensorInfo = sensorInfo;\n> -       context_.gpuIspEnabled = gpuIspEnabled;\n>  \n>         /* Load the tuning data file */\n>         File file(settings.configurationFile);\n> @@ -161,6 +159,11 @@ int IPASoftSimple::init(const IPASettings &settings,\n>                 }\n>  \n>                 params_ = static_cast<DebayerParams *>(mem);\n> +               params_->blackLevel = { { 0.0, 0.0, 0.0 } };\n> +               params_->gamma = 1.0 / algorithms::kDefaultGamma;\n> +               params_->contrastExp = 1.0;\n> +               params_->gains = { { 1.0, 1.0, 1.0 } };\n> +               /* combinedMatrix is reset for each frame. */\n>         }\n>  \n>         {\n> @@ -287,6 +290,8 @@ void IPASoftSimple::computeParams(const uint32_t frame)\n>         IPAFrameContext &frameContext = context_.frameContexts.get(frame);\n>         for (auto const &algo : algorithms())\n>                 algo->prepare(context_, frame, frameContext, params_);\n> +       params_->combinedMatrix = context_.activeState.combinedMatrix;\n> +\n>         setIspParams.emit();\n>  }\n>  \n> diff --git a/src/libcamera/software_isp/debayer.cpp b/src/libcamera/software_isp/debayer.cpp\n> index 65a1762dd..dccdd86b4 100644\n> --- a/src/libcamera/software_isp/debayer.cpp\n> +++ b/src/libcamera/software_isp/debayer.cpp\n> @@ -1,7 +1,7 @@\n>  /* SPDX-License-Identifier: LGPL-2.1-or-later */\n>  /*\n>   * Copyright (C) 2023, Linaro Ltd\n> - * Copyright (C) 2023-2025 Red Hat Inc.\n> + * Copyright (C) 2023-2026 Red Hat Inc.\n>   *\n>   * Authors:\n>   * Hans de Goede <hdegoede@redhat.com>\n> @@ -25,99 +25,28 @@ namespace libcamera {\n>   */\n>  \n>  /**\n> - * \\var DebayerParams::kRGBLookupSize\n> - * \\brief Size of a color lookup table\n> + * \\var DebayerParams::gains\n> + * \\brief Colour channel gains\n>   */\n>  \n>  /**\n> - * \\struct DebayerParams::CcmColumn\n> - * \\brief Type of a single column of a color correction matrix (CCM)\n> - *\n> - * When multiplying an input pixel, columns in the CCM correspond to the red,\n> - * green or blue component of input pixel values, while rows correspond to the\n> - * red, green or blue components of the output pixel values. The members of the\n> - * CcmColumn structure are named after the colour components of the output pixel\n> - * values they correspond to.\n> - */\n> -\n> -/**\n> - * \\var DebayerParams::CcmColumn::r\n> - * \\brief Red (first) component of a CCM column\n> - */\n> -\n> -/**\n> - * \\var DebayerParams::CcmColumn::g\n> - * \\brief Green (second) component of a CCM column\n> - */\n> -\n> -/**\n> - * \\var DebayerParams::CcmColumn::b\n> - * \\brief Blue (third) component of a CCM column\n> - */\n> -\n> -/**\n> - * \\typedef DebayerParams::LookupTable\n> - * \\brief Type of the lookup tables for single lookup values\n> - */\n> -\n> -/**\n> - * \\typedef DebayerParams::CcmLookupTable\n> - * \\brief Type of the CCM lookup tables for red, green, blue values\n> - */\n> -\n> -/**\n> - * \\var DebayerParams::red\n> - * \\brief Lookup table for red color, mapping input values to output values\n> - */\n> -\n> -/**\n> - * \\var DebayerParams::green\n> - * \\brief Lookup table for green color, mapping input values to output values\n> - */\n> -\n> -/**\n> - * \\var DebayerParams::blue\n> - * \\brief Lookup table for blue color, mapping input values to output values\n> - */\n> -\n> -/**\n> - * \\var DebayerParams::redCcm\n> - * \\brief Lookup table for the CCM red column, mapping input values to output values\n> - */\n> -\n> -/**\n> - * \\var DebayerParams::greenCcm\n> - * \\brief Lookup table for the CCM green column, mapping input values to output values\n> - */\n> -\n> -/**\n> - * \\var DebayerParams::blueCcm\n> - * \\brief Lookup table for the CCM blue column, mapping input values to output values\n> - */\n> -\n> -/**\n> - * \\var DebayerParams::gammaLut\n> - * \\brief Gamma lookup table used with color correction matrix\n> - */\n> -\n> -/**\n> - * \\var DebayerParams::ccm\n> - * \\brief Per frame colour correction matrix for GPUISP\n> + * \\var DebayerParams::combinedMatrix\n> + * \\brief Colour correction matrix, including other adjustments\n>   */\n>  \n>  /**\n>   * \\var DebayerParams::blackLevel\n> - * \\brief Blacklevel gains for the GPUISP\n> + * \\brief Black level values\n>   */\n>  \n>  /**\n>   * \\var DebayerParams::gamma\n> - * \\brief Gamma value for the GPUISP\n> + * \\brief Gamma value, e.g. 1/2.2\n>   */\n>  \n>  /**\n>   * \\var DebayerParams::contrastExp\n> - * \\brief Contrast value for GPUISP\n> + * \\brief Contrast value to be used as an exponent\n>   */\n>  \n>  /**\n> @@ -131,13 +60,6 @@ LOG_DEFINE_CATEGORY(Debayer)\n>  \n>  Debayer::Debayer(const GlobalConfiguration &configuration) : bench_(configuration)\n>  {\n> -       /* Initialize color lookup tables */\n> -       for (unsigned int i = 0; i < DebayerParams::kRGBLookupSize; i++) {\n> -               red_[i] = green_[i] = blue_[i] = i;\n> -               redCcm_[i] = { static_cast<int16_t>(i), 0, 0 };\n> -               greenCcm_[i] = { 0, static_cast<int16_t>(i), 0 };\n> -               blueCcm_[i] = { 0, 0, static_cast<int16_t>(i) };\n> -       }\n>  }\n>  \n>  Debayer::~Debayer()\n> @@ -305,56 +227,6 @@ Debayer::~Debayer()\n>   * \\brief Output size object\n>   */\n>  \n> -/**\n> - * \\var Debayer::red_\n> - * \\brief Lookup table for red channel gain and correction values\n> - *\n> - * This table provides precomputed per-pixel or per-intensity\n> - * correction values for the red color channel used during debayering.\n> - */\n> -\n> -/**\n> - * \\var Debayer::green_\n> - * \\brief Lookup table for green channel gain and correction values\n> - *\n> - * This table provides precomputed per-pixel or per-intensity\n> - * correction values for the green color channel used during debayering.\n> - */\n> -\n> -/**\n> - * \\var Debayer::blue_\n> - * \\brief Lookup table for blue channel gain and correction values\n> - *\n> - * This table provides precomputed per-pixel or per-intensity\n> - * correction values for the blue color channel used during debayering.\n> - */\n> -\n> -/**\n> - * \\var Debayer::redCcm_\n> - * \\brief Red channel Color Correction Matrix (CCM) lookup table\n> - *\n> - * Contains coefficients for green channel color correction.\n> - */\n> -\n> -/**\n> - * \\var Debayer::greenCcm_\n> - * \\brief Green channel Color Correction Matrix (CCM) lookup table\n> - *\n> - * Contains coefficients for green channel color correction.\n> - */\n> -\n> -/**\n> - * \\var Debayer::blueCcm_\n> - * \\brief Blue channel Color Correction Matrix (CCM) lookup table\n> - *\n> - * Contains coefficients for blue channel color correction.\n> - */\n> -\n> -/**\n> - * \\var Debayer::gammaLut_\n> - * \\brief Gamma correction lookup table\n> - */\n> -\n>  /**\n>   * \\var Debayer::swapRedBlueGains_\n>   * \\brief Flag indicating whether red and blue channel gains should be swapped\n> @@ -396,34 +268,6 @@ Debayer::~Debayer()\n>   * DebayerEGL::start.\n>   */\n>  \n> -/**\n> - * \\fn void Debayer::setParams(DebayerParams &params)\n> - * \\brief Select the bayer params to use for the next frame debayer\n> - * \\param[in] params The parameters to be used in debayering\n> - */\n> -void Debayer::setParams(DebayerParams &params)\n> -{\n> -       green_ = params.green;\n> -       greenCcm_ = params.greenCcm;\n> -       if (swapRedBlueGains_) {\n> -               red_ = params.blue;\n> -               blue_ = params.red;\n> -               redCcm_ = params.blueCcm;\n> -               blueCcm_ = params.redCcm;\n> -               for (unsigned int i = 0; i < 256; i++) {\n> -                       std::swap(redCcm_[i].r, redCcm_[i].b);\n> -                       std::swap(greenCcm_[i].r, greenCcm_[i].b);\n> -                       std::swap(blueCcm_[i].r, blueCcm_[i].b);\n> -               }\n> -       } else {\n> -               red_ = params.red;\n> -               blue_ = params.blue;\n> -               redCcm_ = params.redCcm;\n> -               blueCcm_ = params.blueCcm;\n> -       }\n> -       gammaLut_ = params.gammaLut;\n> -}\n> -\n>  /**\n>   * \\fn void Debayer::dmaSyncBegin(DebayerParams &params)\n>   * \\brief Common CPU/GPU Dma Sync Buffer begin\n> diff --git a/src/libcamera/software_isp/debayer.h b/src/libcamera/software_isp/debayer.h\n> index cd2db9930..652cff4cc 100644\n> --- a/src/libcamera/software_isp/debayer.h\n> +++ b/src/libcamera/software_isp/debayer.h\n> @@ -78,13 +78,6 @@ public:\n>         Size outputSize_;\n>         PixelFormat inputPixelFormat_;\n>         PixelFormat outputPixelFormat_;\n> -       DebayerParams::LookupTable red_;\n> -       DebayerParams::LookupTable green_;\n> -       DebayerParams::LookupTable blue_;\n> -       DebayerParams::CcmLookupTable redCcm_;\n> -       DebayerParams::CcmLookupTable greenCcm_;\n> -       DebayerParams::CcmLookupTable blueCcm_;\n> -       DebayerParams::LookupTable gammaLut_;\n>         bool swapRedBlueGains_;\n>         Benchmark bench_;\n>  \n> @@ -92,7 +85,6 @@ private:\n>         virtual Size patternSize(PixelFormat inputFormat) = 0;\n>  \n>  protected:\n> -       void setParams(DebayerParams &params);\n>         void dmaSyncBegin(std::vector<DmaSyncer> &dmaSyncers, FrameBuffer *input, FrameBuffer *output);\n>         static bool isStandardBayerOrder(BayerFormat::Order order);\n>  };\n> diff --git a/src/libcamera/software_isp/debayer_cpu.cpp b/src/libcamera/software_isp/debayer_cpu.cpp\n> index 00738c56b..af7af0a8d 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>  /* SPDX-License-Identifier: LGPL-2.1-or-later */\n>  /*\n>   * Copyright (C) 2023, Linaro Ltd\n> - * Copyright (C) 2023-2025 Red Hat Inc.\n> + * Copyright (C) 2023-2026 Red Hat Inc.\n>   *\n>   * Authors:\n>   * Hans de Goede <hdegoede@redhat.com>\n> @@ -68,21 +68,21 @@ DebayerCpu::~DebayerCpu() = default;\n>  #define GAMMA(value) \\\n>         *dst++ = gammaLut_[std::clamp(value, 0, static_cast<int>(gammaLut_.size()) - 1)]\n>  \n> -#define STORE_PIXEL(b_, g_, r_)                                        \\\n> -       if constexpr (ccmEnabled) {                                    \\\n> -               const DebayerParams::CcmColumn &blue = blueCcm_[b_];   \\\n> -               const DebayerParams::CcmColumn &green = greenCcm_[g_]; \\\n> -               const DebayerParams::CcmColumn &red = redCcm_[r_];     \\\n> -               GAMMA(blue.b + green.b + red.b);                       \\\n> -               GAMMA(blue.g + green.g + red.g);                       \\\n> -               GAMMA(blue.r + green.r + red.r);                       \\\n> -       } else {                                                       \\\n> -               *dst++ = blue_[b_];                                    \\\n> -               *dst++ = green_[g_];                                   \\\n> -               *dst++ = red_[r_];                                     \\\n> -       }                                                              \\\n> -       if constexpr (addAlphaByte)                                    \\\n> -               *dst++ = 255;                                          \\\n> +#define STORE_PIXEL(b_, g_, r_)                         \\\n> +       if constexpr (ccmEnabled) {                     \\\n> +               const CcmColumn &blue = blueCcm_[b_];   \\\n> +               const CcmColumn &green = greenCcm_[g_]; \\\n> +               const CcmColumn &red = redCcm_[r_];     \\\n> +               GAMMA(blue.b + green.b + red.b);        \\\n> +               GAMMA(blue.g + green.g + red.g);        \\\n> +               GAMMA(blue.r + green.r + red.r);        \\\n> +       } else {                                        \\\n> +               *dst++ = blue_[b_];                     \\\n> +               *dst++ = green_[g_];                    \\\n> +               *dst++ = red_[r_];                      \\\n> +       }                                               \\\n> +       if constexpr (addAlphaByte)                     \\\n> +               *dst++ = 255;                           \\\n>         x++;\n>  \n>  /*\n> @@ -525,6 +525,16 @@ int DebayerCpu::configure(const StreamConfiguration &inputCfg,\n>         if (ret != 0)\n>                 return -EINVAL;\n>  \n> +       ccmEnabled_ = ccmEnabled;\n> +\n> +       /*\n> +        * Lookup tables must be initialized because the initial value is used for\n> +        * the first two frames, i.e. until stats processing starts providing its\n> +        * own parameters. Let's enforce recomputing lookup tables by setting the\n> +        * stored last used gamma to an out-of-range value.\n> +        */\n> +       params_.gamma = 1.0;\n> +\n>         window_.x = ((inputCfg.size.width - outputCfg.size.width) / 2) &\n>                     ~(inputConfig_.patternSize.width - 1);\n>         window_.y = ((inputCfg.size.height - outputCfg.size.height) / 2) &\n> @@ -740,6 +750,98 @@ void DebayerCpu::process4(uint32_t frame, const uint8_t *src, uint8_t *dst)\n>         }\n>  }\n>  \n> +void DebayerCpu::updateGammaTable(DebayerParams &params)\n> +{\n> +       const RGB<float> blackLevel = params.blackLevel;\n> +       /* Take let's say the green channel black level */\n> +       const unsigned int blackIndex = blackLevel[1] * gammaTable_.size();\n> +       const float gamma = params.gamma;\n> +       const float contrastExp = params.contrastExp;\n> +\n> +       const float divisor = gammaTable_.size() - blackIndex - 1.0;\n> +       for (unsigned int i = blackIndex; i < gammaTable_.size(); i++) {\n> +               float normalized = (i - blackIndex) / divisor;\n> +               /* Convert 0..2 to 0..infinity; avoid actual inifinity at tan(pi/2) */\n> +               /* Apply simple S-curve */\n> +               if (normalized < 0.5)\n> +                       normalized = 0.5 * std::pow(normalized / 0.5, contrastExp);\n> +               else\n> +                       normalized = 1.0 - 0.5 * std::pow((1.0 - normalized) / 0.5, contrastExp);\n> +               gammaTable_[i] = UINT8_MAX *\n> +                                std::pow(normalized, gamma);\n> +       }\n> +       /*\n> +        * Due to CCM operations, the table lookup may reach indices below the black\n> +        * level. Let's set the table values below black level to the minimum\n> +        * non-black value to prevent problems when the minimum value is\n> +        * significantly non-zero (for example, when the image should be all grey).\n> +        */\n> +       std::fill(gammaTable_.begin(), gammaTable_.begin() + blackIndex,\n> +                 gammaTable_[blackIndex]);\n> +}\n> +\n> +void DebayerCpu::updateLookupTables(DebayerParams &params)\n> +{\n> +       const bool gammaUpdateNeeded =\n> +               params.gamma != params_.gamma ||\n> +               params.blackLevel != params_.blackLevel ||\n> +               params.contrastExp != params_.contrastExp;\n> +       if (gammaUpdateNeeded)\n> +               updateGammaTable(params);\n> +\n> +       auto matrixChanged = [](const Matrix<float, 3, 3> &m1, const Matrix<float, 3, 3> &m2) -> bool {\n> +               return !std::equal(m1.data().begin(), m1.data().end(), m2.data().begin());\n> +       };\n> +       const unsigned int gammaTableSize = gammaTable_.size();\n> +       const double div = static_cast<double>(kRGBLookupSize) / gammaTableSize;\n> +       if (ccmEnabled_) {\n> +               if (gammaUpdateNeeded ||\n> +                   matrixChanged(params.combinedMatrix, params_.combinedMatrix)) {\n> +                       auto &red = swapRedBlueGains_ ? blueCcm_ : redCcm_;\n> +                       auto &green = greenCcm_;\n> +                       auto &blue = swapRedBlueGains_ ? redCcm_ : blueCcm_;\n> +                       const unsigned int redIndex = swapRedBlueGains_ ? 2 : 0;\n> +                       const unsigned int greenIndex = 1;\n> +                       const unsigned int blueIndex = swapRedBlueGains_ ? 0 : 2;\n> +                       for (unsigned int i = 0; i < kRGBLookupSize; i++) {\n> +                               red[i].r = std::round(i * params.combinedMatrix[redIndex][0]);\n> +                               red[i].g = std::round(i * params.combinedMatrix[greenIndex][0]);\n> +                               red[i].b = std::round(i * params.combinedMatrix[blueIndex][0]);\n> +                               green[i].r = std::round(i * params.combinedMatrix[redIndex][1]);\n> +                               green[i].g = std::round(i * params.combinedMatrix[greenIndex][1]);\n> +                               green[i].b = std::round(i * params.combinedMatrix[blueIndex][1]);\n> +                               blue[i].r = std::round(i * params.combinedMatrix[redIndex][2]);\n> +                               blue[i].g = std::round(i * params.combinedMatrix[greenIndex][2]);\n> +                               blue[i].b = std::round(i * params.combinedMatrix[blueIndex][2]);\n> +                               gammaLut_[i] = gammaTable_[i / div];\n> +                       }\n> +               }\n> +       } else {\n> +               if (gammaUpdateNeeded || params.gains != params_.gains) {\n> +                       auto &gains = params.gains;\n> +                       auto &red = swapRedBlueGains_ ? blue_ : red_;\n> +                       auto &green = green_;\n> +                       auto &blue = swapRedBlueGains_ ? red_ : blue_;\n> +                       for (unsigned int i = 0; i < kRGBLookupSize; i++) {\n> +                               /* Apply gamma after gain! */\n> +                               const RGB<float> lutGains = (gains * i / div).min(gammaTableSize - 1);\n> +                               red[i] = gammaTable_[static_cast<unsigned int>(lutGains.r())];\n> +                               green[i] = gammaTable_[static_cast<unsigned int>(lutGains.g())];\n> +                               blue[i] = gammaTable_[static_cast<unsigned int>(lutGains.b())];\n> +                       }\n> +               }\n> +       }\n> +\n> +       LOG(Debayer, Debug)\n> +               << \"Debayer parameters: blackLevel=\" << params.blackLevel\n> +               << \"; gamma=\" << params.gamma\n> +               << \"; contrastExp=\" << params.contrastExp\n> +               << \"; gains=\" << params.gains\n> +               << \"; matrix=\" << params.combinedMatrix;\n> +\n> +       params_ = params;\n> +}\n> +\n>  void DebayerCpu::process(uint32_t frame, FrameBuffer *input, FrameBuffer *output, DebayerParams params)\n>  {\n>         bench_.startFrame();\n> @@ -748,7 +850,7 @@ void DebayerCpu::process(uint32_t frame, FrameBuffer *input, FrameBuffer *output\n>  \n>         dmaSyncBegin(dmaSyncers, input, output);\n>  \n> -       setParams(params);\n> +       updateLookupTables(params);\n>  \n>         /* Copy metadata from the input buffer */\n>         FrameMetadata &metadata = output->_d()->metadata();\n> diff --git a/src/libcamera/software_isp/debayer_cpu.h b/src/libcamera/software_isp/debayer_cpu.h\n> index 67df2b93a..b5cbb5bd2 100644\n> --- a/src/libcamera/software_isp/debayer_cpu.h\n> +++ b/src/libcamera/software_isp/debayer_cpu.h\n> @@ -1,7 +1,7 @@\n>  /* SPDX-License-Identifier: LGPL-2.1-or-later */\n>  /*\n>   * Copyright (C) 2023, Linaro Ltd\n> - * Copyright (C) 2023-2025 Red Hat Inc.\n> + * Copyright (C) 2023-2026 Red Hat Inc.\n>   *\n>   * Authors:\n>   * Hans de Goede <hdegoede@redhat.com>\n> @@ -18,6 +18,8 @@\n>  #include <libcamera/base/object.h>\n>  \n>  #include \"libcamera/internal/bayer_format.h\"\n> +#include \"libcamera/internal/global_configuration.h\"\n> +#include \"libcamera/internal/software_isp/debayer_params.h\"\n>  #include \"libcamera/internal/software_isp/swstats_cpu.h\"\n>  \n>  #include \"debayer.h\"\n> @@ -108,10 +110,32 @@ private:\n>         void memcpyNextLine(const uint8_t *linePointers[]);\n>         void process2(uint32_t frame, const uint8_t *src, uint8_t *dst);\n>         void process4(uint32_t frame, const uint8_t *src, uint8_t *dst);\n> +       void updateGammaTable(DebayerParams &params);\n> +       void updateLookupTables(DebayerParams &params);\n>  \n>         /* Max. supported Bayer pattern height is 4, debayering this requires 5 lines */\n>         static constexpr unsigned int kMaxLineBuffers = 5;\n>  \n> +       static constexpr unsigned int kRGBLookupSize = 256;\n> +       static constexpr unsigned int kGammaLookupSize = 1024;\n> +       struct CcmColumn {\n> +               int16_t r;\n> +               int16_t g;\n> +               int16_t b;\n> +       };\n> +       using LookupTable = std::array<uint8_t, kRGBLookupSize>;\n> +       using CcmLookupTable = std::array<CcmColumn, kRGBLookupSize>;\n> +       LookupTable red_;\n> +       LookupTable green_;\n> +       LookupTable blue_;\n> +       CcmLookupTable redCcm_;\n> +       CcmLookupTable greenCcm_;\n> +       CcmLookupTable blueCcm_;\n> +       std::array<double, kGammaLookupSize> gammaTable_;\n> +       LookupTable gammaLut_;\n> +       bool ccmEnabled_;\n> +       DebayerParams params_;\n> +\n>         debayerFn debayer0_;\n>         debayerFn debayer1_;\n>         debayerFn debayer2_;\n> diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp\n> index 37c44e8b1..722778103 100644\n> --- a/src/libcamera/software_isp/debayer_egl.cpp\n> +++ b/src/libcamera/software_isp/debayer_egl.cpp\n> @@ -475,18 +475,18 @@ void DebayerEGL::setShaderVariableValues(DebayerParams &params)\n>                             << \" textureUniformProjMatrix_ \" << textureUniformProjMatrix_;\n>  \n>         GLfloat ccm[9] = {\n> -               params.ccm[0][0],\n> -               params.ccm[0][1],\n> -               params.ccm[0][2],\n> -               params.ccm[1][0],\n> -               params.ccm[1][1],\n> -               params.ccm[1][2],\n> -               params.ccm[2][0],\n> -               params.ccm[2][1],\n> -               params.ccm[2][2],\n> +               params.combinedMatrix[0][0],\n> +               params.combinedMatrix[0][1],\n> +               params.combinedMatrix[0][2],\n> +               params.combinedMatrix[1][0],\n> +               params.combinedMatrix[1][1],\n> +               params.combinedMatrix[1][2],\n> +               params.combinedMatrix[2][0],\n> +               params.combinedMatrix[2][1],\n> +               params.combinedMatrix[2][2],\n>         };\n>         glUniformMatrix3fv(ccmUniformDataIn_, 1, GL_FALSE, ccm);\n> -       LOG(Debayer, Debug) << \" ccmUniformDataIn_ \" << ccmUniformDataIn_ << \" data \" << params.ccm;\n> +       LOG(Debayer, Debug) << \" ccmUniformDataIn_ \" << ccmUniformDataIn_ << \" data \" << params.combinedMatrix;\n>  \n>         /*\n>          * 0 = Red, 1 = Green, 2 = Blue\n> @@ -544,8 +544,6 @@ void DebayerEGL::process(uint32_t frame, FrameBuffer *input, FrameBuffer *output\n>  \n>         dmaSyncBegin(dmaSyncers, input, nullptr);\n>  \n> -       setParams(params);\n> -\n>         /* Copy metadata from the input buffer */\n>         FrameMetadata &metadata = output->_d()->metadata();\n>         metadata.status = input->metadata().status;\n> diff --git a/src/libcamera/software_isp/software_isp.cpp b/src/libcamera/software_isp/software_isp.cpp\n> index 7ad3511db..a83986b78 100644\n> --- a/src/libcamera/software_isp/software_isp.cpp\n> +++ b/src/libcamera/software_isp/software_isp.cpp\n> @@ -84,23 +84,6 @@ SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, const CameraSensor *sensor,\n>                    DmaBufAllocator::DmaBufAllocatorFlag::SystemHeap |\n>                    DmaBufAllocator::DmaBufAllocatorFlag::UDmaBuf)\n>  {\n> -       /*\n> -        * debayerParams_ must be initialized because the initial value is used for\n> -        * the first two frames, i.e. until stats processing starts providing its\n> -        * own parameters.\n> -        *\n> -        * \\todo This should be handled in the same place as the related\n> -        * operations, in the IPA module.\n> -        */\n> -       std::array<uint8_t, 256> gammaTable;\n> -       for (unsigned int i = 0; i < 256; i++)\n> -               gammaTable[i] = UINT8_MAX * std::pow(i / 256.0, 0.5);\n> -       for (unsigned int i = 0; i < DebayerParams::kRGBLookupSize; i++) {\n> -               debayerParams_.red[i] = gammaTable[i];\n> -               debayerParams_.green[i] = gammaTable[i];\n> -               debayerParams_.blue[i] = gammaTable[i];\n> -       }\n> -\n>         if (!dmaHeap_.isValid()) {\n>                 LOG(SoftwareIsp, Error) << \"Failed to create DmaBufAllocator object\";\n>                 return;\n> @@ -121,8 +104,6 @@ SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, const CameraSensor *sensor,\n>         }\n>         stats->statsReady.connect(this, &SoftwareIsp::statsReady);\n>  \n> -       bool gpuIspEnabled;\n> -\n>  #if HAVE_DEBAYER_EGL\n>         std::optional<std::string> softISPMode = configuration.envOption(\"LIBCAMERA_SOFTISP_MODE\", { \"software_isp\", \"mode\" });\n>         if (softISPMode) {\n> @@ -133,15 +114,12 @@ SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, const CameraSensor *sensor,\n>                 }\n>         }\n>  \n> -       if (!softISPMode || softISPMode == \"gpu\") {\n> +       if (!softISPMode || softISPMode == \"gpu\")\n>                 debayer_ = std::make_unique<DebayerEGL>(std::move(stats), configuration);\n> -               gpuIspEnabled = true;\n> -       }\n> +\n>  #endif\n> -       if (!debayer_) {\n> +       if (!debayer_)\n>                 debayer_ = std::make_unique<DebayerCpu>(std::move(stats), configuration);\n> -               gpuIspEnabled = false;\n> -       }\n>  \n>         debayer_->inputBufferReady.connect(this, &SoftwareIsp::inputReady);\n>         debayer_->outputBufferReady.connect(this, &SoftwareIsp::outputReady);\n> @@ -173,7 +151,6 @@ SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, const CameraSensor *sensor,\n>                          sharedParams_.fd(),\n>                          sensorInfo,\n>                          sensor->controls(),\n> -                        gpuIspEnabled,\n>                          ipaControls,\n>                          &ccmEnabled_);\n>         if (ret) {\n> -- \n> 2.52.0\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 740A1C3226\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 28 Jan 2026 12:58:48 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id A841B61FD0;\n\tWed, 28 Jan 2026 13:58:47 +0100 (CET)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 2F96F61FC4\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 28 Jan 2026 13:58:46 +0100 (CET)","from pendragon.ideasonboard.com\n\t(cpc89244-aztw30-2-0-cust6594.18-1.cable.virginm.net [86.31.185.195])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 06335E70;\n\tWed, 28 Jan 2026 13:58:08 +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=\"p7GzyIjO\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1769605089;\n\tbh=BU6kkP7dOYiulmReBC2LPtvIQ5o+jc+wz7jblfZcE+o=;\n\th=In-Reply-To:References:Subject:From:Cc:To:Date:From;\n\tb=p7GzyIjObBNJGlHPF62gtJdDIgGORd+4llicOseRrdFozSYD1Hslu86wLST+dNCth\n\txNBVbEEJ0GSjLauLjl34xkE9YYbe9nSSIJDd5VXV3cDiPT+xp07ryycXYRPs3OZl2i\n\tmhTPdLxh/afn2p4GAV8HF2hFGwoGAL9lA8OEbZ7M=","Content-Type":"text/plain; charset=\"utf-8\"","MIME-Version":"1.0","Content-Transfer-Encoding":"quoted-printable","In-Reply-To":"<20260128114402.31570-15-mzamazal@redhat.com>","References":"<20260128114402.31570-1-mzamazal@redhat.com>\n\t<20260128114402.31570-15-mzamazal@redhat.com>","Subject":"Re: [PATCH v5 14/15] libcamera: ipa: simple: Remove Lut algorithm","From":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Cc":"Milan Zamazal <mzamazal@redhat.com>,\n\tRobert Mader <robert.mader@collabora.com>","To":"Milan Zamazal <mzamazal@redhat.com>, libcamera-devel@lists.libcamera.org","Date":"Wed, 28 Jan 2026 12:58:42 +0000","Message-ID":"<176960512266.3376561.8957030056680826249@ping.linuxembedded.co.uk>","User-Agent":"alot/0.9.1","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>"}}]