Right now this should not do anything because all windows are per-monitor DPI aware. When this is changed this will automatically fall back to window surface scaling through `NtGdiStretchBlt` in win32u.
This has the disadvantage that `NtGdiStretchBlt` is doing an absolutely terrible job at upscaling. This then adds a way for drivers to opt-in and do their own surface scaling before falling back to win32u. Alternatively and perhaps better, we could pull libcairo and use it to scale the surface contents with high quality filtering instead of using GDI.
-- v5: win32u: Implement DPI scaled window surface. win32u: Move window_surface creation helper to dce.c. win32u: Map window rects DPI before calling into the drivers. win32u: Map window region DPI before calling into the drivers.
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/sysparams.c | 23 +++++++++++++++++++++++ dlls/win32u/win32u_private.h | 1 + dlls/win32u/window.c | 8 +++++++- 3 files changed, 31 insertions(+), 1 deletion(-)
diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 1106c265402..d26e7f76bfe 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -2249,6 +2249,29 @@ RECT map_dpi_rect( RECT rect, UINT dpi_from, UINT dpi_to ) return rect; }
+/********************************************************************** + * map_dpi_region + */ +HRGN map_dpi_region( HRGN hrgn, UINT dpi_from, UINT dpi_to ) +{ + RGNDATA *data; + UINT i, size; + + if (!(size = NtGdiGetRegionData( hrgn, 0, NULL ))) return 0; + if (!(data = malloc( size ))) return 0; + NtGdiGetRegionData( hrgn, size, data ); + + if (dpi_from && dpi_to && dpi_from != dpi_to) + { + RECT *rects = (RECT *)data->Buffer; + for (i = 0; i < data->rdh.nCount; i++) rects[i] = map_dpi_rect( rects[i], dpi_from, dpi_to ); + } + + hrgn = NtGdiExtCreateRegion( NULL, data->rdh.dwSize + data->rdh.nRgnSize, data ); + free( data ); + return hrgn; +} + /********************************************************************** * map_dpi_point */ diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 2058d0332f7..b15c8ebd9dd 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -183,6 +183,7 @@ extern RECT get_virtual_screen_rect( UINT dpi ); extern BOOL is_exiting_thread( DWORD tid ); extern POINT map_dpi_point( POINT pt, UINT dpi_from, UINT dpi_to ); extern RECT map_dpi_rect( RECT rect, UINT dpi_from, UINT dpi_to ); +extern HRGN map_dpi_region( HRGN region, UINT dpi_from, UINT dpi_to ); extern BOOL message_beep( UINT i ); extern POINT point_phys_to_win_dpi( HWND hwnd, POINT pt ); extern POINT point_thread_to_win_dpi( HWND hwnd, POINT pt ); diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index 35710f862d5..f1c898446b6 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -2232,8 +2232,14 @@ int WINAPI NtUserSetWindowRgn( HWND hwnd, HRGN hrgn, BOOL redraw ) { UINT swp_flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE; + HRGN monitor_hrgn; + if (!redraw) swp_flags |= SWP_NOREDRAW; - user_driver->pSetWindowRgn( hwnd, hrgn, redraw ); + + monitor_hrgn = map_dpi_region( hrgn, get_thread_dpi(), get_win_monitor_dpi( hwnd ) ); + user_driver->pSetWindowRgn( hwnd, monitor_hrgn, redraw ); + if (monitor_hrgn) NtGdiDeleteObjectApp( monitor_hrgn ); + NtUserSetWindowPos( hwnd, 0, 0, 0, 0, 0, swp_flags ); if (hrgn) NtGdiDeleteObjectApp( hrgn ); }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/sysparams.c | 11 +++++++++++ dlls/win32u/win32u_private.h | 1 + dlls/win32u/window.c | 26 ++++++++++++++++++++++---- 3 files changed, 34 insertions(+), 4 deletions(-)
diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index d26e7f76bfe..cd9e2a37e6c 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -2272,6 +2272,17 @@ HRGN map_dpi_region( HRGN hrgn, UINT dpi_from, UINT dpi_to ) return hrgn; }
+/********************************************************************** + * map_dpi_window_rects + */ +struct window_rects map_dpi_window_rects( struct window_rects rects, UINT dpi_from, UINT dpi_to ) +{ + rects.window = map_dpi_rect( rects.window, dpi_from, dpi_to ); + rects.client = map_dpi_rect( rects.client, dpi_from, dpi_to ); + rects.visible = map_dpi_rect( rects.visible, dpi_from, dpi_to ); + return rects; +} + /********************************************************************** * map_dpi_point */ diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index b15c8ebd9dd..2b77cd20a9e 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -184,6 +184,7 @@ extern BOOL is_exiting_thread( DWORD tid ); extern POINT map_dpi_point( POINT pt, UINT dpi_from, UINT dpi_to ); extern RECT map_dpi_rect( RECT rect, UINT dpi_from, UINT dpi_to ); extern HRGN map_dpi_region( HRGN region, UINT dpi_from, UINT dpi_to ); +extern struct window_rects map_dpi_window_rects( struct window_rects rects, UINT dpi_from, UINT dpi_to ); extern BOOL message_beep( UINT i ); extern POINT point_phys_to_win_dpi( HWND hwnd, POINT pt ); extern POINT point_thread_to_win_dpi( HWND hwnd, POINT pt ); diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index f1c898446b6..909b7ca4bec 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -1897,10 +1897,15 @@ static struct window_surface *create_window_surface( HWND hwnd, UINT swp_flags, BOOL shaped, needs_surface, create_opaque, is_layered, is_child; HWND parent = NtUserGetAncestor( hwnd, GA_PARENT ); struct window_surface *new_surface; - UINT style, ex_style; + struct window_rects monitor_rects; + UINT monitor_dpi, style, ex_style; + HMONITOR monitor; RECT dummy; HRGN shape;
+ monitor = monitor_from_rect( &rects->window, MONITOR_DEFAULTTONEAREST, get_thread_dpi() ); + monitor_dpi = get_monitor_dpi( monitor ); + style = NtUserGetWindowLongW( hwnd, GWL_STYLE ); ex_style = NtUserGetWindowLongW( hwnd, GWL_EXSTYLE ); is_child = parent && parent != NtUserGetDesktopWindow(); @@ -1909,7 +1914,8 @@ static struct window_surface *create_window_surface( HWND hwnd, UINT swp_flags, else if ((shaped = !!shape)) NtGdiDeleteObjectApp( shape );
rects->visible = rects->window; - if (!user_driver->pWindowPosChanging( hwnd, swp_flags, shaped, rects )) needs_surface = FALSE; + monitor_rects = map_dpi_window_rects( *rects, get_thread_dpi(), monitor_dpi ); + if (!user_driver->pWindowPosChanging( hwnd, swp_flags, shaped, &monitor_rects )) needs_surface = FALSE; else if (is_child) needs_surface = FALSE; else if (swp_flags & SWP_HIDEWINDOW) needs_surface = FALSE; else if (swp_flags & SWP_SHOWWINDOW) needs_surface = TRUE; @@ -1968,12 +1974,15 @@ static struct window_surface *create_window_surface( HWND hwnd, UINT swp_flags, static BOOL apply_window_pos( HWND hwnd, HWND insert_after, UINT swp_flags, struct window_surface *new_surface, const struct window_rects *new_rects, const RECT *valid_rects ) { + struct window_rects monitor_rects; WND *win; HWND surface_win = 0; BOOL ret, is_layered, needs_update = FALSE; struct window_rects old_rects; RECT extra_rects[3]; struct window_surface *old_surface; + HMONITOR monitor; + UINT monitor_dpi;
is_layered = new_surface && new_surface->alpha_mask;
@@ -1993,6 +2002,11 @@ static BOOL apply_window_pos( HWND hwnd, HWND insert_after, UINT swp_flags, stru valid_rects = NULL; }
+ monitor = monitor_from_rect( &new_rects->window, MONITOR_DEFAULTTONEAREST, get_thread_dpi() ); + monitor_dpi = get_monitor_dpi( monitor ); + + monitor_rects = map_dpi_window_rects( *new_rects, get_thread_dpi(), monitor_dpi ); + SERVER_START_REQ( set_window_pos ) { req->handle = wine_server_user_handle( hwnd ); @@ -2090,10 +2104,14 @@ static BOOL apply_window_pos( HWND hwnd, HWND insert_after, UINT swp_flags, stru if (surface_win && surface_win != hwnd) move_window_bits( hwnd, &new_rects->visible, &new_rects->visible, &new_rects->window, valid_rects ); else - user_driver->pMoveWindowBits( hwnd, new_rects, valid_rects ); + { + rects[0] = map_dpi_rect( valid_rects[0], get_thread_dpi(), monitor_dpi ); + rects[1] = map_dpi_rect( valid_rects[1], get_thread_dpi(), monitor_dpi ); + user_driver->pMoveWindowBits( hwnd, &monitor_rects, rects ); + } }
- user_driver->pWindowPosChanged( hwnd, insert_after, swp_flags, new_rects, new_surface ); + user_driver->pWindowPosChanged( hwnd, insert_after, swp_flags, &monitor_rects, new_surface ); }
return ret;
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/dce.c | 16 +++++++++++++++- dlls/win32u/win32u_private.h | 4 ++-- dlls/win32u/window.c | 24 ++++++++++-------------- 3 files changed, 27 insertions(+), 17 deletions(-)
diff --git a/dlls/win32u/dce.c b/dlls/win32u/dce.c index 6749e2b1725..8bad1949ebd 100644 --- a/dlls/win32u/dce.c +++ b/dlls/win32u/dce.c @@ -115,7 +115,7 @@ static const struct window_surface_funcs offscreen_window_surface_funcs = offscreen_window_surface_destroy };
-void create_offscreen_window_surface( HWND hwnd, const RECT *surface_rect, struct window_surface **window_surface ) +static void create_offscreen_window_surface( HWND hwnd, const RECT *surface_rect, struct window_surface **window_surface ) { char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )]; struct window_surface *surface, *previous; @@ -138,6 +138,20 @@ void create_offscreen_window_surface( HWND hwnd, const RECT *surface_rect, struc *window_surface = window_surface_create( sizeof(*surface), &offscreen_window_surface_funcs, hwnd, surface_rect, info, 0 ); }
+void create_window_surface( HWND hwnd, BOOL create_layered, const RECT *surface_rect, + struct window_surface **window_surface ) +{ + if (!user_driver->pCreateWindowSurface( hwnd, create_layered, surface_rect, window_surface )) + { + if (*window_surface) + { + window_surface_release( *window_surface ); + /* create an offscreen window surface if the driver doesn't implement CreateWindowSurface */ + create_offscreen_window_surface( hwnd, surface_rect, window_surface ); + } + } +} + /* window surface common helpers */
static UINT get_color_component( UINT color, UINT mask ) diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 2b77cd20a9e..6b7734d2af5 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -45,8 +45,8 @@ extern ULONG_PTR set_icon_param( HICON handle, const struct free_icon_params *pa
/* dce.c */ extern struct window_surface dummy_surface; -extern void create_offscreen_window_surface( HWND hwnd, const RECT *surface_rect, - struct window_surface **surface ); +extern void create_window_surface( HWND hwnd, BOOL create_layered, const RECT *surface_rect, + struct window_surface **window_surface ); extern void erase_now( HWND hwnd, UINT rdw_flags ); extern void flush_window_surfaces( BOOL idle ); extern void move_window_bits( HWND hwnd, const RECT *visible_rect, const RECT *old_visible_rect, diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index 909b7ca4bec..2aed22350e7 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -1891,8 +1891,8 @@ static BOOL get_default_window_surface( HWND hwnd, const RECT *surface_rect, str return TRUE; }
-static struct window_surface *create_window_surface( HWND hwnd, UINT swp_flags, BOOL create_layered, - struct window_rects *rects, RECT *surface_rect ) +static struct window_surface *get_window_surface( HWND hwnd, UINT swp_flags, BOOL create_layered, + struct window_rects *rects, RECT *surface_rect ) { BOOL shaped, needs_surface, create_opaque, is_layered, is_child; HWND parent = NtUserGetAncestor( hwnd, GA_PARENT ); @@ -1939,17 +1939,13 @@ static struct window_surface *create_window_surface( HWND hwnd, UINT swp_flags, if (IsRectEmpty( surface_rect )) needs_surface = FALSE; else if (create_layered || is_layered) needs_surface = TRUE;
- if (!needs_surface && new_surface && new_surface != &dummy_surface) + if (needs_surface) + create_window_surface( hwnd, create_layered, surface_rect, &new_surface ); + else if (new_surface && new_surface != &dummy_surface) { window_surface_release( new_surface ); window_surface_add_ref( (new_surface = &dummy_surface) ); } - else if (needs_surface && !user_driver->pCreateWindowSurface( hwnd, create_layered, surface_rect, &new_surface ) && new_surface) - { - /* create or update window surface for top-level windows if the driver doesn't implement CreateWindowSurface */ - window_surface_release( new_surface ); - create_offscreen_window_surface( hwnd, surface_rect, &new_surface ); - }
if (new_surface && !is_layered) { @@ -2383,7 +2379,7 @@ BOOL WINAPI NtUserUpdateLayeredWindow( HWND hwnd, HDC hdc_dst, const POINT *pts_
TRACE( "window %p new_rects %s\n", hwnd, debugstr_window_rects( &new_rects ) );
- surface = create_window_surface( hwnd, swp_flags, TRUE, &new_rects, &surface_rect ); + surface = get_window_surface( hwnd, swp_flags, TRUE, &new_rects, &surface_rect ); apply_window_pos( hwnd, 0, swp_flags, surface, &new_rects, NULL ); if (!surface) return FALSE;
@@ -3698,7 +3694,7 @@ BOOL set_window_pos( WINDOWPOS *winpos, int parent_x, int parent_y )
calc_ncsize( winpos, &old_rects, &new_rects, valid_rects, parent_x, parent_y );
- surface = create_window_surface( winpos->hwnd, winpos->flags, FALSE, &new_rects, &surface_rect ); + surface = get_window_surface( winpos->hwnd, winpos->flags, FALSE, &new_rects, &surface_rect ); if (!apply_window_pos( winpos->hwnd, winpos->hwndInsertAfter, winpos->flags, surface, &new_rects, valid_rects )) { @@ -4497,7 +4493,7 @@ void update_window_state( HWND hwnd ) get_window_rects( hwnd, COORDS_PARENT, &new_rects, get_thread_dpi() ); valid_rects[0] = valid_rects[1] = new_rects.client;
- surface = create_window_surface( hwnd, swp_flags, FALSE, &new_rects, &surface_rect ); + surface = get_window_surface( hwnd, swp_flags, FALSE, &new_rects, &surface_rect ); apply_window_pos( hwnd, 0, swp_flags, surface, &new_rects, valid_rects ); if (surface) window_surface_release( surface );
@@ -5551,7 +5547,7 @@ HWND WINAPI NtUserCreateWindowEx( DWORD ex_style, UNICODE_STRING *class_name, if (cs.y > 0x7fffffff - cy) new_rects.window.bottom = 0x7fffffff; new_rects.client = new_rects.window;
- surface = create_window_surface( hwnd, SWP_NOZORDER | SWP_NOACTIVATE, FALSE, &new_rects, &surface_rect ); + surface = get_window_surface( hwnd, SWP_NOZORDER | SWP_NOACTIVATE, FALSE, &new_rects, &surface_rect ); if (!apply_window_pos( hwnd, 0, SWP_NOZORDER | SWP_NOACTIVATE, surface, &new_rects, NULL )) { if (surface) window_surface_release( surface ); @@ -5590,7 +5586,7 @@ HWND WINAPI NtUserCreateWindowEx( DWORD ex_style, UNICODE_STRING *class_name, send_message( hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&new_rects.client ); map_window_points( 0, parent, (POINT *)&new_rects.client, 2, win_dpi );
- surface = create_window_surface( hwnd, SWP_NOACTIVATE, FALSE, &new_rects, &surface_rect ); + surface = get_window_surface( hwnd, SWP_NOACTIVATE, FALSE, &new_rects, &surface_rect ); apply_window_pos( hwnd, insert_after, SWP_NOACTIVATE, surface, &new_rects, NULL ); if (surface) window_surface_release( surface ); }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/dce.c | 169 ++++++++++++++++++++++++++++++++++- dlls/win32u/win32u_private.h | 3 +- dlls/win32u/window.c | 4 +- 3 files changed, 171 insertions(+), 5 deletions(-)
diff --git a/dlls/win32u/dce.c b/dlls/win32u/dce.c index 8bad1949ebd..3b8bc699017 100644 --- a/dlls/win32u/dce.c +++ b/dlls/win32u/dce.c @@ -138,18 +138,183 @@ static void create_offscreen_window_surface( HWND hwnd, const RECT *surface_rect *window_surface = window_surface_create( sizeof(*surface), &offscreen_window_surface_funcs, hwnd, surface_rect, info, 0 ); }
-void create_window_surface( HWND hwnd, BOOL create_layered, const RECT *surface_rect, +struct scaled_surface +{ + struct window_surface header; + struct window_surface *target_surface; + UINT dpi_from; + UINT dpi_to; +}; + +static struct scaled_surface *get_scaled_surface( struct window_surface *window_surface ) +{ + return CONTAINING_RECORD( window_surface, struct scaled_surface, header ); +} + +static void scaled_surface_set_clip( struct window_surface *window_surface, const RECT *rects, UINT count ) +{ + struct scaled_surface *surface = get_scaled_surface( window_surface ); + HRGN hrgn = map_dpi_region( window_surface->clip_region, surface->dpi_from, surface->dpi_to ); + window_surface_set_clip( surface->target_surface, hrgn ); + if (hrgn) NtGdiDeleteObjectApp( hrgn ); +} + +static BOOL scaled_surface_flush( struct window_surface *window_surface, const RECT *rect, const RECT *dirty, + const BITMAPINFO *color_info, const void *color_bits, BOOL shape_changed, + const BITMAPINFO *shape_info, const void *shape_bits ) +{ + struct scaled_surface *surface = get_scaled_surface( window_surface ); + RECT src = *dirty, dst; + HDC hdc_dst, hdc_src; + + src.left &= ~7; + src.top &= ~7; + src.right = (src.right + 7) & ~7; + src.bottom = (src.bottom + 7) & ~7; + + dst = map_dpi_rect( src, surface->dpi_from, surface->dpi_to ); + + hdc_dst = NtGdiCreateCompatibleDC( 0 ); + hdc_src = NtGdiCreateCompatibleDC( 0 ); + + NtGdiSelectBitmap( hdc_src, window_surface->color_bitmap ); + NtGdiSelectBitmap( hdc_dst, surface->target_surface->color_bitmap ); + + /* FIXME: implement HALFTONE with alpha for layered surfaces */ + if (!window_surface->alpha_mask) set_stretch_blt_mode( hdc_dst, STRETCH_HALFTONE ); + + NtGdiStretchBlt( hdc_dst, dst.left, dst.top, dst.right - dst.left, dst.bottom - dst.top, + hdc_src, src.left, src.top, src.right - src.left, src.bottom - src.top, + SRCCOPY, 0 ); + + NtGdiDeleteObjectApp( hdc_dst ); + NtGdiDeleteObjectApp( hdc_src ); + + window_surface_lock( surface->target_surface ); + add_bounds_rect( &surface->target_surface->bounds, &dst ); + window_surface_unlock( surface->target_surface ); + + if (shape_changed) + { + HRGN hrgn = map_dpi_region( window_surface->shape_region, surface->dpi_from, surface->dpi_to ); + window_surface_set_shape( surface->target_surface, hrgn ); + if (hrgn) NtGdiDeleteObjectApp( hrgn ); + + window_surface_set_layered( surface->target_surface, window_surface->color_key, + window_surface->alpha_bits, window_surface->alpha_mask ); + } + + window_surface_flush( surface->target_surface ); + return TRUE; +} + +static void scaled_surface_destroy( struct window_surface *window_surface ) +{ + struct scaled_surface *surface = get_scaled_surface( window_surface ); + window_surface_release( surface->target_surface ); +} + +static const struct window_surface_funcs scaled_surface_funcs = +{ + scaled_surface_set_clip, + scaled_surface_flush, + scaled_surface_destroy +}; + +static void scaled_surface_set_target( struct scaled_surface *surface, struct window_surface *target, UINT dpi_to ) +{ + if (surface->target_surface) window_surface_release( surface->target_surface ); + window_surface_add_ref( (surface->target_surface = target) ); + surface->dpi_to = dpi_to; +} + +static struct window_surface *scaled_surface_create( HWND hwnd, const RECT *surface_rect, UINT dpi_from, UINT dpi_to, + struct window_surface *target_surface ) +{ + char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )]; + BITMAPINFO *info = (BITMAPINFO *)buffer; + struct window_surface *window_surface; + struct scaled_surface *surface; + + memset( info, 0, sizeof(*info) ); + info->bmiHeader.biSize = sizeof(info->bmiHeader); + info->bmiHeader.biWidth = surface_rect->right; + info->bmiHeader.biHeight = -surface_rect->bottom; /* top-down */ + info->bmiHeader.biPlanes = 1; + info->bmiHeader.biBitCount = 32; + info->bmiHeader.biSizeImage = get_dib_image_size( info ); + info->bmiHeader.biCompression = BI_RGB; + + if ((window_surface = window_surface_create( sizeof(*surface), &scaled_surface_funcs, hwnd, surface_rect, info, 0 ))) + { + surface = get_scaled_surface( window_surface ); + surface->dpi_from = dpi_from; + scaled_surface_set_target( surface, target_surface, dpi_to ); + } + + return window_surface; +} + +static RECT get_surface_rect( RECT rect ) +{ + OffsetRect( &rect, -rect.left, -rect.top ); + + rect.left &= ~127; + rect.top &= ~127; + rect.right = max( rect.left + 128, (rect.right + 127) & ~127 ); + rect.bottom = max( rect.top + 128, (rect.bottom + 127) & ~127 ); + + return rect; +} + +void create_window_surface( HWND hwnd, BOOL create_layered, const RECT *surface_rect, UINT monitor_dpi, struct window_surface **window_surface ) { - if (!user_driver->pCreateWindowSurface( hwnd, create_layered, surface_rect, window_surface )) + struct window_surface *previous, *driver_surface; + UINT dpi = get_dpi_for_window( hwnd ); + RECT monitor_rect; + + if ((driver_surface = get_driver_window_surface( *window_surface, monitor_dpi ))) + window_surface_add_ref( driver_surface ); + + monitor_rect = get_surface_rect( map_dpi_rect( *surface_rect, dpi, monitor_dpi ) ); + if (!user_driver->pCreateWindowSurface( hwnd, create_layered, &monitor_rect, &driver_surface )) { + if (driver_surface) window_surface_release( driver_surface ); if (*window_surface) { window_surface_release( *window_surface ); /* create an offscreen window surface if the driver doesn't implement CreateWindowSurface */ create_offscreen_window_surface( hwnd, surface_rect, window_surface ); } + return; } + + if (!driver_surface || dpi == monitor_dpi) + { + if (*window_surface) window_surface_release( *window_surface ); + *window_surface = driver_surface; + return; + } + + /* reuse previous scaling surface, update its target to the driver surface */ + if ((previous = *window_surface) && previous->funcs == &scaled_surface_funcs) + { + struct scaled_surface *surface = get_scaled_surface( previous ); + scaled_surface_set_target( surface, driver_surface, monitor_dpi ); + return; + } + if (previous) window_surface_release( previous ); + + *window_surface = scaled_surface_create( hwnd, surface_rect, dpi, monitor_dpi, driver_surface ); +} + +struct window_surface *get_driver_window_surface( struct window_surface *surface, UINT monitor_dpi ) +{ + if (!surface || surface == &dummy_surface) return surface; + if (surface->funcs != &scaled_surface_funcs) return surface; + if (get_scaled_surface( surface )->dpi_to != monitor_dpi) return &dummy_surface; + return get_scaled_surface( surface )->target_surface; }
/* window surface common helpers */ diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 6b7734d2af5..f7d869d1feb 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -45,8 +45,9 @@ extern ULONG_PTR set_icon_param( HICON handle, const struct free_icon_params *pa
/* dce.c */ extern struct window_surface dummy_surface; -extern void create_window_surface( HWND hwnd, BOOL create_layered, const RECT *surface_rect, +extern void create_window_surface( HWND hwnd, BOOL create_layered, const RECT *surface_rect, UINT monitor_dpi, struct window_surface **window_surface ); +extern struct window_surface *get_driver_window_surface( struct window_surface *surface, UINT monitor_dpi ); extern void erase_now( HWND hwnd, UINT rdw_flags ); extern void flush_window_surfaces( BOOL idle ); extern void move_window_bits( HWND hwnd, const RECT *visible_rect, const RECT *old_visible_rect, diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index 2aed22350e7..05a353ae53a 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -1940,7 +1940,7 @@ static struct window_surface *get_window_surface( HWND hwnd, UINT swp_flags, BOO else if (create_layered || is_layered) needs_surface = TRUE;
if (needs_surface) - create_window_surface( hwnd, create_layered, surface_rect, &new_surface ); + create_window_surface( hwnd, create_layered, surface_rect, monitor_dpi, &new_surface ); else if (new_surface && new_surface != &dummy_surface) { window_surface_release( new_surface ); @@ -2107,7 +2107,7 @@ static BOOL apply_window_pos( HWND hwnd, HWND insert_after, UINT swp_flags, stru } }
- user_driver->pWindowPosChanged( hwnd, insert_after, swp_flags, &monitor_rects, new_surface ); + user_driver->pWindowPosChanged( hwnd, insert_after, swp_flags, &monitor_rects, get_driver_window_surface( new_surface, monitor_dpi ) ); }
return ret;