GNOME Bugzilla – Bug 685460
Add frame synchronization to GTK+
Last modified: 2013-12-05 21:54:35 UTC
I'm filing these patches on a bug for review that way for those who prefer - they are also in the wip/frame-synchronization branch in git.
Created attachment 225739 [details] [review] GdkDisplayX11: Don't use substructure events in internal accounting We may receive events because SubstructureNotifyMask has been selected for the root window. (Most likely, this would occur because GTK+ is being used inside a window manager like Metacity or Mutter.) This can confuse various types of internal accounting, so detect such events and comprehensively ignore them for GDK's internal purposes. We still need to generate GDK events for these cases because you can select for substructure events with GDK_SUBSTRUCTURE_MASK.
Created attachment 225740 [details] [review] Add GdkPaintClock Add an object GdkPaintClock that we associate with a GdkWindow. This tracks when the window needs to be repainted, and will also be used for other operations in the future like relayout and updating animations. Based on a patch from Havoc Pennington: https://mail.gnome.org/archives/gtk-devel-list/2010-October/msg00004.html
Created attachment 225741 [details] [review] Use GdkPaintClock for relayout Add a ::layout signal to GdkPaintClock and use it instead of an idle handler to drive the restyling and relayout of containers.
Created attachment 225742 [details] [review] GdkPaintClock: Make the phase explicit when requesting the frame Instead of having gdk_paint_clock_request_frame() have gdk_paint_clock_request_phase() where we can say what phase we need. This allows us to know if we get a frame-request during layout whether it's just a request for drawing from the layout, or whether another layout phase is needed.
Created attachment 225743 [details] [review] GdkPaintClock: add freeze/thaw Add the ability to freeze a paint clock, which pauses its operation, then thaw it again later to resume. Initially this is used to implement freezing updates when we are waiting for ConfigureNotify in response to changing the size of a toplevel. We need a per-window clock for this to work properly, so add that for the X11 backend.
Created attachment 225744 [details] [review] Switch to an extended form of _NET_WM_SYNC_REQUEST_COUNTER By exporting two XSync counters on a toplevel window, we subscribe to an extended form of the _NET_WM_SYNC_REQUEST_COUNTER protocol, where the window manager can initiate an atomic frame, as previously, but the application can also do so by incrementing the new counter to an odd value, and then to an even value to finish the frame. See: https://mail.gnome.org/archives/wm-spec-list/2011-October/msg00006.html The support for 64-bit integers that GLib requires is used to simplify the logic.
Created attachment 225745 [details] [review] Use _NET_WM_FRAME_DRAWN to synchronize frame drawing As part of the extended _NET_WM_SYNC_REQUEST_COUNTER protocol, we get a _NET_WM_FRAME_DRAWN message for each frame we draw. Use this to synchronize the updates we are doing with the compositing manager's drawing, and ultimately with with display refresh. We now set the sync request counters on all windows, including override-redirect windows, since it is also useful to do synchronized, atomic updates for such windows.
Created attachment 225746 [details] [review] Freeze the update counter for unmapped windows When a window is unmapped, freeze its paint clock. This avoids doing unnecessary work, but also means that we won't block waiting for _NET_WM_FRAME_DRAWN messages that will never be received since the frame ended while the window was withdrawn.
Created attachment 225747 [details] [review] GdkWindowX11: start off with an odd frame-counter value By starting with an odd frame counter value, we make the mapping and initial paint of the window an atomic operation, avoiding any visual artifacts from an unpainted window. Possible improvement: start the frame when doing gdk_window_show(), so that the same improvement occurs for windows that were previously shown and are being mapped again.
Created attachment 225748 [details] [review] GdkPaintClockIdle: add throttling to 60fps If the backend is throttling paints, then the paint clock will be frozen at the end of the frame. If not, then we need to add throttling, so wait until 16ms after the start of the frame before beginning the next frame.
Created attachment 225749 [details] [review] Add an UPDATE phase and GdkPaintClockTarget, use for GtkStyleContext Switch GtkStyleContext to using GdkPaintClock. To do this, add a new UPDATE phase to GdkPaintClock. Add a GdkPaintClockTarget interface with a single set_clock() method, and use this to deal with the fact that GtkWidget only has a paint clock when realized.
Created attachment 225750 [details] [review] Add back GtkTimeline Add back the GtkTimeline code that previously made private and then removed. It will be hooked up to GdkPaintClock. This commit purely adds the old code back.
Created attachment 225751 [details] [review] GtkTimeline: remove settable FPS The frames-per-second for an animation should be controlled by how fast we can process frames and the the frame-rate of the display; it's not a meaningful app-settable property.
Created attachment 225752 [details] [review] Hook GtkTimeline up to GdkPaintClock Use GdkPaintClock for the timing of GtkTimeline. This require the user to provide either a GtkWidget or a GdkPaintClock when creating the timeline. The default constructor now takes a GtkWidget. If you want to create a GdkPaintClock without a widget, you need to use g_object_new() and pass in a GdkPaintClock and GdkScreen.
Created attachment 225753 [details] [review] GtkTimeline: introspection fixes, add :progress-type property Fix up introspection information for GtkTimeline, install the header has a public heaer, and add the property for :progress-type.
Created attachment 225754 [details] [review] GtkTimeline: Wrap around the progress correctly when looping When we have a looping animation for something like an angle, we need to make sure that the distance we go past 1.0 becomes the starting distance for the next frame. This prevents a stutter at the loop position.
Created attachment 225755 [details] [review] Add a test of an animated resizing window Add a test of a window with an animated size and contents. The test accepts load factor command line argument to see how things work as the drawing of the content requires more GPU resources.
Created attachment 225756 [details] [review] GtkScrolledWindow: use GdkPaintClock for kinetic scrolling Use GdkPaintClock when animating scrolling via touch, rather than a timeout.
Created attachment 225757 [details] [review] Compress motion synchronized with the paint cycle When we have pending motion events, instead of delivering them directly, request the new FLUSH_EVENTS phase of the paint clock. This allows us to compress repeated motion events sent to the same window. In the FLUSH_EVENTS phase, which occur at priority GDK_PRIORITY_EVENTS + 1, we deliver any pending motion events then turn off event delivery until the end of the next frame. Turning off event delivery means that we'll reliably paint the compressed motion events even if more have arrived. Add a motion-compression test case which demonstrates behavior when an application takes too long handle motion events. It is unusable without this patch but behaves fine with the patch.
(In reply to comment #19) > Created an attachment (id=225757) [details] [review] > Compress motion synchronized with the paint cycle This patch might bring in subtle issues with multipointer, probably event compression must be maintained per gdk_event_get_device() there
I believe this should be closed, since we've gotten it all merged for 3.8
this change causes trouble for painting/drawing apps, see Bug 702392