Module: wine
Branch: master
Commit: 6d2bd75c4a82d10ee98c63010a5701d428ccc5d0
URL: https://gitlab.winehq.org/wine/wine/-/commit/6d2bd75c4a82d10ee98c63010a5701…
Author: Alexandros Frantzis <alexandros.frantzis(a)collabora.com>
Date: Thu Feb 16 18:20:56 2023 +0200
win32u: Reset draw_start_ticks for new window_surface.
Normally, a new window_surface has no damage so its draw_start_ticks
value is reset at the time of the first lock_surface.
However, if contents from the old window_surface are copied to the new
one when the window_surface for a window is updated, the new
window_surface will be initially damaged. We want to reset the
draw_start_ticks value in this case too, to avoid flushes occuring soon
after such updates, during the initial redraw of the window_surface.
Signed-off-by: Alexandros Frantzis <alexandros.frantzis(a)collabora.com>
---
dlls/win32u/dibdrv/dc.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/dlls/win32u/dibdrv/dc.c b/dlls/win32u/dibdrv/dc.c
index f96374c1229..23ef7f64390 100644
--- a/dlls/win32u/dibdrv/dc.c
+++ b/dlls/win32u/dibdrv/dc.c
@@ -744,7 +744,8 @@ 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 = NtGetTickCount();
+ if (IsRectEmpty( dev->dibdrv->bounds ) || dev->surface->draw_start_ticks == 0)
+ dev->surface->draw_start_ticks = NtGetTickCount();
}
static inline void unlock_surface( struct windrv_physdev *dev )
Module: wine
Branch: master
Commit: aa72d7d42d64a8fd9ded6d870f261eeaccf632fb
URL: https://gitlab.winehq.org/wine/wine/-/commit/aa72d7d42d64a8fd9ded6d870f261e…
Author: Alexandros Frantzis <alexandros.frantzis(a)collabora.com>
Date: Thu Feb 16 18:17:03 2023 +0200
gdi32: Track ticks since draw start per window_surface.
Track ticks since draw start per window_surface, instead of per DC as is
currently the case. This change helps reduce visual glitches caused by
badly timed flushes when drawing to the same window_surface from
multiple DCs (e.g., for child windows).
This approach is a better fit for the current heuristic for forcing
flushing, which consults the shared window_surface bounds to decide
whether this is the start of a draw in order to reset the (currently per
DC) draw start time.
The problem in the current implementation occurs when a drawing to a DC
begins with an already damaged window_surface, e.g., due to draws from
other DCs targeting that window_surface. In such a case, the DC draw
start time is not reset and refers to the start of some previous draw
sequence using this DC, thus increasing the chances that the 50ms time
flush limit will be eventually exceeded in the middle of the current
draw sequence. In other words, the state of the (shared) window_surface
damage is not a reliable indicator of the beginning (or not) of a draw
to a DC.
An example, assuming DC1 and DC2 target the same window_surface:
DC1.start_ticks = 0
DC2.start_ticks = 0
FLUSH_PERIOD = 50
0 flush
1 draw to DC1 -> DC1.start_ticks = 1
... [no flush] ...
2 draw to DC2 -> DC2.start_ticks remains 0 since surface is damaged
...
50 flush
51 draw to DC1 -> DC1.start_ticks = 51
... [no flush] ...
52 draw to DC2 -> DC2.start_ticks remains 0 since surface is damaged,
current - DC2.start_ticks > FLUSH_PERIOD so we are
forced to flush in the middle of the drawing
sequence => potential glitch
Tracking the draw start per window_surface ameliorates the problem
because the beginning of a draw on a DC targeting an undamaged
window_surface resets the start time for all DCs targeting that
window_surface:
...
50 flush
51 draw to DC1 -> surface.draw_ticks = 51
... [no flush] ...
52 draw to DC2 -> surface.draw_ticks remains 51 since surface is damaged,
but current - surface.draw_ticks < FLUSH_PERIOD, so we
do not flush
Signed-off-by: Alexandros Frantzis <alexandros.frantzis(a)collabora.com>
---
dlls/win32u/dibdrv/dc.c | 6 +++---
include/wine/gdi_driver.h | 1 +
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/dlls/win32u/dibdrv/dc.c b/dlls/win32u/dibdrv/dc.c
index 68a009f576e..f96374c1229 100644
--- a/dlls/win32u/dibdrv/dc.c
+++ b/dlls/win32u/dibdrv/dc.c
@@ -731,7 +731,6 @@ struct windrv_physdev
struct gdi_physdev dev;
struct dibdrv_physdev *dibdrv;
struct window_surface *surface;
- DWORD start_ticks;
};
static const struct gdi_dc_funcs window_driver;
@@ -745,13 +744,14 @@ 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->start_ticks = NtGetTickCount();
+ if (IsRectEmpty( dev->dibdrv->bounds )) dev->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 (NtGetTickCount() - dev->start_ticks > FLUSH_PERIOD) dev->surface->funcs->flush( dev->surface );
+ if (should_flush) dev->surface->funcs->flush( dev->surface );
}
static void CDECL unlock_bits_surface( struct gdi_image_bits *bits )
diff --git a/include/wine/gdi_driver.h b/include/wine/gdi_driver.h
index 3de7e20af9a..fe0894b2820 100644
--- a/include/wine/gdi_driver.h
+++ b/include/wine/gdi_driver.h
@@ -217,6 +217,7 @@ struct window_surface
struct list entry; /* entry in global list managed by user32 */
LONG ref; /* reference count */
RECT rect; /* constant, no locking needed */
+ DWORD draw_start_ticks; /* start ticks of fresh draw */
/* driver-specific fields here */
};