Instead of https://gitlab.winehq.org/wine/wine/-/merge_requests/8496, leaving context sharing for later.
-- v5: win32u: Remove now unnecessary opengl_drawable hdc member. winewayland: Use a distinct wayland_pbuffer struct for pbuffers. win32u: Implement generic EGL driver pbuffer surface. win32u: Avoid releasing opengl drawable within drawables_lock. win32u: Avoid calling detach, flush or swap on pbuffer drawables. winemac: Remove now unnecessary pbuffer tracking.
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winemac.drv/opengl.c | 77 ++++++--------------------------------- 1 file changed, 11 insertions(+), 66 deletions(-)
diff --git a/dlls/winemac.drv/opengl.c b/dlls/winemac.drv/opengl.c index dd3b3e4da59..57b2ed23dd9 100644 --- a/dlls/winemac.drv/opengl.c +++ b/dlls/winemac.drv/opengl.c @@ -93,9 +93,6 @@ static struct gl_drawable *impl_from_opengl_drawable(struct opengl_drawable *bas static struct list context_list = LIST_INIT(context_list); static pthread_mutex_t context_mutex = PTHREAD_MUTEX_INITIALIZER;
-static CFMutableDictionaryRef dc_pbuffers; -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; @@ -2370,10 +2367,6 @@ static BOOL macdrv_pbuffer_create(HDC hdc, int format, BOOL largest, GLenum text return FALSE; }
- pthread_mutex_lock(&dc_pbuffers_mutex); - CFDictionarySetValue(dc_pbuffers, hdc, gl->pbuffer); - pthread_mutex_unlock(&dc_pbuffers_mutex); - *drawable = &gl->base; TRACE(" -> %p\n", gl); return TRUE; @@ -2385,10 +2378,6 @@ static void macdrv_pbuffer_destroy(struct opengl_drawable *base)
TRACE("drawable %s\n", debugstr_opengl_drawable(base));
- pthread_mutex_lock(&dc_pbuffers_mutex); - CFDictionaryRemoveValue(dc_pbuffers, gl->pbuffer); - pthread_mutex_unlock(&dc_pbuffers_mutex); - CGLReleasePBuffer(gl->pbuffer); }
@@ -2439,22 +2428,9 @@ static BOOL macdrv_make_current(struct opengl_drawable *draw_base, struct opengl } else { - CGLPBufferObj pbuffer; - - pthread_mutex_lock(&dc_pbuffers_mutex); - pbuffer = (CGLPBufferObj)CFDictionaryGetValue(dc_pbuffers, draw->base.hdc); - if (!pbuffer) - { - WARN("no window or pbuffer for DC\n"); - pthread_mutex_unlock(&dc_pbuffers_mutex); - RtlSetLastWin32Error(ERROR_INVALID_HANDLE); - return FALSE; - } - context->draw_hwnd = NULL; context->draw_view = NULL; - context->draw_pbuffer = pbuffer; - pthread_mutex_unlock(&dc_pbuffers_mutex); + context->draw_pbuffer = draw->pbuffer; }
context->read_view = NULL; @@ -2476,9 +2452,7 @@ static BOOL macdrv_make_current(struct opengl_drawable *draw_base, struct opengl } else { - pthread_mutex_lock(&dc_pbuffers_mutex); - context->read_pbuffer = (CGLPBufferObj)CFDictionaryGetValue(dc_pbuffers, read->base.hdc); - pthread_mutex_unlock(&dc_pbuffers_mutex); + context->read_pbuffer = read->pbuffer; } }
@@ -2790,13 +2764,6 @@ UINT macdrv_OpenGLInit(UINT version, const struct opengl_funcs *opengl_funcs, co } funcs = opengl_funcs;
- dc_pbuffers = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); - if (!dc_pbuffers) - { - WARN("CFDictionaryCreateMutable failed\n"); - return STATUS_NOT_SUPPORTED; - } - opengl_handle = dlopen("/System/Library/Frameworks/OpenGL.framework/OpenGL", RTLD_LAZY|RTLD_LOCAL|RTLD_NOLOAD); if (!opengl_handle) { @@ -2951,49 +2918,27 @@ static void *macdrv_get_proc_address(const char *name) static BOOL macdrv_surface_swap(struct opengl_drawable *base) { struct macdrv_context *context = NtCurrentTeb()->glReserved2; + struct macdrv_win_data *data; HWND hwnd = base->hwnd; - HDC hdc = base->hdc; BOOL match = FALSE;
- TRACE("hdc %p context %p/%p/%p\n", hdc, context, (context ? context->context : NULL), + TRACE("%s context %p/%p/%p\n", debugstr_opengl_drawable(base), context, (context ? context->context : NULL), (context ? context->cglcontext : NULL));
- if (hwnd) + if (!(data = get_win_data(hwnd))) { - struct macdrv_win_data *data; - - if (!(data = get_win_data(hwnd))) - { - RtlSetLastWin32Error(ERROR_INVALID_HANDLE); - return FALSE; - } - - if (context && context->draw_view == data->client_cocoa_view) - match = TRUE; - - release_win_data(data); + RtlSetLastWin32Error(ERROR_INVALID_HANDLE); + return FALSE; } - else - { - CGLPBufferObj pbuffer;
- pthread_mutex_lock(&dc_pbuffers_mutex); - pbuffer = (CGLPBufferObj)CFDictionaryGetValue(dc_pbuffers, hdc); - pthread_mutex_unlock(&dc_pbuffers_mutex); + if (context && context->draw_view == data->client_cocoa_view) + match = TRUE;
- if (!pbuffer) - { - RtlSetLastWin32Error(ERROR_INVALID_HANDLE); - return FALSE; - } - - if (context && context->draw_pbuffer == pbuffer) - match = TRUE; - } + release_win_data(data);
if (!match) { - FIXME("current context %p doesn't match hdc %p; can't swap\n", context, hdc); + FIXME("current context %p doesn't match; can't swap\n", context); return FALSE; }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/opengl.c | 14 ++++++++++---- dlls/winemac.drv/opengl.c | 16 ---------------- dlls/winex11.drv/opengl.c | 16 ---------------- 3 files changed, 10 insertions(+), 36 deletions(-)
diff --git a/dlls/win32u/opengl.c b/dlls/win32u/opengl.c index 65318895a65..f89f16c2f48 100644 --- a/dlls/win32u/opengl.c +++ b/dlls/win32u/opengl.c @@ -246,9 +246,12 @@ void opengl_drawable_release( struct opengl_drawable *drawable ) const struct opengl_funcs *funcs = &display_funcs; const struct egl_platform *egl = &display_egl;
- pthread_mutex_lock( &drawables_lock ); - opengl_drawable_detach( drawable ); - pthread_mutex_unlock( &drawables_lock ); + if (drawable->hwnd) + { + pthread_mutex_lock( &drawables_lock ); + opengl_drawable_detach( drawable ); + pthread_mutex_unlock( &drawables_lock ); + }
drawable->funcs->destroy( drawable ); if (drawable->surface) funcs->p_eglDestroySurface( egl->display, drawable->surface ); @@ -258,6 +261,8 @@ void opengl_drawable_release( struct opengl_drawable *drawable )
static void opengl_drawable_flush( struct opengl_drawable *drawable, int interval, UINT flags ) { + if (!drawable->hwnd) return; + if (InterlockedCompareExchange( &drawable->updated, 0, 1 )) flags |= GL_FLUSH_UPDATED; if (interval != drawable->interval) { @@ -1658,7 +1663,8 @@ static BOOL win32u_wglSwapBuffers( HDC hdc )
if (!(draw = get_dc_opengl_drawable( draw_hdc, FALSE ))) return FALSE; opengl_drawable_flush( draw, interval, 0 ); - ret = draw->funcs->swap( draw ); + if (!draw->hwnd) ret = FALSE; /* pbuffer, nothing to do */ + else ret = draw->funcs->swap( draw ); opengl_drawable_release( draw );
return ret; diff --git a/dlls/winemac.drv/opengl.c b/dlls/winemac.drv/opengl.c index 57b2ed23dd9..4d9780c7eb3 100644 --- a/dlls/winemac.drv/opengl.c +++ b/dlls/winemac.drv/opengl.c @@ -2381,19 +2381,6 @@ static void macdrv_pbuffer_destroy(struct opengl_drawable *base) CGLReleasePBuffer(gl->pbuffer); }
-static void macdrv_pbuffer_detach(struct opengl_drawable *base) -{ -} - -static void macdrv_pbuffer_flush(struct opengl_drawable *base, UINT flags) -{ -} - -static BOOL macdrv_pbuffer_swap(struct opengl_drawable *base) -{ - return FALSE; -} - static BOOL macdrv_make_current(struct opengl_drawable *draw_base, struct opengl_drawable *read_base, void *private) { struct gl_drawable *draw = impl_from_opengl_drawable(draw_base), *read = impl_from_opengl_drawable(read_base); @@ -2973,7 +2960,4 @@ static const struct opengl_drawable_funcs macdrv_surface_funcs = static const struct opengl_drawable_funcs macdrv_pbuffer_funcs = { .destroy = macdrv_pbuffer_destroy, - .detach = macdrv_pbuffer_detach, - .flush = macdrv_pbuffer_flush, - .swap = macdrv_pbuffer_swap, }; diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index 547608aa79f..4d100088030 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -1428,19 +1428,6 @@ static void x11drv_pbuffer_destroy( struct opengl_drawable *base ) if (gl->drawable) pglXDestroyPbuffer( gdi_display, gl->drawable ); }
-static void x11drv_pbuffer_detach( struct opengl_drawable *base ) -{ -} - -static void x11drv_pbuffer_flush( struct opengl_drawable *base, UINT flags ) -{ -} - -static BOOL x11drv_pbuffer_swap( struct opengl_drawable *base ) -{ - return FALSE; -} - static BOOL x11drv_pbuffer_updated( HDC hdc, struct opengl_drawable *base, GLenum cube_face, GLint mipmap_level ) { return GL_TRUE; @@ -1669,9 +1656,6 @@ static const struct opengl_drawable_funcs x11drv_surface_funcs = static const struct opengl_drawable_funcs x11drv_pbuffer_funcs = { .destroy = x11drv_pbuffer_destroy, - .detach = x11drv_pbuffer_detach, - .flush = x11drv_pbuffer_flush, - .swap = x11drv_pbuffer_swap, };
static const struct opengl_drawable_funcs x11drv_egl_surface_funcs =
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/opengl.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-)
diff --git a/dlls/win32u/opengl.c b/dlls/win32u/opengl.c index f89f16c2f48..1c89b49b483 100644 --- a/dlls/win32u/opengl.c +++ b/dlls/win32u/opengl.c @@ -166,16 +166,9 @@ static void register_extension( char *list, size_t size, const char *name ) static pthread_mutex_t drawables_lock = PTHREAD_MUTEX_INITIALIZER; static struct list drawables = LIST_INIT( drawables );
-/* drawables_lock must be held */ -static void opengl_drawable_detach( struct opengl_drawable *drawable ) -{ - drawable->funcs->detach( drawable ); - list_remove( &drawable->entry ); - list_init( &drawable->entry ); -} - void detach_opengl_drawables( HWND hwnd ) { + struct list detached = LIST_INIT( detached ); struct opengl_drawable *drawable, *next;
pthread_mutex_lock( &drawables_lock ); @@ -183,10 +176,22 @@ void detach_opengl_drawables( HWND hwnd ) LIST_FOR_EACH_ENTRY_SAFE( drawable, next, &drawables, struct opengl_drawable, entry ) { if (drawable->hwnd != hwnd) continue; - opengl_drawable_detach( drawable ); + + list_remove( &drawable->entry ); + list_add_tail( &detached, &drawable->entry ); + opengl_drawable_add_ref( drawable ); + + drawable->funcs->detach( drawable ); + drawable->hwnd = NULL; }
pthread_mutex_unlock( &drawables_lock ); + + LIST_FOR_EACH_ENTRY_SAFE( drawable, next, &detached, struct opengl_drawable, entry ) + { + list_remove( &drawable->entry ); + opengl_drawable_release( drawable ); + } }
void update_opengl_drawables( HWND hwnd ) @@ -246,12 +251,13 @@ void opengl_drawable_release( struct opengl_drawable *drawable ) const struct opengl_funcs *funcs = &display_funcs; const struct egl_platform *egl = &display_egl;
+ pthread_mutex_lock( &drawables_lock ); if (drawable->hwnd) { - pthread_mutex_lock( &drawables_lock ); - opengl_drawable_detach( drawable ); - pthread_mutex_unlock( &drawables_lock ); + drawable->funcs->detach( drawable ); + list_remove( &drawable->entry ); } + pthread_mutex_unlock( &drawables_lock );
drawable->funcs->destroy( drawable ); if (drawable->surface) funcs->p_eglDestroySurface( egl->display, drawable->surface );
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/opengl.c | 103 ++++++++++++++++++++++++++++++---- dlls/wineandroid.drv/opengl.c | 6 +- dlls/winewayland.drv/opengl.c | 7 ++- dlls/winex11.drv/opengl.c | 6 +- include/wine/opengl_driver.h | 7 ++- 5 files changed, 108 insertions(+), 21 deletions(-)
diff --git a/dlls/win32u/opengl.c b/dlls/win32u/opengl.c index 1c89b49b483..3d84995005c 100644 --- a/dlls/win32u/opengl.c +++ b/dlls/win32u/opengl.c @@ -281,6 +281,15 @@ static void opengl_drawable_flush( struct opengl_drawable *drawable, int interva
#ifdef SONAME_LIBEGL
+static const struct opengl_drawable_funcs egldrv_pbuffer_funcs; + +static inline EGLConfig egl_config_for_format( const struct egl_platform *egl, int format ) +{ + assert(format > 0 && format <= 2 * egl->config_count); + if (format <= egl->config_count) return egl->configs[format - 1]; + return egl->configs[format - egl->config_count - 1]; +} + static void *egldrv_get_proc_address( const char *name ) { return display_funcs.p_eglGetProcAddress( name ); @@ -293,7 +302,6 @@ static UINT egldrv_init_pixel_formats( UINT *onscreen_count ) const EGLint attribs[] = { EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, - EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_NONE }; EGLConfig *configs; @@ -420,7 +428,10 @@ static BOOL describe_egl_config( EGLConfig config, struct wgl_pixel_format *fmt, } else fmt->pixel_type = -1;
- fmt->draw_to_pbuffer = TRUE; + if (egl->force_pbuffer_formats) fmt->draw_to_pbuffer = TRUE; + else if (surface_type & EGL_PBUFFER_BIT) fmt->draw_to_pbuffer = TRUE; + if (fmt->draw_to_pbuffer) pfd->dwFlags |= PFD_DRAW_TO_BITMAP; + /* Use some arbitrary but reasonable limits (4096 is also Mesa's default) */ fmt->max_pbuffer_width = 4096; fmt->max_pbuffer_height = 4096; @@ -489,19 +500,81 @@ static BOOL egldrv_surface_create( HWND hwnd, HDC hdc, int format, struct opengl static BOOL egldrv_pbuffer_create( HDC hdc, int format, BOOL largest, GLenum texture_format, GLenum texture_target, GLint max_level, GLsizei *width, GLsizei *height, struct opengl_drawable **drawable ) { - FIXME( "stub!\n" ); - return FALSE; + const struct opengl_funcs *funcs = &display_funcs; + const struct egl_platform *egl = &display_egl; + EGLint attribs[13], *attrib = attribs; + struct opengl_drawable *gl; + + TRACE( "hdc %p, format %d, largest %u, texture_format %#x, texture_target %#x, max_level %#x, width %d, height %d, drawable %p\n", + hdc, format, largest, texture_format, texture_target, max_level, *width, *height, drawable ); + + *attrib++ = EGL_WIDTH; + *attrib++ = *width; + *attrib++ = EGL_HEIGHT; + *attrib++ = *height; + if (largest) + { + *attrib++ = EGL_LARGEST_PBUFFER; + *attrib++ = 1; + } + switch (texture_format) + { + case 0: break; + case GL_RGB: + *attrib++ = EGL_TEXTURE_FORMAT; + *attrib++ = EGL_TEXTURE_RGB; + break; + case GL_RGBA: + *attrib++ = EGL_TEXTURE_FORMAT; + *attrib++ = EGL_TEXTURE_RGBA; + break; + default: + FIXME( "Unsupported format %#x\n", texture_format ); + *attrib++ = EGL_TEXTURE_FORMAT; + *attrib++ = EGL_TEXTURE_RGBA; + break; + } + switch (texture_target) + { + case 0: break; + case GL_TEXTURE_2D: + *attrib++ = EGL_TEXTURE_TARGET; + *attrib++ = EGL_TEXTURE_2D; + break; + default: + FIXME( "Unsupported target %#x\n", texture_target ); + *attrib++ = EGL_TEXTURE_TARGET; + *attrib++ = EGL_TEXTURE_2D; + break; + } + if (max_level) + { + *attrib++ = EGL_MIPMAP_TEXTURE; + *attrib++ = GL_TRUE; + } + *attrib++ = EGL_NONE; + + if (!(gl = opengl_drawable_create( sizeof(*gl), &egldrv_pbuffer_funcs, format, 0, hdc ))) return FALSE; + if (!(gl->surface = funcs->p_eglCreatePbufferSurface( egl->display, egl_config_for_format( egl, gl->format ), attribs ))) + { + opengl_drawable_release( gl ); + return FALSE; + } + + funcs->p_eglQuerySurface( egl->display, gl->surface, EGL_WIDTH, width ); + funcs->p_eglQuerySurface( egl->display, gl->surface, EGL_HEIGHT, height ); + + *drawable = gl; + return TRUE; }
static BOOL egldrv_pbuffer_updated( HDC hdc, struct opengl_drawable *drawable, GLenum cube_face, GLint mipmap_level ) { - FIXME( "stub!\n" ); return GL_TRUE; }
static UINT egldrv_pbuffer_bind( HDC hdc, struct opengl_drawable *drawable, GLenum buffer ) { - FIXME( "stub!\n" ); return -1; /* use default implementation */ }
@@ -596,6 +669,16 @@ static BOOL egldrv_make_current( struct opengl_drawable *draw, struct opengl_dra return funcs->p_eglMakeCurrent( egl->display, context ? draw->surface : EGL_NO_SURFACE, context ? read->surface : EGL_NO_SURFACE, context ); }
+static void egldrv_pbuffer_destroy( struct opengl_drawable *drawable ) +{ + TRACE( "%s\n", debugstr_opengl_drawable( drawable ) ); +} + +static const struct opengl_drawable_funcs egldrv_pbuffer_funcs = +{ + .destroy = egldrv_pbuffer_destroy, +}; + static const struct opengl_driver_funcs egldrv_funcs = { .p_get_proc_address = egldrv_get_proc_address, @@ -671,16 +754,14 @@ failed: static void init_egl_platform( struct egl_platform *egl, struct opengl_funcs *funcs, const struct opengl_driver_funcs *driver_funcs ) { - EGLNativeDisplayType platform_display; const char *extensions; EGLint major, minor; - EGLenum platform;
if (!funcs->egl_handle || !driver_funcs->p_init_egl_platform) return;
- platform = driver_funcs->p_init_egl_platform( egl, &platform_display ); - if (!platform) egl->display = funcs->p_eglGetDisplay( EGL_DEFAULT_DISPLAY ); - else egl->display = funcs->p_eglGetPlatformDisplay( platform, platform_display, NULL ); + driver_funcs->p_init_egl_platform( egl ); + if (!egl->type) egl->display = funcs->p_eglGetDisplay( EGL_DEFAULT_DISPLAY ); + else egl->display = funcs->p_eglGetPlatformDisplay( egl->type, egl->native_display, NULL );
if (!egl->display) { diff --git a/dlls/wineandroid.drv/opengl.c b/dlls/wineandroid.drv/opengl.c index ba72dbd4979..a26fba088a5 100644 --- a/dlls/wineandroid.drv/opengl.c +++ b/dlls/wineandroid.drv/opengl.c @@ -146,11 +146,11 @@ static BOOL android_surface_create( HWND hwnd, HDC hdc, int format, struct openg return TRUE; }
-static EGLenum android_init_egl_platform( const struct egl_platform *platform, EGLNativeDisplayType *platform_display ) +static void android_init_egl_platform( struct egl_platform *platform ) { + platform->type = EGL_PLATFORM_ANDROID_KHR; + platform->native_display = EGL_DEFAULT_DISPLAY; egl = platform; - *platform_display = EGL_DEFAULT_DISPLAY; - return EGL_PLATFORM_ANDROID_KHR; }
static void *android_get_proc_address( const char *name ) diff --git a/dlls/winewayland.drv/opengl.c b/dlls/winewayland.drv/opengl.c index 9f1660a80a6..148b41d76d3 100644 --- a/dlls/winewayland.drv/opengl.c +++ b/dlls/winewayland.drv/opengl.c @@ -179,11 +179,12 @@ static BOOL wayland_opengl_surface_create(HWND hwnd, HDC hdc, int format, struct return TRUE; }
-static EGLenum wayland_init_egl_platform(const struct egl_platform *platform, EGLNativeDisplayType *platform_display) +static void wayland_init_egl_platform(struct egl_platform *platform) { + platform->type = EGL_PLATFORM_WAYLAND_KHR; + platform->native_display = process_wayland.wl_display; + platform->force_pbuffer_formats = TRUE; egl = platform; - *platform_display = process_wayland.wl_display; - return EGL_PLATFORM_WAYLAND_KHR; }
static void wayland_drawable_flush(struct opengl_drawable *base, UINT flags) diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index 4d100088030..a4b87667380 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -470,11 +470,11 @@ done: return ret; }
-static EGLenum x11drv_init_egl_platform( const struct egl_platform *platform, EGLNativeDisplayType *platform_display ) +static void x11drv_init_egl_platform( struct egl_platform *platform ) { + platform->type = EGL_PLATFORM_X11_KHR; + platform->native_display = gdi_display; egl = platform; - *platform_display = gdi_display; - return EGL_PLATFORM_X11_KHR; }
static inline EGLConfig egl_config_for_format(int format) diff --git a/include/wine/opengl_driver.h b/include/wine/opengl_driver.h index 188c7b81249..0a013d782c2 100644 --- a/include/wine/opengl_driver.h +++ b/include/wine/opengl_driver.h @@ -119,6 +119,11 @@ struct opengl_funcs
struct egl_platform { + EGLenum type; + EGLNativeDisplayType native_display; + BOOL force_pbuffer_formats; + + /* filled by win32u after init_egl_platform */ EGLDisplay display; UINT config_count; EGLConfig *configs; @@ -176,7 +181,7 @@ W32KAPI void set_window_opengl_drawable( HWND hwnd, struct opengl_drawable *draw /* interface between win32u and the user drivers */ struct opengl_driver_funcs { - GLenum (*p_init_egl_platform)(const struct egl_platform*,EGLNativeDisplayType*); + void (*p_init_egl_platform)(struct egl_platform*); void *(*p_get_proc_address)(const char *); UINT (*p_init_pixel_formats)(UINT*); BOOL (*p_describe_pixel_format)(int,struct wgl_pixel_format*);
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winewayland.drv/opengl.c | 136 +++++++++++++++++----------------- 1 file changed, 70 insertions(+), 66 deletions(-)
diff --git a/dlls/winewayland.drv/opengl.c b/dlls/winewayland.drv/opengl.c index 148b41d76d3..dbbcec97d87 100644 --- a/dlls/winewayland.drv/opengl.c +++ b/dlls/winewayland.drv/opengl.c @@ -51,7 +51,6 @@ struct wayland_gl_drawable struct opengl_drawable base; struct wayland_client_surface *client; struct wl_egl_window *wl_egl_window; - BOOL double_buffered; };
static struct wayland_gl_drawable *impl_from_opengl_drawable(struct opengl_drawable *base) @@ -86,68 +85,13 @@ static void wayland_drawable_update(struct opengl_drawable *base) TRACE("%s\n", debugstr_opengl_drawable(base)); }
-static inline BOOL is_onscreen_format(int format) -{ - return format > 0 && format <= egl->config_count; -} - -static inline EGLConfig egl_config_for_format(int format) +static EGLConfig egl_config_for_format(int format) { assert(format > 0 && format <= 2 * egl->config_count); if (format <= egl->config_count) return egl->configs[format - 1]; return egl->configs[format - egl->config_count - 1]; }
-static struct wayland_gl_drawable *wayland_gl_drawable_create(HWND hwnd, HDC hdc, int format, int width, int height) -{ - struct wayland_gl_drawable *gl; - EGLint attribs[4], *attrib = attribs; - - TRACE("hwnd=%p format=%d\n", hwnd, format); - - if (!egl->has_EGL_EXT_present_opaque) - WARN("Missing EGL_EXT_present_opaque extension\n"); - else - { - *attrib++ = EGL_PRESENT_OPAQUE_EXT; - *attrib++ = EGL_TRUE; - } - *attrib++ = EGL_NONE; - - if (!(gl = opengl_drawable_create(sizeof(*gl), &wayland_drawable_funcs, format, hwnd, hdc))) return NULL; - - /* 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 (!(gl->client = wayland_client_surface_create(hwnd))) goto err; - set_client_surface(hwnd, gl->client); - - gl->wl_egl_window = wl_egl_window_create(gl->client->wl_surface, width, height); - if (!gl->wl_egl_window) - { - ERR("Failed to create wl_egl_window\n"); - goto err; - } - - gl->base.surface = funcs->p_eglCreateWindowSurface(egl->display, egl_config_for_format(format), - gl->wl_egl_window, attribs); - if (!gl->base.surface) - { - ERR("Failed to create EGL surface\n"); - goto err; - } - - gl->double_buffered = is_onscreen_format(format); - - TRACE("Created drawable %s with egl_surface %p\n", debugstr_opengl_drawable(&gl->base), gl->base.surface); - - return gl; - -err: - opengl_drawable_release(&gl->base); - return NULL; -} - static void wayland_gl_drawable_sync_size(struct wayland_gl_drawable *gl) { int client_width, client_height; @@ -163,20 +107,44 @@ static void wayland_gl_drawable_sync_size(struct wayland_gl_drawable *gl)
static BOOL wayland_opengl_surface_create(HWND hwnd, HDC hdc, int format, struct opengl_drawable **drawable) { + EGLConfig config = egl_config_for_format(format); + EGLint attribs[4], *attrib = attribs; struct opengl_drawable *previous; struct wayland_gl_drawable *gl; RECT rect;
+ TRACE("hwnd=%p format=%d\n", hwnd, 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, format, rect.right - rect.left, rect.bottom - rect.top))) return FALSE; + if (!egl->has_EGL_EXT_present_opaque) + WARN("Missing EGL_EXT_present_opaque extension\n"); + else + { + *attrib++ = EGL_PRESENT_OPAQUE_EXT; + *attrib++ = EGL_TRUE; + } + *attrib++ = EGL_NONE; + + if (!(gl = opengl_drawable_create(sizeof(*gl), &wayland_drawable_funcs, format, hwnd, hdc))) return FALSE; + if (!(gl->client = wayland_client_surface_create(hwnd))) goto err; + if (!(gl->wl_egl_window = wl_egl_window_create(gl->client->wl_surface, rect.right, rect.bottom))) goto err; + if (!(gl->base.surface = funcs->p_eglCreateWindowSurface(egl->display, config, gl->wl_egl_window, attribs))) goto err; + set_client_surface(hwnd, gl->client); + + TRACE("Created drawable %s with egl_surface %p\n", debugstr_opengl_drawable(&gl->base), gl->base.surface); + if (previous) opengl_drawable_release( previous ); *drawable = &gl->base; return TRUE; + +err: + opengl_drawable_release(&gl->base); + return FALSE; }
static void wayland_init_egl_platform(struct egl_platform *platform) @@ -207,26 +175,62 @@ static BOOL wayland_drawable_swap(struct opengl_drawable *base)
ensure_window_surface_contents(toplevel); set_client_surface(hwnd, gl->client); - - /* Although all the EGL surfaces we create are double-buffered, we want to - * use some as single-buffered, so avoid swapping those. */ - if (gl->double_buffered) funcs->p_eglSwapBuffers(egl->display, gl->base.surface); + funcs->p_eglSwapBuffers(egl->display, gl->base.surface);
return TRUE; }
+struct wayland_pbuffer +{ + struct opengl_drawable base; + struct wl_surface *surface; + struct wl_egl_window *window; +}; + +static struct wayland_pbuffer *pbuffer_from_opengl_drawable(struct opengl_drawable *base) +{ + return CONTAINING_RECORD(base, struct wayland_pbuffer, base); +} + +static void wayland_pbuffer_destroy(struct opengl_drawable *base) +{ + struct wayland_pbuffer *gl = pbuffer_from_opengl_drawable(base); + + TRACE("%s\n", debugstr_opengl_drawable(base)); + + if (gl->window) + wl_egl_window_destroy(gl->window); + if (gl->surface) + wl_surface_destroy(gl->surface); +} + +static const struct opengl_drawable_funcs wayland_pbuffer_funcs = +{ + .destroy = wayland_pbuffer_destroy, +}; + static BOOL wayland_pbuffer_create(HDC hdc, int format, BOOL largest, GLenum texture_format, GLenum texture_target, GLint max_level, GLsizei *width, GLsizei *height, struct opengl_drawable **surface) { - struct wayland_gl_drawable *drawable; + EGLConfig config = egl_config_for_format(format); + struct wayland_pbuffer *gl;
TRACE("hdc %p, format %d, largest %u, texture_format %#x, texture_target %#x, max_level %#x, width %d, height %d, private %p\n", hdc, format, largest, texture_format, texture_target, max_level, *width, *height, surface);
- /* Use an unmapped wayland surface as our offscreen "pbuffer" surface. */ - if (!(drawable = wayland_gl_drawable_create(0, hdc, format, *width, *height))) return FALSE; - *surface = &drawable->base; + if (!(gl = opengl_drawable_create(sizeof(*gl), &wayland_pbuffer_funcs, format, NULL, hdc))) return FALSE; + /* Wayland EGL doesn't support pixmap or pbuffer, create a dummy window surface to act as the target render surface. */ + if (!(gl->surface = wl_compositor_create_surface(process_wayland.wl_compositor))) goto err; + if (!(gl->window = wl_egl_window_create(gl->surface, *width, *height))) goto err; + if (!(gl->base.surface = funcs->p_eglCreateWindowSurface(egl->display, config, gl->window, NULL))) goto err; + + TRACE("Created pbuffer %s with egl_surface %p\n", debugstr_opengl_drawable(&gl->base), gl->base.surface); + *surface = &gl->base; return TRUE; + +err: + opengl_drawable_release(&gl->base); + return FALSE; }
static BOOL wayland_pbuffer_updated(HDC hdc, struct opengl_drawable *base, GLenum cube_face, GLint mipmap_level)
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/opengl.c | 5 ++--- dlls/wineandroid.drv/opengl.c | 3 +-- dlls/winemac.drv/opengl.c | 4 ++-- dlls/winewayland.drv/opengl.c | 4 ++-- dlls/winex11.drv/opengl.c | 17 +++++++++-------- include/wine/opengl_driver.h | 5 ++--- 6 files changed, 18 insertions(+), 20 deletions(-)
diff --git a/dlls/win32u/opengl.c b/dlls/win32u/opengl.c index 3d84995005c..6ed8ac1010e 100644 --- a/dlls/win32u/opengl.c +++ b/dlls/win32u/opengl.c @@ -210,7 +210,7 @@ void update_opengl_drawables( HWND hwnd ) pthread_mutex_unlock( &drawables_lock ); }
-void *opengl_drawable_create( UINT size, const struct opengl_drawable_funcs *funcs, int format, HWND hwnd, HDC hdc ) +void *opengl_drawable_create( UINT size, const struct opengl_drawable_funcs *funcs, int format, HWND hwnd ) { struct opengl_drawable *drawable;
@@ -221,7 +221,6 @@ void *opengl_drawable_create( UINT size, const struct opengl_drawable_funcs *fun drawable->format = format; drawable->interval = INT_MIN; drawable->hwnd = hwnd; - drawable->hdc = hdc;
if (!hwnd) list_init( &drawable->entry ); /* pbuffer, keep it unlinked */ else @@ -554,7 +553,7 @@ static BOOL egldrv_pbuffer_create( HDC hdc, int format, BOOL largest, GLenum tex } *attrib++ = EGL_NONE;
- if (!(gl = opengl_drawable_create( sizeof(*gl), &egldrv_pbuffer_funcs, format, 0, hdc ))) return FALSE; + if (!(gl = opengl_drawable_create( sizeof(*gl), &egldrv_pbuffer_funcs, format, 0 ))) return FALSE; if (!(gl->surface = funcs->p_eglCreatePbufferSurface( egl->display, egl_config_for_format( egl, gl->format ), attribs ))) { opengl_drawable_release( gl ); diff --git a/dlls/wineandroid.drv/opengl.c b/dlls/wineandroid.drv/opengl.c index a26fba088a5..e5f660c2be4 100644 --- a/dlls/wineandroid.drv/opengl.c +++ b/dlls/wineandroid.drv/opengl.c @@ -75,7 +75,7 @@ static struct gl_drawable *create_gl_drawable( HWND hwnd, HDC hdc, int format, A static const int attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE }; struct gl_drawable *gl;
- if (!(gl = opengl_drawable_create( sizeof(*gl), &android_drawable_funcs, format, hwnd, hdc ))) return NULL; + if (!(gl = opengl_drawable_create( sizeof(*gl), &android_drawable_funcs, format, hwnd ))) return NULL;
if (!window) gl->window = create_ioctl_window( hwnd, TRUE, 1.0f ); else gl->window = grab_ioctl_window( window ); @@ -134,7 +134,6 @@ static BOOL android_surface_create( HWND hwnd, HDC hdc, int format, struct openg 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 ) ); diff --git a/dlls/winemac.drv/opengl.c b/dlls/winemac.drv/opengl.c index 4d9780c7eb3..f48737c1b43 100644 --- a/dlls/winemac.drv/opengl.c +++ b/dlls/winemac.drv/opengl.c @@ -1484,7 +1484,7 @@ static BOOL macdrv_surface_create(HWND hwnd, HDC hdc, int format, struct opengl_ data->pixel_format = format; release_win_data(data);
- if (!(gl = opengl_drawable_create(sizeof(*gl), &macdrv_surface_funcs, format, hwnd, hdc))) return FALSE; + if (!(gl = opengl_drawable_create(sizeof(*gl), &macdrv_surface_funcs, format, hwnd))) return FALSE; *drawable = &gl->base;
return TRUE; @@ -2357,7 +2357,7 @@ static BOOL macdrv_pbuffer_create(HDC hdc, int format, BOOL largest, GLenum text texture_format = GL_RGB; }
- if (!(gl = opengl_drawable_create(sizeof(*gl), &macdrv_pbuffer_funcs, format, 0, hdc))) return FALSE; + if (!(gl = opengl_drawable_create(sizeof(*gl), &macdrv_pbuffer_funcs, format, 0))) return FALSE;
err = CGLCreatePBuffer(*width, *height, texture_target, texture_format, max_level, &gl->pbuffer); if (err != kCGLNoError) diff --git a/dlls/winewayland.drv/opengl.c b/dlls/winewayland.drv/opengl.c index dbbcec97d87..bf7be9daccc 100644 --- a/dlls/winewayland.drv/opengl.c +++ b/dlls/winewayland.drv/opengl.c @@ -130,7 +130,7 @@ static BOOL wayland_opengl_surface_create(HWND hwnd, HDC hdc, int format, struct } *attrib++ = EGL_NONE;
- if (!(gl = opengl_drawable_create(sizeof(*gl), &wayland_drawable_funcs, format, hwnd, hdc))) return FALSE; + if (!(gl = opengl_drawable_create(sizeof(*gl), &wayland_drawable_funcs, format, hwnd))) return FALSE; if (!(gl->client = wayland_client_surface_create(hwnd))) goto err; if (!(gl->wl_egl_window = wl_egl_window_create(gl->client->wl_surface, rect.right, rect.bottom))) goto err; if (!(gl->base.surface = funcs->p_eglCreateWindowSurface(egl->display, config, gl->wl_egl_window, attribs))) goto err; @@ -218,7 +218,7 @@ static BOOL wayland_pbuffer_create(HDC hdc, int format, BOOL largest, GLenum tex TRACE("hdc %p, format %d, largest %u, texture_format %#x, texture_target %#x, max_level %#x, width %d, height %d, private %p\n", hdc, format, largest, texture_format, texture_target, max_level, *width, *height, surface);
- if (!(gl = opengl_drawable_create(sizeof(*gl), &wayland_pbuffer_funcs, format, NULL, hdc))) return FALSE; + if (!(gl = opengl_drawable_create(sizeof(*gl), &wayland_pbuffer_funcs, format, NULL))) return FALSE; /* Wayland EGL doesn't support pixmap or pbuffer, create a dummy window surface to act as the target render surface. */ if (!(gl->surface = wl_compositor_create_surface(process_wayland.wl_compositor))) goto err; if (!(gl->window = wl_egl_window_create(gl->surface, *width, *height))) goto err; diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index a4b87667380..f841a45651c 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -203,6 +203,7 @@ struct gl_drawable Colormap colormap; /* colormap for the client window */ Pixmap pixmap; /* base pixmap if drawable is a GLXPixmap */ BOOL offscreen; + HDC hdc; HDC hdc_src; HDC hdc_dst; }; @@ -493,16 +494,16 @@ static BOOL x11drv_egl_surface_create( HWND hwnd, HDC hdc, int format, struct op if ((previous = *drawable) && previous->format == format) return TRUE; NtUserGetClientRect( hwnd, &rect, NtUserGetDpiForWindow( hwnd ) );
- if (!(gl = opengl_drawable_create( sizeof(*gl), &x11drv_egl_surface_funcs, format, hwnd, hdc ))) return FALSE; + if (!(gl = opengl_drawable_create( sizeof(*gl), &x11drv_egl_surface_funcs, format, hwnd ))) return FALSE; gl->rect = rect; + gl->hdc = hdc;
gl->window = create_client_window( hwnd, &default_visual, default_colormap ); gl->base.surface = funcs->p_eglCreateWindowSurface( egl->display, egl_config_for_format(format), (void *)gl->window, NULL ); if (!gl->base.surface) { - destroy_client_window( hwnd, gl->window ); - free( gl ); + opengl_drawable_release( &gl->base ); return FALSE; }
@@ -934,8 +935,9 @@ static BOOL x11drv_surface_create( HWND hwnd, HDC hdc, int format, struct opengl 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, hdc ))) return FALSE; + if (!(gl = opengl_drawable_create( sizeof(*gl), &x11drv_surface_funcs, format, hwnd ))) return FALSE; gl->rect = rect; + gl->hdc = hdc;
gl->colormap = XCreateColormap( gdi_display, get_dummy_parent(), fmt->visual->visual, (fmt->visual->class == PseudoColor || fmt->visual->class == GrayScale || @@ -1261,15 +1263,14 @@ static void present_gl_drawable( struct gl_drawable *gl, BOOL flush, BOOL gl_fin { HWND hwnd = gl->base.hwnd, toplevel = NtUserGetAncestor( hwnd, GA_ROOT ); struct x11drv_win_data *data; - HDC hdc = gl->base.hdc; Drawable window; RECT rect_dst, rect; HRGN region;
if (!gl->offscreen) return;
- window = get_dc_drawable( hdc, &rect ); - region = get_dc_monitor_region( hwnd, hdc ); + window = get_dc_drawable( gl->hdc, &rect ); + region = get_dc_monitor_region( hwnd, gl->hdc );
if (gl_finish) funcs->p_glFinish(); if (flush) XFlush( gdi_display ); @@ -1401,7 +1402,7 @@ static BOOL x11drv_pbuffer_create( HDC hdc, int format, BOOL largest, GLenum tex } glx_attribs[count++] = 0;
- if (!(gl = opengl_drawable_create( sizeof(*gl), &x11drv_pbuffer_funcs, format, 0, hdc ))) return FALSE; + if (!(gl = opengl_drawable_create( sizeof(*gl), &x11drv_pbuffer_funcs, format, 0 ))) return FALSE;
gl->drawable = pglXCreatePbuffer( gdi_display, fmt->fbconfig, glx_attribs ); TRACE( "new Pbuffer drawable as %p (%lx)\n", gl, gl->drawable ); diff --git a/include/wine/opengl_driver.h b/include/wine/opengl_driver.h index 0a013d782c2..1e744622dbd 100644 --- a/include/wine/opengl_driver.h +++ b/include/wine/opengl_driver.h @@ -159,7 +159,6 @@ struct opengl_drawable int format; /* pixel format of the drawable */ int interval; /* last set surface swap interval */ HWND hwnd; /* window the drawable was created for */ - HDC hdc; /* DC the drawable was created for */ struct list entry; /* entry in win32u managed list */ LONG updated; /* has been moved / resized / reparented */ EGLSurface surface; /* surface for EGL based drivers */ @@ -168,10 +167,10 @@ struct opengl_drawable static inline const char *debugstr_opengl_drawable( struct opengl_drawable *drawable ) { if (!drawable) return "(null)"; - return wine_dbg_sprintf( "%p (format %u, hwnd %p, hdc %p)", drawable, drawable->format, drawable->hwnd, drawable->hdc ); + return wine_dbg_sprintf( "%p (format %u, hwnd %p)", drawable, drawable->format, drawable->hwnd ); }
-W32KAPI void *opengl_drawable_create( UINT size, const struct opengl_drawable_funcs *funcs, int format, HWND hwnd, HDC hdc ); +W32KAPI void *opengl_drawable_create( UINT size, const struct opengl_drawable_funcs *funcs, int format, HWND hwnd ); W32KAPI void opengl_drawable_add_ref( struct opengl_drawable *drawable ); W32KAPI void opengl_drawable_release( struct opengl_drawable *drawable );
v5: Add a `force_pbuffer_formats` flag to `egl_platform` to indicate that all formats should be made pbuffer compatible for a given platform.
On Thu Jul 3 14:12:20 2025 +0000, Alexandros Frantzis wrote:
Yes this should be enough. Note that we still need a way to expose "fake" pbuffer capable formats.
Thank you! I've added a flag that should implement this for winewayland.
This merge request was approved by Alexandros Frantzis.