From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/dce.c | 36 +++++++++++++++++++++++------------- dlls/win32u/dibdrv/dc.c | 32 ++++++++++++++++++++------------ 2 files changed, 43 insertions(+), 25 deletions(-)
diff --git a/dlls/win32u/dce.c b/dlls/win32u/dce.c index 5df30550cae..24a53b9191e 100644 --- a/dlls/win32u/dce.c +++ b/dlls/win32u/dce.c @@ -1268,7 +1268,7 @@ static BOOL send_erase( HWND hwnd, UINT flags, HRGN client_rgn, * Copy bits from a window surface; helper for move_window_bits and move_window_bits_parent. */ static void copy_bits_from_surface( HWND hwnd, struct window_surface *surface, - const RECT *dst, const RECT *src ) + const RECT *dst, const RECT *src, BOOL same ) { char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )]; BITMAPINFO *info = (BITMAPINFO *)buffer; @@ -1277,13 +1277,23 @@ static void copy_bits_from_surface( HWND hwnd, struct window_surface *surface, HRGN rgn = get_update_region( hwnd, &flags, NULL ); HDC hdc = NtUserGetDCEx( hwnd, rgn, DCX_CACHE | DCX_WINDOW | DCX_EXCLUDERGN );
- bits = surface->funcs->get_info( surface, info ); - surface->funcs->lock( surface ); - NtGdiSetDIBitsToDeviceInternal( hdc, dst->left, dst->top, dst->right - dst->left, dst->bottom - dst->top, - src->left - surface->rect.left, surface->rect.bottom - src->bottom, - 0, surface->rect.bottom - surface->rect.top, - bits, info, DIB_RGB_COLORS, 0, 0, FALSE, NULL ); - surface->funcs->unlock( surface ); + if (same) + { + RECT rect = *src; + NtGdiStretchBlt( hdc, dst->left, dst->top, dst->right - dst->left, dst->bottom - dst->top, + hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SRCCOPY, 0 ); + } + else + { + bits = surface->funcs->get_info( surface, info ); + surface->funcs->lock( surface ); + NtGdiSetDIBitsToDeviceInternal( hdc, dst->left, dst->top, dst->right - dst->left, dst->bottom - dst->top, + src->left - surface->rect.left, surface->rect.bottom - src->bottom, + 0, surface->rect.bottom - surface->rect.top, + bits, info, DIB_RGB_COLORS, 0, 0, FALSE, NULL ); + surface->funcs->unlock( surface ); + } + NtUserReleaseDC( hwnd, hdc ); }
@@ -1305,9 +1315,10 @@ void move_window_bits( HWND hwnd, struct window_surface *old_surface, src.top - old_visible_rect->top != dst.top - visible_rect->top) { TRACE( "copying %s -> %s\n", wine_dbgstr_rect( &src ), wine_dbgstr_rect( &dst )); - OffsetRect( &src, -old_visible_rect->left, -old_visible_rect->top ); + if (new_surface != old_surface) OffsetRect( &src, -old_visible_rect->left, -old_visible_rect->top ); + else OffsetRect( &src, -window_rect->left, -window_rect->top ); OffsetRect( &dst, -window_rect->left, -window_rect->top ); - copy_bits_from_surface( hwnd, old_surface, &dst, &src ); + copy_bits_from_surface( hwnd, old_surface, &dst, &src, new_surface == old_surface ); } }
@@ -1336,13 +1347,12 @@ void move_window_bits_parent( HWND hwnd, HWND parent, const RECT *window_rect, c
TRACE( "copying %s -> %s\n", wine_dbgstr_rect( &src ), wine_dbgstr_rect( &dst )); map_window_points( NtUserGetAncestor( hwnd, GA_PARENT ), parent, (POINT *)&src, 2, get_thread_dpi() ); - OffsetRect( &src, win->client_rect.left - win->visible_rect.left, - win->client_rect.top - win->visible_rect.top ); + OffsetRect( &src, -window_rect->left, -window_rect->top ); OffsetRect( &dst, -window_rect->left, -window_rect->top ); window_surface_add_ref( surface ); release_win_ptr( win );
- copy_bits_from_surface( hwnd, surface, &dst, &src ); + copy_bits_from_surface( hwnd, surface, &dst, &src, TRUE ); window_surface_release( surface ); }
diff --git a/dlls/win32u/dibdrv/dc.c b/dlls/win32u/dibdrv/dc.c index 637b92f5256..f1eb0c96300 100644 --- a/dlls/win32u/dibdrv/dc.c +++ b/dlls/win32u/dibdrv/dc.c @@ -725,6 +725,7 @@ struct windrv_physdev struct gdi_physdev dev; struct dibdrv_physdev *dibdrv; struct window_surface *surface; + UINT surface_locks; };
static const struct gdi_dc_funcs window_driver; @@ -734,25 +735,32 @@ static inline struct windrv_physdev *get_windrv_physdev( PHYSDEV dev ) return (struct windrv_physdev *)dev; }
+/* gdi_lock should not be locked */ static inline void lock_surface( struct windrv_physdev *dev ) { - /* gdi_lock should not be locked */ - dev->surface->funcs->lock( dev->surface ); - if (IsRectEmpty( dev->dibdrv->bounds ) || dev->surface->draw_start_ticks == 0) - dev->surface->draw_start_ticks = NtGetTickCount(); + struct window_surface *surface = dev->surface; + + if (!dev->surface_locks++) + surface->funcs->lock( surface ); + + if (IsRectEmpty( dev->dibdrv->bounds ) || !surface->draw_start_ticks) + surface->draw_start_ticks = NtGetTickCount(); }
static inline void unlock_surface( struct windrv_physdev *dev ) { - BOOL should_flush = NtGetTickCount() - dev->surface->draw_start_ticks > FLUSH_PERIOD; - dev->surface->funcs->unlock( dev->surface ); - if (should_flush) dev->surface->funcs->flush( dev->surface ); + struct window_surface *surface = dev->surface; + DWORD ticks = NtGetTickCount() - surface->draw_start_ticks; + + if (!--dev->surface_locks) + surface->funcs->unlock( surface ); + + if (ticks > FLUSH_PERIOD) surface->funcs->flush( dev->surface ); }
-static void unlock_bits_surface( struct gdi_image_bits *bits ) +static void unlock_windrv_bits( struct gdi_image_bits *bits ) { - struct window_surface *surface = bits->param; - surface->funcs->unlock( surface ); + unlock_surface( bits->param ); }
void dibdrv_set_window_surface( DC *dc, struct window_surface *surface ) @@ -955,8 +963,8 @@ static DWORD windrv_GetImage( PHYSDEV dev, BITMAPINFO *info, { /* use the freeing callback to unlock the surface */ assert( !bits->free ); - bits->free = unlock_bits_surface; - bits->param = physdev->surface; + bits->free = unlock_windrv_bits; + bits->param = physdev; } else unlock_surface( physdev ); return ret;