[{"id":39499,"web_url":"https://patchwork.libcamera.org/comment/39499/","msgid":"<178272772679.36676.11544520694646861766@ping.linuxembedded.co.uk>","date":"2026-06-29T10:08:46","subject":"Re: [PATCH v2 06/12] ipa: libipa: Add GammaAlgorithm class","submitter":{"id":4,"url":"https://patchwork.libcamera.org/api/people/4/","name":"Kieran Bingham","email":"kieran.bingham@ideasonboard.com"},"content":"Quoting Daniel Scally (2026-06-26 14:05:53)\n> Add a base GammaAlgorithm class that can be used by IPA specific\n> gamma algorithms to reduce the amount of work that they need to\n> implement.\n> \n> Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\n\nI'm interested to see where this goes, but having a common block looks\nuseful so:\n\n\nReviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n\n\n> Signed-off-by: Daniel Scally <dan.scally@ideasonboard.com>\n> ---\n> Changes in v2:\n> \n>         - Updated documentation comments, and minor styling changes\n> ---\n>  src/ipa/libipa/gamma.cpp   | 257 +++++++++++++++++++++++++++++++++++++++++++++\n>  src/ipa/libipa/gamma.h     |  94 +++++++++++++++++\n>  src/ipa/libipa/meson.build |   2 +\n>  3 files changed, 353 insertions(+)\n> \n> diff --git a/src/ipa/libipa/gamma.cpp b/src/ipa/libipa/gamma.cpp\n> new file mode 100644\n> index 0000000000000000000000000000000000000000..5fec5329a50f0b3dd0e39504dfbb63484ca4fcd9\n> --- /dev/null\n> +++ b/src/ipa/libipa/gamma.cpp\n> @@ -0,0 +1,257 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2026 Ideas on Board Oy\n> + *\n> + * libIPA Gamma correction algorithm\n> + */\n> +\n> +#include \"gamma.h\"\n> +\n> +#include <numeric>\n> +\n> +#include <libcamera/controls.h>\n> +\n> +#include \"libcamera/internal/value_node.h\"\n> +\n> +/**\n> + * \\file gamma.h\n> + * \\brief libipa implementation of a gamma curve correction algorithm\n> + */\n> +\n> +namespace libcamera {\n> +\n> +namespace ipa {\n> +\n> +LOG_DEFINE_CATEGORY(Gamma)\n> +\n> +namespace gamma {\n> +\n> +/**\n> + * \\struct ActiveState\n> + * \\brief Active gamma correction algorithm state\n> + *\n> + * \\var ActiveState::gamma\n> + * \\brief The gamma correction value\n> + */\n> +\n> +/**\n> + * \\struct FrameContext\n> + * \\brief Per-frame gamma correction settings\n> + *\n> + * \\var FrameContext::gamma\n> + * \\brief The gamma correction value applied for this frame\n> + *\n> + * \\var FrameContext::update\n> + * \\brief A flag instructing the algorithm to push an update to the hardware\n> + */\n> +\n> +} /* namespace gamma */\n> +\n> +/**\n> + * \\brief The default gamma correction value\n> + */\n> +const float kDefaultGamma = 2.2f;\n> +\n> +/**\n> + * \\class GammaAlgorithmBase\n> + * \\brief Base class for GammaAlgorithm to implement non-templated functions\n> + *\n> + * This base class for GammeaAlgorithm allows us to implement non templated\n> + * functions. IPA specific implementations shall derive from GammaAlgorithm and\n> + * not this class.\n> + */\n> +\n> +/**\n> + * \\fn GammaAlgorithmBase::GammaAlgorithmBase\n> + * \\brief Construct an instance of the class\n> + * \\param[in] nLutNodes Set the number of function knee-points expected by the\n> + * IPA algorithm\n> + */\n> +\n> +/**\n> + * \\brief Initialise the algorithm with the given tuning data\n> + * \\param[out] controls The ControlList into which this algorithm's supported\n> + * controls will be emplaced.\n> + * \\param[in] tuningData The tuning data to use with the algorithm\n> + * \\param[in] segments A vector of segment spacings to define a custom\n> + * X coordinate system for the curve\n> + *\n> + * Parse \\a tuningData and \\a segments to initialize the gamma correction curve.\n> + * The tuning data may contain a default gamma value to use; otherwise the value\n> + * of \\a kDefaultGamma will be taken as the default. The piecewise linear\n> + * function will be applied on a number of knots whose position is described by\n> + * the optional \\a segments argument, which describes each segment's relative\n> + * length.\n> + *\n> + * For example, if the gamma correction has to be applied on 16 equally spaced\n> + * sampling points, a \\segments array like:\n> + *\n> + * [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]\n> + *\n> + * would result in evenly spaced knee-points along the X-axis.\n> + *\n> + * Hardware may expect the knee-points to be spaced more densely towards the\n> + * start of the curve and more sparsely towards the end, in which case an\n> + * alternative array might be:\n> + *\n> + * [1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 8, 8, 8, 8, 8]\n> + *\n> + * As the values in \\a segments represent the distance between two knee-points\n> + * relative to the total distance between the first and last point, the length\n> + * of \\a segments should be equal to the number of knee-points minus one.\n> + *;\n> + * If an IPA implementation doesnt't provide \\a segments, the GammaAlgorithm\n> + * class consturcts an evenly-spaced default.\n> + *\n> + * IPA modules are expected to call this function as part of their\n> + * implementation of Algorithm::init()\n> + *\n> + * @return 0 on success, a negative error code otherwise\n> + */\n> +int GammaAlgorithmBase::init(ControlInfoMap::Map &controls, const ValueNode &tuningData,\n> +                            Span<unsigned int> segments)\n> +{\n> +       /*\n> +        * If the caller doesn't pass in a segment list we simply construct one\n> +        * with equally spaced segments. We need one less segment than we have\n> +        * LUT nodes.\n> +        */\n> +       unsigned int expectedNSegments = nLutNodes_ - 1;\n> +\n> +       if (segments.empty()) {\n> +               for (unsigned int i = 0; i < expectedNSegments; i++)\n> +                       segments_.push_back(1);\n> +       } else {\n> +               segments_.assign(segments.begin(), segments.end());\n> +       }\n> +\n> +       if (segments_.size() != expectedNSegments)\n> +               return -EINVAL;\n> +\n> +       segmentsSum_ = std::accumulate(segments_.begin(), segments_.end(), 0.0f);\n> +\n> +       defaultGamma_ = tuningData[\"gamma\"].get<double>(kDefaultGamma);\n> +       controls[&controls::Gamma] = ControlInfo(0.1f, 10.0f, defaultGamma_);\n> +\n> +       return 0;\n> +}\n> +\n> +/**\n> + * \\brief Configure the gamma correction algorithm\n> + * \\param[out] state The gamma correction algorithm's active state\n> + *\n> + * Reset to the default gamma correction value.\n> + *\n> + * IPA modules are expected to call this function as part of their\n> + * implementation of Algorithm::configure()\n> + */\n> +void GammaAlgorithmBase::configure(gamma::ActiveState &state)\n> +{\n> +       state.gamma = defaultGamma_;\n> +}\n> +\n> +/**\n> + * \\brief Queue a request to the gamma correction algorithm\n> + * \\param[in] state The algorithm's active state\n> + * \\param[in] frame The current frame number\n> + * \\param[in] context The algorithm's frame context\n> + * \\param[in] controls The ControlList that was queued with the request\n> + *\n> + * Queue a new request to the gamma correction algorithm and handle any relevant\n> + * controls that were queued. The only control currently handled is:\n> + *\n> + * - controls::Gamma\n> + *\n> + * If a control with that ID is queued the value is stored in \\a state and\n> + * \\a context.\n> + *\n> + * IPA modules are expected to call this function as part of their\n> + * implementation of Algorithm::queueRequest()\n> + */\n> +void GammaAlgorithmBase::queueRequest(gamma::ActiveState &state,\n> +                                     const uint32_t frame,\n> +                                     gamma::FrameContext &context,\n> +                                     const ControlList &controls)\n> +{\n> +       if (frame == 0)\n> +               context.update = true;\n> +\n> +       const auto &gamma = controls.get(controls::Gamma);\n> +       if (gamma) {\n> +               state.gamma = *gamma;\n> +               context.update = true;\n> +               LOG(Gamma, Info) << \"Set gamma to \" << *gamma;\n> +       }\n> +\n> +       context.gamma = state.gamma;\n> +}\n> +\n> +/**\n> + * \\brief Populate metadata with the gamma correction values for a frame\n> + * \\param[in] context The frame context\n> + * \\param[out] metadata The ControlList of metadata for a frame\n> + *\n> + * Report the gamma value used to calculate the correction curve that was\n> + * applied to a frame.\n> + */\n> +void GammaAlgorithmBase::process(gamma::FrameContext &context, ControlList &metadata)\n> +{\n> +       metadata.set(controls::Gamma, context.gamma);\n> +}\n> +\n> +/**\n> + * \\var GammaAlgorithmBase::nLutNodes_\n> + * \\brief The number of gamma LUT sampling points\n> + */\n> +\n> +/**\n> + * \\var GammaAlgorithmBase::defaultGamma_\n> + * \\brief The default gamma parameter\n> + */\n> +\n> +/**\n> + * \\var GammaAlgorithmBase::segments_\n> + * \\brief The vector of segment sizes describing the space between knee-points\n> + */\n> +\n> +/**\n> + * \\var GammaAlgorithmBase::segmentsSum_\n> + * \\brief The sum of \\a GammaAlgorithmBase::segments_\n> + */\n> +\n> +/**\n> + * \\class GammaAlgorithm\n> + * \\brief The libipa gamma correction algorithm\n> + * \\tparam nLutNodes The number of gamma LUT sampling points\n> + * \\tparam UQ The fixedpoint representation of the gamma correction values\n> + *\n> + * Gamma correction adjusts for the differences in the way light is perceived\n> + * by a camera and the human eye by applying a function to the input values.\n> + * The GammaAlgorithm class facilitates this by building a piecewise linear\n> + * function from a gamma parameter and supplying it in the hardware-specific\n> + * formats defined by the IPA algorithms.\n> + *\n> + * IPA modules are expected to store an instance of GammaAlgorithm as a class\n> + * member, templated with the format and number of knee-points in the PWL\n> + * expected by their hardware and then call its functions in their overload of\n> + * the Algorithm class's function.\n> + *\n> + * When an application queues a new value for the gamma parameter with a\n> + * Request, the GammaAlgorithm will recalculate and populate the new LUT to be\n> + * sent to the ISP.\n> + *\n> + * Useful links:\n> + * - https://www.cambridgeincolour.com/tutorials/gamma-correction.htm\n> + * - https://en.wikipedia.org/wiki/SRGB\n> + */\n> +\n> +/**\n> + * \\fn GammaAlgorithm::prepare()\n> + * \\tparam T The type of data expected by the hardware's look-up table\n> + * \\param[in] context The frame context\n> + * \\param[out] lut The Span into which to place the calculated look-up table\n> + */\n> +\n> +} /* namespace ipa */\n> +\n> +} /* namespace libcamera */\n> diff --git a/src/ipa/libipa/gamma.h b/src/ipa/libipa/gamma.h\n> new file mode 100644\n> index 0000000000000000000000000000000000000000..94be8c7a2328e7b5a3618b0d65989ee511cece09\n> --- /dev/null\n> +++ b/src/ipa/libipa/gamma.h\n> @@ -0,0 +1,94 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2026 Ideas on Board Oy\n> + *\n> + * libIPA Gamma correction algorithm\n> + */\n> +\n> +#pragma once\n> +\n> +#include <cmath>\n> +#include <vector>\n> +\n> +#include <libcamera/base/log.h>\n> +#include <libcamera/base/span.h>\n> +\n> +#include <libcamera/control_ids.h>\n> +\n> +#include \"libcamera/internal/value_node.h\"\n> +\n> +#include \"fixedpoint.h\"\n> +\n> +namespace libcamera {\n> +\n> +namespace ipa {\n> +\n> +LOG_DECLARE_CATEGORY(Gamma)\n> +\n> +namespace gamma {\n> +\n> +struct ActiveState {\n> +       double gamma;\n> +};\n> +\n> +struct FrameContext {\n> +       double gamma;\n> +       bool update;\n> +};\n> +\n> +} /* namespace gamma */\n> +\n> +class GammaAlgorithmBase\n> +{\n> +public:\n> +       GammaAlgorithmBase(unsigned int nLutNodes)\n> +               : nLutNodes_(nLutNodes)\n> +       {\n> +       }\n> +\n> +       int init(ControlInfoMap::Map &controls, const ValueNode &tuningData,\n> +                Span<unsigned int> segments = {});\n> +\n> +       void configure(gamma::ActiveState &state);\n> +       void queueRequest(gamma::ActiveState &state, const uint32_t frame,\n> +                         gamma::FrameContext &context, const ControlList &controls);\n> +       void process(gamma::FrameContext &context, ControlList &metadata);\n> +\n> +protected:\n> +       unsigned int nLutNodes_;\n> +       float defaultGamma_;\n> +       std::vector<unsigned int> segments_;\n> +       unsigned int segmentsSum_;\n> +};\n> +\n> +template<unsigned int nLutNodes, typename UQ>\n> +class GammaAlgorithm : public GammaAlgorithmBase\n> +{\n> +public:\n> +       GammaAlgorithm()\n> +               : GammaAlgorithmBase(nLutNodes)\n> +       {\n> +       }\n> +\n> +       template<typename T>\n> +       void prepare(gamma::FrameContext &context, Span<T> lut)\n> +       {\n> +               float x = 0;\n> +\n> +               for (unsigned int i = 0; i < nLutNodes_; i++) {\n> +                       float gamma = std::pow(x / segmentsSum_,\n> +                                              1.0 / context.gamma);\n> +                       lut[i] = UQ(gamma).quantized();\n> +\n> +                       LOG(Gamma, Debug) << \"LUT[\" << i << \"]=\" << gamma\n> +                                         << \"(\" << lut[i] << \")\";\n> +\n> +                       if (i < segments_.size())\n> +                               x += segments_[i];\n> +               }\n> +       }\n> +};\n> +\n> +} /* namespace ipa */\n> +\n> +} /* namespace libcamera */\n> diff --git a/src/ipa/libipa/meson.build b/src/ipa/libipa/meson.build\n> index da6ea0c5e13000f78b2196c7334610c350f1ad13..565da9be9059f2167d107061d643e58202e655ef 100644\n> --- a/src/ipa/libipa/meson.build\n> +++ b/src/ipa/libipa/meson.build\n> @@ -12,6 +12,7 @@ libipa_headers = files([\n>      'exposure_mode_helper.h',\n>      'fc_queue.h',\n>      'fixedpoint.h',\n> +    'gamma.h',\n>      'histogram.h',\n>      'interpolator.h',\n>      'lsc.h',\n> @@ -37,6 +38,7 @@ libipa_sources = files([\n>      'exposure_mode_helper.cpp',\n>      'fc_queue.cpp',\n>      'fixedpoint.cpp',\n> +    'gamma.cpp',\n>      'histogram.cpp',\n>      'interpolator.cpp',\n>      'lsc.cpp',\n> \n> -- \n> 2.43.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 8B28DC3261\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 29 Jun 2026 10:08:51 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id DEF5D65F1E;\n\tMon, 29 Jun 2026 12:08:50 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 0543B65F04\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 29 Jun 2026 12:08:50 +0200 (CEST)","from monstersaurus.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 C24CD34;\n\tMon, 29 Jun 2026 12:08:06 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"IfrAlg9z\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1782727686;\n\tbh=AgkeFL/+ED6kQDDQz38IfFRuBtIx9WwTnp0tr4VViwo=;\n\th=In-Reply-To:References:Subject:From:Cc:To:Date:From;\n\tb=IfrAlg9z+WN6niHFXuZwlHVQ7SV4kwAiTTzNCJz0+mq1+RzAh4CL0wG2chjgV83ma\n\tu5TKD2C9aF32icKMhT0DeQWaz42PQB94rlhdytGEQ3BMo13GH2+upngjNqpBcOwCqu\n\tzg/YKTdltKqI0QJrOjsb6bSWmpHnxsptbeJmJr3I=","Content-Type":"text/plain; charset=\"utf-8\"","MIME-Version":"1.0","Content-Transfer-Encoding":"quoted-printable","In-Reply-To":"<20260626-ipu3-libipa-rework-v2-6-41546e23de3e@ideasonboard.com>","References":"<20260626-ipu3-libipa-rework-v2-0-41546e23de3e@ideasonboard.com>\n\t<20260626-ipu3-libipa-rework-v2-6-41546e23de3e@ideasonboard.com>","Subject":"Re: [PATCH v2 06/12] ipa: libipa: Add GammaAlgorithm class","From":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Cc":"Daniel Scally <dan.scally@ideasonboard.com>,\n\tJacopo Mondi <jacopo.mondi@ideasonboard.com>","To":"Daniel Scally <dan.scally@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org","Date":"Mon, 29 Jun 2026 11:08:46 +0100","Message-ID":"<178272772679.36676.11544520694646861766@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>"}},{"id":39510,"web_url":"https://patchwork.libcamera.org/comment/39510/","msgid":"<b280b521-07fe-4936-a2fb-07a6a8f5af55@ideasonboard.com>","date":"2026-06-30T08:53:02","subject":"Re: [PATCH v2 06/12] ipa: libipa: Add GammaAlgorithm class","submitter":{"id":216,"url":"https://patchwork.libcamera.org/api/people/216/","name":"Barnabás Pőcze","email":"barnabas.pocze@ideasonboard.com"},"content":"2026. 06. 26. 15:05 keltezéssel, Daniel Scally írta:\n> Add a base GammaAlgorithm class that can be used by IPA specific\n> gamma algorithms to reduce the amount of work that they need to\n> implement.\n> \n> Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\n> Signed-off-by: Daniel Scally <dan.scally@ideasonboard.com>\n> ---\n> Changes in v2:\n> \n>          - Updated documentation comments, and minor styling changes\n> ---\n>   src/ipa/libipa/gamma.cpp   | 257 +++++++++++++++++++++++++++++++++++++++++++++\n>   src/ipa/libipa/gamma.h     |  94 +++++++++++++++++\n>   src/ipa/libipa/meson.build |   2 +\n>   3 files changed, 353 insertions(+)\n> \n> diff --git a/src/ipa/libipa/gamma.cpp b/src/ipa/libipa/gamma.cpp\n> new file mode 100644\n> index 0000000000000000000000000000000000000000..5fec5329a50f0b3dd0e39504dfbb63484ca4fcd9\n> --- /dev/null\n> +++ b/src/ipa/libipa/gamma.cpp\n> @@ -0,0 +1,257 @@\n> [...]\n> +/**\n> + * \\brief Queue a request to the gamma correction algorithm\n> + * \\param[in] state The algorithm's active state\n> + * \\param[in] frame The current frame number\n> + * \\param[in] context The algorithm's frame context\n> + * \\param[in] controls The ControlList that was queued with the request\n> + *\n> + * Queue a new request to the gamma correction algorithm and handle any relevant\n> + * controls that were queued. The only control currently handled is:\n> + *\n> + * - controls::Gamma\n> + *\n> + * If a control with that ID is queued the value is stored in \\a state and\n> + * \\a context.\n> + *\n> + * IPA modules are expected to call this function as part of their\n> + * implementation of Algorithm::queueRequest()\n> + */\n> +void GammaAlgorithmBase::queueRequest(gamma::ActiveState &state,\n> +\t\t\t\t      const uint32_t frame,\n> +\t\t\t\t      gamma::FrameContext &context,\n> +\t\t\t\t      const ControlList &controls)\n> +{\n> +\tif (frame == 0)\n> +\t\tcontext.update = true;\n\nIs there not a risk of dropping frame 0? I suppose as long as the request\nsequence number is used, this is guaranteed to work.\n\n\n> +\n> +\tconst auto &gamma = controls.get(controls::Gamma);\n> +\tif (gamma) {\n> +\t\tstate.gamma = *gamma;\n> +\t\tcontext.update = true;\n> +\t\tLOG(Gamma, Info) << \"Set gamma to \" << *gamma;\n> +\t}\n> +\n> +\tcontext.gamma = state.gamma;\n> +}\n> [...]\n> diff --git a/src/ipa/libipa/gamma.h b/src/ipa/libipa/gamma.h\n> new file mode 100644\n> index 0000000000000000000000000000000000000000..94be8c7a2328e7b5a3618b0d65989ee511cece09\n> --- /dev/null\n> +++ b/src/ipa/libipa/gamma.h\n> @@ -0,0 +1,94 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2026 Ideas on Board Oy\n> + *\n> + * libIPA Gamma correction algorithm\n> + */\n> +\n> +#pragma once\n> +\n> +#include <cmath>\n> +#include <vector>\n> +\n> +#include <libcamera/base/log.h>\n> +#include <libcamera/base/span.h>\n> +\n> +#include <libcamera/control_ids.h>\n> +\n> +#include \"libcamera/internal/value_node.h\"\n> +\n> +#include \"fixedpoint.h\"\n> +\n> +namespace libcamera {\n> +\n> +namespace ipa {\n> +\n> +LOG_DECLARE_CATEGORY(Gamma)\n> +\n> +namespace gamma {\n> +\n> +struct ActiveState {\n> +\tdouble gamma;\n> +};\n> +\n> +struct FrameContext {\n> +\tdouble gamma;\n> +\tbool update;\n> +};\n> +\n> +} /* namespace gamma */\n> +\n> +class GammaAlgorithmBase\n> +{\n> +public:\n> +\tGammaAlgorithmBase(unsigned int nLutNodes)\n> +\t\t: nLutNodes_(nLutNodes)\n> +\t{\n> +\t}\n> +\n> +\tint init(ControlInfoMap::Map &controls, const ValueNode &tuningData,\n> +\t\t Span<unsigned int> segments = {});\n> +\n> +\tvoid configure(gamma::ActiveState &state);\n> +\tvoid queueRequest(gamma::ActiveState &state, const uint32_t frame,\n> +\t\t\t  gamma::FrameContext &context, const ControlList &controls);\n> +\tvoid process(gamma::FrameContext &context, ControlList &metadata);\n> +\n> +protected:\n> +\tunsigned int nLutNodes_;\n> +\tfloat defaultGamma_;\n> +\tstd::vector<unsigned int> segments_;\n> +\tunsigned int segmentsSum_;\n> +};\n> +\n> +template<unsigned int nLutNodes, typename UQ>\n\nShould template arguments be always camel case? I suppose this is a question\nfor the style guide.\n\n\n> +class GammaAlgorithm : public GammaAlgorithmBase\n> +{\n> +public:\n> +\tGammaAlgorithm()\n> +\t\t: GammaAlgorithmBase(nLutNodes)\n> +\t{\n> +\t}\n> +\n> +\ttemplate<typename T>\n> +\tvoid prepare(gamma::FrameContext &context, Span<T> lut)\n\nThis could be `Span<T, nLutNodes>` to enforce the size. Feels like a worthwhile\nchange to me, even if creating a spans becomes a bit bit more convoluted.\n\n\n> +\t{\n> +\t\tfloat x = 0;\n> +\n> +\t\tfor (unsigned int i = 0; i < nLutNodes_; i++) {\n> +\t\t\tfloat gamma = std::pow(x / segmentsSum_,\n> +\t\t\t\t\t       1.0 / context.gamma);\n> +\t\t\tlut[i] = UQ(gamma).quantized();\n> +\n> +\t\t\tLOG(Gamma, Debug) << \"LUT[\" << i << \"]=\" << gamma\n> +\t\t\t\t\t  << \"(\" << lut[i] << \")\";\n> +\n> +\t\t\tif (i < segments_.size())\n> +\t\t\t\tx += segments_[i];\n> +\t\t}\n> +\t}\n> +};\n> +\n> +} /* namespace ipa */\n> +\n> +} /* namespace libcamera */\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 5783EC3264\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 30 Jun 2026 08:53:10 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 2517D65F46;\n\tTue, 30 Jun 2026 10:53:09 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id D7A04658C5\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 30 Jun 2026 10:53:07 +0200 (CEST)","from [192.168.33.31] (185.221.140.128.nat.pool.zt.hu\n\t[185.221.140.128])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 7DF96D52;\n\tTue, 30 Jun 2026 10:52:23 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"RlEmwc3j\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1782809544;\n\tbh=rN0nwKmMGyzrDaoK/vcFtT3zFEp8tG9MS8BJbPfr0U8=;\n\th=Date:Subject:To:Cc:References:From:In-Reply-To:From;\n\tb=RlEmwc3jlMVlw+CSSXj4/UU3mvIzltukWE5qs+Qbs6M8HxxMOj72FUoX5WMHwp/+U\n\txscsromS7o7ukMJDhE1v6+cO4pCxmmehMwl3slDKu6kpWIFxCNWuaY4xHI2/DQKeuq\n\tW1Q6ROpwBcTmw7pGkWXKXN/fVJBXbfgkc9za0q5M=","Message-ID":"<b280b521-07fe-4936-a2fb-07a6a8f5af55@ideasonboard.com>","Date":"Tue, 30 Jun 2026 10:53:02 +0200","MIME-Version":"1.0","User-Agent":"Mozilla Thunderbird","Subject":"Re: [PATCH v2 06/12] ipa: libipa: Add GammaAlgorithm class","To":"Daniel Scally <dan.scally@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org","Cc":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>","References":"<20260626-ipu3-libipa-rework-v2-0-41546e23de3e@ideasonboard.com>\n\t<20260626-ipu3-libipa-rework-v2-6-41546e23de3e@ideasonboard.com>","From":"=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <barnabas.pocze@ideasonboard.com>","Content-Language":"en-US, hu-HU","In-Reply-To":"<20260626-ipu3-libipa-rework-v2-6-41546e23de3e@ideasonboard.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>"}}]