From: Alexandros Frantzis alexandros.frantzis@collabora.com
The client area subsurface (the target of Vulkan rendering) is not going to be presented by the compositor if its parent surface is not mapped, even though the window may be visible from Wine's perspective. To avoid this issue, ensure that the parent surface has valid contents, 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 | 60 ++++++++++++++++++++++++++ dlls/winewayland.drv/waylanddrv.h | 3 ++ dlls/winewayland.drv/window.c | 12 +++++- 4 files changed, 75 insertions(+), 2 deletions(-)
diff --git a/dlls/winewayland.drv/vulkan.c b/dlls/winewayland.drv/vulkan.c index 396acdbc174..ca559d1ea65 100644 --- a/dlls/winewayland.drv/vulkan.c +++ b/dlls/winewayland.drv/vulkan.c @@ -289,6 +289,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..166c1bba002 100644 --- a/dlls/winewayland.drv/wayland_surface.c +++ b/dlls/winewayland.drv/wayland_surface.c @@ -336,6 +336,8 @@ void wayland_surface_attach_shm(struct wayland_surface *surface, } free(surface_damage); } + + surface->needs_contents = FALSE; }
/********************************************************************** @@ -825,3 +827,61 @@ 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; + + TRACE("surface=%p hwnd=%p needs_contents=%d\n", + surface, surface->hwnd, surface->needs_contents); + + if (!surface->needs_contents) return; + + width = surface->window.rect.right - surface->window.rect.left; + height = surface->window.rect.bottom - surface->window.rect.top; + + /* 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..0516e1cbd91 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -187,6 +187,7 @@ struct wayland_surface BOOL resizing; struct wayland_window_config window; struct wayland_client_surface *client; + BOOL needs_contents; };
struct wayland_shm_buffer @@ -240,6 +241,8 @@ 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..f30b3a88c74 100644 --- a/dlls/winewayland.drv/window.c +++ b/dlls/winewayland.drv/window.c @@ -183,7 +183,8 @@ static void wayland_win_data_get_config(struct wayland_win_data *data, conf->scale = NtUserGetDpiForWindow(data->hwnd) / 96.0; }
-static void wayland_win_data_update_wayland_surface(struct wayland_win_data *data) +static void wayland_win_data_update_wayland_surface(struct wayland_win_data *data, + BOOL has_new_window_surface) { struct wayland_surface *surface = data->wayland_surface; HWND parent = NtUserGetAncestor(data->hwnd, GA_PARENT); @@ -221,6 +222,11 @@ static void wayland_win_data_update_wayland_surface(struct wayland_win_data *dat
wayland_win_data_get_config(data, &surface->window);
+ if (!visible) + surface->needs_contents = FALSE; + else if (xdg_visible != visible || has_new_window_surface) + surface->needs_contents = TRUE; + pthread_mutex_unlock(&surface->mutex);
if (data->window_surface) @@ -359,6 +365,7 @@ void WAYLAND_WindowPosChanged(HWND hwnd, HWND insert_after, UINT swp_flags, struct window_surface *surface) { struct wayland_win_data *data = wayland_win_data_get(hwnd); + BOOL has_new_window_surface;
TRACE("hwnd %p window %s client %s visible %s after %p flags %08x\n", hwnd, wine_dbgstr_rect(window_rect), wine_dbgstr_rect(client_rect), @@ -369,11 +376,12 @@ void WAYLAND_WindowPosChanged(HWND hwnd, HWND insert_after, UINT swp_flags, data->window_rect = *window_rect; data->client_rect = *client_rect;
+ has_new_window_surface = surface != data->window_surface; if (surface) window_surface_add_ref(surface); if (data->window_surface) window_surface_release(data->window_surface); data->window_surface = surface;
- wayland_win_data_update_wayland_surface(data); + wayland_win_data_update_wayland_surface(data, has_new_window_surface); if (data->wayland_surface) wayland_win_data_update_wayland_state(data);
wayland_win_data_release(data);