• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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>
max(T a,T b)34 	inline T 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 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 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 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 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 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>
swap(T & a,T & b)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>
bit_cast(const sourceType & source)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 
iround(float x)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 
ifloor(float x)95 	inline int ifloor(float x)
96 	{
97 		return (int)floor(x);
98 	}
99 
ceilFix4(int x)100 	inline int ceilFix4(int x)
101 	{
102 		return (x + 0xF) & 0xFFFFFFF0;
103 	}
104 
ceilInt4(int x)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 
exp2(float x)147 	inline float exp2(float x)
148 	{
149 		return exp2f(x);
150 	}
151 
exp2(int x)152 	inline int exp2(int x)
153 	{
154 		return 1 << x;
155 	}
156 
log2(int x)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 
ilog2(float x)168 	inline int ilog2(float x)
169 	{
170 		unsigned int y = *(unsigned int*)&x;
171 
172 		return ((y & 0x7F800000) >> 23) - 127;
173 	}
174 
log2(float x)175 	inline float log2(float x)
176 	{
177 		return logf(x) * 1.44269504f;   // 1.0 / log[e](2)
178 	}
179 
isPow2(int x)180 	inline bool isPow2(int x)
181 	{
182 		return (x & -x) == x;
183 	}
184 
185 	template<class T>
clamp(T x,T a,T b)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 
clamp01(float x)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.
float_as_twos_complement(float f)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).
clamp_s(float x,float min,float max)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 
ceilPow2(int x)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 
floorDiv(int a,int b)231 	inline int floorDiv(int a, int b)
232 	{
233 		return a / b + ((a % b) >> 31);
234 	}
235 
floorMod(int a,int b)236 	inline int floorMod(int a, int b)
237 	{
238 		int r = a % b;
239 		return r + ((r >> 31) & b);
240 	}
241 
ceilDiv(int a,int b)242 	inline int ceilDiv(int a, int b)
243 	{
244 		return a / b - (-(a % b) >> 31);
245 	}
246 
ceilMod(int a,int b)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>
unorm(float x)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>
snorm(float x)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>
ucast(float x)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>
scast(float x)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 
sRGBtoLinear(float c)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 
linearToSRGB(float c)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>
align(T value,unsigned int alignment)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>
align(T value)394 	inline T align(T value)
395 	{
396 		return ((value + alignment - 1) / alignment) * alignment;
397 	}
398 
clampToSignedInt(unsigned int x)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