On Thu, 2010-10-21 at 08:17 -0400, Havoc Pennington wrote: > Hi, > > On Thu, Oct 21, 2010 at 5:46 AM, Ryan Lortie <de...@desrt.ca> wrote: > > > > 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. > > I brought this up a bit in the earlier thread. > > My takeaway is that for I/O type stuff you usually want what we ended > up with at litl, which is to limit it to some length of time per > frame. Unfortunately GMainLoop has no native way to do that. I > described our solution a bit in the old paint clock thread. > > There's a danger both of some random download starving animation and > of your download spinner starving the download.
I think to start off we have to realize that a GTK+ application is significantly different from a compositor like Mutter or the litl shell in a number of ways: * GTK+ is quite efficient when just a small amount of stuff is changing. Even if the entire toplevel takes a long time to paint, a cheesy animation somewhere in the frame isn't going to cause all the time to be spent painting. * GTK+ is not going to be using a blocking glSwapBuffers(); GTK+ will be timing frames either based on a straight-up timer, or by getting frame-complete signals back from the compositor. * It's not the compositor - if painting blocks, it's not the end of the world. Once we move beyond that, then I'm skeptical about lumping everything that's not events/animation/relayout/repaint into the same bucket. "Everything else" includes a number of different things: * UI updates being done in response to asynchronous IO finishing In this case, I think usually you just want to do the updates immediately; for most UI updates the real expense is the relayout/ repaint, so there's no advantage to trickling them in... if you get such a bunch of updates that you block for a couple hundred ms, then you just accept a small stutter. If that might be a couple of seconds, then I think it's up to the app author to figure out how to fix the situation - if updates can be batched and batching reduces the work that needs to be done, then an easy to use "before relayout" API is handy. * Computations being done in idle chunks because "threads are evil". If the computations don't affect the GUI, then in my mind they should just happen in whatever time isn't needed to draw whatever is going on. We have no way of knowing whether whatever is going on is a spinner or is a video playing. In other words, progress displays need to be self-limiting to eat only a small amount of CPU. After all, it's pretty bad if my computation is going on at *half*-speed because of the progress spinner! * Servicing incoming IPC calls Assuming incoming calls queue up, I think it's fine to just handle them at higher priority than the repaint. The pathological case here is that Totem is playing a movie which is maxing out the frame rate, and somebody in another process does sync calls: for (movie in allMovies) movie.length = totemProxy.getPlayingTime(movie.id); And Totem handles one call, then paints a frame, then handles another call and the whole thing takes forever. This is clearly bad, but I don't think the solution is for totem to reserve 5ms for ever frame of every movie just because someone might start using the D-Bus API it exports. Solutions here are general solutions: - Don't put "service" API's in the GUI thread of GUI applications - Use async calls - if the above was done by making a bunch of async calls in parallel, it would be completed in one frame. * Expensive GUI work done incrementally (adding thousands of items to a GtkTreeView, say) Threads not useful because GTK+ isn't thread-safe. This one is slightly harder because each update can actually trigger a relayout/repaint, which might be expensive. So if this is being done at idle priority, you may be in the situation of do one chunk, which takes 0.1ms, repaint for 20ms, do another chunk, and so forth. This is the case where something like your proposal of reserving time per frame starts making sense to me. But rather than just doing a blanket reservation of 5ms per frame, it seems better to actually let the master clock know what's going on. To have an API where you add a function and the master clock balances calling it with relayout. That a) avoids wasting time waiting for nothing to happen b) allows better handling of the case where the relayout takes 100ms not 20ms so you don't work for 5ms, relayout for 100ms, repeat. - Owen _______________________________________________ gtk-devel-list mailing list gtk-devel-list@gnome.org http://mail.gnome.org/mailman/listinfo/gtk-devel-list