From a767ee99fa59a15980847bc9af980a860919f114 Mon Sep 17 00:00:00 2001 From: Ken Thomases Date: Thu, 28 Mar 2013 23:34:06 -0500 Subject: [PATCH] winemac: Track drawn surface region to reduce black flicker for new or resized windows. --- dlls/winemac.drv/cocoa_window.m | 10 +---- dlls/winemac.drv/macdrv.h | 3 +- dlls/winemac.drv/macdrv_cocoa.h | 2 +- dlls/winemac.drv/surface.c | 84 +++++++++++++++++++++++++++++++++-------- dlls/winemac.drv/window.c | 4 +- 5 files changed, 74 insertions(+), 29 deletions(-) diff --git a/dlls/winemac.drv/cocoa_window.m b/dlls/winemac.drv/cocoa_window.m index 279f81fb2e3..1d5c551c9d9 100644 --- a/dlls/winemac.drv/cocoa_window.m +++ b/dlls/winemac.drv/cocoa_window.m @@ -186,18 +186,10 @@ static inline void fix_generic_modifiers_by_device(NSUInteger* modifiers) if (window.surface && window.surface_mutex && !pthread_mutex_lock(window.surface_mutex)) { - CGRect bounds; const CGRect* rects; int count; - if (!get_surface_region_rects(window.surface, &rects, &count)) - { - bounds = NSRectToCGRect([self bounds]); - rects = &bounds; - count = 1; - } - - if (count) + if (get_surface_blit_rects(window.surface, &rects, &count) && count) { CGContextRef context; int i; diff --git a/dlls/winemac.drv/macdrv.h b/dlls/winemac.drv/macdrv.h index 970a228c5dc..f8c45ab21a5 100644 --- a/dlls/winemac.drv/macdrv.h +++ b/dlls/winemac.drv/macdrv.h @@ -137,7 +137,8 @@ extern struct macdrv_win_data *get_win_data(HWND hwnd) DECLSPEC_HIDDEN; extern void release_win_data(struct macdrv_win_data *data) DECLSPEC_HIDDEN; extern macdrv_window macdrv_get_cocoa_window(HWND hwnd, BOOL require_on_screen) DECLSPEC_HIDDEN; extern RGNDATA *get_region_data(HRGN hrgn, HDC hdc_lptodp) DECLSPEC_HIDDEN; -extern struct window_surface *create_surface(macdrv_window window, const RECT *rect, BOOL use_alpha) DECLSPEC_HIDDEN; +extern struct window_surface *create_surface(macdrv_window window, const RECT *rect, + struct window_surface *old_surface, BOOL use_alpha) DECLSPEC_HIDDEN; extern void set_window_surface(macdrv_window window, struct window_surface *window_surface) DECLSPEC_HIDDEN; extern void set_surface_use_alpha(struct window_surface *window_surface, BOOL use_alpha) DECLSPEC_HIDDEN; diff --git a/dlls/winemac.drv/macdrv_cocoa.h b/dlls/winemac.drv/macdrv_cocoa.h index c014fbe3cfc..2d749698f1f 100644 --- a/dlls/winemac.drv/macdrv_cocoa.h +++ b/dlls/winemac.drv/macdrv_cocoa.h @@ -319,7 +319,7 @@ extern void macdrv_get_cocoa_window_frame(macdrv_window w, CGRect* out_frame) DE extern void macdrv_set_cocoa_parent_window(macdrv_window w, macdrv_window parent) DECLSPEC_HIDDEN; extern void macdrv_set_window_surface(macdrv_window w, void *surface, pthread_mutex_t *mutex) DECLSPEC_HIDDEN; extern CGImageRef create_surface_image(void *window_surface, CGRect *rect, int copy_data) DECLSPEC_HIDDEN; -extern int get_surface_region_rects(void *window_surface, const CGRect **rects, int *count) DECLSPEC_HIDDEN; +extern int get_surface_blit_rects(void *window_surface, const CGRect **rects, int *count) DECLSPEC_HIDDEN; extern void macdrv_window_needs_display(macdrv_window w, CGRect rect) DECLSPEC_HIDDEN; extern void macdrv_set_window_shape(macdrv_window w, const CGRect *rects, int count) DECLSPEC_HIDDEN; extern void macdrv_set_window_alpha(macdrv_window w, CGFloat alpha) DECLSPEC_HIDDEN; diff --git a/dlls/winemac.drv/surface.c b/dlls/winemac.drv/surface.c index 29fc7f885eb..564d004f711 100644 --- a/dlls/winemac.drv/surface.c +++ b/dlls/winemac.drv/surface.c @@ -61,8 +61,10 @@ struct macdrv_window_surface struct window_surface header; macdrv_window window; RECT bounds; + HRGN region; + HRGN drawn; BOOL use_alpha; - RGNDATA *region_data; + RGNDATA *blit_data; BYTE *bits; pthread_mutex_t mutex; BITMAPINFO info; /* variable size, must be last */ @@ -74,6 +76,27 @@ static struct macdrv_window_surface *get_mac_surface(struct window_surface *surf } /*********************************************************************** + * update_blit_data + */ +static void update_blit_data(struct macdrv_window_surface *surface) +{ + HeapFree(GetProcessHeap(), 0, surface->blit_data); + surface->blit_data = NULL; + + if (surface->drawn) + { + HRGN blit = CreateRectRgn(0, 0, 0, 0); + + if (CombineRgn(blit, surface->drawn, 0, RGN_COPY) > NULLREGION && + (!surface->region || CombineRgn(blit, blit, surface->region, RGN_AND) > NULLREGION) && + OffsetRgn(blit, surface->header.rect.left, surface->header.rect.top) > NULLREGION) + surface->blit_data = get_region_data(blit, 0); + + DeleteObject(blit); + } +} + +/*********************************************************************** * macdrv_surface_lock */ static void macdrv_surface_lock(struct window_surface *window_surface) @@ -126,15 +149,17 @@ static void macdrv_surface_set_region(struct window_surface *window_surface, HRG window_surface->funcs->lock(window_surface); - HeapFree(GetProcessHeap(), 0, surface->region_data); - surface->region_data = NULL; - if (region) { - int rc = OffsetRgn(region, surface->header.rect.left, surface->header.rect.top); - if (rc != ERROR) - surface->region_data = get_region_data(region, 0); + if (!surface->region) surface->region = CreateRectRgn(0, 0, 0, 0); + CombineRgn(surface->region, region, 0, RGN_COPY); + } + else + { + if (surface->region) DeleteObject(surface->region); + surface->region = 0; } + update_blit_data(surface); window_surface->funcs->unlock(window_surface); } @@ -146,6 +171,7 @@ static void macdrv_surface_flush(struct window_surface *window_surface) { struct macdrv_window_surface *surface = get_mac_surface(window_surface); CGRect rect; + HRGN region; window_surface->funcs->lock(window_surface); @@ -154,6 +180,18 @@ static void macdrv_surface_flush(struct window_surface *window_surface) rect = cgrect_from_rect(surface->bounds); rect = CGRectOffset(rect, surface->header.rect.left, surface->header.rect.top); + + if (!IsRectEmpty(&surface->bounds) && (region = CreateRectRgnIndirect(&surface->bounds))) + { + if (surface->drawn) + { + CombineRgn(surface->drawn, surface->drawn, region, RGN_OR); + DeleteObject(region); + } + else + surface->drawn = region; + } + update_blit_data(surface); reset_bounds(&surface->bounds); window_surface->funcs->unlock(window_surface); @@ -189,9 +227,11 @@ static const struct window_surface_funcs macdrv_surface_funcs = /*********************************************************************** * create_surface */ -struct window_surface *create_surface(macdrv_window window, const RECT *rect, BOOL use_alpha) +struct window_surface *create_surface(macdrv_window window, const RECT *rect, + struct window_surface *old_surface, BOOL use_alpha) { struct macdrv_window_surface *surface; + struct macdrv_window_surface *old_mac_surface = get_mac_surface(old_surface); int width = rect->right - rect->left, height = rect->bottom - rect->top; DWORD *colors; pthread_mutexattr_t attr; @@ -234,6 +274,17 @@ struct window_surface *create_surface(macdrv_window window, const RECT *rect, BO surface->header.ref = 1; surface->window = window; reset_bounds(&surface->bounds); + if (old_mac_surface && old_mac_surface->drawn) + { + surface->drawn = CreateRectRgnIndirect(rect); + OffsetRgn(surface->drawn, -rect->left, -rect->top); + if (CombineRgn(surface->drawn, surface->drawn, old_mac_surface->drawn, RGN_AND) <= NULLREGION) + { + DeleteObject(surface->drawn); + surface->drawn = 0; + } + } + update_blit_data(surface); surface->use_alpha = use_alpha; surface->bits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, surface->info.bmiHeader.biSizeImage); if (!surface->bits) goto failed; @@ -267,24 +318,25 @@ void set_window_surface(macdrv_window window, struct window_surface *window_surf } /*********************************************************************** - * get_surface_region_rects + * get_surface_blit_rects * * Caller must hold the surface lock. Indirectly returns the surface - * region rects. Returns zero if the surface has no region set (it is - * unclipped); returns non-zero if the surface does have a region set. + * blit region rects. Returns zero if the surface has nothing to blit; + * returns non-zero if the surface does have rects to blit (drawn area + * which isn't clipped away by a surface region). * * IMPORTANT: This function is called from non-Wine threads, so it * must not use Win32 or Wine functions, including debug * logging. */ -int get_surface_region_rects(void *window_surface, const CGRect **rects, int *count) +int get_surface_blit_rects(void *window_surface, const CGRect **rects, int *count) { struct macdrv_window_surface *surface = get_mac_surface(window_surface); - if (surface->region_data) + if (surface->blit_data) { - *rects = (const CGRect*)surface->region_data->Buffer; - *count = surface->region_data->rdh.nCount; + *rects = (const CGRect*)surface->blit_data->Buffer; + *count = surface->blit_data->rdh.nCount; } else { @@ -292,7 +344,7 @@ int get_surface_region_rects(void *window_surface, const CGRect **rects, int *co *count = 0; } - return (surface->region_data != NULL); + return (surface->blit_data != NULL); } /*********************************************************************** diff --git a/dlls/winemac.drv/window.c b/dlls/winemac.drv/window.c index 07c4643e3e3..9932d9976ef 100644 --- a/dlls/winemac.drv/window.c +++ b/dlls/winemac.drv/window.c @@ -1101,7 +1101,7 @@ BOOL CDECL macdrv_UpdateLayeredWindow(HWND hwnd, const UPDATELAYEREDWINDOWINFO * surface = data->surface; if (!surface || memcmp(&surface->rect, &rect, sizeof(RECT))) { - data->surface = create_surface(data->cocoa_window, &rect, TRUE); + data->surface = create_surface(data->cocoa_window, &rect, NULL, TRUE); set_window_surface(data->cocoa_window, data->surface); if (surface) window_surface_release(surface); surface = data->surface; @@ -1291,7 +1291,7 @@ void CDECL macdrv_WindowPosChanging(HWND hwnd, HWND insert_after, UINT swp_flags } else if (!(swp_flags & SWP_SHOWWINDOW) && !(style & WS_VISIBLE)) goto done; - *surface = create_surface(data->cocoa_window, &surface_rect, FALSE); + *surface = create_surface(data->cocoa_window, &surface_rect, data->surface, FALSE); done: release_win_data(data); -- 2.11.4.GIT