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.
This commit is contained in:
Chris Robinson
2017-09-19 03:42:00 -07:00
parent 4ca8b4080a
commit bc386af5c5
2 changed files with 13 additions and 0 deletions
+10
View File
@@ -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));
+3
View File
@@ -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