forked from Mirrors/wine-wine
winemac: Track drawn surface region to reduce black flicker for new or resized windows.
parent
0e8b305023
commit
a767ee99fa
|
@ -186,18 +186,10 @@ static inline void fix_generic_modifiers_by_device(NSUInteger* modifiers)
|
||||||
if (window.surface && window.surface_mutex &&
|
if (window.surface && window.surface_mutex &&
|
||||||
!pthread_mutex_lock(window.surface_mutex))
|
!pthread_mutex_lock(window.surface_mutex))
|
||||||
{
|
{
|
||||||
CGRect bounds;
|
|
||||||
const CGRect* rects;
|
const CGRect* rects;
|
||||||
int count;
|
int count;
|
||||||
|
|
||||||
if (!get_surface_region_rects(window.surface, &rects, &count))
|
if (get_surface_blit_rects(window.surface, &rects, &count) && count)
|
||||||
{
|
|
||||||
bounds = NSRectToCGRect([self bounds]);
|
|
||||||
rects = &bounds;
|
|
||||||
count = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count)
|
|
||||||
{
|
{
|
||||||
CGContextRef context;
|
CGContextRef context;
|
||||||
int i;
|
int i;
|
||||||
|
|
|
@ -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 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 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 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_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;
|
extern void set_surface_use_alpha(struct window_surface *window_surface, BOOL use_alpha) DECLSPEC_HIDDEN;
|
||||||
|
|
||||||
|
|
|
@ -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_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 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 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_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_shape(macdrv_window w, const CGRect *rects, int count) DECLSPEC_HIDDEN;
|
||||||
extern void macdrv_set_window_alpha(macdrv_window w, CGFloat alpha) DECLSPEC_HIDDEN;
|
extern void macdrv_set_window_alpha(macdrv_window w, CGFloat alpha) DECLSPEC_HIDDEN;
|
||||||
|
|
|
@ -61,8 +61,10 @@ struct macdrv_window_surface
|
||||||
struct window_surface header;
|
struct window_surface header;
|
||||||
macdrv_window window;
|
macdrv_window window;
|
||||||
RECT bounds;
|
RECT bounds;
|
||||||
|
HRGN region;
|
||||||
|
HRGN drawn;
|
||||||
BOOL use_alpha;
|
BOOL use_alpha;
|
||||||
RGNDATA *region_data;
|
RGNDATA *blit_data;
|
||||||
BYTE *bits;
|
BYTE *bits;
|
||||||
pthread_mutex_t mutex;
|
pthread_mutex_t mutex;
|
||||||
BITMAPINFO info; /* variable size, must be last */
|
BITMAPINFO info; /* variable size, must be last */
|
||||||
|
@ -73,6 +75,27 @@ static struct macdrv_window_surface *get_mac_surface(struct window_surface *surf
|
||||||
return (struct macdrv_window_surface *)surface;
|
return (struct macdrv_window_surface *)surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* 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
|
* macdrv_surface_lock
|
||||||
*/
|
*/
|
||||||
|
@ -126,15 +149,17 @@ static void macdrv_surface_set_region(struct window_surface *window_surface, HRG
|
||||||
|
|
||||||
window_surface->funcs->lock(window_surface);
|
window_surface->funcs->lock(window_surface);
|
||||||
|
|
||||||
HeapFree(GetProcessHeap(), 0, surface->region_data);
|
|
||||||
surface->region_data = NULL;
|
|
||||||
|
|
||||||
if (region)
|
if (region)
|
||||||
{
|
{
|
||||||
int rc = OffsetRgn(region, surface->header.rect.left, surface->header.rect.top);
|
if (!surface->region) surface->region = CreateRectRgn(0, 0, 0, 0);
|
||||||
if (rc != ERROR)
|
CombineRgn(surface->region, region, 0, RGN_COPY);
|
||||||
surface->region_data = get_region_data(region, 0);
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (surface->region) DeleteObject(surface->region);
|
||||||
|
surface->region = 0;
|
||||||
|
}
|
||||||
|
update_blit_data(surface);
|
||||||
|
|
||||||
window_surface->funcs->unlock(window_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);
|
struct macdrv_window_surface *surface = get_mac_surface(window_surface);
|
||||||
CGRect rect;
|
CGRect rect;
|
||||||
|
HRGN region;
|
||||||
|
|
||||||
window_surface->funcs->lock(window_surface);
|
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 = cgrect_from_rect(surface->bounds);
|
||||||
rect = CGRectOffset(rect, surface->header.rect.left, surface->header.rect.top);
|
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);
|
reset_bounds(&surface->bounds);
|
||||||
|
|
||||||
window_surface->funcs->unlock(window_surface);
|
window_surface->funcs->unlock(window_surface);
|
||||||
|
@ -189,9 +227,11 @@ static const struct window_surface_funcs macdrv_surface_funcs =
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* create_surface
|
* 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 *surface;
|
||||||
|
struct macdrv_window_surface *old_mac_surface = get_mac_surface(old_surface);
|
||||||
int width = rect->right - rect->left, height = rect->bottom - rect->top;
|
int width = rect->right - rect->left, height = rect->bottom - rect->top;
|
||||||
DWORD *colors;
|
DWORD *colors;
|
||||||
pthread_mutexattr_t attr;
|
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->header.ref = 1;
|
||||||
surface->window = window;
|
surface->window = window;
|
||||||
reset_bounds(&surface->bounds);
|
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->use_alpha = use_alpha;
|
||||||
surface->bits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, surface->info.bmiHeader.biSizeImage);
|
surface->bits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, surface->info.bmiHeader.biSizeImage);
|
||||||
if (!surface->bits) goto failed;
|
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
|
* Caller must hold the surface lock. Indirectly returns the surface
|
||||||
* region rects. Returns zero if the surface has no region set (it is
|
* blit region rects. Returns zero if the surface has nothing to blit;
|
||||||
* unclipped); returns non-zero if the surface does have a region set.
|
* 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
|
* IMPORTANT: This function is called from non-Wine threads, so it
|
||||||
* must not use Win32 or Wine functions, including debug
|
* must not use Win32 or Wine functions, including debug
|
||||||
* logging.
|
* 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);
|
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;
|
*rects = (const CGRect*)surface->blit_data->Buffer;
|
||||||
*count = surface->region_data->rdh.nCount;
|
*count = surface->blit_data->rdh.nCount;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -292,7 +344,7 @@ int get_surface_region_rects(void *window_surface, const CGRect **rects, int *co
|
||||||
*count = 0;
|
*count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (surface->region_data != NULL);
|
return (surface->blit_data != NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
|
|
|
@ -1101,7 +1101,7 @@ BOOL CDECL macdrv_UpdateLayeredWindow(HWND hwnd, const UPDATELAYEREDWINDOWINFO *
|
||||||
surface = data->surface;
|
surface = data->surface;
|
||||||
if (!surface || memcmp(&surface->rect, &rect, sizeof(RECT)))
|
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);
|
set_window_surface(data->cocoa_window, data->surface);
|
||||||
if (surface) window_surface_release(surface);
|
if (surface) window_surface_release(surface);
|
||||||
surface = data->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;
|
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:
|
done:
|
||||||
release_win_data(data);
|
release_win_data(data);
|
||||||
|
|
Loading…
Reference in New Issue