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 "Debug.hpp"
19 #include "Types.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>
max(T a,T b)34 inline T constexpr max(T a, T b)
35 {
36 return a > b ? a : b;
37 }
38
39 template<class T>
min(T a,T b)40 inline constexpr T min(T a, T b)
41 {
42 return a < b ? a : b;
43 }
44
45 template<class T>
max(T a,T b,T c)46 inline constexpr T max(T a, T b, T c)
47 {
48 return max(max(a, b), c);
49 }
50
51 template<class T>
min(T a,T b,T c)52 inline constexpr T min(T a, T b, T c)
53 {
54 return min(min(a, b), c);
55 }
56
57 template<class T>
max(T a,T b,T c,T d)58 inline constexpr 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>
min(T a,T b,T c,T d)64 inline constexpr T min(T a, T b, T c, T d)
65 {
66 return min(min(a, b), min(c, d));
67 }
68
69 template<typename destType, typename sourceType>
bit_cast(const sourceType & source)70 destType bit_cast(const sourceType &source)
71 {
72 union
73 {
74 sourceType s;
75 destType d;
76 } sd;
77 sd.s = source;
78 return sd.d;
79 }
80
iround(float x)81 inline int iround(float x)
82 {
83 return (int)floor(x + 0.5f);
84 // return _mm_cvtss_si32(_mm_load_ss(&x)); // FIXME: Demands SSE support
85 }
86
ifloor(float x)87 inline int ifloor(float x)
88 {
89 return (int)floor(x);
90 }
91
ceilFix4(int x)92 inline int ceilFix4(int x)
93 {
94 return (x + 0xF) & 0xFFFFFFF0;
95 }
96
ceilInt4(int x)97 inline int ceilInt4(int x)
98 {
99 return (x + 0xF) >> 4;
100 }
101
102 #define BITS(x) ( \
103 !!((x)&0x80000000) + \
104 !!((x)&0xC0000000) + \
105 !!((x)&0xE0000000) + \
106 !!((x)&0xF0000000) + \
107 !!((x)&0xF8000000) + \
108 !!((x)&0xFC000000) + \
109 !!((x)&0xFE000000) + \
110 !!((x)&0xFF000000) + \
111 !!((x)&0xFF800000) + \
112 !!((x)&0xFFC00000) + \
113 !!((x)&0xFFE00000) + \
114 !!((x)&0xFFF00000) + \
115 !!((x)&0xFFF80000) + \
116 !!((x)&0xFFFC0000) + \
117 !!((x)&0xFFFE0000) + \
118 !!((x)&0xFFFF0000) + \
119 !!((x)&0xFFFF8000) + \
120 !!((x)&0xFFFFC000) + \
121 !!((x)&0xFFFFE000) + \
122 !!((x)&0xFFFFF000) + \
123 !!((x)&0xFFFFF800) + \
124 !!((x)&0xFFFFFC00) + \
125 !!((x)&0xFFFFFE00) + \
126 !!((x)&0xFFFFFF00) + \
127 !!((x)&0xFFFFFF80) + \
128 !!((x)&0xFFFFFFC0) + \
129 !!((x)&0xFFFFFFE0) + \
130 !!((x)&0xFFFFFFF0) + \
131 !!((x)&0xFFFFFFF8) + \
132 !!((x)&0xFFFFFFFC) + \
133 !!((x)&0xFFFFFFFE) + \
134 !!((x)&0xFFFFFFFF))
135
log2i(int x)136 inline unsigned long log2i(int x)
137 {
138 #if defined(_MSC_VER)
139 unsigned long y;
140 _BitScanReverse(&y, x);
141 return y;
142 #else
143 return 31 - __builtin_clz(x);
144 #endif
145 }
146
isPow2(int x)147 inline bool isPow2(int x)
148 {
149 return (x & -x) == x;
150 }
151
152 template<class T>
clamp(T x,T a,T b)153 inline T clamp(T x, T a, T b)
154 {
155 ASSERT(a <= b);
156 if(x < a) x = a;
157 if(x > b) x = b;
158
159 return x;
160 }
161
clamp01(float x)162 inline float clamp01(float x)
163 {
164 return clamp(x, 0.0f, 1.0f);
165 }
166
167 // Bit-cast of a floating-point value into a two's complement integer representation.
168 // This makes floating-point values comparable as integers.
float_as_twos_complement(float f)169 inline int32_t float_as_twos_complement(float f)
170 {
171 // IEEE-754 floating-point numbers are sorted by magnitude in the same way as integers,
172 // except negative values are like one's complement integers. Convert them to two's complement.
173 int32_t i = bit_cast<int32_t>(f);
174 return (i < 0) ? (0x7FFFFFFFu - i) : i;
175 }
176
177 // 'Safe' clamping operation which always returns a value between min and max (inclusive).
clamp_s(float x,float min,float max)178 inline float clamp_s(float x, float min, float max)
179 {
180 // NaN values can't be compared directly
181 if(float_as_twos_complement(x) < float_as_twos_complement(min)) x = min;
182 if(float_as_twos_complement(x) > float_as_twos_complement(max)) x = max;
183
184 return x;
185 }
186
ceilPow2(int x)187 inline int ceilPow2(int x)
188 {
189 int i = 1;
190
191 while(i < x)
192 {
193 i <<= 1;
194 }
195
196 return i;
197 }
198
floorDiv(int a,int b)199 inline int floorDiv(int a, int b)
200 {
201 return a / b + ((a % b) >> 31);
202 }
203
floorMod(int a,int b)204 inline int floorMod(int a, int b)
205 {
206 int r = a % b;
207 return r + ((r >> 31) & b);
208 }
209
ceilDiv(int a,int b)210 inline int ceilDiv(int a, int b)
211 {
212 return a / b - (-(a % b) >> 31);
213 }
214
ceilMod(int a,int b)215 inline int ceilMod(int a, int b)
216 {
217 int r = a % b;
218 return r - ((-r >> 31) & b);
219 }
220
221 template<const int n>
unorm(float x)222 inline unsigned int unorm(float x)
223 {
224 static const unsigned int max = 0xFFFFFFFF >> (32 - n);
225 static const float maxf = static_cast<float>(max);
226
227 if(x >= 1.0f)
228 {
229 return max;
230 }
231 else if(x <= 0.0f)
232 {
233 return 0;
234 }
235 else
236 {
237 return static_cast<unsigned int>(maxf * x + 0.5f);
238 }
239 }
240
241 template<const int n>
snorm(float x)242 inline int snorm(float x)
243 {
244 static const unsigned int min = 0x80000000 >> (32 - n);
245 static const unsigned int max = 0xFFFFFFFF >> (32 - n + 1);
246 static const float maxf = static_cast<float>(max);
247 static const unsigned int range = 0xFFFFFFFF >> (32 - n);
248
249 if(x >= 0.0f)
250 {
251 if(x >= 1.0f)
252 {
253 return max;
254 }
255 else
256 {
257 return static_cast<int>(maxf * x + 0.5f);
258 }
259 }
260 else
261 {
262 if(x <= -1.0f)
263 {
264 return min;
265 }
266 else
267 {
268 return static_cast<int>(maxf * x - 0.5f) & range;
269 }
270 }
271 }
272
273 template<const int n>
ucast(float x)274 inline unsigned int ucast(float x)
275 {
276 static const unsigned int max = 0xFFFFFFFF >> (32 - n);
277 static const float maxf = static_cast<float>(max);
278
279 if(x >= maxf)
280 {
281 return max;
282 }
283 else if(x <= 0.0f)
284 {
285 return 0;
286 }
287 else
288 {
289 return static_cast<unsigned int>(x + 0.5f);
290 }
291 }
292
293 template<const int n>
scast(float x)294 inline int scast(float x)
295 {
296 static const unsigned int min = 0x80000000 >> (32 - n);
297 static const unsigned int max = 0xFFFFFFFF >> (32 - n + 1);
298 static const float maxf = static_cast<float>(max);
299 static const float minf = static_cast<float>(min);
300 static const unsigned int range = 0xFFFFFFFF >> (32 - n);
301
302 if(x > 0.0f)
303 {
304 if(x >= maxf)
305 {
306 return max;
307 }
308 else
309 {
310 return static_cast<int>(x + 0.5f);
311 }
312 }
313 else
314 {
315 if(x <= -minf)
316 {
317 return min;
318 }
319 else
320 {
321 return static_cast<int>(x - 0.5f) & range;
322 }
323 }
324 }
325
sRGBtoLinear(float c)326 inline float sRGBtoLinear(float c)
327 {
328 if(c <= 0.04045f)
329 {
330 return c / 12.92f;
331 }
332 else
333 {
334 return powf((c + 0.055f) / 1.055f, 2.4f);
335 }
336 }
337
linearToSRGB(float c)338 inline float linearToSRGB(float c)
339 {
340 if(c <= 0.0031308f)
341 {
342 return c * 12.92f;
343 }
344 else
345 {
346 return 1.055f * powf(c, 1.0f / 2.4f) - 0.055f;
347 }
348 }
349
350 unsigned char sRGB8toLinear8(unsigned char value);
351
352 uint64_t FNV_1a(const unsigned char *data, int size); // Fowler-Noll-Vo hash function
353
354 // Round up to the next multiple of alignment
355 template<typename T>
align(T value,unsigned int alignment)356 inline T align(T value, unsigned int alignment)
357 {
358 return ((value + alignment - 1) / alignment) * alignment;
359 }
360
361 template<unsigned int alignment, typename T>
align(T value)362 inline T align(T value)
363 {
364 return ((value + alignment - 1) / alignment) * alignment;
365 }
366
clampToSignedInt(unsigned int x)367 inline int clampToSignedInt(unsigned int x)
368 {
369 return static_cast<int>(min(x, 0x7FFFFFFFu));
370 }
371
372 // Convert floating value v to fixed point with p digits after the decimal point
toFixedPoint(float v,int p)373 constexpr int toFixedPoint(float v, int p)
374 {
375 return static_cast<int>(v * (1 << p));
376 }
377
378 } // namespace sw
379
380 #endif // sw_Math_hpp
381