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