This is the first of (tentatively) 3 MRs that add Vulkan support to the Wayland driver. Here is the proposed breakdown:
* part 10.1 (this one): Basic setup and VkSurfaceKHR integration * part 10.2: VkSwapchainKHR integration * part 10.3: Everything else (mostly passthrough implementations of other Vulkan functions)
I chose to go with Vulkan first, instead of OpenGL, since the integration is more straightforward, and allows us to implement required core driver changes (which will also be used for OpenGL later) with fewer distractions.
Please note that all 3 parts need to land before the Vulkan support is actually usable in applications/games. I have uploaded the full (tentative) series for people that want to take a look or try out the final state: https://gitlab.winehq.org/afrantzis/wine/-/tree/wayland-part-10
Finally, part 10 is not based on part 9, so they can land in either order. However, there are interactions and conflicts between the two, so whichever part lands last will need to be (slightly) adapted. Note, though, that without part 9, some things won't work well on scaled outputs (esp. fullscreen).
Thanks!
-- v2: winewayland.drv: Forward all client surface pointer events to parent. winewayland.drv: Set client area subsurface size. winewayland.drv: Set client area subsurface position. winewayland.drv: Use a client area subsurface as the Vulkan target. winewayland.drv: Implement vkDestroySurfaceKHR. winewayland.drv: Implement vkCreateWin32SurfaceKHR. winewayland.drv: Implement vkGetDeviceProcAddr and vkGetInstanceProcAddr. winewayland.drv: Implement vkDestroyInstance. winewayland.drv: Implement vkCreateInstance. winewayland.drv: Implement vkEnumerateInstanceExtensionProperties. winewayland.drv: Add skeleton Vulkan driver.
From: Alexandros Frantzis alexandros.frantzis@collabora.com
--- dlls/winewayland.drv/Makefile.in | 1 + dlls/winewayland.drv/vulkan.c | 80 ++++++++++++++++++++++++++ dlls/winewayland.drv/waylanddrv.h | 1 + dlls/winewayland.drv/waylanddrv_main.c | 3 +- 4 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 dlls/winewayland.drv/vulkan.c
diff --git a/dlls/winewayland.drv/Makefile.in b/dlls/winewayland.drv/Makefile.in index 95ddbcedf8b..fa2beaad79c 100644 --- a/dlls/winewayland.drv/Makefile.in +++ b/dlls/winewayland.drv/Makefile.in @@ -8,6 +8,7 @@ SOURCES = \ dllmain.c \ version.rc \ viewporter.xml \ + vulkan.c \ wayland.c \ wayland_keyboard.c \ wayland_output.c \ diff --git a/dlls/winewayland.drv/vulkan.c b/dlls/winewayland.drv/vulkan.c new file mode 100644 index 00000000000..f807256c9e4 --- /dev/null +++ b/dlls/winewayland.drv/vulkan.c @@ -0,0 +1,80 @@ +/* WAYLANDDRV Vulkan implementation + * + * Copyright 2017 Roderick Colenbrander + * Copyright 2021 Alexandros Frantzis + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#if 0 +#pragma makedep unix +#endif + +#include "config.h" + +#include <dlfcn.h> + +#include "waylanddrv.h" +#include "wine/debug.h" + +#define VK_NO_PROTOTYPES +#define WINE_VK_HOST + +#include "wine/vulkan.h" +#include "wine/vulkan_driver.h" + +WINE_DEFAULT_DEBUG_CHANNEL(vulkan); + +#ifdef SONAME_LIBVULKAN + +static void *vulkan_handle; + +static void wine_vk_init(void) +{ + if (!(vulkan_handle = dlopen(SONAME_LIBVULKAN, RTLD_NOW))) + ERR("Failed to load %s.\n", SONAME_LIBVULKAN); +} + +static const struct vulkan_funcs vulkan_funcs; + +/********************************************************************** + * WAYLAND_wine_get_vulkan_driver + */ +const struct vulkan_funcs *WAYLAND_wine_get_vulkan_driver(UINT version) +{ + static pthread_once_t init_once = PTHREAD_ONCE_INIT; + + if (version != WINE_VULKAN_DRIVER_VERSION) + { + ERR("version mismatch, vulkan wants %u but driver has %u\n", version, WINE_VULKAN_DRIVER_VERSION); + return NULL; + } + + pthread_once(&init_once, wine_vk_init); + if (vulkan_handle) + return &vulkan_funcs; + + return NULL; +} + +#else /* No vulkan */ + +const struct vulkan_funcs *WAYLAND_wine_get_vulkan_driver(UINT version) +{ + ERR("Wine was built without Vulkan support.\n"); + return NULL; +} + +#endif /* SONAME_LIBVULKAN */ diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h index 6bb30447f30..9bc6aedf356 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -297,5 +297,6 @@ void WAYLAND_WindowPosChanged(HWND hwnd, HWND insert_after, UINT swp_flags, BOOL WAYLAND_WindowPosChanging(HWND hwnd, HWND insert_after, UINT swp_flags, const RECT *window_rect, const RECT *client_rect, RECT *visible_rect, struct window_surface **surface) DECLSPEC_HIDDEN; +const struct vulkan_funcs *WAYLAND_wine_get_vulkan_driver(UINT version) DECLSPEC_HIDDEN;
#endif /* __WINE_WAYLANDDRV_H */ diff --git a/dlls/winewayland.drv/waylanddrv_main.c b/dlls/winewayland.drv/waylanddrv_main.c index 7151d7b931a..be898f9e2c3 100644 --- a/dlls/winewayland.drv/waylanddrv_main.c +++ b/dlls/winewayland.drv/waylanddrv_main.c @@ -38,7 +38,8 @@ static const struct user_driver_funcs waylanddrv_funcs = .pUpdateDisplayDevices = WAYLAND_UpdateDisplayDevices, .pWindowMessage = WAYLAND_WindowMessage, .pWindowPosChanged = WAYLAND_WindowPosChanged, - .pWindowPosChanging = WAYLAND_WindowPosChanging + .pWindowPosChanging = WAYLAND_WindowPosChanging, + .pwine_get_vulkan_driver = WAYLAND_wine_get_vulkan_driver, };
static NTSTATUS waylanddrv_unix_init(void *arg)
From: Alexandros Frantzis alexandros.frantzis@collabora.com
Return the native instance extension properties, substituting VK_KHR_wayland_surface for VK_KHR_win32_surface. --- dlls/winewayland.drv/vulkan.c | 62 ++++++++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-)
diff --git a/dlls/winewayland.drv/vulkan.c b/dlls/winewayland.drv/vulkan.c index f807256c9e4..81d109acd8f 100644 --- a/dlls/winewayland.drv/vulkan.c +++ b/dlls/winewayland.drv/vulkan.c @@ -39,15 +39,75 @@ WINE_DEFAULT_DEBUG_CHANNEL(vulkan);
#ifdef SONAME_LIBVULKAN
+static VkResult (*pvkEnumerateInstanceExtensionProperties)(const char *, uint32_t *, VkExtensionProperties *); + static void *vulkan_handle;
+static VkResult wayland_vkEnumerateInstanceExtensionProperties(const char *layer_name, + uint32_t *count, + VkExtensionProperties* properties) +{ + unsigned int i; + VkResult res; + + TRACE("layer_name %s, count %p, properties %p\n", debugstr_a(layer_name), count, properties); + + /* This shouldn't get called with layer_name set, the ICD loader prevents it. */ + if (layer_name) + { + ERR("Layer enumeration not supported from ICD.\n"); + return VK_ERROR_LAYER_NOT_PRESENT; + } + + /* We will return the same number of instance extensions reported by the host back to + * winevulkan. Along the way we may replace xlib extensions with their win32 equivalents. + * Winevulkan will perform more detailed filtering as it knows whether it has thunks + * for a particular extension. + */ + res = pvkEnumerateInstanceExtensionProperties(layer_name, count, properties); + if (!properties || res < 0) + return res; + + for (i = 0; i < *count; i++) + { + /* For now the only wayland extension we need to fixup. Long-term we may need an array. */ + if (!strcmp(properties[i].extensionName, "VK_KHR_wayland_surface")) + { + TRACE("Substituting VK_KHR_wayland_surface for VK_KHR_win32_surface\n"); + + snprintf(properties[i].extensionName, sizeof(properties[i].extensionName), + VK_KHR_WIN32_SURFACE_EXTENSION_NAME); + properties[i].specVersion = VK_KHR_WIN32_SURFACE_SPEC_VERSION; + } + } + + TRACE("Returning %u extensions.\n", *count); + return res; +} + static void wine_vk_init(void) { if (!(vulkan_handle = dlopen(SONAME_LIBVULKAN, RTLD_NOW))) + { ERR("Failed to load %s.\n", SONAME_LIBVULKAN); + return; + } + +#define LOAD_FUNCPTR(f) if (!(p##f = dlsym(vulkan_handle, #f))) goto fail + LOAD_FUNCPTR(vkEnumerateInstanceExtensionProperties); +#undef LOAD_FUNCPTR + + return; + +fail: + dlclose(vulkan_handle); + vulkan_handle = NULL; }
-static const struct vulkan_funcs vulkan_funcs; +static const struct vulkan_funcs vulkan_funcs = +{ + .p_vkEnumerateInstanceExtensionProperties = wayland_vkEnumerateInstanceExtensionProperties, +};
/********************************************************************** * WAYLAND_wine_get_vulkan_driver
From: Alexandros Frantzis alexandros.frantzis@collabora.com
Create a Vulkan instance, ensuring we use the proper (Wayland) SurfaceKHR extension when forwarding the request to the native Vulkan platform. --- dlls/winewayland.drv/vulkan.c | 75 +++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+)
diff --git a/dlls/winewayland.drv/vulkan.c b/dlls/winewayland.drv/vulkan.c index 81d109acd8f..7f0f5652f97 100644 --- a/dlls/winewayland.drv/vulkan.c +++ b/dlls/winewayland.drv/vulkan.c @@ -25,6 +25,7 @@ #include "config.h"
#include <dlfcn.h> +#include <stdlib.h>
#include "waylanddrv.h" #include "wine/debug.h" @@ -39,10 +40,82 @@ WINE_DEFAULT_DEBUG_CHANNEL(vulkan);
#ifdef SONAME_LIBVULKAN
+static VkResult (*pvkCreateInstance)(const VkInstanceCreateInfo *, const VkAllocationCallbacks *, VkInstance *); static VkResult (*pvkEnumerateInstanceExtensionProperties)(const char *, uint32_t *, VkExtensionProperties *);
static void *vulkan_handle;
+/* 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, + VkInstanceCreateInfo *dst) +{ + unsigned int i; + const char **enabled_extensions = NULL; + + dst->sType = src->sType; + dst->flags = src->flags; + dst->pApplicationInfo = src->pApplicationInfo; + dst->pNext = src->pNext; + dst->enabledLayerCount = 0; + dst->ppEnabledLayerNames = NULL; + dst->enabledExtensionCount = 0; + dst->ppEnabledExtensionNames = NULL; + + if (src->enabledExtensionCount > 0) + { + enabled_extensions = calloc(src->enabledExtensionCount, + sizeof(*src->ppEnabledExtensionNames)); + if (!enabled_extensions) + { + ERR("Failed to allocate memory for enabled extensions\n"); + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + + for (i = 0; i < src->enabledExtensionCount; i++) + { + /* Substitute extension with Wayland ones else copy. Long-term, when we + * support more extensions, we should store these in a list. */ + if (!strcmp(src->ppEnabledExtensionNames[i], "VK_KHR_win32_surface")) + enabled_extensions[i] = "VK_KHR_wayland_surface"; + else + enabled_extensions[i] = src->ppEnabledExtensionNames[i]; + } + dst->ppEnabledExtensionNames = enabled_extensions; + dst->enabledExtensionCount = src->enabledExtensionCount; + } + + return VK_SUCCESS; +} + +static VkResult wayland_vkCreateInstance(const VkInstanceCreateInfo *create_info, + const VkAllocationCallbacks *allocator, + VkInstance *instance) +{ + VkInstanceCreateInfo create_info_host; + VkResult res; + + TRACE("create_info %p, allocator %p, instance %p\n", create_info, allocator, instance); + + if (allocator) + FIXME("Support for allocation callbacks not implemented yet\n"); + + /* Perform a second pass on converting VkInstanceCreateInfo. Winevulkan + * performed a first pass in which it handles everything except for WSI + * functionality such as VK_KHR_win32_surface. Handle this now. */ + res = wine_vk_instance_convert_create_info(create_info, &create_info_host); + if (res != VK_SUCCESS) + { + ERR("Failed to convert instance create info, res=%d\n", res); + return res; + } + + res = pvkCreateInstance(&create_info_host, NULL /* allocator */, instance); + + free((void *)create_info_host.ppEnabledExtensionNames); + return res; +} + static VkResult wayland_vkEnumerateInstanceExtensionProperties(const char *layer_name, uint32_t *count, VkExtensionProperties* properties) @@ -94,6 +167,7 @@ static void wine_vk_init(void) }
#define LOAD_FUNCPTR(f) if (!(p##f = dlsym(vulkan_handle, #f))) goto fail + LOAD_FUNCPTR(vkCreateInstance); LOAD_FUNCPTR(vkEnumerateInstanceExtensionProperties); #undef LOAD_FUNCPTR
@@ -106,6 +180,7 @@ fail:
static const struct vulkan_funcs vulkan_funcs = { + .p_vkCreateInstance = wayland_vkCreateInstance, .p_vkEnumerateInstanceExtensionProperties = wayland_vkEnumerateInstanceExtensionProperties, };
From: Alexandros Frantzis alexandros.frantzis@collabora.com
--- dlls/winewayland.drv/vulkan.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
diff --git a/dlls/winewayland.drv/vulkan.c b/dlls/winewayland.drv/vulkan.c index 7f0f5652f97..9b8ee6ee9e2 100644 --- a/dlls/winewayland.drv/vulkan.c +++ b/dlls/winewayland.drv/vulkan.c @@ -41,6 +41,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(vulkan); #ifdef SONAME_LIBVULKAN
static VkResult (*pvkCreateInstance)(const VkInstanceCreateInfo *, const VkAllocationCallbacks *, VkInstance *); +static void (*pvkDestroyInstance)(VkInstance, const VkAllocationCallbacks *); static VkResult (*pvkEnumerateInstanceExtensionProperties)(const char *, uint32_t *, VkExtensionProperties *);
static void *vulkan_handle; @@ -116,6 +117,17 @@ static VkResult wayland_vkCreateInstance(const VkInstanceCreateInfo *create_info return res; }
+static void wayland_vkDestroyInstance(VkInstance instance, + const VkAllocationCallbacks *allocator) +{ + TRACE("%p %p\n", instance, allocator); + + if (allocator) + FIXME("Support for allocation callbacks not implemented yet\n"); + + pvkDestroyInstance(instance, NULL /* allocator */); +} + static VkResult wayland_vkEnumerateInstanceExtensionProperties(const char *layer_name, uint32_t *count, VkExtensionProperties* properties) @@ -168,6 +180,7 @@ static void wine_vk_init(void)
#define LOAD_FUNCPTR(f) if (!(p##f = dlsym(vulkan_handle, #f))) goto fail LOAD_FUNCPTR(vkCreateInstance); + LOAD_FUNCPTR(vkDestroyInstance); LOAD_FUNCPTR(vkEnumerateInstanceExtensionProperties); #undef LOAD_FUNCPTR
@@ -181,6 +194,7 @@ fail: static const struct vulkan_funcs vulkan_funcs = { .p_vkCreateInstance = wayland_vkCreateInstance, + .p_vkDestroyInstance = wayland_vkDestroyInstance, .p_vkEnumerateInstanceExtensionProperties = wayland_vkEnumerateInstanceExtensionProperties, };
From: Alexandros Frantzis alexandros.frantzis@collabora.com
--- dlls/winewayland.drv/vulkan.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+)
diff --git a/dlls/winewayland.drv/vulkan.c b/dlls/winewayland.drv/vulkan.c index 9b8ee6ee9e2..d22b8401422 100644 --- a/dlls/winewayland.drv/vulkan.c +++ b/dlls/winewayland.drv/vulkan.c @@ -43,8 +43,11 @@ WINE_DEFAULT_DEBUG_CHANNEL(vulkan); static VkResult (*pvkCreateInstance)(const VkInstanceCreateInfo *, const VkAllocationCallbacks *, VkInstance *); static void (*pvkDestroyInstance)(VkInstance, const VkAllocationCallbacks *); static VkResult (*pvkEnumerateInstanceExtensionProperties)(const char *, uint32_t *, VkExtensionProperties *); +static void * (*pvkGetDeviceProcAddr)(VkDevice, const char *); +static void * (*pvkGetInstanceProcAddr)(VkInstance, const char *);
static void *vulkan_handle; +static const struct vulkan_funcs vulkan_funcs;
/* Helper function for converting between win32 and Wayland compatible VkInstanceCreateInfo. * Caller is responsible for allocation and cleanup of 'dst'. */ @@ -170,6 +173,30 @@ static VkResult wayland_vkEnumerateInstanceExtensionProperties(const char *layer return res; }
+static void *wayland_vkGetDeviceProcAddr(VkDevice device, const char *name) +{ + void *proc_addr; + + TRACE("%p, %s\n", device, debugstr_a(name)); + + if ((proc_addr = get_vulkan_driver_device_proc_addr(&vulkan_funcs, name))) + return proc_addr; + + return pvkGetDeviceProcAddr(device, name); +} + +static void *wayland_vkGetInstanceProcAddr(VkInstance instance, const char *name) +{ + void *proc_addr; + + TRACE("%p, %s\n", instance, debugstr_a(name)); + + if ((proc_addr = get_vulkan_driver_instance_proc_addr(&vulkan_funcs, instance, name))) + return proc_addr; + + return pvkGetInstanceProcAddr(instance, name); +} + static void wine_vk_init(void) { if (!(vulkan_handle = dlopen(SONAME_LIBVULKAN, RTLD_NOW))) @@ -182,6 +209,8 @@ static void wine_vk_init(void) LOAD_FUNCPTR(vkCreateInstance); LOAD_FUNCPTR(vkDestroyInstance); LOAD_FUNCPTR(vkEnumerateInstanceExtensionProperties); + LOAD_FUNCPTR(vkGetDeviceProcAddr); + LOAD_FUNCPTR(vkGetInstanceProcAddr); #undef LOAD_FUNCPTR
return; @@ -196,6 +225,8 @@ static const struct vulkan_funcs vulkan_funcs = .p_vkCreateInstance = wayland_vkCreateInstance, .p_vkDestroyInstance = wayland_vkDestroyInstance, .p_vkEnumerateInstanceExtensionProperties = wayland_vkEnumerateInstanceExtensionProperties, + .p_vkGetDeviceProcAddr = wayland_vkGetDeviceProcAddr, + .p_vkGetInstanceProcAddr = wayland_vkGetInstanceProcAddr, };
/**********************************************************************
From: Alexandros Frantzis alexandros.frantzis@collabora.com
Create Win32 VkSurfaceKHR objects which are backed by native Wayland VkSurfaceKHR objects. For now we associate a dummy Wayland surface with the VkSurfaceKHR. --- dlls/winewayland.drv/vulkan.c | 111 ++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+)
diff --git a/dlls/winewayland.drv/vulkan.c b/dlls/winewayland.drv/vulkan.c index d22b8401422..15e5edf503b 100644 --- a/dlls/winewayland.drv/vulkan.c +++ b/dlls/winewayland.drv/vulkan.c @@ -40,7 +40,19 @@ WINE_DEFAULT_DEBUG_CHANNEL(vulkan);
#ifdef SONAME_LIBVULKAN
+#define VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR 1000006000 + +typedef struct VkWaylandSurfaceCreateInfoKHR +{ + VkStructureType sType; + const void *pNext; + VkWaylandSurfaceCreateFlagsKHR flags; + struct wl_display *display; + struct wl_surface *surface; +} VkWaylandSurfaceCreateInfoKHR; + static VkResult (*pvkCreateInstance)(const VkInstanceCreateInfo *, const VkAllocationCallbacks *, VkInstance *); +static VkResult (*pvkCreateWaylandSurfaceKHR)(VkInstance, const VkWaylandSurfaceCreateInfoKHR *, const VkAllocationCallbacks *, VkSurfaceKHR *); static void (*pvkDestroyInstance)(VkInstance, const VkAllocationCallbacks *); static VkResult (*pvkEnumerateInstanceExtensionProperties)(const char *, uint32_t *, VkExtensionProperties *); static void * (*pvkGetDeviceProcAddr)(VkDevice, const char *); @@ -49,6 +61,23 @@ static void * (*pvkGetInstanceProcAddr)(VkInstance, const char *); static void *vulkan_handle; static const struct vulkan_funcs vulkan_funcs;
+struct wine_vk_surface +{ + struct wl_surface *client; + VkSurfaceKHR native; +}; + +static struct wine_vk_surface *wine_vk_surface_from_handle(VkSurfaceKHR handle) +{ + return (struct wine_vk_surface *)(uintptr_t)handle; +} + +static void wine_vk_surface_destroy(struct wine_vk_surface *wine_vk_surface) +{ + if (wine_vk_surface->client) wl_surface_destroy(wine_vk_surface->client); + free(wine_vk_surface); +} + /* 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, @@ -92,6 +121,14 @@ static VkResult wine_vk_instance_convert_create_info(const VkInstanceCreateInfo return VK_SUCCESS; }
+static const char *wine_vk_native_fn_name(const char *name) +{ + if (!strcmp(name, "vkCreateWin32SurfaceKHR")) + return "vkCreateWaylandSurfaceKHR"; + + return name; +} + static VkResult wayland_vkCreateInstance(const VkInstanceCreateInfo *create_info, const VkAllocationCallbacks *allocator, VkInstance *instance) @@ -120,6 +157,62 @@ static VkResult wayland_vkCreateInstance(const VkInstanceCreateInfo *create_info return res; }
+static VkResult wayland_vkCreateWin32SurfaceKHR(VkInstance instance, + const VkWin32SurfaceCreateInfoKHR *create_info, + const VkAllocationCallbacks *allocator, + VkSurfaceKHR *vk_surface) +{ + VkResult res; + VkWaylandSurfaceCreateInfoKHR create_info_host; + struct wine_vk_surface *wine_vk_surface; + + TRACE("%p %p %p %p\n", instance, create_info, allocator, vk_surface); + + if (allocator) + FIXME("Support for allocation callbacks not implemented yet\n"); + + wine_vk_surface = calloc(1, sizeof(*wine_vk_surface)); + if (!wine_vk_surface) + { + ERR("Failed to allocate memory for wayland vulkan surface\n"); + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto err; + } + + wine_vk_surface->client = wl_compositor_create_surface(process_wayland.wl_compositor); + if (!wine_vk_surface->client) + { + ERR("Failed to create client surface for hwnd=%p\n", create_info->hwnd); + /* VK_KHR_win32_surface only allows out of host and device memory as errors. */ + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto err; + } + + create_info_host.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR; + create_info_host.pNext = NULL; + create_info_host.flags = 0; /* reserved */ + create_info_host.display = process_wayland.wl_display; + create_info_host.surface = wine_vk_surface->client; + + res = pvkCreateWaylandSurfaceKHR(instance, &create_info_host, + NULL /* allocator */, + &wine_vk_surface->native); + if (res != VK_SUCCESS) + { + ERR("Failed to create vulkan wayland surface, res=%d\n", res); + goto err; + } + + *vk_surface = (uintptr_t)wine_vk_surface; + + TRACE("Created surface=0x%s\n", wine_dbgstr_longlong(*vk_surface)); + return VK_SUCCESS; + +err: + if (wine_vk_surface) wine_vk_surface_destroy(wine_vk_surface); + return res; +} + static void wayland_vkDestroyInstance(VkInstance instance, const VkAllocationCallbacks *allocator) { @@ -179,6 +272,11 @@ static void *wayland_vkGetDeviceProcAddr(VkDevice device, const char *name)
TRACE("%p, %s\n", device, debugstr_a(name));
+ /* Do not return the driver function if the corresponding native function + * is not available. */ + if (!pvkGetDeviceProcAddr(device, wine_vk_native_fn_name(name))) + return NULL; + if ((proc_addr = get_vulkan_driver_device_proc_addr(&vulkan_funcs, name))) return proc_addr;
@@ -191,12 +289,22 @@ static void *wayland_vkGetInstanceProcAddr(VkInstance instance, const char *name
TRACE("%p, %s\n", instance, debugstr_a(name));
+ /* Do not return the driver function if the corresponding native function + * is not available. */ + if (!pvkGetInstanceProcAddr(instance, wine_vk_native_fn_name(name))) + return NULL; + if ((proc_addr = get_vulkan_driver_instance_proc_addr(&vulkan_funcs, instance, name))) return proc_addr;
return pvkGetInstanceProcAddr(instance, name); }
+static VkSurfaceKHR wayland_wine_get_native_surface(VkSurfaceKHR surface) +{ + return wine_vk_surface_from_handle(surface)->native; +} + static void wine_vk_init(void) { if (!(vulkan_handle = dlopen(SONAME_LIBVULKAN, RTLD_NOW))) @@ -207,6 +315,7 @@ static void wine_vk_init(void)
#define LOAD_FUNCPTR(f) if (!(p##f = dlsym(vulkan_handle, #f))) goto fail LOAD_FUNCPTR(vkCreateInstance); + LOAD_FUNCPTR(vkCreateWaylandSurfaceKHR); LOAD_FUNCPTR(vkDestroyInstance); LOAD_FUNCPTR(vkEnumerateInstanceExtensionProperties); LOAD_FUNCPTR(vkGetDeviceProcAddr); @@ -223,10 +332,12 @@ fail: static const struct vulkan_funcs vulkan_funcs = { .p_vkCreateInstance = wayland_vkCreateInstance, + .p_vkCreateWin32SurfaceKHR = wayland_vkCreateWin32SurfaceKHR, .p_vkDestroyInstance = wayland_vkDestroyInstance, .p_vkEnumerateInstanceExtensionProperties = wayland_vkEnumerateInstanceExtensionProperties, .p_vkGetDeviceProcAddr = wayland_vkGetDeviceProcAddr, .p_vkGetInstanceProcAddr = wayland_vkGetInstanceProcAddr, + .p_wine_get_native_surface = wayland_wine_get_native_surface, };
/**********************************************************************
From: Alexandros Frantzis alexandros.frantzis@collabora.com
--- dlls/winewayland.drv/vulkan.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)
diff --git a/dlls/winewayland.drv/vulkan.c b/dlls/winewayland.drv/vulkan.c index 15e5edf503b..da1b644f9e5 100644 --- a/dlls/winewayland.drv/vulkan.c +++ b/dlls/winewayland.drv/vulkan.c @@ -54,6 +54,7 @@ typedef struct VkWaylandSurfaceCreateInfoKHR static VkResult (*pvkCreateInstance)(const VkInstanceCreateInfo *, const VkAllocationCallbacks *, VkInstance *); static VkResult (*pvkCreateWaylandSurfaceKHR)(VkInstance, const VkWaylandSurfaceCreateInfoKHR *, const VkAllocationCallbacks *, VkSurfaceKHR *); static void (*pvkDestroyInstance)(VkInstance, const VkAllocationCallbacks *); +static void (*pvkDestroySurfaceKHR)(VkInstance, VkSurfaceKHR, const VkAllocationCallbacks *); static VkResult (*pvkEnumerateInstanceExtensionProperties)(const char *, uint32_t *, VkExtensionProperties *); static void * (*pvkGetDeviceProcAddr)(VkDevice, const char *); static void * (*pvkGetInstanceProcAddr)(VkInstance, const char *); @@ -224,6 +225,23 @@ static void wayland_vkDestroyInstance(VkInstance instance, pvkDestroyInstance(instance, NULL /* allocator */); }
+static void wayland_vkDestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface, + const VkAllocationCallbacks *allocator) +{ + struct wine_vk_surface *wine_vk_surface = wine_vk_surface_from_handle(surface); + + TRACE("%p 0x%s %p\n", instance, wine_dbgstr_longlong(surface), allocator); + + if (allocator) + FIXME("Support for allocation callbacks not implemented yet\n"); + + /* vkDestroySurfaceKHR must handle VK_NULL_HANDLE (0) for surface. */ + if (!wine_vk_surface) return; + + pvkDestroySurfaceKHR(instance, wine_vk_surface->native, NULL /* allocator */); + wine_vk_surface_destroy(wine_vk_surface); +} + static VkResult wayland_vkEnumerateInstanceExtensionProperties(const char *layer_name, uint32_t *count, VkExtensionProperties* properties) @@ -317,6 +335,7 @@ static void wine_vk_init(void) LOAD_FUNCPTR(vkCreateInstance); LOAD_FUNCPTR(vkCreateWaylandSurfaceKHR); LOAD_FUNCPTR(vkDestroyInstance); + LOAD_FUNCPTR(vkDestroySurfaceKHR); LOAD_FUNCPTR(vkEnumerateInstanceExtensionProperties); LOAD_FUNCPTR(vkGetDeviceProcAddr); LOAD_FUNCPTR(vkGetInstanceProcAddr); @@ -334,6 +353,7 @@ static const struct vulkan_funcs vulkan_funcs = .p_vkCreateInstance = wayland_vkCreateInstance, .p_vkCreateWin32SurfaceKHR = wayland_vkCreateWin32SurfaceKHR, .p_vkDestroyInstance = wayland_vkDestroyInstance, + .p_vkDestroySurfaceKHR = wayland_vkDestroySurfaceKHR, .p_vkEnumerateInstanceExtensionProperties = wayland_vkEnumerateInstanceExtensionProperties, .p_vkGetDeviceProcAddr = wayland_vkGetDeviceProcAddr, .p_vkGetInstanceProcAddr = wayland_vkGetInstanceProcAddr,
From: Alexandros Frantzis alexandros.frantzis@collabora.com
Since we can't render to parts of surfaces, use a dedicated client area subsurface as the target of Vulkan rendering. --- dlls/winewayland.drv/vulkan.c | 33 +++++++++++-- dlls/winewayland.drv/wayland.c | 10 ++++ dlls/winewayland.drv/wayland_surface.c | 67 ++++++++++++++++++++++++++ dlls/winewayland.drv/waylanddrv.h | 11 +++++ 4 files changed, 117 insertions(+), 4 deletions(-)
diff --git a/dlls/winewayland.drv/vulkan.c b/dlls/winewayland.drv/vulkan.c index da1b644f9e5..be7f048f9d3 100644 --- a/dlls/winewayland.drv/vulkan.c +++ b/dlls/winewayland.drv/vulkan.c @@ -64,7 +64,7 @@ static const struct vulkan_funcs vulkan_funcs;
struct wine_vk_surface { - struct wl_surface *client; + struct wayland_client_surface *client; VkSurfaceKHR native; };
@@ -75,7 +75,20 @@ static struct wine_vk_surface *wine_vk_surface_from_handle(VkSurfaceKHR handle)
static void wine_vk_surface_destroy(struct wine_vk_surface *wine_vk_surface) { - if (wine_vk_surface->client) wl_surface_destroy(wine_vk_surface->client); + if (wine_vk_surface->client) + { + HWND hwnd = wl_surface_get_user_data(wine_vk_surface->client->wl_surface); + struct wayland_surface *wayland_surface = wayland_surface_lock_hwnd(hwnd); + + if (wayland_client_surface_release(wine_vk_surface->client) && + wayland_surface) + { + wayland_surface->client = NULL; + } + + if (wayland_surface) pthread_mutex_unlock(&wayland_surface->mutex); + } + free(wine_vk_surface); }
@@ -166,6 +179,7 @@ static VkResult wayland_vkCreateWin32SurfaceKHR(VkInstance instance, VkResult res; VkWaylandSurfaceCreateInfoKHR create_info_host; struct wine_vk_surface *wine_vk_surface; + struct wayland_surface *wayland_surface;
TRACE("%p %p %p %p\n", instance, create_info, allocator, vk_surface);
@@ -180,7 +194,18 @@ static VkResult wayland_vkCreateWin32SurfaceKHR(VkInstance instance, goto err; }
- wine_vk_surface->client = wl_compositor_create_surface(process_wayland.wl_compositor); + wayland_surface = wayland_surface_lock_hwnd(create_info->hwnd); + if (!wayland_surface) + { + ERR("Failed to find wayland surface for hwnd=%p\n", create_info->hwnd); + /* VK_KHR_win32_surface only allows out of host and device memory as errors. */ + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto err; + } + + wine_vk_surface->client = wayland_surface_get_client(wayland_surface); + pthread_mutex_unlock(&wayland_surface->mutex); + if (!wine_vk_surface->client) { ERR("Failed to create client surface for hwnd=%p\n", create_info->hwnd); @@ -193,7 +218,7 @@ static VkResult wayland_vkCreateWin32SurfaceKHR(VkInstance instance, create_info_host.pNext = NULL; create_info_host.flags = 0; /* reserved */ create_info_host.display = process_wayland.wl_display; - create_info_host.surface = wine_vk_surface->client; + create_info_host.surface = wine_vk_surface->client->wl_surface;
res = pvkCreateWaylandSurfaceKHR(instance, &create_info_host, NULL /* allocator */, diff --git a/dlls/winewayland.drv/wayland.c b/dlls/winewayland.drv/wayland.c index ddb25209804..31cd27f7a76 100644 --- a/dlls/winewayland.drv/wayland.c +++ b/dlls/winewayland.drv/wayland.c @@ -149,6 +149,11 @@ static void registry_handle_global(void *data, struct wl_registry *registry, process_wayland.wp_viewporter = wl_registry_bind(registry, id, &wp_viewporter_interface, 1); } + else if (strcmp(interface, "wl_subcompositor") == 0) + { + process_wayland.wl_subcompositor = + wl_registry_bind(registry, id, &wl_subcompositor_interface, 1); + } }
static void registry_handle_global_remove(void *data, struct wl_registry *registry, @@ -249,6 +254,11 @@ BOOL wayland_process_init(void) ERR("Wayland compositor doesn't support wl_shm\n"); return FALSE; } + if (!process_wayland.wl_subcompositor) + { + ERR("Wayland compositor doesn't support wl_subcompositor\n"); + return FALSE; + }
wayland_init_display_devices(FALSE);
diff --git a/dlls/winewayland.drv/wayland_surface.c b/dlls/winewayland.drv/wayland_surface.c index 8cfefefb969..cdcee27a042 100644 --- a/dlls/winewayland.drv/wayland_surface.c +++ b/dlls/winewayland.drv/wayland_surface.c @@ -687,3 +687,70 @@ void wayland_surface_coords_to_window(struct wayland_surface *surface, *window_x = round(surface_x * surface->window.scale); *window_y = round(surface_y * surface->window.scale); } + +/********************************************************************** + * wayland_client_surface_release + */ +BOOL wayland_client_surface_release(struct wayland_client_surface *client) +{ + if (InterlockedDecrement(&client->ref)) return FALSE; + + if (client->wl_subsurface) + wl_subsurface_destroy(client->wl_subsurface); + if (client->wl_surface) + wl_surface_destroy(client->wl_surface); + + free(client); + + return TRUE; +} + +/********************************************************************** + * wayland_surface_get_client + */ +struct wayland_client_surface *wayland_surface_get_client(struct wayland_surface *surface) +{ + if (surface->client) + { + InterlockedIncrement(&surface->client->ref); + return surface->client; + } + + surface->client = calloc(1, sizeof(*surface->client)); + if (!surface->client) + { + ERR("Failed to allocate space for client surface\n"); + goto err; + } + + surface->client->ref = 1; + + surface->client->wl_surface = + wl_compositor_create_surface(process_wayland.wl_compositor); + if (!surface->client->wl_surface) + { + ERR("Failed to create client wl_surface\n"); + goto err; + } + wl_surface_set_user_data(surface->client->wl_surface, surface->hwnd); + + surface->client->wl_subsurface = + wl_subcompositor_get_subsurface(process_wayland.wl_subcompositor, + surface->client->wl_surface, + surface->wl_surface); + if (!surface->client->wl_subsurface) + { + ERR("Failed to create client wl_subsurface\n"); + goto err; + } + + return surface->client; + +err: + if (surface->client) + { + wayland_client_surface_release(surface->client); + surface->client = NULL; + } + return NULL; +} diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h index 9bc6aedf356..928c2f023eb 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -111,6 +111,7 @@ struct wayland struct xdg_wm_base *xdg_wm_base; struct wl_shm *wl_shm; struct wp_viewporter *wp_viewporter; + struct wl_subcompositor *wl_subcompositor; struct wayland_seat seat; struct wayland_keyboard keyboard; struct wayland_pointer pointer; @@ -163,6 +164,13 @@ struct wayland_window_config double scale; };
+struct wayland_client_surface +{ + LONG ref; + struct wl_surface *wl_surface; + struct wl_subsurface *wl_subsurface; +}; + struct wayland_surface { HWND hwnd; @@ -175,6 +183,7 @@ struct wayland_surface struct wayland_shm_buffer *latest_window_buffer; BOOL resizing; struct wayland_window_config window; + struct wayland_client_surface *client; };
struct wayland_shm_buffer @@ -226,6 +235,8 @@ void wayland_surface_coords_from_window(struct wayland_surface *surface, void wayland_surface_coords_to_window(struct wayland_surface *surface, double surface_x, double surface_y, 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;
/********************************************************************** * Wayland SHM buffer
From: Alexandros Frantzis alexandros.frantzis@collabora.com
Set the position of the client area subsurface relative to its parent surface. --- dlls/winewayland.drv/wayland_surface.c | 26 ++++++++++++++++++++++++++ dlls/winewayland.drv/waylanddrv.h | 1 + dlls/winewayland.drv/window.c | 11 +++++++++-- 3 files changed, 36 insertions(+), 2 deletions(-)
diff --git a/dlls/winewayland.drv/wayland_surface.c b/dlls/winewayland.drv/wayland_surface.c index cdcee27a042..f4a64d19ecd 100644 --- a/dlls/winewayland.drv/wayland_surface.c +++ b/dlls/winewayland.drv/wayland_surface.c @@ -468,6 +468,29 @@ static void wayland_surface_reconfigure_size(struct wayland_surface *surface, } }
+/********************************************************************** + * wayland_surface_reconfigure_client + * + * Reconfigures the subsurface covering the client area. + */ +static void wayland_surface_reconfigure_client(struct wayland_surface *surface) +{ + struct wayland_window_config *window = &surface->window; + int client_x, client_y, x, y; + + if (!surface->client) return; + + /* The offset of the client area origin relatively to the window origin. */ + client_x = window->client_rect.left - window->rect.left; + client_y = window->client_rect.top - window->rect.top; + + wayland_surface_coords_from_window(surface, client_x, client_y, &x, &y); + + TRACE("hwnd=%p subsurface=%d,%d\n", surface->hwnd, x, y); + + wl_subsurface_set_position(surface->client->wl_subsurface, x, y); +} + /********************************************************************** * wayland_surface_reconfigure * @@ -525,6 +548,7 @@ BOOL wayland_surface_reconfigure(struct wayland_surface *surface)
wayland_surface_reconfigure_geometry(surface, width, height); wayland_surface_reconfigure_size(surface, width, height); + wayland_surface_reconfigure_client(surface);
return TRUE; } @@ -744,6 +768,8 @@ struct wayland_client_surface *wayland_surface_get_client(struct wayland_surface goto err; }
+ wayland_surface_reconfigure_client(surface); + return surface->client;
err: diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h index 928c2f023eb..2dc49a2fd4b 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -159,6 +159,7 @@ struct wayland_surface_config struct wayland_window_config { RECT rect; + RECT client_rect; enum wayland_surface_config_state state; /* The scale (i.e., normalized dpi) the window is rendering at. */ double scale; diff --git a/dlls/winewayland.drv/window.c b/dlls/winewayland.drv/window.c index 1423164834e..fff3749e9ad 100644 --- a/dlls/winewayland.drv/window.c +++ b/dlls/winewayland.drv/window.c @@ -45,6 +45,8 @@ struct wayland_win_data struct window_surface *window_surface; /* USER window rectangle relative to win32 parent window client area */ RECT window_rect; + /* USER client rectangle relative to win32 parent window client area */ + RECT client_rect; };
static int wayland_win_data_cmp_rb(const void *key, @@ -68,7 +70,8 @@ static struct rb_tree win_data_rb = { wayland_win_data_cmp_rb }; * Create a data window structure for an existing window. */ static struct wayland_win_data *wayland_win_data_create(HWND hwnd, - const RECT *window_rect) + const RECT *window_rect, + const RECT *client_rect) { struct wayland_win_data *data; struct rb_entry *rb_entry; @@ -83,6 +86,7 @@ static struct wayland_win_data *wayland_win_data_create(HWND hwnd,
data->hwnd = hwnd; data->window_rect = *window_rect; + data->client_rect = *client_rect;
pthread_mutex_lock(&win_data_mutex);
@@ -157,6 +161,7 @@ static void wayland_win_data_get_config(struct wayland_win_data *data, DWORD style;
conf->rect = data->window_rect; + conf->client_rect = data->client_rect; style = NtUserGetWindowLongW(data->hwnd, GWL_STYLE);
TRACE("window=%s style=%#lx\n", wine_dbgstr_rect(&conf->rect), (long)style); @@ -310,7 +315,8 @@ BOOL WAYLAND_WindowPosChanging(HWND hwnd, HWND insert_after, UINT swp_flags, hwnd, wine_dbgstr_rect(window_rect), wine_dbgstr_rect(client_rect), wine_dbgstr_rect(visible_rect), insert_after, swp_flags);
- if (!data && !(data = wayland_win_data_create(hwnd, window_rect))) return TRUE; + if (!data && !(data = wayland_win_data_create(hwnd, window_rect, client_rect))) + return TRUE;
/* Release the dummy surface wine provides for toplevels. */ if (*surface) window_surface_release(*surface); @@ -361,6 +367,7 @@ void WAYLAND_WindowPosChanged(HWND hwnd, HWND insert_after, UINT swp_flags, if (!data) return;
data->window_rect = *window_rect; + data->client_rect = *client_rect;
if (surface) window_surface_add_ref(surface); if (data->window_surface) window_surface_release(data->window_surface);
From: Alexandros Frantzis alexandros.frantzis@collabora.com
Use the viewporter Wayland protocol to set the size of the client area subsurface, so that it always covers the client area bounds exactly. This may transiently lead to scaled contents. --- dlls/winewayland.drv/wayland.c | 5 ++++ dlls/winewayland.drv/wayland_surface.c | 33 +++++++++++++++++++++++++- dlls/winewayland.drv/waylanddrv.h | 1 + 3 files changed, 38 insertions(+), 1 deletion(-)
diff --git a/dlls/winewayland.drv/wayland.c b/dlls/winewayland.drv/wayland.c index 31cd27f7a76..f7119367543 100644 --- a/dlls/winewayland.drv/wayland.c +++ b/dlls/winewayland.drv/wayland.c @@ -154,6 +154,11 @@ static void registry_handle_global(void *data, struct wl_registry *registry, process_wayland.wl_subcompositor = wl_registry_bind(registry, id, &wl_subcompositor_interface, 1); } + else if (strcmp(interface, "wp_viewporter") == 0) + { + process_wayland.wp_viewporter = + wl_registry_bind(registry, id, &wp_viewporter_interface, 1); + } }
static void registry_handle_global_remove(void *data, struct wl_registry *registry, diff --git a/dlls/winewayland.drv/wayland_surface.c b/dlls/winewayland.drv/wayland_surface.c index f4a64d19ecd..b83709c5a8a 100644 --- a/dlls/winewayland.drv/wayland_surface.c +++ b/dlls/winewayland.drv/wayland_surface.c @@ -477,6 +477,7 @@ static void wayland_surface_reconfigure_client(struct wayland_surface *surface) { struct wayland_window_config *window = &surface->window; int client_x, client_y, x, y; + int client_width, client_height, width, height;
if (!surface->client) return;
@@ -484,11 +485,32 @@ static void wayland_surface_reconfigure_client(struct wayland_surface *surface) client_x = window->client_rect.left - window->rect.left; client_y = window->client_rect.top - window->rect.top;
+ client_width = window->client_rect.right - window->client_rect.left; + client_height = window->client_rect.bottom - window->client_rect.top; + wayland_surface_coords_from_window(surface, client_x, client_y, &x, &y); + wayland_surface_coords_from_window(surface, client_width, client_height, + &width, &height);
- TRACE("hwnd=%p subsurface=%d,%d\n", surface->hwnd, x, y); + TRACE("hwnd=%p subsurface=%d,%d+%dx%d\n", surface->hwnd, x, y, width, height);
wl_subsurface_set_position(surface->client->wl_subsurface, x, y); + + if (surface->client->wp_viewport) + { + if (width != 0 && height != 0) + { + wp_viewport_set_destination(surface->client->wp_viewport, + width, height); + } + else + { + /* We can't have a 0x0 destination, use 1x1 instead. */ + wp_viewport_set_destination(surface->client->wp_viewport, 1, 1); + } + } + + wl_surface_commit(surface->client->wl_surface); }
/********************************************************************** @@ -719,6 +741,8 @@ BOOL wayland_client_surface_release(struct wayland_client_surface *client) { if (InterlockedDecrement(&client->ref)) return FALSE;
+ if (client->wp_viewport) + wp_viewport_destroy(client->wp_viewport); if (client->wl_subsurface) wl_subsurface_destroy(client->wl_subsurface); if (client->wl_surface) @@ -768,6 +792,13 @@ struct wayland_client_surface *wayland_surface_get_client(struct wayland_surface goto err; }
+ if (process_wayland.wp_viewporter) + { + surface->client->wp_viewport = + wp_viewporter_get_viewport(process_wayland.wp_viewporter, + surface->client->wl_surface); + } + wayland_surface_reconfigure_client(surface);
return surface->client; diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h index 2dc49a2fd4b..00c9112d5de 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -170,6 +170,7 @@ struct wayland_client_surface LONG ref; struct wl_surface *wl_surface; struct wl_subsurface *wl_subsurface; + struct wp_viewport *wp_viewport; };
struct wayland_surface
From: Alexandros Frantzis alexandros.frantzis@collabora.com
Set an empty input region for the client area surface, so that the compositor forwards input events to the main/parent surface instead. This simplifies input handling, since otherwise we would need to implement special handling of events on the client area surface and transform them accordingly. --- dlls/winewayland.drv/wayland_surface.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
diff --git a/dlls/winewayland.drv/wayland_surface.c b/dlls/winewayland.drv/wayland_surface.c index b83709c5a8a..5a808b3ac96 100644 --- a/dlls/winewayland.drv/wayland_surface.c +++ b/dlls/winewayland.drv/wayland_surface.c @@ -758,6 +758,8 @@ BOOL wayland_client_surface_release(struct wayland_client_surface *client) */ struct wayland_client_surface *wayland_surface_get_client(struct wayland_surface *surface) { + struct wl_region *empty_region; + if (surface->client) { InterlockedIncrement(&surface->client->ref); @@ -782,6 +784,16 @@ struct wayland_client_surface *wayland_surface_get_client(struct wayland_surface } wl_surface_set_user_data(surface->client->wl_surface, surface->hwnd);
+ /* Let parent handle all pointer events. */ + empty_region = wl_compositor_create_region(process_wayland.wl_compositor); + if (!empty_region) + { + ERR("Failed to create wl_region\n"); + goto err; + } + wl_surface_set_input_region(surface->client->wl_surface, empty_region); + wl_region_destroy(empty_region); + surface->client->wl_subsurface = wl_subcompositor_get_subsurface(process_wayland.wl_subcompositor, surface->client->wl_surface,
On Thu Nov 9 09:14:12 2023 +0000, Alexandros Frantzis wrote:
Ack, I will update the MR (and subsequent MRs) accordingly.
Done.
On Thu Nov 9 21:32:40 2023 +0000, Rémi Bernon wrote:
Not asking to do that now, as it's the same for every of the other interfaces, but could we make these interfaces mandatory and get rid of the ifs everywhere? It's quite pointless to start a process without wl_subcompositor or wl_viewporter as they are pretty much required for the code to behave correctly.
I have added a check at driver init for wl_subcompositor. For wl_viewporter, I am somewhat torn because:
1. There is at least one compositor not supporting the extension at the moment. 2. It's a non-core (although stable) extension. 3. The lack of wp_viewporter is not catastrophic at the moment: a. We wouldn't have proper support for scaled monitors, b. the client subsurface (i.e., vulkan rendering) may transiently leak out of the client area extents.
I could imagine scenarios of using Wine that don't require wp_viewporter at all, e.g., a custom, software-rendering only Wayland compositor that runs some non-accelerated win32 app.
You should add the vkEnumerateInstanceExtensionProperties and vkGetInstanceProcAddr implementation as early as possible in this first MR.
Done.
Regarding the later upcoming changes I think you should leave the swapchain wrapping for later and instead use minImageExtent from vkGetPhysicalDeviceSurfaceCapabilities2KHR (which you should also implement before vkCreateSwapchain) to indicate that 0 is unsupported. If that's not enough we may later consider wrapping swapchains but I would be more comfortable if we didn't introduce it only for this purpose if there's a simpler way.
The swapchain wrapping is used to implement (see https://gitlab.winehq.org/afrantzis/wine/-/commits/wayland-part-10/ for the tentative commits):
1. `VK_ERROR_SURFACE_LOST_KHR` and `VK_ERROR_OUT_OF_DATE_KHR` since the Wayland WSI doesn't provide these results: we are required by the spec to keep the associated `wl_surface` alive, so there can be no "surface lost" for destroyed surfaces, and there can be no "out-of-date" for resizes since the surface size is dynamic. 2. Mapping of the parent surface to ensure the client subsurface is actually visible.
For the above we need to keep the required information in a internal `wine_vk_swapchain`. That being said, we don't have to implement this through winevulkan swapchain wrapping. We could maintain a mapping between the native VkSwapchainKHR and `wine_vk_swapchain` internally in the driver and use that when needed, while passing the native VkSwapchainKHR to winevulkan unchanged. This approach adds a little bit of complexity to the driver, but it's totally reasonable (in fact the experimental branch used this). Let me know if you would prefer this route so that I can rework the upcoming part accordingly.
--
Concerning using a 0x0 extent, I went with it because I find it to be a cleaner way to communicate "nothing to draw" (e.g., when minimized) compared to 1x1. It is supported by the win32 WSI spec, and 0x0 matches the client area size in such cases, so everything is more consistent.
Some applications/frameworks detect this and skip swapchain creation/rendering. Unfortunately, I do remember coming across some applications that will do the wrong thing and actually try to create a 0x0 swapchain (prohibited by the spec), that's why I have this workaround for them to continue to work.
If we prefer a 1x1 extent instead, for consistency with WineX11, I am fine with that too. Perhaps there are also other compatibility reasons to go with 1x1?
Thanks for the feedback!
v2: * Rebased on latest master to fix conflicts with and use functionality introduced in wayland-part-9 (coordinate system mappings) which landed first. * Reordered `#include`s in vulkan.c to be consistent with other files (and Wine in general). * Added commit to implement `vkEnumerateInstanceExtensionProperties` * Added commit to implement `vkGetDeviceProcAddr` and `vkGetInstanceProcAddr` * Added trailing commas to struct field initializations. * Set client surface viewport destination to 1x1 (smallest possible), instead of disabling the viewport, when the client area size becomes 0x0, to ensure contents are not visible (ideally we should unmap, but that also involves swapchain involvement, so we leave that for later).
This merge request was approved by Rémi Bernon.
For the above we need to keep the required information in a internal `wine_vk_swapchain`. That being said, we don't have to implement this through winevulkan swapchain wrapping. We could maintain a mapping between the native VkSwapchainKHR and `wine_vk_swapchain` internally in the driver and use that when needed, while passing the native VkSwapchainKHR to winevulkan unchanged. This approach adds a little bit of complexity to the driver, but it's totally reasonable (in fact the experimental branch used this). Let me know if you would prefer this route so that I can rework the upcoming part accordingly.
Yes, I think it'd be better for now. I don't think you even need to wrap swapchains in the driver either. You only need a mapping from `VkSwapchainKHR` to `wine_vk_surface` to detect invalidated surfaces. Proton winex11 does this, more or less for the same reasons.