Fix race condition between ConfigureNotify and PresentCompleteNotify

* compositor.h: Update prototypes.
* frame_clock.c (struct _FrameClock): New fields for keeping
track of configure events.
(FreezeForValue): If the freeze is outdated, bring the counter
up to date now.
(XLFrameClockHandleFrameEvent): Set the number of configure
events that should have been considered by the frame clock upon
processing.
(XLFrameClockNoteConfigure): New function.
* picture_renderer.c (SwapBackBuffers): Remove outdated comment.
* xdg_surface.c (NoteConfigure, XLXdgRoleReconstrain):
* xdg_toplevel.c (NoteWindowResized): Note frame clock
configure.
This commit is contained in:
hujianwei 2022-11-01 01:25:42 +00:00
parent da212fe729
commit 743d363ad2
5 changed files with 61 additions and 3 deletions

View file

@ -1288,6 +1288,7 @@ extern void XLFrameClockDisablePredictRefresh (FrameClock *);
extern void XLFrameClockSetFreezeCallback (FrameClock *, void (*) (void *),
void *);
extern uint64_t XLFrameClockGetFrameTime (FrameClock *);
extern void XLFrameClockNoteConfigure (FrameClock *);
extern void *XLAddCursorClockCallback (void (*) (void *, struct timespec),
void *);
extern void XLStopCursorClockCallback (void *);

View file

@ -109,6 +109,11 @@ struct _FrameClock
/* The delay between the start of vblank and the redraw point. */
uint32_t frame_delay;
/* The number of configure events received affecting freeze, and the
number of configure events that should be received after a freeze
is put in place. */
uint32_t got_configure_count, pending_configure_count;
/* Whether or not configury is in progress, and whether or not this
is frozen, and whether or not the frame shouldn't actually be
unfrozen until EndFrame. */
@ -239,18 +244,31 @@ HandleEndFrame (Timer *timer, void *data, struct timespec time)
EndFrame (clock);
}
/* Forward declaration. */
/* Forward declarations. */
static void RunFrameCallbacks (FrameClock *);
static Bool StartFrame (FrameClock *, Bool, Bool);
static void
FreezeForValue (FrameClock *clock, uint64_t counter_value)
{
Bool need_empty_frame;
/* If it took too long (1 second at 60fps) to obtain the counter
value, and said value is now out of date, don't do anything. */
if (clock->next_frame_id > counter_value)
return;
need_empty_frame = False;
/* If ending a frame waits for PresentCompleteNotify, then the
configure event after this freeze may have been put into effect
by the time the freeze itself. Start a new frame to bring up to
date contents to the display. */
if (clock->pending_configure_count <= clock->got_configure_count)
need_empty_frame = True;
/* The frame clock is now frozen, and we will have to wait for a
client to ack_configure and then commit something. */
@ -278,7 +296,20 @@ FreezeForValue (FrameClock *clock, uint64_t counter_value)
clock->in_frame = False;
clock->need_configure = True;
clock->configure_id = counter_value;
if (need_empty_frame)
{
/* Request a new frame and don't allow starting frames until it
finishes. See above for why. clock->in_frame is False for
now to really force the frame to happen. */
StartFrame (clock, True, False);
EndFrame (clock);
}
else
clock->frozen = True;
return;
}
static void
@ -408,6 +439,10 @@ StartFrame (FrameClock *clock, Bool urgent, Bool predict)
{
clock->next_frame_id = clock->configure_id;
clock->finished_frame_id = 0;
/* Don't start the end frame timer if this frame is being drawn
in response to configury. */
predict = True;
}
clock->in_frame = True;
@ -700,6 +735,11 @@ XLFrameClockHandleFrameEvent (FrameClock *clock, XEvent *event)
if (value % 2)
value += 1;
/* Set the number of configure events that should be received by
the time the freeze is put into effect. */
clock->pending_configure_count
= clock->got_configure_count + 1;
/* If a frame is in progress, postpone this frame
synchronization message. */
if (clock->in_frame && !clock->end_frame_called)
@ -861,6 +901,13 @@ XLFrameClockGetFrameTime (FrameClock *clock)
return clock->last_frame_time;
}
void
XLFrameClockNoteConfigure (FrameClock *clock)
{
/* This value is to track resize event validity. */
clock->got_configure_count += 1;
}
/* Cursor animation clock-related functions. */

View file

@ -804,7 +804,6 @@ SwapBackBuffers (PictureTarget *target, pixman_region32_t *damage)
if (!present_serial)
present_serial++;
/* TODO: handle completion correctly. */
XPresentPixmap (compositor.display, target->window,
back_buffer->pixmap, present_serial,
None, region, 0, 0, None, None, fence,

View file

@ -1064,6 +1064,11 @@ NoteConfigure (XdgRole *role, XEvent *event)
event->xconfigure.y);
}
/* Tell the frame clock how many WM-generated configure events have
arrived. */
XLFrameClockNoteConfigure (role->clock);
/* Run reconstrain callbacks. */
RunReconstrainCallbacksForXEvent (role, event);
}
@ -1956,6 +1961,10 @@ XLXdgRoleReconstrain (Role *role, XEvent *event)
xdg_role = XdgRoleFromRole (role);
RunReconstrainCallbacksForXEvent (xdg_role, event);
/* If event is a configure event, tell the frame clock about it. */
if (event->type == ConfigureNotify)
XLFrameClockNoteConfigure (xdg_role->clock);
}
void

View file

@ -1660,6 +1660,8 @@ NoteWindowResized (Role *role, XdgRoleImplementation *impl,
if (event.xconfigure.send_event)
XLXdgRoleNoteConfigure (toplevel->role, &event);
else
XLXdgRoleReconstrain (toplevel->role, &event);
RecordStateSize (toplevel);
}