From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/win32u/ntuser_private.h | 1 + dlls/win32u/opengl.c | 57 ++++++++++++++++++++++++++++++++++-- dlls/win32u/sysparams.c | 1 + dlls/win32u/win32u_private.h | 1 + dlls/winemac.drv/opengl.c | 5 ++++ dlls/winex11.drv/opengl.c | 24 +++++++++++++++ include/wine/opengl_driver.h | 1 + 7 files changed, 87 insertions(+), 3 deletions(-) diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index 978700a37aa..dc14811ce86 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -127,6 +127,7 @@ struct user_thread_info DWORD clipping_reset; /* time when clipping was last reset */ struct session_thread_data *session_data; /* shared session thread data */ struct mouse_tracking_info *mouse_tracking_info; /* NtUserTrackMouseEvent handling */ + struct opengl_thread_data *opengl_data; /* OpenGL private thread data */ }; extern struct user_thread_info *get_user_thread_info(void); diff --git a/dlls/win32u/opengl.c b/dlls/win32u/opengl.c index 3d03b41fc24..bb4b7c93e48 100644 --- a/dlls/win32u/opengl.c +++ b/dlls/win32u/opengl.c @@ -39,6 +39,21 @@ WINE_DEFAULT_DEBUG_CHANNEL(wgl); +struct opengl_thread_data +{ + void *null_context; /* dummy context when no client context is active */ + struct opengl_drawable *null_surface; /* dummy surface when no client context is active */ +}; + +static struct opengl_thread_data *get_opengl_thread_data(void) +{ + struct user_thread_info *info = get_user_thread_info(); + struct opengl_thread_data *data; + + if ((data = info->opengl_data)) return data; + return (info->opengl_data = calloc( 1, sizeof(*data) )); +} + struct pbuffer { struct opengl_drawable *drawable; @@ -183,6 +198,30 @@ static BOOL opengl_drawable_swap( struct opengl_drawable *drawable ) return drawable->funcs->swap( drawable ); } +static BOOL make_null_context_current(void) +{ + struct opengl_thread_data *data = get_opengl_thread_data(); + int format; + + if (!data->null_context) + { + for (format = 1; format <= formats_count; format++) + { + struct wgl_pixel_format *desc = pixel_formats + format - 1; + if (!(desc->pfd.dwFlags & PFD_SUPPORT_OPENGL)) continue; + if (desc->pfd.iPixelType != PFD_TYPE_RGBA) continue; + if (desc->pfd.cColorBits < 24) continue; + break; + } + + if (format > formats_count) return FALSE; + driver_funcs->p_context_create( format, NULL, NULL, &data->null_context ); + if (driver_funcs->p_null_surface_create) driver_funcs->p_null_surface_create( format, &data->null_surface ); + } + + return driver_funcs->p_make_current( data->null_surface, data->null_surface, data->null_context ); +} + #ifdef SONAME_LIBEGL struct framebuffer_surface @@ -847,7 +886,8 @@ static BOOL egldrv_make_current( struct opengl_drawable *draw, struct opengl_dra TRACE( "draw %s, read %s, context %p\n", debugstr_opengl_drawable( draw ), debugstr_opengl_drawable( read ), context ); - return funcs->p_eglMakeCurrent( egl->display, context ? draw->surface : EGL_NO_SURFACE, context ? read->surface : EGL_NO_SURFACE, context ); + if (!context) return funcs->p_eglMakeCurrent( egl->display, EGL_NO_SURFACE, EGL_NO_SURFACE, NULL ); + return funcs->p_eglMakeCurrent( egl->display, draw ? draw->surface : EGL_NO_SURFACE, read ? read->surface : EGL_NO_SURFACE, context ); } static void egldrv_pbuffer_destroy( struct opengl_drawable *drawable ) @@ -1779,7 +1819,7 @@ static BOOL context_unset_current( struct opengl_context *context ) opengl_drawable_set_context( old_read, NULL ); if (old_read != old_draw) opengl_drawable_set_context( old_draw, NULL ); - if (driver_funcs->p_make_current( NULL, NULL, NULL )) return TRUE; + if (make_null_context_current()) return TRUE; opengl_drawable_set_context( old_read, context ); if (old_read != old_draw) opengl_drawable_set_context( old_draw, context ); @@ -1909,7 +1949,7 @@ static BOOL win32u_wglMakeContextCurrentARB( HDC draw_hdc, HDC read_hdc, HGLRC c { struct opengl_drawable *draw = NULL, *read = NULL; - if (!(context = prev_context)) return TRUE; + if (!(context = prev_context)) return make_null_context_current(); if (!context_unset_current( context )) return FALSE; NtCurrentTeb()->glContext = NULL; @@ -2830,3 +2870,14 @@ BOOL get_opengl_gpus( struct list *gpus ) return TRUE; } + +void cleanup_opengl_thread(void) +{ + struct user_thread_info *info = get_user_thread_info(); + struct opengl_thread_data *data; + + if (!(data = info->opengl_data)) return; + if (data->null_context) driver_funcs->p_context_destroy( data->null_context ); + if (data->null_surface) opengl_drawable_release( data->null_surface ); + free( data ); +} diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index f0cff127b26..239d13df6cc 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -7467,6 +7467,7 @@ static void thread_detach(void) free( thread_info->rawinput ); cleanup_imm_thread(); + cleanup_opengl_thread(); NtClose( thread_info->server_queue ); if (thread_info->idle_event) NtClose( thread_info->idle_event ); free( thread_info->session_data ); diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index be303ae4d13..5914f1c689f 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -229,6 +229,7 @@ extern NTSTATUS d3dkmt_destroy_sync( D3DKMT_HANDLE local ); /* opengl.c */ extern BOOL get_opengl_gpus( struct list *gpus ); +extern void cleanup_opengl_thread(void); /* winstation.c */ diff --git a/dlls/winemac.drv/opengl.c b/dlls/winemac.drv/opengl.c index 0af1d3f7192..2c18bce7635 100644 --- a/dlls/winemac.drv/opengl.c +++ b/dlls/winemac.drv/opengl.c @@ -2272,6 +2272,11 @@ static BOOL macdrv_make_current(struct opengl_drawable *draw_base, struct opengl NtCurrentTeb()->glReserved2 = NULL; return TRUE; } + if (!draw || !read) + { + CGLSetCurrentContext(context->cglcontext); + return TRUE; + } context->read_hwnd = context->draw_hwnd = NULL; context->read_view = context->draw_view = NULL; diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index 56c22ab7ee7..ebee3bb3e86 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -1344,6 +1344,29 @@ static UINT x11drv_pbuffer_bind( HDC hdc, struct opengl_drawable *base, GLenum b return -1; /* use default implementation */ } +static BOOL x11drv_null_surface_create( int format, struct opengl_drawable **drawable ) +{ + const struct glx_pixel_format *fmt = glx_pixel_format_from_format( format ); + int glx_attribs[7], count = 0; + struct gl_drawable *gl; + + glx_attribs[count++] = GLX_PBUFFER_WIDTH; + glx_attribs[count++] = 1; + glx_attribs[count++] = GLX_PBUFFER_HEIGHT; + glx_attribs[count++] = 1; + glx_attribs[count++] = 0; + + if (!(gl = opengl_drawable_create( sizeof(*gl), &x11drv_pbuffer_funcs, format, NULL ))) return FALSE; + if (!(gl->drawable = pglXCreatePbuffer( gdi_display, fmt->fbconfig, glx_attribs ))) + { + opengl_drawable_release( &gl->base ); + return FALSE; + } + + *drawable = &gl->base; + return TRUE; +} + static BOOL X11DRV_wglQueryCurrentRendererIntegerWINE( GLenum attribute, GLuint *value ) { return pglXQueryCurrentRendererIntegerMESA( attribute, value ); @@ -1520,6 +1543,7 @@ static struct opengl_driver_funcs x11drv_driver_funcs = .p_pbuffer_create = x11drv_pbuffer_create, .p_pbuffer_updated = x11drv_pbuffer_updated, .p_pbuffer_bind = x11drv_pbuffer_bind, + .p_null_surface_create = x11drv_null_surface_create, }; static const struct opengl_drawable_funcs x11drv_surface_funcs = diff --git a/include/wine/opengl_driver.h b/include/wine/opengl_driver.h index af745e038a6..79babe18ff3 100644 --- a/include/wine/opengl_driver.h +++ b/include/wine/opengl_driver.h @@ -252,6 +252,7 @@ struct opengl_driver_funcs GLint max_level, GLsizei *width, GLsizei *height, struct opengl_drawable **drawable ); BOOL (*p_pbuffer_updated)( HDC hdc, struct opengl_drawable *drawable, GLenum cube_face, GLint mipmap_level ); UINT (*p_pbuffer_bind)( HDC hdc, struct opengl_drawable *drawable, GLenum buffer ); + BOOL (*p_null_surface_create)( int format, struct opengl_drawable **drawable ); }; #endif /* WINE_UNIX_LIB */ -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11161