From 5f9f43e658853ab98bfac38a3f4fd61e12127963 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Fri, 27 Sep 2024 10:55:24 +0200 Subject: [PATCH] [util] Add helpers to encode or decode fixed-point numbers --- src/util/util_bit.h | 57 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/src/util/util_bit.h b/src/util/util_bit.h index 8f7b17dc6..10d6e79b4 100644 --- a/src/util/util_bit.h +++ b/src/util/util_bit.h @@ -529,4 +529,61 @@ namespace dxvk::bit { uint32_t m_mask; }; + + + /** + * \brief Encodes float as fixed point + * + * Rounds away from zero. If this is not suitable for + * certain use cases, implement round to nearest even. + * \tparam T Integer type, may be signed + * \tparam I Integer bits + * \tparam F Fractional bits + * \param n Float to encode + * \returns Encoded fixed-point value + */ + template + T encodeFixed(float n) { + if (n != n) + return 0u; + + n *= float(1u << F); + + if constexpr (std::is_signed_v) { + n = std::max(n, -float(1u << (I + F - 1u))); + n = std::min(n, float(1u << (I + F - 1u)) - 1.0f); + n += n < 0.0f ? -0.5f : 0.5f; + } else { + n = std::max(n, 0.0f); + n = std::min(n, float(1u << (I + F)) - 1.0f); + n += 0.5f; + } + + T result = T(n); + + if constexpr (std::is_signed_v) + result &= ((T(1u) << (I + F)) - 1u); + + return result; + } + + + /** + * \brief Decodes fixed-point integer to float + * + * \tparam T Integer type, may be signed + * \tparam I Integer bits + * \tparam F Fractional bits + * \param n Number to decode + * \returns Decoded number + */ + template + float decodeFixed(T n) { + // Sign-extend as necessary + if constexpr (std::is_signed_v) + n -= (n & (T(1u) << (I + F - 1u))) << 1u; + + return float(n) / float(1u << F); + } + }