ipa: libipa: fixedpoint: Move float conversion inline

With all users of the floatingToFixedPoint and fixedToFloatingPoint
calls converted to use the FixedPoint Quantized types, remove the calls
and documentation and move the implementation inline in the
FixedPointTraits implementation.

Reviewed-by: Isaac Scott <isaac.scott@ideasonboard.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
This commit is contained in:
Kieran Bingham
2026-02-19 15:05:16 +00:00
parent f05aab5aca
commit 8064c4f33a
2 changed files with 22 additions and 75 deletions

View File

@@ -15,28 +15,6 @@ namespace libcamera {
namespace ipa {
/**
* \fn R floatingToFixedPoint(T number)
* \brief Convert a floating point number to a fixed-point representation
* \tparam I Bit width of the integer part of the fixed-point
* \tparam F Bit width of the fractional part of the fixed-point
* \tparam R Return type of the fixed-point representation
* \tparam T Input type of the floating point representation
* \param number The floating point number to convert to fixed point
* \return The converted value
*/
/**
* \fn R fixedToFloatingPoint(T number)
* \brief Convert a fixed-point number to a floating point representation
* \tparam I Bit width of the integer part of the fixed-point
* \tparam F Bit width of the fractional part of the fixed-point
* \tparam R Return type of the floating point representation
* \tparam T Input type of the fixed-point representation
* \param number The fixed point number to convert to floating point
* \return The converted value
*/
/**
* \struct libcamera::ipa::FixedPointQTraits
* \brief Traits type implementing fixed-point quantization conversions

View File

@@ -16,55 +16,6 @@ namespace libcamera {
namespace ipa {
#ifndef __DOXYGEN__
template<unsigned int I, unsigned int F, typename R, typename T,
std::enable_if_t<std::is_integral_v<R> &&
std::is_floating_point_v<T>> * = nullptr>
#else
template<unsigned int I, unsigned int F, typename R, typename T>
#endif
constexpr R floatingToFixedPoint(T number)
{
static_assert(sizeof(int) >= sizeof(R));
static_assert(I + F <= sizeof(R) * 8);
/*
* The intermediate cast to int is needed on arm platforms to properly
* cast negative values. See
* https://embeddeduse.com/2013/08/25/casting-a-negative-float-to-an-unsigned-int/
*/
R mask = (1 << (F + I)) - 1;
R frac = static_cast<R>(static_cast<int>(std::round(number * (1 << F)))) & mask;
return frac;
}
#ifndef __DOXYGEN__
template<unsigned int I, unsigned int F, typename R, typename T,
std::enable_if_t<std::is_floating_point_v<R> &&
std::is_integral_v<T>> * = nullptr>
#else
template<unsigned int I, unsigned int F, typename R, typename T>
#endif
constexpr R fixedToFloatingPoint(T number)
{
static_assert(sizeof(int) >= sizeof(T));
static_assert(I + F <= sizeof(T) * 8);
if constexpr (std::is_unsigned_v<T>)
return static_cast<R>(number) / static_cast<R>(T{ 1 } << F);
/*
* Recreate the upper bits in case of a negative number by shifting the sign
* bit from the fixed point to the first bit of the unsigned and then right shifting
* by the same amount which keeps the sign bit in place.
* This can be optimized by the compiler quite well.
*/
int remaining_bits = sizeof(int) * 8 - (I + F);
int t = static_cast<int>(static_cast<unsigned>(number) << remaining_bits) >> remaining_bits;
return static_cast<R>(t) / static_cast<R>(1 << F);
}
template<unsigned int I, unsigned int F, typename T>
struct FixedPointQTraits {
private:
@@ -97,11 +48,23 @@ public:
static constexpr float toFloat(QuantizedType q)
{
return fixedToFloatingPoint<I, F, float, T>(q);
if constexpr (std::is_unsigned_v<T>)
return static_cast<float>(q) / static_cast<float>(UT{ 1 } << F);
/*
* Recreate the upper bits in case of a negative number by
* shifting the sign bit from the fixed point to the first bit
* of the unsigned and then right shifting by the same amount
* which keeps the sign bit in place. This can be optimized by
* the compiler quite well.
*/
unsigned int remaining_bits = sizeof(UT) * 8 - (I + F);
T t = static_cast<T>(static_cast<UT>(q) << remaining_bits) >> remaining_bits;
return static_cast<float>(t) / static_cast<float>(UT{ 1 } << F);
}
static constexpr float min = fixedToFloatingPoint<I, F, float>(static_cast<T>(qMin));
static constexpr float max = fixedToFloatingPoint<I, F, float>(static_cast<T>(qMax));
static constexpr float min = toFloat(qMin);
static constexpr float max = toFloat(qMax);
static_assert(min < max, "FixedPointQTraits: Minimum must be less than maximum");
@@ -109,7 +72,13 @@ public:
static QuantizedType fromFloat(float v)
{
v = std::clamp(v, min, max);
return floatingToFixedPoint<I, F, T, float>(v);
/*
* The intermediate cast to int is needed on arm platforms to
* properly cast negative values. See
* https://embeddeduse.com/2013/08/25/casting-a-negative-float-to-an-unsigned-int/
*/
return static_cast<UT>(static_cast<T>(std::round(v * (1 << F)))) & bitMask;
}
};