forked from 12to11/12to11
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:
parent
da212fe729
commit
743d363ad2
5 changed files with 61 additions and 3 deletions
|
@ -1288,6 +1288,7 @@ extern void XLFrameClockDisablePredictRefresh (FrameClock *);
|
||||||
extern void XLFrameClockSetFreezeCallback (FrameClock *, void (*) (void *),
|
extern void XLFrameClockSetFreezeCallback (FrameClock *, void (*) (void *),
|
||||||
void *);
|
void *);
|
||||||
extern uint64_t XLFrameClockGetFrameTime (FrameClock *);
|
extern uint64_t XLFrameClockGetFrameTime (FrameClock *);
|
||||||
|
extern void XLFrameClockNoteConfigure (FrameClock *);
|
||||||
extern void *XLAddCursorClockCallback (void (*) (void *, struct timespec),
|
extern void *XLAddCursorClockCallback (void (*) (void *, struct timespec),
|
||||||
void *);
|
void *);
|
||||||
extern void XLStopCursorClockCallback (void *);
|
extern void XLStopCursorClockCallback (void *);
|
||||||
|
|
|
@ -109,6 +109,11 @@ struct _FrameClock
|
||||||
/* The delay between the start of vblank and the redraw point. */
|
/* The delay between the start of vblank and the redraw point. */
|
||||||
uint32_t frame_delay;
|
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
|
/* Whether or not configury is in progress, and whether or not this
|
||||||
is frozen, and whether or not the frame shouldn't actually be
|
is frozen, and whether or not the frame shouldn't actually be
|
||||||
unfrozen until EndFrame. */
|
unfrozen until EndFrame. */
|
||||||
|
@ -239,18 +244,31 @@ HandleEndFrame (Timer *timer, void *data, struct timespec time)
|
||||||
EndFrame (clock);
|
EndFrame (clock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Forward declaration. */
|
/* Forward declarations. */
|
||||||
|
|
||||||
static void RunFrameCallbacks (FrameClock *);
|
static void RunFrameCallbacks (FrameClock *);
|
||||||
|
static Bool StartFrame (FrameClock *, Bool, Bool);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
FreezeForValue (FrameClock *clock, uint64_t counter_value)
|
FreezeForValue (FrameClock *clock, uint64_t counter_value)
|
||||||
{
|
{
|
||||||
|
Bool need_empty_frame;
|
||||||
|
|
||||||
/* If it took too long (1 second at 60fps) to obtain the counter
|
/* 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. */
|
value, and said value is now out of date, don't do anything. */
|
||||||
|
|
||||||
if (clock->next_frame_id > counter_value)
|
if (clock->next_frame_id > counter_value)
|
||||||
return;
|
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
|
/* The frame clock is now frozen, and we will have to wait for a
|
||||||
client to ack_configure and then commit something. */
|
client to ack_configure and then commit something. */
|
||||||
|
|
||||||
|
@ -278,7 +296,20 @@ FreezeForValue (FrameClock *clock, uint64_t counter_value)
|
||||||
clock->in_frame = False;
|
clock->in_frame = False;
|
||||||
clock->need_configure = True;
|
clock->need_configure = True;
|
||||||
clock->configure_id = counter_value;
|
clock->configure_id = counter_value;
|
||||||
clock->frozen = True;
|
|
||||||
|
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
|
static void
|
||||||
|
@ -408,6 +439,10 @@ StartFrame (FrameClock *clock, Bool urgent, Bool predict)
|
||||||
{
|
{
|
||||||
clock->next_frame_id = clock->configure_id;
|
clock->next_frame_id = clock->configure_id;
|
||||||
clock->finished_frame_id = 0;
|
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;
|
clock->in_frame = True;
|
||||||
|
@ -700,6 +735,11 @@ XLFrameClockHandleFrameEvent (FrameClock *clock, XEvent *event)
|
||||||
if (value % 2)
|
if (value % 2)
|
||||||
value += 1;
|
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
|
/* If a frame is in progress, postpone this frame
|
||||||
synchronization message. */
|
synchronization message. */
|
||||||
if (clock->in_frame && !clock->end_frame_called)
|
if (clock->in_frame && !clock->end_frame_called)
|
||||||
|
@ -861,6 +901,13 @@ XLFrameClockGetFrameTime (FrameClock *clock)
|
||||||
return clock->last_frame_time;
|
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. */
|
/* Cursor animation clock-related functions. */
|
||||||
|
|
||||||
|
|
|
@ -804,7 +804,6 @@ SwapBackBuffers (PictureTarget *target, pixman_region32_t *damage)
|
||||||
if (!present_serial)
|
if (!present_serial)
|
||||||
present_serial++;
|
present_serial++;
|
||||||
|
|
||||||
/* TODO: handle completion correctly. */
|
|
||||||
XPresentPixmap (compositor.display, target->window,
|
XPresentPixmap (compositor.display, target->window,
|
||||||
back_buffer->pixmap, present_serial,
|
back_buffer->pixmap, present_serial,
|
||||||
None, region, 0, 0, None, None, fence,
|
None, region, 0, 0, None, None, fence,
|
||||||
|
|
|
@ -1064,6 +1064,11 @@ NoteConfigure (XdgRole *role, XEvent *event)
|
||||||
event->xconfigure.y);
|
event->xconfigure.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Tell the frame clock how many WM-generated configure events have
|
||||||
|
arrived. */
|
||||||
|
XLFrameClockNoteConfigure (role->clock);
|
||||||
|
|
||||||
|
/* Run reconstrain callbacks. */
|
||||||
RunReconstrainCallbacksForXEvent (role, event);
|
RunReconstrainCallbacksForXEvent (role, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1956,6 +1961,10 @@ XLXdgRoleReconstrain (Role *role, XEvent *event)
|
||||||
|
|
||||||
xdg_role = XdgRoleFromRole (role);
|
xdg_role = XdgRoleFromRole (role);
|
||||||
RunReconstrainCallbacksForXEvent (xdg_role, event);
|
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
|
void
|
||||||
|
|
|
@ -1660,6 +1660,8 @@ NoteWindowResized (Role *role, XdgRoleImplementation *impl,
|
||||||
|
|
||||||
if (event.xconfigure.send_event)
|
if (event.xconfigure.send_event)
|
||||||
XLXdgRoleNoteConfigure (toplevel->role, &event);
|
XLXdgRoleNoteConfigure (toplevel->role, &event);
|
||||||
|
else
|
||||||
|
XLXdgRoleReconstrain (toplevel->role, &event);
|
||||||
|
|
||||||
RecordStateSize (toplevel);
|
RecordStateSize (toplevel);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue