diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c index 7e252326b5a..7eca31bdea3 100644 --- a/dlls/winex11.drv/vulkan.c +++ b/dlls/winex11.drv/vulkan.c @@ -41,11 +41,23 @@ WINE_DEFAULT_DEBUG_CHANNEL(vulkan); #ifdef SONAME_LIBVULKAN +static CRITICAL_SECTION context_section; +static CRITICAL_SECTION_DEBUG critsect_debug = +{ + 0, 0, &context_section, + { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": context_section") } +}; +static CRITICAL_SECTION context_section = { &critsect_debug, -1, 0, 0, 0, 0 }; + +static XContext vulkan_hwnd_context; + typedef VkFlags VkXlibSurfaceCreateFlagsKHR; #define VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR 1000004000 struct wine_vk_surface { + LONG ref; Window window; VkSurfaceKHR surface; /* native surface */ }; @@ -115,6 +127,8 @@ static BOOL WINAPI wine_vk_init(INIT_ONCE *once, void *param, void **context) LOAD_FUNCPTR(vkQueuePresentKHR) #undef LOAD_FUNCPTR + vulkan_hwnd_context = XUniqueContext(); + return TRUE; fail: @@ -171,13 +185,16 @@ static VkResult wine_vk_instance_convert_create_info(const VkInstanceCreateInfo return VK_SUCCESS; } -static void wine_vk_surface_destroy(VkInstance instance, struct wine_vk_surface *surface) +static struct wine_vk_surface *wine_vk_surface_grab(struct wine_vk_surface *surface) { - if (!surface) - return; + InterlockedIncrement(&surface->ref); + return surface; +} - /* vkDestroySurfaceKHR must handle VK_NULL_HANDLE (0) for surface. */ - pvkDestroySurfaceKHR(instance, surface->surface, NULL /* allocator */); +static void wine_vk_surface_release(struct wine_vk_surface *surface) +{ + if (InterlockedDecrement(&surface->ref)) + return; if (surface->window) XDestroyWindow(gdi_display, surface->window); @@ -185,6 +202,18 @@ static void wine_vk_surface_destroy(VkInstance instance, struct wine_vk_surface heap_free(surface); } +void wine_vk_surface_destroy(HWND hwnd) +{ + struct wine_vk_surface *surface; + EnterCriticalSection(&context_section); + if (!XFindContext(gdi_display, (XID)hwnd, vulkan_hwnd_context, (char **)&surface)) + { + wine_vk_surface_release(surface); + } + XDeleteContext(gdi_display, (XID)hwnd, vulkan_hwnd_context); + LeaveCriticalSection(&context_section); +} + static VkResult X11DRV_vkAcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t *index) { @@ -245,7 +274,7 @@ static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance, { VkResult res; VkXlibSurfaceCreateInfoKHR create_info_host; - struct wine_vk_surface *x11_surface; + struct wine_vk_surface *x11_surface, *prev; TRACE("%p %p %p %p\n", instance, create_info, allocator, surface); @@ -263,6 +292,8 @@ static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance, if (!x11_surface) return VK_ERROR_OUT_OF_HOST_MEMORY; + x11_surface->ref = 1; + x11_surface->window = create_client_window(create_info->hwnd, &default_visual); if (!x11_surface->window) { @@ -286,13 +317,21 @@ static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance, goto err; } + EnterCriticalSection(&context_section); + if (!XFindContext(gdi_display, (XID)create_info->hwnd, vulkan_hwnd_context, (char **)&prev)) + { + wine_vk_surface_release(prev); + } + XSaveContext(gdi_display, (XID)create_info->hwnd, vulkan_hwnd_context, (char *)wine_vk_surface_grab(x11_surface)); + LeaveCriticalSection(&context_section); + *surface = (uintptr_t)x11_surface; TRACE("Created surface=0x%s\n", wine_dbgstr_longlong(*surface)); return VK_SUCCESS; err: - wine_vk_surface_destroy(instance, x11_surface); + wine_vk_surface_release(x11_surface); return res; } @@ -316,7 +355,13 @@ static void X11DRV_vkDestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface if (allocator) FIXME("Support for allocation callbacks not implemented yet\n"); - wine_vk_surface_destroy(instance, x11_surface); + /* vkDestroySurfaceKHR must handle VK_NULL_HANDLE (0) for surface. */ + if (x11_surface) + { + pvkDestroySurfaceKHR(instance, x11_surface->surface, NULL /* allocator */); + + wine_vk_surface_release(x11_surface); + } } static void X11DRV_vkDestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain, diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 5fecd9a17b8..a848dc61e14 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1719,6 +1719,7 @@ void CDECL X11DRV_DestroyWindow( HWND hwnd ) release_win_data( data ); HeapFree( GetProcessHeap(), 0, data ); destroy_gl_drawable( hwnd ); + wine_vk_surface_destroy( hwnd ); } diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 85a05a904aa..939c2e7f3bb 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -586,6 +586,7 @@ extern XIC X11DRV_get_ic( HWND hwnd ) DECLSPEC_HIDDEN; extern void sync_gl_drawable( HWND hwnd ) 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 wait_for_withdrawn_state( HWND hwnd, BOOL set ) DECLSPEC_HIDDEN; extern Window init_clip_window(void) DECLSPEC_HIDDEN;