From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/ntuser_private.h | 1 + dlls/win32u/opengl.c | 52 +++++++++++++++++++++++++++++++---- dlls/win32u/window.c | 3 ++ dlls/wineandroid.drv/opengl.c | 32 +++++++++++++-------- dlls/winemac.drv/opengl.c | 23 +++++++++++++--- dlls/winewayland.drv/opengl.c | 16 +++++------ dlls/winex11.drv/opengl.c | 32 ++++++--------------- include/wine/opengl_driver.h | 2 +- 8 files changed, 107 insertions(+), 54 deletions(-)
diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index 33b5cdc3b27..a3714cd8994 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -67,6 +67,7 @@ typedef struct tagWND HIMC imc; /* window's input context */ struct window_surface *surface; /* Window surface if any */ struct list vulkan_surfaces; /* list of vulkan surfaces created for this window */ + struct opengl_drawable *opengl_drawable; /* last GL client surface for this window */ struct tagDIALOGINFO *dlgInfo; /* Dialog additional info (dialogs only) */ int swap_interval; /* OpenGL surface swap interval */ int pixel_format; /* Pixel format set by the graphics driver */ diff --git a/dlls/win32u/opengl.c b/dlls/win32u/opengl.c index c165f9588c7..7450fb91ada 100644 --- a/dlls/win32u/opengl.c +++ b/dlls/win32u/opengl.c @@ -398,7 +398,7 @@ static const char *egldrv_init_wgl_extensions( struct opengl_funcs *funcs ) return ""; }
-static BOOL egldrv_set_pixel_format( HWND hwnd, int old_format, int new_format, BOOL internal ) +static BOOL egldrv_surface_create( HWND hwnd, HDC hdc, int format, struct opengl_drawable **drawable ) { FIXME( "stub!\n" ); return TRUE; @@ -459,7 +459,7 @@ static const struct opengl_driver_funcs egldrv_funcs = .p_init_pixel_formats = egldrv_init_pixel_formats, .p_describe_pixel_format = egldrv_describe_pixel_format, .p_init_wgl_extensions = egldrv_init_wgl_extensions, - .p_set_pixel_format = egldrv_set_pixel_format, + .p_surface_create = egldrv_surface_create, .p_swap_buffers = egldrv_swap_buffers, .p_pbuffer_create = egldrv_pbuffer_create, .p_pbuffer_updated = egldrv_pbuffer_updated, @@ -607,7 +607,7 @@ static const char *nulldrv_init_wgl_extensions( struct opengl_funcs *funcs ) return ""; }
-static BOOL nulldrv_set_pixel_format( HWND hwnd, int old_format, int new_format, BOOL internal ) +static BOOL nulldrv_surface_create( HWND hwnd, HDC hdc, int format, struct opengl_drawable **drawable ) { return TRUE; } @@ -648,7 +648,7 @@ static BOOL nulldrv_context_flush( void *private, HWND hwnd, HDC hdc, int interv return FALSE; }
-static BOOL nulldrv_context_make_current( HDC draw_hdc, HDC read_hdc, void *private ) +static BOOL nulldrv_context_make_current( HDC draw, HDC read, void *context ) { return FALSE; } @@ -659,7 +659,7 @@ static const struct opengl_driver_funcs nulldrv_funcs = .p_init_pixel_formats = nulldrv_init_pixel_formats, .p_describe_pixel_format = nulldrv_describe_pixel_format, .p_init_wgl_extensions = nulldrv_init_wgl_extensions, - .p_set_pixel_format = nulldrv_set_pixel_format, + .p_surface_create = nulldrv_surface_create, .p_swap_buffers = nulldrv_swap_buffers, .p_pbuffer_create = nulldrv_pbuffer_create, .p_pbuffer_updated = nulldrv_pbuffer_updated, @@ -723,6 +723,38 @@ static int win32u_wglGetPixelFormat( HDC hdc ) return format > 0 ? format : 0; }
+static void set_window_opengl_drawable( HWND hwnd, struct opengl_drawable *new_drawable ) +{ + void *old_drawable = NULL; + WND *win; + + TRACE( "hwnd %p, new_drawable %s\n", hwnd, debugstr_opengl_drawable( new_drawable ) ); + + if ((win = get_win_ptr( hwnd )) && win != WND_DESKTOP && win != WND_OTHER_PROCESS) + { + old_drawable = win->opengl_drawable; + if ((win->opengl_drawable = new_drawable)) opengl_drawable_add_ref( new_drawable ); + release_win_ptr( win ); + } + + if (old_drawable) opengl_drawable_release( old_drawable ); +} + +static struct opengl_drawable *get_window_opengl_drawable( HWND hwnd ) +{ + void *drawable = NULL; + WND *win; + + if ((win = get_win_ptr( hwnd )) && win != WND_DESKTOP && win != WND_OTHER_PROCESS) + { + if ((drawable = win->opengl_drawable)) opengl_drawable_add_ref( drawable ); + release_win_ptr( win ); + } + + TRACE( "hwnd %p, drawable %s\n", hwnd, debugstr_opengl_drawable( drawable ) ); + return drawable; +} + static struct wgl_pbuffer *create_memory_pbuffer( HDC hdc, int format ) { const struct opengl_funcs *funcs = &display_funcs; @@ -804,7 +836,9 @@ static BOOL set_dc_pixel_format( HDC hdc, int new_format, BOOL internal )
if ((hwnd = NtUserWindowFromDC( hdc ))) { + struct opengl_drawable *drawable; int old_format; + BOOL ret;
if (new_format > onscreen) { @@ -815,7 +849,13 @@ static BOOL set_dc_pixel_format( HDC hdc, int new_format, BOOL internal ) TRACE( "%p/%p format %d, internal %u\n", hdc, hwnd, new_format, internal );
if ((old_format = get_window_pixel_format( hwnd, FALSE )) && !internal) return old_format == new_format; - if (!driver_funcs->p_set_pixel_format( hwnd, old_format, new_format, internal )) return FALSE; + + drawable = get_window_opengl_drawable( hwnd ); + if ((ret = driver_funcs->p_surface_create( hwnd, hdc, new_format, &drawable ))) + set_window_opengl_drawable( hwnd, drawable ); + if (drawable) opengl_drawable_release( drawable ); + + if (!ret) return FALSE; return set_window_pixel_format( hwnd, new_format, internal ); }
diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index 08db9cab0bd..352dc938b66 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -29,6 +29,7 @@ #define WIN32_NO_STATUS #include "ntgdi_private.h" #include "ntuser_private.h" +#include "wine/opengl_driver.h" #include "wine/server.h" #include "wine/debug.h"
@@ -5054,6 +5055,7 @@ LRESULT destroy_window( HWND hwnd ) }
vulkan_detach_surfaces( &vulkan_surfaces ); + if (win->opengl_drawable) opengl_drawable_release( win->opengl_drawable ); user_driver->pDestroyWindow( hwnd );
free_window_handle( hwnd ); @@ -5208,6 +5210,7 @@ void destroy_thread_windows(void) TRACE( "destroying %p\n", entry );
user_driver->pDestroyWindow( entry->handle ); + if (win->opengl_drawable) opengl_drawable_release( win->opengl_drawable );
NtUserDestroyMenu( entry->menu ); NtUserDestroyMenu( entry->sys_menu ); diff --git a/dlls/wineandroid.drv/opengl.c b/dlls/wineandroid.drv/opengl.c index 593b5e448aa..c570d82e2e4 100644 --- a/dlls/wineandroid.drv/opengl.c +++ b/dlls/wineandroid.drv/opengl.c @@ -199,23 +199,31 @@ void update_gl_drawable( HWND hwnd ) } }
-static BOOL android_set_pixel_format( HWND hwnd, int old_format, int new_format, BOOL internal ) +static BOOL android_surface_create( HWND hwnd, HDC hdc, int format, struct opengl_drawable **drawable ) { struct gl_drawable *gl;
- TRACE( "hwnd %p, old_format %d, new_format %d, internal %u\n", hwnd, old_format, new_format, internal ); + TRACE( "hwnd %p, hdc %p, format %d, drawable %p\n", hwnd, hdc, format, drawable );
- if ((gl = get_gl_drawable( hwnd, 0 ))) + if (*drawable) { - if (internal) - { - EGLint pf; - funcs->p_eglGetConfigAttrib( egl->display, egl_config_for_format(new_format), EGL_NATIVE_VISUAL_ID, &pf ); - gl->window->perform( gl->window, NATIVE_WINDOW_SET_BUFFERS_FORMAT, pf ); - gl->base.format = new_format; - } + EGLint pf; + + FIXME( "Updating drawable %s, multiple surfaces not implemented\n", debugstr_opengl_drawable( *drawable ) ); + + gl = impl_from_opengl_drawable( *drawable ); + funcs->p_eglGetConfigAttrib( egl->display, egl_config_for_format(format), EGL_NATIVE_VISUAL_ID, &pf ); + gl->window->perform( gl->window, NATIVE_WINDOW_SET_BUFFERS_FORMAT, pf ); + gl->base.hwnd = hwnd; + gl->base.hdc = hdc; + gl->base.format = format; + + TRACE( "Updated drawable %s\n", debugstr_opengl_drawable( *drawable ) ); + return TRUE; } - else if (!(gl = create_gl_drawable( hwnd, 0, new_format ))) return FALSE; + + if (!(gl = create_gl_drawable( hwnd, hdc, format ))) return FALSE; + opengl_drawable_add_ref( (*drawable = &gl->base) ); release_gl_drawable( gl );
return TRUE; @@ -397,7 +405,7 @@ static struct opengl_driver_funcs android_driver_funcs = .p_init_egl_platform = android_init_egl_platform, .p_get_proc_address = android_get_proc_address, .p_init_wgl_extensions = android_init_wgl_extensions, - .p_set_pixel_format = android_set_pixel_format, + .p_surface_create = android_surface_create, .p_swap_buffers = android_swap_buffers, .p_context_create = android_context_create, .p_context_destroy = android_context_destroy, diff --git a/dlls/winemac.drv/opengl.c b/dlls/winemac.drv/opengl.c index bddd6f531f4..11f90ff8ac1 100644 --- a/dlls/winemac.drv/opengl.c +++ b/dlls/winemac.drv/opengl.c @@ -100,6 +100,7 @@ static pthread_mutex_t dc_pbuffers_mutex = PTHREAD_MUTEX_INITIALIZER; static void *opengl_handle; static const struct opengl_funcs *funcs; static const struct opengl_driver_funcs macdrv_driver_funcs; +static const struct opengl_drawable_funcs macdrv_surface_funcs; static const struct opengl_drawable_funcs macdrv_pbuffer_funcs;
static void (*pglCopyColorTable)(GLenum target, GLenum internalformat, GLint x, GLint y, @@ -1473,11 +1474,12 @@ static BOOL create_context(struct macdrv_context *context, CGLContextObj share, return TRUE; }
-static BOOL macdrv_set_pixel_format(HWND hwnd, int old_format, int new_format, BOOL internal) +static BOOL macdrv_surface_create(HWND hwnd, HDC hdc, int format, struct opengl_drawable **drawable) { struct macdrv_win_data *data; + struct gl_drawable *gl;
- TRACE("hwnd %p, old_format %d, new_format %d, internal %u\n", hwnd, old_format, new_format, internal); + TRACE("hwnd %p, hdc %p, format %d, drawable %p\n", hwnd, hdc, format, drawable);
if (!(data = get_win_data(hwnd))) { @@ -1485,11 +1487,19 @@ static BOOL macdrv_set_pixel_format(HWND hwnd, int old_format, int new_format, B return FALSE; }
- data->pixel_format = new_format; + data->pixel_format = format; release_win_data(data); + + if (!(gl = opengl_drawable_create(sizeof(*gl), &macdrv_surface_funcs, format, hwnd, hdc))) return FALSE; + *drawable = &gl->base; + return TRUE; }
+static void macdrv_surface_destroy(struct opengl_drawable *base) +{ + TRACE("drawable %s\n", debugstr_opengl_drawable(base)); +}
/********************************************************************** * mark_contexts_for_moved_view @@ -3050,7 +3060,7 @@ static const struct opengl_driver_funcs macdrv_driver_funcs = .p_init_pixel_formats = macdrv_init_pixel_formats, .p_describe_pixel_format = macdrv_describe_pixel_format, .p_init_wgl_extensions = macdrv_init_wgl_extensions, - .p_set_pixel_format = macdrv_set_pixel_format, + .p_surface_create = macdrv_surface_create, .p_swap_buffers = macdrv_swap_buffers, .p_context_create = macdrv_context_create, .p_context_destroy = macdrv_context_destroy, @@ -3061,6 +3071,11 @@ static const struct opengl_driver_funcs macdrv_driver_funcs = .p_pbuffer_bind = macdrv_pbuffer_bind, };
+static const struct opengl_drawable_funcs macdrv_surface_funcs = +{ + .destroy = macdrv_surface_destroy, +}; + static const struct opengl_drawable_funcs macdrv_pbuffer_funcs = { .destroy = macdrv_pbuffer_destroy, diff --git a/dlls/winewayland.drv/opengl.c b/dlls/winewayland.drv/opengl.c index 0b7595c3dcf..2bfd41a6358 100644 --- a/dlls/winewayland.drv/opengl.c +++ b/dlls/winewayland.drv/opengl.c @@ -337,23 +337,23 @@ static void wayland_context_refresh(struct wayland_context *ctx) if (old_read) opengl_drawable_release(&old_read->base); }
-static BOOL wayland_set_pixel_format(HWND hwnd, int old_format, int new_format, BOOL internal) +static BOOL wayland_opengl_surface_create(HWND hwnd, HDC hdc, int format, struct opengl_drawable **drawable) { + struct opengl_drawable *previous; struct wayland_gl_drawable *gl; RECT rect;
- /* 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 (old_format) return old_format == new_format; + if ((previous = *drawable) && previous->format == format) return TRUE;
NtUserGetClientRect(hwnd, &rect, NtUserGetDpiForWindow(hwnd)); if (rect.right == rect.left) rect.right = rect.left + 1; if (rect.bottom == rect.top) rect.bottom = rect.top + 1;
- if (!(gl = wayland_gl_drawable_create(hwnd, 0, new_format, rect.right - rect.left, rect.bottom - rect.top))) return FALSE; + if (!(gl = wayland_gl_drawable_create(hwnd, 0, format, rect.right - rect.left, rect.bottom - rect.top))) return FALSE; wayland_update_gl_drawable(hwnd, gl); + + if (previous) opengl_drawable_release( previous ); + opengl_drawable_add_ref( (*drawable = &gl->base) ); return TRUE; }
@@ -538,7 +538,7 @@ static UINT wayland_pbuffer_bind(HDC hdc, struct opengl_drawable *base, GLenum b static struct opengl_driver_funcs wayland_driver_funcs = { .p_init_egl_platform = wayland_init_egl_platform, - .p_set_pixel_format = wayland_set_pixel_format, + .p_surface_create = wayland_opengl_surface_create, .p_swap_buffers = wayland_swap_buffers, .p_context_create = wayland_context_create, .p_context_destroy = wayland_context_destroy, diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index ad82c8d8f7a..96b9d62321e 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -908,18 +908,17 @@ static GLXContext create_glxcontext( struct x11drv_context *context, int format, return ctx; }
-/*********************************************************************** - * create_gl_drawable - */ -static struct gl_drawable *create_gl_drawable( HWND hwnd, int format ) +static BOOL x11drv_surface_create( HWND hwnd, HDC hdc, int format, struct opengl_drawable **drawable ) { struct glx_pixel_format *fmt = glx_pixel_format_from_format( format ); + struct opengl_drawable *previous; struct gl_drawable *gl, *prev; RECT rect;
+ if ((previous = *drawable) && previous->format == format) return TRUE; NtUserGetClientRect( hwnd, &rect, NtUserGetDpiForWindow( hwnd ) );
- if (!(gl = opengl_drawable_create( sizeof(*gl), &x11drv_surface_funcs, format, hwnd, 0 ))) return NULL; + if (!(gl = opengl_drawable_create( sizeof(*gl), &x11drv_surface_funcs, format, hwnd, hdc ))) return FALSE; /* Default GLX and WGL swap interval is 1, but in case of glXSwapIntervalSGI there is no way to query it. */ gl->swap_interval = INT_MIN; gl->rect = rect; @@ -933,7 +932,7 @@ static struct gl_drawable *create_gl_drawable( HWND hwnd, int format ) if (!gl->drawable) { free( gl ); - return NULL; + return FALSE; }
TRACE( "Created drawable %s with client window %lx\n", debugstr_opengl_drawable( &gl->base ), gl->window ); @@ -941,26 +940,13 @@ static struct gl_drawable *create_gl_drawable( HWND hwnd, int format ) pthread_mutex_lock( &context_mutex ); if (!XFindContext( gdi_display, (XID)hwnd, gl_hwnd_context, (char **)&prev )) opengl_drawable_release( &prev->base ); - XSaveContext( gdi_display, (XID)hwnd, gl_hwnd_context, (char *)grab_gl_drawable(gl) ); + XSaveContext( gdi_display, (XID)hwnd, gl_hwnd_context, (char *)gl ); pthread_mutex_unlock( &context_mutex ); - return gl; -}
-static BOOL x11drv_set_pixel_format( HWND hwnd, int old_format, int new_format, BOOL internal ) -{ - struct gl_drawable *gl; - - /* 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 (old_format) return old_format == new_format; - - if (!(gl = create_gl_drawable( hwnd, new_format ))) return FALSE; - TRACE( "created GL drawable %lx for win %p\n", gl->drawable, hwnd); XFlush( gdi_display ); - opengl_drawable_release( &gl->base );
+ if (previous) opengl_drawable_release( previous ); + opengl_drawable_add_ref( (*drawable = &gl->base) ); return TRUE; }
@@ -1719,7 +1705,7 @@ static const struct opengl_driver_funcs x11drv_driver_funcs = .p_init_pixel_formats = x11drv_init_pixel_formats, .p_describe_pixel_format = x11drv_describe_pixel_format, .p_init_wgl_extensions = x11drv_init_wgl_extensions, - .p_set_pixel_format = x11drv_set_pixel_format, + .p_surface_create = x11drv_surface_create, .p_swap_buffers = x11drv_swap_buffers, .p_context_create = x11drv_context_create, .p_context_destroy = x11drv_context_destroy, diff --git a/include/wine/opengl_driver.h b/include/wine/opengl_driver.h index 15f9b26e5cf..3cf775a4317 100644 --- a/include/wine/opengl_driver.h +++ b/include/wine/opengl_driver.h @@ -161,7 +161,7 @@ struct opengl_driver_funcs UINT (*p_init_pixel_formats)(UINT*); BOOL (*p_describe_pixel_format)(int,struct wgl_pixel_format*); const char *(*p_init_wgl_extensions)(struct opengl_funcs *funcs); - BOOL (*p_set_pixel_format)(HWND,int,int,BOOL); + BOOL (*p_surface_create)( HWND hwnd, HDC hdc, int format, struct opengl_drawable **drawable ); BOOL (*p_swap_buffers)(void*,HWND,HDC,int); BOOL (*p_context_create)( int format, void *share, const int *attribs, void **context ); BOOL (*p_context_destroy)(void*);