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
26namespace 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