From dc35c8a7b96f663e47326efc9bc39cad049bf777 Mon Sep 17 00:00:00 2001 From: Alexandros Frantzis Date: Tue, 7 Nov 2023 08:15:36 +0200 Subject: [PATCH] winewayland.drv: Ensure Vulkan parent surface is mapped with proper size. 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 2eaec3af3c9..cb945986cba 100644 --- a/dlls/winewayland.drv/vulkan.c +++ b/dlls/winewayland.drv/vulkan.c @@ -266,6 +266,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)