msvcrt: Save and restore rounding mode in fegetenv() / fesetenv().
Fixes Serious Sam 4 flickering in Vulkan mode. Signed-off-by: Paul Gofman <pgofman@codeweavers.com> Signed-off-by: Piotr Caban <piotr@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
c72e1b096d
commit
3acd68b241
|
@ -23,6 +23,7 @@
|
|||
#include <stdio.h>
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
#include <fenv.h>
|
||||
#include <limits.h>
|
||||
#include <wctype.h>
|
||||
|
||||
|
@ -183,6 +184,9 @@ static float (CDECL *p_wcstof)(const wchar_t*, wchar_t**);
|
|||
static double (CDECL *p_remainder)(double, double);
|
||||
static int* (CDECL *p_errno)(void);
|
||||
static int (CDECL *p_fegetenv)(fenv_t*);
|
||||
static int (CDECL *p_fesetenv)(const fenv_t*);
|
||||
static int (CDECL *p_fegetround)(void);
|
||||
static int (CDECL *p_fesetround)(int);
|
||||
static int (CDECL *p__clearfp)(void);
|
||||
static _locale_t (__cdecl *p_wcreate_locale)(int, const wchar_t *);
|
||||
static void (__cdecl *p_free_locale)(_locale_t);
|
||||
|
@ -254,6 +258,10 @@ static BOOL init(void)
|
|||
p_free_locale = (void*)GetProcAddress(module, "_free_locale");
|
||||
SET(p_wctype, "wctype");
|
||||
SET(p_fegetenv, "fegetenv");
|
||||
SET(p_fesetenv, "fesetenv");
|
||||
SET(p_fegetround, "fegetround");
|
||||
SET(p_fesetround, "fesetround");
|
||||
|
||||
SET(p__clearfp, "_clearfp");
|
||||
SET(p_vsscanf, "vsscanf");
|
||||
SET(p__Cbuild, "_Cbuild");
|
||||
|
@ -780,18 +788,27 @@ static void test_critical_section(void)
|
|||
call_func1(p_critical_section_dtor, &cs);
|
||||
}
|
||||
|
||||
static void test_fegetenv(void)
|
||||
static void test_feenv(void)
|
||||
{
|
||||
fenv_t env, env2;
|
||||
int ret;
|
||||
fenv_t env;
|
||||
|
||||
p__clearfp();
|
||||
|
||||
ret = p_fegetenv(&env);
|
||||
ok(!ret, "fegetenv returned %x\n", ret);
|
||||
p_fesetround(FE_UPWARD);
|
||||
ok(env.control == (_EM_INEXACT|_EM_UNDERFLOW|_EM_OVERFLOW|_EM_ZERODIVIDE|_EM_INVALID),
|
||||
"env.control = %x\n", env.control);
|
||||
ok(!env.status, "env.status = %x\n", env.status);
|
||||
ret = p_fegetenv(&env2);
|
||||
ok(!ret, "fegetenv returned %x\n", ret);
|
||||
ok(env2.control == (_EM_INEXACT|_EM_UNDERFLOW|_EM_OVERFLOW|_EM_ZERODIVIDE|_EM_INVALID | FE_UPWARD),
|
||||
"env2.control = %x\n", env2.control);
|
||||
ret = p_fesetenv(&env);
|
||||
ok(!ret, "fesetenv returned %x\n", ret);
|
||||
ret = p_fegetround();
|
||||
ok(ret == FE_TONEAREST, "Got unexpected round mode %#x.\n", ret);
|
||||
}
|
||||
|
||||
static void test__wcreate_locale(void)
|
||||
|
@ -1110,7 +1127,7 @@ START_TEST(msvcr120)
|
|||
test__strtof();
|
||||
test_remainder();
|
||||
test_critical_section();
|
||||
test_fegetenv();
|
||||
test_feenv();
|
||||
test__wcreate_locale();
|
||||
test__Condition_variable();
|
||||
test_wctype();
|
||||
|
|
|
@ -2074,7 +2074,7 @@ int CDECL _controlfp_s(unsigned int *cur, unsigned int newval, unsigned int mask
|
|||
int CDECL MSVCRT_fegetenv(MSVCRT_fenv_t *env)
|
||||
{
|
||||
env->control = _controlfp(0, 0) & (MSVCRT__EM_INEXACT | MSVCRT__EM_UNDERFLOW |
|
||||
MSVCRT__EM_OVERFLOW | MSVCRT__EM_ZERODIVIDE | MSVCRT__EM_INVALID);
|
||||
MSVCRT__EM_OVERFLOW | MSVCRT__EM_ZERODIVIDE | MSVCRT__EM_INVALID | MSVCRT__RC_CHOP);
|
||||
env->status = _statusfp();
|
||||
return 0;
|
||||
}
|
||||
|
@ -2193,12 +2193,18 @@ int CDECL MSVCRT_fesetenv(const MSVCRT_fenv_t *env)
|
|||
|
||||
__asm__ __volatile__( "fnstenv %0" : "=m" (fenv) );
|
||||
|
||||
fenv.control_word &= ~0x3d;
|
||||
fenv.control_word &= ~0xc3d;
|
||||
if (env->control & MSVCRT__EM_INVALID) fenv.control_word |= 0x1;
|
||||
if (env->control & MSVCRT__EM_ZERODIVIDE) fenv.control_word |= 0x4;
|
||||
if (env->control & MSVCRT__EM_OVERFLOW) fenv.control_word |= 0x8;
|
||||
if (env->control & MSVCRT__EM_UNDERFLOW) fenv.control_word |= 0x10;
|
||||
if (env->control & MSVCRT__EM_INEXACT) fenv.control_word |= 0x20;
|
||||
switch (env->control & MSVCRT__MCW_RC)
|
||||
{
|
||||
case MSVCRT__RC_UP|MSVCRT__RC_DOWN: fenv.control_word |= 0xc00; break;
|
||||
case MSVCRT__RC_UP: fenv.control_word |= 0x800; break;
|
||||
case MSVCRT__RC_DOWN: fenv.control_word |= 0x400; break;
|
||||
}
|
||||
|
||||
fenv.status_word &= ~0x3d;
|
||||
if (env->status & MSVCRT__SW_INVALID) fenv.status_word |= 0x1;
|
||||
|
@ -2213,14 +2219,19 @@ int CDECL MSVCRT_fesetenv(const MSVCRT_fenv_t *env)
|
|||
if (sse2_supported)
|
||||
{
|
||||
DWORD fpword;
|
||||
|
||||
__asm__ __volatile__( "stmxcsr %0" : "=m" (fpword) );
|
||||
fpword &= ~0x1e80;
|
||||
fpword &= ~0x7e80;
|
||||
if (env->control & MSVCRT__EM_INVALID) fpword |= 0x80;
|
||||
if (env->control & MSVCRT__EM_ZERODIVIDE) fpword |= 0x200;
|
||||
if (env->control & MSVCRT__EM_OVERFLOW) fpword |= 0x400;
|
||||
if (env->control & MSVCRT__EM_UNDERFLOW) fpword |= 0x800;
|
||||
if (env->control & MSVCRT__EM_INEXACT) fpword |= 0x1000;
|
||||
switch (env->control & MSVCRT__MCW_RC)
|
||||
{
|
||||
case MSVCRT__RC_CHOP: fpword |= 0x6000; break;
|
||||
case MSVCRT__RC_UP: fpword |= 0x4000; break;
|
||||
case MSVCRT__RC_DOWN: fpword |= 0x2000; break;
|
||||
}
|
||||
__asm__ __volatile__( "ldmxcsr %0" : : "m" (fpword) );
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue