Signed-off-by: Paul Gofman pgofman@codeweavers.com --- For Red Dead Redemption 2. v2: - store hwnd in struct wine_vk_surface instead of a dedicated flag. v3: - create_dummy_client_window() function name in comment; - formatting.
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;
Hi,
On Mon, 3 May 2021, Paul Gofman wrote: [...]
- vr = vkGetPhysicalDevicePresentRectanglesKHR(vk_physical_device, surface, &count, NULL);
This patch prevents vulkan-1:vulkan from running on cw-rx460 and cw-gtx560. Given that these are the only two machines that run WineTest on real GPUs it's a bit of a shame :-(
https://test.winehq.org/data/patterns.html#vulkan-1:vulkan
In the cw-gtx560 case it's because it is missing vkGetPhysicalDevicePresentRectanglesKHR(). The Windows 10 2009 snapshot has the Nividia 391.35 driver and as far as I can tell there is no newer version available (I attached the driver's full system information just in case).
It would be nice to load it dynamically and optinally skip some tests if not available.
I suspect cw-rx460 has the same problem but it's running tests right now (it's has Adrenalin 21.4.1 because I updated it last week and of course they just released 21.5.1 yesterday!).
Hello Francois,
how can I run the test on these machines? I think before sending this patch a few days ago I run it on testbot selecting all the available VMs and there weren't any failures.
And yes, I think I am missing VK_KHR_device_group_creationextension for the test to be skipped correctly, while ideally it would be better to test this change on failing machines before sending.
Regards, Paul.
On 5/7/21 13:24, Francois Gouget wrote:
Hi,
On Mon, 3 May 2021, Paul Gofman wrote: [...]
- vr = vkGetPhysicalDevicePresentRectanglesKHR(vk_physical_device, surface, &count, NULL);
This patch prevents vulkan-1:vulkan from running on cw-rx460 and cw-gtx560. Given that these are the only two machines that run WineTest on real GPUs it's a bit of a shame :-(
https://test.winehq.org/data/patterns.html#vulkan-1:vulkan
In the cw-gtx560 case it's because it is missing vkGetPhysicalDevicePresentRectanglesKHR(). The Windows 10 2009 snapshot has the Nividia 391.35 driver and as far as I can tell there is no newer version available (I attached the driver's full system information just in case).
It would be nice to load it dynamically and optinally skip some tests if not available.
I suspect cw-rx460 has the same problem but it's running tests right now (it's has Adrenalin 21.4.1 because I updated it last week and of course they just released 21.5.1 yesterday!).
On Fri, 7 May 2021, Paul Gofman wrote:
Hello Francois,
how can I run the test on these machines? I think before sending this patch a few days ago I run it on testbot selecting all the available VMs and there weren't any failures.
They are not VMs so they are not part of the TestBot. But I can run tests on them (usually, I'm having KVM trouble today).
On 5/7/21 15:34, Francois Gouget wrote:
On Fri, 7 May 2021, Paul Gofman wrote:
Hello Francois,
how can I run the test on these machines? I think before sending this patch a few days ago I run it on testbot selecting all the available VMs and there weren't any failures.
They are not VMs so they are not part of the TestBot. But I can run tests on them (usually, I'm having KVM trouble today).
I've sent the patch for this: https://source.winehq.org/patches/data/205348
Hope that works.