Modernizing the display loop [try 2]



My current large-scale project is to get proper coordination between the
application and window system for timing; part of this is defining a
protocol between application/toolkit and compositor - see:

https://mail.gnome.org/archives/wm-spec-list/2011-October/msg00006.html

but to make it work for GTK+, we also have to update how GTK+ works
internally.

Window Clocks
==============

My basic idea is to have a "Window Clock" object that serves as the
central point of timing coordination for each toplevel window.

 /* Get the singleton window clock for a toplevel window */
 GdkWindowClock *gdk_window_get_clock (GdkWindow *window);

The window clock object has two signals:

 ::layout
 ::draw

With corresponding methods:

 gdk_window_clock_queue_layout (GdkWindowClock *clock);
 gdk_window_clock_queue_draw   (GdkWindowClock *clock);

It also has can have any number of "clock targets" objects added to it:

 void gdk_window_clock_add    (GdkWindowClock *clock,
                               GdkClockTarget *target);
 void gdk_window_clock_remove (GdkWindowClock *clock,
                               GdkClockTarget *target);

GdkClockTarget is a simple interface:

 struct _GdkClockTargetClass {
     GTypeInterface base_iface;

     void (*update) (GdkClockTarget  target,
                     GdkWindowClock *clock);
 };

When there is at least one clock target added, the clock is "on", and
whenever it's time to draw a frame, each clock is updated.

[ 

Alternative: do it with functions:

 guint gdk_window_clock_add   (GdkWindowClock *clock,
                               GdkUpdateFunc   func,
                               gpointer        data,
                               GDestroyNotify  notify);
 void gdk_window_clock_remove (guint           id);

]

The other thing we might want to do here is add in the ability to
get the time for a clock - say:

 guint64 gdk_window_clock_get_time()

which would return a monotonically increasing time for the clock
(in microseconds?) The advantages of this are:

 - We could define the time to behave correctly with regard to
   suspend/resume, etc. (The caller could just call
   g_get_monotonic_time() if we didn't provide functionality)

 - We have the option of adjusting the time to be something other
   than the current time - like the predicted display time for the
   frame.

Event compression
=================

One of the most interesting things that we were able to do for Clutter
when we made it strictly frame-based is frame-based motion event
compression.

There's quite a bit of juggling in GTK+ to handle not building up
motion 
vents and lagging - we use  GDK_POINTER_MOTION_HINT_MASK in a lot of
places
- with the issues that drags in -  and we call
gdk_window_process_updates()
in various places to avoid problems with scrolling in response to mouse
events getting ahead of other redrawing.

The almost-always-right approach for motion events once you have
a frame-cycle is to just store motion events, and right before you do
the frame update process the last one and drop the other events.

The exception to "almost-always-right" is when someone is painting
with motion events - in that case you want the ability to have
have a full history instead of a jagged one.

I'm not quite sure how to introduce this into GTK+ compatibly, two
ideas:

 - We could just deliver "jagged" events, and say that if you 
   want smooth events you need to call the existing
   gdk_device_get_history() - because that function is there, we
   presumably at least have the concept that you may not get
   every event normally.

 - We could add a 'more_events' flag to GdkEventMotion - which is
   set if there will be more events coming; and say that almost
   everyone should ignore events with this flag set.

Cross-platform issues
=====================

I spent some time looking at what windowing system capabilities we'd
want to hook this into on Windows and the Mac. It seemed like on the
Mac, you might want to hook this up to CVDisplayLink:

http://developer.apple.com/library/mac/#documentation/QuartzCore/Reference/CVDisplayLinkRef/Reference/reference.html

On Windows (Vista, 7), the Desktop Window Manager APIs allow querying
for information about how the screen is being updated:

http://msdn.microsoft.com/en-us/library/windows/desktop/aa969514%
28v=vs.85%29.aspx

But don't obviously have any sort of ability to get callbacks or to
block until time to render a frame. Windows 7 adds "Windows Animation"
where you can create timer objects with callbacks
(http://msdn.microsoft.com/en-us/library/windows/desktop/dd371981%
28v=VS.85%29.aspx)
but it seems this is just straight up timers, and doesn't give VBlank
synchronization.

In any case  general feeling is that the public API above is general
enough
so that we should be able to put it on top of almost any backend, once
we figure out how to do it correctly for a platform.

- Owen





[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]