From: Akihiro Sagawa Subject: [PATCH] winex11.drv: Mask floating-point invalid exception during glXCreateContext(). Message-Id: <20210408232258.E982.375B48EC@gmail.com> Date: Thu, 08 Apr 2021 23:25:15 +0900 Workaround for Mesa bug 3096. I can reproduce the issue with Mesa 21.2 and set LIBGL_ALWAYS_SOFTWARE environment to 1, i.e. LIBGL_ALWAYS_SOFTWARE=1. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47716 Signed-off-by: Akihiro Sagawa --- configure.ac | 2 ++ dlls/winex11.drv/opengl.c | 40 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/configure.ac b/configure.ac index 2f5a6987a13..a2344680224 100644 --- a/configure.ac +++ b/configure.ac @@ -448,6 +448,7 @@ AC_CHECK_HEADERS(\ dirent.h \ dlfcn.h \ elf.h \ + fenv.h \ float.h \ fnmatch.h \ getopt.h \ @@ -2673,6 +2674,7 @@ AC_CHECK_FUNCS(\ exp2f \ expm1 \ expm1f \ + fedisableexcept \ fma \ fmaf \ j0 \ diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index c44c587bf14..a611c7f11ea 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -36,6 +36,9 @@ #ifdef HAVE_SYS_UN_H #include #endif +#ifdef HAVE_FENV_H +#include +#endif #include "x11drv.h" #include "xcomposite.h" @@ -259,6 +262,15 @@ enum glx_swap_control_method GLX_SWAP_CONTROL_MESA }; +/* floating-point environments, see save_fenv() for details */ +struct fenv +{ + int old_excepts; +#ifdef HAVE_FENV_H + fenv_t fenv; +#endif +}; + /* X context to associate a struct gl_drawable to an hwnd */ static XContext gl_hwnd_context; /* X context to associate a struct gl_drawable to a pbuffer hdc */ @@ -417,6 +429,26 @@ static int GLXErrorHandler(Display *dpy, XErrorEvent *event, void *arg) return 1; } +/* Workaround for Mesa 20.1's NaN to integer operation + when FE_INVALID is unmasked and llvmpipe is used. */ +static inline void save_fenv(struct fenv *fenv) +{ +#if defined(HAVE_FEDISABLEEXCEPT) && defined(FE_INVALID) + if (fegetenv(&fenv->fenv) == 0) + fenv->old_excepts = fedisableexcept(FE_INVALID); + else + fenv->old_excepts = -1; +#endif +} + +static inline void restore_fenv(const struct fenv *fenv) +{ +#if defined(HAVE_FEDISABLEEXCEPT) && defined(FE_INVALID) + if (fenv->old_excepts != -1 && (fenv->old_excepts & FE_INVALID)) + fesetenv(&fenv->fenv); +#endif +} + static BOOL X11DRV_WineGL_InitOpenglInfo(void) { static const char legacy_extensions[] = " WGL_EXT_extensions_string WGL_EXT_swap_control"; @@ -441,6 +473,10 @@ static BOOL X11DRV_WineGL_InitOpenglInfo(void) if (vis) { #ifdef __i386__ WORD old_fs, new_fs; +#endif + struct fenv fenv; + save_fenv(&fenv); +#ifdef __i386__ __asm__( "mov %%fs,%0" : "=r" (old_fs) ); /* Create a GLX Context. Without one we can't query GL information */ ctx = pglXCreateContext(gdi_display, vis, None, GL_TRUE); @@ -455,6 +491,7 @@ static BOOL X11DRV_WineGL_InitOpenglInfo(void) #else ctx = pglXCreateContext(gdi_display, vis, None, GL_TRUE); #endif + restore_fenv(&fenv); } if (!ctx) goto done; @@ -1286,7 +1323,9 @@ static struct gl_drawable *get_gl_drawable( HWND hwnd, HDC hdc ) static GLXContext create_glxcontext(Display *display, struct wgl_context *context, GLXContext shareList) { GLXContext ctx; + struct fenv fenv; + save_fenv(&fenv); if(context->gl3_context) { if(context->numAttribs) @@ -1299,6 +1338,7 @@ static GLXContext create_glxcontext(Display *display, struct wgl_context *contex else /* Create a GLX Context for a pbuffer */ ctx = pglXCreateNewContext(gdi_display, context->fmt->fbconfig, context->fmt->render_type, shareList, TRUE); + restore_fenv(&fenv); return ctx; }