| Message ID | 20251114005428.90024-4-kieran.bingham@ideasonboard.com |
|---|---|
| State | New |
| Headers | show |
| Series |
|
| Related | show |
2025. 11. 14. 1:54 keltezéssel, Kieran Bingham írta: > Extend the new Quantized type infrastructure by providing a > FixedPointQTraits template. > > This allows construction of fixed point types with a Quantized storage > that allows easy reading of both the underlying quantized type value and > a floating point representation of that same value. > > Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com> > > --- > v4: > - Assert that the given type has enough bits for the usage > - Use unsigned types for calculating qmin/qmax > - Reorder toFloat/fromFloat and min/max for future inlining > - Make toFloat and fromFloat constexpr > > src/ipa/libipa/fixedpoint.cpp | 121 ++++++++++++++++++++++++++++++++++ > src/ipa/libipa/fixedpoint.h | 45 +++++++++++++ > 2 files changed, 166 insertions(+) > > diff --git a/src/ipa/libipa/fixedpoint.cpp b/src/ipa/libipa/fixedpoint.cpp > index 6b698fc5d680..4c3ea33497bf 100644 > --- a/src/ipa/libipa/fixedpoint.cpp > +++ b/src/ipa/libipa/fixedpoint.cpp > @@ -37,6 +37,127 @@ namespace ipa { > * \return The converted value > */ > > +/** > + * \struct libcamera::ipa::FixedPointQTraits > + * \brief Traits type implementing fixed-point quantisation conversions > + * > + * The FixedPointQTraits structure defines a policy for mapping floating-point > + * values to and from fixed-point integer representations. It is parameterised > + * by the number of integer bits \a I, fractional bits \a F, and the integral > + * storage type \a T. The traits are used with Quantized<Traits> to create a > + * quantised type that stores both the fixed-point representation and the > + * corresponding floating-point value. > + * > + * The trait exposes compile-time constants describing the bit layout, limits, > + * and scaling factors used in the fixed-point representation. > + * > + * \tparam I Number of integer bits > + * \tparam F Number of fractional bits > + * \tparam T Integral type used to store the quantised value > + */ > + > +/** > + * \typedef FixedPointQTraits::QuantizedType > + * \brief The integral storage type used for the fixed-point representation > + */ > + > +/** > + * \typedef FixedPointQTraits::UT > + * \brief The unsigned representation of the integral storage > + * > + * This type definition is to support internal usage only. > + */ > + > +/** > + * \var FixedPointQTraits::Bits > + * \brief Total number of bits used in the fixed-point format (I + F) > + */ > + > +/** > + * \var FixedPointQTraits::BitMask > + * \brief Bit mask selecting all valid bits in the fixed-point representation > + */ > + > +/** > + * \var FixedPointQTraits::qmin > + * \brief Minimum representable quantised integer value > + * > + * This corresponds to the most negative value for signed formats or zero for > + * unsigned formats. > + */ > + > +/** > + * \var FixedPointQTraits::qmax > + * \brief Maximum representable quantised integer value > + */ > + > +/** > + * \var FixedPointQTraits::min > + * \brief Minimum representable floating-point value corresponding to qmin > + */ > + > +/** > + * \var FixedPointQTraits::max > + * \brief Maximum representable floating-point value corresponding to qmax > + */ > + > +/** > + * \fn FixedPointQTraits::fromFloat(float v) > + * \brief Convert a floating-point value to a fixed-point integer > + * \param[in] v The floating-point value to be converted > + * \return The quantised fixed-point integer representation > + * > + * The conversion rounds the floating-point input \a v to the nearest integer > + * according to the scaling factor defined by the number of fractional bits F. > + */ > + > +/** > + * \fn FixedPointQTraits::toFloat(QuantizedType q) > + * \brief Convert a fixed-point integer to a floating-point value > + * \param[in] q The fixed-point integer value to be converted > + * \return The corresponding floating-point value > + * > + * The conversion sign-extends the integer value if required and divides by the > + * scaling factor defined by the number of fractional bits F. > + */ > + > +/** > + * \typedef Q1_7 > + * \brief 1.7 signed fixed-point quantizer > + * > + * A Quantized type using 1 bit for the integer part and 7 bits for the > + * fractional part, stored in a signed 8-bit integer (\c int8_t). Represents > + * values approximately in the range [-1.0, 0.992] with a resolution of 1/128. > + */ > + > +/** > + * \typedef UQ1_7 > + * \brief 1.7 unsigned fixed-point quantizer > + * > + * A Quantized type using 1 bit for the integer part and 7 bits for the > + * fractional part, stored in an unsigned 8-bit integer (\c uint8_t). Represents > + * values in the range [0.0, 1.992] with a resolution of 1/128. > + */ > + > +/** > + * \typedef Q12_4 > + * \brief 12.4 signed fixed-point quantizer > + * > + * A Quantized type using 12 bits for the integer part and 4 bits for the > + * fractional part, stored in a signed 16-bit integer (\c int16_t). Represents > + * values in the range approximately [-2048.0, 2047.9375] with a resolution of > + * 1/16. > + */ > + > +/** > + * \typedef UQ12_4 > + * \brief 12.4 unsigned fixed-point quantizer > + * > + * A Quantized type using 12 bits for the integer part and 4 bits for the > + * fractional part, stored in an unsigned 16-bit integer (\c uint16_t). > + * Represents values in the range [0.0, 4095.9375] with a resolution of 1/16. > + */ > + > } /* namespace ipa */ > > } /* namespace libcamera */ > diff --git a/src/ipa/libipa/fixedpoint.h b/src/ipa/libipa/fixedpoint.h > index 709cf50f0fcd..17db8a026502 100644 > --- a/src/ipa/libipa/fixedpoint.h > +++ b/src/ipa/libipa/fixedpoint.h > @@ -10,6 +10,8 @@ > #include <cmath> > #include <type_traits> > > +#include "quantized.h" > + > namespace libcamera { > > namespace ipa { > @@ -60,6 +62,49 @@ constexpr R fixedToFloatingPoint(T number) > return static_cast<R>(t) / static_cast<R>(1 << F); > } > > +template<unsigned int I, unsigned int F, typename T> > +struct FixedPointQTraits { > + static_assert(std::is_integral_v<T>, "FixedPointQTraits: T must be integral"); > + using QuantizedType = T; > + using UT = std::make_unsigned_t<T>; > + > + static constexpr unsigned int Bits = I + F; > + static_assert(Bits <= sizeof(T) * 8, "FixedPointQTraits: too many bits for type T"); > + > + static constexpr T BitMask = (Bits < sizeof(T) * 8) > + ? static_cast<T>((UT{1} << Bits) - 1) > + : static_cast<T>(~UT{0}); I think `UT`, `Bits`, `BitMask` could very well be private. > + > + static constexpr T qmin = std::is_signed_v<T> > + ? static_cast<T>(-(UT{1} << (Bits - 1))) > + : static_cast<T>(0); > + > + static constexpr T qmax = std::is_signed_v<T> > + ? static_cast<T>((UT{1} << (Bits - 1)) - 1) > + : static_cast<T>((UT{1} << Bits) - 1); > + > + static constexpr float toFloat(QuantizedType q) > + { > + return fixedToFloatingPoint<I, F, float, QuantizedType>(q); > + } > + > + static constexpr float min = fixedToFloatingPoint<I, F, float>(qmin); > + static constexpr float max = fixedToFloatingPoint<I, F, float>(qmax); > + > + /* Conversion functions required by Quantized<Traits> */ > + static constexpr QuantizedType fromFloat(float v) > + { > + v = std::clamp(v, min, max); > + return floatingToFixedPoint<I, F, QuantizedType, float>(v); > + } > +}; > + > +using Q1_7 = Quantized<FixedPointQTraits<1, 7, int8_t>>; > +using UQ1_7 = Quantized<FixedPointQTraits<1, 7, uint8_t>>; > + > +using Q12_4 = Quantized<FixedPointQTraits<12, 4, int16_t>>; > +using UQ12_4 = Quantized<FixedPointQTraits<12, 4, uint16_t>>; > + > } /* namespace ipa */ > > } /* namespace libcamera */
2025. 11. 14. 19:08 keltezéssel, Barnabás Pőcze írta: > 2025. 11. 14. 1:54 keltezéssel, Kieran Bingham írta: >> Extend the new Quantized type infrastructure by providing a >> FixedPointQTraits template. >> >> This allows construction of fixed point types with a Quantized storage >> that allows easy reading of both the underlying quantized type value and >> a floating point representation of that same value. >> >> Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com> >> >> --- >> v4: >> - Assert that the given type has enough bits for the usage >> - Use unsigned types for calculating qmin/qmax >> - Reorder toFloat/fromFloat and min/max for future inlining >> - Make toFloat and fromFloat constexpr >> >> src/ipa/libipa/fixedpoint.cpp | 121 ++++++++++++++++++++++++++++++++++ >> src/ipa/libipa/fixedpoint.h | 45 +++++++++++++ >> 2 files changed, 166 insertions(+) >> > [...] >> diff --git a/src/ipa/libipa/fixedpoint.h b/src/ipa/libipa/fixedpoint.h >> index 709cf50f0fcd..17db8a026502 100644 >> --- a/src/ipa/libipa/fixedpoint.h >> +++ b/src/ipa/libipa/fixedpoint.h >> @@ -10,6 +10,8 @@ >> #include <cmath> >> #include <type_traits> >> +#include "quantized.h" >> + >> namespace libcamera { >> namespace ipa { >> @@ -60,6 +62,49 @@ constexpr R fixedToFloatingPoint(T number) >> return static_cast<R>(t) / static_cast<R>(1 << F); >> } >> +template<unsigned int I, unsigned int F, typename T> >> +struct FixedPointQTraits { >> + static_assert(std::is_integral_v<T>, "FixedPointQTraits: T must be integral"); >> + using QuantizedType = T; >> + using UT = std::make_unsigned_t<T>; >> + >> + static constexpr unsigned int Bits = I + F; >> + static_assert(Bits <= sizeof(T) * 8, "FixedPointQTraits: too many bits for type T"); >> + >> + static constexpr T BitMask = (Bits < sizeof(T) * 8) >> + ? static_cast<T>((UT{1} << Bits) - 1) >> + : static_cast<T>(~UT{0}); > > I think `UT`, `Bits`, `BitMask` could very well be private. > > >> + >> + static constexpr T qmin = std::is_signed_v<T> >> + ? static_cast<T>(-(UT{1} << (Bits - 1))) >> + : static_cast<T>(0); >> + >> + static constexpr T qmax = std::is_signed_v<T> >> + ? static_cast<T>((UT{1} << (Bits - 1)) - 1) >> + : static_cast<T>((UT{1} << Bits) - 1); >> + >> + static constexpr float toFloat(QuantizedType q) >> + { >> + return fixedToFloatingPoint<I, F, float, QuantizedType>(q); >> + } >> + >> + static constexpr float min = fixedToFloatingPoint<I, F, float>(qmin); >> + static constexpr float max = fixedToFloatingPoint<I, F, float>(qmax); >> + >> + /* Conversion functions required by Quantized<Traits> */ >> + static constexpr QuantizedType fromFloat(float v) `floatingToFixedPoint()` can't really be `constexpr` because `std::round` is not (before C++23), so this cannot be `constexpr` either. >> + { >> + v = std::clamp(v, min, max); >> + return floatingToFixedPoint<I, F, QuantizedType, float>(v); >> + } >> +}; >> + >> +using Q1_7 = Quantized<FixedPointQTraits<1, 7, int8_t>>; >> +using UQ1_7 = Quantized<FixedPointQTraits<1, 7, uint8_t>>; >> + >> +using Q12_4 = Quantized<FixedPointQTraits<12, 4, int16_t>>; >> +using UQ12_4 = Quantized<FixedPointQTraits<12, 4, uint16_t>>; >> + >> } /* namespace ipa */ >> } /* namespace libcamera */ >
Quoting Barnabás Pőcze (2025-11-17 11:27:23) > 2025. 11. 14. 19:08 keltezéssel, Barnabás Pőcze írta: > > 2025. 11. 14. 1:54 keltezéssel, Kieran Bingham írta: > >> Extend the new Quantized type infrastructure by providing a > >> FixedPointQTraits template. > >> > >> This allows construction of fixed point types with a Quantized storage > >> that allows easy reading of both the underlying quantized type value and > >> a floating point representation of that same value. > >> > >> Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com> > >> > >> --- > >> v4: > >> - Assert that the given type has enough bits for the usage > >> - Use unsigned types for calculating qmin/qmax > >> - Reorder toFloat/fromFloat and min/max for future inlining > >> - Make toFloat and fromFloat constexpr > >> > >> src/ipa/libipa/fixedpoint.cpp | 121 ++++++++++++++++++++++++++++++++++ > >> src/ipa/libipa/fixedpoint.h | 45 +++++++++++++ > >> 2 files changed, 166 insertions(+) > >> > > [...] > >> diff --git a/src/ipa/libipa/fixedpoint.h b/src/ipa/libipa/fixedpoint.h > >> index 709cf50f0fcd..17db8a026502 100644 > >> --- a/src/ipa/libipa/fixedpoint.h > >> +++ b/src/ipa/libipa/fixedpoint.h > >> @@ -10,6 +10,8 @@ > >> #include <cmath> > >> #include <type_traits> > >> +#include "quantized.h" > >> + > >> namespace libcamera { > >> namespace ipa { > >> @@ -60,6 +62,49 @@ constexpr R fixedToFloatingPoint(T number) > >> return static_cast<R>(t) / static_cast<R>(1 << F); > >> } > >> +template<unsigned int I, unsigned int F, typename T> > >> +struct FixedPointQTraits { > >> + static_assert(std::is_integral_v<T>, "FixedPointQTraits: T must be integral"); > >> + using QuantizedType = T; > >> + using UT = std::make_unsigned_t<T>; > >> + > >> + static constexpr unsigned int Bits = I + F; > >> + static_assert(Bits <= sizeof(T) * 8, "FixedPointQTraits: too many bits for type T"); > >> + > >> + static constexpr T BitMask = (Bits < sizeof(T) * 8) > >> + ? static_cast<T>((UT{1} << Bits) - 1) > >> + : static_cast<T>(~UT{0}); > > > > I think `UT`, `Bits`, `BitMask` could very well be private. Excellent point. > >> + > >> + static constexpr T qmin = std::is_signed_v<T> > >> + ? static_cast<T>(-(UT{1} << (Bits - 1))) > >> + : static_cast<T>(0); > >> + > >> + static constexpr T qmax = std::is_signed_v<T> > >> + ? static_cast<T>((UT{1} << (Bits - 1)) - 1) > >> + : static_cast<T>((UT{1} << Bits) - 1); > >> + > >> + static constexpr float toFloat(QuantizedType q) > >> + { > >> + return fixedToFloatingPoint<I, F, float, QuantizedType>(q); > >> + } > >> + > >> + static constexpr float min = fixedToFloatingPoint<I, F, float>(qmin); > >> + static constexpr float max = fixedToFloatingPoint<I, F, float>(qmax); > >> + > >> + /* Conversion functions required by Quantized<Traits> */ > >> + static constexpr QuantizedType fromFloat(float v) > > `floatingToFixedPoint()` can't really be `constexpr` because `std::round` > is not (before C++23), so this cannot be `constexpr` either. Phew ... I got /reaaaaally/ scared there thinking that was going to break my constexprs for defining min and max in the type. If it's just fromFloat that can't be constexpr - I think that might not be 'as bad'. Perhaps just 'sad'. I'll remove constexpr here and leave a note that it can be made constexpr in C++23. Will this break the static initialisation/usage in other ways? > >> + { > >> + v = std::clamp(v, min, max); > >> + return floatingToFixedPoint<I, F, QuantizedType, float>(v); > >> + } > >> +}; > >> + > >> +using Q1_7 = Quantized<FixedPointQTraits<1, 7, int8_t>>; > >> +using UQ1_7 = Quantized<FixedPointQTraits<1, 7, uint8_t>>; > >> + > >> +using Q12_4 = Quantized<FixedPointQTraits<12, 4, int16_t>>; > >> +using UQ12_4 = Quantized<FixedPointQTraits<12, 4, uint16_t>>; > >> + > >> } /* namespace ipa */ > >> } /* namespace libcamera */ > > >
2025. 11. 17. 13:16 keltezéssel, Kieran Bingham írta: > Quoting Barnabás Pőcze (2025-11-17 11:27:23) >> 2025. 11. 14. 19:08 keltezéssel, Barnabás Pőcze írta: >>> 2025. 11. 14. 1:54 keltezéssel, Kieran Bingham írta: >>>> Extend the new Quantized type infrastructure by providing a >>>> FixedPointQTraits template. >>>> >>>> This allows construction of fixed point types with a Quantized storage >>>> that allows easy reading of both the underlying quantized type value and >>>> a floating point representation of that same value. >>>> >>>> Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com> >>>> >>>> --- >>>> v4: >>>> - Assert that the given type has enough bits for the usage >>>> - Use unsigned types for calculating qmin/qmax >>>> - Reorder toFloat/fromFloat and min/max for future inlining >>>> - Make toFloat and fromFloat constexpr >>>> >>>> src/ipa/libipa/fixedpoint.cpp | 121 ++++++++++++++++++++++++++++++++++ >>>> src/ipa/libipa/fixedpoint.h | 45 +++++++++++++ >>>> 2 files changed, 166 insertions(+) >>>> >>> [...] >>>> diff --git a/src/ipa/libipa/fixedpoint.h b/src/ipa/libipa/fixedpoint.h >>>> index 709cf50f0fcd..17db8a026502 100644 >>>> --- a/src/ipa/libipa/fixedpoint.h >>>> +++ b/src/ipa/libipa/fixedpoint.h >>>> @@ -10,6 +10,8 @@ >>>> #include <cmath> >>>> #include <type_traits> >>>> +#include "quantized.h" >>>> + >>>> namespace libcamera { >>>> namespace ipa { >>>> @@ -60,6 +62,49 @@ constexpr R fixedToFloatingPoint(T number) >>>> return static_cast<R>(t) / static_cast<R>(1 << F); >>>> } >>>> +template<unsigned int I, unsigned int F, typename T> >>>> +struct FixedPointQTraits { >>>> + static_assert(std::is_integral_v<T>, "FixedPointQTraits: T must be integral"); >>>> + using QuantizedType = T; >>>> + using UT = std::make_unsigned_t<T>; >>>> + >>>> + static constexpr unsigned int Bits = I + F; >>>> + static_assert(Bits <= sizeof(T) * 8, "FixedPointQTraits: too many bits for type T"); >>>> + >>>> + static constexpr T BitMask = (Bits < sizeof(T) * 8) >>>> + ? static_cast<T>((UT{1} << Bits) - 1) >>>> + : static_cast<T>(~UT{0}); >>> >>> I think `UT`, `Bits`, `BitMask` could very well be private. > > Excellent point. > >>>> + >>>> + static constexpr T qmin = std::is_signed_v<T> >>>> + ? static_cast<T>(-(UT{1} << (Bits - 1))) >>>> + : static_cast<T>(0); >>>> + >>>> + static constexpr T qmax = std::is_signed_v<T> >>>> + ? static_cast<T>((UT{1} << (Bits - 1)) - 1) >>>> + : static_cast<T>((UT{1} << Bits) - 1); >>>> + >>>> + static constexpr float toFloat(QuantizedType q) >>>> + { >>>> + return fixedToFloatingPoint<I, F, float, QuantizedType>(q); >>>> + } >>>> + >>>> + static constexpr float min = fixedToFloatingPoint<I, F, float>(qmin); >>>> + static constexpr float max = fixedToFloatingPoint<I, F, float>(qmax); >>>> + >>>> + /* Conversion functions required by Quantized<Traits> */ >>>> + static constexpr QuantizedType fromFloat(float v) >> >> `floatingToFixedPoint()` can't really be `constexpr` because `std::round` >> is not (before C++23), so this cannot be `constexpr` either. > > > > Phew ... I got /reaaaaally/ scared there thinking that was going to > break my constexprs for defining min and max in the type. > > If it's just fromFloat that can't be constexpr - I think that might not > be 'as bad'. Perhaps just 'sad'. > > I'll remove constexpr here and leave a note that it can be made > constexpr in C++23. > > Will this break the static initialisation/usage in other ways? Well, `Quantized` does not have `constexpr` members, so this shouldn't change anything. In C++20, there is `std::is_constant_evaluated()` which would probably enable us to implement the necessary rounding, but I'm not sure if it's worth it without it being actually needed. In any case, gcc seems to have actually evaluated std::round() in constexpr contexts for a long time. But clang does not seem so allowing. > > >>>> + { >>>> + v = std::clamp(v, min, max); >>>> + return floatingToFixedPoint<I, F, QuantizedType, float>(v); >>>> + } >>>> +}; >>>> + >>>> +using Q1_7 = Quantized<FixedPointQTraits<1, 7, int8_t>>; >>>> +using UQ1_7 = Quantized<FixedPointQTraits<1, 7, uint8_t>>; >>>> + >>>> +using Q12_4 = Quantized<FixedPointQTraits<12, 4, int16_t>>; >>>> +using UQ12_4 = Quantized<FixedPointQTraits<12, 4, uint16_t>>; >>>> + >>>> } /* namespace ipa */ >>>> } /* namespace libcamera */ >>> >>
Hi Kieran, Thank you for the patch! Reviewed-by: Isaac Scott <isaac.scott@ideasonboard.com> Quoting Kieran Bingham (2025-11-14 00:54:07) > Extend the new Quantized type infrastructure by providing a > FixedPointQTraits template. > > This allows construction of fixed point types with a Quantized storage > that allows easy reading of both the underlying quantized type value and > a floating point representation of that same value. > > Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com> > > --- > v4: > - Assert that the given type has enough bits for the usage > - Use unsigned types for calculating qmin/qmax > - Reorder toFloat/fromFloat and min/max for future inlining > - Make toFloat and fromFloat constexpr > > src/ipa/libipa/fixedpoint.cpp | 121 ++++++++++++++++++++++++++++++++++ > src/ipa/libipa/fixedpoint.h | 45 +++++++++++++ > 2 files changed, 166 insertions(+) > > diff --git a/src/ipa/libipa/fixedpoint.cpp b/src/ipa/libipa/fixedpoint.cpp > index 6b698fc5d680..4c3ea33497bf 100644 > --- a/src/ipa/libipa/fixedpoint.cpp > +++ b/src/ipa/libipa/fixedpoint.cpp > @@ -37,6 +37,127 @@ namespace ipa { > * \return The converted value > */ > > +/** > + * \struct libcamera::ipa::FixedPointQTraits > + * \brief Traits type implementing fixed-point quantisation conversions > + * > + * The FixedPointQTraits structure defines a policy for mapping floating-point > + * values to and from fixed-point integer representations. It is parameterised > + * by the number of integer bits \a I, fractional bits \a F, and the integral > + * storage type \a T. The traits are used with Quantized<Traits> to create a > + * quantised type that stores both the fixed-point representation and the > + * corresponding floating-point value. > + * > + * The trait exposes compile-time constants describing the bit layout, limits, > + * and scaling factors used in the fixed-point representation. > + * > + * \tparam I Number of integer bits > + * \tparam F Number of fractional bits > + * \tparam T Integral type used to store the quantised value > + */ > + > +/** > + * \typedef FixedPointQTraits::QuantizedType > + * \brief The integral storage type used for the fixed-point representation > + */ > + > +/** > + * \typedef FixedPointQTraits::UT > + * \brief The unsigned representation of the integral storage > + * > + * This type definition is to support internal usage only. > + */ > + > +/** > + * \var FixedPointQTraits::Bits > + * \brief Total number of bits used in the fixed-point format (I + F) > + */ > + > +/** > + * \var FixedPointQTraits::BitMask > + * \brief Bit mask selecting all valid bits in the fixed-point representation > + */ > + > +/** > + * \var FixedPointQTraits::qmin > + * \brief Minimum representable quantised integer value > + * > + * This corresponds to the most negative value for signed formats or zero for > + * unsigned formats. > + */ > + > +/** > + * \var FixedPointQTraits::qmax > + * \brief Maximum representable quantised integer value > + */ > + > +/** > + * \var FixedPointQTraits::min > + * \brief Minimum representable floating-point value corresponding to qmin > + */ > + > +/** > + * \var FixedPointQTraits::max > + * \brief Maximum representable floating-point value corresponding to qmax > + */ > + > +/** > + * \fn FixedPointQTraits::fromFloat(float v) > + * \brief Convert a floating-point value to a fixed-point integer > + * \param[in] v The floating-point value to be converted > + * \return The quantised fixed-point integer representation > + * > + * The conversion rounds the floating-point input \a v to the nearest integer > + * according to the scaling factor defined by the number of fractional bits F. > + */ > + > +/** > + * \fn FixedPointQTraits::toFloat(QuantizedType q) > + * \brief Convert a fixed-point integer to a floating-point value > + * \param[in] q The fixed-point integer value to be converted > + * \return The corresponding floating-point value > + * > + * The conversion sign-extends the integer value if required and divides by the > + * scaling factor defined by the number of fractional bits F. > + */ > + > +/** > + * \typedef Q1_7 > + * \brief 1.7 signed fixed-point quantizer > + * > + * A Quantized type using 1 bit for the integer part and 7 bits for the > + * fractional part, stored in a signed 8-bit integer (\c int8_t). Represents > + * values approximately in the range [-1.0, 0.992] with a resolution of 1/128. > + */ > + > +/** > + * \typedef UQ1_7 > + * \brief 1.7 unsigned fixed-point quantizer > + * > + * A Quantized type using 1 bit for the integer part and 7 bits for the > + * fractional part, stored in an unsigned 8-bit integer (\c uint8_t). Represents > + * values in the range [0.0, 1.992] with a resolution of 1/128. > + */ > + > +/** > + * \typedef Q12_4 > + * \brief 12.4 signed fixed-point quantizer > + * > + * A Quantized type using 12 bits for the integer part and 4 bits for the > + * fractional part, stored in a signed 16-bit integer (\c int16_t). Represents > + * values in the range approximately [-2048.0, 2047.9375] with a resolution of > + * 1/16. > + */ > + > +/** > + * \typedef UQ12_4 > + * \brief 12.4 unsigned fixed-point quantizer > + * > + * A Quantized type using 12 bits for the integer part and 4 bits for the > + * fractional part, stored in an unsigned 16-bit integer (\c uint16_t). > + * Represents values in the range [0.0, 4095.9375] with a resolution of 1/16. > + */ > + > } /* namespace ipa */ > > } /* namespace libcamera */ > diff --git a/src/ipa/libipa/fixedpoint.h b/src/ipa/libipa/fixedpoint.h > index 709cf50f0fcd..17db8a026502 100644 > --- a/src/ipa/libipa/fixedpoint.h > +++ b/src/ipa/libipa/fixedpoint.h > @@ -10,6 +10,8 @@ > #include <cmath> > #include <type_traits> > > +#include "quantized.h" > + > namespace libcamera { > > namespace ipa { > @@ -60,6 +62,49 @@ constexpr R fixedToFloatingPoint(T number) > return static_cast<R>(t) / static_cast<R>(1 << F); > } > > +template<unsigned int I, unsigned int F, typename T> > +struct FixedPointQTraits { > + static_assert(std::is_integral_v<T>, "FixedPointQTraits: T must be integral"); > + using QuantizedType = T; > + using UT = std::make_unsigned_t<T>; > + > + static constexpr unsigned int Bits = I + F; > + static_assert(Bits <= sizeof(T) * 8, "FixedPointQTraits: too many bits for type T"); > + > + static constexpr T BitMask = (Bits < sizeof(T) * 8) > + ? static_cast<T>((UT{1} << Bits) - 1) > + : static_cast<T>(~UT{0}); > + > + static constexpr T qmin = std::is_signed_v<T> > + ? static_cast<T>(-(UT{1} << (Bits - 1))) > + : static_cast<T>(0); > + > + static constexpr T qmax = std::is_signed_v<T> > + ? static_cast<T>((UT{1} << (Bits - 1)) - 1) > + : static_cast<T>((UT{1} << Bits) - 1); > + > + static constexpr float toFloat(QuantizedType q) > + { > + return fixedToFloatingPoint<I, F, float, QuantizedType>(q); > + } > + > + static constexpr float min = fixedToFloatingPoint<I, F, float>(qmin); > + static constexpr float max = fixedToFloatingPoint<I, F, float>(qmax); > + > + /* Conversion functions required by Quantized<Traits> */ > + static constexpr QuantizedType fromFloat(float v) > + { > + v = std::clamp(v, min, max); > + return floatingToFixedPoint<I, F, QuantizedType, float>(v); > + } > +}; > + > +using Q1_7 = Quantized<FixedPointQTraits<1, 7, int8_t>>; > +using UQ1_7 = Quantized<FixedPointQTraits<1, 7, uint8_t>>; > + > +using Q12_4 = Quantized<FixedPointQTraits<12, 4, int16_t>>; > +using UQ12_4 = Quantized<FixedPointQTraits<12, 4, uint16_t>>; > + > } /* namespace ipa */ > > } /* namespace libcamera */ > -- > 2.51.1 >
On Fri, Nov 14, 2025 at 12:54:07AM +0000, Kieran Bingham wrote: > Extend the new Quantized type infrastructure by providing a > FixedPointQTraits template. > > This allows construction of fixed point types with a Quantized storage > that allows easy reading of both the underlying quantized type value and > a floating point representation of that same value. > > Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com> > > --- > v4: > - Assert that the given type has enough bits for the usage > - Use unsigned types for calculating qmin/qmax > - Reorder toFloat/fromFloat and min/max for future inlining > - Make toFloat and fromFloat constexpr > > src/ipa/libipa/fixedpoint.cpp | 121 ++++++++++++++++++++++++++++++++++ > src/ipa/libipa/fixedpoint.h | 45 +++++++++++++ > 2 files changed, 166 insertions(+) > > diff --git a/src/ipa/libipa/fixedpoint.cpp b/src/ipa/libipa/fixedpoint.cpp > index 6b698fc5d680..4c3ea33497bf 100644 > --- a/src/ipa/libipa/fixedpoint.cpp > +++ b/src/ipa/libipa/fixedpoint.cpp > @@ -37,6 +37,127 @@ namespace ipa { > * \return The converted value > */ > > +/** > + * \struct libcamera::ipa::FixedPointQTraits > + * \brief Traits type implementing fixed-point quantisation conversions > + * > + * The FixedPointQTraits structure defines a policy for mapping floating-point > + * values to and from fixed-point integer representations. It is parameterised > + * by the number of integer bits \a I, fractional bits \a F, and the integral > + * storage type \a T. The traits are used with Quantized<Traits> to create a > + * quantised type that stores both the fixed-point representation and the > + * corresponding floating-point value. > + * > + * The trait exposes compile-time constants describing the bit layout, limits, > + * and scaling factors used in the fixed-point representation. > + * > + * \tparam I Number of integer bits > + * \tparam F Number of fractional bits > + * \tparam T Integral type used to store the quantised value > + */ > + > +/** > + * \typedef FixedPointQTraits::QuantizedType > + * \brief The integral storage type used for the fixed-point representation > + */ > + > +/** > + * \typedef FixedPointQTraits::UT > + * \brief The unsigned representation of the integral storage > + * > + * This type definition is to support internal usage only. > + */ > + > +/** > + * \var FixedPointQTraits::Bits > + * \brief Total number of bits used in the fixed-point format (I + F) > + */ > + > +/** > + * \var FixedPointQTraits::BitMask > + * \brief Bit mask selecting all valid bits in the fixed-point representation > + */ > + > +/** > + * \var FixedPointQTraits::qmin > + * \brief Minimum representable quantised integer value > + * > + * This corresponds to the most negative value for signed formats or zero for > + * unsigned formats. > + */ > + > +/** > + * \var FixedPointQTraits::qmax > + * \brief Maximum representable quantised integer value > + */ > + > +/** > + * \var FixedPointQTraits::min > + * \brief Minimum representable floating-point value corresponding to qmin > + */ > + > +/** > + * \var FixedPointQTraits::max > + * \brief Maximum representable floating-point value corresponding to qmax > + */ > + > +/** > + * \fn FixedPointQTraits::fromFloat(float v) > + * \brief Convert a floating-point value to a fixed-point integer > + * \param[in] v The floating-point value to be converted > + * \return The quantised fixed-point integer representation > + * > + * The conversion rounds the floating-point input \a v to the nearest integer > + * according to the scaling factor defined by the number of fractional bits F. > + */ > + > +/** > + * \fn FixedPointQTraits::toFloat(QuantizedType q) > + * \brief Convert a fixed-point integer to a floating-point value > + * \param[in] q The fixed-point integer value to be converted > + * \return The corresponding floating-point value > + * > + * The conversion sign-extends the integer value if required and divides by the > + * scaling factor defined by the number of fractional bits F. > + */ > + > +/** > + * \typedef Q1_7 > + * \brief 1.7 signed fixed-point quantizer > + * > + * A Quantized type using 1 bit for the integer part and 7 bits for the > + * fractional part, stored in a signed 8-bit integer (\c int8_t). Represents > + * values approximately in the range [-1.0, 0.992] with a resolution of 1/128. > + */ > + > +/** > + * \typedef UQ1_7 > + * \brief 1.7 unsigned fixed-point quantizer > + * > + * A Quantized type using 1 bit for the integer part and 7 bits for the > + * fractional part, stored in an unsigned 8-bit integer (\c uint8_t). Represents > + * values in the range [0.0, 1.992] with a resolution of 1/128. > + */ > + > +/** > + * \typedef Q12_4 > + * \brief 12.4 signed fixed-point quantizer > + * > + * A Quantized type using 12 bits for the integer part and 4 bits for the > + * fractional part, stored in a signed 16-bit integer (\c int16_t). Represents > + * values in the range approximately [-2048.0, 2047.9375] with a resolution of > + * 1/16. > + */ > + > +/** > + * \typedef UQ12_4 > + * \brief 12.4 unsigned fixed-point quantizer > + * > + * A Quantized type using 12 bits for the integer part and 4 bits for the > + * fractional part, stored in an unsigned 16-bit integer (\c uint16_t). > + * Represents values in the range [0.0, 4095.9375] with a resolution of 1/16. > + */ > + > } /* namespace ipa */ > > } /* namespace libcamera */ > diff --git a/src/ipa/libipa/fixedpoint.h b/src/ipa/libipa/fixedpoint.h > index 709cf50f0fcd..17db8a026502 100644 > --- a/src/ipa/libipa/fixedpoint.h > +++ b/src/ipa/libipa/fixedpoint.h > @@ -10,6 +10,8 @@ > #include <cmath> > #include <type_traits> > > +#include "quantized.h" > + > namespace libcamera { > > namespace ipa { > @@ -60,6 +62,49 @@ constexpr R fixedToFloatingPoint(T number) > return static_cast<R>(t) / static_cast<R>(1 << F); > } > > +template<unsigned int I, unsigned int F, typename T> > +struct FixedPointQTraits { > + static_assert(std::is_integral_v<T>, "FixedPointQTraits: T must be integral"); > + using QuantizedType = T; > + using UT = std::make_unsigned_t<T>; > + > + static constexpr unsigned int Bits = I + F; s/Bits/bits/ member variables start with a lower-case latter. kBits is another option. > + static_assert(Bits <= sizeof(T) * 8, "FixedPointQTraits: too many bits for type T"); > + > + static constexpr T BitMask = (Bits < sizeof(T) * 8) Same here, bitMask or kBitMask. > + ? static_cast<T>((UT{1} << Bits) - 1) > + : static_cast<T>(~UT{0}); > + > + static constexpr T qmin = std::is_signed_v<T> qMin ? kQMin looks weird. > + ? static_cast<T>(-(UT{1} << (Bits - 1))) > + : static_cast<T>(0); > + > + static constexpr T qmax = std::is_signed_v<T> > + ? static_cast<T>((UT{1} << (Bits - 1)) - 1) > + : static_cast<T>((UT{1} << Bits) - 1); > + > + static constexpr float toFloat(QuantizedType q) > + { > + return fixedToFloatingPoint<I, F, float, QuantizedType>(q); > + } > + > + static constexpr float min = fixedToFloatingPoint<I, F, float>(qmin); > + static constexpr float max = fixedToFloatingPoint<I, F, float>(qmax); > + > + /* Conversion functions required by Quantized<Traits> */ > + static constexpr QuantizedType fromFloat(float v) > + { > + v = std::clamp(v, min, max); > + return floatingToFixedPoint<I, F, QuantizedType, float>(v); > + } > +}; > + > +using Q1_7 = Quantized<FixedPointQTraits<1, 7, int8_t>>; > +using UQ1_7 = Quantized<FixedPointQTraits<1, 7, uint8_t>>; > + > +using Q12_4 = Quantized<FixedPointQTraits<12, 4, int16_t>>; > +using UQ12_4 = Quantized<FixedPointQTraits<12, 4, uint16_t>>; > + Why Q1.7 and Q12.4 in particular ? I assume you use them later, maybe they should be introduced where they first get used ? > } /* namespace ipa */ > > } /* namespace libcamera */
Quoting Laurent Pinchart (2025-11-19 04:31:49) > On Fri, Nov 14, 2025 at 12:54:07AM +0000, Kieran Bingham wrote: > > Extend the new Quantized type infrastructure by providing a > > FixedPointQTraits template. > > > > This allows construction of fixed point types with a Quantized storage > > that allows easy reading of both the underlying quantized type value and > > a floating point representation of that same value. > > > > Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com> > > > > --- > > v4: > > - Assert that the given type has enough bits for the usage > > - Use unsigned types for calculating qmin/qmax > > - Reorder toFloat/fromFloat and min/max for future inlining > > - Make toFloat and fromFloat constexpr > > > > src/ipa/libipa/fixedpoint.cpp | 121 ++++++++++++++++++++++++++++++++++ > > src/ipa/libipa/fixedpoint.h | 45 +++++++++++++ > > 2 files changed, 166 insertions(+) > > > > diff --git a/src/ipa/libipa/fixedpoint.cpp b/src/ipa/libipa/fixedpoint.cpp > > index 6b698fc5d680..4c3ea33497bf 100644 > > --- a/src/ipa/libipa/fixedpoint.cpp > > +++ b/src/ipa/libipa/fixedpoint.cpp > > @@ -37,6 +37,127 @@ namespace ipa { > > * \return The converted value > > */ > > > > +/** > > + * \struct libcamera::ipa::FixedPointQTraits > > + * \brief Traits type implementing fixed-point quantisation conversions > > + * > > + * The FixedPointQTraits structure defines a policy for mapping floating-point > > + * values to and from fixed-point integer representations. It is parameterised > > + * by the number of integer bits \a I, fractional bits \a F, and the integral > > + * storage type \a T. The traits are used with Quantized<Traits> to create a > > + * quantised type that stores both the fixed-point representation and the > > + * corresponding floating-point value. > > + * > > + * The trait exposes compile-time constants describing the bit layout, limits, > > + * and scaling factors used in the fixed-point representation. > > + * > > + * \tparam I Number of integer bits > > + * \tparam F Number of fractional bits > > + * \tparam T Integral type used to store the quantised value > > + */ > > + > > +/** > > + * \typedef FixedPointQTraits::QuantizedType > > + * \brief The integral storage type used for the fixed-point representation > > + */ > > + > > +/** > > + * \typedef FixedPointQTraits::UT > > + * \brief The unsigned representation of the integral storage > > + * > > + * This type definition is to support internal usage only. > > + */ > > + > > +/** > > + * \var FixedPointQTraits::Bits > > + * \brief Total number of bits used in the fixed-point format (I + F) > > + */ > > + > > +/** > > + * \var FixedPointQTraits::BitMask > > + * \brief Bit mask selecting all valid bits in the fixed-point representation > > + */ > > + > > +/** > > + * \var FixedPointQTraits::qmin > > + * \brief Minimum representable quantised integer value > > + * > > + * This corresponds to the most negative value for signed formats or zero for > > + * unsigned formats. > > + */ > > + > > +/** > > + * \var FixedPointQTraits::qmax > > + * \brief Maximum representable quantised integer value > > + */ > > + > > +/** > > + * \var FixedPointQTraits::min > > + * \brief Minimum representable floating-point value corresponding to qmin > > + */ > > + > > +/** > > + * \var FixedPointQTraits::max > > + * \brief Maximum representable floating-point value corresponding to qmax > > + */ > > + > > +/** > > + * \fn FixedPointQTraits::fromFloat(float v) > > + * \brief Convert a floating-point value to a fixed-point integer > > + * \param[in] v The floating-point value to be converted > > + * \return The quantised fixed-point integer representation > > + * > > + * The conversion rounds the floating-point input \a v to the nearest integer > > + * according to the scaling factor defined by the number of fractional bits F. > > + */ > > + > > +/** > > + * \fn FixedPointQTraits::toFloat(QuantizedType q) > > + * \brief Convert a fixed-point integer to a floating-point value > > + * \param[in] q The fixed-point integer value to be converted > > + * \return The corresponding floating-point value > > + * > > + * The conversion sign-extends the integer value if required and divides by the > > + * scaling factor defined by the number of fractional bits F. > > + */ > > + > > +/** > > + * \typedef Q1_7 > > + * \brief 1.7 signed fixed-point quantizer > > + * > > + * A Quantized type using 1 bit for the integer part and 7 bits for the > > + * fractional part, stored in a signed 8-bit integer (\c int8_t). Represents > > + * values approximately in the range [-1.0, 0.992] with a resolution of 1/128. > > + */ > > + > > +/** > > + * \typedef UQ1_7 > > + * \brief 1.7 unsigned fixed-point quantizer > > + * > > + * A Quantized type using 1 bit for the integer part and 7 bits for the > > + * fractional part, stored in an unsigned 8-bit integer (\c uint8_t). Represents > > + * values in the range [0.0, 1.992] with a resolution of 1/128. > > + */ > > + > > +/** > > + * \typedef Q12_4 > > + * \brief 12.4 signed fixed-point quantizer > > + * > > + * A Quantized type using 12 bits for the integer part and 4 bits for the > > + * fractional part, stored in a signed 16-bit integer (\c int16_t). Represents > > + * values in the range approximately [-2048.0, 2047.9375] with a resolution of > > + * 1/16. > > + */ > > + > > +/** > > + * \typedef UQ12_4 > > + * \brief 12.4 unsigned fixed-point quantizer > > + * > > + * A Quantized type using 12 bits for the integer part and 4 bits for the > > + * fractional part, stored in an unsigned 16-bit integer (\c uint16_t). > > + * Represents values in the range [0.0, 4095.9375] with a resolution of 1/16. > > + */ > > + > > } /* namespace ipa */ > > > > } /* namespace libcamera */ > > diff --git a/src/ipa/libipa/fixedpoint.h b/src/ipa/libipa/fixedpoint.h > > index 709cf50f0fcd..17db8a026502 100644 > > --- a/src/ipa/libipa/fixedpoint.h > > +++ b/src/ipa/libipa/fixedpoint.h > > @@ -10,6 +10,8 @@ > > #include <cmath> > > #include <type_traits> > > > > +#include "quantized.h" > > + > > namespace libcamera { > > > > namespace ipa { > > @@ -60,6 +62,49 @@ constexpr R fixedToFloatingPoint(T number) > > return static_cast<R>(t) / static_cast<R>(1 << F); > > } > > > > +template<unsigned int I, unsigned int F, typename T> > > +struct FixedPointQTraits { > > + static_assert(std::is_integral_v<T>, "FixedPointQTraits: T must be integral"); > > + using QuantizedType = T; > > + using UT = std::make_unsigned_t<T>; > > + > > + static constexpr unsigned int Bits = I + F; > > s/Bits/bits/ > > member variables start with a lower-case latter. kBits is another > option. > > > + static_assert(Bits <= sizeof(T) * 8, "FixedPointQTraits: too many bits for type T"); > > + > > + static constexpr T BitMask = (Bits < sizeof(T) * 8) > > Same here, bitMask or kBitMask. > > > + ? static_cast<T>((UT{1} << Bits) - 1) > > + : static_cast<T>(~UT{0}); > > + > > + static constexpr T qmin = std::is_signed_v<T> > > qMin ? kQMin looks weird. > > > + ? static_cast<T>(-(UT{1} << (Bits - 1))) > > + : static_cast<T>(0); > > + > > + static constexpr T qmax = std::is_signed_v<T> > > + ? static_cast<T>((UT{1} << (Bits - 1)) - 1) > > + : static_cast<T>((UT{1} << Bits) - 1); > > + > > + static constexpr float toFloat(QuantizedType q) > > + { > > + return fixedToFloatingPoint<I, F, float, QuantizedType>(q); > > + } > > + > > + static constexpr float min = fixedToFloatingPoint<I, F, float>(qmin); > > + static constexpr float max = fixedToFloatingPoint<I, F, float>(qmax); > > + > > + /* Conversion functions required by Quantized<Traits> */ > > + static constexpr QuantizedType fromFloat(float v) > > + { > > + v = std::clamp(v, min, max); > > + return floatingToFixedPoint<I, F, QuantizedType, float>(v); > > + } > > +}; > > + > > +using Q1_7 = Quantized<FixedPointQTraits<1, 7, int8_t>>; > > +using UQ1_7 = Quantized<FixedPointQTraits<1, 7, uint8_t>>; > > + > > +using Q12_4 = Quantized<FixedPointQTraits<12, 4, int16_t>>; > > +using UQ12_4 = Quantized<FixedPointQTraits<12, 4, uint16_t>>; > > + > > Why Q1.7 and Q12.4 in particular ? I assume you use them later, maybe > they should be introduced where they first get used ? They are the types that started this project. Used by RKISP1 Cproc, so they give me the starting point to test, along side the test already in fixedpoint.c which get replaced by this implementation. I can split them out if you wish ... but it seems later you want me to drop all of these new types anyway (I would still like them though) -- Kieran > > > } /* namespace ipa */ > > > > } /* namespace libcamera */ > > -- > Regards, > > Laurent Pinchart
diff --git a/src/ipa/libipa/fixedpoint.cpp b/src/ipa/libipa/fixedpoint.cpp index 6b698fc5d680..4c3ea33497bf 100644 --- a/src/ipa/libipa/fixedpoint.cpp +++ b/src/ipa/libipa/fixedpoint.cpp @@ -37,6 +37,127 @@ namespace ipa { * \return The converted value */ +/** + * \struct libcamera::ipa::FixedPointQTraits + * \brief Traits type implementing fixed-point quantisation conversions + * + * The FixedPointQTraits structure defines a policy for mapping floating-point + * values to and from fixed-point integer representations. It is parameterised + * by the number of integer bits \a I, fractional bits \a F, and the integral + * storage type \a T. The traits are used with Quantized<Traits> to create a + * quantised type that stores both the fixed-point representation and the + * corresponding floating-point value. + * + * The trait exposes compile-time constants describing the bit layout, limits, + * and scaling factors used in the fixed-point representation. + * + * \tparam I Number of integer bits + * \tparam F Number of fractional bits + * \tparam T Integral type used to store the quantised value + */ + +/** + * \typedef FixedPointQTraits::QuantizedType + * \brief The integral storage type used for the fixed-point representation + */ + +/** + * \typedef FixedPointQTraits::UT + * \brief The unsigned representation of the integral storage + * + * This type definition is to support internal usage only. + */ + +/** + * \var FixedPointQTraits::Bits + * \brief Total number of bits used in the fixed-point format (I + F) + */ + +/** + * \var FixedPointQTraits::BitMask + * \brief Bit mask selecting all valid bits in the fixed-point representation + */ + +/** + * \var FixedPointQTraits::qmin + * \brief Minimum representable quantised integer value + * + * This corresponds to the most negative value for signed formats or zero for + * unsigned formats. + */ + +/** + * \var FixedPointQTraits::qmax + * \brief Maximum representable quantised integer value + */ + +/** + * \var FixedPointQTraits::min + * \brief Minimum representable floating-point value corresponding to qmin + */ + +/** + * \var FixedPointQTraits::max + * \brief Maximum representable floating-point value corresponding to qmax + */ + +/** + * \fn FixedPointQTraits::fromFloat(float v) + * \brief Convert a floating-point value to a fixed-point integer + * \param[in] v The floating-point value to be converted + * \return The quantised fixed-point integer representation + * + * The conversion rounds the floating-point input \a v to the nearest integer + * according to the scaling factor defined by the number of fractional bits F. + */ + +/** + * \fn FixedPointQTraits::toFloat(QuantizedType q) + * \brief Convert a fixed-point integer to a floating-point value + * \param[in] q The fixed-point integer value to be converted + * \return The corresponding floating-point value + * + * The conversion sign-extends the integer value if required and divides by the + * scaling factor defined by the number of fractional bits F. + */ + +/** + * \typedef Q1_7 + * \brief 1.7 signed fixed-point quantizer + * + * A Quantized type using 1 bit for the integer part and 7 bits for the + * fractional part, stored in a signed 8-bit integer (\c int8_t). Represents + * values approximately in the range [-1.0, 0.992] with a resolution of 1/128. + */ + +/** + * \typedef UQ1_7 + * \brief 1.7 unsigned fixed-point quantizer + * + * A Quantized type using 1 bit for the integer part and 7 bits for the + * fractional part, stored in an unsigned 8-bit integer (\c uint8_t). Represents + * values in the range [0.0, 1.992] with a resolution of 1/128. + */ + +/** + * \typedef Q12_4 + * \brief 12.4 signed fixed-point quantizer + * + * A Quantized type using 12 bits for the integer part and 4 bits for the + * fractional part, stored in a signed 16-bit integer (\c int16_t). Represents + * values in the range approximately [-2048.0, 2047.9375] with a resolution of + * 1/16. + */ + +/** + * \typedef UQ12_4 + * \brief 12.4 unsigned fixed-point quantizer + * + * A Quantized type using 12 bits for the integer part and 4 bits for the + * fractional part, stored in an unsigned 16-bit integer (\c uint16_t). + * Represents values in the range [0.0, 4095.9375] with a resolution of 1/16. + */ + } /* namespace ipa */ } /* namespace libcamera */ diff --git a/src/ipa/libipa/fixedpoint.h b/src/ipa/libipa/fixedpoint.h index 709cf50f0fcd..17db8a026502 100644 --- a/src/ipa/libipa/fixedpoint.h +++ b/src/ipa/libipa/fixedpoint.h @@ -10,6 +10,8 @@ #include <cmath> #include <type_traits> +#include "quantized.h" + namespace libcamera { namespace ipa { @@ -60,6 +62,49 @@ constexpr R fixedToFloatingPoint(T number) return static_cast<R>(t) / static_cast<R>(1 << F); } +template<unsigned int I, unsigned int F, typename T> +struct FixedPointQTraits { + static_assert(std::is_integral_v<T>, "FixedPointQTraits: T must be integral"); + using QuantizedType = T; + using UT = std::make_unsigned_t<T>; + + static constexpr unsigned int Bits = I + F; + static_assert(Bits <= sizeof(T) * 8, "FixedPointQTraits: too many bits for type T"); + + static constexpr T BitMask = (Bits < sizeof(T) * 8) + ? static_cast<T>((UT{1} << Bits) - 1) + : static_cast<T>(~UT{0}); + + static constexpr T qmin = std::is_signed_v<T> + ? static_cast<T>(-(UT{1} << (Bits - 1))) + : static_cast<T>(0); + + static constexpr T qmax = std::is_signed_v<T> + ? static_cast<T>((UT{1} << (Bits - 1)) - 1) + : static_cast<T>((UT{1} << Bits) - 1); + + static constexpr float toFloat(QuantizedType q) + { + return fixedToFloatingPoint<I, F, float, QuantizedType>(q); + } + + static constexpr float min = fixedToFloatingPoint<I, F, float>(qmin); + static constexpr float max = fixedToFloatingPoint<I, F, float>(qmax); + + /* Conversion functions required by Quantized<Traits> */ + static constexpr QuantizedType fromFloat(float v) + { + v = std::clamp(v, min, max); + return floatingToFixedPoint<I, F, QuantizedType, float>(v); + } +}; + +using Q1_7 = Quantized<FixedPointQTraits<1, 7, int8_t>>; +using UQ1_7 = Quantized<FixedPointQTraits<1, 7, uint8_t>>; + +using Q12_4 = Quantized<FixedPointQTraits<12, 4, int16_t>>; +using UQ12_4 = Quantized<FixedPointQTraits<12, 4, uint16_t>>; + } /* namespace ipa */ } /* namespace libcamera */
Extend the new Quantized type infrastructure by providing a FixedPointQTraits template. This allows construction of fixed point types with a Quantized storage that allows easy reading of both the underlying quantized type value and a floating point representation of that same value. Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com> --- v4: - Assert that the given type has enough bits for the usage - Use unsigned types for calculating qmin/qmax - Reorder toFloat/fromFloat and min/max for future inlining - Make toFloat and fromFloat constexpr src/ipa/libipa/fixedpoint.cpp | 121 ++++++++++++++++++++++++++++++++++ src/ipa/libipa/fixedpoint.h | 45 +++++++++++++ 2 files changed, 166 insertions(+)