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