1 | // Copyright 2016 The SwiftShader Authors. All Rights Reserved. |
2 | // |
3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | // you may not use this file except in compliance with the License. |
5 | // You may obtain a copy of the License at |
6 | // |
7 | // http://www.apache.org/licenses/LICENSE-2.0 |
8 | // |
9 | // Unless required by applicable law or agreed to in writing, software |
10 | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | // See the License for the specific language governing permissions and |
13 | // limitations under the License. |
14 | |
15 | #ifndef sw_Math_hpp |
16 | #define sw_Math_hpp |
17 | |
18 | #include "Types.hpp" |
19 | #include "Half.hpp" |
20 | |
21 | #include <cmath> |
22 | #if defined(_MSC_VER) |
23 | #include <intrin.h> |
24 | #endif |
25 | |
26 | namespace sw |
27 | { |
28 | using std::abs; |
29 | |
30 | #undef min |
31 | #undef max |
32 | |
33 | template<class T> |
34 | inline T max(T a, T b) |
35 | { |
36 | return a > b ? a : b; |
37 | } |
38 | |
39 | template<class T> |
40 | inline T min(T a, T b) |
41 | { |
42 | return a < b ? a : b; |
43 | } |
44 | |
45 | template<class T> |
46 | inline T max(T a, T b, T c) |
47 | { |
48 | return max(max(a, b), c); |
49 | } |
50 | |
51 | template<class T> |
52 | inline T min(T a, T b, T c) |
53 | { |
54 | return min(min(a, b), c); |
55 | } |
56 | |
57 | template<class T> |
58 | inline T max(T a, T b, T c, T d) |
59 | { |
60 | return max(max(a, b), max(c, d)); |
61 | } |
62 | |
63 | template<class T> |
64 | inline T min(T a, T b, T c, T d) |
65 | { |
66 | return min(min(a, b), min(c, d)); |
67 | } |
68 | |
69 | template<class T> |
70 | inline void swap(T &a, T &b) |
71 | { |
72 | T t = a; |
73 | a = b; |
74 | b = t; |
75 | } |
76 | |
77 | template <typename destType, typename sourceType> |
78 | destType bit_cast(const sourceType &source) |
79 | { |
80 | union |
81 | { |
82 | sourceType s; |
83 | destType d; |
84 | } sd; |
85 | sd.s = source; |
86 | return sd.d; |
87 | } |
88 | |
89 | inline int iround(float x) |
90 | { |
91 | return (int)floor(x + 0.5f); |
92 | // return _mm_cvtss_si32(_mm_load_ss(&x)); // FIXME: Demands SSE support |
93 | } |
94 | |
95 | inline int ifloor(float x) |
96 | { |
97 | return (int)floor(x); |
98 | } |
99 | |
100 | inline int ceilFix4(int x) |
101 | { |
102 | return (x + 0xF) & 0xFFFFFFF0; |
103 | } |
104 | |
105 | inline int ceilInt4(int x) |
106 | { |
107 | return (x + 0xF) >> 4; |
108 | } |
109 | |
110 | #define BITS(x) ( \ |
111 | !!((x) & 0x80000000) + \ |
112 | !!((x) & 0xC0000000) + \ |
113 | !!((x) & 0xE0000000) + \ |
114 | !!((x) & 0xF0000000) + \ |
115 | !!((x) & 0xF8000000) + \ |
116 | !!((x) & 0xFC000000) + \ |
117 | !!((x) & 0xFE000000) + \ |
118 | !!((x) & 0xFF000000) + \ |
119 | !!((x) & 0xFF800000) + \ |
120 | !!((x) & 0xFFC00000) + \ |
121 | !!((x) & 0xFFE00000) + \ |
122 | !!((x) & 0xFFF00000) + \ |
123 | !!((x) & 0xFFF80000) + \ |
124 | !!((x) & 0xFFFC0000) + \ |
125 | !!((x) & 0xFFFE0000) + \ |
126 | !!((x) & 0xFFFF0000) + \ |
127 | !!((x) & 0xFFFF8000) + \ |
128 | !!((x) & 0xFFFFC000) + \ |
129 | !!((x) & 0xFFFFE000) + \ |
130 | !!((x) & 0xFFFFF000) + \ |
131 | !!((x) & 0xFFFFF800) + \ |
132 | !!((x) & 0xFFFFFC00) + \ |
133 | !!((x) & 0xFFFFFE00) + \ |
134 | !!((x) & 0xFFFFFF00) + \ |
135 | !!((x) & 0xFFFFFF80) + \ |
136 | !!((x) & 0xFFFFFFC0) + \ |
137 | !!((x) & 0xFFFFFFE0) + \ |
138 | !!((x) & 0xFFFFFFF0) + \ |
139 | !!((x) & 0xFFFFFFF8) + \ |
140 | !!((x) & 0xFFFFFFFC) + \ |
141 | !!((x) & 0xFFFFFFFE) + \ |
142 | !!((x) & 0xFFFFFFFF)) |
143 | |
144 | #define MAX(x, y) ((x) > (y) ? (x) : (y)) |
145 | #define MIN(x, y) ((x) < (y) ? (x) : (y)) |
146 | |
147 | inline float exp2(float x) |
148 | { |
149 | return exp2f(x); |
150 | } |
151 | |
152 | inline int exp2(int x) |
153 | { |
154 | return 1 << x; |
155 | } |
156 | |
157 | inline unsigned long log2(int x) |
158 | { |
159 | #if defined(_MSC_VER) |
160 | unsigned long y; |
161 | _BitScanReverse(&y, x); |
162 | return y; |
163 | #else |
164 | return 31 - __builtin_clz(x); |
165 | #endif |
166 | } |
167 | |
168 | inline int ilog2(float x) |
169 | { |
170 | unsigned int y = *(unsigned int*)&x; |
171 | |
172 | return ((y & 0x7F800000) >> 23) - 127; |
173 | } |
174 | |
175 | inline float log2(float x) |
176 | { |
177 | return logf(x) * 1.44269504f; // 1.0 / log[e](2) |
178 | } |
179 | |
180 | inline bool isPow2(int x) |
181 | { |
182 | return (x & -x) == x; |
183 | } |
184 | |
185 | template<class T> |
186 | inline T clamp(T x, T a, T b) |
187 | { |
188 | if(x < a) x = a; |
189 | if(x > b) x = b; |
190 | |
191 | return x; |
192 | } |
193 | |
194 | inline float clamp01(float x) |
195 | { |
196 | return clamp(x, 0.0f, 1.0f); |
197 | } |
198 | |
199 | // Bit-cast of a floating-point value into a two's complement integer representation. |
200 | // This makes floating-point values comparable as integers. |
201 | inline int32_t float_as_twos_complement(float f) |
202 | { |
203 | // IEEE-754 floating-point numbers are sorted by magnitude in the same way as integers, |
204 | // except negative values are like one's complement integers. Convert them to two's complement. |
205 | int32_t i = bit_cast<int32_t>(f); |
206 | return (i < 0) ? (0x7FFFFFFFu - i) : i; |
207 | } |
208 | |
209 | // 'Safe' clamping operation which always returns a value between min and max (inclusive). |
210 | inline float clamp_s(float x, float min, float max) |
211 | { |
212 | // NaN values can't be compared directly |
213 | if(float_as_twos_complement(x) < float_as_twos_complement(min)) x = min; |
214 | if(float_as_twos_complement(x) > float_as_twos_complement(max)) x = max; |
215 | |
216 | return x; |
217 | } |
218 | |
219 | inline int ceilPow2(int x) |
220 | { |
221 | int i = 1; |
222 | |
223 | while(i < x) |
224 | { |
225 | i <<= 1; |
226 | } |
227 | |
228 | return i; |
229 | } |
230 | |
231 | inline int floorDiv(int a, int b) |
232 | { |
233 | return a / b + ((a % b) >> 31); |
234 | } |
235 | |
236 | inline int floorMod(int a, int b) |
237 | { |
238 | int r = a % b; |
239 | return r + ((r >> 31) & b); |
240 | } |
241 | |
242 | inline int ceilDiv(int a, int b) |
243 | { |
244 | return a / b - (-(a % b) >> 31); |
245 | } |
246 | |
247 | inline int ceilMod(int a, int b) |
248 | { |
249 | int r = a % b; |
250 | return r - ((-r >> 31) & b); |
251 | } |
252 | |
253 | template<const int n> |
254 | inline unsigned int unorm(float x) |
255 | { |
256 | static const unsigned int max = 0xFFFFFFFF >> (32 - n); |
257 | static const float maxf = static_cast<float>(max); |
258 | |
259 | if(x >= 1.0f) |
260 | { |
261 | return max; |
262 | } |
263 | else if(x <= 0.0f) |
264 | { |
265 | return 0; |
266 | } |
267 | else |
268 | { |
269 | return static_cast<unsigned int>(maxf * x + 0.5f); |
270 | } |
271 | } |
272 | |
273 | template<const int n> |
274 | inline int snorm(float x) |
275 | { |
276 | static const unsigned int min = 0x80000000 >> (32 - n); |
277 | static const unsigned int max = 0xFFFFFFFF >> (32 - n + 1); |
278 | static const float maxf = static_cast<float>(max); |
279 | static const unsigned int range = 0xFFFFFFFF >> (32 - n); |
280 | |
281 | if(x >= 0.0f) |
282 | { |
283 | if(x >= 1.0f) |
284 | { |
285 | return max; |
286 | } |
287 | else |
288 | { |
289 | return static_cast<int>(maxf * x + 0.5f); |
290 | } |
291 | } |
292 | else |
293 | { |
294 | if(x <= -1.0f) |
295 | { |
296 | return min; |
297 | } |
298 | else |
299 | { |
300 | return static_cast<int>(maxf * x - 0.5f) & range; |
301 | } |
302 | } |
303 | } |
304 | |
305 | template<const int n> |
306 | inline unsigned int ucast(float x) |
307 | { |
308 | static const unsigned int max = 0xFFFFFFFF >> (32 - n); |
309 | static const float maxf = static_cast<float>(max); |
310 | |
311 | if(x >= maxf) |
312 | { |
313 | return max; |
314 | } |
315 | else if(x <= 0.0f) |
316 | { |
317 | return 0; |
318 | } |
319 | else |
320 | { |
321 | return static_cast<unsigned int>(x + 0.5f); |
322 | } |
323 | } |
324 | |
325 | template<const int n> |
326 | inline int scast(float x) |
327 | { |
328 | static const unsigned int min = 0x80000000 >> (32 - n); |
329 | static const unsigned int max = 0xFFFFFFFF >> (32 - n + 1); |
330 | static const float maxf = static_cast<float>(max); |
331 | static const float minf = static_cast<float>(min); |
332 | static const unsigned int range = 0xFFFFFFFF >> (32 - n); |
333 | |
334 | if(x > 0.0f) |
335 | { |
336 | if(x >= maxf) |
337 | { |
338 | return max; |
339 | } |
340 | else |
341 | { |
342 | return static_cast<int>(x + 0.5f); |
343 | } |
344 | } |
345 | else |
346 | { |
347 | if(x <= -minf) |
348 | { |
349 | return min; |
350 | } |
351 | else |
352 | { |
353 | return static_cast<int>(x - 0.5f) & range; |
354 | } |
355 | } |
356 | } |
357 | |
358 | inline float sRGBtoLinear(float c) |
359 | { |
360 | if(c <= 0.04045f) |
361 | { |
362 | return c * 0.07739938f; // 1.0f / 12.92f; |
363 | } |
364 | else |
365 | { |
366 | return powf((c + 0.055f) * 0.9478673f, 2.4f); // 1.0f / 1.055f |
367 | } |
368 | } |
369 | |
370 | inline float linearToSRGB(float c) |
371 | { |
372 | if(c <= 0.0031308f) |
373 | { |
374 | return c * 12.92f; |
375 | } |
376 | else |
377 | { |
378 | return 1.055f * powf(c, 0.4166667f) - 0.055f; // 1.0f / 2.4f |
379 | } |
380 | } |
381 | |
382 | unsigned char sRGB8toLinear8(unsigned char value); |
383 | |
384 | uint64_t FNV_1a(const unsigned char *data, int size); // Fowler-Noll-Vo hash function |
385 | |
386 | // Round up to the next multiple of alignment |
387 | template<typename T> |
388 | inline T align(T value, unsigned int alignment) |
389 | { |
390 | return ((value + alignment - 1) / alignment) * alignment; |
391 | } |
392 | |
393 | template<unsigned int alignment, typename T> |
394 | inline T align(T value) |
395 | { |
396 | return ((value + alignment - 1) / alignment) * alignment; |
397 | } |
398 | |
399 | inline int clampToSignedInt(unsigned int x) |
400 | { |
401 | return static_cast<int>(min(x, 0x7FFFFFFFu)); |
402 | } |
403 | } |
404 | |
405 | #endif // sw_Math_hpp |
406 | |