From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/opengl.c | 20 ++++++------- dlls/winex11.drv/vulkan.c | 62 +++++++++++++++++++++++++++++++++++++++ dlls/winex11.drv/x11drv.h | 5 ++++ 3 files changed, 76 insertions(+), 11 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..21152114357 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 ); }
@@ -107,6 +114,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 +191,40 @@ 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 */