I'm not completely sure about the mechanism, but I think it's simple enough to consider having that upstream now. This shows at least how we can leverage win32u surface changes to decide to switch surfaces on/off-screen and fallback to manual blitting.
Having the surfaces on-screen makes sure they are presented as efficiently as possible, having them off-screen we use GDI blit to indirectly call XCopyArea and this will be suboptimal, probably with visible tearing, but hopefully not too common.
-- v4: win32u: Use GDI blit to implement partial or other process presentation. winex11: Return an offscreen HDC from vulkan_surface_detach. win32u: Pass a HDC parameter to vulkan_surface_detach. winex11: Create a window surface even when there is client window. winex11: Also attach child client windows to their toplevel window. win32u: Make sure vulkan windows have a pixel format selected. win32u: Detach vulkan surfaces that aren't fully visible. win32u: Detach offscreen, child or vulkan surfaces for another process. win32u: Move vulkan surfaces to their new parent when reparenting. win32u: Introduce a new vulkan offscreen surfaces list.
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/vulkan.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-)
diff --git a/dlls/win32u/vulkan.c b/dlls/win32u/vulkan.c index 5b128afe3cb..91cfa237a61 100644 --- a/dlls/win32u/vulkan.c +++ b/dlls/win32u/vulkan.c @@ -45,6 +45,10 @@ static void *vulkan_handle; static const struct vulkan_driver_funcs *driver_funcs; static struct vulkan_funcs vulkan_funcs;
+/* list of surfaces attached to other processes / desktop windows */ +static struct list offscreen_surfaces = LIST_INIT(offscreen_surfaces); +static pthread_mutex_t vulkan_mutex = PTHREAD_MUTEX_INITIALIZER; + static void (*p_vkDestroySurfaceKHR)(VkInstance, VkSurfaceKHR, const VkAllocationCallbacks *); static VkResult (*p_vkQueuePresentKHR)(VkQueue, const VkPresentInfoKHR *); static void *(*p_vkGetDeviceProcAddr)(VkDevice, const char *); @@ -71,6 +75,7 @@ static inline VkSurfaceKHR surface_to_handle( struct surface *surface ) static VkResult win32u_vkCreateWin32SurfaceKHR( VkInstance instance, const VkWin32SurfaceCreateInfoKHR *info, const VkAllocationCallbacks *allocator, VkSurfaceKHR *handle ) { + HWND toplevel = NtUserGetAncestor( info->hwnd, GA_ROOT ); struct surface *surface; VkResult res; WND *win; @@ -85,8 +90,12 @@ static VkResult win32u_vkCreateWin32SurfaceKHR( VkInstance instance, const VkWin return res; }
- if (!(win = get_win_ptr( info->hwnd )) || win == WND_DESKTOP || win == WND_OTHER_PROCESS) - list_init( &surface->entry ); + if (!(win = get_win_ptr( toplevel )) || win == WND_DESKTOP || win == WND_OTHER_PROCESS) + { + pthread_mutex_lock( &vulkan_mutex ); + list_add_tail( &offscreen_surfaces, &surface->entry ); + pthread_mutex_unlock( &vulkan_mutex ); + } else { list_add_tail( &win->vulkan_surfaces, &surface->entry ); @@ -105,7 +114,10 @@ static void win32u_vkDestroySurfaceKHR( VkInstance instance, VkSurfaceKHR handle TRACE( "instance %p, handle 0x%s, allocator %p\n", instance, wine_dbgstr_longlong(handle), allocator ); if (allocator) FIXME( "Support for allocation callbacks not implemented yet\n" );
+ pthread_mutex_lock( &vulkan_mutex ); list_remove( &surface->entry ); + pthread_mutex_unlock( &vulkan_mutex ); + p_vkDestroySurfaceKHR( instance, surface->host_surface, NULL /* allocator */ ); driver_funcs->p_vulkan_surface_destroy( surface->hwnd, surface->driver_private ); free( surface ); @@ -313,14 +325,14 @@ static void vulkan_init(void)
void vulkan_detach_surfaces( struct list *surfaces ) { - struct surface *surface, *next; + struct surface *surface;
- LIST_FOR_EACH_ENTRY_SAFE( surface, next, surfaces, struct surface, entry ) - { + LIST_FOR_EACH_ENTRY( surface, surfaces, struct surface, entry ) driver_funcs->p_vulkan_surface_detach( surface->hwnd, surface->driver_private ); - list_remove( &surface->entry ); - list_init( &surface->entry ); - } + + pthread_mutex_lock( &vulkan_mutex ); + list_move_tail( &offscreen_surfaces, surfaces ); + pthread_mutex_unlock( &vulkan_mutex ); }
/***********************************************************************
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/ntuser_private.h | 1 + dlls/win32u/vulkan.c | 62 ++++++++++++++++++++++++++++++++++++ dlls/win32u/window.c | 1 + 3 files changed, 64 insertions(+)
diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index 11b1a3ff8a1..04396abca72 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -257,6 +257,7 @@ extern LRESULT system_tray_call( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpar
/* vulkan.c */ extern void vulkan_detach_surfaces( struct list *surfaces ); +extern void vulkan_set_parent( HWND hwnd, HWND new_parent, HWND old_parent );
/* window.c */ HANDLE alloc_user_handle( struct user_object *ptr, unsigned int type ); diff --git a/dlls/win32u/vulkan.c b/dlls/win32u/vulkan.c index 91cfa237a61..a6255e9bf36 100644 --- a/dlls/win32u/vulkan.c +++ b/dlls/win32u/vulkan.c @@ -335,6 +335,68 @@ void vulkan_detach_surfaces( struct list *surfaces ) pthread_mutex_unlock( &vulkan_mutex ); }
+static void append_window_surfaces( HWND toplevel, struct list *surfaces ) +{ + WND *win; + + if (!(win = get_win_ptr( toplevel )) || win == WND_DESKTOP || win == WND_OTHER_PROCESS) + { + pthread_mutex_lock( &vulkan_mutex ); + list_move_tail( &offscreen_surfaces, surfaces ); + pthread_mutex_unlock( &vulkan_mutex ); + } + else + { + list_move_tail( &win->vulkan_surfaces, surfaces ); + release_win_ptr( win ); + } +} + +static void enum_window_surfaces( HWND toplevel, HWND hwnd, struct list *surfaces ) +{ + struct list tmp_surfaces = LIST_INIT(tmp_surfaces); + struct surface *surface, *next; + WND *win; + + if (!(win = get_win_ptr( toplevel )) || win == WND_DESKTOP || win == WND_OTHER_PROCESS) + { + pthread_mutex_lock( &vulkan_mutex ); + list_move_tail( &tmp_surfaces, &offscreen_surfaces ); + pthread_mutex_unlock( &vulkan_mutex ); + } + else + { + list_move_tail( &tmp_surfaces, &win->vulkan_surfaces ); + release_win_ptr( win ); + } + + LIST_FOR_EACH_ENTRY_SAFE( surface, next, &tmp_surfaces, struct surface, entry ) + { + if (surface->hwnd != hwnd && !NtUserIsChild( hwnd, surface->hwnd )) continue; + list_remove( &surface->entry ); + list_add_tail( surfaces, &surface->entry ); + } + + append_window_surfaces( toplevel, &tmp_surfaces ); +} + +void vulkan_set_parent( HWND hwnd, HWND new_parent, HWND old_parent ) +{ + struct list surfaces = LIST_INIT(surfaces); + HWND new_toplevel, old_toplevel; + + TRACE( "hwnd %p new_parent %p old_parent %p\n", hwnd, new_parent, old_parent ); + + if (new_parent == NtUserGetDesktopWindow()) new_toplevel = hwnd; + else new_toplevel = NtUserGetAncestor( new_parent, GA_ROOT ); + if (old_parent == NtUserGetDesktopWindow()) old_toplevel = hwnd; + else old_toplevel = NtUserGetAncestor( old_parent, GA_ROOT ); + if (old_toplevel == new_toplevel) return; + + enum_window_surfaces( old_toplevel, hwnd, &surfaces ); + append_window_surfaces( new_toplevel, &surfaces ); +} + /*********************************************************************** * __wine_get_vulkan_driver (win32u.so) */ diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index 13dd1c8d80a..f630f107b00 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -463,6 +463,7 @@ HWND WINAPI NtUserSetParent( HWND hwnd, HWND parent ) context = SetThreadDpiAwarenessContext( get_window_dpi_awareness_context( hwnd ));
user_driver->pSetParent( full_handle, parent, old_parent ); + vulkan_set_parent( full_handle, parent, old_parent );
winpos.hwnd = hwnd; winpos.hwndInsertAfter = HWND_TOP;
From: Rémi Bernon rbernon@codeweavers.com
And attach them back when they are on-screen again. --- dlls/win32u/vulkan.c | 23 +++++++++++++++++++++++ dlls/winemac.drv/vulkan.c | 5 +++++ dlls/winewayland.drv/vulkan.c | 5 +++++ dlls/winex11.drv/vulkan.c | 15 +++++++++++++++ dlls/winex11.drv/window.c | 2 +- dlls/winex11.drv/x11drv.h | 1 + include/wine/vulkan_driver.h | 3 ++- 7 files changed, 52 insertions(+), 2 deletions(-)
diff --git a/dlls/win32u/vulkan.c b/dlls/win32u/vulkan.c index a6255e9bf36..d739a46ab39 100644 --- a/dlls/win32u/vulkan.c +++ b/dlls/win32u/vulkan.c @@ -95,11 +95,13 @@ static VkResult win32u_vkCreateWin32SurfaceKHR( VkInstance instance, const VkWin pthread_mutex_lock( &vulkan_mutex ); list_add_tail( &offscreen_surfaces, &surface->entry ); pthread_mutex_unlock( &vulkan_mutex ); + driver_funcs->p_vulkan_surface_detach( info->hwnd, surface->driver_private ); } else { list_add_tail( &win->vulkan_surfaces, &surface->entry ); release_win_ptr( win ); + if (toplevel != info->hwnd) driver_funcs->p_vulkan_surface_detach( info->hwnd, surface->driver_private ); }
surface->hwnd = info->hwnd; @@ -197,6 +199,10 @@ static void nulldrv_vulkan_surface_destroy( HWND hwnd, void *private ) { }
+static void nulldrv_vulkan_surface_attach( HWND hwnd, void *private ) +{ +} + static void nulldrv_vulkan_surface_detach( HWND hwnd, void *private ) { } @@ -219,6 +225,7 @@ static const struct vulkan_driver_funcs nulldrv_funcs = { .p_vulkan_surface_create = nulldrv_vulkan_surface_create, .p_vulkan_surface_destroy = nulldrv_vulkan_surface_destroy, + .p_vulkan_surface_attach = nulldrv_vulkan_surface_attach, .p_vulkan_surface_detach = nulldrv_vulkan_surface_detach, .p_vulkan_surface_presented = nulldrv_vulkan_surface_presented, .p_vkGetPhysicalDeviceWin32PresentationSupportKHR = nulldrv_vkGetPhysicalDeviceWin32PresentationSupportKHR, @@ -263,6 +270,12 @@ static void lazydrv_vulkan_surface_destroy( HWND hwnd, void *private ) return driver_funcs->p_vulkan_surface_destroy( hwnd, private ); }
+static void lazydrv_vulkan_surface_attach( HWND hwnd, void *private ) +{ + vulkan_driver_load(); + return driver_funcs->p_vulkan_surface_attach( hwnd, private ); +} + static void lazydrv_vulkan_surface_detach( HWND hwnd, void *private ) { vulkan_driver_load(); @@ -291,6 +304,7 @@ static const struct vulkan_driver_funcs lazydrv_funcs = { .p_vulkan_surface_create = lazydrv_vulkan_surface_create, .p_vulkan_surface_destroy = lazydrv_vulkan_surface_destroy, + .p_vulkan_surface_attach = lazydrv_vulkan_surface_attach, .p_vulkan_surface_detach = lazydrv_vulkan_surface_detach, .p_vulkan_surface_presented = lazydrv_vulkan_surface_presented, }; @@ -337,6 +351,7 @@ void vulkan_detach_surfaces( struct list *surfaces )
static void append_window_surfaces( HWND toplevel, struct list *surfaces ) { + struct surface *surface; WND *win;
if (!(win = get_win_ptr( toplevel )) || win == WND_DESKTOP || win == WND_OTHER_PROCESS) @@ -349,6 +364,9 @@ static void append_window_surfaces( HWND toplevel, struct list *surfaces ) { list_move_tail( &win->vulkan_surfaces, surfaces ); release_win_ptr( win ); + + LIST_FOR_EACH_ENTRY( surface, surfaces, struct surface, entry ) + driver_funcs->p_vulkan_surface_attach( surface->hwnd, surface->driver_private ); } }
@@ -384,6 +402,7 @@ void vulkan_set_parent( HWND hwnd, HWND new_parent, HWND old_parent ) { struct list surfaces = LIST_INIT(surfaces); HWND new_toplevel, old_toplevel; + struct surface *surface;
TRACE( "hwnd %p new_parent %p old_parent %p\n", hwnd, new_parent, old_parent );
@@ -394,6 +413,10 @@ void vulkan_set_parent( HWND hwnd, HWND new_parent, HWND old_parent ) if (old_toplevel == new_toplevel) return;
enum_window_surfaces( old_toplevel, hwnd, &surfaces ); + + LIST_FOR_EACH_ENTRY( surface, &surfaces, struct surface, entry ) + driver_funcs->p_vulkan_surface_detach( surface->hwnd, surface->driver_private ); + append_window_surfaces( new_toplevel, &surfaces ); }
diff --git a/dlls/winemac.drv/vulkan.c b/dlls/winemac.drv/vulkan.c index d5a3df579d0..9b033a84d57 100644 --- a/dlls/winemac.drv/vulkan.c +++ b/dlls/winemac.drv/vulkan.c @@ -178,6 +178,10 @@ static void macdrv_vulkan_surface_destroy(HWND hwnd, void *private) wine_vk_surface_destroy(mac_surface); }
+static void macdrv_vulkan_surface_attach(HWND hwnd, void *private) +{ +} + static void macdrv_vulkan_surface_detach(HWND hwnd, void *private) { } @@ -203,6 +207,7 @@ static const struct vulkan_driver_funcs macdrv_vulkan_driver_funcs = { .p_vulkan_surface_create = macdrv_vulkan_surface_create, .p_vulkan_surface_destroy = macdrv_vulkan_surface_destroy, + .p_vulkan_surface_attach = macdrv_vulkan_surface_attach, .p_vulkan_surface_detach = macdrv_vulkan_surface_detach, .p_vulkan_surface_presented = macdrv_vulkan_surface_presented,
diff --git a/dlls/winewayland.drv/vulkan.c b/dlls/winewayland.drv/vulkan.c index 16084175013..cd63981bf0d 100644 --- a/dlls/winewayland.drv/vulkan.c +++ b/dlls/winewayland.drv/vulkan.c @@ -132,6 +132,10 @@ static void wayland_vulkan_surface_destroy(HWND hwnd, void *private) wine_vk_surface_destroy(client); }
+static void wayland_vulkan_surface_attach(HWND hwnd, void *private) +{ +} + static void wayland_vulkan_surface_detach(HWND hwnd, void *private) { } @@ -175,6 +179,7 @@ static const struct vulkan_driver_funcs wayland_vulkan_driver_funcs = { .p_vulkan_surface_create = wayland_vulkan_surface_create, .p_vulkan_surface_destroy = wayland_vulkan_surface_destroy, + .p_vulkan_surface_attach = wayland_vulkan_surface_attach, .p_vulkan_surface_detach = wayland_vulkan_surface_detach, .p_vulkan_surface_presented = wayland_vulkan_surface_presented,
diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c index 85993bc517a..b979da1085e 100644 --- a/dlls/winex11.drv/vulkan.c +++ b/dlls/winex11.drv/vulkan.c @@ -109,6 +109,20 @@ static void X11DRV_vulkan_surface_destroy( HWND hwnd, void *private ) destroy_client_window( hwnd, client_window ); }
+static void X11DRV_vulkan_surface_attach( HWND hwnd, void *private ) +{ + Window client_window = (Window)private; + struct x11drv_win_data *data; + + TRACE( "%p %p\n", hwnd, private ); + + if ((data = get_win_data( hwnd ))) + { + attach_client_window( data, client_window ); + release_win_data( data ); + } +} + static void X11DRV_vulkan_surface_detach( HWND hwnd, void *private ) { Window client_window = (Window)private; @@ -145,6 +159,7 @@ static const struct vulkan_driver_funcs x11drv_vulkan_driver_funcs = { .p_vulkan_surface_create = X11DRV_vulkan_surface_create, .p_vulkan_surface_destroy = X11DRV_vulkan_surface_destroy, + .p_vulkan_surface_attach = X11DRV_vulkan_surface_attach, .p_vulkan_surface_detach = X11DRV_vulkan_surface_detach, .p_vulkan_surface_presented = X11DRV_vulkan_surface_presented,
diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index c6bf49c6ec8..47851f442a3 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1623,7 +1623,7 @@ void detach_client_window( struct x11drv_win_data *data, Window client_window ) /********************************************************************** * attach_client_window */ -static void attach_client_window( struct x11drv_win_data *data, Window client_window ) +void attach_client_window( struct x11drv_win_data *data, Window client_window ) { if (data->client_window == client_window || !client_window) return;
diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 1aaba9bf24b..e919ad36c70 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -649,6 +649,7 @@ extern void read_net_wm_states( Display *display, struct x11drv_win_data *data ) extern void update_net_wm_states( struct x11drv_win_data *data ); extern void make_window_embedded( struct x11drv_win_data *data ); extern Window create_client_window( HWND hwnd, const XVisualInfo *visual, Colormap colormap ); +extern void attach_client_window( struct x11drv_win_data *data, Window client_window ); extern void detach_client_window( struct x11drv_win_data *data, Window client_window ); extern void destroy_client_window( HWND hwnd, Window client_window ); extern void set_window_visual( struct x11drv_win_data *data, const XVisualInfo *vis, BOOL use_alpha ); diff --git a/include/wine/vulkan_driver.h b/include/wine/vulkan_driver.h index 7ddba4739f4..180cff0e09b 100644 --- a/include/wine/vulkan_driver.h +++ b/include/wine/vulkan_driver.h @@ -21,7 +21,7 @@ #define __WINE_VULKAN_DRIVER_H
/* Wine internal vulkan driver version, needs to be bumped upon vulkan_funcs changes. */ -#define WINE_VULKAN_DRIVER_VERSION 34 +#define WINE_VULKAN_DRIVER_VERSION 35
struct vulkan_funcs { @@ -46,6 +46,7 @@ struct vulkan_driver_funcs { VkResult (*p_vulkan_surface_create)(HWND, VkInstance, VkSurfaceKHR *, void **); void (*p_vulkan_surface_destroy)(HWND, void *); + void (*p_vulkan_surface_attach)(HWND, void *); void (*p_vulkan_surface_detach)(HWND, void *); void (*p_vulkan_surface_presented)(HWND, VkResult);
From: Rémi Bernon rbernon@codeweavers.com
And attach them back when they are. --- dlls/win32u/ntuser_private.h | 1 + dlls/win32u/vulkan.c | 54 ++++++++++++++++++++++++++++++++---- dlls/win32u/window.c | 4 ++- 3 files changed, 53 insertions(+), 6 deletions(-)
diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index 04396abca72..7662436a588 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -258,6 +258,7 @@ extern LRESULT system_tray_call( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpar /* vulkan.c */ extern void vulkan_detach_surfaces( struct list *surfaces ); extern void vulkan_set_parent( HWND hwnd, HWND new_parent, HWND old_parent ); +extern void vulkan_set_region( HWND toplevel, HRGN region );
/* window.c */ HANDLE alloc_user_handle( struct user_object *ptr, unsigned int type ); diff --git a/dlls/win32u/vulkan.c b/dlls/win32u/vulkan.c index d739a46ab39..dc126726bc9 100644 --- a/dlls/win32u/vulkan.c +++ b/dlls/win32u/vulkan.c @@ -59,6 +59,7 @@ struct surface struct list entry; VkSurfaceKHR host_surface; void *driver_private; + BOOL is_detached; HWND hwnd; };
@@ -96,12 +97,17 @@ static VkResult win32u_vkCreateWin32SurfaceKHR( VkInstance instance, const VkWin list_add_tail( &offscreen_surfaces, &surface->entry ); pthread_mutex_unlock( &vulkan_mutex ); driver_funcs->p_vulkan_surface_detach( info->hwnd, surface->driver_private ); + surface->is_detached = TRUE; } else { list_add_tail( &win->vulkan_surfaces, &surface->entry ); release_win_ptr( win ); - if (toplevel != info->hwnd) driver_funcs->p_vulkan_surface_detach( info->hwnd, surface->driver_private ); + if (toplevel != info->hwnd) + { + driver_funcs->p_vulkan_surface_detach( info->hwnd, surface->driver_private ); + surface->is_detached = TRUE; + } }
surface->hwnd = info->hwnd; @@ -342,7 +348,11 @@ void vulkan_detach_surfaces( struct list *surfaces ) struct surface *surface;
LIST_FOR_EACH_ENTRY( surface, surfaces, struct surface, entry ) + { + if (surface->is_detached) continue; driver_funcs->p_vulkan_surface_detach( surface->hwnd, surface->driver_private ); + surface->is_detached = TRUE; + }
pthread_mutex_lock( &vulkan_mutex ); list_move_tail( &offscreen_surfaces, surfaces ); @@ -351,7 +361,6 @@ void vulkan_detach_surfaces( struct list *surfaces )
static void append_window_surfaces( HWND toplevel, struct list *surfaces ) { - struct surface *surface; WND *win;
if (!(win = get_win_ptr( toplevel )) || win == WND_DESKTOP || win == WND_OTHER_PROCESS) @@ -364,9 +373,6 @@ static void append_window_surfaces( HWND toplevel, struct list *surfaces ) { list_move_tail( &win->vulkan_surfaces, surfaces ); release_win_ptr( win ); - - LIST_FOR_EACH_ENTRY( surface, surfaces, struct surface, entry ) - driver_funcs->p_vulkan_surface_attach( surface->hwnd, surface->driver_private ); } }
@@ -414,12 +420,50 @@ void vulkan_set_parent( HWND hwnd, HWND new_parent, HWND old_parent )
enum_window_surfaces( old_toplevel, hwnd, &surfaces );
+ /* surfaces will be re-attached as needed from surface region updates */ LIST_FOR_EACH_ENTRY( surface, &surfaces, struct surface, entry ) + { + if (surface->is_detached) continue; driver_funcs->p_vulkan_surface_detach( surface->hwnd, surface->driver_private ); + surface->is_detached = TRUE; + }
append_window_surfaces( new_toplevel, &surfaces ); }
+void vulkan_set_region( HWND toplevel, HRGN region ) +{ + struct list surfaces = LIST_INIT(surfaces); + struct surface *surface; + + enum_window_surfaces( toplevel, toplevel, &surfaces ); + + LIST_FOR_EACH_ENTRY( surface, &surfaces, struct surface, entry ) + { + RECT client_rect; + BOOL is_clipped; + + NtUserGetClientRect( surface->hwnd, &client_rect ); + NtUserMapWindowPoints( surface->hwnd, toplevel, (POINT *)&client_rect, 2 ); + is_clipped = NtGdiRectInRegion( region, &client_rect ); + + if (is_clipped && !surface->is_detached) + { + TRACE( "surface %p is now clipped\n", surface->hwnd ); + driver_funcs->p_vulkan_surface_detach( surface->hwnd, surface->driver_private ); + surface->is_detached = TRUE; + } + else if (!is_clipped && surface->is_detached) + { + TRACE( "surface %p is now unclipped\n", surface->hwnd ); + driver_funcs->p_vulkan_surface_attach( surface->hwnd, surface->driver_private ); + surface->is_detached = FALSE; + } + } + + append_window_surfaces( toplevel, &surfaces ); +} + /*********************************************************************** * __wine_get_vulkan_driver (win32u.so) */ diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index f630f107b00..4cef4b71757 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -1762,10 +1762,12 @@ static void update_surface_region( HWND hwnd ) if (status) goto done;
win->surface->funcs->set_region( win->surface, region ); - if (region) NtGdiDeleteObjectApp( region );
done: release_win_ptr( win ); + + vulkan_set_region( hwnd, region ); + if (region) NtGdiDeleteObjectApp( region ); }
/***********************************************************************
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/vulkan.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/dlls/win32u/vulkan.c b/dlls/win32u/vulkan.c index dc126726bc9..509bb9f1dbd 100644 --- a/dlls/win32u/vulkan.c +++ b/dlls/win32u/vulkan.c @@ -91,6 +91,9 @@ static VkResult win32u_vkCreateWin32SurfaceKHR( VkInstance instance, const VkWin return res; }
+ /* make sure the window has a pixel format selected to get consistent window surface updates */ + if (!win32u_get_window_pixel_format( info->hwnd )) win32u_set_window_pixel_format( info->hwnd, 1, TRUE ); + if (!(win = get_win_ptr( toplevel )) || win == WND_DESKTOP || win == WND_OTHER_PROCESS) { pthread_mutex_lock( &vulkan_mutex );
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/window.c | 54 +++++++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 14 deletions(-)
diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 47851f442a3..c173375694d 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1456,8 +1456,21 @@ static void sync_client_position( struct x11drv_win_data *data,
if (!data->client_window) return;
- changes.x = data->client_rect.left - data->whole_rect.left; - changes.y = data->client_rect.top - data->whole_rect.top; + if (data->whole_window) + { + changes.x = data->client_rect.left - data->whole_rect.left; + changes.y = data->client_rect.top - data->whole_rect.top; + } + else + { + HWND toplevel = NtUserGetAncestor( data->hwnd, GA_ROOT ); + POINT pos = {data->client_rect.left, data->client_rect.top}; + + NtUserMapWindowPoints( toplevel, toplevel, &pos, 1 ); + changes.x = pos.x; + changes.y = pos.y; + } + changes.width = min( max( 1, data->client_rect.right - data->client_rect.left ), 65535 ); changes.height = min( max( 1, data->client_rect.bottom - data->client_rect.top ), 65535 );
@@ -1610,11 +1623,8 @@ void detach_client_window( struct x11drv_win_data *data, Window client_window )
TRACE( "%p/%lx detaching client window %lx\n", data->hwnd, data->whole_window, client_window );
- if (data->whole_window) - { - client_window_events_disable( data, client_window ); - XReparentWindow( gdi_display, client_window, get_dummy_parent(), 0, 0 ); - } + client_window_events_disable( data, client_window ); + XReparentWindow( gdi_display, client_window, get_dummy_parent(), 0, 0 );
data->client_window = 0; } @@ -1625,18 +1635,33 @@ void detach_client_window( struct x11drv_win_data *data, Window client_window ) */ void attach_client_window( struct x11drv_win_data *data, Window client_window ) { + Window whole_window; + POINT pos = {0}; + if (data->client_window == client_window || !client_window) return;
TRACE( "%p/%lx attaching client window %lx\n", data->hwnd, data->whole_window, client_window );
detach_client_window( data, data->client_window );
- if (data->whole_window) + if ((whole_window = data->whole_window)) { - client_window_events_enable( data, client_window ); - XReparentWindow( gdi_display, client_window, data->whole_window, data->client_rect.left - data->whole_rect.left, - data->client_rect.top - data->whole_rect.top ); + pos.x = data->client_rect.left - data->whole_rect.left; + pos.y = data->client_rect.top - data->whole_rect.top; } + else + { + HWND toplevel = NtUserGetAncestor( data->hwnd, GA_ROOT ); + whole_window = X11DRV_get_whole_window( toplevel ); + + pos.x = data->client_rect.left; + pos.y = data->client_rect.top; + NtUserMapWindowPoints( toplevel, toplevel, &pos, 1 ); + } + if (!whole_window) whole_window = get_dummy_parent(); + + client_window_events_enable( data, client_window ); + XReparentWindow( gdi_display, client_window, whole_window, pos.x, pos.y );
data->client_window = client_window; } @@ -1800,6 +1825,9 @@ static void destroy_whole_window( struct x11drv_win_data *data, BOOL already_des { TRACE( "win %p xwin %lx/%lx\n", data->hwnd, data->whole_window, data->client_window );
+ if (!already_destroyed) detach_client_window( data, data->client_window ); + else if (data->client_window) client_window_events_disable( data, data->client_window ); + if (!data->whole_window) { if (data->embedded) @@ -1816,8 +1844,6 @@ static void destroy_whole_window( struct x11drv_win_data *data, BOOL already_des } else { - if (!already_destroyed) detach_client_window( data, data->client_window ); - else if (data->client_window) client_window_events_disable( data, data->client_window ); XDeleteContext( data->display, data->whole_window, winContext ); if (!already_destroyed) { @@ -1826,7 +1852,7 @@ static void destroy_whole_window( struct x11drv_win_data *data, BOOL already_des } } if (data->whole_colormap) XFreeColormap( data->display, data->whole_colormap ); - data->whole_window = data->client_window = 0; + data->whole_window = 0; data->whole_colormap = 0; data->wm_state = WithdrawnState; data->net_wm_state = 0;
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/window.c | 1 - 1 file changed, 1 deletion(-)
diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index c173375694d..3a93ed89afe 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -2653,7 +2653,6 @@ BOOL X11DRV_WindowPosChanging( HWND hwnd, HWND insert_after, UINT swp_flags,
if (data->embedded) goto done; if (data->whole_window == root_window) goto done; - if (data->client_window) goto done; if (!client_side_graphics && !layered) goto done;
if (data->surface)
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/vulkan.c | 38 +++++++++++++++-------------------- dlls/winemac.drv/vulkan.c | 2 +- dlls/winewayland.drv/vulkan.c | 2 +- dlls/winex11.drv/vulkan.c | 4 ++-- include/wine/vulkan_driver.h | 2 +- 5 files changed, 21 insertions(+), 27 deletions(-)
diff --git a/dlls/win32u/vulkan.c b/dlls/win32u/vulkan.c index 509bb9f1dbd..4d03ec87504 100644 --- a/dlls/win32u/vulkan.c +++ b/dlls/win32u/vulkan.c @@ -59,7 +59,7 @@ struct surface struct list entry; VkSurfaceKHR host_surface; void *driver_private; - BOOL is_detached; + HDC offscreen_dc; HWND hwnd; };
@@ -99,18 +99,13 @@ static VkResult win32u_vkCreateWin32SurfaceKHR( VkInstance instance, const VkWin pthread_mutex_lock( &vulkan_mutex ); list_add_tail( &offscreen_surfaces, &surface->entry ); pthread_mutex_unlock( &vulkan_mutex ); - driver_funcs->p_vulkan_surface_detach( info->hwnd, surface->driver_private ); - surface->is_detached = TRUE; + driver_funcs->p_vulkan_surface_detach( info->hwnd, surface->driver_private, &surface->offscreen_dc ); } else { list_add_tail( &win->vulkan_surfaces, &surface->entry ); release_win_ptr( win ); - if (toplevel != info->hwnd) - { - driver_funcs->p_vulkan_surface_detach( info->hwnd, surface->driver_private ); - surface->is_detached = TRUE; - } + if (toplevel != info->hwnd) driver_funcs->p_vulkan_surface_detach( info->hwnd, surface->driver_private, &surface->offscreen_dc ); }
surface->hwnd = info->hwnd; @@ -129,6 +124,7 @@ static void win32u_vkDestroySurfaceKHR( VkInstance instance, VkSurfaceKHR handle list_remove( &surface->entry ); pthread_mutex_unlock( &vulkan_mutex );
+ if (surface->offscreen_dc) NtGdiDeleteObjectApp( surface->offscreen_dc ); p_vkDestroySurfaceKHR( instance, surface->host_surface, NULL /* allocator */ ); driver_funcs->p_vulkan_surface_destroy( surface->hwnd, surface->driver_private ); free( surface ); @@ -212,7 +208,7 @@ static void nulldrv_vulkan_surface_attach( HWND hwnd, void *private ) { }
-static void nulldrv_vulkan_surface_detach( HWND hwnd, void *private ) +static void nulldrv_vulkan_surface_detach( HWND hwnd, void *private, HDC *hdc ) { }
@@ -285,10 +281,10 @@ static void lazydrv_vulkan_surface_attach( HWND hwnd, void *private ) return driver_funcs->p_vulkan_surface_attach( hwnd, private ); }
-static void lazydrv_vulkan_surface_detach( HWND hwnd, void *private ) +static void lazydrv_vulkan_surface_detach( HWND hwnd, void *private, HDC *hdc ) { vulkan_driver_load(); - return driver_funcs->p_vulkan_surface_detach( hwnd, private ); + return driver_funcs->p_vulkan_surface_detach( hwnd, private, hdc ); }
static void lazydrv_vulkan_surface_presented( HWND hwnd, VkResult result ) @@ -352,9 +348,8 @@ void vulkan_detach_surfaces( struct list *surfaces )
LIST_FOR_EACH_ENTRY( surface, surfaces, struct surface, entry ) { - if (surface->is_detached) continue; - driver_funcs->p_vulkan_surface_detach( surface->hwnd, surface->driver_private ); - surface->is_detached = TRUE; + if (surface->offscreen_dc) continue; + driver_funcs->p_vulkan_surface_detach( surface->hwnd, surface->driver_private, &surface->offscreen_dc ); }
pthread_mutex_lock( &vulkan_mutex ); @@ -426,9 +421,8 @@ void vulkan_set_parent( HWND hwnd, HWND new_parent, HWND old_parent ) /* surfaces will be re-attached as needed from surface region updates */ LIST_FOR_EACH_ENTRY( surface, &surfaces, struct surface, entry ) { - if (surface->is_detached) continue; - driver_funcs->p_vulkan_surface_detach( surface->hwnd, surface->driver_private ); - surface->is_detached = TRUE; + if (surface->offscreen_dc) continue; + driver_funcs->p_vulkan_surface_detach( surface->hwnd, surface->driver_private, &surface->offscreen_dc ); }
append_window_surfaces( new_toplevel, &surfaces ); @@ -450,17 +444,17 @@ void vulkan_set_region( HWND toplevel, HRGN region ) NtUserMapWindowPoints( surface->hwnd, toplevel, (POINT *)&client_rect, 2 ); is_clipped = NtGdiRectInRegion( region, &client_rect );
- if (is_clipped && !surface->is_detached) + if (is_clipped && !surface->offscreen_dc) { TRACE( "surface %p is now clipped\n", surface->hwnd ); - driver_funcs->p_vulkan_surface_detach( surface->hwnd, surface->driver_private ); - surface->is_detached = TRUE; + driver_funcs->p_vulkan_surface_detach( surface->hwnd, surface->driver_private, &surface->offscreen_dc ); } - else if (!is_clipped && surface->is_detached) + else if (!is_clipped && surface->offscreen_dc) { TRACE( "surface %p is now unclipped\n", surface->hwnd ); driver_funcs->p_vulkan_surface_attach( surface->hwnd, surface->driver_private ); - surface->is_detached = FALSE; + NtGdiDeleteObjectApp( surface->offscreen_dc ); + surface->offscreen_dc = NULL; } }
diff --git a/dlls/winemac.drv/vulkan.c b/dlls/winemac.drv/vulkan.c index 9b033a84d57..736d0d397d5 100644 --- a/dlls/winemac.drv/vulkan.c +++ b/dlls/winemac.drv/vulkan.c @@ -182,7 +182,7 @@ static void macdrv_vulkan_surface_attach(HWND hwnd, void *private) { }
-static void macdrv_vulkan_surface_detach(HWND hwnd, void *private) +static void macdrv_vulkan_surface_detach(HWND hwnd, void *private, HDC *hdc) { }
diff --git a/dlls/winewayland.drv/vulkan.c b/dlls/winewayland.drv/vulkan.c index cd63981bf0d..175d8cfa49a 100644 --- a/dlls/winewayland.drv/vulkan.c +++ b/dlls/winewayland.drv/vulkan.c @@ -136,7 +136,7 @@ static void wayland_vulkan_surface_attach(HWND hwnd, void *private) { }
-static void wayland_vulkan_surface_detach(HWND hwnd, void *private) +static void wayland_vulkan_surface_detach(HWND hwnd, void *private, HDC *hdc) { }
diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c index b979da1085e..cf5c44012c8 100644 --- a/dlls/winex11.drv/vulkan.c +++ b/dlls/winex11.drv/vulkan.c @@ -123,12 +123,12 @@ static void X11DRV_vulkan_surface_attach( HWND hwnd, void *private ) } }
-static void X11DRV_vulkan_surface_detach( HWND hwnd, void *private ) +static void X11DRV_vulkan_surface_detach( HWND hwnd, void *private, HDC *hdc ) { Window client_window = (Window)private; struct x11drv_win_data *data;
- TRACE( "%p %p\n", hwnd, private ); + TRACE( "%p %p %p\n", hwnd, private, hdc );
if ((data = get_win_data( hwnd ))) { diff --git a/include/wine/vulkan_driver.h b/include/wine/vulkan_driver.h index 180cff0e09b..74cdcd8987f 100644 --- a/include/wine/vulkan_driver.h +++ b/include/wine/vulkan_driver.h @@ -47,7 +47,7 @@ struct vulkan_driver_funcs VkResult (*p_vulkan_surface_create)(HWND, VkInstance, VkSurfaceKHR *, void **); void (*p_vulkan_surface_destroy)(HWND, void *); void (*p_vulkan_surface_attach)(HWND, void *); - void (*p_vulkan_surface_detach)(HWND, void *); + void (*p_vulkan_surface_detach)(HWND, void *, HDC *); void (*p_vulkan_surface_presented)(HWND, VkResult);
VkBool32 (*p_vkGetPhysicalDeviceWin32PresentationSupportKHR)(VkPhysicalDevice, uint32_t);
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/vulkan.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-)
diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c index cf5c44012c8..df6882271b4 100644 --- a/dlls/winex11.drv/vulkan.c +++ b/dlls/winex11.drv/vulkan.c @@ -37,6 +37,7 @@
#include "wine/debug.h" #include "x11drv.h" +#include "xcomposite.h"
#define VK_NO_PROTOTYPES #define WINE_VK_HOST @@ -74,13 +75,6 @@ static VkResult X11DRV_vulkan_surface_create( HWND hwnd, VkInstance instance, Vk
TRACE( "%p %p %p %p\n", hwnd, instance, surface, private );
- /* TODO: support child window rendering. */ - if (NtUserGetAncestor( hwnd, GA_PARENT ) != NtUserGetDesktopWindow()) - { - FIXME("Application requires child window rendering, which is not implemented yet!\n"); - return VK_ERROR_INCOMPATIBLE_DRIVER; - } - if (!(info.window = create_client_window( hwnd, &default_visual, default_colormap ))) { ERR("Failed to allocate client window for hwnd=%p\n", hwnd); @@ -118,6 +112,9 @@ static void X11DRV_vulkan_surface_attach( HWND hwnd, void *private )
if ((data = get_win_data( hwnd ))) { +#ifdef SONAME_LIBXCOMPOSITE + if (usexcomposite) pXCompositeUnredirectWindow( gdi_display, client_window, CompositeRedirectManual ); +#endif attach_client_window( data, client_window ); release_win_data( data ); } @@ -125,6 +122,8 @@ static void X11DRV_vulkan_surface_attach( HWND hwnd, void *private )
static void X11DRV_vulkan_surface_detach( HWND hwnd, void *private, HDC *hdc ) { + static const WCHAR displayW[] = {'D','I','S','P','L','A','Y'}; + UNICODE_STRING device_str = RTL_CONSTANT_STRING(displayW); Window client_window = (Window)private; struct x11drv_win_data *data;
@@ -135,6 +134,19 @@ static void X11DRV_vulkan_surface_detach( HWND hwnd, void *private, HDC *hdc ) detach_client_window( data, client_window ); release_win_data( data ); } + + if (hdc && (*hdc = NtGdiOpenDCW( &device_str, NULL, NULL, 0, TRUE, NULL, NULL, NULL ))) + { + struct x11drv_escape_set_drawable escape = {0}; + escape.code = X11DRV_SET_DRAWABLE; + escape.mode = IncludeInferiors; + escape.drawable = client_window; + NtUserGetClientRect( hwnd, &escape.dc_rect ); + NtGdiExtEscape( *hdc, NULL, 0, X11DRV_ESCAPE, sizeof(escape), (LPSTR)&escape, 0, NULL ); +#ifdef SONAME_LIBXCOMPOSITE + if (usexcomposite) pXCompositeRedirectWindow( gdi_display, client_window, CompositeRedirectManual ); +#endif + } }
static void X11DRV_vulkan_surface_presented(HWND hwnd, VkResult result)
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/vulkan.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+)
diff --git a/dlls/win32u/vulkan.c b/dlls/win32u/vulkan.c index 4d03ec87504..29c9dfbdb72 100644 --- a/dlls/win32u/vulkan.c +++ b/dlls/win32u/vulkan.c @@ -60,6 +60,7 @@ struct surface VkSurfaceKHR host_surface; void *driver_private; HDC offscreen_dc; + HRGN region; HWND hwnd; };
@@ -108,6 +109,7 @@ static VkResult win32u_vkCreateWin32SurfaceKHR( VkInstance instance, const VkWin if (toplevel != info->hwnd) driver_funcs->p_vulkan_surface_detach( info->hwnd, surface->driver_private, &surface->offscreen_dc ); }
+ surface->region = NtGdiCreateRectRgn( 0, 0, 0, 0 ); surface->hwnd = info->hwnd; *handle = surface_to_handle( surface ); return VK_SUCCESS; @@ -127,6 +129,7 @@ static void win32u_vkDestroySurfaceKHR( VkInstance instance, VkSurfaceKHR handle if (surface->offscreen_dc) NtGdiDeleteObjectApp( surface->offscreen_dc ); p_vkDestroySurfaceKHR( instance, surface->host_surface, NULL /* allocator */ ); driver_funcs->p_vulkan_surface_destroy( surface->hwnd, surface->driver_private ); + NtGdiDeleteObjectApp( surface->region ); free( surface ); }
@@ -145,6 +148,26 @@ static VkResult win32u_vkQueuePresentKHR( VkQueue queue, const VkPresentInfoKHR struct surface *surface = surface_from_handle( surfaces[i] );
driver_funcs->p_vulkan_surface_presented( surface->hwnd, swapchain_res ); + + if (swapchain_res >= VK_SUCCESS && surface->offscreen_dc) + { + UINT width, height; + RECT client_rect; + HDC hdc_dst; + + NtUserGetClientRect( surface->hwnd, &client_rect ); + width = client_rect.right - client_rect.left; + height = client_rect.bottom - client_rect.top; + + WARN("Copying vulkan child window %p rect %s\n", surface->hwnd, wine_dbgstr_rect(&client_rect)); + + if ((hdc_dst = NtUserGetDCEx(surface->hwnd, surface->region, DCX_USESTYLE | DCX_CACHE))) + { + NtGdiStretchBlt(hdc_dst, client_rect.left, client_rect.top, width, height, + surface->offscreen_dc, 0, 0, width, height, SRCCOPY, 0); + NtUserReleaseDC(surface->hwnd, hdc_dst); + } + } }
return res; @@ -448,6 +471,7 @@ void vulkan_set_region( HWND toplevel, HRGN region ) { TRACE( "surface %p is now clipped\n", surface->hwnd ); driver_funcs->p_vulkan_surface_detach( surface->hwnd, surface->driver_private, &surface->offscreen_dc ); + NtGdiCombineRgn( surface->region, region, 0, RGN_COPY ); } else if (!is_clipped && surface->offscreen_dc) {
On Fri May 24 07:02:27 2024 +0000, Rémi Bernon wrote:
This should be working now, thanks.
after tested, the skyrim has screen rendered.
Any opinion on this?
On Fri May 24 11:19:46 2024 +0000, Rémi Bernon wrote:
Any opinion on this?
Thank you for the rebased patches! I tested the rebased version on top of 3b0943e0 (May 22) and the OIV app has these issues:
Actions: - start the app in a clean prefix - the cursor is outside of the OIV app's window
Result: - no startup text 'Welcome to OIV' shows in the OIV app window
Action: - move cursor into the OIV app's window or - click on another window that will overlap with the OIV window
Result: - the startup text 'Welcome to OIV...' shows in the window
Actions with OIV app running: - move cursor outside of the OIV window - press F1
Result: - no key bindings are shown
Action: - move cursor into the OVI app's window or - click on another window that will overlap with the OIV window
Result: - the keybindings screen is shown
When DXVK 2.3.1 is installed in the prefix there are no issues. The output from wine (with/without DXVK):
[MR5573_rebased_cli_output.txt](/uploads/fbc81b6724b65df12c5cb502629f0202/MR5573_rebased_cli_output.txt)
This was wine + wine-staging + a few TKG fsync patches. If you prefer I test in plain wine please let me know. The version I tested with (requires Fedora 40) is available at: https://copr.fedorainfracloud.org/coprs/patrickl/wine-tkg-dev/
When DXVK 2.3.1 is installed in the prefix there are no issues.
@Patrick That means OpenGL child window support in winex11 should be reworked (maybe by Rémi?)
On Fri May 24 11:23:16 2024 +0000, Aida Jonikienė wrote:
When DXVK 2.3.1 is installed in the prefix there are no issues.
@Patrick That means OpenGL child window support in winex11 should be reworked (maybe by Rémi?)
I have no intention to touch the GL side at this point, this is only for Vulkan so needs to be tested either with WineD3D Vulkan renderer (setting the `WINE_D3D_CONFIG="renderer=vulkan"` env var), or with DXVK.
On Fri May 24 11:40:30 2024 +0000, Rémi Bernon wrote:
I have no intention to touch the GL side at this point, this is only for Vulkan so needs to be tested either with WineD3D Vulkan renderer (setting the `WINE_D3D_CONFIG="renderer=vulkan"` env var), or with DXVK.
@rbernon Thanks for the env var. I will test wine-9.10 with the env var and with DXVK but it requires a change to the last hunk of patch 04/10 "win32u: Detach vulkan surfaces that aren't fully visible." which no longer applies to 9.10. See https://gitlab.winehq.org/rbernon/wine/-/commit/bc5764024932969016ccc8d84cb3...
Sorry for the delay, it's hard for me to have a concrete opinion. The approach is very different than what I imagined. Those win32u internals and child list shuffling feels specific to this exact winex11 implementation and it's not clear to me that we need a driver-specific thing like that in the first place.
With things like the compositor on the horizon, I expect that we will want to submit child window to the compositor rather than to graphics driver. I guess that means we will need to be able to create some form of virtualized swapchain where we have full control over the presentation, sort of like you did for the GDI fallback. Something like `VK_EXT_headless_surface` seems nice for it, but we have enough control over Vulkan overall to do things like that without it.
For the actual host WSI surface, we could require just one, for the top level window. If we had it detached from the client surfaces (like above), we could just create, modify, recreate and reattach it to surfaces at as it suits us. For the presentation, we'd pass through images whenever possible. If it's not possible to pass through, we fallback to GDI path. Ideally, that's where we'd plug into the compositor to make it efficient, but I think it would be interesting to try something like that even without the compositor.
I can't be sure about any of that without trying. That said, I'm unassigning myself as I don't intend to be a blocker.
I have been testing this MR with Roblox Studio has a bunch of issues
- The scene window is not in the correct position overlapping the top tool window - The Roblox Marketplace window on the left is completely covered with graphical artifacts - Many menu windows break or are drawn on top of other windows when you resize the window
Tested on top of 3b0943e0 with DXVK 2.4 and special for roblox patch

Legacy childwindow patch don`t have its issues

Log file: [roblox-studio.log](/uploads/c8e4ceea5cb9d5dac0859530a9f6dcc6/roblox-studio.log)
Closing in favor of https://gitlab.winehq.org/wine/wine/-/merge_requests/6467, which keeps the winex11-specific logic private to winex11. Something smarter could later be implemented, possibly through the use of an internal compositor.
This merge request was closed by Rémi Bernon.