From 011fabb2c43d13402ea18b6ea7be3669b5e6c7a8 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 3 May 2021 13:26:27 +0300 Subject: [PATCH] winex11.drv: Handle Vulkan surface creation with NULL hwnd. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Paul Gofman Signed-off-by: RĂ©mi Bernon Signed-off-by: Alexandre Julliard --- dlls/vulkan-1/tests/vulkan.c | 112 ++++++++++++++++++++++++++++++++++- dlls/winex11.drv/vulkan.c | 38 +++++++++--- dlls/winex11.drv/window.c | 18 ++++++ dlls/winex11.drv/x11drv.h | 1 + 4 files changed, 158 insertions(+), 11 deletions(-) diff --git a/dlls/vulkan-1/tests/vulkan.c b/dlls/vulkan-1/tests/vulkan.c index 9061b2b6db8..e516d0d61c8 100644 --- a/dlls/vulkan-1/tests/vulkan.c +++ b/dlls/vulkan-1/tests/vulkan.c @@ -437,7 +437,102 @@ static void test_private_data(VkPhysicalDevice vk_physical_device) vkDestroyDevice(vk_device, NULL); } -static void for_each_device(void (*test_func)(VkPhysicalDevice)) +static const char *test_null_hwnd_extensions[] = +{ + "VK_KHR_surface", + "VK_KHR_win32_surface", +}; + +static void test_null_hwnd(VkInstance vk_instance, VkPhysicalDevice vk_physical_device) +{ + PFN_vkGetPhysicalDeviceSurfacePresentModesKHR pvkGetPhysicalDeviceSurfacePresentModesKHR; + VkDeviceGroupPresentModeFlagsKHR present_mode_flags; + VkWin32SurfaceCreateInfoKHR surface_create_info; + VkSurfaceCapabilitiesKHR surf_caps; + VkSurfaceFormatKHR *formats; + uint32_t queue_family_index; + VkPresentModeKHR *modes; + VkSurfaceKHR surface; + VkDevice vk_device; + uint32_t count; + VkRect2D rect; + VkBool32 bval; + VkResult vr; + + pvkGetPhysicalDeviceSurfacePresentModesKHR = (void *)vkGetInstanceProcAddr(vk_instance, + "vkGetPhysicalDeviceSurfacePresentModesKHR"); + surface_create_info.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; + surface_create_info.pNext = NULL; + surface_create_info.flags = 0; + surface_create_info.hinstance = NULL; + surface_create_info.hwnd = NULL; + + bval = find_queue_family(vk_physical_device, VK_QUEUE_GRAPHICS_BIT, &queue_family_index); + ok(bval, "Could not find presentation queue.\n"); + + surface = 0xdeadbeef; + vr = vkCreateWin32SurfaceKHR(vk_instance, &surface_create_info, NULL, &surface); + ok(vr == VK_SUCCESS, "Got unexpected vr %d.\n", vr); + ok(surface != 0xdeadbeef, "Surface not created.\n"); + + count = 0; + vr = vkGetPhysicalDeviceSurfaceFormatsKHR(vk_physical_device, surface, &count, NULL); + ok(vr == VK_SUCCESS, "Got unexpected vr %d.\n", vr); + ok(count, "Got zero count.\n"); + formats = heap_alloc(sizeof(*formats) * count); + vr = vkGetPhysicalDeviceSurfaceFormatsKHR(vk_physical_device, surface, &count, formats); + ok(vr == VK_SUCCESS, "Got unexpected vr %d.\n", vr); + heap_free(formats); + + vr = vkGetPhysicalDeviceSurfaceSupportKHR(vk_physical_device, queue_family_index, surface, &bval); + ok(vr == VK_SUCCESS, "Got unexpected vr %d.\n", vr); + + vr = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vk_physical_device, surface, &surf_caps); + ok(vr, "vkGetPhysicalDeviceSurfaceCapabilitiesKHR succeeded.\n"); + + count = 0; + vr = pvkGetPhysicalDeviceSurfacePresentModesKHR(vk_physical_device, surface, &count, NULL); + ok(vr == VK_SUCCESS, "Got unexpected vr %d.\n", vr); + ok(count, "Got zero count.\n"); + modes = heap_alloc(sizeof(*modes) * count); + vr = pvkGetPhysicalDeviceSurfacePresentModesKHR(vk_physical_device, surface, &count, modes); + ok(vr == VK_SUCCESS, "Got unexpected vr %d.\n", vr); + heap_free(modes); + + count = 0; + vr = vkGetPhysicalDevicePresentRectanglesKHR(vk_physical_device, surface, &count, NULL); + ok(vr == VK_SUCCESS, "Got unexpected vr %d.\n", vr); + ok(count == 1, "Got unexpected count %u.\n", count); + memset(&rect, 0xcc, sizeof(rect)); + vr = vkGetPhysicalDevicePresentRectanglesKHR(vk_physical_device, surface, &count, &rect); + if (vr == VK_SUCCESS) /* Fails on AMD, succeeds on Nvidia. */ + { + ok(count == 1, "Got unexpected count %u.\n", count); + ok(!rect.offset.x && !rect.offset.y && !rect.extent.width && !rect.extent.height, + "Got unexpected rect %d, %d, %u, %u.\n", + rect.offset.x, rect.offset.y, rect.extent.width, rect.extent.height); + } + + if ((vr = create_device(vk_physical_device, 0, NULL, NULL, &vk_device)) < 0) + { + skip("Failed to create device, vr %d.\n", vr); + vkDestroySurfaceKHR(vk_instance, surface, NULL); + return; + } + + if (0) + { + /* Causes access violation on Windows. */ + vr = vkGetDeviceGroupSurfacePresentModesKHR(vk_device, surface, &present_mode_flags); + ok(vr == VK_SUCCESS, "Got unexpected vr %d.\n", vr); + } + + vkDestroyDevice(vk_device, NULL); + vkDestroySurfaceKHR(vk_instance, surface, NULL); +} + +static void for_each_device_instance(uint32_t extension_count, const char * const *enabled_extensions, + void (*test_func_instance)(VkInstance, VkPhysicalDevice), void (*test_func)(VkPhysicalDevice)) { VkPhysicalDevice *vk_physical_devices; VkInstance vk_instance; @@ -445,7 +540,7 @@ static void for_each_device(void (*test_func)(VkPhysicalDevice)) uint32_t count; VkResult vr; - if ((vr = create_instance_skip(0, NULL, &vk_instance)) < 0) + if ((vr = create_instance_skip(extension_count, enabled_extensions, &vk_instance)) < 0) return; ok(vr == VK_SUCCESS, "Got unexpected VkResult %d.\n", vr); @@ -463,13 +558,23 @@ static void for_each_device(void (*test_func)(VkPhysicalDevice)) ok(vr == VK_SUCCESS, "Got unexpected VkResult %d.\n", vr); for (i = 0; i < count; ++i) - test_func(vk_physical_devices[i]); + { + if (test_func_instance) + test_func_instance(vk_instance, vk_physical_devices[i]); + else + test_func(vk_physical_devices[i]); + } heap_free(vk_physical_devices); vkDestroyInstance(vk_instance, NULL); } +static void for_each_device(void (*test_func)(VkPhysicalDevice)) +{ + for_each_device_instance(0, NULL, NULL, test_func); +} + START_TEST(vulkan) { test_instance_version(); @@ -481,4 +586,5 @@ START_TEST(vulkan) test_unsupported_instance_extensions(); for_each_device(test_unsupported_device_extensions); for_each_device(test_private_data); + for_each_device_instance(ARRAY_SIZE(test_null_hwnd_extensions), test_null_hwnd_extensions, test_null_hwnd, NULL); } diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c index 139faf6b407..bdc287afeea 100644 --- a/dlls/winex11.drv/vulkan.c +++ b/dlls/winex11.drv/vulkan.c @@ -62,6 +62,7 @@ struct wine_vk_surface LONG ref; Window window; VkSurfaceKHR surface; /* native surface */ + HWND hwnd; }; typedef struct VkXlibSurfaceCreateInfoKHR @@ -255,14 +256,18 @@ static VkResult X11DRV_vkCreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR *create_info, const VkAllocationCallbacks *allocator, VkSwapchainKHR *swapchain) { + struct wine_vk_surface *x11_surface = surface_from_handle(create_info->surface); VkSwapchainCreateInfoKHR create_info_host; TRACE("%p %p %p %p\n", device, create_info, allocator, swapchain); if (allocator) FIXME("Support for allocation callbacks not implemented yet\n"); + if (!x11_surface->hwnd) + return VK_ERROR_SURFACE_LOST_KHR; + create_info_host = *create_info; - create_info_host.surface = surface_from_handle(create_info->surface)->surface; + create_info_host.surface = x11_surface->surface; return pvkCreateSwapchainKHR(device, &create_info_host, NULL /* allocator */, swapchain); } @@ -281,7 +286,7 @@ static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance, FIXME("Support for allocation callbacks not implemented yet\n"); /* TODO: support child window rendering. */ - if (GetAncestor(create_info->hwnd, GA_PARENT) != GetDesktopWindow()) + if (create_info->hwnd && GetAncestor(create_info->hwnd, GA_PARENT) != GetDesktopWindow()) { FIXME("Application requires child window rendering, which is not implemented yet!\n"); return VK_ERROR_INCOMPATIBLE_DRIVER; @@ -292,8 +297,10 @@ static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance, return VK_ERROR_OUT_OF_HOST_MEMORY; 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(); - x11_surface->window = create_client_window(create_info->hwnd, &default_visual); if (!x11_surface->window) { ERR("Failed to allocate client window for hwnd=%p\n", create_info->hwnd); @@ -316,13 +323,16 @@ static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance, goto err; } - EnterCriticalSection(&context_section); - if (!XFindContext(gdi_display, (XID)create_info->hwnd, vulkan_hwnd_context, (char **)&prev)) + if (x11_surface->hwnd) { - wine_vk_surface_release(prev); + 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); } - 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; @@ -456,6 +466,15 @@ static VkResult X11DRV_vkGetPhysicalDevicePresentRectanglesKHR(VkPhysicalDevice TRACE("%p, 0x%s, %p, %p\n", phys_dev, wine_dbgstr_longlong(surface), count, rects); + if (!x11_surface->hwnd) + { + if (rects) + return VK_ERROR_SURFACE_LOST_KHR; + + *count = 1; + return VK_SUCCESS; + } + return pvkGetPhysicalDevicePresentRectanglesKHR(phys_dev, x11_surface->surface, count, rects); } @@ -485,6 +504,9 @@ static VkResult X11DRV_vkGetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevic TRACE("%p, 0x%s, %p\n", phys_dev, wine_dbgstr_longlong(surface), capabilities); + if (!x11_surface->hwnd) + return VK_ERROR_SURFACE_LOST_KHR; + return pvkGetPhysicalDeviceSurfaceCapabilitiesKHR(phys_dev, x11_surface->surface, capabilities); } diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index baaa30d74e3..b3ae5c54408 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1466,6 +1466,24 @@ static Window get_dummy_parent(void) } +/********************************************************************** + * create_dummy_client_window + */ +Window create_dummy_client_window(void) +{ + XSetWindowAttributes attr; + + attr.colormap = default_colormap; + attr.bit_gravity = NorthWestGravity; + attr.win_gravity = NorthWestGravity; + attr.backing_store = NotUseful; + attr.border_pixel = 0; + + return XCreateWindow( gdi_display, get_dummy_parent(), 0, 0, 1, 1, 0, + default_visual.depth, InputOutput, default_visual.visual, + CWBitGravity | CWWinGravity | CWBackingStore | CWColormap | CWBorderPixel, &attr ); +} + /********************************************************************** * create_client_window */ diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 45855976607..2362dfd9563 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -601,6 +601,7 @@ extern void update_user_time( Time time ) DECLSPEC_HIDDEN; extern void read_net_wm_states( Display *display, struct x11drv_win_data *data ) DECLSPEC_HIDDEN; extern void update_net_wm_states( struct x11drv_win_data *data ) DECLSPEC_HIDDEN; extern void make_window_embedded( struct x11drv_win_data *data ) DECLSPEC_HIDDEN; +extern Window create_dummy_client_window(void) DECLSPEC_HIDDEN; extern Window create_client_window( HWND hwnd, const XVisualInfo *visual ) DECLSPEC_HIDDEN; extern void set_window_visual( struct x11drv_win_data *data, const XVisualInfo *vis, BOOL use_alpha ) DECLSPEC_HIDDEN; extern void change_systray_owner( Display *display, Window systray_window ) DECLSPEC_HIDDEN;