summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/angle/src/common/mathutil.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/angle/src/common/mathutil.h')
-rw-r--r--src/3rdparty/angle/src/common/mathutil.h206
1 files changed, 178 insertions, 28 deletions
diff --git a/src/3rdparty/angle/src/common/mathutil.h b/src/3rdparty/angle/src/common/mathutil.h
index 1015bd2312..3de62aef10 100644
--- a/src/3rdparty/angle/src/common/mathutil.h
+++ b/src/3rdparty/angle/src/common/mathutil.h
@@ -14,7 +14,9 @@
#include <limits>
#include <algorithm>
+#include <math.h>
#include <string.h>
+#include <stdint.h>
#include <stdlib.h>
namespace gl
@@ -67,14 +69,29 @@ inline int clampToInt(unsigned int x)
template <typename DestT, typename SrcT>
inline DestT clampCast(SrcT value)
{
- // This assumes SrcT can properly represent DestT::min/max
- // Unfortunately we can't use META_ASSERT without C++11 constexpr support
- ASSERT(static_cast<DestT>(static_cast<SrcT>(std::numeric_limits<DestT>::min())) == std::numeric_limits<DestT>::min());
- ASSERT(static_cast<DestT>(static_cast<SrcT>(std::numeric_limits<DestT>::max())) == std::numeric_limits<DestT>::max());
-
- SrcT lo = static_cast<SrcT>(std::numeric_limits<DestT>::min());
- SrcT hi = static_cast<SrcT>(std::numeric_limits<DestT>::max());
- return static_cast<DestT>(value > lo ? (value > hi ? hi : value) : lo);
+ static const DestT destLo = std::numeric_limits<DestT>::min();
+ static const DestT destHi = std::numeric_limits<DestT>::max();
+ static const SrcT srcLo = static_cast<SrcT>(destLo);
+ static const SrcT srcHi = static_cast<SrcT>(destHi);
+
+ // When value is outside of or equal to the limits for DestT we use the DestT limit directly.
+ // This avoids undefined behaviors due to loss of precision when converting from floats to
+ // integers:
+ // destHi for ints is 2147483647 but the closest float number is around 2147483648, so when
+ // doing a conversion from float to int we run into an UB because the float is outside of the
+ // range representable by the int.
+ if (value <= srcLo)
+ {
+ return destLo;
+ }
+ else if (value >= srcHi)
+ {
+ return destHi;
+ }
+ else
+ {
+ return static_cast<DestT>(value);
+ }
}
template<typename T, typename MIN, typename MAX>
@@ -119,9 +136,6 @@ inline bool supportsSSE2()
return supports;
}
-#if defined(__GNUC__)
- supports = __builtin_cpu_supports("sse2");
-#else
int info[4];
__cpuid(info, 0);
@@ -131,7 +145,6 @@ inline bool supportsSSE2()
supports = (info[3] >> 26) & 1;
}
-#endif
checked = true;
@@ -153,13 +166,13 @@ destType bitCast(const sourceType &source)
inline unsigned short float32ToFloat16(float fp32)
{
- unsigned int fp32i = (unsigned int&)fp32;
+ unsigned int fp32i = bitCast<unsigned int>(fp32);
unsigned int sign = (fp32i & 0x80000000) >> 16;
unsigned int abs = fp32i & 0x7FFFFFFF;
if(abs > 0x47FFEFFF) // Infinity
{
- return sign | 0x7FFF;
+ return static_cast<unsigned short>(sign | 0x7FFF);
}
else if(abs < 0x38800000) // Denormal
{
@@ -175,11 +188,11 @@ inline unsigned short float32ToFloat16(float fp32)
abs = 0;
}
- return sign | (abs + 0x00000FFF + ((abs >> 13) & 1)) >> 13;
+ return static_cast<unsigned short>(sign | (abs + 0x00000FFF + ((abs >> 13) & 1)) >> 13);
}
else
{
- return sign | (abs + 0xC8000000 + 0x00000FFF + ((abs >> 13) & 1)) >> 13;
+ return static_cast<unsigned short>(sign | (abs + 0xC8000000 + 0x00000FFF + ((abs >> 13) & 1)) >> 13);
}
}
@@ -426,14 +439,14 @@ inline float normalizedToFloat(T input)
template <typename T>
inline T floatToNormalized(float input)
{
- return std::numeric_limits<T>::max() * input + 0.5f;
+ return static_cast<T>(std::numeric_limits<T>::max() * input + 0.5f);
}
template <unsigned int outputBitCount, typename T>
inline T floatToNormalized(float input)
{
static_assert(outputBitCount < (sizeof(T) * 8), "T must have more bits than outputBitCount.");
- return ((1 << outputBitCount) - 1) * input + 0.5f;
+ return static_cast<T>(((1 << outputBitCount) - 1) * input + 0.5f);
}
template <unsigned int inputBitCount, unsigned int inputBitStart, typename T>
@@ -480,9 +493,10 @@ inline unsigned int average(unsigned int a, unsigned int b)
return ((a ^ b) >> 1) + (a & b);
}
-inline signed int average(signed int a, signed int b)
+inline int average(int a, int b)
{
- return ((long long)a + (long long)b) / 2;
+ long long average = (static_cast<long long>(a) + static_cast<long long>(b)) / 2ll;
+ return static_cast<int>(average);
}
inline float average(float a, float b)
@@ -497,20 +511,14 @@ inline unsigned short averageHalfFloat(unsigned short a, unsigned short b)
inline unsigned int averageFloat11(unsigned int a, unsigned int b)
{
- return float32ToFloat11((float11ToFloat32(a) + float11ToFloat32(b)) * 0.5f);
+ return float32ToFloat11((float11ToFloat32(static_cast<unsigned short>(a)) + float11ToFloat32(static_cast<unsigned short>(b))) * 0.5f);
}
inline unsigned int averageFloat10(unsigned int a, unsigned int b)
{
- return float32ToFloat10((float10ToFloat32(a) + float10ToFloat32(b)) * 0.5f);
-}
-
+ return float32ToFloat10((float10ToFloat32(static_cast<unsigned short>(a)) + float10ToFloat32(static_cast<unsigned short>(b))) * 0.5f);
}
-namespace rx
-{
-
-// Represents intervals of the type [a, b)
template <typename T>
struct Range
{
@@ -533,11 +541,146 @@ struct Range
return start < other.end;
}
}
+
+ void extend(T value)
+ {
+ start = value > start ? value : start;
+ end = value < end ? value : end;
+ }
+
+ bool empty() const
+ {
+ return end <= start;
+ }
};
typedef Range<int> RangeI;
typedef Range<unsigned int> RangeUI;
+struct IndexRange
+{
+ IndexRange() : IndexRange(0, 0, 0) {}
+ IndexRange(size_t start_, size_t end_, size_t vertexIndexCount_)
+ : start(start_), end(end_), vertexIndexCount(vertexIndexCount_)
+ {
+ ASSERT(start <= end);
+ }
+
+ // Number of vertices in the range.
+ size_t vertexCount() const { return (end - start) + 1; }
+
+ // Inclusive range of indices that are not primitive restart
+ size_t start;
+ size_t end;
+
+ // Number of non-primitive restart indices
+ size_t vertexIndexCount;
+};
+
+// First, both normalized floating-point values are converted into 16-bit integer values.
+// Then, the results are packed into the returned 32-bit unsigned integer.
+// The first float value will be written to the least significant bits of the output;
+// the last float value will be written to the most significant bits.
+// The conversion of each value to fixed point is done as follows :
+// packSnorm2x16 : round(clamp(c, -1, +1) * 32767.0)
+inline uint32_t packSnorm2x16(float f1, float f2)
+{
+ int16_t leastSignificantBits = static_cast<int16_t>(roundf(clamp(f1, -1.0f, 1.0f) * 32767.0f));
+ int16_t mostSignificantBits = static_cast<int16_t>(roundf(clamp(f2, -1.0f, 1.0f) * 32767.0f));
+ return static_cast<uint32_t>(mostSignificantBits) << 16 |
+ (static_cast<uint32_t>(leastSignificantBits) & 0xFFFF);
+}
+
+// First, unpacks a single 32-bit unsigned integer u into a pair of 16-bit unsigned integers. Then, each
+// component is converted to a normalized floating-point value to generate the returned two float values.
+// The first float value will be extracted from the least significant bits of the input;
+// the last float value will be extracted from the most-significant bits.
+// The conversion for unpacked fixed-point value to floating point is done as follows:
+// unpackSnorm2x16 : clamp(f / 32767.0, -1, +1)
+inline void unpackSnorm2x16(uint32_t u, float *f1, float *f2)
+{
+ int16_t leastSignificantBits = static_cast<int16_t>(u & 0xFFFF);
+ int16_t mostSignificantBits = static_cast<int16_t>(u >> 16);
+ *f1 = clamp(static_cast<float>(leastSignificantBits) / 32767.0f, -1.0f, 1.0f);
+ *f2 = clamp(static_cast<float>(mostSignificantBits) / 32767.0f, -1.0f, 1.0f);
+}
+
+// First, both normalized floating-point values are converted into 16-bit integer values.
+// Then, the results are packed into the returned 32-bit unsigned integer.
+// The first float value will be written to the least significant bits of the output;
+// the last float value will be written to the most significant bits.
+// The conversion of each value to fixed point is done as follows:
+// packUnorm2x16 : round(clamp(c, 0, +1) * 65535.0)
+inline uint32_t packUnorm2x16(float f1, float f2)
+{
+ uint16_t leastSignificantBits = static_cast<uint16_t>(roundf(clamp(f1, 0.0f, 1.0f) * 65535.0f));
+ uint16_t mostSignificantBits = static_cast<uint16_t>(roundf(clamp(f2, 0.0f, 1.0f) * 65535.0f));
+ return static_cast<uint32_t>(mostSignificantBits) << 16 | static_cast<uint32_t>(leastSignificantBits);
+}
+
+// First, unpacks a single 32-bit unsigned integer u into a pair of 16-bit unsigned integers. Then, each
+// component is converted to a normalized floating-point value to generate the returned two float values.
+// The first float value will be extracted from the least significant bits of the input;
+// the last float value will be extracted from the most-significant bits.
+// The conversion for unpacked fixed-point value to floating point is done as follows:
+// unpackUnorm2x16 : f / 65535.0
+inline void unpackUnorm2x16(uint32_t u, float *f1, float *f2)
+{
+ uint16_t leastSignificantBits = static_cast<uint16_t>(u & 0xFFFF);
+ uint16_t mostSignificantBits = static_cast<uint16_t>(u >> 16);
+ *f1 = static_cast<float>(leastSignificantBits) / 65535.0f;
+ *f2 = static_cast<float>(mostSignificantBits) / 65535.0f;
+}
+
+// Returns an unsigned integer obtained by converting the two floating-point values to the 16-bit
+// floating-point representation found in the OpenGL ES Specification, and then packing these
+// two 16-bit integers into a 32-bit unsigned integer.
+// f1: The 16 least-significant bits of the result;
+// f2: The 16 most-significant bits.
+inline uint32_t packHalf2x16(float f1, float f2)
+{
+ uint16_t leastSignificantBits = static_cast<uint16_t>(float32ToFloat16(f1));
+ uint16_t mostSignificantBits = static_cast<uint16_t>(float32ToFloat16(f2));
+ return static_cast<uint32_t>(mostSignificantBits) << 16 | static_cast<uint32_t>(leastSignificantBits);
+}
+
+// Returns two floating-point values obtained by unpacking a 32-bit unsigned integer into a pair of 16-bit values,
+// interpreting those values as 16-bit floating-point numbers according to the OpenGL ES Specification,
+// and converting them to 32-bit floating-point values.
+// The first float value is obtained from the 16 least-significant bits of u;
+// the second component is obtained from the 16 most-significant bits of u.
+inline void unpackHalf2x16(uint32_t u, float *f1, float *f2)
+{
+ uint16_t leastSignificantBits = static_cast<uint16_t>(u & 0xFFFF);
+ uint16_t mostSignificantBits = static_cast<uint16_t>(u >> 16);
+
+ *f1 = float16ToFloat32(leastSignificantBits);
+ *f2 = float16ToFloat32(mostSignificantBits);
+}
+
+// Returns whether the argument is Not a Number.
+// IEEE 754 single precision NaN representation: Exponent(8 bits) - 255, Mantissa(23 bits) - non-zero.
+inline bool isNaN(float f)
+{
+ // Exponent mask: ((1u << 8) - 1u) << 23 = 0x7f800000u
+ // Mantissa mask: ((1u << 23) - 1u) = 0x7fffffu
+ return ((bitCast<uint32_t>(f) & 0x7f800000u) == 0x7f800000u) && (bitCast<uint32_t>(f) & 0x7fffffu);
+}
+
+// Returns whether the argument is infinity.
+// IEEE 754 single precision infinity representation: Exponent(8 bits) - 255, Mantissa(23 bits) - zero.
+inline bool isInf(float f)
+{
+ // Exponent mask: ((1u << 8) - 1u) << 23 = 0x7f800000u
+ // Mantissa mask: ((1u << 23) - 1u) = 0x7fffffu
+ return ((bitCast<uint32_t>(f) & 0x7f800000u) == 0x7f800000u) && !(bitCast<uint32_t>(f) & 0x7fffffu);
+}
+
+}
+
+namespace rx
+{
+
template <typename T>
T roundUp(const T value, const T alignment)
{
@@ -573,6 +716,7 @@ inline bool IsIntegerCastSafe(BigIntT bigValue)
#if defined(_MSC_VER)
#define ANGLE_ROTL(x,y) _rotl(x,y)
+#define ANGLE_ROTR16(x,y) _rotr16(x,y)
#else
@@ -581,7 +725,13 @@ inline uint32_t RotL(uint32_t x, int8_t r)
return (x << r) | (x >> (32 - r));
}
+inline uint16_t RotR16(uint16_t x, int8_t r)
+{
+ return (x >> r) | (x << (16 - r));
+}
+
#define ANGLE_ROTL(x,y) RotL(x,y)
+#define ANGLE_ROTR16(x,y) RotR16(x,y)
#endif // namespace rx