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