Blender codebase had two ways to convert half (FP16) to float (FP32):
- BLI_math_bits.h half_to_float. Out of 64k possible half values, it converts
4096 of them incorrectly. Mostly denormals and NaNs, which is perhaps not too
relevant. But more importantly, it converts half zero to float 0.000030517578
which does not sound ideal.
- Functions in Vulkan vk_data_conversion.hh. This one converts 2046 possible
half values incorrectly.
Function to convert float (FP32) to half (FP16) was in Vulkan
vk_data_conversion.hh, and it got a bunch of possible inputs wrong. I guess it
did not do proper "round to nearest even" that CPU/GPU hardware does.
This PR:
- Adds BLI_math_half.hh with float_to_half and half_to_float functions.
- Documentation and test coverage.
- When compiling on ARM NEON, use hardware VCVT instructions.
- Removes the incorrect half_to_float from BLI_math_bits.h and replaces single
usage of it in View3D color picking to use the new function.
- Changes Vulkan FP32<->FP16 conversion code to use the new functions, to fix
correctness issues (makes eevee_next_bsdf_vulkan test pass). This makes it
faster too.
Pull Request: https://projects.blender.org/blender/blender/pulls/127708
70 lines
1.9 KiB
C
70 lines
1.9 KiB
C
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
#pragma once
|
|
|
|
/** \file
|
|
* \ingroup bli
|
|
*/
|
|
|
|
#include "BLI_build_config.h"
|
|
#include "BLI_math_inline.h"
|
|
#include "BLI_utildefines.h"
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/* Search the value from LSB to MSB for a set bit. Returns index of this bit. */
|
|
|
|
MINLINE int bitscan_forward_i(int a);
|
|
MINLINE unsigned int bitscan_forward_uint(unsigned int a);
|
|
MINLINE unsigned int bitscan_forward_uint64(unsigned long long a);
|
|
|
|
/* Similar to above, but also clears the bit. */
|
|
|
|
MINLINE int bitscan_forward_clear_i(int *a);
|
|
MINLINE unsigned int bitscan_forward_clear_uint(unsigned int *a);
|
|
|
|
/* Search the value from MSB to LSB for a set bit. Returns index of this bit. */
|
|
|
|
MINLINE int bitscan_reverse_i(int a);
|
|
MINLINE unsigned int bitscan_reverse_uint(unsigned int a);
|
|
MINLINE unsigned int bitscan_reverse_uint64(unsigned long long a);
|
|
|
|
/* Similar to above, but also clears the bit. */
|
|
|
|
MINLINE int bitscan_reverse_clear_i(int *a);
|
|
MINLINE unsigned int bitscan_reverse_clear_uint(unsigned int *a);
|
|
|
|
/* NOTE: Those functions returns 2 to the power of index of highest order bit. */
|
|
|
|
MINLINE unsigned int highest_order_bit_uint(unsigned int n);
|
|
MINLINE unsigned short highest_order_bit_s(unsigned short n);
|
|
|
|
#if COMPILER_GCC || COMPILER_CLANG
|
|
# define count_bits_i(i) __builtin_popcount(i)
|
|
# define count_bits_uint64(i) __builtin_popcountll(i)
|
|
#elif COMPILER_MSVC
|
|
# define count_bits_i(i) __popcnt(i)
|
|
# define count_bits_uint64(i) __popcnt64(i)
|
|
#else
|
|
MINLINE int count_bits_i(unsigned int n);
|
|
MINLINE int count_bits_uint64(uint64_t a);
|
|
#endif
|
|
|
|
MINLINE int float_as_int(float f);
|
|
MINLINE unsigned int float_as_uint(float f);
|
|
MINLINE float int_as_float(int i);
|
|
MINLINE float uint_as_float(unsigned int i);
|
|
MINLINE float xor_fl(float x, int y);
|
|
|
|
#if BLI_MATH_DO_INLINE
|
|
# include "intern/math_bits_inline.c"
|
|
#endif
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|