Re: Doubts about GPeriodic



On Thu, 2010-10-21 at 11:46 +0200, Ryan Lortie wrote:
> Hi Owen,
> 
> A few questions, if you don't mind me picking your brain:
> 
> On Wed, 2010-10-20 at 14:58 -0400, Owen Taylor wrote:
> > The real problem is that the phases of the repaint cycle matter. We
> > don't just have a bunch of stuff we need to do every frame, we need to
> > do things in the order:
> > 
> >  * Process events
> 
> The only benefit I see to processing input events at the start of a
> frame cycle is that we possibly get to merge them.  We probably do want
> that.

Compressing events to the frame isn't some sort of "oh, that sounds a
bit cool" thing. It's vastly better than any other approach I know of
and fixes problems that have been in GTK+ for a long time. For example,
the explicit calls to gdk_window_process_updates() you'll find in a lot
of GTK+ scrolling widgets are workarounds for lack of proper event
compression.

> What about non-input events, though?  Like, if some download is
> happening and packets are coming in and causing dispatches from the
> mainloop that we do not have control over.
> 
> Do we try to ensure that those people treat this 'external stimulus' in
> the same way that we treat events (ie: possibly merge multiple incoming
> packets so that they update their UI state only once in response to it)
> or do we want them to just call the GTK API on the spot and risk
> duplicated work because that's quite a lot easier to understand?
> 
> Maybe we should have some mechanism that allows them to choose.

We shouldn't generalize when there is one case that is 90% of the
problem and that has a better solution than you can provide generally.

Mouse events are special because:

 - The user can very easily see things lagging behind the mouse pointer
 - Mouse events flood in and *do* cause lag in many programs
 - Pointer motion events are inherently compressible in almost every
   circumstance... it simply doesn't matter if the mouse moves more than
   once per painted frame (the only exception is a paint program, you
   may want some sort of history API to get compressed events.)

Yes, you can have compressible network events or whatever; and so there
does need to be be an easy way to schedule things to happen once before
relayout/repaint. Once you have a paint clock, g_idle_add() doesn't for
work for compression.

See MetaLaterAdd:
 
 http://git.gnome.org/browse/mutter/tree/src/core/util.c#n801

For the API we are using in gnome-shell. (Maybe you could do it with adding a
"tick" function, but the important thing is being able to do it during
event processing and happen *this* frame. And that it's convenient.)

> >  * Update animations
> 
> "tick"

Note that this has to happen *after* event processing.

> >  * Update layout
> 
> Clutter and GDK want to do two different things here, it seems.
> Presently (and almost by chance) GPeriodic is emitting a "tick" signal
> after running all of the tick functions and Emmanuele is using this to
> run "stage updates" on all of the Clutter stages.  This is a little bit
> like Gtk managing it's geometry but not exactly.
> 
> In Gtk's case, we have a chance to do this a bit more programmatically -
> only run layout adjustments on widgets/windows that have been marked as
> requiring some resize (ie: toplevels and containers with
> GTK_RESIZE_QUEUE themselves).  That could be handled from a 'tick'
> handler, or we could add some more hooks to GPeriodic.

I don't think it works to just talk about handling stuff from *a* tick
handler. Order matters, you can't just add a bunch of tick handlers and
hope they get run in the right order.

> A reason that I think it makes sense to do layout updates separate from
> repainting is that layout updates can result in us wanting to change the
> size of our toplevels (eg: someone opened GtkExpander).

Sure, that's a reason that GTK+ doesn't look like Clutter exactly.

> This is a *really* tough problem because if that happens, we can't just
> paint.  We have to wait until the window manager has actually given us
> our new size.  I did some benchmarking, and that tends not to happen
> until about 1ms later (a bit less for metacity, a bit more for compiz
> and mutter).

Have you looked at how it works in GtkWindow currently? GTK+ computes
the new size, and requests a new size from the window manager, but
doesn't actually allocate children and *freezes updates* on the toplevel
(gdk_window_freeze_toplevel_updates_libgtk_only) until the configure
response is received.

> So do we block the mainloop for ~1-2ms and desperately suck from the X
> socket until we receive ConfigureNotify (at least until some timeout)?

No, you cannot block synchronously for the window manager to handle your
ConfigureRequest. Don't go there.

> Do we skip drawing the window and wait until next frame if we have a
> pending ConfigureNotify?

You draw the next frame *when* you get the ConfigureNotify.

>   Is there some way we can abuse
> _NET_WM_SYNC_REQUEST to make this problem easier?

There's been some work to try and figure out how, for *override
redirect* windows to display a single frame for resize and repaint.

http://www.mail-archive.com/wm-spec-list gnome org/msg00694.html

(Using that URL since the thread goes across several months, which
you wouldn't see on mail.gnome.org)

If that was followed up on, I think it might work for redirected
toplevels as well. So you get an atomic display of the new window size
that the window manager allocates the window to and the contents ofr the
size. But that's just display. It doesn't change the fact that you have
to ask the window manager for the new size, you can't assume that the
window manager will give you the new size, and you can't redraw until
the window manager does resize you.

> On the Gtk experiment branch, layout updates are actually done pretty
> much "on the spot" right now (ie: you make some changes to the layout
> which will queue a idle that will run pretty much immediately).  There
> have been no changes to this part yet.

That sounds like a change to me. GTK+ always repaints the window
immediately after layout. If that's no longer happening then you can get
many layouts for a repaint. If you are forcing a repaint at a high
priority every 1/60th of a second, then you won't starve paints, it will
just be inefficient.

[discussion of GPeriodic and additional phases snipped]

> For timeline advancement, however (ie: the stuff that the user wants to
> do) I think an abstraction like GPeriodic is quite useful.  It gives a
> common place that users can register their animation hooks that works
> the same way for both Clutter and Gtk.  It prevents us from having some
> timeline system within Gtk that is clocked by Clutter telling Gtk "run
> all your timelines now!".  Cody is creating a timeline class right now
> as part of his experimenting, and I could easily see that we might want
> that in GIO alongside GPeriodic.

Makes some sense. I think it's only a good idea though if it ends up
being convenient enough that it can be used directly rather than people
having to wrap it up. Something like GHookList which is half of an API 
tends to be a bad idea.

Whether you have one clock per toplevel or one clock per process needs
to be resolved, since it has a big effect on how people actually use the
API.

> That seems like a bit of a weird fit, of course, but we long-ago decided
> that libgio was intentionally destined to become libkitchen-sink.  Also,
> the smooth changing of a variable over time is not necessarily related
> to animation or graphics, and people could easily want to create their
> own GPeriodic.

One thing you should definitely keep in mind is that if you keep all the
terminology in GPeriodic generic because it might have some
non-graphical usage later, you likely will make it much harder to use.

- Owen




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