From bc386af5c5607f0d7a7ed911d5975fc9758c7110 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 19 Sep 2017 03:42:00 -0700 Subject: Manually save and restore the FPU rounding mode on Windows Apparently there is a bug with at least MinGW-W64 where fegetenv and fesetenv do not properly save and restore the FPU rounding mode, resulting in the rounding mode remaining as round-to-zero after certain function calls. I do not know if this also affects MSVC, but better safe than sorry for now. --- Alc/helpers.c | 10 ++++++++++ OpenAL32/Include/alMain.h | 3 +++ 2 files changed, 13 insertions(+) diff --git a/Alc/helpers.c b/Alc/helpers.c index 8e6306ae..e9eb5faf 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -295,6 +295,13 @@ void SetMixerFPUMode(FPUCtl *ctl) { #ifdef HAVE_FENV_H fegetenv(STATIC_CAST(fenv_t, ctl)); +#ifdef _WIN32 + /* HACK: A nasty bug in MinGW-W64 causes fegetenv and fesetenv to not save + * and restore the FPU rounding mode, so we have to do it manually. Don't + * know if this also applies to MSVC. + */ + ctl->round_mode = fegetround(); +#endif #if defined(__GNUC__) && defined(HAVE_SSE) /* FIXME: Some fegetenv implementations can get the SSE environment too? * How to tell when it does? */ @@ -341,6 +348,9 @@ void RestoreFPUMode(const FPUCtl *ctl) { #ifdef HAVE_FENV_H fesetenv(STATIC_CAST(fenv_t, ctl)); +#ifdef _WIN32 + fesetround(ctl->round_mode); +#endif #if defined(__GNUC__) && defined(HAVE_SSE) if((CPUCapFlags&CPU_CAP_SSE)) __asm__ __volatile__("ldmxcsr %0" : : "m" (*&ctl->sse_state)); diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index f24eb000..614c3b43 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -901,6 +901,9 @@ void ALCcontext_ProcessUpdates(ALCcontext *context); typedef struct { #ifdef HAVE_FENV_H DERIVE_FROM_TYPE(fenv_t); +#ifdef _WIN32 + int round_mode; +#endif #else int state; #endif -- cgit v1.2.3