blob: 8c6a06938783efa6864b20638f33cc1d2d32a04a [file] [log] [blame]
Nicolas Capens68a82382018-10-02 13:16:55 -04001// 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
Ben Clayton25e06e02020-02-07 11:19:08 +000018#include "Debug.hpp"
Nicolas Capens68a82382018-10-02 13:16:55 -040019#include "Types.hpp"
Nicolas Capens68a82382018-10-02 13:16:55 -040020
21#include <cmath>
22#if defined(_MSC_VER)
Ben Clayton595d9112019-12-17 20:37:57 +000023# include <intrin.h>
Nicolas Capens68a82382018-10-02 13:16:55 -040024#endif
25
Nicolas Capens157ba262019-12-10 17:49:14 -050026namespace sw {
27
28using std::abs;
29
30#undef min
31#undef max
32
33template<class T>
34inline T constexpr max(T a, T b)
Nicolas Capens68a82382018-10-02 13:16:55 -040035{
Nicolas Capens157ba262019-12-10 17:49:14 -050036 return a > b ? a : b;
37}
Nicolas Capens68a82382018-10-02 13:16:55 -040038
Nicolas Capens157ba262019-12-10 17:49:14 -050039template<class T>
40inline constexpr T min(T a, T b)
41{
42 return a < b ? a : b;
43}
Nicolas Capens68a82382018-10-02 13:16:55 -040044
Nicolas Capens157ba262019-12-10 17:49:14 -050045template<class T>
46inline constexpr T max(T a, T b, T c)
47{
48 return max(max(a, b), c);
49}
50
51template<class T>
52inline constexpr T min(T a, T b, T c)
53{
54 return min(min(a, b), c);
55}
56
57template<class T>
58inline constexpr T max(T a, T b, T c, T d)
59{
60 return max(max(a, b), max(c, d));
61}
62
63template<class T>
64inline constexpr T min(T a, T b, T c, T d)
65{
66 return min(min(a, b), min(c, d));
67}
68
Ben Clayton595d9112019-12-17 20:37:57 +000069template<typename destType, typename sourceType>
Nicolas Capens157ba262019-12-10 17:49:14 -050070destType bit_cast(const sourceType &source)
71{
72 union
Nicolas Capens68a82382018-10-02 13:16:55 -040073 {
Nicolas Capens157ba262019-12-10 17:49:14 -050074 sourceType s;
75 destType d;
76 } sd;
77 sd.s = source;
78 return sd.d;
79}
80
81inline int iround(float x)
82{
83 return (int)floor(x + 0.5f);
Ben Clayton595d9112019-12-17 20:37:57 +000084 // return _mm_cvtss_si32(_mm_load_ss(&x)); // FIXME: Demands SSE support
Nicolas Capens157ba262019-12-10 17:49:14 -050085}
86
87inline int ifloor(float x)
88{
89 return (int)floor(x);
90}
91
92inline int ceilFix4(int x)
93{
94 return (x + 0xF) & 0xFFFFFFF0;
95}
96
97inline int ceilInt4(int x)
98{
99 return (x + 0xF) >> 4;
100}
101
Ben Clayton595d9112019-12-17 20:37:57 +0000102#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))
Nicolas Capens157ba262019-12-10 17:49:14 -0500135
Nicolas Capens157ba262019-12-10 17:49:14 -0500136inline unsigned long log2i(int x)
137{
Ben Clayton595d9112019-12-17 20:37:57 +0000138#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
Nicolas Capens157ba262019-12-10 17:49:14 -0500145}
146
147inline bool isPow2(int x)
148{
149 return (x & -x) == x;
150}
151
152template<class T>
153inline 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
162inline 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.
169inline 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).
178inline 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
187inline int ceilPow2(int x)
188{
189 int i = 1;
190
191 while(i < x)
192 {
193 i <<= 1;
Nicolas Capens68a82382018-10-02 13:16:55 -0400194 }
195
Nicolas Capens157ba262019-12-10 17:49:14 -0500196 return i;
197}
198
199inline int floorDiv(int a, int b)
200{
201 return a / b + ((a % b) >> 31);
202}
203
204inline int floorMod(int a, int b)
205{
206 int r = a % b;
207 return r + ((r >> 31) & b);
208}
209
210inline int ceilDiv(int a, int b)
211{
212 return a / b - (-(a % b) >> 31);
213}
214
215inline int ceilMod(int a, int b)
216{
217 int r = a % b;
218 return r - ((-r >> 31) & b);
219}
220
221template<const int n>
222inline 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)
Nicolas Capens68a82382018-10-02 13:16:55 -0400228 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500229 return max;
Nicolas Capens68a82382018-10-02 13:16:55 -0400230 }
Nicolas Capens157ba262019-12-10 17:49:14 -0500231 else if(x <= 0.0f)
Nicolas Capens68a82382018-10-02 13:16:55 -0400232 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500233 return 0;
Nicolas Capens68a82382018-10-02 13:16:55 -0400234 }
Nicolas Capens157ba262019-12-10 17:49:14 -0500235 else
Nicolas Capens68a82382018-10-02 13:16:55 -0400236 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500237 return static_cast<unsigned int>(maxf * x + 0.5f);
Nicolas Capens68a82382018-10-02 13:16:55 -0400238 }
Nicolas Capens157ba262019-12-10 17:49:14 -0500239}
Nicolas Capens68a82382018-10-02 13:16:55 -0400240
Nicolas Capens157ba262019-12-10 17:49:14 -0500241template<const int n>
242inline 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)
Nicolas Capens68a82382018-10-02 13:16:55 -0400250 {
Nicolas Capens68a82382018-10-02 13:16:55 -0400251 if(x >= 1.0f)
252 {
253 return max;
254 }
Nicolas Capens157ba262019-12-10 17:49:14 -0500255 else
Nicolas Capens68a82382018-10-02 13:16:55 -0400256 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500257 return static_cast<int>(maxf * x + 0.5f);
258 }
259 }
260 else
261 {
262 if(x <= -1.0f)
263 {
264 return min;
Nicolas Capens68a82382018-10-02 13:16:55 -0400265 }
266 else
267 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500268 return static_cast<int>(maxf * x - 0.5f) & range;
Nicolas Capens68a82382018-10-02 13:16:55 -0400269 }
270 }
Nicolas Capens157ba262019-12-10 17:49:14 -0500271}
Nicolas Capens68a82382018-10-02 13:16:55 -0400272
Nicolas Capens157ba262019-12-10 17:49:14 -0500273template<const int n>
274inline 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)
Nicolas Capens68a82382018-10-02 13:16:55 -0400280 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500281 return max;
Nicolas Capens68a82382018-10-02 13:16:55 -0400282 }
Nicolas Capens157ba262019-12-10 17:49:14 -0500283 else if(x <= 0.0f)
Nicolas Capens68a82382018-10-02 13:16:55 -0400284 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500285 return 0;
286 }
287 else
288 {
289 return static_cast<unsigned int>(x + 0.5f);
290 }
291}
Nicolas Capens68a82382018-10-02 13:16:55 -0400292
Nicolas Capens157ba262019-12-10 17:49:14 -0500293template<const int n>
294inline 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 {
Nicolas Capens68a82382018-10-02 13:16:55 -0400304 if(x >= maxf)
305 {
306 return max;
307 }
Nicolas Capens157ba262019-12-10 17:49:14 -0500308 else
Nicolas Capens68a82382018-10-02 13:16:55 -0400309 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500310 return static_cast<int>(x + 0.5f);
311 }
312 }
313 else
314 {
315 if(x <= -minf)
316 {
317 return min;
Nicolas Capens68a82382018-10-02 13:16:55 -0400318 }
319 else
320 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500321 return static_cast<int>(x - 0.5f) & range;
Nicolas Capens68a82382018-10-02 13:16:55 -0400322 }
323 }
Nicolas Capens68a82382018-10-02 13:16:55 -0400324}
325
Nicolas Capens157ba262019-12-10 17:49:14 -0500326inline float sRGBtoLinear(float c)
327{
328 if(c <= 0.04045f)
329 {
Nicolas Capens2883de92020-01-27 14:58:14 -0500330 return c / 12.92f;
Nicolas Capens157ba262019-12-10 17:49:14 -0500331 }
332 else
333 {
Nicolas Capens2883de92020-01-27 14:58:14 -0500334 return powf((c + 0.055f) / 1.055f, 2.4f);
Nicolas Capens157ba262019-12-10 17:49:14 -0500335 }
336}
337
338inline float linearToSRGB(float c)
339{
340 if(c <= 0.0031308f)
341 {
342 return c * 12.92f;
343 }
344 else
345 {
Nicolas Capens2883de92020-01-27 14:58:14 -0500346 return 1.055f * powf(c, 1.0f / 2.4f) - 0.055f;
Nicolas Capens157ba262019-12-10 17:49:14 -0500347 }
348}
349
350unsigned char sRGB8toLinear8(unsigned char value);
351
Ben Clayton595d9112019-12-17 20:37:57 +0000352uint64_t FNV_1a(const unsigned char *data, int size); // Fowler-Noll-Vo hash function
Nicolas Capens157ba262019-12-10 17:49:14 -0500353
354// Round up to the next multiple of alignment
355template<typename T>
356inline T align(T value, unsigned int alignment)
357{
358 return ((value + alignment - 1) / alignment) * alignment;
359}
360
361template<unsigned int alignment, typename T>
362inline T align(T value)
363{
364 return ((value + alignment - 1) / alignment) * alignment;
365}
366
367inline 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
Ben Clayton595d9112019-12-17 20:37:57 +0000373constexpr int toFixedPoint(float v, int p)
374{
Nicolas Capens157ba262019-12-10 17:49:14 -0500375 return static_cast<int>(v * (1 << p));
376}
377
378} // namespace sw
379
Ben Clayton595d9112019-12-17 20:37:57 +0000380#endif // sw_Math_hpp