Blender V4.3
mikk_util.hh
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2022-2023 Blender Authors
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
9#pragma once
10
11#include <cassert>
12#include <cmath>
13
14#ifndef M_PI_F
15# define M_PI_F (3.1415926535897932f) /* pi */
16#endif
17
18namespace mikk {
19
20inline bool not_zero(const float fX)
21{
22 return fabsf(fX) > FLT_MIN;
23}
24
25/* Helpers for (un)packing a 2-bit vertex index and a 30-bit face index to one integer. */
26static uint pack_index(const uint face, const uint vert)
27{
28 assert((vert & 0x3) == vert);
29 return (face << 2) | (vert & 0x3);
30}
31
32static void unpack_index(uint &face, uint &vert, const uint indexIn)
33{
34 vert = indexIn & 0x3;
35 face = indexIn >> 2;
36}
37
38/* From intern/cycles/util/math_fast.h */
39inline float fast_acosf(float x)
40{
41 const float f = fabsf(x);
42 /* clamp and crush denormals. */
43 const float m = (f < 1.0f) ? 1.0f - (1.0f - f) : 1.0f;
44 /* Based on http://www.pouet.net/topic.php?which=9132&page=2
45 * 85% accurate (ULP 0)
46 * Examined 2130706434 values of acos:
47 * 15.2000597 avg ULP diff, 4492 max ULP, 4.51803e-05 max error // without "denormal crush"
48 * Examined 2130706434 values of acos:
49 * 15.2007108 avg ULP diff, 4492 max ULP, 4.51803e-05 max error // with "denormal crush"
50 */
51 const float a = sqrtf(1.0f - m) *
52 (1.5707963267f + m * (-0.213300989f + m * (0.077980478f + m * -0.02164095f)));
53 return x < 0 ? M_PI_F - a : a;
54}
55
56static uint rotl(uint x, uint k)
57{
58 return (x << k) | (x >> (32 - k));
59}
60
61static uint hash_uint3(uint kx, uint ky, uint kz)
62{
63 uint a, b, c;
64 a = b = c = 0xdeadbeef + (2 << 2) + 13;
65
66 c += kz;
67 b += ky;
68 a += kx;
69
70 c = (c ^ b) - rotl(b, 14);
71 a = (a ^ c) - rotl(c, 11);
72 b = (b ^ a) - rotl(a, 25);
73 c = (c ^ b) - rotl(b, 16);
74
75 return c;
76}
77
78static uint hash_uint3_fast(const uint x, const uint y, const uint z)
79{
80 return (x * 73856093) ^ (y * 19349663) ^ (z * 83492791);
81}
82
83static uint float_as_uint(const float v)
84{
85 return *((uint *)(&v));
86}
87
88static float uint_as_float(const uint v)
89{
90 return *((float *)(&v));
91}
92
93static uint hash_float3_fast(const float x, const float y, const float z)
94{
96}
97
98static uint hash_float3x3(const float3 &x, const float3 &y, const float3 &z)
99{
100 return hash_uint3(hash_float3_fast(x.x, x.y, x.z),
101 hash_float3_fast(y.x, y.y, y.z),
102 hash_float3_fast(z.x, z.y, z.z));
103}
104
105template<typename T, typename KeyGetter>
106void radixsort(std::vector<T> &data, std::vector<T> &data2, KeyGetter getKey)
107{
108 typedef decltype(getKey(data[0])) key_t;
109 constexpr size_t datasize = sizeof(key_t);
110 static_assert(datasize % 2 == 0);
111 static_assert(std::is_integral<key_t>::value);
112
113 uint bins[datasize][257] = {{0}};
114
115 /* Count number of elements per bin. */
116 for (const T &item : data) {
117 key_t key = getKey(item);
118 for (uint pass = 0; pass < datasize; pass++)
119 bins[pass][((key >> (8 * pass)) & 0xff) + 1]++;
120 }
121
122 /* Compute prefix sum to find position of each bin in the sorted array. */
123 for (uint pass = 0; pass < datasize; pass++) {
124 for (uint i = 2; i < 256; i++) {
125 bins[pass][i] += bins[pass][i - 1];
126 }
127 }
128
129 int shift = 0;
130 for (uint pass = 0; pass < datasize; pass++, shift += 8) {
131 /* Insert the elements in their correct location based on their bin. */
132 for (const T &item : data) {
133 uint pos = bins[pass][(getKey(item) >> shift) & 0xff]++;
134 data2[pos] = item;
135 }
136
137 /* Swap arrays. */
138 std::swap(data, data2);
139 }
140}
141
142static void float_add_atomic(float *val, float add)
143{
144 /* Hacky, but atomic floats are only supported from C++20 onward.
145 * This works in practice since `std::atomic<uint32_t>` is really just an `uint32_t` in memory,
146 * so this cast lets us do a 32-bit CAS operation (which is used to build the atomic float
147 * operation) without needing any external libraries or compiler-specific builtins. */
148 std::atomic<uint32_t> *atomic_val = reinterpret_cast<std::atomic<uint32_t> *>(val);
149 for (;;) {
150 uint32_t old_v = atomic_val->load();
151 uint32_t new_v = float_as_uint(uint_as_float(old_v) + add);
152 if (atomic_val->compare_exchange_weak(old_v, new_v)) {
153 return;
154 }
155 }
156}
157
158} // namespace mikk
unsigned int uint
ATTR_WARN_UNUSED_RESULT const BMVert * v
SIMD_FORCE_INLINE const btScalar & z() const
Return the z value.
Definition btQuadWord.h:117
local_group_size(16, 16) .push_constant(Type b
#define fabsf(x)
#define sqrtf(x)
#define M_PI_F
Definition mikk_util.hh:15
static uint hash_uint3(uint kx, uint ky, uint kz)
Definition mikk_util.hh:61
static uint pack_index(const uint face, const uint vert)
Definition mikk_util.hh:26
bool not_zero(const float fX)
Definition mikk_util.hh:20
static uint float_as_uint(const float v)
Definition mikk_util.hh:83
static uint hash_float3_fast(const float x, const float y, const float z)
Definition mikk_util.hh:93
static void unpack_index(uint &face, uint &vert, const uint indexIn)
Definition mikk_util.hh:32
static uint rotl(uint x, uint k)
Definition mikk_util.hh:56
static uint hash_float3x3(const float3 &x, const float3 &y, const float3 &z)
Definition mikk_util.hh:98
static void float_add_atomic(float *val, float add)
Definition mikk_util.hh:142
static float uint_as_float(const uint v)
Definition mikk_util.hh:88
void radixsort(std::vector< T > &data, std::vector< T > &data2, KeyGetter getKey)
Definition mikk_util.hh:106
static uint hash_uint3_fast(const uint x, const uint y, const uint z)
Definition mikk_util.hh:78
float fast_acosf(float x)
Definition mikk_util.hh:39
unsigned int uint32_t
Definition stdint.h:80