[{"id":36832,"web_url":"https://patchwork.libcamera.org/comment/36832/","msgid":"<9e57aad9-5182-47e8-b644-4a27ecadec15@ideasonboard.com>","date":"2025-11-14T18:08:09","subject":"Re: [PATCH v4 03/21] ipa: libipa: Provide fixed point quantized\n\ttraits","submitter":{"id":216,"url":"https://patchwork.libcamera.org/api/people/216/","name":"Barnabás Pőcze","email":"barnabas.pocze@ideasonboard.com"},"content":"2025. 11. 14. 1:54 keltezéssel, Kieran Bingham írta:\n> Extend the new Quantized type infrastructure by providing a\n> FixedPointQTraits template.\n> \n> This allows construction of fixed point types with a Quantized storage\n> that allows easy reading of both the underlying quantized type value and\n> a floating point representation of that same value.\n> \n> Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n> \n> ---\n> v4:\n> - Assert that the given type has enough bits for the usage\n> - Use unsigned types for calculating qmin/qmax\n> - Reorder toFloat/fromFloat and min/max for future inlining\n> - Make toFloat and fromFloat constexpr\n> \n>   src/ipa/libipa/fixedpoint.cpp | 121 ++++++++++++++++++++++++++++++++++\n>   src/ipa/libipa/fixedpoint.h   |  45 +++++++++++++\n>   2 files changed, 166 insertions(+)\n> \n> diff --git a/src/ipa/libipa/fixedpoint.cpp b/src/ipa/libipa/fixedpoint.cpp\n> index 6b698fc5d680..4c3ea33497bf 100644\n> --- a/src/ipa/libipa/fixedpoint.cpp\n> +++ b/src/ipa/libipa/fixedpoint.cpp\n> @@ -37,6 +37,127 @@ namespace ipa {\n>    * \\return The converted value\n>    */\n>   \n> +/**\n> + * \\struct libcamera::ipa::FixedPointQTraits\n> + * \\brief Traits type implementing fixed-point quantisation conversions\n> + *\n> + * The FixedPointQTraits structure defines a policy for mapping floating-point\n> + * values to and from fixed-point integer representations. It is parameterised\n> + * by the number of integer bits \\a I, fractional bits \\a F, and the integral\n> + * storage type \\a T. The traits are used with Quantized<Traits> to create a\n> + * quantised type that stores both the fixed-point representation and the\n> + * corresponding floating-point value.\n> + *\n> + * The trait exposes compile-time constants describing the bit layout, limits,\n> + * and scaling factors used in the fixed-point representation.\n> + *\n> + * \\tparam I Number of integer bits\n> + * \\tparam F Number of fractional bits\n> + * \\tparam T Integral type used to store the quantised value\n> + */\n> +\n> +/**\n> + * \\typedef FixedPointQTraits::QuantizedType\n> + * \\brief The integral storage type used for the fixed-point representation\n> + */\n> +\n> +/**\n> + * \\typedef FixedPointQTraits::UT\n> + * \\brief The unsigned representation of the integral storage\n> + *\n> + * This type definition is to support internal usage only.\n> + */\n> +\n> +/**\n> + * \\var FixedPointQTraits::Bits\n> + * \\brief Total number of bits used in the fixed-point format (I + F)\n> + */\n> +\n> +/**\n> + * \\var FixedPointQTraits::BitMask\n> + * \\brief Bit mask selecting all valid bits in the fixed-point representation\n> + */\n> +\n> +/**\n> + * \\var FixedPointQTraits::qmin\n> + * \\brief Minimum representable quantised integer value\n> + *\n> + * This corresponds to the most negative value for signed formats or zero for\n> + * unsigned formats.\n> + */\n> +\n> +/**\n> + * \\var FixedPointQTraits::qmax\n> + * \\brief Maximum representable quantised integer value\n> + */\n> +\n> +/**\n> + * \\var FixedPointQTraits::min\n> + * \\brief Minimum representable floating-point value corresponding to qmin\n> + */\n> +\n> +/**\n> + * \\var FixedPointQTraits::max\n> + * \\brief Maximum representable floating-point value corresponding to qmax\n> + */\n> +\n> +/**\n> + * \\fn FixedPointQTraits::fromFloat(float v)\n> + * \\brief Convert a floating-point value to a fixed-point integer\n> + * \\param[in] v The floating-point value to be converted\n> + * \\return The quantised fixed-point integer representation\n> + *\n> + * The conversion rounds the floating-point input \\a v to the nearest integer\n> + * according to the scaling factor defined by the number of fractional bits F.\n> + */\n> +\n> +/**\n> + * \\fn FixedPointQTraits::toFloat(QuantizedType q)\n> + * \\brief Convert a fixed-point integer to a floating-point value\n> + * \\param[in] q The fixed-point integer value to be converted\n> + * \\return The corresponding floating-point value\n> + *\n> + * The conversion sign-extends the integer value if required and divides by the\n> + * scaling factor defined by the number of fractional bits F.\n> + */\n> +\n> +/**\n> + * \\typedef Q1_7\n> + * \\brief 1.7 signed fixed-point quantizer\n> + *\n> + * A Quantized type using 1 bit for the integer part and 7 bits for the\n> + * fractional part, stored in a signed 8-bit integer (\\c int8_t). Represents\n> + * values approximately in the range [-1.0, 0.992] with a resolution of 1/128.\n> + */\n> +\n> +/**\n> + * \\typedef UQ1_7\n> + * \\brief 1.7 unsigned fixed-point quantizer\n> + *\n> + * A Quantized type using 1 bit for the integer part and 7 bits for the\n> + * fractional part, stored in an unsigned 8-bit integer (\\c uint8_t). Represents\n> + * values in the range [0.0, 1.992] with a resolution of 1/128.\n> + */\n> +\n> +/**\n> + * \\typedef Q12_4\n> + * \\brief 12.4 signed fixed-point quantizer\n> + *\n> + * A Quantized type using 12 bits for the integer part and 4 bits for the\n> + * fractional part, stored in a signed 16-bit integer (\\c int16_t). Represents\n> + * values in the range approximately [-2048.0, 2047.9375] with a resolution of\n> + * 1/16.\n> + */\n> +\n> +/**\n> + * \\typedef UQ12_4\n> + * \\brief 12.4 unsigned fixed-point quantizer\n> + *\n> + * A Quantized type using 12 bits for the integer part and 4 bits for the\n> + * fractional part, stored in an unsigned 16-bit integer (\\c uint16_t).\n> + * Represents values in the range [0.0, 4095.9375] with a resolution of 1/16.\n> + */\n> +\n>   } /* namespace ipa */\n>   \n>   } /* namespace libcamera */\n> diff --git a/src/ipa/libipa/fixedpoint.h b/src/ipa/libipa/fixedpoint.h\n> index 709cf50f0fcd..17db8a026502 100644\n> --- a/src/ipa/libipa/fixedpoint.h\n> +++ b/src/ipa/libipa/fixedpoint.h\n> @@ -10,6 +10,8 @@\n>   #include <cmath>\n>   #include <type_traits>\n>   \n> +#include \"quantized.h\"\n> +\n>   namespace libcamera {\n>   \n>   namespace ipa {\n> @@ -60,6 +62,49 @@ constexpr R fixedToFloatingPoint(T number)\n>   \treturn static_cast<R>(t) / static_cast<R>(1 << F);\n>   }\n>   \n> +template<unsigned int I, unsigned int F, typename T>\n> +struct FixedPointQTraits {\n> +\tstatic_assert(std::is_integral_v<T>, \"FixedPointQTraits: T must be integral\");\n> +\tusing QuantizedType = T;\n> +\tusing UT = std::make_unsigned_t<T>;\n> +\n> +\tstatic constexpr unsigned int Bits = I + F;\n> +\tstatic_assert(Bits <= sizeof(T) * 8, \"FixedPointQTraits: too many bits for type T\");\n> +\n> +\tstatic constexpr T BitMask = (Bits < sizeof(T) * 8)\n> +\t\t\t\t   ? static_cast<T>((UT{1} << Bits) - 1)\n> +\t\t\t\t   : static_cast<T>(~UT{0});\n\nI think `UT`, `Bits`, `BitMask` could very well be private.\n\n\n> +\n> +\tstatic constexpr T qmin = std::is_signed_v<T>\n> +\t\t\t\t? static_cast<T>(-(UT{1} << (Bits - 1)))\n> +\t\t\t\t: static_cast<T>(0);\n> +\n> +\tstatic constexpr T qmax = std::is_signed_v<T>\n> +\t\t\t\t? static_cast<T>((UT{1} << (Bits - 1)) - 1)\n> +\t\t\t\t: static_cast<T>((UT{1} << Bits) - 1);\n> +\n> +\tstatic constexpr float toFloat(QuantizedType q)\n> +\t{\n> +\t\treturn fixedToFloatingPoint<I, F, float, QuantizedType>(q);\n> +\t}\n> +\n> +\tstatic constexpr float min = fixedToFloatingPoint<I, F, float>(qmin);\n> +\tstatic constexpr float max = fixedToFloatingPoint<I, F, float>(qmax);\n> +\n> +\t/* Conversion functions required by Quantized<Traits> */\n> +\tstatic constexpr QuantizedType fromFloat(float v)\n> +\t{\n> +\t\tv = std::clamp(v, min, max);\n> +\t\treturn floatingToFixedPoint<I, F, QuantizedType, float>(v);\n> +\t}\n> +};\n> +\n> +using Q1_7 = Quantized<FixedPointQTraits<1, 7, int8_t>>;\n> +using UQ1_7 = Quantized<FixedPointQTraits<1, 7, uint8_t>>;\n> +\n> +using Q12_4 = Quantized<FixedPointQTraits<12, 4, int16_t>>;\n> +using UQ12_4 = Quantized<FixedPointQTraits<12, 4, uint16_t>>;\n> +\n>   } /* namespace ipa */\n>   \n>   } /* namespace libcamera */","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 2746AC3263\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri, 14 Nov 2025 18:08:13 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id C19DA60A8B;\n\tFri, 14 Nov 2025 19:08:12 +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 81D4A60A86\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 14 Nov 2025 19:08:10 +0100 (CET)","from [192.168.33.35] (185.221.143.100.nat.pool.zt.hu\n\t[185.221.143.100])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 827B9397;\n\tFri, 14 Nov 2025 19:06:09 +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=\"kgjW5/47\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1763143569;\n\tbh=885siUAefsAFdIb0+NdAfL4AcjIqg5BF82XRCvpb1sE=;\n\th=Date:Subject:To:References:From:In-Reply-To:From;\n\tb=kgjW5/47wnDac+PYdCCti5slSlHfOGvqxAKXGXrI2aX4f88n7d7gf/h595khBpp4+\n\tQLgkO0iC2ysckxGZfmFyJABLzsXeeIIpPpDRdkw1X3oR41rmPJ6eWVJfy1yOLTTFI3\n\tcNUhEuhXlTw3lBzwLPBWoisoEeXtkpkLD8YzPF3A=","Message-ID":"<9e57aad9-5182-47e8-b644-4a27ecadec15@ideasonboard.com>","Date":"Fri, 14 Nov 2025 19:08:09 +0100","MIME-Version":"1.0","User-Agent":"Mozilla Thunderbird","Subject":"Re: [PATCH v4 03/21] ipa: libipa: Provide fixed point quantized\n\ttraits","To":"Kieran Bingham <kieran.bingham@ideasonboard.com>,\n\tlibcamera devel <libcamera-devel@lists.libcamera.org>","References":"<20251114005428.90024-1-kieran.bingham@ideasonboard.com>\n\t<20251114005428.90024-4-kieran.bingham@ideasonboard.com>","From":"=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <barnabas.pocze@ideasonboard.com>","Content-Language":"en-US, hu-HU, en-GB","In-Reply-To":"<20251114005428.90024-4-kieran.bingham@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>"}},{"id":36853,"web_url":"https://patchwork.libcamera.org/comment/36853/","msgid":"<ac64d595-f5b5-4f8b-bd3a-e8a58bff4480@ideasonboard.com>","date":"2025-11-17T11:27:23","subject":"Re: [PATCH v4 03/21] ipa: libipa: Provide fixed point quantized\n\ttraits","submitter":{"id":216,"url":"https://patchwork.libcamera.org/api/people/216/","name":"Barnabás Pőcze","email":"barnabas.pocze@ideasonboard.com"},"content":"2025. 11. 14. 19:08 keltezéssel, Barnabás Pőcze írta:\n> 2025. 11. 14. 1:54 keltezéssel, Kieran Bingham írta:\n>> Extend the new Quantized type infrastructure by providing a\n>> FixedPointQTraits template.\n>>\n>> This allows construction of fixed point types with a Quantized storage\n>> that allows easy reading of both the underlying quantized type value and\n>> a floating point representation of that same value.\n>>\n>> Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n>>\n>> ---\n>> v4:\n>> - Assert that the given type has enough bits for the usage\n>> - Use unsigned types for calculating qmin/qmax\n>> - Reorder toFloat/fromFloat and min/max for future inlining\n>> - Make toFloat and fromFloat constexpr\n>>\n>>   src/ipa/libipa/fixedpoint.cpp | 121 ++++++++++++++++++++++++++++++++++\n>>   src/ipa/libipa/fixedpoint.h   |  45 +++++++++++++\n>>   2 files changed, 166 insertions(+)\n>>\n> [...]\n>> diff --git a/src/ipa/libipa/fixedpoint.h b/src/ipa/libipa/fixedpoint.h\n>> index 709cf50f0fcd..17db8a026502 100644\n>> --- a/src/ipa/libipa/fixedpoint.h\n>> +++ b/src/ipa/libipa/fixedpoint.h\n>> @@ -10,6 +10,8 @@\n>>   #include <cmath>\n>>   #include <type_traits>\n>> +#include \"quantized.h\"\n>> +\n>>   namespace libcamera {\n>>   namespace ipa {\n>> @@ -60,6 +62,49 @@ constexpr R fixedToFloatingPoint(T number)\n>>       return static_cast<R>(t) / static_cast<R>(1 << F);\n>>   }\n>> +template<unsigned int I, unsigned int F, typename T>\n>> +struct FixedPointQTraits {\n>> +    static_assert(std::is_integral_v<T>, \"FixedPointQTraits: T must be integral\");\n>> +    using QuantizedType = T;\n>> +    using UT = std::make_unsigned_t<T>;\n>> +\n>> +    static constexpr unsigned int Bits = I + F;\n>> +    static_assert(Bits <= sizeof(T) * 8, \"FixedPointQTraits: too many bits for type T\");\n>> +\n>> +    static constexpr T BitMask = (Bits < sizeof(T) * 8)\n>> +                   ? static_cast<T>((UT{1} << Bits) - 1)\n>> +                   : static_cast<T>(~UT{0});\n> \n> I think `UT`, `Bits`, `BitMask` could very well be private.\n> \n> \n>> +\n>> +    static constexpr T qmin = std::is_signed_v<T>\n>> +                ? static_cast<T>(-(UT{1} << (Bits - 1)))\n>> +                : static_cast<T>(0);\n>> +\n>> +    static constexpr T qmax = std::is_signed_v<T>\n>> +                ? static_cast<T>((UT{1} << (Bits - 1)) - 1)\n>> +                : static_cast<T>((UT{1} << Bits) - 1);\n>> +\n>> +    static constexpr float toFloat(QuantizedType q)\n>> +    {\n>> +        return fixedToFloatingPoint<I, F, float, QuantizedType>(q);\n>> +    }\n>> +\n>> +    static constexpr float min = fixedToFloatingPoint<I, F, float>(qmin);\n>> +    static constexpr float max = fixedToFloatingPoint<I, F, float>(qmax);\n>> +\n>> +    /* Conversion functions required by Quantized<Traits> */\n>> +    static constexpr QuantizedType fromFloat(float v)\n\n`floatingToFixedPoint()` can't really be `constexpr` because `std::round`\nis not (before C++23), so this cannot be `constexpr` either.\n\n\n>> +    {\n>> +        v = std::clamp(v, min, max);\n>> +        return floatingToFixedPoint<I, F, QuantizedType, float>(v);\n>> +    }\n>> +};\n>> +\n>> +using Q1_7 = Quantized<FixedPointQTraits<1, 7, int8_t>>;\n>> +using UQ1_7 = Quantized<FixedPointQTraits<1, 7, uint8_t>>;\n>> +\n>> +using Q12_4 = Quantized<FixedPointQTraits<12, 4, int16_t>>;\n>> +using UQ12_4 = Quantized<FixedPointQTraits<12, 4, uint16_t>>;\n>> +\n>>   } /* namespace ipa */\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 AE1CDC0F1B\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 17 Nov 2025 11:27:32 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 93C9360A80;\n\tMon, 17 Nov 2025 12:27:31 +0100 (CET)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 1DEEB60856\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 17 Nov 2025 12:27:30 +0100 (CET)","from [192.168.33.31] (185.221.143.100.nat.pool.zt.hu\n\t[185.221.143.100])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id D5608B5;\n\tMon, 17 Nov 2025 12:25:26 +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=\"QzDJ7hz0\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1763378727;\n\tbh=mgtKcAU6f8Jjnj4cGjpmv+sQ0VCakNKu7MsqmvAfhzk=;\n\th=Date:Subject:From:To:References:In-Reply-To:From;\n\tb=QzDJ7hz04qGRBSbSyUG2xM/B83gbqAycunf/TUiVB9hnWzbc/JS+o9gntTK3rZxGj\n\t56CI1YNv8LtB6GH9/61WfQHBQCSt02jSyVD20VQELImuNamYPYCqVSSxFnuiqINe61\n\tsxosVu0zwlz/jm67syvKD2lxRpmvIsZXVhY/oNk4=","Message-ID":"<ac64d595-f5b5-4f8b-bd3a-e8a58bff4480@ideasonboard.com>","Date":"Mon, 17 Nov 2025 12:27:23 +0100","MIME-Version":"1.0","User-Agent":"Mozilla Thunderbird","Subject":"Re: [PATCH v4 03/21] ipa: libipa: Provide fixed point quantized\n\ttraits","From":"=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <barnabas.pocze@ideasonboard.com>","To":"Kieran Bingham <kieran.bingham@ideasonboard.com>,\n\tlibcamera devel <libcamera-devel@lists.libcamera.org>","References":"<20251114005428.90024-1-kieran.bingham@ideasonboard.com>\n\t<20251114005428.90024-4-kieran.bingham@ideasonboard.com>\n\t<9e57aad9-5182-47e8-b644-4a27ecadec15@ideasonboard.com>","Content-Language":"en-US, hu-HU","In-Reply-To":"<9e57aad9-5182-47e8-b644-4a27ecadec15@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>"}},{"id":36859,"web_url":"https://patchwork.libcamera.org/comment/36859/","msgid":"<176338180326.1979555.16502881131097711089@ping.linuxembedded.co.uk>","date":"2025-11-17T12:16:43","subject":"Re: [PATCH v4 03/21] ipa: libipa: Provide fixed point quantized\n\ttraits","submitter":{"id":4,"url":"https://patchwork.libcamera.org/api/people/4/","name":"Kieran Bingham","email":"kieran.bingham@ideasonboard.com"},"content":"Quoting Barnabás Pőcze (2025-11-17 11:27:23)\n> 2025. 11. 14. 19:08 keltezéssel, Barnabás Pőcze írta:\n> > 2025. 11. 14. 1:54 keltezéssel, Kieran Bingham írta:\n> >> Extend the new Quantized type infrastructure by providing a\n> >> FixedPointQTraits template.\n> >>\n> >> This allows construction of fixed point types with a Quantized storage\n> >> that allows easy reading of both the underlying quantized type value and\n> >> a floating point representation of that same value.\n> >>\n> >> Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n> >>\n> >> ---\n> >> v4:\n> >> - Assert that the given type has enough bits for the usage\n> >> - Use unsigned types for calculating qmin/qmax\n> >> - Reorder toFloat/fromFloat and min/max for future inlining\n> >> - Make toFloat and fromFloat constexpr\n> >>\n> >>   src/ipa/libipa/fixedpoint.cpp | 121 ++++++++++++++++++++++++++++++++++\n> >>   src/ipa/libipa/fixedpoint.h   |  45 +++++++++++++\n> >>   2 files changed, 166 insertions(+)\n> >>\n> > [...]\n> >> diff --git a/src/ipa/libipa/fixedpoint.h b/src/ipa/libipa/fixedpoint.h\n> >> index 709cf50f0fcd..17db8a026502 100644\n> >> --- a/src/ipa/libipa/fixedpoint.h\n> >> +++ b/src/ipa/libipa/fixedpoint.h\n> >> @@ -10,6 +10,8 @@\n> >>   #include <cmath>\n> >>   #include <type_traits>\n> >> +#include \"quantized.h\"\n> >> +\n> >>   namespace libcamera {\n> >>   namespace ipa {\n> >> @@ -60,6 +62,49 @@ constexpr R fixedToFloatingPoint(T number)\n> >>       return static_cast<R>(t) / static_cast<R>(1 << F);\n> >>   }\n> >> +template<unsigned int I, unsigned int F, typename T>\n> >> +struct FixedPointQTraits {\n> >> +    static_assert(std::is_integral_v<T>, \"FixedPointQTraits: T must be integral\");\n> >> +    using QuantizedType = T;\n> >> +    using UT = std::make_unsigned_t<T>;\n> >> +\n> >> +    static constexpr unsigned int Bits = I + F;\n> >> +    static_assert(Bits <= sizeof(T) * 8, \"FixedPointQTraits: too many bits for type T\");\n> >> +\n> >> +    static constexpr T BitMask = (Bits < sizeof(T) * 8)\n> >> +                   ? static_cast<T>((UT{1} << Bits) - 1)\n> >> +                   : static_cast<T>(~UT{0});\n> > \n> > I think `UT`, `Bits`, `BitMask` could very well be private.\n\nExcellent point.\n\n> >> +\n> >> +    static constexpr T qmin = std::is_signed_v<T>\n> >> +                ? static_cast<T>(-(UT{1} << (Bits - 1)))\n> >> +                : static_cast<T>(0);\n> >> +\n> >> +    static constexpr T qmax = std::is_signed_v<T>\n> >> +                ? static_cast<T>((UT{1} << (Bits - 1)) - 1)\n> >> +                : static_cast<T>((UT{1} << Bits) - 1);\n> >> +\n> >> +    static constexpr float toFloat(QuantizedType q)\n> >> +    {\n> >> +        return fixedToFloatingPoint<I, F, float, QuantizedType>(q);\n> >> +    }\n> >> +\n> >> +    static constexpr float min = fixedToFloatingPoint<I, F, float>(qmin);\n> >> +    static constexpr float max = fixedToFloatingPoint<I, F, float>(qmax);\n> >> +\n> >> +    /* Conversion functions required by Quantized<Traits> */\n> >> +    static constexpr QuantizedType fromFloat(float v)\n> \n> `floatingToFixedPoint()` can't really be `constexpr` because `std::round`\n> is not (before C++23), so this cannot be `constexpr` either.\n\n\n\nPhew ... I got /reaaaaally/ scared there thinking that was going to\nbreak my constexprs for defining min and max in the type.\n\nIf it's just fromFloat that can't be constexpr - I think that might not\nbe 'as bad'. Perhaps just 'sad'.\n\nI'll remove constexpr here and leave a note that it can be made\nconstexpr in C++23.\n\nWill this break the static initialisation/usage in other ways?\n\n\n> >> +    {\n> >> +        v = std::clamp(v, min, max);\n> >> +        return floatingToFixedPoint<I, F, QuantizedType, float>(v);\n> >> +    }\n> >> +};\n> >> +\n> >> +using Q1_7 = Quantized<FixedPointQTraits<1, 7, int8_t>>;\n> >> +using UQ1_7 = Quantized<FixedPointQTraits<1, 7, uint8_t>>;\n> >> +\n> >> +using Q12_4 = Quantized<FixedPointQTraits<12, 4, int16_t>>;\n> >> +using UQ12_4 = Quantized<FixedPointQTraits<12, 4, uint16_t>>;\n> >> +\n> >>   } /* namespace ipa */\n> >>   } /* namespace libcamera */\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 6308BBD80A\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 17 Nov 2025 12:16:49 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 7B54960A81;\n\tMon, 17 Nov 2025 13:16:48 +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 BAD3660856\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 17 Nov 2025 13:16: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 778D342B;\n\tMon, 17 Nov 2025 13:14:43 +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=\"V2vH9E7H\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1763381683;\n\tbh=FTEs0G88b6EMcFIIPLm3mJ0cHT+zmG/IBVKxhBFvLiY=;\n\th=In-Reply-To:References:Subject:From:To:Date:From;\n\tb=V2vH9E7H6r54Lre/44q3ehB/vQg2AfM4AsT0fZJLQEZ5YkFRcKaBc4Ic1hh1t0MLL\n\t2vmeJGe9EktV1dmJCfmnS9c96Cmo/zYcZ82GlsUNe7rzAaX8qJrKQwQUa9YGGkjC3i\n\tQrrQmxzNzsGaxZn2A1VzllVfE+p1H+EeraTPNDkk=","Content-Type":"text/plain; charset=\"utf-8\"","MIME-Version":"1.0","Content-Transfer-Encoding":"quoted-printable","In-Reply-To":"<ac64d595-f5b5-4f8b-bd3a-e8a58bff4480@ideasonboard.com>","References":"<20251114005428.90024-1-kieran.bingham@ideasonboard.com>\n\t<20251114005428.90024-4-kieran.bingham@ideasonboard.com>\n\t<9e57aad9-5182-47e8-b644-4a27ecadec15@ideasonboard.com>\n\t<ac64d595-f5b5-4f8b-bd3a-e8a58bff4480@ideasonboard.com>","Subject":"Re: [PATCH v4 03/21] ipa: libipa: Provide fixed point quantized\n\ttraits","From":"Kieran Bingham <kieran.bingham@ideasonboard.com>","To":"=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <barnabas.pocze@ideasonboard.com>,\n\tlibcamera devel <libcamera-devel@lists.libcamera.org>","Date":"Mon, 17 Nov 2025 12:16:43 +0000","Message-ID":"<176338180326.1979555.16502881131097711089@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":36860,"web_url":"https://patchwork.libcamera.org/comment/36860/","msgid":"<79cdd5d2-5dfe-4aa0-af64-7d63ca753873@ideasonboard.com>","date":"2025-11-17T12:33:50","subject":"Re: [PATCH v4 03/21] ipa: libipa: Provide fixed point quantized\n\ttraits","submitter":{"id":216,"url":"https://patchwork.libcamera.org/api/people/216/","name":"Barnabás Pőcze","email":"barnabas.pocze@ideasonboard.com"},"content":"2025. 11. 17. 13:16 keltezéssel, Kieran Bingham írta:\n> Quoting Barnabás Pőcze (2025-11-17 11:27:23)\n>> 2025. 11. 14. 19:08 keltezéssel, Barnabás Pőcze írta:\n>>> 2025. 11. 14. 1:54 keltezéssel, Kieran Bingham írta:\n>>>> Extend the new Quantized type infrastructure by providing a\n>>>> FixedPointQTraits template.\n>>>>\n>>>> This allows construction of fixed point types with a Quantized storage\n>>>> that allows easy reading of both the underlying quantized type value and\n>>>> a floating point representation of that same value.\n>>>>\n>>>> Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n>>>>\n>>>> ---\n>>>> v4:\n>>>> - Assert that the given type has enough bits for the usage\n>>>> - Use unsigned types for calculating qmin/qmax\n>>>> - Reorder toFloat/fromFloat and min/max for future inlining\n>>>> - Make toFloat and fromFloat constexpr\n>>>>\n>>>>    src/ipa/libipa/fixedpoint.cpp | 121 ++++++++++++++++++++++++++++++++++\n>>>>    src/ipa/libipa/fixedpoint.h   |  45 +++++++++++++\n>>>>    2 files changed, 166 insertions(+)\n>>>>\n>>> [...]\n>>>> diff --git a/src/ipa/libipa/fixedpoint.h b/src/ipa/libipa/fixedpoint.h\n>>>> index 709cf50f0fcd..17db8a026502 100644\n>>>> --- a/src/ipa/libipa/fixedpoint.h\n>>>> +++ b/src/ipa/libipa/fixedpoint.h\n>>>> @@ -10,6 +10,8 @@\n>>>>    #include <cmath>\n>>>>    #include <type_traits>\n>>>> +#include \"quantized.h\"\n>>>> +\n>>>>    namespace libcamera {\n>>>>    namespace ipa {\n>>>> @@ -60,6 +62,49 @@ constexpr R fixedToFloatingPoint(T number)\n>>>>        return static_cast<R>(t) / static_cast<R>(1 << F);\n>>>>    }\n>>>> +template<unsigned int I, unsigned int F, typename T>\n>>>> +struct FixedPointQTraits {\n>>>> +    static_assert(std::is_integral_v<T>, \"FixedPointQTraits: T must be integral\");\n>>>> +    using QuantizedType = T;\n>>>> +    using UT = std::make_unsigned_t<T>;\n>>>> +\n>>>> +    static constexpr unsigned int Bits = I + F;\n>>>> +    static_assert(Bits <= sizeof(T) * 8, \"FixedPointQTraits: too many bits for type T\");\n>>>> +\n>>>> +    static constexpr T BitMask = (Bits < sizeof(T) * 8)\n>>>> +                   ? static_cast<T>((UT{1} << Bits) - 1)\n>>>> +                   : static_cast<T>(~UT{0});\n>>>\n>>> I think `UT`, `Bits`, `BitMask` could very well be private.\n> \n> Excellent point.\n> \n>>>> +\n>>>> +    static constexpr T qmin = std::is_signed_v<T>\n>>>> +                ? static_cast<T>(-(UT{1} << (Bits - 1)))\n>>>> +                : static_cast<T>(0);\n>>>> +\n>>>> +    static constexpr T qmax = std::is_signed_v<T>\n>>>> +                ? static_cast<T>((UT{1} << (Bits - 1)) - 1)\n>>>> +                : static_cast<T>((UT{1} << Bits) - 1);\n>>>> +\n>>>> +    static constexpr float toFloat(QuantizedType q)\n>>>> +    {\n>>>> +        return fixedToFloatingPoint<I, F, float, QuantizedType>(q);\n>>>> +    }\n>>>> +\n>>>> +    static constexpr float min = fixedToFloatingPoint<I, F, float>(qmin);\n>>>> +    static constexpr float max = fixedToFloatingPoint<I, F, float>(qmax);\n>>>> +\n>>>> +    /* Conversion functions required by Quantized<Traits> */\n>>>> +    static constexpr QuantizedType fromFloat(float v)\n>>\n>> `floatingToFixedPoint()` can't really be `constexpr` because `std::round`\n>> is not (before C++23), so this cannot be `constexpr` either.\n> \n> \n> \n> Phew ... I got /reaaaaally/ scared there thinking that was going to\n> break my constexprs for defining min and max in the type.\n> \n> If it's just fromFloat that can't be constexpr - I think that might not\n> be 'as bad'. Perhaps just 'sad'.\n> \n> I'll remove constexpr here and leave a note that it can be made\n> constexpr in C++23.\n> \n> Will this break the static initialisation/usage in other ways?\n\nWell, `Quantized` does not have `constexpr` members, so this shouldn't change\nanything.\n\nIn C++20, there is `std::is_constant_evaluated()` which would probably enable us\nto implement the necessary rounding, but I'm not sure if it's worth it without\nit being actually needed.\n\nIn any case, gcc seems to have actually evaluated std::round() in constexpr contexts\nfor a long time. But clang does not seem so allowing.\n\n\n> \n> \n>>>> +    {\n>>>> +        v = std::clamp(v, min, max);\n>>>> +        return floatingToFixedPoint<I, F, QuantizedType, float>(v);\n>>>> +    }\n>>>> +};\n>>>> +\n>>>> +using Q1_7 = Quantized<FixedPointQTraits<1, 7, int8_t>>;\n>>>> +using UQ1_7 = Quantized<FixedPointQTraits<1, 7, uint8_t>>;\n>>>> +\n>>>> +using Q12_4 = Quantized<FixedPointQTraits<12, 4, int16_t>>;\n>>>> +using UQ12_4 = Quantized<FixedPointQTraits<12, 4, uint16_t>>;\n>>>> +\n>>>>    } /* namespace ipa */\n>>>>    } /* namespace libcamera */\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 BEA75C0F1B\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 17 Nov 2025 12:33:57 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id E5EF2609D8;\n\tMon, 17 Nov 2025 13:33:56 +0100 (CET)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 5C1A260856\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 17 Nov 2025 13:33:55 +0100 (CET)","from [192.168.33.31] (185.221.143.100.nat.pool.zt.hu\n\t[185.221.143.100])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 2363CFE;\n\tMon, 17 Nov 2025 13:31:52 +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=\"Ji2owXBR\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1763382712;\n\tbh=HhAWIg6YvSZp81iSBy9SIxx2DCjBLE5N1kleNubnGkk=;\n\th=Date:Subject:To:References:From:In-Reply-To:From;\n\tb=Ji2owXBRMY51NNZ23pmI5/k18dvJ+miDcLNg+JALsjN2fAck4xWl0YbTmghUP6wwl\n\tSc33qZLfb/ODkE22vT4iM2eFN19knSsTS8SMWZp3WlcvM6WtCeb9TvRiihz2l0xDbf\n\t85BGSXKElx4RkdxmlWvc4/7iuTi0CPYexBOFwCAk=","Message-ID":"<79cdd5d2-5dfe-4aa0-af64-7d63ca753873@ideasonboard.com>","Date":"Mon, 17 Nov 2025 13:33:50 +0100","MIME-Version":"1.0","User-Agent":"Mozilla Thunderbird","Subject":"Re: [PATCH v4 03/21] ipa: libipa: Provide fixed point quantized\n\ttraits","To":"Kieran Bingham <kieran.bingham@ideasonboard.com>,\n\tlibcamera devel <libcamera-devel@lists.libcamera.org>","References":"<20251114005428.90024-1-kieran.bingham@ideasonboard.com>\n\t<20251114005428.90024-4-kieran.bingham@ideasonboard.com>\n\t<9e57aad9-5182-47e8-b644-4a27ecadec15@ideasonboard.com>\n\t<ac64d595-f5b5-4f8b-bd3a-e8a58bff4480@ideasonboard.com>\n\t<176338180326.1979555.16502881131097711089@ping.linuxembedded.co.uk>","From":"=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <barnabas.pocze@ideasonboard.com>","Content-Language":"en-US, hu-HU","In-Reply-To":"<176338180326.1979555.16502881131097711089@ping.linuxembedded.co.uk>","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":36869,"web_url":"https://patchwork.libcamera.org/comment/36869/","msgid":"<176346945889.880260.5800726811687956450@isaac-ThinkPad-T16-Gen-2>","date":"2025-11-18T12:37:38","subject":"Re: [PATCH v4 03/21] ipa: libipa: Provide fixed point quantized\n\ttraits","submitter":{"id":215,"url":"https://patchwork.libcamera.org/api/people/215/","name":"Isaac Scott","email":"isaac.scott@ideasonboard.com"},"content":"Hi Kieran,\n\nThank you for the patch!\n\nReviewed-by: Isaac Scott <isaac.scott@ideasonboard.com>\n\nQuoting Kieran Bingham (2025-11-14 00:54:07)\n> Extend the new Quantized type infrastructure by providing a\n> FixedPointQTraits template.\n> \n> This allows construction of fixed point types with a Quantized storage\n> that allows easy reading of both the underlying quantized type value and\n> a floating point representation of that same value.\n> \n> Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n> \n> ---\n> v4:\n> - Assert that the given type has enough bits for the usage\n> - Use unsigned types for calculating qmin/qmax\n> - Reorder toFloat/fromFloat and min/max for future inlining\n> - Make toFloat and fromFloat constexpr\n> \n>  src/ipa/libipa/fixedpoint.cpp | 121 ++++++++++++++++++++++++++++++++++\n>  src/ipa/libipa/fixedpoint.h   |  45 +++++++++++++\n>  2 files changed, 166 insertions(+)\n> \n> diff --git a/src/ipa/libipa/fixedpoint.cpp b/src/ipa/libipa/fixedpoint.cpp\n> index 6b698fc5d680..4c3ea33497bf 100644\n> --- a/src/ipa/libipa/fixedpoint.cpp\n> +++ b/src/ipa/libipa/fixedpoint.cpp\n> @@ -37,6 +37,127 @@ namespace ipa {\n>   * \\return The converted value\n>   */\n>  \n> +/**\n> + * \\struct libcamera::ipa::FixedPointQTraits\n> + * \\brief Traits type implementing fixed-point quantisation conversions\n> + *\n> + * The FixedPointQTraits structure defines a policy for mapping floating-point\n> + * values to and from fixed-point integer representations. It is parameterised\n> + * by the number of integer bits \\a I, fractional bits \\a F, and the integral\n> + * storage type \\a T. The traits are used with Quantized<Traits> to create a\n> + * quantised type that stores both the fixed-point representation and the\n> + * corresponding floating-point value.\n> + *\n> + * The trait exposes compile-time constants describing the bit layout, limits,\n> + * and scaling factors used in the fixed-point representation.\n> + *\n> + * \\tparam I Number of integer bits\n> + * \\tparam F Number of fractional bits\n> + * \\tparam T Integral type used to store the quantised value\n> + */\n> +\n> +/**\n> + * \\typedef FixedPointQTraits::QuantizedType\n> + * \\brief The integral storage type used for the fixed-point representation\n> + */\n> +\n> +/**\n> + * \\typedef FixedPointQTraits::UT\n> + * \\brief The unsigned representation of the integral storage\n> + *\n> + * This type definition is to support internal usage only.\n> + */\n> +\n> +/**\n> + * \\var FixedPointQTraits::Bits\n> + * \\brief Total number of bits used in the fixed-point format (I + F)\n> + */\n> +\n> +/**\n> + * \\var FixedPointQTraits::BitMask\n> + * \\brief Bit mask selecting all valid bits in the fixed-point representation\n> + */\n> +\n> +/**\n> + * \\var FixedPointQTraits::qmin\n> + * \\brief Minimum representable quantised integer value\n> + *\n> + * This corresponds to the most negative value for signed formats or zero for\n> + * unsigned formats.\n> + */\n> +\n> +/**\n> + * \\var FixedPointQTraits::qmax\n> + * \\brief Maximum representable quantised integer value\n> + */\n> +\n> +/**\n> + * \\var FixedPointQTraits::min\n> + * \\brief Minimum representable floating-point value corresponding to qmin\n> + */\n> +\n> +/**\n> + * \\var FixedPointQTraits::max\n> + * \\brief Maximum representable floating-point value corresponding to qmax\n> + */\n> +\n> +/**\n> + * \\fn FixedPointQTraits::fromFloat(float v)\n> + * \\brief Convert a floating-point value to a fixed-point integer\n> + * \\param[in] v The floating-point value to be converted\n> + * \\return The quantised fixed-point integer representation\n> + *\n> + * The conversion rounds the floating-point input \\a v to the nearest integer\n> + * according to the scaling factor defined by the number of fractional bits F.\n> + */\n> +\n> +/**\n> + * \\fn FixedPointQTraits::toFloat(QuantizedType q)\n> + * \\brief Convert a fixed-point integer to a floating-point value\n> + * \\param[in] q The fixed-point integer value to be converted\n> + * \\return The corresponding floating-point value\n> + *\n> + * The conversion sign-extends the integer value if required and divides by the\n> + * scaling factor defined by the number of fractional bits F.\n> + */\n> +\n> +/**\n> + * \\typedef Q1_7\n> + * \\brief 1.7 signed fixed-point quantizer\n> + *\n> + * A Quantized type using 1 bit for the integer part and 7 bits for the\n> + * fractional part, stored in a signed 8-bit integer (\\c int8_t). Represents\n> + * values approximately in the range [-1.0, 0.992] with a resolution of 1/128.\n> + */\n> +\n> +/**\n> + * \\typedef UQ1_7\n> + * \\brief 1.7 unsigned fixed-point quantizer\n> + *\n> + * A Quantized type using 1 bit for the integer part and 7 bits for the\n> + * fractional part, stored in an unsigned 8-bit integer (\\c uint8_t). Represents\n> + * values in the range [0.0, 1.992] with a resolution of 1/128.\n> + */\n> +\n> +/**\n> + * \\typedef Q12_4\n> + * \\brief 12.4 signed fixed-point quantizer\n> + *\n> + * A Quantized type using 12 bits for the integer part and 4 bits for the\n> + * fractional part, stored in a signed 16-bit integer (\\c int16_t). Represents\n> + * values in the range approximately [-2048.0, 2047.9375] with a resolution of\n> + * 1/16.\n> + */\n> +\n> +/**\n> + * \\typedef UQ12_4\n> + * \\brief 12.4 unsigned fixed-point quantizer\n> + *\n> + * A Quantized type using 12 bits for the integer part and 4 bits for the\n> + * fractional part, stored in an unsigned 16-bit integer (\\c uint16_t).\n> + * Represents values in the range [0.0, 4095.9375] with a resolution of 1/16.\n> + */\n> +\n>  } /* namespace ipa */\n>  \n>  } /* namespace libcamera */\n> diff --git a/src/ipa/libipa/fixedpoint.h b/src/ipa/libipa/fixedpoint.h\n> index 709cf50f0fcd..17db8a026502 100644\n> --- a/src/ipa/libipa/fixedpoint.h\n> +++ b/src/ipa/libipa/fixedpoint.h\n> @@ -10,6 +10,8 @@\n>  #include <cmath>\n>  #include <type_traits>\n>  \n> +#include \"quantized.h\"\n> +\n>  namespace libcamera {\n>  \n>  namespace ipa {\n> @@ -60,6 +62,49 @@ constexpr R fixedToFloatingPoint(T number)\n>         return static_cast<R>(t) / static_cast<R>(1 << F);\n>  }\n>  \n> +template<unsigned int I, unsigned int F, typename T>\n> +struct FixedPointQTraits {\n> +       static_assert(std::is_integral_v<T>, \"FixedPointQTraits: T must be integral\");\n> +       using QuantizedType = T;\n> +       using UT = std::make_unsigned_t<T>;\n> +\n> +       static constexpr unsigned int Bits = I + F;\n> +       static_assert(Bits <= sizeof(T) * 8, \"FixedPointQTraits: too many bits for type T\");\n> +\n> +       static constexpr T BitMask = (Bits < sizeof(T) * 8)\n> +                                  ? static_cast<T>((UT{1} << Bits) - 1)\n> +                                  : static_cast<T>(~UT{0});\n> +\n> +       static constexpr T qmin = std::is_signed_v<T>\n> +                               ? static_cast<T>(-(UT{1} << (Bits - 1)))\n> +                               : static_cast<T>(0);\n> +\n> +       static constexpr T qmax = std::is_signed_v<T>\n> +                               ? static_cast<T>((UT{1} << (Bits - 1)) - 1)\n> +                               : static_cast<T>((UT{1} << Bits) - 1);\n> +\n> +       static constexpr float toFloat(QuantizedType q)\n> +       {\n> +               return fixedToFloatingPoint<I, F, float, QuantizedType>(q);\n> +       }\n> +\n> +       static constexpr float min = fixedToFloatingPoint<I, F, float>(qmin);\n> +       static constexpr float max = fixedToFloatingPoint<I, F, float>(qmax);\n> +\n> +       /* Conversion functions required by Quantized<Traits> */\n> +       static constexpr QuantizedType fromFloat(float v)\n> +       {\n> +               v = std::clamp(v, min, max);\n> +               return floatingToFixedPoint<I, F, QuantizedType, float>(v);\n> +       }\n> +};\n> +\n> +using Q1_7 = Quantized<FixedPointQTraits<1, 7, int8_t>>;\n> +using UQ1_7 = Quantized<FixedPointQTraits<1, 7, uint8_t>>;\n> +\n> +using Q12_4 = Quantized<FixedPointQTraits<12, 4, int16_t>>;\n> +using UQ12_4 = Quantized<FixedPointQTraits<12, 4, uint16_t>>;\n> +\n>  } /* namespace ipa */\n>  \n>  } /* namespace libcamera */\n> -- \n> 2.51.1\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 811A2BD80A\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 18 Nov 2025 12:37:43 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 3BF8C60AA2;\n\tTue, 18 Nov 2025 13:37:43 +0100 (CET)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 91F42606D5\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 18 Nov 2025 13:37:41 +0100 (CET)","from thinkpad.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 D0859D52;\n\tTue, 18 Nov 2025 13:35:37 +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=\"VBC+AERh\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1763469337;\n\tbh=pt60XvRPFjYPbm3AlbjfmHnBpLaB4DnU2saTVjXVX94=;\n\th=In-Reply-To:References:Subject:From:Cc:To:Date:From;\n\tb=VBC+AERhH7rX1dz4AbI+99i7gfHFPXaoOLYITu8UfEbZYi266JCJLRHyyv7j1bjg9\n\tWSU3FQ2VQ/7CGpLEwdLQwKMzUDW4etk9jAbjeV9Y4HcclWVhAkoTOsOWExWr0x0Dkb\n\t/TGSeagKdigh0ka4FqRPmKhfP/uCXtXlc+ekU73g=","Content-Type":"text/plain; charset=\"utf-8\"","MIME-Version":"1.0","Content-Transfer-Encoding":"quoted-printable","In-Reply-To":"<20251114005428.90024-4-kieran.bingham@ideasonboard.com>","References":"<20251114005428.90024-1-kieran.bingham@ideasonboard.com>\n\t<20251114005428.90024-4-kieran.bingham@ideasonboard.com>","Subject":"Re: [PATCH v4 03/21] ipa: libipa: Provide fixed point quantized\n\ttraits","From":"Isaac Scott <isaac.scott@ideasonboard.com>","Cc":"Kieran Bingham <kieran.bingham@ideasonboard.com>","To":"Kieran Bingham <kieran.bingham@ideasonboard.com>,\n\tlibcamera devel <libcamera-devel@lists.libcamera.org>","Date":"Tue, 18 Nov 2025 12:37:38 +0000","Message-ID":"<176346945889.880260.5800726811687956450@isaac-ThinkPad-T16-Gen-2>","User-Agent":"alot/0.10","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":36907,"web_url":"https://patchwork.libcamera.org/comment/36907/","msgid":"<20251119043149.GW10711@pendragon.ideasonboard.com>","date":"2025-11-19T04:31:49","subject":"Re: [PATCH v4 03/21] ipa: libipa: Provide fixed point quantized\n\ttraits","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"On Fri, Nov 14, 2025 at 12:54:07AM +0000, Kieran Bingham wrote:\n> Extend the new Quantized type infrastructure by providing a\n> FixedPointQTraits template.\n> \n> This allows construction of fixed point types with a Quantized storage\n> that allows easy reading of both the underlying quantized type value and\n> a floating point representation of that same value.\n> \n> Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n> \n> ---\n> v4:\n> - Assert that the given type has enough bits for the usage\n> - Use unsigned types for calculating qmin/qmax\n> - Reorder toFloat/fromFloat and min/max for future inlining\n> - Make toFloat and fromFloat constexpr\n> \n>  src/ipa/libipa/fixedpoint.cpp | 121 ++++++++++++++++++++++++++++++++++\n>  src/ipa/libipa/fixedpoint.h   |  45 +++++++++++++\n>  2 files changed, 166 insertions(+)\n> \n> diff --git a/src/ipa/libipa/fixedpoint.cpp b/src/ipa/libipa/fixedpoint.cpp\n> index 6b698fc5d680..4c3ea33497bf 100644\n> --- a/src/ipa/libipa/fixedpoint.cpp\n> +++ b/src/ipa/libipa/fixedpoint.cpp\n> @@ -37,6 +37,127 @@ namespace ipa {\n>   * \\return The converted value\n>   */\n>  \n> +/**\n> + * \\struct libcamera::ipa::FixedPointQTraits\n> + * \\brief Traits type implementing fixed-point quantisation conversions\n> + *\n> + * The FixedPointQTraits structure defines a policy for mapping floating-point\n> + * values to and from fixed-point integer representations. It is parameterised\n> + * by the number of integer bits \\a I, fractional bits \\a F, and the integral\n> + * storage type \\a T. The traits are used with Quantized<Traits> to create a\n> + * quantised type that stores both the fixed-point representation and the\n> + * corresponding floating-point value.\n> + *\n> + * The trait exposes compile-time constants describing the bit layout, limits,\n> + * and scaling factors used in the fixed-point representation.\n> + *\n> + * \\tparam I Number of integer bits\n> + * \\tparam F Number of fractional bits\n> + * \\tparam T Integral type used to store the quantised value\n> + */\n> +\n> +/**\n> + * \\typedef FixedPointQTraits::QuantizedType\n> + * \\brief The integral storage type used for the fixed-point representation\n> + */\n> +\n> +/**\n> + * \\typedef FixedPointQTraits::UT\n> + * \\brief The unsigned representation of the integral storage\n> + *\n> + * This type definition is to support internal usage only.\n> + */\n> +\n> +/**\n> + * \\var FixedPointQTraits::Bits\n> + * \\brief Total number of bits used in the fixed-point format (I + F)\n> + */\n> +\n> +/**\n> + * \\var FixedPointQTraits::BitMask\n> + * \\brief Bit mask selecting all valid bits in the fixed-point representation\n> + */\n> +\n> +/**\n> + * \\var FixedPointQTraits::qmin\n> + * \\brief Minimum representable quantised integer value\n> + *\n> + * This corresponds to the most negative value for signed formats or zero for\n> + * unsigned formats.\n> + */\n> +\n> +/**\n> + * \\var FixedPointQTraits::qmax\n> + * \\brief Maximum representable quantised integer value\n> + */\n> +\n> +/**\n> + * \\var FixedPointQTraits::min\n> + * \\brief Minimum representable floating-point value corresponding to qmin\n> + */\n> +\n> +/**\n> + * \\var FixedPointQTraits::max\n> + * \\brief Maximum representable floating-point value corresponding to qmax\n> + */\n> +\n> +/**\n> + * \\fn FixedPointQTraits::fromFloat(float v)\n> + * \\brief Convert a floating-point value to a fixed-point integer\n> + * \\param[in] v The floating-point value to be converted\n> + * \\return The quantised fixed-point integer representation\n> + *\n> + * The conversion rounds the floating-point input \\a v to the nearest integer\n> + * according to the scaling factor defined by the number of fractional bits F.\n> + */\n> +\n> +/**\n> + * \\fn FixedPointQTraits::toFloat(QuantizedType q)\n> + * \\brief Convert a fixed-point integer to a floating-point value\n> + * \\param[in] q The fixed-point integer value to be converted\n> + * \\return The corresponding floating-point value\n> + *\n> + * The conversion sign-extends the integer value if required and divides by the\n> + * scaling factor defined by the number of fractional bits F.\n> + */\n> +\n> +/**\n> + * \\typedef Q1_7\n> + * \\brief 1.7 signed fixed-point quantizer\n> + *\n> + * A Quantized type using 1 bit for the integer part and 7 bits for the\n> + * fractional part, stored in a signed 8-bit integer (\\c int8_t). Represents\n> + * values approximately in the range [-1.0, 0.992] with a resolution of 1/128.\n> + */\n> +\n> +/**\n> + * \\typedef UQ1_7\n> + * \\brief 1.7 unsigned fixed-point quantizer\n> + *\n> + * A Quantized type using 1 bit for the integer part and 7 bits for the\n> + * fractional part, stored in an unsigned 8-bit integer (\\c uint8_t). Represents\n> + * values in the range [0.0, 1.992] with a resolution of 1/128.\n> + */\n> +\n> +/**\n> + * \\typedef Q12_4\n> + * \\brief 12.4 signed fixed-point quantizer\n> + *\n> + * A Quantized type using 12 bits for the integer part and 4 bits for the\n> + * fractional part, stored in a signed 16-bit integer (\\c int16_t). Represents\n> + * values in the range approximately [-2048.0, 2047.9375] with a resolution of\n> + * 1/16.\n> + */\n> +\n> +/**\n> + * \\typedef UQ12_4\n> + * \\brief 12.4 unsigned fixed-point quantizer\n> + *\n> + * A Quantized type using 12 bits for the integer part and 4 bits for the\n> + * fractional part, stored in an unsigned 16-bit integer (\\c uint16_t).\n> + * Represents values in the range [0.0, 4095.9375] with a resolution of 1/16.\n> + */\n> +\n>  } /* namespace ipa */\n>  \n>  } /* namespace libcamera */\n> diff --git a/src/ipa/libipa/fixedpoint.h b/src/ipa/libipa/fixedpoint.h\n> index 709cf50f0fcd..17db8a026502 100644\n> --- a/src/ipa/libipa/fixedpoint.h\n> +++ b/src/ipa/libipa/fixedpoint.h\n> @@ -10,6 +10,8 @@\n>  #include <cmath>\n>  #include <type_traits>\n>  \n> +#include \"quantized.h\"\n> +\n>  namespace libcamera {\n>  \n>  namespace ipa {\n> @@ -60,6 +62,49 @@ constexpr R fixedToFloatingPoint(T number)\n>  \treturn static_cast<R>(t) / static_cast<R>(1 << F);\n>  }\n>  \n> +template<unsigned int I, unsigned int F, typename T>\n> +struct FixedPointQTraits {\n> +\tstatic_assert(std::is_integral_v<T>, \"FixedPointQTraits: T must be integral\");\n> +\tusing QuantizedType = T;\n> +\tusing UT = std::make_unsigned_t<T>;\n> +\n> +\tstatic constexpr unsigned int Bits = I + F;\n\ns/Bits/bits/\n\nmember variables start with a lower-case latter. kBits is another\noption.\n\n> +\tstatic_assert(Bits <= sizeof(T) * 8, \"FixedPointQTraits: too many bits for type T\");\n> +\n> +\tstatic constexpr T BitMask = (Bits < sizeof(T) * 8)\n\nSame here, bitMask or kBitMask.\n\n> +\t\t\t\t   ? static_cast<T>((UT{1} << Bits) - 1)\n> +\t\t\t\t   : static_cast<T>(~UT{0});\n> +\n> +\tstatic constexpr T qmin = std::is_signed_v<T>\n\nqMin ? kQMin looks weird.\n\n> +\t\t\t\t? static_cast<T>(-(UT{1} << (Bits - 1)))\n> +\t\t\t\t: static_cast<T>(0);\n> +\n> +\tstatic constexpr T qmax = std::is_signed_v<T>\n> +\t\t\t\t? static_cast<T>((UT{1} << (Bits - 1)) - 1)\n> +\t\t\t\t: static_cast<T>((UT{1} << Bits) - 1);\n> +\n> +\tstatic constexpr float toFloat(QuantizedType q)\n> +\t{\n> +\t\treturn fixedToFloatingPoint<I, F, float, QuantizedType>(q);\n> +\t}\n> +\n> +\tstatic constexpr float min = fixedToFloatingPoint<I, F, float>(qmin);\n> +\tstatic constexpr float max = fixedToFloatingPoint<I, F, float>(qmax);\n> +\n> +\t/* Conversion functions required by Quantized<Traits> */\n> +\tstatic constexpr QuantizedType fromFloat(float v)\n> +\t{\n> +\t\tv = std::clamp(v, min, max);\n> +\t\treturn floatingToFixedPoint<I, F, QuantizedType, float>(v);\n> +\t}\n> +};\n> +\n> +using Q1_7 = Quantized<FixedPointQTraits<1, 7, int8_t>>;\n> +using UQ1_7 = Quantized<FixedPointQTraits<1, 7, uint8_t>>;\n> +\n> +using Q12_4 = Quantized<FixedPointQTraits<12, 4, int16_t>>;\n> +using UQ12_4 = Quantized<FixedPointQTraits<12, 4, uint16_t>>;\n> +\n\nWhy Q1.7 and Q12.4 in particular ? I assume you use them later, maybe\nthey should be introduced where they first get used ?\n\n>  } /* namespace ipa */\n>  \n>  } /* namespace libcamera */","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 3C5F3BD80A\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 19 Nov 2025 04:32:26 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id E364360A86;\n\tWed, 19 Nov 2025 05:32:25 +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 92CA360A7B\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 19 Nov 2025 05:32:24 +0100 (CET)","from pendragon.ideasonboard.com (unknown [205.220.129.225])\n\tby perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 71129B5;\n\tWed, 19 Nov 2025 05:30:17 +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=\"m6xxB6sj\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1763526620;\n\tbh=5Hg9y7f52Rv9EmWl5QCOOfqOt9h9r8eFhIIqft7Jgnc=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=m6xxB6sjDz/uZyVIuoxIjMB0YJP3MLY68TuG5Mp0ExMSaKpL30HBxI69uQ3sVvK50\n\tkRGy7aMuTzpN8lmlSchnVoFUraAGbk36JfRHU6h2clJ/J9X3LHdheASr8vu5gKRuhZ\n\tgbyNtB+yYgX3DiTZg+e/Enng8ojDZmAugNMaHR2w=","Date":"Wed, 19 Nov 2025 13:31:49 +0900","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Cc":"libcamera devel <libcamera-devel@lists.libcamera.org>","Subject":"Re: [PATCH v4 03/21] ipa: libipa: Provide fixed point quantized\n\ttraits","Message-ID":"<20251119043149.GW10711@pendragon.ideasonboard.com>","References":"<20251114005428.90024-1-kieran.bingham@ideasonboard.com>\n\t<20251114005428.90024-4-kieran.bingham@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20251114005428.90024-4-kieran.bingham@ideasonboard.com>","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":36914,"web_url":"https://patchwork.libcamera.org/comment/36914/","msgid":"<176354501331.567526.9807533735124782483@ping.linuxembedded.co.uk>","date":"2025-11-19T09:36:53","subject":"Re: [PATCH v4 03/21] ipa: libipa: Provide fixed point quantized\n\ttraits","submitter":{"id":4,"url":"https://patchwork.libcamera.org/api/people/4/","name":"Kieran Bingham","email":"kieran.bingham@ideasonboard.com"},"content":"Quoting Laurent Pinchart (2025-11-19 04:31:49)\n> On Fri, Nov 14, 2025 at 12:54:07AM +0000, Kieran Bingham wrote:\n> > Extend the new Quantized type infrastructure by providing a\n> > FixedPointQTraits template.\n> > \n> > This allows construction of fixed point types with a Quantized storage\n> > that allows easy reading of both the underlying quantized type value and\n> > a floating point representation of that same value.\n> > \n> > Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n> > \n> > ---\n> > v4:\n> > - Assert that the given type has enough bits for the usage\n> > - Use unsigned types for calculating qmin/qmax\n> > - Reorder toFloat/fromFloat and min/max for future inlining\n> > - Make toFloat and fromFloat constexpr\n> > \n> >  src/ipa/libipa/fixedpoint.cpp | 121 ++++++++++++++++++++++++++++++++++\n> >  src/ipa/libipa/fixedpoint.h   |  45 +++++++++++++\n> >  2 files changed, 166 insertions(+)\n> > \n> > diff --git a/src/ipa/libipa/fixedpoint.cpp b/src/ipa/libipa/fixedpoint.cpp\n> > index 6b698fc5d680..4c3ea33497bf 100644\n> > --- a/src/ipa/libipa/fixedpoint.cpp\n> > +++ b/src/ipa/libipa/fixedpoint.cpp\n> > @@ -37,6 +37,127 @@ namespace ipa {\n> >   * \\return The converted value\n> >   */\n> >  \n> > +/**\n> > + * \\struct libcamera::ipa::FixedPointQTraits\n> > + * \\brief Traits type implementing fixed-point quantisation conversions\n> > + *\n> > + * The FixedPointQTraits structure defines a policy for mapping floating-point\n> > + * values to and from fixed-point integer representations. It is parameterised\n> > + * by the number of integer bits \\a I, fractional bits \\a F, and the integral\n> > + * storage type \\a T. The traits are used with Quantized<Traits> to create a\n> > + * quantised type that stores both the fixed-point representation and the\n> > + * corresponding floating-point value.\n> > + *\n> > + * The trait exposes compile-time constants describing the bit layout, limits,\n> > + * and scaling factors used in the fixed-point representation.\n> > + *\n> > + * \\tparam I Number of integer bits\n> > + * \\tparam F Number of fractional bits\n> > + * \\tparam T Integral type used to store the quantised value\n> > + */\n> > +\n> > +/**\n> > + * \\typedef FixedPointQTraits::QuantizedType\n> > + * \\brief The integral storage type used for the fixed-point representation\n> > + */\n> > +\n> > +/**\n> > + * \\typedef FixedPointQTraits::UT\n> > + * \\brief The unsigned representation of the integral storage\n> > + *\n> > + * This type definition is to support internal usage only.\n> > + */\n> > +\n> > +/**\n> > + * \\var FixedPointQTraits::Bits\n> > + * \\brief Total number of bits used in the fixed-point format (I + F)\n> > + */\n> > +\n> > +/**\n> > + * \\var FixedPointQTraits::BitMask\n> > + * \\brief Bit mask selecting all valid bits in the fixed-point representation\n> > + */\n> > +\n> > +/**\n> > + * \\var FixedPointQTraits::qmin\n> > + * \\brief Minimum representable quantised integer value\n> > + *\n> > + * This corresponds to the most negative value for signed formats or zero for\n> > + * unsigned formats.\n> > + */\n> > +\n> > +/**\n> > + * \\var FixedPointQTraits::qmax\n> > + * \\brief Maximum representable quantised integer value\n> > + */\n> > +\n> > +/**\n> > + * \\var FixedPointQTraits::min\n> > + * \\brief Minimum representable floating-point value corresponding to qmin\n> > + */\n> > +\n> > +/**\n> > + * \\var FixedPointQTraits::max\n> > + * \\brief Maximum representable floating-point value corresponding to qmax\n> > + */\n> > +\n> > +/**\n> > + * \\fn FixedPointQTraits::fromFloat(float v)\n> > + * \\brief Convert a floating-point value to a fixed-point integer\n> > + * \\param[in] v The floating-point value to be converted\n> > + * \\return The quantised fixed-point integer representation\n> > + *\n> > + * The conversion rounds the floating-point input \\a v to the nearest integer\n> > + * according to the scaling factor defined by the number of fractional bits F.\n> > + */\n> > +\n> > +/**\n> > + * \\fn FixedPointQTraits::toFloat(QuantizedType q)\n> > + * \\brief Convert a fixed-point integer to a floating-point value\n> > + * \\param[in] q The fixed-point integer value to be converted\n> > + * \\return The corresponding floating-point value\n> > + *\n> > + * The conversion sign-extends the integer value if required and divides by the\n> > + * scaling factor defined by the number of fractional bits F.\n> > + */\n> > +\n> > +/**\n> > + * \\typedef Q1_7\n> > + * \\brief 1.7 signed fixed-point quantizer\n> > + *\n> > + * A Quantized type using 1 bit for the integer part and 7 bits for the\n> > + * fractional part, stored in a signed 8-bit integer (\\c int8_t). Represents\n> > + * values approximately in the range [-1.0, 0.992] with a resolution of 1/128.\n> > + */\n> > +\n> > +/**\n> > + * \\typedef UQ1_7\n> > + * \\brief 1.7 unsigned fixed-point quantizer\n> > + *\n> > + * A Quantized type using 1 bit for the integer part and 7 bits for the\n> > + * fractional part, stored in an unsigned 8-bit integer (\\c uint8_t). Represents\n> > + * values in the range [0.0, 1.992] with a resolution of 1/128.\n> > + */\n> > +\n> > +/**\n> > + * \\typedef Q12_4\n> > + * \\brief 12.4 signed fixed-point quantizer\n> > + *\n> > + * A Quantized type using 12 bits for the integer part and 4 bits for the\n> > + * fractional part, stored in a signed 16-bit integer (\\c int16_t). Represents\n> > + * values in the range approximately [-2048.0, 2047.9375] with a resolution of\n> > + * 1/16.\n> > + */\n> > +\n> > +/**\n> > + * \\typedef UQ12_4\n> > + * \\brief 12.4 unsigned fixed-point quantizer\n> > + *\n> > + * A Quantized type using 12 bits for the integer part and 4 bits for the\n> > + * fractional part, stored in an unsigned 16-bit integer (\\c uint16_t).\n> > + * Represents values in the range [0.0, 4095.9375] with a resolution of 1/16.\n> > + */\n> > +\n> >  } /* namespace ipa */\n> >  \n> >  } /* namespace libcamera */\n> > diff --git a/src/ipa/libipa/fixedpoint.h b/src/ipa/libipa/fixedpoint.h\n> > index 709cf50f0fcd..17db8a026502 100644\n> > --- a/src/ipa/libipa/fixedpoint.h\n> > +++ b/src/ipa/libipa/fixedpoint.h\n> > @@ -10,6 +10,8 @@\n> >  #include <cmath>\n> >  #include <type_traits>\n> >  \n> > +#include \"quantized.h\"\n> > +\n> >  namespace libcamera {\n> >  \n> >  namespace ipa {\n> > @@ -60,6 +62,49 @@ constexpr R fixedToFloatingPoint(T number)\n> >       return static_cast<R>(t) / static_cast<R>(1 << F);\n> >  }\n> >  \n> > +template<unsigned int I, unsigned int F, typename T>\n> > +struct FixedPointQTraits {\n> > +     static_assert(std::is_integral_v<T>, \"FixedPointQTraits: T must be integral\");\n> > +     using QuantizedType = T;\n> > +     using UT = std::make_unsigned_t<T>;\n> > +\n> > +     static constexpr unsigned int Bits = I + F;\n> \n> s/Bits/bits/\n> \n> member variables start with a lower-case latter. kBits is another\n> option.\n> \n> > +     static_assert(Bits <= sizeof(T) * 8, \"FixedPointQTraits: too many bits for type T\");\n> > +\n> > +     static constexpr T BitMask = (Bits < sizeof(T) * 8)\n> \n> Same here, bitMask or kBitMask.\n> \n> > +                                ? static_cast<T>((UT{1} << Bits) - 1)\n> > +                                : static_cast<T>(~UT{0});\n> > +\n> > +     static constexpr T qmin = std::is_signed_v<T>\n> \n> qMin ? kQMin looks weird.\n> \n> > +                             ? static_cast<T>(-(UT{1} << (Bits - 1)))\n> > +                             : static_cast<T>(0);\n> > +\n> > +     static constexpr T qmax = std::is_signed_v<T>\n> > +                             ? static_cast<T>((UT{1} << (Bits - 1)) - 1)\n> > +                             : static_cast<T>((UT{1} << Bits) - 1);\n> > +\n> > +     static constexpr float toFloat(QuantizedType q)\n> > +     {\n> > +             return fixedToFloatingPoint<I, F, float, QuantizedType>(q);\n> > +     }\n> > +\n> > +     static constexpr float min = fixedToFloatingPoint<I, F, float>(qmin);\n> > +     static constexpr float max = fixedToFloatingPoint<I, F, float>(qmax);\n> > +\n> > +     /* Conversion functions required by Quantized<Traits> */\n> > +     static constexpr QuantizedType fromFloat(float v)\n> > +     {\n> > +             v = std::clamp(v, min, max);\n> > +             return floatingToFixedPoint<I, F, QuantizedType, float>(v);\n> > +     }\n> > +};\n> > +\n> > +using Q1_7 = Quantized<FixedPointQTraits<1, 7, int8_t>>;\n> > +using UQ1_7 = Quantized<FixedPointQTraits<1, 7, uint8_t>>;\n> > +\n> > +using Q12_4 = Quantized<FixedPointQTraits<12, 4, int16_t>>;\n> > +using UQ12_4 = Quantized<FixedPointQTraits<12, 4, uint16_t>>;\n> > +\n> \n> Why Q1.7 and Q12.4 in particular ? I assume you use them later, maybe\n> they should be introduced where they first get used ?\n\nThey are the types that started this project. Used by RKISP1 Cproc, so\nthey give me the starting point to test, along side the test already in\nfixedpoint.c which get replaced by this implementation.\n\nI can split them out if you wish ... but it seems later you want me to\ndrop all of these new types anyway (I would still like them though)\n\n--\nKieran\n\n> \n> >  } /* namespace ipa */\n> >  \n> >  } /* namespace libcamera */\n> \n> -- \n> Regards,\n> \n> Laurent Pinchart","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 AFB13C0F1B\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 19 Nov 2025 09:36:57 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 0E16F60A80;\n\tWed, 19 Nov 2025 10:36:57 +0100 (CET)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 122EC60805\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 19 Nov 2025 10:36:56 +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 6357BE7C;\n\tWed, 19 Nov 2025 10:34:51 +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=\"d+3FSQ4R\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1763544891;\n\tbh=bEZFslUWn+lQWauLLwTNb4b24OBlJxKeMwZh9aDJAQA=;\n\th=In-Reply-To:References:Subject:From:Cc:To:Date:From;\n\tb=d+3FSQ4RaLAxOCgTYo4pAhWajg/vMEsvUFv5mVeRVyzYkUSO3TZAIIYcTPflm9Bfc\n\tBYjhT/2pc3SSh2zwbp1LgLXBx94HWab/qpNYl6LliAuzawrDQUYshgcTJrKQeMxylX\n\tPtVAr056HOKbrKOcQ5McB4s2/HwAz66R37FzPkY4=","Content-Type":"text/plain; charset=\"utf-8\"","MIME-Version":"1.0","Content-Transfer-Encoding":"quoted-printable","In-Reply-To":"<20251119043149.GW10711@pendragon.ideasonboard.com>","References":"<20251114005428.90024-1-kieran.bingham@ideasonboard.com>\n\t<20251114005428.90024-4-kieran.bingham@ideasonboard.com>\n\t<20251119043149.GW10711@pendragon.ideasonboard.com>","Subject":"Re: [PATCH v4 03/21] ipa: libipa: Provide fixed point quantized\n\ttraits","From":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Cc":"libcamera devel <libcamera-devel@lists.libcamera.org>","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Date":"Wed, 19 Nov 2025 09:36:53 +0000","Message-ID":"<176354501331.567526.9807533735124782483@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>"}}]