This MR introduces support for OpenGL in the Wayland driver.
Since the MR started to become somewhat long I have left some things for a subsequent part 13.2:
* wgl(Get)SwapIntervalEXT (which means everything is vsync-ed at the moment) * wglShareLists * wglCreateContextAttribsARB * Fix for some apps appearing translucent in certain compositors (typically when fullscreen).
Missing features not planned to be part of the 13.x MRs:
* Offscreen rendering through pbuffers or pixmaps, since Wayland EGL doesn't support them (perhaps we can simulate with FBOs instead?). * Front buffer rendering. Again Wayland EGL doesn't support this, and certainly not in the form needed (i.e., the surface should be available for additional rendering with GDI). In the experimental branch I implemented a workaround that seemed to work for many cases, but will need to revisit and reevaluate options. IIRC, the most common case I have seen for this is when using wined3d/gl for older (Direct)2D games, so perhaps we can find a better solution at that layer. * Child window rendering (this needs infrastructure in Wayland driver core which will enable both GL and Vulkan rendering in child windows). * Cross-process rendering.
Thanks!
From: Alexandros Frantzis alexandros.frantzis@collabora.com
The driver performs basic EGL initialization. --- configure | 112 ++++++++++++++++++++ configure.ac | 11 ++ dlls/winewayland.drv/Makefile.in | 1 + dlls/winewayland.drv/opengl.c | 136 +++++++++++++++++++++++++ dlls/winewayland.drv/waylanddrv.h | 1 + dlls/winewayland.drv/waylanddrv_main.c | 1 + 6 files changed, 262 insertions(+) create mode 100644 dlls/winewayland.drv/opengl.c
diff --git a/configure b/configure index 5e1b3765413..a96f0172579 100755 --- a/configure +++ b/configure @@ -702,6 +702,8 @@ INOTIFY_LIBS INOTIFY_CFLAGS PCSCLITE_LIBS PCAP_LIBS +EGL_LIBS +EGL_CFLAGS XKBREGISTRY_LIBS XKBREGISTRY_CFLAGS XKBCOMMON_LIBS @@ -1803,6 +1805,8 @@ XKBCOMMON_CFLAGS XKBCOMMON_LIBS XKBREGISTRY_CFLAGS XKBREGISTRY_LIBS +EGL_CFLAGS +EGL_LIBS INOTIFY_CFLAGS INOTIFY_LIBS DBUS_CFLAGS @@ -2629,6 +2633,8 @@ Some influential environment variables: C compiler flags for xkbregistry, overriding pkg-config XKBREGISTRY_LIBS Linker flags for xkbregistry, overriding pkg-config + EGL_CFLAGS C compiler flags for egl, overriding pkg-config + EGL_LIBS Linker flags for egl, overriding pkg-config INOTIFY_CFLAGS C compiler flags for libinotify, overriding pkg-config INOTIFY_LIBS @@ -16137,6 +16143,110 @@ fi
CPPFLAGS=$ac_save_CPPFLAGS
+ if test "x$with_opengl" != "xno" + then + rm -f conftest.err +if ${EGL_CFLAGS:+false} : +then : + if test ${PKG_CONFIG+y} +then : + EGL_CFLAGS=`$PKG_CONFIG --cflags egl 2>conftest.err` +fi +fi + +if ${EGL_LIBS:+false} : +then : + if test ${PKG_CONFIG+y} +then : + EGL_LIBS=`$PKG_CONFIG --libs egl 2>/dev/null` +fi +fi + +EGL_LIBS=${EGL_LIBS:-"-lEGL"} +printf "%s\n" "$as_me:${as_lineno-$LINENO}: egl cflags: $EGL_CFLAGS" >&5 +printf "%s\n" "$as_me:${as_lineno-$LINENO}: egl libs: $EGL_LIBS" >&5 +if test -s conftest.err; then + printf %s "$as_me:${as_lineno-$LINENO}: egl errors: " >&5 + cat conftest.err >&5 +fi +rm -f conftest.err +ac_save_CPPFLAGS=$CPPFLAGS +CPPFLAGS="$CPPFLAGS $EGL_CFLAGS" +ac_fn_c_check_header_compile "$LINENO" "EGL/egl.h" "ac_cv_header_EGL_egl_h" "$ac_includes_default" +if test "x$ac_cv_header_EGL_egl_h" = xyes +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lEGL" >&5 +printf %s "checking for -lEGL... " >&6; } +if test ${ac_cv_lib_soname_EGL+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_soname_save_LIBS=$LIBS +LIBS="-lEGL $EGL_LIBS $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +char eglGetProcAddress (); +int +main (void) +{ +return eglGetProcAddress (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + case "$LIBEXT" in + dll) ac_cv_lib_soname_EGL=`$ac_cv_path_LDD conftest.exe | grep "EGL" | sed -e "s/dll.*/dll/"';2,$d'` ;; + dylib) ac_cv_lib_soname_EGL=`$OTOOL -L conftest$ac_exeext | grep "libEGL\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*/(libEGL.[0-9A-Za-z.]*dylib).*$/\1/"';2,$d'` ;; + *) ac_cv_lib_soname_EGL=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libEGL\.$LIBEXT" | sed -e "s/^.*\[\(libEGL\.$LIBEXT[^ ]*\)\].*$/\1/"';2,$d'` + if ${ac_cv_lib_soname_EGL:+false} : +then : + ac_cv_lib_soname_EGL=`$LDD conftest$ac_exeext | grep "libEGL\.$LIBEXT" | sed -e "s/^.*(libEGL.$LIBEXT[^ ]*).*$/\1/"';2,$d'` +fi ;; + esac +else $as_nop + ac_cv_lib_soname_EGL= +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + LIBS=$ac_check_soname_save_LIBS +fi +if ${ac_cv_lib_soname_EGL:+false} : +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 +printf "%s\n" "not found" >&6; } + +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_EGL" >&5 +printf "%s\n" "$ac_cv_lib_soname_EGL" >&6; } + +printf "%s\n" "#define SONAME_LIBEGL "$ac_cv_lib_soname_EGL"" >>confdefs.h + + +fi +fi + +CPPFLAGS=$ac_save_CPPFLAGS + + if test "x$with_wayland" != "x" + then + if test -z "$SONAME_LIBEGL" +then : + case "x$with_opengl" in + x) as_fn_append wine_notices "|Wayland EGL/GL ${notice_platform}development files not found, the Wayland driver won't support OpenGL" ;; + xno) ;; + *) as_fn_error $? "Wayland EGL/GL ${notice_platform}development files not found, the Wayland driver won't support OpenGL +This is an error since --with-opengl was requested." "$LINENO" 5 ;; +esac + +fi + fi + fi fi if test -z "$WAYLAND_CLIENT_LIBS" -o -z "$WAYLAND_SCANNER" -o -z "$XKBCOMMON_LIBS" -o -z "$XKBREGISTRY_LIBS" -o "$ac_cv_header_linux_input_h" = "no" then : @@ -23738,6 +23848,8 @@ XKBCOMMON_CFLAGS = $XKBCOMMON_CFLAGS XKBCOMMON_LIBS = $XKBCOMMON_LIBS XKBREGISTRY_CFLAGS = $XKBREGISTRY_CFLAGS XKBREGISTRY_LIBS = $XKBREGISTRY_LIBS +EGL_CFLAGS = $EGL_CFLAGS +EGL_LIBS = $EGL_LIBS PCAP_LIBS = $PCAP_LIBS PCSCLITE_LIBS = $PCSCLITE_LIBS INOTIFY_CFLAGS = $INOTIFY_CFLAGS diff --git a/configure.ac b/configure.ac index 1c59651ba1e..9af42badc31 100644 --- a/configure.ac +++ b/configure.ac @@ -1377,6 +1377,17 @@ then WINE_PACKAGE_FLAGS(XKBREGISTRY,[xkbregistry],,,, [AC_CHECK_HEADERS([xkbcommon/xkbregistry.h]) AC_CHECK_LIB(xkbregistry,rxkb_context_new,[:],[XKBREGISTRY_LIBS=""],[$XKBREGISTRY_LIBS])]) + if test "x$with_opengl" != "xno" + then + WINE_PACKAGE_FLAGS(EGL,[egl],[-lEGL],,, + [AC_CHECK_HEADER([EGL/egl.h], + [WINE_CHECK_SONAME(EGL,eglGetProcAddress,,,[$EGL_LIBS])])]) + if test "x$with_wayland" != "x" + then + WINE_NOTICE_WITH(opengl, [test -z "$SONAME_LIBEGL"], + [Wayland EGL/GL ${notice_platform}development files not found, the Wayland driver won't support OpenGL]) + fi + fi fi WINE_NOTICE_WITH(wayland, [test -z "$WAYLAND_CLIENT_LIBS" -o -z "$WAYLAND_SCANNER" -o -z "$XKBCOMMON_LIBS" -o -z "$XKBREGISTRY_LIBS" -o "$ac_cv_header_linux_input_h" = "no"], [Wayland ${notice_platform}development files not found, the Wayland driver won't be supported.], diff --git a/dlls/winewayland.drv/Makefile.in b/dlls/winewayland.drv/Makefile.in index b47bdb262c0..e9e16b474ba 100644 --- a/dlls/winewayland.drv/Makefile.in +++ b/dlls/winewayland.drv/Makefile.in @@ -6,6 +6,7 @@ UNIX_LIBS = -lwin32u $(WAYLAND_CLIENT_LIBS) $(XKBCOMMON_LIBS) $(XKBREGISTRY_LIBS SOURCES = \ display.c \ dllmain.c \ + opengl.c \ pointer-constraints-unstable-v1.xml \ relative-pointer-unstable-v1.xml \ version.rc \ diff --git a/dlls/winewayland.drv/opengl.c b/dlls/winewayland.drv/opengl.c new file mode 100644 index 00000000000..54ae281c86a --- /dev/null +++ b/dlls/winewayland.drv/opengl.c @@ -0,0 +1,136 @@ +/* + * Wayland OpenGL functions + * + * Copyright 2020 Alexandros Frantzis for Collabora Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#if 0 +#pragma makedep unix +#endif + +#include "config.h" + +#include <dlfcn.h> + +#include "waylanddrv.h" +#include "wine/debug.h" + +#if defined(SONAME_LIBEGL) + +WINE_DEFAULT_DEBUG_CHANNEL(waylanddrv); + +#include <EGL/egl.h> + +#include "wine/wgl.h" +#include "wine/wgl_driver.h" + +static void *egl_handle; +static struct opengl_funcs opengl_funcs; +static EGLDisplay egl_display; +static EGLint egl_version[2]; + +#define DECL_FUNCPTR(f) static __typeof__(f) * p_##f = NULL +DECL_FUNCPTR(eglGetDisplay); +DECL_FUNCPTR(eglGetError); +DECL_FUNCPTR(eglGetProcAddress); +DECL_FUNCPTR(eglInitialize); +#undef DECL_FUNCPTR + +static void* load_symbol(void *handle, const char *symbol) +{ + void *addr; + if (!(addr = dlsym(handle, symbol))) addr = p_eglGetProcAddress(symbol); + return addr; +} + +static void init_opengl(void) +{ + if (!(egl_handle = dlopen(SONAME_LIBEGL, RTLD_NOW|RTLD_GLOBAL))) + { + ERR("Failed to load %s: %s\n", SONAME_LIBEGL, dlerror()); + goto err; + } + + if (!(p_eglGetProcAddress = dlsym(egl_handle, "eglGetProcAddress"))) + { + ERR("Failed to load eglGetProcAddress\n"); + goto err; + } + +#define LOAD_FUNCPTR(func) \ + do { \ + if (!(p_##func = load_symbol(egl_handle, #func))) \ + { ERR("Failed to load symbol %s\n", #func); goto err; } \ + } while(0) + LOAD_FUNCPTR(eglGetDisplay); + LOAD_FUNCPTR(eglGetError); + LOAD_FUNCPTR(eglInitialize); +#undef LOAD_FUNCPTR + + egl_display = p_eglGetDisplay((EGLNativeDisplayType)process_wayland.wl_display); + if (egl_display == EGL_NO_DISPLAY) + { + ERR("Failed to get EGLDisplay\n"); + goto err; + } + if (!p_eglInitialize(egl_display, &egl_version[0], &egl_version[1])) + { + ERR("Failed to initialized EGLDisplay with error %d\n", p_eglGetError()); + goto err; + } + TRACE("EGL version %u.%u\n", egl_version[0], egl_version[1]); + + return; + +err: + if (egl_handle) + { + dlclose(egl_handle); + egl_handle = NULL; + } +} + +static BOOL has_opengl(void) +{ + static pthread_once_t init_once = PTHREAD_ONCE_INIT; + + return !pthread_once(&init_once, init_opengl) && egl_handle; +} + +/********************************************************************** + * WAYLAND_wine_get_wgl_driver + */ +struct opengl_funcs *WAYLAND_wine_get_wgl_driver(UINT version) +{ + if (version != WINE_WGL_DRIVER_VERSION) + { + ERR("Version mismatch, opengl32 wants %u but driver has %u\n", + version, WINE_WGL_DRIVER_VERSION); + return NULL; + } + if (!has_opengl()) return NULL; + return &opengl_funcs; +} + +#else /* No GL */ + +struct opengl_funcs *WAYLAND_wine_get_wgl_driver(UINT version) +{ + return NULL; +} + +#endif diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h index f030f6fc6a0..66806503edf 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -332,5 +332,6 @@ BOOL WAYLAND_WindowPosChanging(HWND hwnd, HWND insert_after, UINT swp_flags, const RECT *window_rect, const RECT *client_rect, RECT *visible_rect, struct window_surface **surface); const struct vulkan_funcs *WAYLAND_wine_get_vulkan_driver(UINT version); +struct opengl_funcs *WAYLAND_wine_get_wgl_driver(UINT version);
#endif /* __WINE_WAYLANDDRV_H */ diff --git a/dlls/winewayland.drv/waylanddrv_main.c b/dlls/winewayland.drv/waylanddrv_main.c index b60d282aacb..ca73cd4c97d 100644 --- a/dlls/winewayland.drv/waylanddrv_main.c +++ b/dlls/winewayland.drv/waylanddrv_main.c @@ -43,6 +43,7 @@ static const struct user_driver_funcs waylanddrv_funcs = .pWindowPosChanged = WAYLAND_WindowPosChanged, .pWindowPosChanging = WAYLAND_WindowPosChanging, .pwine_get_vulkan_driver = WAYLAND_wine_get_vulkan_driver, + .pwine_get_wgl_driver = WAYLAND_wine_get_wgl_driver, };
static NTSTATUS waylanddrv_unix_init(void *arg)
From: Alexandros Frantzis alexandros.frantzis@collabora.com
--- configure | 92 ++++++++++++++++++++++++++++++++++- configure.ac | 4 +- dlls/winewayland.drv/opengl.c | 36 +++++++++++++- include/config.h.in | 3 ++ 4 files changed, 132 insertions(+), 3 deletions(-)
diff --git a/configure b/configure index a96f0172579..ada319c6f20 100755 --- a/configure +++ b/configure @@ -702,6 +702,7 @@ INOTIFY_LIBS INOTIFY_CFLAGS PCSCLITE_LIBS PCAP_LIBS +OPENGL_CFLAGS EGL_LIBS EGL_CFLAGS XKBREGISTRY_LIBS @@ -1807,6 +1808,8 @@ XKBREGISTRY_CFLAGS XKBREGISTRY_LIBS EGL_CFLAGS EGL_LIBS +OPENGL_CFLAGS +OPENGL_LIBS INOTIFY_CFLAGS INOTIFY_LIBS DBUS_CFLAGS @@ -2635,6 +2638,9 @@ Some influential environment variables: Linker flags for xkbregistry, overriding pkg-config EGL_CFLAGS C compiler flags for egl, overriding pkg-config EGL_LIBS Linker flags for egl, overriding pkg-config + OPENGL_CFLAGS + C compiler flags for OpenGL, overriding pkg-config + OPENGL_LIBS Linker flags for OpenGL, overriding pkg-config INOTIFY_CFLAGS C compiler flags for libinotify, overriding pkg-config INOTIFY_LIBS @@ -16231,11 +16237,94 @@ printf "%s\n" "#define SONAME_LIBEGL "$ac_cv_lib_soname_EGL"" >>confdefs.h fi fi
+CPPFLAGS=$ac_save_CPPFLAGS + + rm -f conftest.err +if ${OPENGL_CFLAGS:+false} : +then : + if test ${PKG_CONFIG+y} +then : + OPENGL_CFLAGS=`$PKG_CONFIG --cflags OpenGL 2>conftest.err` +fi +fi + +if ${OPENGL_LIBS:+false} : +then : + if test ${PKG_CONFIG+y} +then : + OPENGL_LIBS=`$PKG_CONFIG --libs OpenGL 2>/dev/null` +fi +fi + +OPENGL_LIBS=${OPENGL_LIBS:-"-lOpenGL"} +printf "%s\n" "$as_me:${as_lineno-$LINENO}: OpenGL cflags: $OPENGL_CFLAGS" >&5 +printf "%s\n" "$as_me:${as_lineno-$LINENO}: OpenGL libs: $OPENGL_LIBS" >&5 +if test -s conftest.err; then + printf %s "$as_me:${as_lineno-$LINENO}: OpenGL errors: " >&5 + cat conftest.err >&5 +fi +rm -f conftest.err +ac_save_CPPFLAGS=$CPPFLAGS +CPPFLAGS="$CPPFLAGS $OPENGL_CFLAGS" +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lOpenGL" >&5 +printf %s "checking for -lOpenGL... " >&6; } +if test ${ac_cv_lib_soname_OpenGL+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_soname_save_LIBS=$LIBS +LIBS="-lOpenGL $OPENGL_LIBS $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +char glFlush (); +int +main (void) +{ +return glFlush (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + case "$LIBEXT" in + dll) ac_cv_lib_soname_OpenGL=`$ac_cv_path_LDD conftest.exe | grep "OpenGL" | sed -e "s/dll.*/dll/"';2,$d'` ;; + dylib) ac_cv_lib_soname_OpenGL=`$OTOOL -L conftest$ac_exeext | grep "libOpenGL\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*/(libOpenGL.[0-9A-Za-z.]*dylib).*$/\1/"';2,$d'` ;; + *) ac_cv_lib_soname_OpenGL=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libOpenGL\.$LIBEXT" | sed -e "s/^.*\[\(libOpenGL\.$LIBEXT[^ ]*\)\].*$/\1/"';2,$d'` + if ${ac_cv_lib_soname_OpenGL:+false} : +then : + ac_cv_lib_soname_OpenGL=`$LDD conftest$ac_exeext | grep "libOpenGL\.$LIBEXT" | sed -e "s/^.*(libOpenGL.$LIBEXT[^ ]*).*$/\1/"';2,$d'` +fi ;; + esac +else $as_nop + ac_cv_lib_soname_OpenGL= +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + LIBS=$ac_check_soname_save_LIBS +fi +if ${ac_cv_lib_soname_OpenGL:+false} : +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 +printf "%s\n" "not found" >&6; } + +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_OpenGL" >&5 +printf "%s\n" "$ac_cv_lib_soname_OpenGL" >&6; } + +printf "%s\n" "#define SONAME_LIBOPENGL "$ac_cv_lib_soname_OpenGL"" >>confdefs.h + + +fi CPPFLAGS=$ac_save_CPPFLAGS
if test "x$with_wayland" != "x" then - if test -z "$SONAME_LIBEGL" + if test -z "$SONAME_LIBEGL" -o -z "$SONAME_LIBOPENGL" then : case "x$with_opengl" in x) as_fn_append wine_notices "|Wayland EGL/GL ${notice_platform}development files not found, the Wayland driver won't support OpenGL" ;; @@ -23850,6 +23939,7 @@ XKBREGISTRY_CFLAGS = $XKBREGISTRY_CFLAGS XKBREGISTRY_LIBS = $XKBREGISTRY_LIBS EGL_CFLAGS = $EGL_CFLAGS EGL_LIBS = $EGL_LIBS +OPENGL_CFLAGS = $OPENGL_CFLAGS PCAP_LIBS = $PCAP_LIBS PCSCLITE_LIBS = $PCSCLITE_LIBS INOTIFY_CFLAGS = $INOTIFY_CFLAGS diff --git a/configure.ac b/configure.ac index 9af42badc31..69e9f1675c3 100644 --- a/configure.ac +++ b/configure.ac @@ -1382,9 +1382,11 @@ then WINE_PACKAGE_FLAGS(EGL,[egl],[-lEGL],,, [AC_CHECK_HEADER([EGL/egl.h], [WINE_CHECK_SONAME(EGL,eglGetProcAddress,,,[$EGL_LIBS])])]) + WINE_PACKAGE_FLAGS(OPENGL,[OpenGL],[-lOpenGL],,, + [WINE_CHECK_SONAME(OpenGL,glFlush,,,[$OPENGL_LIBS])]) if test "x$with_wayland" != "x" then - WINE_NOTICE_WITH(opengl, [test -z "$SONAME_LIBEGL"], + WINE_NOTICE_WITH(opengl, [test -z "$SONAME_LIBEGL" -o -z "$SONAME_LIBOPENGL"], [Wayland EGL/GL ${notice_platform}development files not found, the Wayland driver won't support OpenGL]) fi fi diff --git a/dlls/winewayland.drv/opengl.c b/dlls/winewayland.drv/opengl.c index 54ae281c86a..86d48428d6e 100644 --- a/dlls/winewayland.drv/opengl.c +++ b/dlls/winewayland.drv/opengl.c @@ -29,7 +29,7 @@ #include "waylanddrv.h" #include "wine/debug.h"
-#if defined(SONAME_LIBEGL) +#if defined(SONAME_LIBEGL) && defined(SONAME_LIBOPENGL)
WINE_DEFAULT_DEBUG_CHANNEL(waylanddrv);
@@ -39,10 +39,15 @@ WINE_DEFAULT_DEBUG_CHANNEL(waylanddrv); #include "wine/wgl_driver.h"
static void *egl_handle; +static void *opengl_handle; static struct opengl_funcs opengl_funcs; static EGLDisplay egl_display; static EGLint egl_version[2];
+#define USE_GL_FUNC(name) #name, +static const char *opengl_func_names[] = { ALL_WGL_FUNCS }; +#undef USE_GL_FUNC + #define DECL_FUNCPTR(f) static __typeof__(f) * p_##f = NULL DECL_FUNCPTR(eglGetDisplay); DECL_FUNCPTR(eglGetError); @@ -57,6 +62,22 @@ static void* load_symbol(void *handle, const char *symbol) return addr; }
+static BOOL init_opengl_funcs(void) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(opengl_func_names); i++) + { + if (!(((void **)&opengl_funcs.gl)[i] = load_symbol(opengl_handle, opengl_func_names[i]))) + { + ERR("%s not found, disabling OpenGL.\n", opengl_func_names[i]); + return FALSE; + } + } + + return TRUE; +} + static void init_opengl(void) { if (!(egl_handle = dlopen(SONAME_LIBEGL, RTLD_NOW|RTLD_GLOBAL))) @@ -65,6 +86,12 @@ static void init_opengl(void) goto err; }
+ if (!(opengl_handle = dlopen(SONAME_LIBOPENGL, RTLD_NOW|RTLD_GLOBAL))) + { + ERR("Failed to load %s: %s\n", SONAME_LIBOPENGL, dlerror()); + goto err; + } + if (!(p_eglGetProcAddress = dlsym(egl_handle, "eglGetProcAddress"))) { ERR("Failed to load eglGetProcAddress\n"); @@ -94,6 +121,8 @@ static void init_opengl(void) } TRACE("EGL version %u.%u\n", egl_version[0], egl_version[1]);
+ if (!init_opengl_funcs()) goto err; + return;
err: @@ -102,6 +131,11 @@ err: dlclose(egl_handle); egl_handle = NULL; } + if (opengl_handle) + { + dlclose(opengl_handle); + opengl_handle = NULL; + } }
static BOOL has_opengl(void) diff --git a/include/config.h.in b/include/config.h.in index a910b2c85f1..5888781d1a0 100644 --- a/include/config.h.in +++ b/include/config.h.in @@ -759,6 +759,9 @@ /* Define to the soname of the libodbc library. */ #undef SONAME_LIBODBC
+/* Define to the soname of the libOpenGL library. */ +#undef SONAME_LIBOPENGL + /* Define to the soname of the libOSMesa library. */ #undef SONAME_LIBOSMESA
From: Alexandros Frantzis alexandros.frantzis@collabora.com
--- dlls/winewayland.drv/opengl.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+)
diff --git a/dlls/winewayland.drv/opengl.c b/dlls/winewayland.drv/opengl.c index 86d48428d6e..3fb989833c2 100644 --- a/dlls/winewayland.drv/opengl.c +++ b/dlls/winewayland.drv/opengl.c @@ -25,6 +25,7 @@ #include "config.h"
#include <dlfcn.h> +#include <string.h>
#include "waylanddrv.h" #include "wine/debug.h" @@ -43,6 +44,7 @@ static void *opengl_handle; static struct opengl_funcs opengl_funcs; static EGLDisplay egl_display; static EGLint egl_version[2]; +static char wgl_extensions[4096];
#define USE_GL_FUNC(name) #name, static const char *opengl_func_names[] = { ALL_WGL_FUNCS }; @@ -55,6 +57,18 @@ DECL_FUNCPTR(eglGetProcAddress); DECL_FUNCPTR(eglInitialize); #undef DECL_FUNCPTR
+static const char *wayland_wglGetExtensionsStringARB(HDC hdc) +{ + TRACE("() returning "%s"\n", wgl_extensions); + return wgl_extensions; +} + +static const char *wayland_wglGetExtensionsStringEXT(void) +{ + TRACE("() returning "%s"\n", wgl_extensions); + return wgl_extensions; +} + static void* load_symbol(void *handle, const char *symbol) { void *addr; @@ -62,6 +76,13 @@ static void* load_symbol(void *handle, const char *symbol) return addr; }
+static void register_extension(const char *ext) +{ + if (wgl_extensions[0]) strcat(wgl_extensions, " "); + strcat(wgl_extensions, ext); + TRACE("%s\n", ext); +} + static BOOL init_opengl_funcs(void) { unsigned int i; @@ -75,6 +96,12 @@ static BOOL init_opengl_funcs(void) } }
+ register_extension("WGL_ARB_extensions_string"); + opengl_funcs.ext.p_wglGetExtensionsStringARB = wayland_wglGetExtensionsStringARB; + + register_extension("WGL_EXT_extensions_string"); + opengl_funcs.ext.p_wglGetExtensionsStringEXT = wayland_wglGetExtensionsStringEXT; + return TRUE; }
From: Alexandros Frantzis alexandros.frantzis@collabora.com
--- dlls/winewayland.drv/opengl.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+)
diff --git a/dlls/winewayland.drv/opengl.c b/dlls/winewayland.drv/opengl.c index 3fb989833c2..9bf1b460860 100644 --- a/dlls/winewayland.drv/opengl.c +++ b/dlls/winewayland.drv/opengl.c @@ -69,6 +69,15 @@ static const char *wayland_wglGetExtensionsStringEXT(void) return wgl_extensions; }
+static PROC wayland_wglGetProcAddress(LPCSTR name) +{ + PROC ret; + if (!strncmp(name, "wgl", 3)) return NULL; + ret = (PROC)p_eglGetProcAddress(name); + TRACE("%s -> %p\n", name, ret); + return ret; +} + static void* load_symbol(void *handle, const char *symbol) { void *addr; @@ -172,6 +181,14 @@ static BOOL has_opengl(void) return !pthread_once(&init_once, init_opengl) && egl_handle; }
+static struct opengl_funcs opengl_funcs = +{ + .wgl = + { + .p_wglGetProcAddress = wayland_wglGetProcAddress, + } +}; + /********************************************************************** * WAYLAND_wine_get_wgl_driver */
From: Alexandros Frantzis alexandros.frantzis@collabora.com
Create an array of supported EGLConfigs, and use this information to populate the PIXELFORMATDESCRIPTOR. --- dlls/winewayland.drv/opengl.c | 118 ++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+)
diff --git a/dlls/winewayland.drv/opengl.c b/dlls/winewayland.drv/opengl.c index 9bf1b460860..fc77950a6a1 100644 --- a/dlls/winewayland.drv/opengl.c +++ b/dlls/winewayland.drv/opengl.c @@ -25,6 +25,7 @@ #include "config.h"
#include <dlfcn.h> +#include <stdlib.h> #include <string.h>
#include "waylanddrv.h" @@ -45,18 +46,77 @@ static struct opengl_funcs opengl_funcs; static EGLDisplay egl_display; static EGLint egl_version[2]; static char wgl_extensions[4096]; +static EGLConfig *egl_configs; +static int num_egl_configs;
#define USE_GL_FUNC(name) #name, static const char *opengl_func_names[] = { ALL_WGL_FUNCS }; #undef USE_GL_FUNC
#define DECL_FUNCPTR(f) static __typeof__(f) * p_##f = NULL +DECL_FUNCPTR(eglChooseConfig); +DECL_FUNCPTR(eglGetConfigAttrib); DECL_FUNCPTR(eglGetDisplay); DECL_FUNCPTR(eglGetError); DECL_FUNCPTR(eglGetProcAddress); DECL_FUNCPTR(eglInitialize); #undef DECL_FUNCPTR
+static BOOL has_opengl(void); + +static int wayland_wglDescribePixelFormat(HDC hdc, int fmt, UINT size, + PIXELFORMATDESCRIPTOR *pfd) +{ + EGLint val; + EGLConfig config; + + if (!has_opengl()) return 0; + if (!pfd) return num_egl_configs; + if (size < sizeof(*pfd)) return 0; + if (fmt <= 0 || fmt > num_egl_configs) return 0; + + config = egl_configs[fmt - 1]; + + memset(pfd, 0, sizeof(*pfd)); + pfd->nSize = sizeof(*pfd); + pfd->nVersion = 1; + pfd->dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER | + PFD_SUPPORT_COMPOSITION; + pfd->iPixelType = PFD_TYPE_RGBA; + pfd->iLayerType = PFD_MAIN_PLANE; + + p_eglGetConfigAttrib(egl_display, config, EGL_RED_SIZE, &val); + pfd->cRedBits = val; + p_eglGetConfigAttrib(egl_display, config, EGL_GREEN_SIZE, &val); + pfd->cGreenBits = val; + p_eglGetConfigAttrib(egl_display, config, EGL_BLUE_SIZE, &val); + pfd->cBlueBits = val; + p_eglGetConfigAttrib(egl_display, config, EGL_ALPHA_SIZE, &val); + pfd->cAlphaBits = val; + p_eglGetConfigAttrib(egl_display, config, EGL_DEPTH_SIZE, &val); + pfd->cDepthBits = val; + p_eglGetConfigAttrib(egl_display, config, EGL_STENCIL_SIZE, &val); + pfd->cStencilBits = val; + /* cColorBits bits exclude alpha */ + pfd->cColorBits = pfd->cRedBits + pfd->cGreenBits + pfd->cBlueBits; + + /* Although we don't get information from EGL about the component shifts + * or the native format, the 0xARGB order is the most common. */ + pfd->cBlueShift = 0; + pfd->cGreenShift = pfd->cBlueBits; + pfd->cRedShift = pfd->cGreenBits + pfd->cBlueBits; + if (pfd->cAlphaBits) + pfd->cAlphaShift = pfd->cRedBits + pfd->cGreenBits + pfd->cBlueBits; + else + pfd->cAlphaShift = 0; + + TRACE("fmt %u color %u %u/%u/%u/%u depth %u stencil %u\n", + fmt, pfd->cColorBits, pfd->cRedBits, pfd->cGreenBits, pfd->cBlueBits, + pfd->cAlphaBits, pfd->cDepthBits, pfd->cStencilBits); + + return num_egl_configs; +} + static const char *wayland_wglGetExtensionsStringARB(HDC hdc) { TRACE("() returning "%s"\n", wgl_extensions); @@ -114,6 +174,60 @@ static BOOL init_opengl_funcs(void) return TRUE; }
+static BOOL init_egl_configs(void) +{ + EGLint i; + const EGLint attribs[] = + { + EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_NONE + }; + + p_eglChooseConfig(egl_display, attribs, NULL, 0, &num_egl_configs); + if (!(egl_configs = malloc(num_egl_configs * sizeof(*egl_configs)))) + { + ERR("Failed to allocate memory for EGL configs\n"); + return FALSE; + } + if (!p_eglChooseConfig(egl_display, attribs, egl_configs, num_egl_configs, + &num_egl_configs) || + !num_egl_configs) + { + free(egl_configs); + egl_configs = NULL; + num_egl_configs = 0; + ERR("Failed to get any configs from eglChooseConfig\n"); + return FALSE; + } + + if (TRACE_ON(waylanddrv)) + { + for (i = 0; i < num_egl_configs; i++) + { + EGLint id, type, visual_id, native, render, color, r, g, b, a, d, s; + p_eglGetConfigAttrib(egl_display, egl_configs[i], EGL_NATIVE_VISUAL_ID, &visual_id); + p_eglGetConfigAttrib(egl_display, egl_configs[i], EGL_SURFACE_TYPE, &type); + p_eglGetConfigAttrib(egl_display, egl_configs[i], EGL_RENDERABLE_TYPE, &render); + p_eglGetConfigAttrib(egl_display, egl_configs[i], EGL_CONFIG_ID, &id); + p_eglGetConfigAttrib(egl_display, egl_configs[i], EGL_NATIVE_RENDERABLE, &native); + p_eglGetConfigAttrib(egl_display, egl_configs[i], EGL_COLOR_BUFFER_TYPE, &color); + p_eglGetConfigAttrib(egl_display, egl_configs[i], EGL_RED_SIZE, &r); + p_eglGetConfigAttrib(egl_display, egl_configs[i], EGL_GREEN_SIZE, &g); + p_eglGetConfigAttrib(egl_display, egl_configs[i], EGL_BLUE_SIZE, &b); + p_eglGetConfigAttrib(egl_display, egl_configs[i], EGL_ALPHA_SIZE, &a); + p_eglGetConfigAttrib(egl_display, egl_configs[i], EGL_DEPTH_SIZE, &d); + p_eglGetConfigAttrib(egl_display, egl_configs[i], EGL_STENCIL_SIZE, &s); + TRACE("%u: config %d id %d type %x visual %d native %d render %x " + "colortype %d rgba %d,%d,%d,%d depth %u stencil %d\n", + num_egl_configs, i, id, type, visual_id, native, render, + color, r, g, b, a, d, s); + } + } + + return TRUE; +} + static void init_opengl(void) { if (!(egl_handle = dlopen(SONAME_LIBEGL, RTLD_NOW|RTLD_GLOBAL))) @@ -139,6 +253,8 @@ static void init_opengl(void) if (!(p_##func = load_symbol(egl_handle, #func))) \ { ERR("Failed to load symbol %s\n", #func); goto err; } \ } while(0) + LOAD_FUNCPTR(eglChooseConfig); + LOAD_FUNCPTR(eglGetConfigAttrib); LOAD_FUNCPTR(eglGetDisplay); LOAD_FUNCPTR(eglGetError); LOAD_FUNCPTR(eglInitialize); @@ -158,6 +274,7 @@ static void init_opengl(void) TRACE("EGL version %u.%u\n", egl_version[0], egl_version[1]);
if (!init_opengl_funcs()) goto err; + if (!init_egl_configs()) goto err;
return;
@@ -185,6 +302,7 @@ static struct opengl_funcs opengl_funcs = { .wgl = { + .p_wglDescribePixelFormat = wayland_wglDescribePixelFormat, .p_wglGetProcAddress = wayland_wglGetProcAddress, } };
From: Alexandros Frantzis alexandros.frantzis@collabora.com
Introduce the internal wayland_gl_drawable object, which associates a window (and its backing Wayland surface) with an EGL surface. --- configure | 90 ++++++++++++++- configure.ac | 7 +- dlls/winewayland.drv/Makefile.in | 4 +- dlls/winewayland.drv/opengl.c | 181 +++++++++++++++++++++++++++++- dlls/winewayland.drv/waylanddrv.h | 6 + dlls/winewayland.drv/window.c | 1 + include/config.h.in | 3 + 7 files changed, 287 insertions(+), 5 deletions(-)
diff --git a/configure b/configure index ada319c6f20..5b125491584 100755 --- a/configure +++ b/configure @@ -702,6 +702,8 @@ INOTIFY_LIBS INOTIFY_CFLAGS PCSCLITE_LIBS PCAP_LIBS +WAYLAND_EGL_LIBS +WAYLAND_EGL_CFLAGS OPENGL_CFLAGS EGL_LIBS EGL_CFLAGS @@ -1810,6 +1812,8 @@ EGL_CFLAGS EGL_LIBS OPENGL_CFLAGS OPENGL_LIBS +WAYLAND_EGL_CFLAGS +WAYLAND_EGL_LIBS INOTIFY_CFLAGS INOTIFY_LIBS DBUS_CFLAGS @@ -2641,6 +2645,10 @@ Some influential environment variables: OPENGL_CFLAGS C compiler flags for OpenGL, overriding pkg-config OPENGL_LIBS Linker flags for OpenGL, overriding pkg-config + WAYLAND_EGL_CFLAGS + C compiler flags for wayland-egl, overriding pkg-config + WAYLAND_EGL_LIBS + Linker flags for wayland-egl, overriding pkg-config INOTIFY_CFLAGS C compiler flags for libinotify, overriding pkg-config INOTIFY_LIBS @@ -16320,11 +16328,89 @@ printf "%s\n" "#define SONAME_LIBOPENGL "$ac_cv_lib_soname_OpenGL"" >>confdefs
fi +CPPFLAGS=$ac_save_CPPFLAGS + + rm -f conftest.err +if ${WAYLAND_EGL_CFLAGS:+false} : +then : + if test ${PKG_CONFIG+y} +then : + WAYLAND_EGL_CFLAGS=`$PKG_CONFIG --cflags wayland-egl 2>conftest.err` +fi +fi + +if ${WAYLAND_EGL_LIBS:+false} : +then : + if test ${PKG_CONFIG+y} +then : + WAYLAND_EGL_LIBS=`$PKG_CONFIG --libs wayland-egl 2>/dev/null` +fi +fi + + +printf "%s\n" "$as_me:${as_lineno-$LINENO}: wayland-egl cflags: $WAYLAND_EGL_CFLAGS" >&5 +printf "%s\n" "$as_me:${as_lineno-$LINENO}: wayland-egl libs: $WAYLAND_EGL_LIBS" >&5 +if test -s conftest.err; then + printf %s "$as_me:${as_lineno-$LINENO}: wayland-egl errors: " >&5 + cat conftest.err >&5 +fi +rm -f conftest.err +ac_save_CPPFLAGS=$CPPFLAGS +CPPFLAGS="$CPPFLAGS $WAYLAND_EGL_CFLAGS" +ac_fn_c_check_header_compile "$LINENO" "wayland-egl.h" "ac_cv_header_wayland_egl_h" "$ac_includes_default" +if test "x$ac_cv_header_wayland_egl_h" = xyes +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for wl_egl_window_create in -lwayland-egl" >&5 +printf %s "checking for wl_egl_window_create in -lwayland-egl... " >&6; } +if test ${ac_cv_lib_wayland_egl_wl_egl_window_create+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lwayland-egl $WAYLAND_EGL_LIBS $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +char wl_egl_window_create (); +int +main (void) +{ +return wl_egl_window_create (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_wayland_egl_wl_egl_window_create=yes +else $as_nop + ac_cv_lib_wayland_egl_wl_egl_window_create=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_wayland_egl_wl_egl_window_create" >&5 +printf "%s\n" "$ac_cv_lib_wayland_egl_wl_egl_window_create" >&6; } +if test "x$ac_cv_lib_wayland_egl_wl_egl_window_create" = xyes +then : + +printf "%s\n" "#define HAVE_LIBWAYLAND_EGL 1" >>confdefs.h + +else $as_nop + WAYLAND_EGL_LIBS="" +fi + +fi + CPPFLAGS=$ac_save_CPPFLAGS
if test "x$with_wayland" != "x" then - if test -z "$SONAME_LIBEGL" -o -z "$SONAME_LIBOPENGL" + if test -z "$SONAME_LIBEGL" -o -z "$SONAME_LIBOPENGL" -o -z "$HAVE_LIBWAYLAND_EGL" then : case "x$with_opengl" in x) as_fn_append wine_notices "|Wayland EGL/GL ${notice_platform}development files not found, the Wayland driver won't support OpenGL" ;; @@ -23940,6 +24026,8 @@ XKBREGISTRY_LIBS = $XKBREGISTRY_LIBS EGL_CFLAGS = $EGL_CFLAGS EGL_LIBS = $EGL_LIBS OPENGL_CFLAGS = $OPENGL_CFLAGS +WAYLAND_EGL_CFLAGS = $WAYLAND_EGL_CFLAGS +WAYLAND_EGL_LIBS = $WAYLAND_EGL_LIBS PCAP_LIBS = $PCAP_LIBS PCSCLITE_LIBS = $PCSCLITE_LIBS INOTIFY_CFLAGS = $INOTIFY_CFLAGS diff --git a/configure.ac b/configure.ac index 69e9f1675c3..4f834b26ef4 100644 --- a/configure.ac +++ b/configure.ac @@ -1384,9 +1384,14 @@ then [WINE_CHECK_SONAME(EGL,eglGetProcAddress,,,[$EGL_LIBS])])]) WINE_PACKAGE_FLAGS(OPENGL,[OpenGL],[-lOpenGL],,, [WINE_CHECK_SONAME(OpenGL,glFlush,,,[$OPENGL_LIBS])]) + WINE_PACKAGE_FLAGS(WAYLAND_EGL,[wayland-egl],,,, + [AC_CHECK_HEADER([wayland-egl.h], + [AC_CHECK_LIB(wayland-egl,wl_egl_window_create, + [AC_DEFINE(HAVE_LIBWAYLAND_EGL, 1, [Define if we have the wayland-egl development environment])], + [WAYLAND_EGL_LIBS=""],[$WAYLAND_EGL_LIBS])])]) if test "x$with_wayland" != "x" then - WINE_NOTICE_WITH(opengl, [test -z "$SONAME_LIBEGL" -o -z "$SONAME_LIBOPENGL"], + WINE_NOTICE_WITH(opengl, [test -z "$SONAME_LIBEGL" -o -z "$SONAME_LIBOPENGL" -o -z "$HAVE_LIBWAYLAND_EGL"], [Wayland EGL/GL ${notice_platform}development files not found, the Wayland driver won't support OpenGL]) fi fi diff --git a/dlls/winewayland.drv/Makefile.in b/dlls/winewayland.drv/Makefile.in index e9e16b474ba..c8a4d5f782c 100644 --- a/dlls/winewayland.drv/Makefile.in +++ b/dlls/winewayland.drv/Makefile.in @@ -1,7 +1,7 @@ MODULE = winewayland.drv UNIXLIB = winewayland.so -UNIX_CFLAGS = $(WAYLAND_CLIENT_CFLAGS) $(XKBCOMMON_CFLAGS) $(XKBREGISTRY_CFLAGS) -UNIX_LIBS = -lwin32u $(WAYLAND_CLIENT_LIBS) $(XKBCOMMON_LIBS) $(XKBREGISTRY_LIBS) $(PTHREAD_LIBS) -lm +UNIX_CFLAGS = $(WAYLAND_CLIENT_CFLAGS) $(WAYLAND_EGL_CFLAGS) $(XKBCOMMON_CFLAGS) $(XKBREGISTRY_CFLAGS) +UNIX_LIBS = -lwin32u $(WAYLAND_CLIENT_LIBS) $(WAYLAND_EGL_LIBS) $(XKBCOMMON_LIBS) $(XKBREGISTRY_LIBS) $(PTHREAD_LIBS) -lm
SOURCES = \ display.c \ diff --git a/dlls/winewayland.drv/opengl.c b/dlls/winewayland.drv/opengl.c index fc77950a6a1..a7b8d0ba40d 100644 --- a/dlls/winewayland.drv/opengl.c +++ b/dlls/winewayland.drv/opengl.c @@ -31,11 +31,12 @@ #include "waylanddrv.h" #include "wine/debug.h"
-#if defined(SONAME_LIBEGL) && defined(SONAME_LIBOPENGL) +#if defined(SONAME_LIBEGL) && defined(SONAME_LIBOPENGL) && defined(HAVE_LIBWAYLAND_EGL)
WINE_DEFAULT_DEBUG_CHANNEL(waylanddrv);
#include <EGL/egl.h> +#include <wayland-egl.h>
#include "wine/wgl.h" #include "wine/wgl_driver.h" @@ -55,6 +56,8 @@ static const char *opengl_func_names[] = { ALL_WGL_FUNCS };
#define DECL_FUNCPTR(f) static __typeof__(f) * p_##f = NULL DECL_FUNCPTR(eglChooseConfig); +DECL_FUNCPTR(eglCreateWindowSurface); +DECL_FUNCPTR(eglDestroySurface); DECL_FUNCPTR(eglGetConfigAttrib); DECL_FUNCPTR(eglGetDisplay); DECL_FUNCPTR(eglGetError); @@ -62,6 +65,153 @@ DECL_FUNCPTR(eglGetProcAddress); DECL_FUNCPTR(eglInitialize); #undef DECL_FUNCPTR
+static pthread_mutex_t gl_object_mutex = PTHREAD_MUTEX_INITIALIZER; +static struct list gl_drawables = LIST_INIT(gl_drawables); + +struct wayland_gl_drawable +{ + struct list entry; + LONG ref; + HWND hwnd; + struct wayland_client_surface *client; + struct wl_egl_window *wl_egl_window; + EGLSurface surface; +}; + +static void wayland_gl_drawable_release(struct wayland_gl_drawable *gl) +{ + if (InterlockedDecrement(&gl->ref)) return; + if (gl->surface) p_eglDestroySurface(egl_display, gl->surface); + if (gl->wl_egl_window) wl_egl_window_destroy(gl->wl_egl_window); + if (gl->client) + { + HWND hwnd = wl_surface_get_user_data(gl->client->wl_surface); + struct wayland_surface *wayland_surface = wayland_surface_lock_hwnd(hwnd); + + if (wayland_client_surface_release(gl->client) && wayland_surface) + wayland_surface->client = NULL; + + if (wayland_surface) pthread_mutex_unlock(&wayland_surface->mutex); + } + + free(gl); +} + +static struct wayland_gl_drawable *wayland_gl_drawable_create(HWND hwnd, int format) +{ + struct wayland_gl_drawable *gl; + struct wayland_surface *wayland_surface; + int client_width = 0, client_height = 0; + + TRACE("hwnd=%p format=%d\n", hwnd, format); + + gl = calloc(1, sizeof(*gl)); + if (!gl) return NULL; + + gl->ref = 1; + gl->hwnd = hwnd; + + /* Get the client surface for the HWND. If don't have a wayland surface + * (e.g., HWND_MESSAGE windows) just create a dummy surface to act as the + * target render surface. */ + if ((wayland_surface = wayland_surface_lock_hwnd(hwnd))) + { + gl->client = wayland_surface_get_client(wayland_surface); + client_width = wayland_surface->window.client_rect.right - + wayland_surface->window.client_rect.left; + client_height = wayland_surface->window.client_rect.bottom - + wayland_surface->window.client_rect.top; + if (client_width == 0 || client_height == 0) + client_width = client_height = 1; + pthread_mutex_unlock(&wayland_surface->mutex); + } + else if ((wayland_surface = wayland_surface_create(0))) + { + gl->client = wayland_surface_get_client(wayland_surface); + client_width = client_height = 1; + /* It's fine to destroy the wayland surface, the client surface + * can safely outlive it. */ + wayland_surface_destroy(wayland_surface); + } + if (!gl->client) goto err; + + gl->wl_egl_window = wl_egl_window_create(gl->client->wl_surface, + client_width, client_height); + if (!gl->wl_egl_window) + { + ERR("Failed to create wl_egl_window\n"); + goto err; + } + + gl->surface = p_eglCreateWindowSurface(egl_display, egl_configs[format - 1], + (EGLNativeWindowType)gl->wl_egl_window, NULL); + if (!gl->surface) + { + ERR("Failed to create EGL surface\n"); + goto err; + } + + TRACE("hwnd=%p egl_surface=%p\n", gl->hwnd, gl->surface); + + return gl; + +err: + wayland_gl_drawable_release(gl); + return NULL; +} + +static void wayland_update_gl_drawable(HWND hwnd, struct wayland_gl_drawable *new) +{ + struct wayland_gl_drawable *gl, *old = NULL; + + pthread_mutex_lock(&gl_object_mutex); + + LIST_FOR_EACH_ENTRY(gl, &gl_drawables, struct wayland_gl_drawable, entry) + { + if (gl->hwnd != hwnd) continue; + list_remove(&gl->entry); + old = gl; + break; + } + if (new) list_add_head(&gl_drawables, &new->entry); + + pthread_mutex_unlock(&gl_object_mutex); + + if (old) wayland_gl_drawable_release(old); +} + +static BOOL set_pixel_format(HDC hdc, int format, BOOL internal) +{ + HWND hwnd = NtUserWindowFromDC(hdc); + struct wayland_gl_drawable *gl; + int prev = 0; + + if (!hwnd || hwnd == NtUserGetDesktopWindow()) + { + WARN("not a proper window DC %p/%p\n", hdc, hwnd); + return FALSE; + } + if (format < 0 || format >= num_egl_configs) + { + WARN("Invalid format %d\n", format); + return FALSE; + } + TRACE("%p/%p format %d\n", hdc, hwnd, format); + + /* Even for internal pixel format fail setting it if the app has already set a + * different pixel format. Let wined3d create a backup GL context instead. + * Switching pixel format involves drawable recreation and is much more expensive + * than blitting from backup context. */ + if ((prev = win32u_get_window_pixel_format(hwnd))) + return prev == format; + + if (!(gl = wayland_gl_drawable_create(hwnd, format))) return FALSE; + wayland_update_gl_drawable(hwnd, gl); + win32u_set_window_pixel_format(hwnd, format, internal); + + return TRUE; +} + static BOOL has_opengl(void);
static int wayland_wglDescribePixelFormat(HDC hdc, int fmt, UINT size, @@ -138,6 +288,17 @@ static PROC wayland_wglGetProcAddress(LPCSTR name) return ret; }
+static BOOL wayland_wglSetPixelFormat(HDC hdc, int format, + const PIXELFORMATDESCRIPTOR *pfd) +{ + return set_pixel_format(hdc, format, FALSE); +} + +static BOOL wayland_wglSetPixelFormatWINE(HDC hdc, int format) +{ + return set_pixel_format(hdc, format, TRUE); +} + static void* load_symbol(void *handle, const char *symbol) { void *addr; @@ -171,6 +332,9 @@ static BOOL init_opengl_funcs(void) register_extension("WGL_EXT_extensions_string"); opengl_funcs.ext.p_wglGetExtensionsStringEXT = wayland_wglGetExtensionsStringEXT;
+ register_extension("WGL_WINE_pixel_format_passthrough"); + opengl_funcs.ext.p_wglSetPixelFormatWINE = wayland_wglSetPixelFormatWINE; + return TRUE; }
@@ -254,6 +418,8 @@ static void init_opengl(void) { ERR("Failed to load symbol %s\n", #func); goto err; } \ } while(0) LOAD_FUNCPTR(eglChooseConfig); + LOAD_FUNCPTR(eglCreateWindowSurface); + LOAD_FUNCPTR(eglDestroySurface); LOAD_FUNCPTR(eglGetConfigAttrib); LOAD_FUNCPTR(eglGetDisplay); LOAD_FUNCPTR(eglGetError); @@ -304,6 +470,7 @@ static struct opengl_funcs opengl_funcs = { .p_wglDescribePixelFormat = wayland_wglDescribePixelFormat, .p_wglGetProcAddress = wayland_wglGetProcAddress, + .p_wglSetPixelFormat = wayland_wglSetPixelFormat, } };
@@ -322,6 +489,14 @@ struct opengl_funcs *WAYLAND_wine_get_wgl_driver(UINT version) return &opengl_funcs; }
+/********************************************************************** + * wayland_destroy_gl_drawable + */ +void wayland_destroy_gl_drawable(HWND hwnd) +{ + wayland_update_gl_drawable(hwnd, NULL); +} + #else /* No GL */
struct opengl_funcs *WAYLAND_wine_get_wgl_driver(UINT version) @@ -329,4 +504,8 @@ struct opengl_funcs *WAYLAND_wine_get_wgl_driver(UINT version) return NULL; }
+void wayland_destroy_gl_drawable(HWND hwnd) +{ +} + #endif diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h index 66806503edf..7da33dc9f18 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -292,6 +292,12 @@ void wayland_pointer_init(struct wl_pointer *wl_pointer); void wayland_pointer_deinit(void); void wayland_pointer_clear_constraint(void);
+/********************************************************************** + * OpenGL + */ + +void wayland_destroy_gl_drawable(HWND hwnd); + /********************************************************************** * Helpers */ diff --git a/dlls/winewayland.drv/window.c b/dlls/winewayland.drv/window.c index ac5da371e5c..a02363411ea 100644 --- a/dlls/winewayland.drv/window.c +++ b/dlls/winewayland.drv/window.c @@ -402,6 +402,7 @@ void WAYLAND_DestroyWindow(HWND hwnd)
if (!(data = wayland_win_data_get(hwnd))) return; wayland_win_data_destroy(data); + wayland_destroy_gl_drawable(hwnd); }
/*********************************************************************** diff --git a/include/config.h.in b/include/config.h.in index 5888781d1a0..d7fdf633871 100644 --- a/include/config.h.in +++ b/include/config.h.in @@ -132,6 +132,9 @@ /* Define to 1 if you have the `unwind' library (-lunwind). */ #undef HAVE_LIBUNWIND
+/* Define if we have the wayland-egl development environment */ +#undef HAVE_LIBWAYLAND_EGL + /* Define if you have the X Shape extension */ #undef HAVE_LIBXSHAPE
From: Alexandros Frantzis alexandros.frantzis@collabora.com
Each WGL context is backed by an EGL context. --- dlls/winewayland.drv/opengl.c | 87 +++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+)
diff --git a/dlls/winewayland.drv/opengl.c b/dlls/winewayland.drv/opengl.c index a7b8d0ba40d..621ee66d3ef 100644 --- a/dlls/winewayland.drv/opengl.c +++ b/dlls/winewayland.drv/opengl.c @@ -55,8 +55,11 @@ static const char *opengl_func_names[] = { ALL_WGL_FUNCS }; #undef USE_GL_FUNC
#define DECL_FUNCPTR(f) static __typeof__(f) * p_##f = NULL +DECL_FUNCPTR(eglBindAPI); DECL_FUNCPTR(eglChooseConfig); +DECL_FUNCPTR(eglCreateContext); DECL_FUNCPTR(eglCreateWindowSurface); +DECL_FUNCPTR(eglDestroyContext); DECL_FUNCPTR(eglDestroySurface); DECL_FUNCPTR(eglGetConfigAttrib); DECL_FUNCPTR(eglGetDisplay); @@ -67,17 +70,43 @@ DECL_FUNCPTR(eglInitialize);
static pthread_mutex_t gl_object_mutex = PTHREAD_MUTEX_INITIALIZER; static struct list gl_drawables = LIST_INIT(gl_drawables); +static struct list gl_contexts = LIST_INIT(gl_contexts);
struct wayland_gl_drawable { struct list entry; LONG ref; HWND hwnd; + int format; struct wayland_client_surface *client; struct wl_egl_window *wl_egl_window; EGLSurface surface; };
+struct wgl_context +{ + struct list entry; + EGLConfig config; + EGLContext context; +}; + +static struct wayland_gl_drawable *wayland_gl_drawable_get(HWND hwnd) +{ + struct wayland_gl_drawable *gl, *ret = NULL; + + pthread_mutex_lock(&gl_object_mutex); + LIST_FOR_EACH_ENTRY(gl, &gl_drawables, struct wayland_gl_drawable, entry) + { + if (gl->hwnd != hwnd) continue; + InterlockedIncrement(&gl->ref); + ret = gl; + break; + } + pthread_mutex_unlock(&gl_object_mutex); + + return ret; +} + static void wayland_gl_drawable_release(struct wayland_gl_drawable *gl) { if (InterlockedDecrement(&gl->ref)) return; @@ -110,6 +139,7 @@ static struct wayland_gl_drawable *wayland_gl_drawable_create(HWND hwnd, int for
gl->ref = 1; gl->hwnd = hwnd; + gl->format = format;
/* Get the client surface for the HWND. If don't have a wayland surface * (e.g., HWND_MESSAGE windows) just create a dummy surface to act as the @@ -212,6 +242,57 @@ static BOOL set_pixel_format(HDC hdc, int format, BOOL internal) return TRUE; }
+static struct wgl_context *create_context(HDC hdc) +{ + struct wayland_gl_drawable *gl; + struct wgl_context *ctx; + + if (!(gl = wayland_gl_drawable_get(NtUserWindowFromDC(hdc)))) return NULL; + + if (!(ctx = calloc(1, sizeof(*ctx)))) + { + ERR("Failed to allocate memory for GL context\n"); + goto out; + } + + ctx->config = egl_configs[gl->format - 1]; + ctx->context = p_eglCreateContext(egl_display, ctx->config, EGL_NO_CONTEXT, NULL); + + pthread_mutex_lock(&gl_object_mutex); + list_add_head(&gl_contexts, &ctx->entry); + pthread_mutex_unlock(&gl_object_mutex); + + TRACE("ctx=%p egl_context=%p\n", ctx, ctx->context); + +out: + wayland_gl_drawable_release(gl); + return ctx; +} + +static BOOL wayland_wglCopyContext(struct wgl_context *src, + struct wgl_context *dst, UINT mask) +{ + FIXME("%p -> %p mask %#x unsupported\n", src, dst, mask); + return FALSE; +} + +static struct wgl_context *wayland_wglCreateContext(HDC hdc) +{ + TRACE("hdc=%p\n", hdc); + p_eglBindAPI(EGL_OPENGL_API); + return create_context(hdc); +} + +static BOOL wayland_wglDeleteContext(struct wgl_context *ctx) +{ + pthread_mutex_lock(&gl_object_mutex); + list_remove(&ctx->entry); + pthread_mutex_unlock(&gl_object_mutex); + p_eglDestroyContext(egl_display, ctx->context); + free(ctx); + return TRUE; +} + static BOOL has_opengl(void);
static int wayland_wglDescribePixelFormat(HDC hdc, int fmt, UINT size, @@ -417,8 +498,11 @@ static void init_opengl(void) if (!(p_##func = load_symbol(egl_handle, #func))) \ { ERR("Failed to load symbol %s\n", #func); goto err; } \ } while(0) + LOAD_FUNCPTR(eglBindAPI); LOAD_FUNCPTR(eglChooseConfig); + LOAD_FUNCPTR(eglCreateContext); LOAD_FUNCPTR(eglCreateWindowSurface); + LOAD_FUNCPTR(eglDestroyContext); LOAD_FUNCPTR(eglDestroySurface); LOAD_FUNCPTR(eglGetConfigAttrib); LOAD_FUNCPTR(eglGetDisplay); @@ -468,6 +552,9 @@ static struct opengl_funcs opengl_funcs = { .wgl = { + .p_wglCopyContext = wayland_wglCopyContext, + .p_wglCreateContext = wayland_wglCreateContext, + .p_wglDeleteContext = wayland_wglDeleteContext, .p_wglDescribePixelFormat = wayland_wglDescribePixelFormat, .p_wglGetProcAddress = wayland_wglGetProcAddress, .p_wglSetPixelFormat = wayland_wglSetPixelFormat,
From: Alexandros Frantzis alexandros.frantzis@collabora.com
--- dlls/winewayland.drv/opengl.c | 122 +++++++++++++++++++++++++++++++++- 1 file changed, 121 insertions(+), 1 deletion(-)
diff --git a/dlls/winewayland.drv/opengl.c b/dlls/winewayland.drv/opengl.c index 621ee66d3ef..d905b4bd22c 100644 --- a/dlls/winewayland.drv/opengl.c +++ b/dlls/winewayland.drv/opengl.c @@ -66,6 +66,7 @@ DECL_FUNCPTR(eglGetDisplay); DECL_FUNCPTR(eglGetError); DECL_FUNCPTR(eglGetProcAddress); DECL_FUNCPTR(eglInitialize); +DECL_FUNCPTR(eglMakeCurrent); #undef DECL_FUNCPTR
static pthread_mutex_t gl_object_mutex = PTHREAD_MUTEX_INITIALIZER; @@ -88,6 +89,7 @@ struct wgl_context struct list entry; EGLConfig config; EGLContext context; + struct wayland_gl_drawable *draw, *read; };
static struct wayland_gl_drawable *wayland_gl_drawable_get(HWND hwnd) @@ -190,9 +192,43 @@ err: return NULL; }
+static inline void wayland_gl_drawable_array_add(struct wl_array *drawables, + struct wayland_gl_drawable *gl) +{ + struct wayland_gl_drawable **elem; + + if ((elem = wl_array_add(drawables, sizeof(gl)))) *elem = gl; +} + +static void update_context_drawables(struct wayland_gl_drawable *new, + struct wayland_gl_drawable *old, + struct wl_array *release) +{ + struct wgl_context *ctx; + + LIST_FOR_EACH_ENTRY(ctx, &gl_contexts, struct wgl_context, entry) + { + if (ctx->draw == old) + { + wayland_gl_drawable_array_add(release, ctx->draw); + InterlockedIncrement(&new->ref); + ctx->draw = new; + } + if (ctx->read == old) + { + wayland_gl_drawable_array_add(release, ctx->read); + InterlockedIncrement(&new->ref); + ctx->read = new; + } + } +} + static void wayland_update_gl_drawable(HWND hwnd, struct wayland_gl_drawable *new) { struct wayland_gl_drawable *gl, *old = NULL; + struct wl_array release; + + wl_array_init(&release);
pthread_mutex_lock(&gl_object_mutex);
@@ -204,10 +240,61 @@ static void wayland_update_gl_drawable(HWND hwnd, struct wayland_gl_drawable *ne break; } if (new) list_add_head(&gl_drawables, &new->entry); + if (old && new) update_context_drawables(new, old, &release); + if (old) wayland_gl_drawable_array_add(&release, old); + + pthread_mutex_unlock(&gl_object_mutex); + + /* Release the drawables outside the gl_object_mutex lock, since the release + * process may acquire the wayland_surface lock and lead to a deadlock. */ + wl_array_for_each(gl, &release) wayland_gl_drawable_release(gl); + wl_array_release(&release); +} + +static BOOL wgl_context_make_current(struct wgl_context *ctx, HWND draw_hwnd, + HWND read_hwnd) +{ + BOOL ret; + struct wayland_gl_drawable *draw_gl = NULL, *read_gl = NULL; + struct wayland_gl_drawable *release[2]; + int i; + + draw_gl = wayland_gl_drawable_get(draw_hwnd); + read_gl = wayland_gl_drawable_get(read_hwnd); + + TRACE("%p/%p context %p surface %p/%p\n", + draw_hwnd, read_hwnd, ctx->context, + draw_gl ? draw_gl->surface : NULL, + read_gl ? read_gl->surface : NULL); + + pthread_mutex_lock(&gl_object_mutex); + + ret = p_eglMakeCurrent(egl_display, + draw_gl ? draw_gl->surface : NULL, + read_gl ? read_gl->surface : NULL, + ctx->context); + if (ret) + { + release[0] = ctx->draw; + release[1] = ctx->read; + ctx->draw = draw_gl; + ctx->read = read_gl; + NtCurrentTeb()->glContext = ctx; + } + else + { + release[0] = draw_gl; + release[1] = read_gl; + }
pthread_mutex_unlock(&gl_object_mutex);
- if (old) wayland_gl_drawable_release(old); + /* Release the drawables outside the gl_object_mutex lock, since the release + * process may acquire the wayland_surface lock and lead to a deadlock. */ + for (i = 0; i < ARRAY_SIZE(release); ++i) + if (release[i]) wayland_gl_drawable_release(release[i]); + + return ret; }
static BOOL set_pixel_format(HDC hdc, int format, BOOL internal) @@ -289,6 +376,8 @@ static BOOL wayland_wglDeleteContext(struct wgl_context *ctx) list_remove(&ctx->entry); pthread_mutex_unlock(&gl_object_mutex); p_eglDestroyContext(egl_display, ctx->context); + if (ctx->draw) wayland_gl_drawable_release(ctx->draw); + if (ctx->read) wayland_gl_drawable_release(ctx->read); free(ctx); return TRUE; } @@ -369,6 +458,31 @@ static PROC wayland_wglGetProcAddress(LPCSTR name) return ret; }
+static BOOL wayland_wglMakeContextCurrentARB(HDC draw_hdc, HDC read_hdc, + struct wgl_context *ctx) +{ + BOOL ret; + + TRACE("draw_hdc=%p read_hdc=%p ctx=%p\n", draw_hdc, read_hdc, ctx); + + if (!ctx) + { + p_eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + NtCurrentTeb()->glContext = NULL; + return TRUE; + } + + ret = wgl_context_make_current(ctx, NtUserWindowFromDC(draw_hdc), NtUserWindowFromDC(read_hdc)); + if (!ret) RtlSetLastWin32Error(ERROR_INVALID_HANDLE); + + return ret; +} + +static BOOL wayland_wglMakeCurrent(HDC hdc, struct wgl_context *ctx) +{ + return wayland_wglMakeContextCurrentARB(hdc, hdc, ctx); +} + static BOOL wayland_wglSetPixelFormat(HDC hdc, int format, const PIXELFORMATDESCRIPTOR *pfd) { @@ -416,6 +530,10 @@ static BOOL init_opengl_funcs(void) register_extension("WGL_WINE_pixel_format_passthrough"); opengl_funcs.ext.p_wglSetPixelFormatWINE = wayland_wglSetPixelFormatWINE;
+ register_extension("WGL_ARB_make_current_read"); + opengl_funcs.ext.p_wglGetCurrentReadDCARB = (void *)1; /* never called */ + opengl_funcs.ext.p_wglMakeContextCurrentARB = wayland_wglMakeContextCurrentARB; + return TRUE; }
@@ -508,6 +626,7 @@ static void init_opengl(void) LOAD_FUNCPTR(eglGetDisplay); LOAD_FUNCPTR(eglGetError); LOAD_FUNCPTR(eglInitialize); + LOAD_FUNCPTR(eglMakeCurrent); #undef LOAD_FUNCPTR
egl_display = p_eglGetDisplay((EGLNativeDisplayType)process_wayland.wl_display); @@ -557,6 +676,7 @@ static struct opengl_funcs opengl_funcs = .p_wglDeleteContext = wayland_wglDeleteContext, .p_wglDescribePixelFormat = wayland_wglDescribePixelFormat, .p_wglGetProcAddress = wayland_wglGetProcAddress, + .p_wglMakeCurrent = wayland_wglMakeCurrent, .p_wglSetPixelFormat = wayland_wglSetPixelFormat, } };
From: Alexandros Frantzis alexandros.frantzis@collabora.com
--- dlls/winewayland.drv/opengl.c | 91 ++++++++++++++++++++++++++++++++--- 1 file changed, 83 insertions(+), 8 deletions(-)
diff --git a/dlls/winewayland.drv/opengl.c b/dlls/winewayland.drv/opengl.c index d905b4bd22c..e174132a730 100644 --- a/dlls/winewayland.drv/opengl.c +++ b/dlls/winewayland.drv/opengl.c @@ -67,6 +67,7 @@ DECL_FUNCPTR(eglGetError); DECL_FUNCPTR(eglGetProcAddress); DECL_FUNCPTR(eglInitialize); DECL_FUNCPTR(eglMakeCurrent); +DECL_FUNCPTR(eglSwapBuffers); #undef DECL_FUNCPTR
static pthread_mutex_t gl_object_mutex = PTHREAD_MUTEX_INITIALIZER; @@ -89,7 +90,7 @@ struct wgl_context struct list entry; EGLConfig config; EGLContext context; - struct wayland_gl_drawable *draw, *read; + struct wayland_gl_drawable *draw, *read, *new_draw, *new_read; };
static struct wayland_gl_drawable *wayland_gl_drawable_get(HWND hwnd) @@ -208,17 +209,17 @@ static void update_context_drawables(struct wayland_gl_drawable *new,
LIST_FOR_EACH_ENTRY(ctx, &gl_contexts, struct wgl_context, entry) { - if (ctx->draw == old) + if (ctx->draw == old || ctx->new_draw == old) { - wayland_gl_drawable_array_add(release, ctx->draw); + if (ctx->new_draw) wayland_gl_drawable_array_add(release, ctx->new_draw); InterlockedIncrement(&new->ref); - ctx->draw = new; + ctx->new_draw = new; } - if (ctx->read == old) + if (ctx->read == old || ctx->new_read == old) { - wayland_gl_drawable_array_add(release, ctx->read); + if (ctx->new_read) wayland_gl_drawable_array_add(release, ctx->new_read); InterlockedIncrement(&new->ref); - ctx->read = new; + ctx->new_read = new; } } } @@ -251,12 +252,32 @@ static void wayland_update_gl_drawable(HWND hwnd, struct wayland_gl_drawable *ne wl_array_release(&release); }
+static void wayland_gl_drawable_sync_surface_state(struct wayland_gl_drawable *gl) +{ + struct wayland_surface *wayland_surface; + + if (!(wayland_surface = wayland_surface_lock_hwnd(gl->hwnd))) return; + + wayland_surface_ensure_contents(wayland_surface); + + /* Handle any processed configure request, to ensure the related + * surface state is applied by the compositor. */ + if (wayland_surface->processing.serial && + wayland_surface->processing.processed && + wayland_surface_reconfigure(wayland_surface)) + { + wl_surface_commit(wayland_surface->wl_surface); + } + + pthread_mutex_unlock(&wayland_surface->mutex); +} + static BOOL wgl_context_make_current(struct wgl_context *ctx, HWND draw_hwnd, HWND read_hwnd) { BOOL ret; struct wayland_gl_drawable *draw_gl = NULL, *read_gl = NULL; - struct wayland_gl_drawable *release[2]; + struct wayland_gl_drawable *release[4]; int i;
draw_gl = wayland_gl_drawable_get(draw_hwnd); @@ -277,14 +298,18 @@ static BOOL wgl_context_make_current(struct wgl_context *ctx, HWND draw_hwnd, { release[0] = ctx->draw; release[1] = ctx->read; + release[2] = ctx->new_draw; + release[3] = ctx->new_read; ctx->draw = draw_gl; ctx->read = read_gl; + ctx->new_draw = ctx->new_read = NULL; NtCurrentTeb()->glContext = ctx; } else { release[0] = draw_gl; release[1] = read_gl; + release[2] = release[3] = NULL; }
pthread_mutex_unlock(&gl_object_mutex); @@ -297,6 +322,35 @@ static BOOL wgl_context_make_current(struct wgl_context *ctx, HWND draw_hwnd, return ret; }
+static void wgl_context_refresh(struct wgl_context *ctx) +{ + BOOL refresh = FALSE; + struct wayland_gl_drawable *old_draw = NULL, *old_read = NULL; + + pthread_mutex_lock(&gl_object_mutex); + + if (ctx->new_draw) + { + old_draw = ctx->draw; + ctx->draw = ctx->new_draw; + ctx->new_draw = NULL; + refresh = TRUE; + } + if (ctx->new_read) + { + old_read = ctx->read; + ctx->read = ctx->new_read; + ctx->new_read = NULL; + refresh = TRUE; + } + if (refresh) p_eglMakeCurrent(egl_display, ctx->draw, ctx->read, ctx->context); + + pthread_mutex_unlock(&gl_object_mutex); + + if (old_draw) wayland_gl_drawable_release(old_draw); + if (old_read) wayland_gl_drawable_release(old_read); +} + static BOOL set_pixel_format(HDC hdc, int format, BOOL internal) { HWND hwnd = NtUserWindowFromDC(hdc); @@ -378,6 +432,8 @@ static BOOL wayland_wglDeleteContext(struct wgl_context *ctx) p_eglDestroyContext(egl_display, ctx->context); if (ctx->draw) wayland_gl_drawable_release(ctx->draw); if (ctx->read) wayland_gl_drawable_release(ctx->read); + if (ctx->new_draw) wayland_gl_drawable_release(ctx->new_draw); + if (ctx->new_read) wayland_gl_drawable_release(ctx->new_read); free(ctx); return TRUE; } @@ -494,6 +550,23 @@ static BOOL wayland_wglSetPixelFormatWINE(HDC hdc, int format) return set_pixel_format(hdc, format, TRUE); }
+static BOOL wayland_wglSwapBuffers(HDC hdc) +{ + struct wgl_context *ctx = NtCurrentTeb()->glContext; + HWND hwnd = NtUserWindowFromDC(hdc); + struct wayland_gl_drawable *gl; + + if (!(gl = wayland_gl_drawable_get(hwnd))) return FALSE; + + if (ctx) wgl_context_refresh(ctx); + wayland_gl_drawable_sync_surface_state(gl); + p_eglSwapBuffers(egl_display, gl->surface); + + wayland_gl_drawable_release(gl); + + return TRUE; +} + static void* load_symbol(void *handle, const char *symbol) { void *addr; @@ -627,6 +700,7 @@ static void init_opengl(void) LOAD_FUNCPTR(eglGetError); LOAD_FUNCPTR(eglInitialize); LOAD_FUNCPTR(eglMakeCurrent); + LOAD_FUNCPTR(eglSwapBuffers); #undef LOAD_FUNCPTR
egl_display = p_eglGetDisplay((EGLNativeDisplayType)process_wayland.wl_display); @@ -678,6 +752,7 @@ static struct opengl_funcs opengl_funcs = .p_wglGetProcAddress = wayland_wglGetProcAddress, .p_wglMakeCurrent = wayland_wglMakeCurrent, .p_wglSetPixelFormat = wayland_wglSetPixelFormat, + .p_wglSwapBuffers = wayland_wglSwapBuffers, } };
From: Alexandros Frantzis alexandros.frantzis@collabora.com
Wayland surfaces don't have an inherent native size that the EGL implementation can track, so we need to explicitly tell EGL about changes in the native size with wl_egl_window_resize.
Since the resize can be triggered outside the GL render thread, and wl_egl_window_resize is not thread safe (with respect to other EGL/GL calls), we cannot call it directly at will. Instead we mark the wayland_gl_drawable as resized, and actually call the wl_egl_window_resize function from the thread in which the respective drawable is current.
Note that the first EGL/GL operation that requires a new backbuffer latches whatever native size we have reported, until the next eglSwapBuffers. In order to ensure the current native size is applied as soon as possible (to avoid glitches), we check for and apply resizes at a few extra points where a new backbuffer may be required (e.g., glClear, eglMakeCurrent). --- dlls/winewayland.drv/opengl.c | 56 ++++++++++++++++++++++++++ dlls/winewayland.drv/wayland_surface.c | 2 + dlls/winewayland.drv/waylanddrv.h | 1 + 3 files changed, 59 insertions(+)
diff --git a/dlls/winewayland.drv/opengl.c b/dlls/winewayland.drv/opengl.c index e174132a730..7533c056ecc 100644 --- a/dlls/winewayland.drv/opengl.c +++ b/dlls/winewayland.drv/opengl.c @@ -68,6 +68,7 @@ DECL_FUNCPTR(eglGetProcAddress); DECL_FUNCPTR(eglInitialize); DECL_FUNCPTR(eglMakeCurrent); DECL_FUNCPTR(eglSwapBuffers); +DECL_FUNCPTR(glClear); #undef DECL_FUNCPTR
static pthread_mutex_t gl_object_mutex = PTHREAD_MUTEX_INITIALIZER; @@ -83,6 +84,7 @@ struct wayland_gl_drawable struct wayland_client_surface *client; struct wl_egl_window *wl_egl_window; EGLSurface surface; + LONG resized; };
struct wgl_context @@ -252,6 +254,28 @@ static void wayland_update_gl_drawable(HWND hwnd, struct wayland_gl_drawable *ne wl_array_release(&release); }
+static void wayland_gl_drawable_sync_size(struct wayland_gl_drawable *gl) +{ + int client_width, client_height; + struct wayland_surface *wayland_surface; + + if (InterlockedCompareExchange(&gl->resized, FALSE, TRUE)) + { + if (!(wayland_surface = wayland_surface_lock_hwnd(gl->hwnd))) return; + + client_width = wayland_surface->window.client_rect.right - + wayland_surface->window.client_rect.left; + client_height = wayland_surface->window.client_rect.bottom - + wayland_surface->window.client_rect.top; + if (client_width == 0 || client_height == 0) + client_width = client_height = 1; + + wl_egl_window_resize(gl->wl_egl_window, client_width, client_height, 0, 0); + + pthread_mutex_unlock(&wayland_surface->mutex); + } +} + static void wayland_gl_drawable_sync_surface_state(struct wayland_gl_drawable *gl) { struct wayland_surface *wayland_surface; @@ -288,6 +312,10 @@ static BOOL wgl_context_make_current(struct wgl_context *ctx, HWND draw_hwnd, draw_gl ? draw_gl->surface : NULL, read_gl ? read_gl->surface : NULL);
+ /* Since making an EGL surface current may latch the native size, + * perform any pending resizes before calling it. */ + if (draw_gl) wayland_gl_drawable_sync_size(draw_gl); + pthread_mutex_lock(&gl_object_mutex);
ret = p_eglMakeCurrent(egl_display, @@ -410,6 +438,15 @@ out: return ctx; }
+void wayland_glClear(GLbitfield mask) +{ + struct wgl_context *ctx = NtCurrentTeb()->glContext; + /* Since glClear is one of the operations that may latch the native size, + * perform any pending resizes before calling it. */ + if (ctx && ctx->draw) wayland_gl_drawable_sync_size(ctx->draw); + p_glClear(mask); +} + static BOOL wayland_wglCopyContext(struct wgl_context *src, struct wgl_context *dst, UINT mask) { @@ -561,6 +598,7 @@ static BOOL wayland_wglSwapBuffers(HDC hdc) if (ctx) wgl_context_refresh(ctx); wayland_gl_drawable_sync_surface_state(gl); p_eglSwapBuffers(egl_display, gl->surface); + wayland_gl_drawable_sync_size(gl);
wayland_gl_drawable_release(gl);
@@ -594,6 +632,9 @@ static BOOL init_opengl_funcs(void) } }
+ p_glClear = opengl_funcs.gl.p_glClear; + opengl_funcs.gl.p_glClear = wayland_glClear; + register_extension("WGL_ARB_extensions_string"); opengl_funcs.ext.p_wglGetExtensionsStringARB = wayland_wglGetExtensionsStringARB;
@@ -779,6 +820,17 @@ void wayland_destroy_gl_drawable(HWND hwnd) wayland_update_gl_drawable(hwnd, NULL); }
+void wayland_resize_gl_drawable(HWND hwnd) +{ + struct wayland_gl_drawable *gl; + + if (!(gl = wayland_gl_drawable_get(hwnd))) return; + /* wl_egl_window_resize is not thread safe, so we just mark the + * drawable as resized and perform the resize in the proper thread. */ + InterlockedExchange(&gl->resized, TRUE); + wayland_gl_drawable_release(gl); +} + #else /* No GL */
struct opengl_funcs *WAYLAND_wine_get_wgl_driver(UINT version) @@ -790,4 +842,8 @@ void wayland_destroy_gl_drawable(HWND hwnd) { }
+void wayland_resize_gl_drawable(HWND hwnd) +{ +} + #endif diff --git a/dlls/winewayland.drv/wayland_surface.c b/dlls/winewayland.drv/wayland_surface.c index a955f3688c5..e212e74362a 100644 --- a/dlls/winewayland.drv/wayland_surface.c +++ b/dlls/winewayland.drv/wayland_surface.c @@ -519,6 +519,8 @@ static void wayland_surface_reconfigure_client(struct wayland_surface *surface) }
wl_surface_commit(surface->client->wl_surface); + + wayland_resize_gl_drawable(surface->hwnd); }
/********************************************************************** diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h index 7da33dc9f18..7cf813a1ca3 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -297,6 +297,7 @@ void wayland_pointer_clear_constraint(void); */
void wayland_destroy_gl_drawable(HWND hwnd); +void wayland_resize_gl_drawable(HWND hwnd);
/********************************************************************** * Helpers
Rémi Bernon (@rbernon) commented about configure.ac:
WINE_PACKAGE_FLAGS(XKBREGISTRY,[xkbregistry],,,, [AC_CHECK_HEADERS([xkbcommon/xkbregistry.h]) AC_CHECK_LIB(xkbregistry,rxkb_context_new,[:],[XKBREGISTRY_LIBS=""],[$XKBREGISTRY_LIBS])])
- if test "x$with_opengl" != "xno"
- then
WINE_PACKAGE_FLAGS(EGL,[egl],[-lEGL],,,
[AC_CHECK_HEADER([EGL/egl.h],
We already check for that header globally.
Rémi Bernon (@rbernon) commented about configure.ac:
WINE_PACKAGE_FLAGS(XKBREGISTRY,[xkbregistry],,,, [AC_CHECK_HEADERS([xkbcommon/xkbregistry.h]) AC_CHECK_LIB(xkbregistry,rxkb_context_new,[:],[XKBREGISTRY_LIBS=""],[$XKBREGISTRY_LIBS])])
- if test "x$with_opengl" != "xno"
- then
WINE_PACKAGE_FLAGS(EGL,[egl],[-lEGL],,,
[AC_CHECK_HEADER([EGL/egl.h],
[WINE_CHECK_SONAME(EGL,eglGetProcAddress,,,[$EGL_LIBS])])])
if test "x$with_wayland" != "x"
Do we need this if?
Rémi Bernon (@rbernon) commented about configure.ac:
WINE_PACKAGE_FLAGS(XKBREGISTRY,[xkbregistry],,,, [AC_CHECK_HEADERS([xkbcommon/xkbregistry.h]) AC_CHECK_LIB(xkbregistry,rxkb_context_new,[:],[XKBREGISTRY_LIBS=""],[$XKBREGISTRY_LIBS])])
- if test "x$with_opengl" != "xno"
- then
WINE_PACKAGE_FLAGS(EGL,[egl],[-lEGL],,,
[AC_CHECK_HEADER([EGL/egl.h],
[WINE_CHECK_SONAME(EGL,eglGetProcAddress,,,[$EGL_LIBS])])])
if test "x$with_wayland" != "x"
then
WINE_NOTICE_WITH(opengl, [test -z "$SONAME_LIBEGL"],
[Wayland EGL/GL ${notice_platform}development files not found, the Wayland driver won't support OpenGL])
Do we need this to be Wayland specific? At least something like that seems more appropriate:
```suggestion:-4+0 [EGL ${notice_platform}development files not found, the Wayland driver won't support OpenGL]) ```
Rémi Bernon (@rbernon) commented about configure.ac:
WINE_PACKAGE_FLAGS(XKBREGISTRY,[xkbregistry],,,, [AC_CHECK_HEADERS([xkbcommon/xkbregistry.h]) AC_CHECK_LIB(xkbregistry,rxkb_context_new,[:],[XKBREGISTRY_LIBS=""],[$XKBREGISTRY_LIBS])])
- if test "x$with_opengl" != "xno"
- then
WINE_PACKAGE_FLAGS(EGL,[egl],[-lEGL],,,
[AC_CHECK_HEADER([EGL/egl.h],
[WINE_CHECK_SONAME(EGL,eglGetProcAddress,,,[$EGL_LIBS])])])
if test "x$with_wayland" != "x"
then
WINE_NOTICE_WITH(opengl, [test -z "$SONAME_LIBEGL"],
```suggestion:-0+0 WINE_NOTICE_WITH(opengl, [test "x$ac_cv_lib_soname_EGL" = "x"], ```
Looks like it's done like that more consistently elsewhere.
Rémi Bernon (@rbernon) commented about configure.ac:
WINE_PACKAGE_FLAGS(XKBREGISTRY,[xkbregistry],,,, [AC_CHECK_HEADERS([xkbcommon/xkbregistry.h]) AC_CHECK_LIB(xkbregistry,rxkb_context_new,[:],[XKBREGISTRY_LIBS=""],[$XKBREGISTRY_LIBS])])
- if test "x$with_opengl" != "xno"
- then
WINE_PACKAGE_FLAGS(EGL,[egl],[-lEGL],,,
I'm not sure if we need to support the case where the library is installed in an unusual place.
When using pkg-config, I expect that the module should then use EGL_CFLAGS, to be able to include that header if the flags contain additional include paths, and it's not the case here.
The same actually goes for the EGL_SONAME, if pkg-config somehow locates the library in an unusual place, whether it then would still work at runtime is unclear.
Rémi Bernon (@rbernon) commented about dlls/winewayland.drv/opengl.c:
+DECL_FUNCPTR(eglInitialize); +#undef DECL_FUNCPTR
+static void* load_symbol(void *handle, const char *symbol) +{
- void *addr;
- if (!(addr = dlsym(handle, symbol))) addr = p_eglGetProcAddress(symbol);
- return addr;
+}
+static void init_opengl(void) +{
- if (!(egl_handle = dlopen(SONAME_LIBEGL, RTLD_NOW|RTLD_GLOBAL)))
- {
ERR("Failed to load %s: %s\n", SONAME_LIBEGL, dlerror());
goto err;
You can just return here, would save an if in the error path.
Rémi Bernon (@rbernon) commented about dlls/winewayland.drv/opengl.c:
- {
ERR("Failed to load eglGetProcAddress\n");
goto err;
- }
+#define LOAD_FUNCPTR(func) \
- do { \
if (!(p_##func = load_symbol(egl_handle, #func))) \
{ ERR("Failed to load symbol %s\n", #func); goto err; } \
- } while(0)
- LOAD_FUNCPTR(eglGetDisplay);
- LOAD_FUNCPTR(eglGetError);
- LOAD_FUNCPTR(eglInitialize);
+#undef LOAD_FUNCPTR
- egl_display = p_eglGetDisplay((EGLNativeDisplayType)process_wayland.wl_display);
What if EGL doesn't expect Wayland as its default platform? What about using EGL_DEFAULT_DISPLAY instead or eglGetPlatformDisplay?
Rémi Bernon (@rbernon) commented about dlls/winewayland.drv/opengl.c:
+static EGLDisplay egl_display; +static EGLint egl_version[2];
+#define DECL_FUNCPTR(f) static __typeof__(f) * p_##f = NULL +DECL_FUNCPTR(eglGetDisplay); +DECL_FUNCPTR(eglGetError); +DECL_FUNCPTR(eglGetProcAddress); +DECL_FUNCPTR(eglInitialize); +#undef DECL_FUNCPTR
+static void* load_symbol(void *handle, const char *symbol) +{
- void *addr;
- if (!(addr = dlsym(handle, symbol))) addr = p_eglGetProcAddress(symbol);
- return addr;
+}
I think you should instead check and require the `EGL_KHR_client_get_all_proc_addresses` extension (though I don't know for sure how widely available it is, I think for now we can assume it is).
This will let you use `eglGetProcAddress` for everything, including for GL core functions, and will save you the trouble of having to check and load libGL separately.
Rémi Bernon (@rbernon) commented about dlls/winewayland.drv/opengl.c:
/* It's fine to destroy the wayland surface, the client surface
* can safely outlive it. */
wayland_surface_destroy(wayland_surface);
- }
- if (!gl->client) goto err;
- gl->wl_egl_window = wl_egl_window_create(gl->client->wl_surface,
client_width, client_height);
- if (!gl->wl_egl_window)
- {
ERR("Failed to create wl_egl_window\n");
goto err;
- }
- gl->surface = p_eglCreateWindowSurface(egl_display, egl_configs[format - 1],
(EGLNativeWindowType)gl->wl_egl_window, NULL);
Do we even need to care about the actual surface pixel format? Same question for the contexts, can we leverage `EGL_KHR_no_config_context` to make things simpler?
This is an open question, I have no good understanding of what it actually implies but reading that extension description (and as far as I could see it seems to be available for Mesa and NVidia drivers), it looks like it could reduce the dependency on the host?
Rémi Bernon (@rbernon) commented about dlls/winewayland.drv/opengl.c:
return wgl_extensions;
}
+static PROC wayland_wglGetProcAddress(LPCSTR name) +{
- PROC ret;
- if (!strncmp(name, "wgl", 3)) return NULL;
- ret = (PROC)p_eglGetProcAddress(name);
- TRACE("%s -> %p\n", name, ret);
- return ret;
Do we really need to trace these?
I only had a look at the first part of the series.
On Wed Feb 28 08:37:49 2024 +0000, Rémi Bernon wrote:
What if EGL doesn't expect Wayland as its default platform? What about using EGL_DEFAULT_DISPLAY instead or eglGetPlatformDisplay?
(The latter is probably better, though you'll have to check and require a few extensions)
On Wed Feb 28 08:37:45 2024 +0000, Rémi Bernon wrote:
Do we need this if?
The purpose of this check is to only fail the build when EGL is missing and both `--with-wayland` and `--with-opengl` are specified. Without this check the build would also fail (due to the following `WINE_NOTICE_WITH`) when EGL is missing and the configure is just `--with-opengl`.
In other words I didn't want non-explicit Wayland builds to suddenly require EGL.
On Wed Feb 28 08:37:46 2024 +0000, Rémi Bernon wrote:
Do we need this to be Wayland specific? At least something like that seems more appropriate:
[EGL ${notice_platform}development files not found, the Wayland driver won't support OpenGL])
What you propose is fine for the early commits. However, we eventually end up testing for more than EGL (`test -z "$SONAME_LIBEGL" -o -z "$SONAME_LIBOPENGL" -o -z "$HAVE_LIBWAYLAND_EGL"`) so a more specific message seems more descriptive. Would you be prefer I evolve the message along with the requirements? Or do you think the generic message is good enough anyway?
If we use `EGL_KHR_client_get_all_proc_addresses` (i.e, depend directly only on EGL and wayland-egl, not OpenGL) the EGL only notice is probably good enough.
On Wed Feb 28 08:37:46 2024 +0000, Rémi Bernon wrote:
WINE_NOTICE_WITH(opengl, [test "x$ac_cv_lib_soname_EGL" = "x"],
Looks like it's done like that more consistently elsewhere.
Ack.
When using pkg-config, I expect that the module should then use EGL_CFLAGS, to be able to include that header if the flags contain additional include paths, and it's not the case here.
This is indeed an oversight, EGL_CFLAGS should be added to UNIX_CFLAGS in the Wayland driver.
The same actually goes for the EGL_SONAME, if pkg-config somehow locates the library in an unusual place, whether it then would still work at runtime is unclear.
I guess the assumption here is that in case of such setups, the dynamic linking runtime environment would also include the proper paths, but of course it's not guaranteed.
The fact that we are dlopen-ing (E)GL instead of doing a normal dynamic link (same as WineX11) is an indication that we also want to gracefully support scenarios in which the GL libraries are missing at runtime (?). I guess an improperly configured dynamic linking runtime above would be another case of this.
All that being said, I think the main benefit of utilizing the pkgconfig mechanism even in this case is to allow for more versatile build setups.
On Wed Feb 28 13:01:18 2024 +0000, Rémi Bernon wrote:
(The latter is probably better, though you'll have to check and require a few extensions)
Mesa's EGL at least, has good autodetection mechanisms based on the provided native_display, but indeed being more explicit with eglGetPlatformDisplay is the better choice if available. I will add support for it, using eglGetDisplay as a fallback.
EGL_DEFAULT_DISPLAY doesn't help here, because even if Wayland is the default EGL platform, EGL will create a new connection/wl_display to the compositor which cannot use objects created from our normal Wine wl_display (notably it won't be able to use the wl_surface we want to make a target for rendering).
On Wed Feb 28 08:37:49 2024 +0000, Rémi Bernon wrote:
I think you should instead check and require the `EGL_KHR_client_get_all_proc_addresses` extension (though I don't know for sure how widely available it is, I think for now we can assume it is). This will let you use `eglGetProcAddress` for everything, including for GL core functions, and will save you the trouble of having to check and load libGL separately.
This should be fine (and very nice) to use with Mesa, but I can't find much direct information about NVIDIA and AMD proprietary support, and that's what's been holding me back a bit. Searching again I was able to find a few references to this extension in various relatively old online reports for the proprietary drivers, so I guess let's go with it and hope for the best :)
Do we even need to care about the actual surface pixel format?
We need to provide an EGLConfig when creating a surface, otherwise EGL wouldn't know which format to use when creating the underlying surface buffers.
Same question for the contexts, can we leverage EGL_KHR_no_config_context to make things simpler?
Yes, this is possible. Again, I am not able to find any direct information about the NVIDIA or AMD proprietary extensions, but I am seeing references to it for such drivers starting around 2019, so I guess we can give it a go and see if it breaks any setups.
On Wed Feb 28 08:37:53 2024 +0000, Rémi Bernon wrote:
Do we really need to trace these?
No, I will remove the traces.
On Wed Feb 28 08:37:45 2024 +0000, Rémi Bernon wrote:
We already check for that header globally.
The difference is that this check is done with `CPPFLAGS` (temporarily) set from the `WINE_PACKAGE_FLAGS` macro. I guess this ties to the discussion in another comment about whether we should care about unusual installations.
On Wed Feb 28 13:24:34 2024 +0000, Alexandros Frantzis wrote:
The purpose of this check is to only fail the build when EGL is missing and both `--with-wayland` and `--with-opengl` are specified. Without this check the build would also fail (due to the following `WINE_NOTICE_WITH`) when EGL is missing and the configure is just `--with-opengl`. In other words I didn't want non-explicit Wayland builds to suddenly require EGL.
I don't think `WINE_NOTICE_WITH` causes a failure, only a message?
I saw after with the later commits why it was done like that, my comments were mostly based on the idea that it would be interesting to use EGL in some win32u common code at some point [^1]. It doesn't matter much anyway.
[^1] On that topic, I'm not much thrilled with the idea of having yet another driver-specific GL implementation, but doing it in win32u will require more experimentation and it's maybe a bit early for that, and I don't want to block this MR just because of that.
This is indeed an oversight, EGL_CFLAGS should be added to UNIX_CFLAGS in the Wayland driver.
Yes.
I guess the assumption here is that in case of such setups, the dynamic linking runtime environment would also include the proper paths, but of course it's not guaranteed.
You can probably ignore this part of my comment. I had in mind that SONAME might include the full path of the libraries, but it does not, so wherever pkg-config ends up locating the libraries it will end up with the same SONAME (which still needs to later be loadable without a path, but that's probably expected).
On Wed Feb 28 13:24:37 2024 +0000, Alexandros Frantzis wrote:
Mesa's EGL at least, has good autodetection mechanisms based on the provided native_display, but indeed being more explicit with eglGetPlatformDisplay is the better choice if available. I will add support for it, using eglGetDisplay as a fallback. EGL_DEFAULT_DISPLAY doesn't help here, because even if Wayland is the default EGL platform, EGL will create a new connection/wl_display to the compositor which cannot use objects created from our normal Wine wl_display (notably it won't be able to use the wl_surface we want to make a target for rendering).
IMO requiring the EGL_EXT_platform_base (and EXT_platform_wayland) extension would be nice, making the code simpler and later making it easier to move it around if we consider having it in win32u, or extending it for instance for offscreen rendering with the device platforms.
There again I don't know how widespread the extensions are but it's been 10 years now, and we can consider adding fallbacks later only when needed.
We need to provide an EGLConfig when creating a surface, otherwise EGL wouldn't know which format to use when creating the underlying surface buffers.
Yes, but if it doesn't actually make any difference and if a surface with an arbitrary config and a config-less context can be used for any Win32 pixel format, then maybe we could use a generic config (say the most feature-ful one) and save the complexity of surface recreation and pixel format changes?
On Wed Feb 28 14:04:24 2024 +0000, Rémi Bernon wrote:
We need to provide an EGLConfig when creating a surface, otherwise EGL
wouldn't know which format to use when creating the underlying surface buffers. Yes, but if it doesn't actually make any difference and if a surface with an arbitrary config and a config-less context can be used for any Win32 pixel format, then maybe we could use a generic config (say the most feature-ful one) and save the complexity of surface recreation and pixel format changes?
This is a candid question, which after looking a bit more into Proton fshack I will answer myself. The surface config will change the framebuffer format, which probably needs to match what the applications will expect.
We could perhaps decouple that from the actual surface format, but that would require creating a FBO ourselves, the same way fshack is doing, rendering to a texture which format would match the selected config, and then rendering that texture again to the actual generic surface.
In the future I think it could be a way to get rid of the set_pixel_format shenanigans.
Cross-process rendering that read to me as use DMABUF like wayland compositors and applications outside Wayland can. https://blaztinn.gitlab.io/post/dmabuf-texture-sharing/
This would also be following windows 10/11 Hardware Accelerated GPU Scheduling kind of path.
"(i.e., the surface should be available for additional rendering with GDI)." This is something where you do run into trouble when you are using windows 10/11 Hardware accelerated GPU Scheduling as well.
Normally it you don't modify another applications gpu buffer unless you want to risk strange thing happening. Cost of having GPU insert buffer into your own buffer is not high.