This is the third (and last) part of the Wayland driver Vulkan subseries:
1. Implement `vkQueuePresentKHR` and support reporting `VK_ERROR_OUT_OF_DATE_KHR` and `VK_ERROR_SURFACE_LOST_KHR`. 2. Misc. enhancements/fixes to ensure the subsurface containing the vulkan rendering is displayed properly. 3. Implement a couple of remaining Vulkan functions.
With this MR you can start enjoying some of your games with the Wayland driver (either directly with Vulkan or with a D3D->Vulkan translation). Please note, however, that we don't currently support what's needed for mouselook (you will currently get erratic view movement), so most first-person 3D games are not playable yet.
Thanks!
From: Alexandros Frantzis alexandros.frantzis@collabora.com
--- dlls/winewayland.drv/vulkan.c | 10 ++++++++++ dlls/winewayland.drv/wayland_surface.c | 2 ++ 2 files changed, 12 insertions(+)
diff --git a/dlls/winewayland.drv/vulkan.c b/dlls/winewayland.drv/vulkan.c index 5ecf3787656..7f73286ec5f 100644 --- a/dlls/winewayland.drv/vulkan.c +++ b/dlls/winewayland.drv/vulkan.c @@ -68,6 +68,7 @@ static VkResult (*pvkGetPhysicalDeviceSurfacePresentModesKHR)(VkPhysicalDevice, static VkResult (*pvkGetPhysicalDeviceSurfaceSupportKHR)(VkPhysicalDevice, uint32_t, VkSurfaceKHR, VkBool32 *); static VkBool32 (*pvkGetPhysicalDeviceWaylandPresentationSupportKHR)(VkPhysicalDevice, uint32_t, struct wl_display *); static VkResult (*pvkGetSwapchainImagesKHR)(VkDevice, VkSwapchainKHR, uint32_t *, VkImage *); +static VkResult (*pvkQueuePresentKHR)(VkQueue, const VkPresentInfoKHR *);
static void *vulkan_handle; static const struct vulkan_funcs vulkan_funcs; @@ -633,6 +634,13 @@ static VkResult wayland_vkGetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR return pvkGetSwapchainImagesKHR(device, swapchain, count, images); }
+static VkResult wayland_vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *present_info) +{ + TRACE("%p, %p\n", queue, present_info); + + return pvkQueuePresentKHR(queue, present_info); +} + static VkSurfaceKHR wayland_wine_get_native_surface(VkSurfaceKHR surface) { return wine_vk_surface_from_handle(surface)->native; @@ -665,6 +673,7 @@ static void wine_vk_init(void) LOAD_FUNCPTR(vkGetPhysicalDeviceSurfaceSupportKHR); LOAD_FUNCPTR(vkGetPhysicalDeviceWaylandPresentationSupportKHR); LOAD_FUNCPTR(vkGetSwapchainImagesKHR); + LOAD_FUNCPTR(vkQueuePresentKHR); #undef LOAD_FUNCPTR #undef LOAD_OPTIONAL_FUNCPTR
@@ -694,6 +703,7 @@ static const struct vulkan_funcs vulkan_funcs = .p_vkGetPhysicalDeviceSurfaceSupportKHR = wayland_vkGetPhysicalDeviceSurfaceSupportKHR, .p_vkGetPhysicalDeviceWin32PresentationSupportKHR = wayland_vkGetPhysicalDeviceWin32PresentationSupportKHR, .p_vkGetSwapchainImagesKHR = wayland_vkGetSwapchainImagesKHR, + .p_vkQueuePresentKHR = wayland_vkQueuePresentKHR, .p_wine_get_native_surface = wayland_wine_get_native_surface, };
diff --git a/dlls/winewayland.drv/wayland_surface.c b/dlls/winewayland.drv/wayland_surface.c index 5a808b3ac96..f71e15f2f9a 100644 --- a/dlls/winewayland.drv/wayland_surface.c +++ b/dlls/winewayland.drv/wayland_surface.c @@ -803,6 +803,8 @@ struct wayland_client_surface *wayland_surface_get_client(struct wayland_surface ERR("Failed to create client wl_subsurface\n"); goto err; } + /* Present contents independently of the parent surface. */ + wl_subsurface_set_desync(surface->client->wl_subsurface);
if (process_wayland.wp_viewporter) {
From: Alexandros Frantzis alexandros.frantzis@collabora.com
If the target HWND is no longer valid, report VK_ERROR_SURFACE_LOST_KHR.
If the VkSwapchainKHR extent does not match the target window client area, report VK_ERROR_OUT_OF_DATE_KHR, to notify the app that it should recreate the swapchain. --- dlls/winewayland.drv/vulkan.c | 126 +++++++++++++++++++++++++++++- dlls/winewayland.drv/waylanddrv.h | 1 + 2 files changed, 126 insertions(+), 1 deletion(-)
diff --git a/dlls/winewayland.drv/vulkan.c b/dlls/winewayland.drv/vulkan.c index 7f73286ec5f..ffdd9291a75 100644 --- a/dlls/winewayland.drv/vulkan.c +++ b/dlls/winewayland.drv/vulkan.c @@ -73,12 +73,23 @@ static VkResult (*pvkQueuePresentKHR)(VkQueue, const VkPresentInfoKHR *); static void *vulkan_handle; static const struct vulkan_funcs vulkan_funcs;
+static pthread_mutex_t wine_vk_swapchain_mutex = PTHREAD_MUTEX_INITIALIZER; +static struct list wine_vk_swapchain_list = LIST_INIT(wine_vk_swapchain_list); + struct wine_vk_surface { struct wayland_client_surface *client; VkSurfaceKHR native; };
+struct wine_vk_swapchain +{ + struct list entry; + VkSwapchainKHR native; + HWND hwnd; + VkExtent2D extent; +}; + static struct wine_vk_surface *wine_vk_surface_from_handle(VkSurfaceKHR handle) { return (struct wine_vk_surface *)(uintptr_t)handle; @@ -122,6 +133,33 @@ static BOOL wine_vk_surface_is_valid(struct wine_vk_surface *wine_vk_surface) return FALSE; }
+static struct wine_vk_swapchain *wine_vk_swapchain_from_handle(VkSwapchainKHR handle) +{ + struct wine_vk_swapchain *wine_vk_swapchain; + + pthread_mutex_lock(&wine_vk_swapchain_mutex); + LIST_FOR_EACH_ENTRY(wine_vk_swapchain, &wine_vk_swapchain_list, + struct wine_vk_swapchain, entry) + { + if (wine_vk_swapchain->native == handle) + { + pthread_mutex_unlock(&wine_vk_swapchain_mutex); + return wine_vk_swapchain; + } + } + pthread_mutex_unlock(&wine_vk_swapchain_mutex); + + return NULL; +} + +static void wine_vk_swapchain_destroy(struct wine_vk_swapchain *wine_vk_swapchain) +{ + pthread_mutex_lock(&wine_vk_swapchain_mutex); + list_remove(&wine_vk_swapchain->entry); + pthread_mutex_unlock(&wine_vk_swapchain_mutex); + free(wine_vk_swapchain); +} + /* Helper function for converting between win32 and Wayland compatible VkInstanceCreateInfo. * Caller is responsible for allocation and cleanup of 'dst'. */ static VkResult wine_vk_instance_convert_create_info(const VkInstanceCreateInfo *src, @@ -206,6 +244,67 @@ static VkResult wine_vk_surface_update_caps(struct wine_vk_surface *wine_vk_surf return VK_SUCCESS; }
+/* Rate the severity of a VkResult according to Vulkan spec rules that + * specify which result to return for vkQueuePresentKHR calls with + * multiple swapchains. */ +static int vk_result_severity(VkResult res) +{ + switch(res) + { + case VK_SUCCESS: return 0; + case VK_SUBOPTIMAL_KHR: return 1; + case VK_ERROR_OUT_OF_DATE_KHR: return 3; + case VK_ERROR_SURFACE_LOST_KHR: return 4; + case VK_ERROR_DEVICE_LOST: return 5; + case VK_ERROR_OUT_OF_DEVICE_MEMORY: return 6; + case VK_ERROR_OUT_OF_HOST_MEMORY: return 7; + /* For unhandled results return the lowest non-success severity. */ + default: return 2; + } +} + +static void vk_result_update_severity(VkResult *res1, VkResult res2) +{ + if (vk_result_severity(res2) > vk_result_severity(*res1)) *res1 = res2; +} + +static VkResult check_queue_present(const VkPresentInfoKHR *present_info, + VkResult present_res) +{ + VkResult res = present_res; + uint32_t i; + + for (i = 0; i < present_info->swapchainCount; ++i) + { + struct wine_vk_swapchain *wine_vk_swapchain = + wine_vk_swapchain_from_handle(present_info->pSwapchains[i]); + HWND hwnd = wine_vk_swapchain->hwnd; + struct wayland_surface *wayland_surface; + + if ((wayland_surface = wayland_surface_lock_hwnd(hwnd))) + { + int client_width = wayland_surface->window.client_rect.right - + wayland_surface->window.client_rect.left; + int client_height = wayland_surface->window.client_rect.bottom - + wayland_surface->window.client_rect.top; + + pthread_mutex_unlock(&wayland_surface->mutex); + + if (client_width != wine_vk_swapchain->extent.width || + client_height != wine_vk_swapchain->extent.height) + { + vk_result_update_severity(&res, VK_ERROR_OUT_OF_DATE_KHR); + } + } + else + { + vk_result_update_severity(&res, VK_ERROR_SURFACE_LOST_KHR); + } + } + + return res; +} + static VkResult wayland_vkCreateInstance(const VkInstanceCreateInfo *create_info, const VkAllocationCallbacks *allocator, VkInstance *instance) @@ -242,6 +341,7 @@ static VkResult wayland_vkCreateSwapchainKHR(VkDevice device, VkResult res; VkSwapchainCreateInfoKHR create_info_host; struct wine_vk_surface *wine_vk_surface; + struct wine_vk_swapchain *wine_vk_swapchain;
TRACE("%p %p %p %p\n", device, create_info, allocator, swapchain);
@@ -252,6 +352,14 @@ static VkResult wayland_vkCreateSwapchainKHR(VkDevice device, if (!wine_vk_surface_is_valid(wine_vk_surface)) return VK_ERROR_SURFACE_LOST_KHR;
+ wine_vk_swapchain = calloc(1, sizeof(*wine_vk_swapchain)); + if (!wine_vk_swapchain) + return VK_ERROR_OUT_OF_HOST_MEMORY; + + list_init(&wine_vk_swapchain->entry); + wine_vk_swapchain->hwnd = wine_vk_surface_get_hwnd(wine_vk_surface); + wine_vk_swapchain->extent = create_info->imageExtent; + create_info_host = *create_info; create_info_host.surface = wine_vk_surface->native;
@@ -270,9 +378,16 @@ static VkResult wayland_vkCreateSwapchainKHR(VkDevice device, if (res != VK_SUCCESS) { ERR("Failed to create vulkan wayland swapchain, res=%d\n", res); + wine_vk_swapchain_destroy(wine_vk_swapchain); return res; }
+ wine_vk_swapchain->native = *swapchain; + + pthread_mutex_lock(&wine_vk_swapchain_mutex); + list_add_head(&wine_vk_swapchain_list, &wine_vk_swapchain->entry); + pthread_mutex_unlock(&wine_vk_swapchain_mutex); + TRACE("Created swapchain=0x%s\n", wine_dbgstr_longlong(*swapchain)); return res; } @@ -377,12 +492,17 @@ static void wayland_vkDestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks *allocator) { + struct wine_vk_swapchain *wine_vk_swapchain; + TRACE("%p, 0x%s %p\n", device, wine_dbgstr_longlong(swapchain), allocator);
if (allocator) FIXME("Support for allocation callbacks not implemented yet\n");
pvkDestroySwapchainKHR(device, swapchain, NULL /* allocator */); + + if ((wine_vk_swapchain = wine_vk_swapchain_from_handle(swapchain))) + wine_vk_swapchain_destroy(wine_vk_swapchain); }
static VkResult wayland_vkEnumerateInstanceExtensionProperties(const char *layer_name, @@ -636,9 +756,13 @@ static VkResult wayland_vkGetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR
static VkResult wayland_vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *present_info) { + VkResult res; + TRACE("%p, %p\n", queue, present_info);
- return pvkQueuePresentKHR(queue, present_info); + res = pvkQueuePresentKHR(queue, present_info); + + return check_queue_present(present_info, res); }
static VkSurfaceKHR wayland_wine_get_native_surface(VkSurfaceKHR surface) diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h index 00c9112d5de..c7d730fbd3e 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -36,6 +36,7 @@ #include "winbase.h" #include "ntgdi.h" #include "wine/gdi_driver.h" +#include "wine/list.h" #include "wine/rbtree.h"
#include "unixlib.h"
From: Alexandros Frantzis alexandros.frantzis@collabora.com
--- dlls/winewayland.drv/vulkan.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/dlls/winewayland.drv/vulkan.c b/dlls/winewayland.drv/vulkan.c index ffdd9291a75..396acdbc174 100644 --- a/dlls/winewayland.drv/vulkan.c +++ b/dlls/winewayland.drv/vulkan.c @@ -280,6 +280,7 @@ static VkResult check_queue_present(const VkPresentInfoKHR *present_info, wine_vk_swapchain_from_handle(present_info->pSwapchains[i]); HWND hwnd = wine_vk_swapchain->hwnd; struct wayland_surface *wayland_surface; + VkResult swap_res;
if ((wayland_surface = wayland_surface_lock_hwnd(hwnd))) { @@ -293,13 +294,21 @@ static VkResult check_queue_present(const VkPresentInfoKHR *present_info, if (client_width != wine_vk_swapchain->extent.width || client_height != wine_vk_swapchain->extent.height) { - vk_result_update_severity(&res, VK_ERROR_OUT_OF_DATE_KHR); + swap_res = VK_ERROR_OUT_OF_DATE_KHR; + } + else + { + swap_res = VK_SUCCESS; } } else { - vk_result_update_severity(&res, VK_ERROR_SURFACE_LOST_KHR); + swap_res = VK_ERROR_SURFACE_LOST_KHR; } + + if (present_info->pResults) + vk_result_update_severity(&present_info->pResults[i], swap_res); + vk_result_update_severity(&res, swap_res); }
return res;
From: Alexandros Frantzis alexandros.frantzis@collabora.com
The client area subsurface (the target of Vulkan rendering) is not going to be presented by the compositor if its parent surface is not mapped, even though the window may be visible from Wine's perspective. To avoid this issue, ensure that the parent surface has valid contents, in case these haven't been provided yet, or will never be provided (e.g., when the Vulkan rendering is fullscreen). --- dlls/winewayland.drv/vulkan.c | 2 + dlls/winewayland.drv/wayland_surface.c | 60 ++++++++++++++++++++++++++ dlls/winewayland.drv/waylanddrv.h | 3 ++ dlls/winewayland.drv/window.c | 12 +++++- 4 files changed, 75 insertions(+), 2 deletions(-)
diff --git a/dlls/winewayland.drv/vulkan.c b/dlls/winewayland.drv/vulkan.c index 396acdbc174..ca559d1ea65 100644 --- a/dlls/winewayland.drv/vulkan.c +++ b/dlls/winewayland.drv/vulkan.c @@ -289,6 +289,8 @@ static VkResult check_queue_present(const VkPresentInfoKHR *present_info, int client_height = wayland_surface->window.client_rect.bottom - wayland_surface->window.client_rect.top;
+ wayland_surface_ensure_contents(wayland_surface); + pthread_mutex_unlock(&wayland_surface->mutex);
if (client_width != wine_vk_swapchain->extent.width || diff --git a/dlls/winewayland.drv/wayland_surface.c b/dlls/winewayland.drv/wayland_surface.c index f71e15f2f9a..166c1bba002 100644 --- a/dlls/winewayland.drv/wayland_surface.c +++ b/dlls/winewayland.drv/wayland_surface.c @@ -336,6 +336,8 @@ void wayland_surface_attach_shm(struct wayland_surface *surface, } free(surface_damage); } + + surface->needs_contents = FALSE; }
/********************************************************************** @@ -825,3 +827,61 @@ err: } return NULL; } + +static void dummy_buffer_release(void *data, struct wl_buffer *buffer) +{ + struct wayland_shm_buffer *shm_buffer = data; + TRACE("shm_buffer=%p\n", shm_buffer); + wayland_shm_buffer_unref(shm_buffer); +} + +static const struct wl_buffer_listener dummy_buffer_listener = +{ + dummy_buffer_release +}; + +/********************************************************************** + * wayland_surface_ensure_contents + * + * Ensure that the wayland surface has up-to-date contents, by committing + * a dummy buffer if necessary. + */ +void wayland_surface_ensure_contents(struct wayland_surface *surface) +{ + struct wayland_shm_buffer *dummy_shm_buffer; + HRGN damage; + int width, height; + + TRACE("surface=%p hwnd=%p needs_contents=%d\n", + surface, surface->hwnd, surface->needs_contents); + + if (!surface->needs_contents) return; + + width = surface->window.rect.right - surface->window.rect.left; + height = surface->window.rect.bottom - surface->window.rect.top; + + /* Create a transparent dummy buffer. */ + dummy_shm_buffer = wayland_shm_buffer_create(width, height, WL_SHM_FORMAT_ARGB8888); + if (!dummy_shm_buffer) + { + ERR("Failed to create dummy buffer\n"); + return; + } + wl_buffer_add_listener(dummy_shm_buffer->wl_buffer, &dummy_buffer_listener, + dummy_shm_buffer); + + if (!(damage = NtGdiCreateRectRgn(0, 0, width, height))) + WARN("Failed to create damage region for dummy buffer\n"); + + if (wayland_surface_reconfigure(surface)) + { + wayland_surface_attach_shm(surface, dummy_shm_buffer, damage); + wl_surface_commit(surface->wl_surface); + } + else + { + wayland_shm_buffer_unref(dummy_shm_buffer); + } + + if (damage) NtGdiDeleteObjectApp(damage); +} diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h index c7d730fbd3e..0516e1cbd91 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -187,6 +187,7 @@ struct wayland_surface BOOL resizing; struct wayland_window_config window; struct wayland_client_surface *client; + BOOL needs_contents; };
struct wayland_shm_buffer @@ -240,6 +241,8 @@ void wayland_surface_coords_to_window(struct wayland_surface *surface, int *window_x, int *window_y) DECLSPEC_HIDDEN; struct wayland_client_surface *wayland_surface_get_client(struct wayland_surface *surface) DECLSPEC_HIDDEN; BOOL wayland_client_surface_release(struct wayland_client_surface *client) DECLSPEC_HIDDEN; +void wayland_surface_ensure_contents(struct wayland_surface *surface) DECLSPEC_HIDDEN; +
/********************************************************************** * Wayland SHM buffer diff --git a/dlls/winewayland.drv/window.c b/dlls/winewayland.drv/window.c index fff3749e9ad..f30b3a88c74 100644 --- a/dlls/winewayland.drv/window.c +++ b/dlls/winewayland.drv/window.c @@ -183,7 +183,8 @@ static void wayland_win_data_get_config(struct wayland_win_data *data, conf->scale = NtUserGetDpiForWindow(data->hwnd) / 96.0; }
-static void wayland_win_data_update_wayland_surface(struct wayland_win_data *data) +static void wayland_win_data_update_wayland_surface(struct wayland_win_data *data, + BOOL has_new_window_surface) { struct wayland_surface *surface = data->wayland_surface; HWND parent = NtUserGetAncestor(data->hwnd, GA_PARENT); @@ -221,6 +222,11 @@ static void wayland_win_data_update_wayland_surface(struct wayland_win_data *dat
wayland_win_data_get_config(data, &surface->window);
+ if (!visible) + surface->needs_contents = FALSE; + else if (xdg_visible != visible || has_new_window_surface) + surface->needs_contents = TRUE; + pthread_mutex_unlock(&surface->mutex);
if (data->window_surface) @@ -359,6 +365,7 @@ void WAYLAND_WindowPosChanged(HWND hwnd, HWND insert_after, UINT swp_flags, struct window_surface *surface) { struct wayland_win_data *data = wayland_win_data_get(hwnd); + BOOL has_new_window_surface;
TRACE("hwnd %p window %s client %s visible %s after %p flags %08x\n", hwnd, wine_dbgstr_rect(window_rect), wine_dbgstr_rect(client_rect), @@ -369,11 +376,12 @@ void WAYLAND_WindowPosChanged(HWND hwnd, HWND insert_after, UINT swp_flags, data->window_rect = *window_rect; data->client_rect = *client_rect;
+ has_new_window_surface = surface != data->window_surface; if (surface) window_surface_add_ref(surface); if (data->window_surface) window_surface_release(data->window_surface); data->window_surface = surface;
- wayland_win_data_update_wayland_surface(data); + wayland_win_data_update_wayland_surface(data, has_new_window_surface); if (data->wayland_surface) wayland_win_data_update_wayland_state(data);
wayland_win_data_release(data);
From: Alexandros Frantzis alexandros.frantzis@collabora.com
We cannot depend on the main surface being committed to after the client subsurface is created, so perform a commit to ensure the subsurface position takes effect on creation. --- dlls/winewayland.drv/wayland_surface.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/dlls/winewayland.drv/wayland_surface.c b/dlls/winewayland.drv/wayland_surface.c index 166c1bba002..72b14afbc67 100644 --- a/dlls/winewayland.drv/wayland_surface.c +++ b/dlls/winewayland.drv/wayland_surface.c @@ -816,6 +816,8 @@ struct wayland_client_surface *wayland_surface_get_client(struct wayland_surface }
wayland_surface_reconfigure_client(surface); + /* Commit to apply subsurface positioning. */ + wl_surface_commit(surface->wl_surface);
return surface->client;
From: Alexandros Frantzis alexandros.frantzis@collabora.com
This is a simple passthrough implementation to the native Vulkan driver, with the addition of a VkSurfaceKHR invalidation check. --- dlls/winewayland.drv/vulkan.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+)
diff --git a/dlls/winewayland.drv/vulkan.c b/dlls/winewayland.drv/vulkan.c index ca559d1ea65..fb5374d3396 100644 --- a/dlls/winewayland.drv/vulkan.c +++ b/dlls/winewayland.drv/vulkan.c @@ -58,6 +58,7 @@ static void (*pvkDestroyInstance)(VkInstance, const VkAllocationCallbacks *); static void (*pvkDestroySurfaceKHR)(VkInstance, VkSurfaceKHR, const VkAllocationCallbacks *); static void (*pvkDestroySwapchainKHR)(VkDevice, VkSwapchainKHR, const VkAllocationCallbacks *); static VkResult (*pvkEnumerateInstanceExtensionProperties)(const char *, uint32_t *, VkExtensionProperties *); +static VkResult (*pvkGetDeviceGroupSurfacePresentModesKHR)(VkDevice, VkSurfaceKHR, VkDeviceGroupPresentModeFlagsKHR *); static void * (*pvkGetDeviceProcAddr)(VkDevice, const char *); static void * (*pvkGetInstanceProcAddr)(VkInstance, const char *); static VkResult (*pvkGetPhysicalDeviceSurfaceCapabilities2KHR)(VkPhysicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR *, VkSurfaceCapabilities2KHR *); @@ -558,6 +559,20 @@ static VkResult wayland_vkEnumerateInstanceExtensionProperties(const char *layer return res; }
+static VkResult wayland_vkGetDeviceGroupSurfacePresentModesKHR(VkDevice device, + VkSurfaceKHR surface, + VkDeviceGroupPresentModeFlagsKHR *flags) +{ + struct wine_vk_surface *wine_vk_surface = wine_vk_surface_from_handle(surface); + + TRACE("%p, 0x%s, %p\n", device, wine_dbgstr_longlong(surface), flags); + + if (!wine_vk_surface_is_valid(wine_vk_surface)) + return VK_ERROR_SURFACE_LOST_KHR; + + return pvkGetDeviceGroupSurfacePresentModesKHR(device, wine_vk_surface->native, flags); +} + static void *wayland_vkGetDeviceProcAddr(VkDevice device, const char *name) { void *proc_addr; @@ -798,6 +813,7 @@ static void wine_vk_init(void) LOAD_FUNCPTR(vkDestroySurfaceKHR); LOAD_FUNCPTR(vkDestroySwapchainKHR); LOAD_FUNCPTR(vkEnumerateInstanceExtensionProperties); + LOAD_OPTIONAL_FUNCPTR(vkGetDeviceGroupSurfacePresentModesKHR); LOAD_FUNCPTR(vkGetDeviceProcAddr); LOAD_FUNCPTR(vkGetInstanceProcAddr); LOAD_OPTIONAL_FUNCPTR(vkGetPhysicalDeviceSurfaceCapabilities2KHR); @@ -828,6 +844,7 @@ static const struct vulkan_funcs vulkan_funcs = .p_vkDestroySurfaceKHR = wayland_vkDestroySurfaceKHR, .p_vkDestroySwapchainKHR = wayland_vkDestroySwapchainKHR, .p_vkEnumerateInstanceExtensionProperties = wayland_vkEnumerateInstanceExtensionProperties, + .p_vkGetDeviceGroupSurfacePresentModesKHR = wayland_vkGetDeviceGroupSurfacePresentModesKHR, .p_vkGetDeviceProcAddr = wayland_vkGetDeviceProcAddr, .p_vkGetInstanceProcAddr = wayland_vkGetInstanceProcAddr, .p_vkGetPhysicalDeviceSurfaceCapabilities2KHR = wayland_vkGetPhysicalDeviceSurfaceCapabilities2KHR,
From: Alexandros Frantzis alexandros.frantzis@collabora.com
This is a simple passthrough implementation to the native Vulkan driver. --- dlls/winewayland.drv/vulkan.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
diff --git a/dlls/winewayland.drv/vulkan.c b/dlls/winewayland.drv/vulkan.c index fb5374d3396..15adc26c551 100644 --- a/dlls/winewayland.drv/vulkan.c +++ b/dlls/winewayland.drv/vulkan.c @@ -61,6 +61,7 @@ static VkResult (*pvkEnumerateInstanceExtensionProperties)(const char *, uint32_ static VkResult (*pvkGetDeviceGroupSurfacePresentModesKHR)(VkDevice, VkSurfaceKHR, VkDeviceGroupPresentModeFlagsKHR *); static void * (*pvkGetDeviceProcAddr)(VkDevice, const char *); static void * (*pvkGetInstanceProcAddr)(VkInstance, const char *); +static VkResult (*pvkGetPhysicalDevicePresentRectanglesKHR)(VkPhysicalDevice, VkSurfaceKHR, uint32_t *, VkRect2D *); static VkResult (*pvkGetPhysicalDeviceSurfaceCapabilities2KHR)(VkPhysicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR *, VkSurfaceCapabilities2KHR *); static VkResult (*pvkGetPhysicalDeviceSurfaceCapabilitiesKHR)(VkPhysicalDevice, VkSurfaceKHR, VkSurfaceCapabilitiesKHR *); static VkResult (*pvkGetPhysicalDeviceSurfaceFormats2KHR)(VkPhysicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR *, uint32_t *, VkSurfaceFormat2KHR *); @@ -607,6 +608,18 @@ static void *wayland_vkGetInstanceProcAddr(VkInstance instance, const char *name return pvkGetInstanceProcAddr(instance, name); }
+static VkResult wayland_vkGetPhysicalDevicePresentRectanglesKHR(VkPhysicalDevice phys_dev, + VkSurfaceKHR surface, + uint32_t *count, VkRect2D *rects) +{ + struct wine_vk_surface *wine_vk_surface = wine_vk_surface_from_handle(surface); + + TRACE("%p, 0x%s, %p, %p\n", phys_dev, wine_dbgstr_longlong(surface), count, rects); + + return pvkGetPhysicalDevicePresentRectanglesKHR(phys_dev, wine_vk_surface->native, + count, rects); +} + static VkResult wayland_vkGetPhysicalDeviceSurfaceCapabilities2KHR(VkPhysicalDevice phys_dev, const VkPhysicalDeviceSurfaceInfo2KHR *surface_info, VkSurfaceCapabilities2KHR *capabilities) @@ -816,6 +829,7 @@ static void wine_vk_init(void) LOAD_OPTIONAL_FUNCPTR(vkGetDeviceGroupSurfacePresentModesKHR); LOAD_FUNCPTR(vkGetDeviceProcAddr); LOAD_FUNCPTR(vkGetInstanceProcAddr); + LOAD_OPTIONAL_FUNCPTR(vkGetPhysicalDevicePresentRectanglesKHR); LOAD_OPTIONAL_FUNCPTR(vkGetPhysicalDeviceSurfaceCapabilities2KHR); LOAD_FUNCPTR(vkGetPhysicalDeviceSurfaceCapabilitiesKHR); LOAD_OPTIONAL_FUNCPTR(vkGetPhysicalDeviceSurfaceFormats2KHR); @@ -847,6 +861,7 @@ static const struct vulkan_funcs vulkan_funcs = .p_vkGetDeviceGroupSurfacePresentModesKHR = wayland_vkGetDeviceGroupSurfacePresentModesKHR, .p_vkGetDeviceProcAddr = wayland_vkGetDeviceProcAddr, .p_vkGetInstanceProcAddr = wayland_vkGetInstanceProcAddr, + .p_vkGetPhysicalDevicePresentRectanglesKHR = wayland_vkGetPhysicalDevicePresentRectanglesKHR, .p_vkGetPhysicalDeviceSurfaceCapabilities2KHR = wayland_vkGetPhysicalDeviceSurfaceCapabilities2KHR, .p_vkGetPhysicalDeviceSurfaceCapabilitiesKHR = wayland_vkGetPhysicalDeviceSurfaceCapabilitiesKHR, .p_vkGetPhysicalDeviceSurfaceFormats2KHR = wayland_vkGetPhysicalDeviceSurfaceFormats2KHR,
Rémi Bernon (@rbernon) commented about dlls/winewayland.drv/vulkan.c:
wayland_surface->window.client_rect.left;
int client_height = wayland_surface->window.client_rect.bottom -
wayland_surface->window.client_rect.top;
pthread_mutex_unlock(&wayland_surface->mutex);
if (client_width != wine_vk_swapchain->extent.width ||
client_height != wine_vk_swapchain->extent.height)
{
vk_result_update_severity(&res, VK_ERROR_OUT_OF_DATE_KHR);
}
}
else
{
vk_result_update_severity(&res, VK_ERROR_SURFACE_LOST_KHR);
}
I think you could make this simpler and return VK_ERROR_OUT_OF_DATE_KHR in both cases. This is what the Nvidia driver on Windows does afaics.
Rémi Bernon (@rbernon) commented about dlls/winewayland.drv/vulkan.c:
if (!wine_vk_surface_is_valid(wine_vk_surface)) return VK_ERROR_SURFACE_LOST_KHR;
- wine_vk_swapchain = calloc(1, sizeof(*wine_vk_swapchain));
- if (!wine_vk_swapchain)
return VK_ERROR_OUT_OF_HOST_MEMORY;
- list_init(&wine_vk_swapchain->entry);
You normally do not need to initialize the list.
Rémi Bernon (@rbernon) commented about dlls/winewayland.drv/vulkan.c:
if (res != VK_SUCCESS) { ERR("Failed to create vulkan wayland swapchain, res=%d\n", res);
wine_vk_swapchain_destroy(wine_vk_swapchain);
However that means that the swapchain should be `free`-d here instead.
Alternatively I think it's better to unlink objects outside of their destructors, and only where it is appropriate (in this case in vkDestroySwapchain).
Rémi Bernon (@rbernon) commented about dlls/winewayland.drv/vulkan.c:
swap_res = VK_ERROR_OUT_OF_DATE_KHR;
}
else
{
swap_res = VK_SUCCESS; } } else {
vk_result_update_severity(&res, VK_ERROR_SURFACE_LOST_KHR);
swap_res = VK_ERROR_SURFACE_LOST_KHR; }
if (present_info->pResults)
vk_result_update_severity(&present_info->pResults[i], swap_res);
vk_result_update_severity(&res, swap_res);
Imo this should be merged with the previous change, to avoid inconsistent state.
Rémi Bernon (@rbernon) commented about dlls/winewayland.drv/vulkan.c:
int client_height = wayland_surface->window.client_rect.bottom - wayland_surface->window.client_rect.top;
Any reason to delay that until the first present and not do it right away when we set needs_content to TRUE?
@afrantzis You are the best!, Im here since the first PR for Wayland and want to give a big Thanks to you
Impressive work, it seems that Vulkan support will be possible before the freeze 🥶. 🎉🎉🎉🎉
Is there a lot left for the mouse input to behave correctly in games?