@@ -37,6 +37,95 @@ 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
+ */
+
+/**
+ * \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 Q
+ * \brief Define a signed fixed-point quantised type with automatic storage width
+ * \tparam I The number of integer bits
+ * \tparam F The number of fractional bits
+ *
+ * This alias defines a signed fixed-point quantised type using the
+ * \ref FixedPointQTraits trait and a suitable signed integer storage type
+ * automatically selected based on the total number of bits \a (I + F).
+ */
+
+/**
+ * \typedef UQ
+ * \brief Define an unsigned fixed-point quantised type with automatic storage width
+ * \tparam I The number of integer bits
+ * \tparam F The number of fractional bits
+ *
+ * This alias defines an unsigned fixed-point quantised type using the
+ * \ref FixedPointQTraits trait and a suitable unsigned integer storage type
+ * automatically selected based on the total number of bits \a (I + F).
+ */
+
} /* namespace ipa */
} /* namespace libcamera */
@@ -10,6 +10,8 @@
#include <cmath>
#include <type_traits>
+#include "quantized.h"
+
namespace libcamera {
namespace ipa {
@@ -63,6 +65,73 @@ 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 {
+private:
+ static_assert(std::is_integral_v<T>, "FixedPointQTraits: T must be integral");
+ 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});
+
+public:
+ using QuantizedType = T;
+
+ 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);
+
+ static_assert(min < max, "FixedPointQTraits: Minimum must be less than maximum");
+
+ /* Conversion functions required by Quantized<Traits> */
+ static QuantizedType fromFloat(float v)
+ {
+ v = std::clamp(v, min, max);
+ return floatingToFixedPoint<I, F, QuantizedType, float>(v);
+ }
+};
+
+namespace details {
+
+template<unsigned int Bits>
+constexpr auto qtype()
+{
+ static_assert(Bits <= 64);
+
+ if constexpr (Bits <= 8)
+ return int8_t();
+ else if constexpr (Bits <= 16)
+ return int16_t();
+ else if constexpr (Bits <= 32)
+ return int32_t();
+ else if constexpr (Bits <= 64)
+ return int64_t();
+}
+
+} /* namespace details */
+
+template<unsigned int I, unsigned int F>
+using Q = Quantized<FixedPointQTraits<I, F, decltype(details::qtype<I + F>())>>;
+
+template<unsigned int I, unsigned int F>
+using UQ = Quantized<FixedPointQTraits<I, F, std::make_unsigned_t<decltype(details::qtype<I + F>())>>>;
+
} /* namespace ipa */
} /* namespace libcamera */