Instead of https://gitlab.winehq.org/wine/wine/-/merge_requests/8869
I think this would be a much lighter and less complicated approach than trying to wake the window threads with internal messages. And it should be able to avoid spurious wake ups when there's no window surfaces involved.
What I'm not completely sure about is whether this is going to flush the surfaces frequently enough, and if we can assume the window thread will always either peek or wait for messages.
-- v2: win32u: Keep window surfaces in a per-thread linked list. win32u: Remove window surface flush in expose_window_surface. win32u: Remove window surface flush on lock / unlock. win32u: Remove some less useful flush_window_surfaces. win32u: Flush window surfaces while waiting for messages. win32u: Use an absolute wait timeout in wait_message. win32u: Remove unnecessary window_surface exports. win32u: Dispatch NtUserUpdateLayeredWindow to the owner thread.
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/message.c | 7 +++++ dlls/win32u/spy.c | 1 + dlls/win32u/win32u_private.h | 17 ++++++++++++ dlls/win32u/window.c | 51 ++++++++++++++++++++++++++---------- include/ntuser.h | 1 + 5 files changed, 63 insertions(+), 14 deletions(-)
diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 035ab6574e4..21ab2e87628 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -2151,6 +2151,13 @@ static LRESULT handle_internal_message( HWND hwnd, UINT msg, WPARAM wparam, LPAR if (!set_active_window( (HWND)wparam, &prev, FALSE, TRUE, lparam )) return 0; return (LRESULT)prev; } + case WM_WINE_UPDATELAYEREDWINDOW: + { + const struct update_layered_window_params *params = (const struct update_layered_window_params *)lparam; + return update_layered_window( hwnd, params->hdc_dst, params->pts_dst, params->size, + params->hdc_src, params->pts_src, params->key, params->blend, + params->flags, params->dirty ); + } case WM_WINE_KEYBOARD_LL_HOOK: case WM_WINE_MOUSE_LL_HOOK: { diff --git a/dlls/win32u/spy.c b/dlls/win32u/spy.c index 67c6b126922..2f088682148 100644 --- a/dlls/win32u/spy.c +++ b/dlls/win32u/spy.c @@ -1137,6 +1137,7 @@ static const char * const WINEMessageTypeNames[SPY_MAX_WINEMSGNUM + 1] = "WM_WINE_SETWINDOWLONG", "WM_WINE_SETSTYLE", "WM_WINE_SETACTIVEWINDOW", + "WM_WINE_UPDATELAYEREDWINDOW", "WM_WINE_KEYBOARD_LL_HOOK", "WM_WINE_MOUSE_LL_HOOK", "WM_WINE_IME_NOTIFY", diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 4c7ce21d5b4..056ef83cdd4 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -292,6 +292,23 @@ extern HWND get_shell_window(void); extern HWND get_progman_window(void); extern HWND get_taskman_window(void);
+struct update_layered_window_params +{ + HDC hdc_dst; + const POINT *pts_dst; + const SIZE *size; + HDC hdc_src; + const POINT *pts_src; + COLORREF key; + const BLENDFUNCTION *blend; + DWORD flags; + const RECT *dirty; +}; + +extern BOOL update_layered_window( HWND hwnd, HDC hdc_dst, const POINT *pts_dst, const SIZE *size, + HDC hdc_src, const POINT *pts_src, COLORREF key, + const BLENDFUNCTION *blend, DWORD flags, const RECT *dirty ); + /* to release pointers retrieved by win_get_ptr */ static inline void release_win_ptr( struct tagWND *ptr ) { diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index 4345c7b7ff4..bb7718346c8 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -2446,12 +2446,10 @@ BOOL WINAPI NtUserSetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alph return ret; }
-/***************************************************************************** - * UpdateLayeredWindow (win32u.@) - */ -BOOL WINAPI NtUserUpdateLayeredWindow( HWND hwnd, HDC hdc_dst, const POINT *pts_dst, const SIZE *size, - HDC hdc_src, const POINT *pts_src, COLORREF key, - const BLENDFUNCTION *blend, DWORD flags, const RECT *dirty ) +/* NtUserUpdateLayeredWindow implementation */ +BOOL update_layered_window( HWND hwnd, HDC hdc_dst, const POINT *pts_dst, const SIZE *size, + HDC hdc_src, const POINT *pts_src, COLORREF key, + const BLENDFUNCTION *blend, DWORD flags, const RECT *dirty ) { DWORD swp_flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW; struct window_rects new_rects; @@ -2460,14 +2458,6 @@ BOOL WINAPI NtUserUpdateLayeredWindow( HWND hwnd, HDC hdc_dst, const POINT *pts_ SIZE offset; BOOL ret = FALSE;
- if (flags & ~(ULW_COLORKEY | ULW_ALPHA | ULW_OPAQUE | ULW_EX_NORESIZE) || - !(get_window_long( hwnd, GWL_EXSTYLE ) & WS_EX_LAYERED) || - NtUserGetLayeredWindowAttributes( hwnd, NULL, NULL, NULL )) - { - RtlSetLastWin32Error( ERROR_INVALID_PARAMETER ); - return FALSE; - } - get_window_rects( hwnd, COORDS_PARENT, &new_rects, get_thread_dpi() );
if (pts_dst) @@ -2553,6 +2543,39 @@ done: return ret; }
+/***************************************************************************** + * UpdateLayeredWindow (win32u.@) + */ +BOOL WINAPI NtUserUpdateLayeredWindow( HWND hwnd, HDC hdc_dst, const POINT *pts_dst, const SIZE *size, + HDC hdc_src, const POINT *pts_src, COLORREF key, + const BLENDFUNCTION *blend, DWORD flags, const RECT *dirty ) +{ + struct update_layered_window_params params = { hdc_dst, pts_dst, size, hdc_src, pts_src, key, blend, flags, dirty }; + + if (flags & ~(ULW_COLORKEY | ULW_ALPHA | ULW_OPAQUE | ULW_EX_NORESIZE) || + !(get_window_long( hwnd, GWL_EXSTYLE ) & WS_EX_LAYERED) || + NtUserGetLayeredWindowAttributes( hwnd, NULL, NULL, NULL )) + { + RtlSetLastWin32Error( ERROR_INVALID_PARAMETER ); + return FALSE; + } + + if (!is_current_process_window( hwnd )) + { + FIXME( "Not supported on other process windows\n" ); + RtlSetLastWin32Error( ERROR_INVALID_PARAMETER ); + return FALSE; + } + + if (!is_current_thread_window( hwnd )) + { + WARN( "Called for other thread window %p\n", hwnd ); + return send_message( hwnd, WM_WINE_UPDATELAYEREDWINDOW, 0, (LPARAM)¶ms ); + } + + return update_layered_window( hwnd, hdc_dst, pts_dst, size, hdc_src, pts_src, key, blend, flags, dirty ); +} + /*********************************************************************** * list_children_from_point * diff --git a/include/ntuser.h b/include/ntuser.h index ef09d7e97bb..5cb11f25f1b 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -633,6 +633,7 @@ enum wine_internal_message WM_WINE_SETWINDOWLONG, WM_WINE_SETSTYLE, WM_WINE_SETACTIVEWINDOW, + WM_WINE_UPDATELAYEREDWINDOW, WM_WINE_KEYBOARD_LL_HOOK, WM_WINE_MOUSE_LL_HOOK, WM_WINE_IME_NOTIFY,
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/dce.c | 22 +++++++++++----------- dlls/win32u/win32u_private.h | 7 ++++++- include/wine/gdi_driver.h | 6 ------ 3 files changed, 17 insertions(+), 18 deletions(-)
diff --git a/dlls/win32u/dce.c b/dlls/win32u/dce.c index d1cf5c78bab..be31b909b3f 100644 --- a/dlls/win32u/dce.c +++ b/dlls/win32u/dce.c @@ -524,8 +524,8 @@ static BOOL update_surface_shape( struct window_surface *surface, const RECT *re return clear_surface_shape( surface ); }
-W32KAPI struct window_surface *window_surface_create( UINT size, const struct window_surface_funcs *funcs, HWND hwnd, - const RECT *rect, BITMAPINFO *info, HBITMAP bitmap ) +struct window_surface *window_surface_create( UINT size, const struct window_surface_funcs *funcs, HWND hwnd, + const RECT *rect, BITMAPINFO *info, HBITMAP bitmap ) { struct window_surface *surface;
@@ -552,12 +552,12 @@ W32KAPI struct window_surface *window_surface_create( UINT size, const struct wi return surface; }
-W32KAPI void window_surface_add_ref( struct window_surface *surface ) +void window_surface_add_ref( struct window_surface *surface ) { InterlockedIncrement( &surface->ref ); }
-W32KAPI void window_surface_release( struct window_surface *surface ) +void window_surface_release( struct window_surface *surface ) { ULONG ret = InterlockedDecrement( &surface->ref ); if (!ret) @@ -571,19 +571,19 @@ W32KAPI void window_surface_release( struct window_surface *surface ) } }
-W32KAPI void window_surface_lock( struct window_surface *surface ) +void window_surface_lock( struct window_surface *surface ) { if (surface == &dummy_surface) return; pthread_mutex_lock( &surface->mutex ); }
-W32KAPI void window_surface_unlock( struct window_surface *surface ) +void window_surface_unlock( struct window_surface *surface ) { if (surface == &dummy_surface) return; pthread_mutex_unlock( &surface->mutex ); }
-void *window_surface_get_color( struct window_surface *surface, BITMAPINFO *info ) +static void *window_surface_get_color( struct window_surface *surface, BITMAPINFO *info ) { struct bitblt_coords coords = {0}; struct gdi_image_bits gdi_bits; @@ -606,7 +606,7 @@ void *window_surface_get_color( struct window_surface *surface, BITMAPINFO *info return gdi_bits.ptr; }
-W32KAPI void window_surface_flush( struct window_surface *surface ) +void window_surface_flush( struct window_surface *surface ) { char color_buf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )]; char shape_buf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )]; @@ -641,7 +641,7 @@ W32KAPI void window_surface_flush( struct window_surface *surface ) window_surface_unlock( surface ); }
-W32KAPI void window_surface_set_layered( struct window_surface *surface, COLORREF color_key, UINT alpha_bits, UINT alpha_mask ) +void window_surface_set_layered( struct window_surface *surface, COLORREF color_key, UINT alpha_bits, UINT alpha_mask ) { char color_buf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )]; BITMAPINFO *color_info = (BITMAPINFO *)color_buf; @@ -670,7 +670,7 @@ W32KAPI void window_surface_set_layered( struct window_surface *surface, COLORRE window_surface_unlock( surface ); }
-W32KAPI void window_surface_set_clip( struct window_surface *surface, HRGN clip_region ) +void window_surface_set_clip( struct window_surface *surface, HRGN clip_region ) { window_surface_lock( surface );
@@ -703,7 +703,7 @@ W32KAPI void window_surface_set_clip( struct window_surface *surface, HRGN clip_ window_surface_unlock( surface ); }
-W32KAPI void window_surface_set_shape( struct window_surface *surface, HRGN shape_region ) +void window_surface_set_shape( struct window_surface *surface, HRGN shape_region ) { window_surface_lock( surface );
diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 056ef83cdd4..a79e163d0b9 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -54,7 +54,12 @@ extern void move_window_bits_surface( HWND hwnd, const RECT *window_rect, struct const RECT *old_visible_rect, const RECT *valid_rects ); extern void register_window_surface( struct window_surface *old, struct window_surface *new ); -extern void *window_surface_get_color( struct window_surface *surface, BITMAPINFO *info ); + +extern void window_surface_lock( struct window_surface *surface ); +extern void window_surface_unlock( struct window_surface *surface ); +extern void window_surface_flush( struct window_surface *surface ); +extern void window_surface_set_clip( struct window_surface *surface, HRGN clip_region ); +extern void window_surface_set_layered( struct window_surface *surface, COLORREF color_key, UINT alpha_bits, UINT alpha_mask );
/* defwnd.c */ extern BOOL adjust_window_rect( RECT *rect, DWORD style, BOOL menu, DWORD ex_style, UINT dpi ); diff --git a/include/wine/gdi_driver.h b/include/wine/gdi_driver.h index abf1b699cab..ef264cace97 100644 --- a/include/wine/gdi_driver.h +++ b/include/wine/gdi_driver.h @@ -317,13 +317,7 @@ W32KAPI struct window_surface *window_surface_create( UINT size, const struct wi const RECT *rect, BITMAPINFO *info, HBITMAP bitmap ); 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_set_layered( struct window_surface *surface, COLORREF color_key, UINT alpha_bits, UINT alpha_mask ); -W32KAPI void window_surface_flush( struct window_surface *surface ); -W32KAPI void window_surface_set_clip( struct window_surface *surface, HRGN clip_region ); W32KAPI void window_surface_set_shape( struct window_surface *surface, HRGN shape_region ); -W32KAPI void window_surface_set_layered( struct window_surface *surface, COLORREF color_key, UINT alpha_bits, UINT alpha_mask );
/* display manager interface, used to initialize display device registry data */
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/message.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 21ab2e87628..a51f452bb7c 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -3158,11 +3158,15 @@ static inline LARGE_INTEGER *get_nt_timeout( LARGE_INTEGER *time, DWORD timeout static DWORD wait_message( DWORD count, const HANDLE *handles, DWORD timeout, DWORD mask, DWORD flags ) { struct thunk_lock_params params = {.dispatch.callback = thunk_lock_callback}; - LARGE_INTEGER time; - DWORD ret; + LARGE_INTEGER time, now, *abs; + DWORD ret = count - 1; void *ret_ptr; ULONG ret_len;
+ NtQuerySystemTime( &now ); + + if ((abs = get_nt_timeout( &time, timeout ))) abs->QuadPart = now.QuadPart - abs->QuadPart; + if (!KeUserDispatchCallback( ¶ms.dispatch, sizeof(params), &ret_ptr, &ret_len ) && ret_len == sizeof(params.locks)) { @@ -3173,8 +3177,7 @@ static DWORD wait_message( DWORD count, const HANDLE *handles, DWORD timeout, DW if (user_driver->pProcessEvents( mask )) ret = count - 1; else { - ret = NtWaitForMultipleObjects( count, handles, !(flags & MWMO_WAITALL), - !!(flags & MWMO_ALERTABLE), get_nt_timeout( &time, timeout )); + ret = NtWaitForMultipleObjects( count, handles, !(flags & MWMO_WAITALL), !!(flags & MWMO_ALERTABLE), abs ); if (ret == count - 1) user_driver->pProcessEvents( mask ); else if (HIWORD(ret)) /* is it an error code? */ {
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/message.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-)
diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index a51f452bb7c..f3e9f6858de 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -3154,19 +3154,34 @@ static inline LARGE_INTEGER *get_nt_timeout( LARGE_INTEGER *time, DWORD timeout return time; }
+static DWORD wait_multiple_objects_flush( DWORD count, const HANDLE *handles, DWORD timeout, DWORD mask, DWORD flags ) +{ + LARGE_INTEGER time, now, *abs; + DWORD ret; + + NtQuerySystemTime( &now ); + + if ((abs = get_nt_timeout( &time, timeout ))) abs->QuadPart = now.QuadPart - abs->QuadPart; + else time.QuadPart = INT64_MAX; + + do + { + flush_window_surfaces( TRUE ); + now.QuadPart = min( time.QuadPart, now.QuadPart + 333333 /* 30 fps */ ); + ret = NtWaitForMultipleObjects( count, handles, !(flags & MWMO_WAITALL), !!(flags & MWMO_ALERTABLE), &now ); + } while (ret == WAIT_TIMEOUT && now.QuadPart < time.QuadPart); + + return ret; +} + /* wait for message or signaled handle */ static DWORD wait_message( DWORD count, const HANDLE *handles, DWORD timeout, DWORD mask, DWORD flags ) { struct thunk_lock_params params = {.dispatch.callback = thunk_lock_callback}; - LARGE_INTEGER time, now, *abs; DWORD ret = count - 1; void *ret_ptr; ULONG ret_len;
- NtQuerySystemTime( &now ); - - if ((abs = get_nt_timeout( &time, timeout ))) abs->QuadPart = now.QuadPart - abs->QuadPart; - if (!KeUserDispatchCallback( ¶ms.dispatch, sizeof(params), &ret_ptr, &ret_len ) && ret_len == sizeof(params.locks)) { @@ -3177,7 +3192,7 @@ static DWORD wait_message( DWORD count, const HANDLE *handles, DWORD timeout, DW if (user_driver->pProcessEvents( mask )) ret = count - 1; else { - ret = NtWaitForMultipleObjects( count, handles, !(flags & MWMO_WAITALL), !!(flags & MWMO_ALERTABLE), abs ); + ret = wait_multiple_objects_flush( count, handles, timeout, mask, flags ); if (ret == count - 1) user_driver->pProcessEvents( mask ); else if (HIWORD(ret)) /* is it an error code? */ {
From: Rémi Bernon rbernon@codeweavers.com
Now that wait_messages is doing it already, and as peek_message should also call it occasionally. --- dlls/win32u/input.c | 4 +--- dlls/win32u/message.c | 2 -- 2 files changed, 1 insertion(+), 5 deletions(-)
diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index c718bd1cbbc..b5ad3d1c027 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -796,9 +796,7 @@ static void check_for_events( UINT flags ) }; MSG msg;
- if (!user_driver->pProcessEvents( flags )) - flush_window_surfaces( TRUE ); - + user_driver->pProcessEvents( flags ); peek_message( &msg, &filter ); }
diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index f3e9f6858de..5fa5e10479d 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -3236,8 +3236,6 @@ static DWORD wait_objects( DWORD count, const HANDLE *handles, DWORD timeout, { assert( count ); /* we must have at least the server queue */
- flush_window_surfaces( TRUE ); - if (!check_queue_masks( wake_mask, changed_mask )) { SERVER_START_REQ( set_queue_mask )
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/dibdrv/dc.c | 16 ++-------------- include/wine/gdi_driver.h | 1 - 2 files changed, 2 insertions(+), 15 deletions(-)
diff --git a/dlls/win32u/dibdrv/dc.c b/dlls/win32u/dibdrv/dc.c index 8a72d9789ea..71599e48528 100644 --- a/dlls/win32u/dibdrv/dc.c +++ b/dlls/win32u/dibdrv/dc.c @@ -517,25 +517,13 @@ static inline struct windrv_physdev *get_windrv_physdev( PHYSDEV dev ) static inline void lock_surface( struct windrv_physdev *dev ) { struct window_surface *surface = dev->surface; - - if (!dev->lock_count++) - { - window_surface_lock( surface ); - if (IsRectEmpty( dev->dibdrv->bounds ) || !surface->draw_start_ticks) - surface->draw_start_ticks = NtGetTickCount(); - } + if (!dev->lock_count++) window_surface_lock( surface ); }
static inline void unlock_surface( struct windrv_physdev *dev ) { struct window_surface *surface = dev->surface; - - if (!--dev->lock_count) - { - DWORD ticks = NtGetTickCount() - surface->draw_start_ticks; - window_surface_unlock( surface ); - if (ticks > FLUSH_PERIOD) window_surface_flush( dev->surface ); - } + if (!--dev->lock_count) window_surface_unlock( surface ); }
static inline void lock_surfaces( struct windrv_physdev *dst_dev, struct windrv_physdev *src_dev ) diff --git a/include/wine/gdi_driver.h b/include/wine/gdi_driver.h index ef264cace97..432f00e8c62 100644 --- a/include/wine/gdi_driver.h +++ b/include/wine/gdi_driver.h @@ -303,7 +303,6 @@ struct window_surface pthread_mutex_t mutex; /* mutex needed for any field below */ RECT bounds; /* dirty area rectangle */ HRGN clip_region; /* visible region of the surface, fully visible if 0 */ - DWORD draw_start_ticks; /* start ticks of fresh draw */ COLORREF color_key; /* layered window surface color key, invalid if CLR_INVALID */ UINT alpha_bits; /* layered window global alpha bits, invalid if -1 */ UINT alpha_mask; /* layered window per-pixel alpha mask, invalid if 0 */
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/window.c | 1 - 1 file changed, 1 deletion(-)
diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index bb7718346c8..73d9fe283e0 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -2291,7 +2291,6 @@ static BOOL expose_window_surface( HWND hwnd, UINT flags, const RECT *rect, UINT add_bounds_rect( &surface->bounds, &exposed_rect ); } window_surface_unlock( surface ); - if (surface->alpha_mask) window_surface_flush( surface ); window_surface_release( surface ); return TRUE; }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/dce.c | 37 ++++++++++++------------------------ dlls/win32u/message.c | 7 ++++--- dlls/win32u/ntuser_private.h | 1 + dlls/win32u/win32u_private.h | 3 +-- dlls/win32u/window.c | 13 ++----------- include/wine/gdi_driver.h | 2 +- 6 files changed, 21 insertions(+), 42 deletions(-)
diff --git a/dlls/win32u/dce.c b/dlls/win32u/dce.c index be31b909b3f..10a7206ec6f 100644 --- a/dlls/win32u/dce.c +++ b/dlls/win32u/dce.c @@ -50,8 +50,12 @@ static struct list dce_list = LIST_INIT(dce_list);
#define DCE_CACHE_SIZE 64
-static struct list window_surfaces = LIST_INIT( window_surfaces ); -static pthread_mutex_t surfaces_lock = PTHREAD_MUTEX_INITIALIZER; +struct list *thread_window_surfaces(void) +{ + struct list *window_surfaces = &get_user_thread_info()->window_surfaces; + if (!window_surfaces->next) list_init( window_surfaces ); + return window_surfaces; +}
/******************************************************************* * Dummy window surface for windows that shouldn't get painted. @@ -547,6 +551,7 @@ struct window_surface *window_surface_create( UINT size, const struct window_sur }
pthread_mutex_init( &surface->mutex, NULL ); + list_add_tail( thread_window_surfaces(), &surface->entry );
TRACE( "created surface %p for hwnd %p rect %s\n", surface, hwnd, wine_dbgstr_rect( &surface->rect ) ); return surface; @@ -562,6 +567,7 @@ void window_surface_release( struct window_surface *surface ) ULONG ret = InterlockedDecrement( &surface->ref ); if (!ret) { + list_remove( &surface->entry ); if (surface != &dummy_surface) pthread_mutex_destroy( &surface->mutex ); if (surface->clip_region) NtGdiDeleteObjectApp( surface->clip_region ); if (surface->color_bitmap) NtGdiDeleteObjectApp( surface->color_bitmap ); @@ -725,22 +731,6 @@ void window_surface_set_shape( struct window_surface *surface, HRGN shape_region window_surface_flush( surface ); }
-/******************************************************************* - * register_window_surface - * - * Register a window surface in the global list, possibly replacing another one. - */ -void register_window_surface( struct window_surface *old, struct window_surface *new ) -{ - if (old == &dummy_surface) old = NULL; - if (new == &dummy_surface) new = NULL; - if (old == new) return; - pthread_mutex_lock( &surfaces_lock ); - if (old) list_remove( &old->entry ); - if (new) list_add_tail( &window_surfaces, &new->entry ); - pthread_mutex_unlock( &surfaces_lock ); -} - /******************************************************************* * flush_window_surfaces * @@ -749,19 +739,16 @@ void register_window_surface( struct window_surface *old, struct window_surface void flush_window_surfaces( BOOL idle ) { static DWORD last_idle; - DWORD now; + DWORD now = NtGetTickCount(); struct window_surface *surface; + struct list *window_surfaces = thread_window_surfaces();
- pthread_mutex_lock( &surfaces_lock ); - now = NtGetTickCount(); if (idle) last_idle = now; /* if not idle, we only flush if there's evidence that the app never goes idle */ - else if ((int)(now - last_idle) < 50) goto done; + else if ((int)(now - last_idle) < 50) return;
- LIST_FOR_EACH_ENTRY( surface, &window_surfaces, struct window_surface, entry ) + LIST_FOR_EACH_ENTRY( surface, window_surfaces, struct window_surface, entry ) window_surface_flush( surface ); -done: - pthread_mutex_unlock( &surfaces_lock ); }
/*********************************************************************** diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 5fa5e10479d..84ac1ae69c5 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -3156,6 +3156,7 @@ static inline LARGE_INTEGER *get_nt_timeout( LARGE_INTEGER *time, DWORD timeout
static DWORD wait_multiple_objects_flush( DWORD count, const HANDLE *handles, DWORD timeout, DWORD mask, DWORD flags ) { + BOOL flush = !list_empty( thread_window_surfaces() ); LARGE_INTEGER time, now, *abs; DWORD ret;
@@ -3166,10 +3167,10 @@ static DWORD wait_multiple_objects_flush( DWORD count, const HANDLE *handles, DW
do { - flush_window_surfaces( TRUE ); + if (flush) flush_window_surfaces( TRUE ); now.QuadPart = min( time.QuadPart, now.QuadPart + 333333 /* 30 fps */ ); - ret = NtWaitForMultipleObjects( count, handles, !(flags & MWMO_WAITALL), !!(flags & MWMO_ALERTABLE), &now ); - } while (ret == WAIT_TIMEOUT && now.QuadPart < time.QuadPart); + ret = NtWaitForMultipleObjects( count, handles, !(flags & MWMO_WAITALL), !!(flags & MWMO_ALERTABLE), flush ? &now : abs ); + } while (flush && ret == WAIT_TIMEOUT && now.QuadPart < time.QuadPart);
return ret; } diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index f5559c5ca4f..4c6f094eae8 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -103,6 +103,7 @@ struct user_thread_info HANDLE server_queue; /* Handle to server-side queue */ DWORD last_getmsg_time; /* Get/PeekMessage last request time */ LONGLONG last_driver_time; /* Get/PeekMessage driver event time */ + struct list window_surfaces; /* window surfaces for this thread */ WORD hook_call_depth; /* Number of recursively called hook procs */ WORD hook_unicode; /* Is current hook unicode? */ HHOOK hook; /* Current hook */ diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index a79e163d0b9..e8bc1e0c62d 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -44,6 +44,7 @@ extern ULONG_PTR set_icon_param( HICON handle, const struct free_icon_params *pa
/* dce.c */ extern struct window_surface dummy_surface; +extern struct list *thread_window_surfaces(void); 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 ); @@ -52,8 +53,6 @@ extern void flush_window_surfaces( BOOL idle ); extern void move_window_bits( HWND hwnd, const struct window_rects *rects, const RECT *valid_rects ); extern void move_window_bits_surface( HWND hwnd, const RECT *window_rect, struct window_surface *old_surface, const RECT *old_visible_rect, const RECT *valid_rects ); -extern void register_window_surface( struct window_surface *old, - struct window_surface *new );
extern void window_surface_lock( struct window_surface *surface ); extern void window_surface_unlock( struct window_surface *surface ); diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index 73d9fe283e0..a8ab2986209 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -2197,7 +2197,6 @@ static BOOL apply_window_pos( HWND hwnd, HWND insert_after, UINT swp_flags, stru if (ret) { TRACE( "win %p surface %p -> %p\n", hwnd, old_surface, new_surface ); - register_window_surface( old_surface, new_surface ); if (old_surface) { if (valid_rects) @@ -5201,11 +5200,7 @@ LRESULT destroy_window( HWND hwnd )
NtUserDestroyMenu( menu ); NtUserDestroyMenu( sys_menu ); - if (surface) - { - register_window_surface( surface, NULL ); - window_surface_release( surface ); - } + if (surface) window_surface_release( surface );
detach_client_surfaces( hwnd ); if (win->opengl_drawable) opengl_drawable_release( win->opengl_drawable ); @@ -5368,11 +5363,7 @@ void destroy_thread_windows(void)
NtUserDestroyMenu( entry->menu ); NtUserDestroyMenu( entry->sys_menu ); - if (entry->surface) - { - register_window_surface( entry->surface, NULL ); - window_surface_release( entry->surface ); - } + if (entry->surface) window_surface_release( entry->surface ); free( entry ); } } diff --git a/include/wine/gdi_driver.h b/include/wine/gdi_driver.h index 432f00e8c62..90c10204859 100644 --- a/include/wine/gdi_driver.h +++ b/include/wine/gdi_driver.h @@ -295,7 +295,7 @@ struct window_surface_funcs struct window_surface { const struct window_surface_funcs *funcs; /* driver-specific implementations */ - struct list entry; /* entry in global list managed by user32 */ + struct list entry; /* entry in win32u thread window surfaces */ LONG ref; /* reference count */ HWND hwnd; /* window the surface was created for */ RECT rect; /* constant, no locking needed */