diff --git a/GPU/Common/GPUCommonMath.h b/GPU/Common/GPUCommonMath.h index 057d3afca0945..65ff3092bc313 100644 --- a/GPU/Common/GPUCommonMath.h +++ b/GPU/Common/GPUCommonMath.h @@ -105,7 +105,7 @@ class GPUCommonMath GPUd() constexpr static bool Finite(float x); GPUd() constexpr static bool IsNaN(float x); #ifndef __FAST_MATH__ - GPUd() constexpr static float QuietNaN() { return GPUCA_CHOICE(std::numeric_limits::quiet_NaN(), __builtin_nanf(""), nan(0u)); } + GPUd() constexpr static float QuietNaN() { return GPUCA_CHOICE(std::numeric_limits::quiet_NaN(), __builtin_nanf(""), NAN); } #endif GPUd() constexpr static uint32_t Clz(uint32_t val); GPUd() constexpr static uint32_t Ctz(uint32_t val); @@ -245,7 +245,21 @@ GPUdi() float2 GPUCommonMath::MakeFloat2(float x, float y) } GPUdi() constexpr float GPUCommonMath::Modf(float x, float y) { return GPUCA_CHOICE(fmodf(x, y), fmodf(x, y), fmod(x, y)); } -GPUhdi() float GPUCommonMath::Remainderf(float x, float y) { return GPUCA_CHOICE(std::remainderf(x, y), remainderf(x, y), remainder(x, y)); } +GPUhdi() float GPUCommonMath::Remainderf(float x, float y) +{ +#ifdef __METAL__ // MSL has no remainder(), so reduce with fmod, which is exact + const float r = fmod(x, y), h = 0.5f * fabs(y), a = fabs(r); + if (a > h) { + return r - copysign(y, r); + } + if (a == h && fmod((x - r) / y, 2.f) != 0.f) { // the quotient of a tie is rounded to even + return r - copysign(y, r); + } + return r; +#else + return GPUCA_CHOICE(std::remainderf(x, y), remainderf(x, y), remainder(x, y)); +#endif +} GPUdi() uint32_t GPUCommonMath::Float2UIntReint(const float& x) { @@ -302,6 +316,11 @@ GPUhdi() void GPUCommonMath::SinCos(float x, float& s, float& c) __sincosf(x, &s, &c); #elif !defined(GPUCA_GPUCODE_DEVICE) && (defined(__GNU_SOURCE__) || defined(_GNU_SOURCE) || defined(GPUCA_GPUCODE)) sincosf(x, &s, &c); +#elif defined(__METAL__) // MSL's sincos returns sin and takes cos by thread + // reference, so it cannot write through a generic one + float metalCos; + s = sincos(x, metalCos); + c = metalCos; #else GPUCA_CHOICE((void)((s = sinf(x)) + (c = cosf(x))), sincosf(x, &s, &c), s = sincos(x, &c)); #endif