Module: wine Branch: master Commit: 9439b3c3ee695ca46ca99fa40f939137dec93514 URL: https://gitlab.winehq.org/wine/wine/-/commit/9439b3c3ee695ca46ca99fa40f93913...
Author: Alexandros Frantzis alexandros.frantzis@collabora.com Date: Tue Nov 7 17:42:05 2023 +0200
winewayland.drv: Use a client area subsurface as the Vulkan target.
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