diff --git a/compositor.h b/compositor.h index bea4905..075e1af 100644 --- a/compositor.h +++ b/compositor.h @@ -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 *); diff --git a/frame_clock.c b/frame_clock.c index 00a8723..a693fe1 100644 --- a/frame_clock.c +++ b/frame_clock.c @@ -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; - 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 @@ -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. */ diff --git a/picture_renderer.c b/picture_renderer.c index 2a8a3f5..1e0f6d4 100644 --- a/picture_renderer.c +++ b/picture_renderer.c @@ -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, diff --git a/xdg_surface.c b/xdg_surface.c index 1ffdcb9..cd5c1af 100644 --- a/xdg_surface.c +++ b/xdg_surface.c @@ -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 diff --git a/xdg_toplevel.c b/xdg_toplevel.c index f640367..5b513a3 100644 --- a/xdg_toplevel.c +++ b/xdg_toplevel.c @@ -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); }