win32u: Use a helper to flush window surface, factor locking and bounds reset.

This commit is contained in:
Rémi Bernon 2024-05-29 11:21:12 +02:00 committed by Alexandre Julliard
parent b44730a39e
commit 5d0efbcc6e
11 changed files with 86 additions and 141 deletions

View file

@ -79,9 +79,10 @@ static void dummy_surface_set_region( struct window_surface *window_surface, HRG
/* nothing to do */
}
static void dummy_surface_flush( struct window_surface *window_surface )
static BOOL dummy_surface_flush( struct window_surface *window_surface, const RECT *rect, const RECT *dirty )
{
/* nothing to do */
return TRUE;
}
static void dummy_surface_destroy( struct window_surface *window_surface )
@ -129,11 +130,9 @@ static void offscreen_window_surface_set_region( struct window_surface *base, HR
{
}
static void offscreen_window_surface_flush( struct window_surface *surface )
static BOOL offscreen_window_surface_flush( struct window_surface *base, const RECT *rect, const RECT *dirty )
{
window_surface_lock( surface );
reset_bounds( &surface->bounds );
window_surface_unlock( surface );
return TRUE;
}
static void offscreen_window_surface_destroy( struct window_surface *base )
@ -229,6 +228,22 @@ W32KAPI void window_surface_unlock( struct window_surface *surface )
pthread_mutex_unlock( &surface->mutex );
}
W32KAPI void window_surface_flush( struct window_surface *surface )
{
RECT dirty = surface->rect;
window_surface_lock( surface );
if (intersect_rect( &dirty, &dirty, &surface->bounds ))
{
TRACE( "Flushing surface %p %s, bounds %s, dirty %s\n", surface, wine_dbgstr_rect( &surface->rect ),
wine_dbgstr_rect( &surface->bounds ), wine_dbgstr_rect( &dirty ) );
if (surface->funcs->flush( surface, &surface->rect, &dirty )) reset_bounds( &surface->bounds );
}
window_surface_unlock( surface );
}
/*******************************************************************
* register_window_surface
*
@ -263,7 +278,7 @@ void flush_window_surfaces( BOOL idle )
else if ((int)(now - last_idle) < 50) goto done;
LIST_FOR_EACH_ENTRY( surface, &window_surfaces, struct window_surface, entry )
surface->funcs->flush( surface );
window_surface_flush( surface );
done:
pthread_mutex_unlock( &surfaces_lock );
}

View file

@ -765,7 +765,7 @@ static inline void unlock_surface( struct windrv_physdev *dev )
{
DWORD ticks = NtGetTickCount() - surface->draw_start_ticks;
window_surface_unlock( surface );
if (ticks > FLUSH_PERIOD) surface->funcs->flush( dev->surface );
if (ticks > FLUSH_PERIOD) window_surface_flush( dev->surface );
}
}

View file

@ -587,12 +587,6 @@ static struct android_window_surface *get_android_surface( struct window_surface
return (struct android_window_surface *)surface;
}
static inline void reset_bounds( RECT *bounds )
{
bounds->left = bounds->top = INT_MAX;
bounds->right = bounds->bottom = INT_MIN;
}
static inline void add_bounds_rect( RECT *bounds, const RECT *rect )
{
if (rect->left >= rect->right || rect->top >= rect->bottom) return;
@ -682,60 +676,41 @@ static void android_surface_set_region( struct window_surface *window_surface, H
/***********************************************************************
* android_surface_flush
*/
static void android_surface_flush( struct window_surface *window_surface )
static BOOL android_surface_flush( struct window_surface *window_surface, const RECT *rect, const RECT *dirty )
{
struct android_window_surface *surface = get_android_surface( window_surface );
ANativeWindow_Buffer buffer;
ARect rc;
RECT rect;
BOOL needs_flush;
window_surface_lock( window_surface );
SetRect( &rect, 0, 0, surface->header.rect.right - surface->header.rect.left,
surface->header.rect.bottom - surface->header.rect.top );
needs_flush = intersect_rect( &rect, &rect, &window_surface->bounds );
reset_bounds( &window_surface->bounds );
if (!needs_flush)
{
window_surface_unlock( window_surface );
return;
}
TRACE( "flushing %p hwnd %p surface %s rect %s bits %p alpha %02x key %08x region %u rects\n",
surface, surface->hwnd, wine_dbgstr_rect( &surface->header.rect ),
wine_dbgstr_rect( &rect ), surface->bits, surface->alpha, (int)surface->color_key,
surface->region_data ? (int)surface->region_data->rdh.nCount : 0 );
rc.left = rect.left;
rc.top = rect.top;
rc.right = rect.right;
rc.bottom = rect.bottom;
rc.left = dirty->left;
rc.top = dirty->top;
rc.right = dirty->right;
rc.bottom = dirty->bottom;
if (!surface->window->perform( surface->window, NATIVE_WINDOW_LOCK, &buffer, &rc ))
{
const RECT *rgn_rect = NULL, *end = NULL;
DWORD *src, *dst;
int x, y, width;
RECT locked;
rect.left = rc.left;
rect.top = rc.top;
rect.right = rc.right;
rect.bottom = rc.bottom;
intersect_rect( &rect, &rect, &surface->header.rect );
locked.left = rc.left;
locked.top = rc.top;
locked.right = rc.right;
locked.bottom = rc.bottom;
intersect_rect( &locked, &locked, rect );
if (surface->region_data)
{
rgn_rect = (RECT *)surface->region_data->Buffer;
end = rgn_rect + surface->region_data->rdh.nCount;
}
src = (DWORD *)surface->bits
+ (rect.top - surface->header.rect.top) * surface->info.bmiHeader.biWidth
+ (rect.left - surface->header.rect.left);
dst = (DWORD *)buffer.bits + rect.top * buffer.stride + rect.left;
width = min( rect.right - rect.left, buffer.stride );
src = (DWORD *)surface->bits + (locked.top - rect->top) * surface->info.bmiHeader.biWidth +
(locked.left - rect->left);
dst = (DWORD *)buffer.bits + locked.top * buffer.stride + locked.left;
width = min( locked.right - locked.left, buffer.stride );
for (y = rect.top; y < min( buffer.height, rect.bottom); y++)
for (y = locked.top; y < min( buffer.height, locked.bottom ); y++)
{
if (surface->info.bmiHeader.biCompression == BI_RGB)
memcpy( dst, src, width * sizeof(*dst) );
@ -754,7 +729,7 @@ static void android_surface_flush( struct window_surface *window_surface )
if (rgn_rect)
{
while (rgn_rect < end && rgn_rect->bottom <= y) rgn_rect++;
apply_line_region( dst, width, rect.left, y, rgn_rect, end );
apply_line_region( dst, width, locked.left, y, rgn_rect, end );
}
src += surface->info.bmiHeader.biWidth;
@ -765,7 +740,7 @@ static void android_surface_flush( struct window_surface *window_surface )
else TRACE( "Unable to lock surface %p window %p buffer %p\n",
surface, surface->hwnd, surface->window );
window_surface_unlock( window_surface );
return TRUE;
}
/***********************************************************************
@ -1576,7 +1551,7 @@ BOOL ANDROID_UpdateLayeredWindow( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info
}
window_surface_unlock( surface );
surface->funcs->flush( surface );
window_surface_flush( surface );
done:
window_surface_release( surface );
@ -1608,7 +1583,7 @@ LRESULT ANDROID_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
window_surface_lock( surface );
surface->bounds = surface->rect;
window_surface_unlock( surface );
if (is_argb_surface( surface )) surface->funcs->flush( surface );
if (is_argb_surface( surface )) window_surface_flush( surface );
}
release_win_data( data );
}

View file

@ -112,21 +112,11 @@ static void macdrv_surface_set_region(struct window_surface *window_surface, HRG
/***********************************************************************
* macdrv_surface_flush
*/
static void macdrv_surface_flush(struct window_surface *window_surface)
static BOOL macdrv_surface_flush(struct window_surface *window_surface, const RECT *rect, const RECT *dirty)
{
struct macdrv_window_surface *surface = get_mac_surface(window_surface);
RECT rect = window_surface->rect;
OffsetRect(&rect, -rect.left, -rect.top);
window_surface_lock(window_surface);
TRACE("flushing %p %s bounds %s bits %p\n", surface, wine_dbgstr_rect(&surface->header.rect),
wine_dbgstr_rect(&window_surface->bounds), surface->bits);
if (intersect_rect(&rect, &rect, &window_surface->bounds))
macdrv_window_needs_display(surface->window, cgrect_from_rect(rect));
window_surface_unlock(window_surface);
macdrv_window_needs_display(surface->window, cgrect_from_rect(*dirty));
return FALSE; /* bounds are reset asynchronously, from macdrv_get_surface_display_image */
}
/***********************************************************************

View file

@ -1985,7 +1985,7 @@ BOOL macdrv_UpdateLayeredWindow(HWND hwnd, const UPDATELAYEREDWINDOWINFO *info,
memcpy(dst_bits, src_bits, bmi->bmiHeader.biSizeImage);
add_bounds_rect(&surface->bounds, &rect);
window_surface_unlock(surface);
surface->funcs->flush(surface);
window_surface_flush(surface);
}
/* The ULW flags are a superset of the LWA flags. */

View file

@ -756,7 +756,7 @@ void wayland_window_flush(HWND hwnd)
if (!data) return;
if (data->window_surface)
data->window_surface->funcs->flush(data->window_surface);
window_surface_flush(data->window_surface);
wayland_win_data_release(data);
}

View file

@ -56,12 +56,6 @@ static struct wayland_window_surface *wayland_window_surface_cast(
return (struct wayland_window_surface *)window_surface;
}
static inline void reset_bounds(RECT *bounds)
{
bounds->left = bounds->top = INT_MAX;
bounds->right = bounds->bottom = INT_MIN;
}
static void buffer_release(void *data, struct wl_buffer *buffer)
{
struct wayland_shm_buffer *shm_buffer = data;
@ -341,19 +335,14 @@ static void wayland_shm_buffer_copy(struct wayland_shm_buffer *src,
/***********************************************************************
* wayland_window_surface_flush
*/
static void wayland_window_surface_flush(struct window_surface *window_surface)
static BOOL wayland_window_surface_flush(struct window_surface *window_surface, const RECT *rect, const RECT *dirty)
{
struct wayland_window_surface *wws = wayland_window_surface_cast(window_surface);
struct wayland_shm_buffer *shm_buffer = NULL;
BOOL flushed = FALSE;
RECT damage_rect;
HRGN surface_damage_region = NULL;
HRGN copy_from_window_region;
window_surface_lock(window_surface);
if (!intersect_rect(&damage_rect, &wws->header.rect, &window_surface->bounds)) goto done;
if (!wws->wayland_surface || !wws->wayland_buffer_queue)
{
ERR("missing wayland surface=%p or buffer_queue=%p, returning\n",
@ -361,11 +350,7 @@ static void wayland_window_surface_flush(struct window_surface *window_surface)
goto done;
}
TRACE("surface=%p hwnd=%p surface_rect=%s bounds=%s\n", wws, wws->hwnd,
wine_dbgstr_rect(&wws->header.rect), wine_dbgstr_rect(&window_surface->bounds));
surface_damage_region = NtGdiCreateRectRgn(damage_rect.left, damage_rect.top,
damage_rect.right, damage_rect.bottom);
surface_damage_region = NtGdiCreateRectRgn(dirty->left, dirty->top, dirty->right, dirty->bottom);
if (!surface_damage_region)
{
ERR("failed to create surface damage region\n");
@ -438,9 +423,8 @@ static void wayland_window_surface_flush(struct window_surface *window_surface)
wayland_shm_buffer_ref((wws->wayland_surface->latest_window_buffer = shm_buffer));
done:
if (flushed) reset_bounds(&window_surface->bounds);
if (surface_damage_region) NtGdiDeleteObjectApp(surface_damage_region);
window_surface_unlock(window_surface);
return flushed;
}
/***********************************************************************

View file

@ -1871,67 +1871,47 @@ static void x11drv_surface_set_region( struct window_surface *window_surface, HR
/***********************************************************************
* x11drv_surface_flush
*/
static void x11drv_surface_flush( struct window_surface *window_surface )
static BOOL x11drv_surface_flush( struct window_surface *window_surface, const RECT *rect, const RECT *dirty )
{
struct x11drv_window_surface *surface = get_x11_surface( window_surface );
unsigned char *src = surface->bits;
unsigned char *dst = (unsigned char *)surface->image->data;
struct bitblt_coords coords;
window_surface_lock( window_surface );
coords.x = 0;
coords.y = 0;
coords.width = surface->header.rect.right - surface->header.rect.left;
coords.height = surface->header.rect.bottom - surface->header.rect.top;
SetRect( &coords.visrect, 0, 0, coords.width, coords.height );
if (intersect_rect( &coords.visrect, &coords.visrect, &window_surface->bounds ))
if (surface->is_argb || surface->color_key != CLR_INVALID) update_surface_region( surface );
if (src != dst)
{
TRACE( "flushing %p %dx%d bounds %s bits %p\n", surface, coords.width, coords.height,
wine_dbgstr_rect( &window_surface->bounds ), surface->bits );
int map[256], *mapping = get_window_surface_mapping( surface->image->bits_per_pixel, map );
int width_bytes = surface->image->bytes_per_line;
if (surface->is_argb || surface->color_key != CLR_INVALID) update_surface_region( surface );
src += dirty->top * width_bytes;
dst += dirty->top * width_bytes;
copy_image_byteswap( &surface->info, src, dst, width_bytes, width_bytes, dirty->bottom - dirty->top,
surface->byteswap, mapping, ~0u, surface->alpha_bits );
}
else if (surface->alpha_bits)
{
int x, y, stride = surface->image->bytes_per_line / sizeof(ULONG);
ULONG *ptr = (ULONG *)dst + dirty->top * stride;
if (src != dst)
{
int map[256], *mapping = get_window_surface_mapping( surface->image->bits_per_pixel, map );
int width_bytes = surface->image->bytes_per_line;
src += coords.visrect.top * width_bytes;
dst += coords.visrect.top * width_bytes;
copy_image_byteswap( &surface->info, src, dst, width_bytes, width_bytes,
coords.visrect.bottom - coords.visrect.top,
surface->byteswap, mapping, ~0u, surface->alpha_bits );
}
else if (surface->alpha_bits)
{
int x, y, stride = surface->image->bytes_per_line / sizeof(ULONG);
ULONG *ptr = (ULONG *)dst + coords.visrect.top * stride;
for (y = coords.visrect.top; y < coords.visrect.bottom; y++, ptr += stride)
for (x = coords.visrect.left; x < coords.visrect.right; x++)
ptr[x] |= surface->alpha_bits;
}
for (y = dirty->top; y < dirty->bottom; y++, ptr += stride)
for (x = dirty->left; x < dirty->right; x++)
ptr[x] |= surface->alpha_bits;
}
#ifdef HAVE_LIBXXSHM
if (surface->shminfo.shmid != -1)
XShmPutImage( gdi_display, surface->window, surface->gc, surface->image,
coords.visrect.left, coords.visrect.top,
surface->header.rect.left + coords.visrect.left,
surface->header.rect.top + coords.visrect.top,
coords.visrect.right - coords.visrect.left,
coords.visrect.bottom - coords.visrect.top, False );
else
if (surface->shminfo.shmid != -1)
XShmPutImage( gdi_display, surface->window, surface->gc, surface->image, dirty->left,
dirty->top, rect->left + dirty->left, rect->top + dirty->top,
dirty->right - dirty->left, dirty->bottom - dirty->top, False );
else
#endif
XPutImage( gdi_display, surface->window, surface->gc, surface->image,
coords.visrect.left, coords.visrect.top,
surface->header.rect.left + coords.visrect.left,
surface->header.rect.top + coords.visrect.top,
coords.visrect.right - coords.visrect.left,
coords.visrect.bottom - coords.visrect.top );
XFlush( gdi_display );
}
reset_bounds( &window_surface->bounds );
window_surface_unlock( window_surface );
XPutImage( gdi_display, surface->window, surface->gc, surface->image, dirty->left,
dirty->top, rect->left + dirty->left, rect->top + dirty->top,
dirty->right - dirty->left, dirty->bottom - dirty->top );
XFlush( gdi_display );
return TRUE;
}
/***********************************************************************

View file

@ -906,7 +906,7 @@ static BOOL X11DRV_Expose( HWND hwnd, XEvent *xev )
data->whole_rect.top - data->client_rect.top );
if (data->vis.visualid != default_visual.visualid)
data->surface->funcs->flush( data->surface );
window_surface_flush( data->surface );
}
OffsetRect( &rect, data->whole_rect.left - data->client_rect.left,
data->whole_rect.top - data->client_rect.top );

View file

@ -1236,7 +1236,7 @@ static void map_window( HWND hwnd, DWORD new_style )
XMapWindow( data->display, data->whole_window );
XFlush( data->display );
if (data->surface && data->vis.visualid != default_visual.visualid)
data->surface->funcs->flush( data->surface );
window_surface_flush( data->surface );
}
else set_xembed_flags( data, XEMBED_MAPPED );
@ -2803,7 +2803,7 @@ void X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flags,
XFlush( data->display ); /* make sure changes are done before we start painting again */
if (data->surface && data->vis.visualid != default_visual.visualid)
data->surface->funcs->flush( data->surface );
window_surface_flush( data->surface );
release_win_data( data );
}
@ -3050,7 +3050,7 @@ BOOL X11DRV_UpdateLayeredWindow( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info,
}
window_surface_unlock( surface );
surface->funcs->flush( surface );
window_surface_flush( surface );
done:
window_surface_release( surface );

View file

@ -213,7 +213,7 @@ struct window_surface_funcs
{
void* (*get_info)( struct window_surface *surface, BITMAPINFO *info );
void (*set_region)( struct window_surface *surface, HRGN region );
void (*flush)( struct window_surface *surface );
BOOL (*flush)( struct window_surface *surface, const RECT *rect, const RECT *dirty );
void (*destroy)( struct window_surface *surface );
};
@ -235,6 +235,7 @@ W32KAPI void window_surface_add_ref( struct window_surface *surface );
W32KAPI void window_surface_release( struct window_surface *surface );
W32KAPI void window_surface_lock( struct window_surface *surface );
W32KAPI void window_surface_unlock( struct window_surface *surface );
W32KAPI void window_surface_flush( struct window_surface *surface );
/* display manager interface, used to initialize display device registry data */