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 | 5 ++ dlls/winewayland.drv/wayland_surface.c | 67 ++++++++++++++++++++++++++ dlls/winewayland.drv/waylanddrv.h | 11 +++++ 4 files changed, 112 insertions(+), 4 deletions(-)
diff --git a/dlls/winewayland.drv/vulkan.c b/dlls/winewayland.drv/vulkan.c index 13ae73645a1..4a3a5dcb852 100644 --- a/dlls/winewayland.drv/vulkan.c +++ b/dlls/winewayland.drv/vulkan.c @@ -61,7 +61,7 @@ static void *vulkan_handle;
struct wine_vk_surface { - struct wl_surface *client; + struct wayland_client_surface *client; VkSurfaceKHR native; };
@@ -72,7 +72,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); }
@@ -155,6 +168,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);
@@ -169,7 +183,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); @@ -182,7 +207,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 b8c69a105cb..c932735101c 100644 --- a/dlls/winewayland.drv/wayland.c +++ b/dlls/winewayland.drv/wayland.c @@ -138,6 +138,11 @@ static void registry_handle_global(void *data, struct wl_registry *registry, wl_seat_add_listener(seat->wl_seat, &seat_listener, NULL); pthread_mutex_unlock(&seat->mutex); } + 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, diff --git a/dlls/winewayland.drv/wayland_surface.c b/dlls/winewayland.drv/wayland_surface.c index ae4812ebb08..61bbfdc2588 100644 --- a/dlls/winewayland.drv/wayland_surface.c +++ b/dlls/winewayland.drv/wayland_surface.c @@ -616,3 +616,70 @@ err: if (shm_buffer) wayland_shm_buffer_unref(shm_buffer); return NULL; } + +/********************************************************************** + * 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 6ef86ae5a37..37c6cef570a 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -99,6 +99,7 @@ struct wayland struct wl_compositor *wl_compositor; struct xdg_wm_base *xdg_wm_base; struct wl_shm *wl_shm; + struct wl_subcompositor *wl_subcompositor; struct wayland_seat seat; struct wayland_pointer pointer; struct wl_list output_list; @@ -148,6 +149,13 @@ struct wayland_window_config enum wayland_surface_config_state state; };
+struct wayland_client_surface +{ + LONG ref; + struct wl_surface *wl_surface; + struct wl_subsurface *wl_subsurface; +}; + struct wayland_surface { HWND hwnd; @@ -159,6 +167,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 @@ -204,6 +213,8 @@ BOOL wayland_surface_reconfigure(struct wayland_surface *surface) DECLSPEC_HIDDE BOOL wayland_surface_config_is_compatible(struct wayland_surface_config *conf, int width, int height, enum wayland_surface_config_state state) 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