Re: paint clock



Hi,

On Sat, Oct 2, 2010 at 8:57 PM, Matthias Clasen
<matthias clasen gmail com> wrote:
> If we move to a fixed order of doing things each frame, like Owen
> described here:
> http://blog.fishsoup.net/2009/05/28/frames-not-idles/

A link I obviously should have included, thank you

>, then the paint
> clock could perhaps just have those before/after hooks as signals (as
> you already have for paint). If we make animation, input handling and
> relayouting a fixed part of the frame cycle, then it is not really a
> 'paint' clock anymore.

Right. Well I was thinking relayout and update-tweens could maybe be
done just by connecting to the before-paint signal in the
GdkPaintClock. But maybe it's better to have specific signals for
relayout and update animations. Among other things that would put them
in a deterministic sequence. (and relayout definitely has to be last)

Maybe "master" clock or "frame" clock would be better names. I don't
think "paint" is wrong (it _is_ all driven off of repainting, tying
everything else to repaint is the point) but clearest name I don't
know.

Also I hadn't really thought about special-casing X event processing,
even though it's the obvious thing to do since Clutter does it, litl
shell does it, and Owen discusses it. litl shell also takes a crack at
the motion event stuff (though we do it by always using motion hint
mask and then doing QueryPointer on each frame if we got a motion,
rather than by discarding all but latest event per frame). We just
discard the QueryPointer reply, though perhaps it would be better to
use it to synthesize a motion event if no actual motion event appeared
for the frame.

One issue is what to do about "other" stuff (not X events, not
resizing, not tweening animations, and not painting)

litl shell runs the other stuff for at least 1 mainloop iteration per
frame, plus more iterations until we've spent 5ms. 1 iteration per
frame of course means all highest (usually default) priority stuff is
guaranteed to dispatch once, so one event or one message or one read()
off an incoming fd or whatever, per source.

Clutter runs the master clock mainloop source as a high idle, so I
believe they would allow any default-priority stuff to starve repaint,
but would never run idles during an animation.
litl shell is happy to run an idle within the 5ms window, but will
stop running default-priority stuff (more than one iteration anyway)
if we exceed 5ms. Not sure the details matter that much here as long
as you have enough performance headroom to be pretty reliably hitting
your target framerate.

GDK's current repaint handler is a high idle also, same idea as
Clutter I guess. GDK then has X events at normal priority so it is
always dispatching all events prior to any repainting.

Looks like gdbus and gio's GSimpleAsyncResult use default priority, so
loading files or talking to other apps are by default treated as
equivalent to X events. It's possible these things should really be at
idle priority, but it sort of depends on the use-case.

I kind of like the idea of limiting "doing stuff" to a fixed time
window before we force a repaint. Having the paint clock main loop
source use a "popping priority" where it does g_source_set_priority on
itself on the fly may actually work I think - gmain.c doesn't seem to
say you can't do that. ;-)

I don't really like the idea of starving non-painting (even idles)
completely just because there's some cheesy animation somewhere in the
frame. Just doesn't seem probable anyone ever wants this. I also don't
really like the idea of starving repainting completely just because
there's a bunch of IO or IPC going on. So in short to me the priority
system doesn't seem expressive enough unless something dynamically
changes its priority. What's wanted is that we give other stuff
priority for "a few ms" and then we force painting to be top priority.

It seems like current GDK and Clutter imply that very little should
ever use default priority, because delaying repaint for more than a
few ms is just fundamentally not OK in most GUI apps. And even if your
default-priority thing is relatively fast, at some point in a big app
you have N default-priority things, and the paint loop has no ability
to limit how many times it dispatches the default priority stuff.
(With GMainLoop there's no way at all to avoid dispatching
all-or-nothing at a given priority, but at least if you have 30
default-priority things, you can dispatch the 30 only once instead of
however long it takes for all 30 to be unready. I think even better
might be to be able to dispatch one GSource at a time and then break
out of dispatch, but who knows what wild implications that has.)

As a practical matter, of course, a GSource dispatch is free to take
100ms to do its thing, and so we're doing cooperative multitasking
here; and if performance just fundamentally isn't keeping up, then
things get hosed no matter how scheduling is done.

But it'd be nice to avoid "accidental total catastrophe." We had a bug
in litl shell (an older version without the same paint loop) where the
loading spinner made downloads slow down incredibly, because we were
very slowly dispatching non-paint main loop sources. But then we've
also had the reverse bug. It's difficult to manage and maybe the
toolkit can just sort it out.

Was kind of thinking phase 1 could just use a thing like
GdkPaintClockIdle in this patch that pretty much keeps current GTK
behavior, and lets you plug in better behavior. But phase 2 "actually
fix default GTK clock" is pretty worthy as well.

> Does it make sense to set a paint clock on anything but a toplevel window ?

What I was thinking was that if you say had a Clutter stage embed
widget in part of the window, and some menus and stuff around that,
then the menus and stuff would use the regular GTK clock and the
clutter embed would use the clutter-style GL-based clock. In this
scenario the window is not double-buffered as a whole anyway.

One hypothesis is that you want one paint clock per "thing that can
swap its backing store onto the actual screen" whether it's a
traditional double-buffered GdkWindow or a GL area. Possibly this
means one paint clock per _native_ window, at least on X11? I toyed
with sticking ensure_native into set_paint_clock but basically I
wasn't sure whether it was necessary (this was my question about "does
it work to have a separate paint clock on a client-side window")

> Also, if you tie relayouting to the clock as well, does it make sense
> to have different clocks on the different windows in the widget
> hierarchy ?

But yeah, good point, this is messy. (Though I _guess_ GtkContainer
already allows some subhierarchies to have their own resize idle...
but not sure I understand that fully)

It also gets messy to have multiple clocks for any reason if any of
those clocks are doing blocking (on vsync) buffer swaps, it seems
like. Not sure how that's even solvable other than "don't use blocking
buffer swaps."

Clearly a lot of open questions here... I do think it's important,
though. Basically I don't think current GTK can do smooth animations.
(Except through hacks, like forcing process_updates regularly before
GTK can get to its idles.) I'd expect this is true of clutter-gtk also
since it lets GTK take over the repaint idle.

Havoc


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