diff options
author | Daniel Scally <dan.scally@ideasonboard.com> | 2024-11-15 12:25:30 +0000 |
---|---|---|
committer | Daniel Scally <dan.scally@ideasonboard.com> | 2024-12-17 22:35:58 +0000 |
commit | 3dd5725a84f5ac71c384431ffc4929962aeaf6b2 (patch) | |
tree | 562c6e6f3338091e5e588cd24fa38161d03e04e2 /src/ipa/libipa/fixedpoint.h | |
parent | e4178d7943e16ffb18074a24e6c4fe0143f6c730 (diff) |
libipa: Centralise Fixed / Floating point convertors
The rkisp1 IPA has some utility functions to convert between fixed
and floating point numbers. Move those to libipa so they're available
for use in other IPA modules too.
Signed-off-by: Daniel Scally <dan.scally@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Diffstat (limited to 'src/ipa/libipa/fixedpoint.h')
-rw-r--r-- | src/ipa/libipa/fixedpoint.h | 65 |
1 files changed, 65 insertions, 0 deletions
diff --git a/src/ipa/libipa/fixedpoint.h b/src/ipa/libipa/fixedpoint.h new file mode 100644 index 00000000..709cf50f --- /dev/null +++ b/src/ipa/libipa/fixedpoint.h @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2024, Paul Elder <paul.elder@ideasonboard.com> + * + * Fixed / floating point conversions + */ + +#pragma once + +#include <cmath> +#include <type_traits> + +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); + + /* + * 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); +} + +} /* namespace ipa */ + +} /* namespace libcamera */ |