// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
|
//
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
//
|
// http://www.apache.org/licenses/LICENSE-2.0
|
//
|
// Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
// limitations under the License.
|
|
#ifndef sw_Math_hpp
|
#define sw_Math_hpp
|
|
#include "Types.hpp"
|
#include "Half.hpp"
|
|
#include "Vulkan/VkDebug.hpp"
|
|
#include <cmath>
|
#if defined(_MSC_VER)
|
#include <intrin.h>
|
#endif
|
|
namespace sw
|
{
|
using std::abs;
|
|
#undef min
|
#undef max
|
|
template<class T>
|
inline T max(T a, T b)
|
{
|
return a > b ? a : b;
|
}
|
|
template<class T>
|
inline T min(T a, T b)
|
{
|
return a < b ? a : b;
|
}
|
|
template<class T>
|
inline T max(T a, T b, T c)
|
{
|
return max(max(a, b), c);
|
}
|
|
template<class T>
|
inline T min(T a, T b, T c)
|
{
|
return min(min(a, b), c);
|
}
|
|
template<class T>
|
inline T max(T a, T b, T c, T d)
|
{
|
return max(max(a, b), max(c, d));
|
}
|
|
template<class T>
|
inline T min(T a, T b, T c, T d)
|
{
|
return min(min(a, b), min(c, d));
|
}
|
|
template <typename destType, typename sourceType>
|
destType bit_cast(const sourceType &source)
|
{
|
union
|
{
|
sourceType s;
|
destType d;
|
} sd;
|
sd.s = source;
|
return sd.d;
|
}
|
|
inline int iround(float x)
|
{
|
return (int)floor(x + 0.5f);
|
// return _mm_cvtss_si32(_mm_load_ss(&x)); // FIXME: Demands SSE support
|
}
|
|
inline int ifloor(float x)
|
{
|
return (int)floor(x);
|
}
|
|
inline int ceilFix4(int x)
|
{
|
return (x + 0xF) & 0xFFFFFFF0;
|
}
|
|
inline int ceilInt4(int x)
|
{
|
return (x + 0xF) >> 4;
|
}
|
|
#define BITS(x) ( \
|
!!((x) & 0x80000000) + \
|
!!((x) & 0xC0000000) + \
|
!!((x) & 0xE0000000) + \
|
!!((x) & 0xF0000000) + \
|
!!((x) & 0xF8000000) + \
|
!!((x) & 0xFC000000) + \
|
!!((x) & 0xFE000000) + \
|
!!((x) & 0xFF000000) + \
|
!!((x) & 0xFF800000) + \
|
!!((x) & 0xFFC00000) + \
|
!!((x) & 0xFFE00000) + \
|
!!((x) & 0xFFF00000) + \
|
!!((x) & 0xFFF80000) + \
|
!!((x) & 0xFFFC0000) + \
|
!!((x) & 0xFFFE0000) + \
|
!!((x) & 0xFFFF0000) + \
|
!!((x) & 0xFFFF8000) + \
|
!!((x) & 0xFFFFC000) + \
|
!!((x) & 0xFFFFE000) + \
|
!!((x) & 0xFFFFF000) + \
|
!!((x) & 0xFFFFF800) + \
|
!!((x) & 0xFFFFFC00) + \
|
!!((x) & 0xFFFFFE00) + \
|
!!((x) & 0xFFFFFF00) + \
|
!!((x) & 0xFFFFFF80) + \
|
!!((x) & 0xFFFFFFC0) + \
|
!!((x) & 0xFFFFFFE0) + \
|
!!((x) & 0xFFFFFFF0) + \
|
!!((x) & 0xFFFFFFF8) + \
|
!!((x) & 0xFFFFFFFC) + \
|
!!((x) & 0xFFFFFFFE) + \
|
!!((x) & 0xFFFFFFFF))
|
|
#define MAX(x, y) ((x) > (y) ? (x) : (y))
|
#define MIN(x, y) ((x) < (y) ? (x) : (y))
|
|
inline float exp2(float x)
|
{
|
return exp2f(x);
|
}
|
|
inline int exp2(int x)
|
{
|
return 1 << x;
|
}
|
|
inline unsigned long log2(int x)
|
{
|
#if defined(_MSC_VER)
|
unsigned long y;
|
_BitScanReverse(&y, x);
|
return y;
|
#else
|
return 31 - __builtin_clz(x);
|
#endif
|
}
|
|
inline int ilog2(float x)
|
{
|
unsigned int y = *(unsigned int*)&x;
|
|
return ((y & 0x7F800000) >> 23) - 127;
|
}
|
|
inline float log2(float x)
|
{
|
return logf(x) * 1.44269504f; // 1.0 / log[e](2)
|
}
|
|
inline bool isPow2(int x)
|
{
|
return (x & -x) == x;
|
}
|
|
template<class T>
|
inline T clamp(T x, T a, T b)
|
{
|
ASSERT(a <= b);
|
if(x < a) x = a;
|
if(x > b) x = b;
|
|
return x;
|
}
|
|
inline float clamp01(float x)
|
{
|
return clamp(x, 0.0f, 1.0f);
|
}
|
|
// Bit-cast of a floating-point value into a two's complement integer representation.
|
// This makes floating-point values comparable as integers.
|
inline int32_t float_as_twos_complement(float f)
|
{
|
// IEEE-754 floating-point numbers are sorted by magnitude in the same way as integers,
|
// except negative values are like one's complement integers. Convert them to two's complement.
|
int32_t i = bit_cast<int32_t>(f);
|
return (i < 0) ? (0x7FFFFFFFu - i) : i;
|
}
|
|
// 'Safe' clamping operation which always returns a value between min and max (inclusive).
|
inline float clamp_s(float x, float min, float max)
|
{
|
// NaN values can't be compared directly
|
if(float_as_twos_complement(x) < float_as_twos_complement(min)) x = min;
|
if(float_as_twos_complement(x) > float_as_twos_complement(max)) x = max;
|
|
return x;
|
}
|
|
inline int ceilPow2(int x)
|
{
|
int i = 1;
|
|
while(i < x)
|
{
|
i <<= 1;
|
}
|
|
return i;
|
}
|
|
inline int floorDiv(int a, int b)
|
{
|
return a / b + ((a % b) >> 31);
|
}
|
|
inline int floorMod(int a, int b)
|
{
|
int r = a % b;
|
return r + ((r >> 31) & b);
|
}
|
|
inline int ceilDiv(int a, int b)
|
{
|
return a / b - (-(a % b) >> 31);
|
}
|
|
inline int ceilMod(int a, int b)
|
{
|
int r = a % b;
|
return r - ((-r >> 31) & b);
|
}
|
|
template<const int n>
|
inline unsigned int unorm(float x)
|
{
|
static const unsigned int max = 0xFFFFFFFF >> (32 - n);
|
static const float maxf = static_cast<float>(max);
|
|
if(x >= 1.0f)
|
{
|
return max;
|
}
|
else if(x <= 0.0f)
|
{
|
return 0;
|
}
|
else
|
{
|
return static_cast<unsigned int>(maxf * x + 0.5f);
|
}
|
}
|
|
template<const int n>
|
inline int snorm(float x)
|
{
|
static const unsigned int min = 0x80000000 >> (32 - n);
|
static const unsigned int max = 0xFFFFFFFF >> (32 - n + 1);
|
static const float maxf = static_cast<float>(max);
|
static const unsigned int range = 0xFFFFFFFF >> (32 - n);
|
|
if(x >= 0.0f)
|
{
|
if(x >= 1.0f)
|
{
|
return max;
|
}
|
else
|
{
|
return static_cast<int>(maxf * x + 0.5f);
|
}
|
}
|
else
|
{
|
if(x <= -1.0f)
|
{
|
return min;
|
}
|
else
|
{
|
return static_cast<int>(maxf * x - 0.5f) & range;
|
}
|
}
|
}
|
|
template<const int n>
|
inline unsigned int ucast(float x)
|
{
|
static const unsigned int max = 0xFFFFFFFF >> (32 - n);
|
static const float maxf = static_cast<float>(max);
|
|
if(x >= maxf)
|
{
|
return max;
|
}
|
else if(x <= 0.0f)
|
{
|
return 0;
|
}
|
else
|
{
|
return static_cast<unsigned int>(x + 0.5f);
|
}
|
}
|
|
template<const int n>
|
inline int scast(float x)
|
{
|
static const unsigned int min = 0x80000000 >> (32 - n);
|
static const unsigned int max = 0xFFFFFFFF >> (32 - n + 1);
|
static const float maxf = static_cast<float>(max);
|
static const float minf = static_cast<float>(min);
|
static const unsigned int range = 0xFFFFFFFF >> (32 - n);
|
|
if(x > 0.0f)
|
{
|
if(x >= maxf)
|
{
|
return max;
|
}
|
else
|
{
|
return static_cast<int>(x + 0.5f);
|
}
|
}
|
else
|
{
|
if(x <= -minf)
|
{
|
return min;
|
}
|
else
|
{
|
return static_cast<int>(x - 0.5f) & range;
|
}
|
}
|
}
|
|
inline float sRGBtoLinear(float c)
|
{
|
if(c <= 0.04045f)
|
{
|
return c * 0.07739938f; // 1.0f / 12.92f;
|
}
|
else
|
{
|
return powf((c + 0.055f) * 0.9478673f, 2.4f); // 1.0f / 1.055f
|
}
|
}
|
|
inline float linearToSRGB(float c)
|
{
|
if(c <= 0.0031308f)
|
{
|
return c * 12.92f;
|
}
|
else
|
{
|
return 1.055f * powf(c, 0.4166667f) - 0.055f; // 1.0f / 2.4f
|
}
|
}
|
|
unsigned char sRGB8toLinear8(unsigned char value);
|
|
uint64_t FNV_1a(const unsigned char *data, int size); // Fowler-Noll-Vo hash function
|
|
// Round up to the next multiple of alignment
|
template<typename T>
|
inline T align(T value, unsigned int alignment)
|
{
|
return ((value + alignment - 1) / alignment) * alignment;
|
}
|
|
template<unsigned int alignment, typename T>
|
inline T align(T value)
|
{
|
return ((value + alignment - 1) / alignment) * alignment;
|
}
|
|
inline int clampToSignedInt(unsigned int x)
|
{
|
return static_cast<int>(min(x, 0x7FFFFFFFu));
|
}
|
}
|
|
#endif // sw_Math_hpp
|