diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c index 1bbdba2ce1d..4f6624b3db8 100644 --- a/dlls/winex11.drv/vulkan.c +++ b/dlls/winex11.drv/vulkan.c @@ -57,12 +57,16 @@ static XContext vulkan_hwnd_context; #define VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR 1000004000 +static struct list surface_list = LIST_INIT( surface_list ); + struct wine_vk_surface { LONG ref; + struct list entry; Window window; VkSurfaceKHR surface; /* native surface */ HWND hwnd; + DWORD hwnd_thread_id; }; typedef struct VkXlibSurfaceCreateInfoKHR @@ -207,6 +211,10 @@ static void wine_vk_surface_release(struct wine_vk_surface *surface) if (InterlockedDecrement(&surface->ref)) return; + EnterCriticalSection(&context_section); + list_remove(&surface->entry); + LeaveCriticalSection(&context_section); + if (surface->window) XDestroyWindow(gdi_display, surface->window); @@ -219,12 +227,33 @@ void wine_vk_surface_destroy(HWND hwnd) EnterCriticalSection(&context_section); if (!XFindContext(gdi_display, (XID)hwnd, vulkan_hwnd_context, (char **)&surface)) { + surface->hwnd_thread_id = 0; + surface->hwnd = NULL; wine_vk_surface_release(surface); } XDeleteContext(gdi_display, (XID)hwnd, vulkan_hwnd_context); LeaveCriticalSection(&context_section); } +void vulkan_thread_detach(void) +{ + struct wine_vk_surface *surface, *next; + DWORD thread_id = GetCurrentThreadId(); + + EnterCriticalSection(&context_section); + LIST_FOR_EACH_ENTRY_SAFE(surface, next, &surface_list, struct wine_vk_surface, entry) + { + if (surface->hwnd_thread_id != thread_id) + continue; + + TRACE("Detaching surface %p, hwnd %p.\n", surface, surface->hwnd); + XReparentWindow(gdi_display, surface->window, get_dummy_parent(), 0, 0); + XSync(gdi_display, False); + wine_vk_surface_destroy(surface->hwnd); + } + LeaveCriticalSection(&context_section); +} + static VkResult X11DRV_vkCreateInstance(const VkInstanceCreateInfo *create_info, const VkAllocationCallbacks *allocator, VkInstance *instance) { @@ -278,7 +307,7 @@ static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance, { VkResult res; VkXlibSurfaceCreateInfoKHR create_info_host; - struct wine_vk_surface *x11_surface, *prev; + struct wine_vk_surface *x11_surface; TRACE("%p %p %p %p\n", instance, create_info, allocator, surface); @@ -298,8 +327,15 @@ static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance, x11_surface->ref = 1; x11_surface->hwnd = create_info->hwnd; - x11_surface->window = x11_surface->hwnd ? create_client_window(create_info->hwnd, &default_visual) - : create_dummy_client_window(); + if (x11_surface->hwnd) + { + x11_surface->window = create_client_window(create_info->hwnd, &default_visual); + x11_surface->hwnd_thread_id = GetWindowThreadProcessId(x11_surface->hwnd, NULL); + } + else + { + x11_surface->window = create_dummy_client_window(); + } if (!x11_surface->window) { @@ -323,16 +359,14 @@ static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance, goto err; } + EnterCriticalSection(&context_section); if (x11_surface->hwnd) { - EnterCriticalSection(&context_section); - if (!XFindContext(gdi_display, (XID)create_info->hwnd, vulkan_hwnd_context, (char **)&prev)) - { - wine_vk_surface_release(prev); - } + wine_vk_surface_destroy( x11_surface->hwnd ); XSaveContext(gdi_display, (XID)create_info->hwnd, vulkan_hwnd_context, (char *)wine_vk_surface_grab(x11_surface)); - LeaveCriticalSection(&context_section); } + list_add_tail(&surface_list, &x11_surface->entry); + LeaveCriticalSection(&context_section); *surface = (uintptr_t)x11_surface; @@ -713,4 +747,8 @@ void wine_vk_surface_destroy(HWND hwnd) { } +void vulkan_thread_detach(void) +{ +} + #endif /* SONAME_LIBVULKAN */ diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 0057a341525..7ec2639e309 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1446,7 +1446,7 @@ static void move_window_bits( HWND hwnd, Window window, const RECT *old_rect, co * * Create a dummy parent window for child windows that don't have a true X11 parent. */ -static Window get_dummy_parent(void) +Window get_dummy_parent(void) { static Window dummy_parent; diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 5ed2fcf73fb..e82ee921830 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -587,11 +587,13 @@ extern struct x11drv_win_data *get_win_data( HWND hwnd ) DECLSPEC_HIDDEN; extern void release_win_data( struct x11drv_win_data *data ) DECLSPEC_HIDDEN; extern Window X11DRV_get_whole_window( HWND hwnd ) DECLSPEC_HIDDEN; extern XIC X11DRV_get_ic( HWND hwnd ) DECLSPEC_HIDDEN; +extern Window get_dummy_parent(void) DECLSPEC_HIDDEN; extern void sync_gl_drawable( HWND hwnd, BOOL known_child ) DECLSPEC_HIDDEN; extern void set_gl_drawable_parent( HWND hwnd, HWND parent ) DECLSPEC_HIDDEN; extern void destroy_gl_drawable( HWND hwnd ) DECLSPEC_HIDDEN; extern void wine_vk_surface_destroy( HWND hwnd ) DECLSPEC_HIDDEN; +extern void vulkan_thread_detach(void) DECLSPEC_HIDDEN; extern void wait_for_withdrawn_state( HWND hwnd, BOOL set ) DECLSPEC_HIDDEN; extern Window init_clip_window(void) DECLSPEC_HIDDEN; diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index e8b273d055e..bd21afc8174 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -645,6 +645,7 @@ void CDECL X11DRV_ThreadDetach(void) if (data) { + vulkan_thread_detach(); if (data->xim) XCloseIM( data->xim ); if (data->font_set) XFreeFontSet( data->display, data->font_set ); XCloseDisplay( data->display );