This does the same as https://gitlab.winehq.org/wine/wine/-/merge_requests/6398 but for Vulkan. It also implements vulkan child window rendering pretty much for free and supersedes https://gitlab.winehq.org/wine/wine/-/merge_requests/5573.
It is not completely optimal and there as missed opportunities to keep child windows on screen when no DPI scaling and no cropping is needed, but it would require to be smarter and have knowledge about the window clipping region, which will probably better be done in win32u. This is exactly the same for OpenGL, and it will probably be solved together.
-- v2: winex11: Implement vulkan DPI scaling and child window rendering. winex11: Only update the client window position in sync_client_position. winex11: Update the GL client window size when it is presented. winex11: Update the vulkan surface size when it is presented. winex11: Use a dedicated structure for vulkan surface private data. win32u: Pass vulkan driver private data to vulkan_surface_presented. winevulkan: Use client rect in window DPI instead of monitor DPI.
From: Rémi Bernon rbernon@codeweavers.com
The application might not be per-monitor aware and we will need to scale the vulkan surface ourselves, but rendering in per-monitor DPI unit will otherwise confuse it. --- dlls/winevulkan/vulkan.c | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-)
diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index 53b567e97d8..4980d42204d 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -38,15 +38,6 @@ static PFN_vkEnumerateInstanceVersion p_vkEnumerateInstanceVersion; static PFN_vkEnumerateInstanceExtensionProperties p_vkEnumerateInstanceExtensionProperties;
-/********************************************************************** - * get_win_monitor_dpi - */ -static UINT get_win_monitor_dpi( HWND hwnd ) -{ - return NtUserGetSystemDpiForProcess( NULL ); /* FIXME: get monitor dpi */ -} - - static int window_surface_compare(const void *key, const struct rb_entry *entry) { const struct wine_surface *surface = RB_ENTRY_VALUE(entry, struct wine_surface, window_entry); @@ -1740,7 +1731,7 @@ VkResult wine_vkAcquireNextImage2KHR(VkDevice device_handle, const VkAcquireNext acquire_info_host.swapchain = swapchain->host_swapchain; res = device->funcs.p_vkAcquireNextImage2KHR(device->host_device, &acquire_info_host, image_index);
- if (res == VK_SUCCESS && NtUserGetClientRect(surface->hwnd, &client_rect, get_win_monitor_dpi(surface->hwnd)) && + if (res == VK_SUCCESS && NtUserGetClientRect(surface->hwnd, &client_rect, NtUserGetDpiForWindow(surface->hwnd)) && !extents_equals(&swapchain->extents, &client_rect)) { WARN("Swapchain size %dx%d does not match client rect %s, returning VK_SUBOPTIMAL_KHR\n", @@ -1763,7 +1754,7 @@ VkResult wine_vkAcquireNextImageKHR(VkDevice device_handle, VkSwapchainKHR swapc res = device->funcs.p_vkAcquireNextImageKHR(device->host_device, swapchain->host_swapchain, timeout, semaphore, fence, image_index);
- if (res == VK_SUCCESS && NtUserGetClientRect(surface->hwnd, &client_rect, get_win_monitor_dpi(surface->hwnd)) && + if (res == VK_SUCCESS && NtUserGetClientRect(surface->hwnd, &client_rect, NtUserGetDpiForWindow(surface->hwnd)) && !extents_equals(&swapchain->extents, &client_rect)) { WARN("Swapchain size %dx%d does not match client rect %s, returning VK_SUBOPTIMAL_KHR\n", @@ -1871,7 +1862,7 @@ VkResult wine_vkQueuePresentKHR(VkQueue queue_handle, const VkPresentInfoKHR *pr RECT client_rect;
if (swapchain_res < VK_SUCCESS) continue; - if (!NtUserGetClientRect(surface->hwnd, &client_rect, get_win_monitor_dpi(surface->hwnd))) + if (!NtUserGetClientRect(surface->hwnd, &client_rect, NtUserGetDpiForWindow(surface->hwnd))) { WARN("Swapchain window %p is invalid, returning VK_ERROR_OUT_OF_DATE_KHR\n", surface->hwnd); if (present_info->pResults) present_info->pResults[i] = VK_ERROR_OUT_OF_DATE_KHR; @@ -2234,7 +2225,7 @@ static void adjust_surface_capabilities(struct wine_instance *instance, struct w
/* Update the image extents to match what the Win32 WSI would provide. */ /* FIXME: handle DPI scaling, somehow */ - NtUserGetClientRect(surface->hwnd, &client_rect, get_win_monitor_dpi(surface->hwnd)); + NtUserGetClientRect(surface->hwnd, &client_rect, NtUserGetDpiForWindow(surface->hwnd)); capabilities->minImageExtent.width = client_rect.right - client_rect.left; capabilities->minImageExtent.height = client_rect.bottom - client_rect.top; capabilities->maxImageExtent.width = client_rect.right - client_rect.left;
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/vulkan.c | 8 ++++---- dlls/winemac.drv/vulkan.c | 2 +- dlls/winewayland.drv/vulkan.c | 2 +- dlls/winex11.drv/vulkan.c | 2 +- include/wine/vulkan_driver.h | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/dlls/win32u/vulkan.c b/dlls/win32u/vulkan.c index 471a4459ec3..d285b07b951 100644 --- a/dlls/win32u/vulkan.c +++ b/dlls/win32u/vulkan.c @@ -127,7 +127,7 @@ static VkResult win32u_vkQueuePresentKHR( VkQueue queue, const VkPresentInfoKHR VkResult swapchain_res = present_info->pResults ? present_info->pResults[i] : res; struct surface *surface = surface_from_handle( surfaces[i] );
- driver_funcs->p_vulkan_surface_presented( surface->hwnd, swapchain_res ); + driver_funcs->p_vulkan_surface_presented( surface->hwnd, surface->driver_private, swapchain_res ); }
return res; @@ -191,7 +191,7 @@ static void nulldrv_vulkan_surface_detach( HWND hwnd, void *private ) { }
-static void nulldrv_vulkan_surface_presented( HWND hwnd, VkResult result ) +static void nulldrv_vulkan_surface_presented( HWND hwnd, void *private, VkResult result ) { }
@@ -259,10 +259,10 @@ static void lazydrv_vulkan_surface_detach( HWND hwnd, void *private ) return driver_funcs->p_vulkan_surface_detach( hwnd, private ); }
-static void lazydrv_vulkan_surface_presented( HWND hwnd, VkResult result ) +static void lazydrv_vulkan_surface_presented( HWND hwnd, void *private, VkResult result ) { vulkan_driver_load(); - return driver_funcs->p_vulkan_surface_presented( hwnd, result ); + driver_funcs->p_vulkan_surface_presented( hwnd, private, result ); }
static VkBool32 lazydrv_vkGetPhysicalDeviceWin32PresentationSupportKHR( VkPhysicalDevice device, uint32_t queue ) diff --git a/dlls/winemac.drv/vulkan.c b/dlls/winemac.drv/vulkan.c index d5a3df579d0..3c6c5ee5b7f 100644 --- a/dlls/winemac.drv/vulkan.c +++ b/dlls/winemac.drv/vulkan.c @@ -182,7 +182,7 @@ static void macdrv_vulkan_surface_detach(HWND hwnd, void *private) { }
-static void macdrv_vulkan_surface_presented(HWND hwnd, VkResult result) +static void macdrv_vulkan_surface_presented(HWND hwnd, void *private, VkResult result) { }
diff --git a/dlls/winewayland.drv/vulkan.c b/dlls/winewayland.drv/vulkan.c index 7a075a925b7..25a6117cb45 100644 --- a/dlls/winewayland.drv/vulkan.c +++ b/dlls/winewayland.drv/vulkan.c @@ -132,7 +132,7 @@ static void wayland_vulkan_surface_detach(HWND hwnd, void *private) { }
-static void wayland_vulkan_surface_presented(HWND hwnd, VkResult result) +static void wayland_vulkan_surface_presented(HWND hwnd, void *private, VkResult result) { ensure_window_surface_contents(hwnd); } diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c index 85993bc517a..7d41d482c8e 100644 --- a/dlls/winex11.drv/vulkan.c +++ b/dlls/winex11.drv/vulkan.c @@ -123,7 +123,7 @@ static void X11DRV_vulkan_surface_detach( HWND hwnd, void *private ) } }
-static void X11DRV_vulkan_surface_presented(HWND hwnd, VkResult result) +static void X11DRV_vulkan_surface_presented( HWND hwnd, void *private, VkResult result ) { }
diff --git a/include/wine/vulkan_driver.h b/include/wine/vulkan_driver.h index 7ddba4739f4..3b1f20fda80 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_detach)(HWND, void *); - void (*p_vulkan_surface_presented)(HWND, VkResult); + void (*p_vulkan_surface_presented)(HWND, void *, VkResult);
VkBool32 (*p_vkGetPhysicalDeviceWin32PresentationSupportKHR)(VkPhysicalDevice, uint32_t); const char *(*p_get_host_surface_extension)(void);
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/vulkan.c | 40 +++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-)
diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c index 7d41d482c8e..92c5fe9212f 100644 --- a/dlls/winex11.drv/vulkan.c +++ b/dlls/winex11.drv/vulkan.c @@ -64,15 +64,27 @@ static VkBool32 (*pvkGetPhysicalDeviceXlibPresentationSupportKHR)(VkPhysicalDevi
static const struct vulkan_driver_funcs x11drv_vulkan_driver_funcs;
-static VkResult X11DRV_vulkan_surface_create( HWND hwnd, VkInstance instance, VkSurfaceKHR *surface, void **private ) +struct vulkan_surface +{ + Window window; +}; + +static void vulkan_surface_destroy( HWND hwnd, struct vulkan_surface *surface ) +{ + destroy_client_window( hwnd, surface->window ); + free( surface ); +} + +static VkResult X11DRV_vulkan_surface_create( HWND hwnd, VkInstance instance, VkSurfaceKHR *handle, void **private ) { VkXlibSurfaceCreateInfoKHR info = { .sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, .dpy = gdi_display, }; + struct vulkan_surface *surface;
- TRACE( "%p %p %p %p\n", hwnd, instance, surface, private ); + TRACE( "%p %p %p %p\n", hwnd, instance, handle, private );
/* TODO: support child window rendering. */ if (NtUserGetAncestor( hwnd, GA_PARENT ) != NtUserGetDesktopWindow()) @@ -81,37 +93,45 @@ static VkResult X11DRV_vulkan_surface_create( HWND hwnd, VkInstance instance, Vk return VK_ERROR_INCOMPATIBLE_DRIVER; }
- if (!(info.window = create_client_window( hwnd, &default_visual, default_colormap ))) + if (!(surface = calloc(1, sizeof(*surface)))) + { + ERR("Failed to allocate vulkan surface for hwnd=%p\n", hwnd); + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + if (!(surface->window = create_client_window( hwnd, &default_visual, default_colormap ))) { ERR("Failed to allocate client window for hwnd=%p\n", hwnd); + free( surface ); return VK_ERROR_OUT_OF_HOST_MEMORY; }
- if (pvkCreateXlibSurfaceKHR( instance, &info, NULL /* allocator */, surface )) + info.window = surface->window; + if (pvkCreateXlibSurfaceKHR( instance, &info, NULL /* allocator */, handle )) { ERR("Failed to create Xlib surface\n"); - destroy_client_window( hwnd, info.window ); + vulkan_surface_destroy( hwnd, surface ); return VK_ERROR_OUT_OF_HOST_MEMORY; }
- *private = (void *)info.window; + *private = (void *)surface;
- TRACE("Created surface 0x%s, private %p\n", wine_dbgstr_longlong(*surface), *private); + TRACE("Created surface 0x%s, private %p\n", wine_dbgstr_longlong(*handle), *private); return VK_SUCCESS; }
static void X11DRV_vulkan_surface_destroy( HWND hwnd, void *private ) { - Window client_window = (Window)private; + struct vulkan_surface *surface = private;
TRACE( "%p %p\n", hwnd, private );
- destroy_client_window( hwnd, client_window ); + vulkan_surface_destroy( hwnd, surface ); }
static void X11DRV_vulkan_surface_detach( HWND hwnd, void *private ) { - Window client_window = (Window)private; + struct vulkan_surface *surface = private; + Window client_window = surface->window; struct x11drv_win_data *data;
TRACE( "%p %p\n", hwnd, private );
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/vulkan.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+)
diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c index 92c5fe9212f..dbfc7a928ec 100644 --- a/dlls/winex11.drv/vulkan.c +++ b/dlls/winex11.drv/vulkan.c @@ -67,6 +67,7 @@ static const struct vulkan_driver_funcs x11drv_vulkan_driver_funcs; struct vulkan_surface { Window window; + RECT rect; };
static void vulkan_surface_destroy( HWND hwnd, struct vulkan_surface *surface ) @@ -104,6 +105,7 @@ static VkResult X11DRV_vulkan_surface_create( HWND hwnd, VkInstance instance, Vk free( surface ); return VK_ERROR_OUT_OF_HOST_MEMORY; } + NtUserGetClientRect( hwnd, &surface->rect, NtUserGetDpiForWindow( hwnd ) );
info.window = surface->window; if (pvkCreateXlibSurfaceKHR( instance, &info, NULL /* allocator */, handle )) @@ -143,8 +145,24 @@ static void X11DRV_vulkan_surface_detach( HWND hwnd, void *private ) } }
+static void vulkan_surface_update_size( HWND hwnd, struct vulkan_surface *surface ) +{ + XWindowChanges changes; + RECT rect; + + NtUserGetClientRect( hwnd, &rect, NtUserGetDpiForWindow( hwnd ) ); + if (EqualRect( &surface->rect, &rect )) return; + + changes.width = min( max( 1, rect.right ), 65535 ); + changes.height = min( max( 1, rect.bottom ), 65535 ); + XConfigureWindow( gdi_display, surface->window, CWWidth | CWHeight, &changes ); + surface->rect = rect; +} + static void X11DRV_vulkan_surface_presented( HWND hwnd, void *private, VkResult result ) { + struct vulkan_surface *surface = private; + vulkan_surface_update_size( hwnd, surface ); }
static VkBool32 X11DRV_vkGetPhysicalDeviceWin32PresentationSupportKHR(VkPhysicalDevice phys_dev,
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/opengl.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index 8ee0a824753..eee57f6b804 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -2840,6 +2840,7 @@ static void update_gl_drawable_size( struct gl_drawable *gl )
switch (gl->type) { + case DC_GL_WINDOW: case DC_GL_CHILD_WIN: gl->rect = rect; XConfigureWindow( gdi_display, gl->window, CWWidth | CWHeight, &changes );
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/window.c | 5 ----- 1 file changed, 5 deletions(-)
diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 8d795581f83..69b38bef5b6 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1387,13 +1387,8 @@ static void sync_client_position( struct x11drv_win_data *data, const struct win
changes.x = data->rects.client.left - data->rects.visible.left; changes.y = data->rects.client.top - data->rects.visible.top; - changes.width = min( max( 1, data->rects.client.right - data->rects.client.left ), 65535 ); - changes.height = min( max( 1, data->rects.client.bottom - data->rects.client.top ), 65535 ); - if (changes.x != old_rects->client.left - old_rects->visible.left) mask |= CWX; if (changes.y != old_rects->client.top - old_rects->visible.top) mask |= CWY; - if (changes.width != old_rects->client.right - old_rects->client.left) mask |= CWWidth; - if (changes.height != old_rects->client.bottom - old_rects->client.top) mask |= CWHeight;
if (mask) {
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/opengl.c | 20 ++++++------ dlls/winex11.drv/vulkan.c | 68 +++++++++++++++++++++++++++++++++++---- dlls/winex11.drv/x11drv.h | 5 +++ 3 files changed, 75 insertions(+), 18 deletions(-)
diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index eee57f6b804..b8ddd859bfb 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -1090,7 +1090,7 @@ static GLXContext create_glxcontext(Display *display, struct wgl_context *contex return ctx; }
-static void set_dc_drawable( HDC hdc, Drawable drawable, const RECT *rect, int mode ) +void set_dc_drawable( HDC hdc, Drawable drawable, const RECT *rect, int mode ) { struct x11drv_escape_set_drawable escape = { @@ -1102,15 +1102,13 @@ static void set_dc_drawable( HDC hdc, Drawable drawable, const RECT *rect, int m NtGdiExtEscape( hdc, NULL, 0, X11DRV_ESCAPE, sizeof(escape), (LPSTR)&escape, 0, NULL ); }
-static BOOL needs_offscreen_rendering( HWND hwnd, BOOL known_child ) +BOOL needs_offscreen_rendering( HWND hwnd, BOOL known_child ) { - if (NtUserGetDpiForWindow( hwnd ) != get_win_monitor_dpi( hwnd )) return TRUE; - - if (!known_child && !NtUserGetWindowRelative( hwnd, GW_CHILD ) && - NtUserGetAncestor( hwnd, GA_PARENT ) == NtUserGetDesktopWindow()) - return FALSE; /* childless top-level window */ - - return TRUE; + if (NtUserGetDpiForWindow( hwnd ) != get_win_monitor_dpi( hwnd )) return TRUE; /* needs DPI scaling */ + if (NtUserGetAncestor( hwnd, GA_PARENT ) != NtUserGetDesktopWindow()) return TRUE; /* child window, needs compositing */ + if (NtUserGetWindowRelative( hwnd, GW_CHILD )) return TRUE; /* window has children, needs compositing */ + if (known_child) return TRUE; /* window is/have children, needs compositing */ + return FALSE; }
/*********************************************************************** @@ -1865,7 +1863,7 @@ static BOOL glxdrv_wglShareLists(struct wgl_context *org, struct wgl_context *de return TRUE; }
-static Drawable get_dc_drawable( HDC hdc, RECT *rect ) +Drawable get_dc_drawable( HDC hdc, RECT *rect ) { struct x11drv_escape_get_drawable escape = {.code = X11DRV_GET_DRAWABLE}; NtGdiExtEscape( hdc, NULL, 0, X11DRV_ESCAPE, sizeof(escape), (LPSTR)&escape, sizeof(escape), (LPSTR)&escape ); @@ -1873,7 +1871,7 @@ static Drawable get_dc_drawable( HDC hdc, RECT *rect ) return escape.drawable; }
-static HRGN get_dc_monitor_region( HWND hwnd, HDC hdc ) +HRGN get_dc_monitor_region( HWND hwnd, HDC hdc ) { RGNDATA *data; UINT i, size; diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c index dbfc7a928ec..338b58b2553 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 @@ -68,11 +69,17 @@ struct vulkan_surface { Window window; RECT rect; + + BOOL offscreen; + HDC hdc_src; + HDC hdc_dst; };
static void vulkan_surface_destroy( HWND hwnd, struct vulkan_surface *surface ) { destroy_client_window( hwnd, surface->window ); + if (surface->hdc_dst) NtGdiDeleteObjectApp( surface->hdc_dst ); + if (surface->hdc_src) NtGdiDeleteObjectApp( surface->hdc_src ); free( surface ); }
@@ -87,13 +94,6 @@ static VkResult X11DRV_vulkan_surface_create( HWND hwnd, VkInstance instance, Vk
TRACE( "%p %p %p %p\n", hwnd, instance, handle, 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 (!(surface = calloc(1, sizeof(*surface)))) { ERR("Failed to allocate vulkan surface for hwnd=%p\n", hwnd); @@ -107,6 +107,28 @@ static VkResult X11DRV_vulkan_surface_create( HWND hwnd, VkInstance instance, Vk } NtUserGetClientRect( hwnd, &surface->rect, NtUserGetDpiForWindow( hwnd ) );
+#ifdef SONAME_LIBXCOMPOSITE + if (needs_offscreen_rendering( hwnd, FALSE ) && usexcomposite) + { + static const WCHAR displayW[] = {'D','I','S','P','L','A','Y'}; + UNICODE_STRING device_str = RTL_CONSTANT_STRING(displayW); + struct x11drv_win_data *data; + + pXCompositeRedirectWindow( gdi_display, surface->window, CompositeRedirectManual ); + + if ((data = get_win_data( hwnd ))) + { + detach_client_window( data, surface->window ); + release_win_data( data ); + } + + surface->offscreen = TRUE; + surface->hdc_dst = NtGdiOpenDCW( &device_str, NULL, NULL, 0, TRUE, NULL, NULL, NULL ); + surface->hdc_src = NtGdiOpenDCW( &device_str, NULL, NULL, 0, TRUE, NULL, NULL, NULL ); + set_dc_drawable( surface->hdc_src, surface->window, &surface->rect, IncludeInferiors ); + } +#endif + info.window = surface->window; if (pvkCreateXlibSurfaceKHR( instance, &info, NULL /* allocator */, handle )) { @@ -162,7 +184,39 @@ static void vulkan_surface_update_size( HWND hwnd, struct vulkan_surface *surfac static void X11DRV_vulkan_surface_presented( HWND hwnd, void *private, VkResult result ) { struct vulkan_surface *surface = private; + HWND toplevel = NtUserGetAncestor( hwnd, GA_ROOT ); + struct x11drv_win_data *data; + RECT rect_dst, rect; + Drawable window; + HRGN region; + HDC hdc; + vulkan_surface_update_size( hwnd, surface ); + + if (!surface->offscreen) return; + if (!(hdc = NtUserGetDCEx( hwnd, 0, DCX_CACHE | DCX_CLIPCHILDREN ))) return; + window = X11DRV_get_whole_window( toplevel ); + region = get_dc_monitor_region( hwnd, hdc ); + + NtUserGetClientRect( hwnd, &rect_dst, get_win_monitor_dpi( hwnd ) ); + NtUserMapWindowPoints( hwnd, toplevel, (POINT *)&rect_dst, 2, get_win_monitor_dpi( hwnd ) ); + + if ((data = get_win_data( toplevel ))) + { + OffsetRect( &rect_dst, data->rects.client.left - data->rects.visible.left, + data->rects.client.top - data->rects.visible.top ); + release_win_data( data ); + } + + if (get_dc_drawable( surface->hdc_dst, &rect ) != window || !EqualRect( &rect, &rect_dst )) + set_dc_drawable( surface->hdc_dst, window, &rect_dst, ClipByChildren ); + if (region) NtGdiExtSelectClipRgn( surface->hdc_dst, region, RGN_COPY ); + + NtGdiStretchBlt( surface->hdc_dst, 0, 0, rect_dst.right - rect_dst.left, rect_dst.bottom - rect_dst.top, + surface->hdc_src, 0, 0, surface->rect.right, surface->rect.bottom, SRCCOPY, 0 ); + + if (region) NtGdiDeleteObjectApp( region ); + if (hdc) NtGdiDeleteObjectApp( hdc ); }
static VkBool32 X11DRV_vkGetPhysicalDeviceWin32PresentationSupportKHR(VkPhysicalDevice phys_dev, diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index bffcd196d04..10257898a76 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -353,6 +353,11 @@ struct x11drv_escape_get_drawable RECT dc_rect; /* DC rectangle relative to drawable */ };
+extern BOOL needs_offscreen_rendering( HWND hwnd, BOOL known_child ); +extern void set_dc_drawable( HDC hdc, Drawable drawable, const RECT *rect, int mode ); +extern Drawable get_dc_drawable( HDC hdc, RECT *rect ); +extern HRGN get_dc_monitor_region( HWND hwnd, HDC hdc ); + /************************************************************************** * X11 USER driver */