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!
-- v2: winewayland.drv: Implement vkGetPhysicalDevicePresentRectanglesKHR. winewayland.drv: Implement vkGetDeviceGroupSurfacePresentModesKHR. winewayland.drv: Apply client subsurface position on creation. winewayland.drv: Ensure Vulkan parent surface is mapped with proper size. winewayland.drv: Detect and report vkQueuePresentKHR errors.
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 | 131 +++++++++++++++++++++++++++++- dlls/winewayland.drv/waylanddrv.h | 1 + 2 files changed, 131 insertions(+), 1 deletion(-)
diff --git a/dlls/winewayland.drv/vulkan.c b/dlls/winewayland.drv/vulkan.c index 7f73286ec5f..ea7a886b7f1 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,25 @@ 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; +} + /* 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 +236,76 @@ 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; + VkResult swap_res; + + 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) + { + swap_res = VK_ERROR_OUT_OF_DATE_KHR; + } + else + { + swap_res = VK_SUCCESS; + } + } + else + { + 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; +} + static VkResult wayland_vkCreateInstance(const VkInstanceCreateInfo *create_info, const VkAllocationCallbacks *allocator, VkInstance *instance) @@ -242,6 +342,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 +353,13 @@ 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; + + 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); + free(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,22 @@ 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))) + { + pthread_mutex_lock(&wine_vk_swapchain_mutex); + list_remove(&wine_vk_swapchain->entry); + pthread_mutex_unlock(&wine_vk_swapchain_mutex); + free(wine_vk_swapchain); + } }
static VkResult wayland_vkEnumerateInstanceExtensionProperties(const char *layer_name, @@ -636,9 +761,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
The client area subsurface (the target of Vulkan rendering) is not going to be presented properly (or at all) by the compositor if its parent surface is not mapped or doesn't have the right size, even though the window may be visible from Wine's perspective. To avoid this issue, ensure that the parent surface has up-to-date contents in terms of size, 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 | 68 ++++++++++++++++++++++++++ dlls/winewayland.drv/waylanddrv.h | 3 ++ dlls/winewayland.drv/window.c | 1 + 4 files changed, 74 insertions(+)
diff --git a/dlls/winewayland.drv/vulkan.c b/dlls/winewayland.drv/vulkan.c index ea7a886b7f1..f9fbab4c009 100644 --- a/dlls/winewayland.drv/vulkan.c +++ b/dlls/winewayland.drv/vulkan.c @@ -281,6 +281,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..57585927914 100644 --- a/dlls/winewayland.drv/wayland_surface.c +++ b/dlls/winewayland.drv/wayland_surface.c @@ -293,6 +293,9 @@ void wayland_surface_clear_role(struct wayland_surface *surface) wl_surface_attach(surface->wl_surface, NULL, 0, 0); wl_surface_commit(surface->wl_surface);
+ surface->buffer_width = 0; + surface->buffer_height = 0; + wl_display_flush(process_wayland.wl_display); }
@@ -336,6 +339,9 @@ void wayland_surface_attach_shm(struct wayland_surface *surface, } free(surface_damage); } + + surface->buffer_width = shm_buffer->width; + surface->buffer_height = shm_buffer->height; }
/********************************************************************** @@ -825,3 +831,65 @@ 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; + BOOL needs_contents; + + width = surface->window.rect.right - surface->window.rect.left; + height = surface->window.rect.bottom - surface->window.rect.top; + needs_contents = surface->window.visible && + (surface->buffer_width != width || + surface->buffer_height != height); + + TRACE("surface=%p hwnd=%p needs_contents=%d\n", + surface, surface->hwnd, needs_contents); + + if (!needs_contents) return; + + /* 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..383c79a23fe 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -164,6 +164,7 @@ struct wayland_window_config enum wayland_surface_config_state state; /* The scale (i.e., normalized dpi) the window is rendering at. */ double scale; + BOOL visible; };
struct wayland_client_surface @@ -187,6 +188,7 @@ struct wayland_surface BOOL resizing; struct wayland_window_config window; struct wayland_client_surface *client; + int buffer_width, buffer_height; };
struct wayland_shm_buffer @@ -240,6 +242,7 @@ 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..31ecb6542c6 100644 --- a/dlls/winewayland.drv/window.c +++ b/dlls/winewayland.drv/window.c @@ -181,6 +181,7 @@ static void wayland_win_data_get_config(struct wayland_win_data *data,
conf->state = window_state; conf->scale = NtUserGetDpiForWindow(data->hwnd) / 96.0; + conf->visible = (style & WS_VISIBLE) == WS_VISIBLE; }
static void wayland_win_data_update_wayland_surface(struct wayland_win_data *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 57585927914..285fb9a38c5 100644 --- a/dlls/winewayland.drv/wayland_surface.c +++ b/dlls/winewayland.drv/wayland_surface.c @@ -820,6 +820,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 f9fbab4c009..ad5b5bcf04d 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 *); @@ -554,6 +555,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; @@ -794,6 +809,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); @@ -824,6 +840,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 ad5b5bcf04d..cddff1d1feb 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 *); @@ -603,6 +604,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) @@ -812,6 +825,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); @@ -843,6 +857,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,
On Mon Nov 27 15:46:31 2023 +0000, Rémi Bernon wrote:
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.
So, in the Nvidia approach, presentation will return out_of_date and when the app tries to recreate the swapchain it will get the real surface_lost error.
I guess that's fine, but it feels a shame to not return the real (and spec-compliant) error code here since we have detected it, and allow apps to handle it directly. Are there any compatibility considerations at play?
On Tue Nov 28 13:09:34 2023 +0000, Alexandros Frantzis wrote:
changed this line in [version 2 of the diff](/wine/wine/-/merge_requests/4522/diffs?diff_id=86483&start_sha=e5587c4977102571ffde7906ae8a277d6e30e48c#e5caf7257b741813ee9fc224383430a07abb1be0_372_364)
Done.
On Tue Nov 28 13:09:35 2023 +0000, Alexandros Frantzis wrote:
changed this line in [version 2 of the diff](/wine/wine/-/merge_requests/4522/diffs?diff_id=86483&start_sha=e5587c4977102571ffde7906ae8a277d6e30e48c#e5caf7257b741813ee9fc224383430a07abb1be0_394_385)
Done. I removed `wine_vk_swapchain_destroy()` completely and handled unlink/free separately as suggested.
On Mon Nov 27 17:01:02 2023 +0000, Rémi Bernon wrote:
Imo this should be merged with the previous change, to avoid inconsistent state.
Done.
On Mon Nov 27 17:01:04 2023 +0000, Rémi Bernon wrote:
Any reason to delay that until the first present and not do it right away when we set needs_content to TRUE?
There are a couple of reasons why we don't want to present the empty buffer at that point:
1. We will introduce an empty frame which may cause flickering if the surface has (out-of-date) contents already (e.g., during resizes). 2. It is wasteful since in most cases we do not need to ensure contents that early (or at all for non-Vulkan apps), and by the time we need them they may have already been provided by the app.
This mechanism is only needed when Vulkan (or other users of the client subsurface in the future) tries to present before the main surface has been flushed with contents matching the latest window size (the most usual scenario is when a window becomes fullscreen and never gets any non-Vulkan contents).
Now, while thinking about all this, I realized that there is a simpler way to express the requirement for up-to-date contents, by tracking the buffer size committed to a surface and checking it against the window size. I have updated the MR accordingly. Let me know what you think.
Are there any compatibility considerations at play?
None that I'm aware of. My point is only that the code should be kept as simple as possible.
If we want to implement a WSI layer following Win32 behavior more closely I think it should not live in the drivers but rather in winevulkan. This would make checking it unnecessary in the drivers and would factor out several things in winex11 and winewayland.
On Tue Nov 28 13:58:46 2023 +0000, Rémi Bernon wrote:
Are there any compatibility considerations at play?
None that I'm aware of. My point is only that the code should be kept as simple as possible. If we want to implement a WSI layer following Win32 behavior more closely I think it should not live in the drivers but rather in winevulkan. This would make checking it unnecessary in the drivers and would factor out several things in winex11 and winewayland.
Also btw, we don't want to implement the Vulkan spec, we want to implement Win32 behavior, as bogus as it is.
@afrantzis do you plan to rebase your more feature full wayland branch onto the winewayland driver that will be in wine at the point of the code freeze? Currently people simply revert the current upstream driver to apply the old branch, which is not ideal.
If you are not planing to do that, then I would be curious on which parts are left to upstream.
Thanks for the awesome work so far! :beers:
On Wed Nov 29 06:58:20 2023 +0000, Stefan Riesenberger wrote:
@afrantzis do you plan to rebase your more feature full wayland branch onto the winewayland driver that will be in wine at the point of the code freeze? Currently people simply revert the current upstream driver to apply the old branch, which is not ideal. If you are not planing to do that, then I would be curious on which parts are left to upstream. Thanks for the awesome work so far! :beers:
@Riesi You spilled my beans 🫘