Re: To Draw | ! To Draw in an Expose Handler



On Fri, 2007-11-30 at 10:38 +0100, Richard Boaz wrote:
> splitting this out into its own thread...
> 
>     >
>     >   2) option 2 is simply impossible to make a one-to-one calculation
> as to
>     > which pixels must be refreshed, programmatically.
> 
>     for many (perhaps even for an overwhelming majority of applications (2)
>     works just fine. if you application can't do this cheaply, then your
>     approach is the right way.
> 
> Sorry, I can't think of a single application responsible for making its
> own drawings by hand where option 2 is not crazy hard.  (If anybody has an
> example of this in real-world application, please post?)

http://ardour.org/ ... of course, a monster app like this has no "expose
handler" .. it has dozens of expose handlers for various custom widgets.
consider the ruler widgets we use (GtkCustomerRuler). this stores all
the data about the rulers in data structures; in the expose event, it
computes where to draw the lines/tick marks/labels for the ruler and
then does it. we *have* to do this, since the "full length" of the ruler
is potentially millions of pixels wide (or more). we cannot possibly
store a precomputed version of it (though caching of parts of it would
be possible).

however, more or less all GTK widgets work in the way i have described.
they also often use the clipping mask feature of a GDK GC to avoid
drawing where they should not (frequently implicitly).

> (Paul, would you be willing to take the scribble code from gtk-demo and do
> this, including any user additions?  Surely for such a trivial example of
> drawing option 2 should be easy?)

sorry, i wouldn't be willing to do anything right now, at the end of a
70 hour week with an impending similar weekend as i get ready for a
major expansion of ardour's user community next week.

> Taking my very simple example of two lines at the midpoints and two
> diagonals corner to corner, taking option 2 makes our expose handler:
> 
> gboolean exposeME(GtkWidget *da, GdkEventExpose *event, gpointer *nil)
> {
>  int w = da->allocation.width;
>  int h = da->allocation.height;
>  GdkGC *gc = da->style->fg_gc[GTK_WIDGET_STATE(widget)]
> 
>  if (event->width == w && event->height = h)
>  { // draw entire area
>    gdk_draw_line(da->window, gc, w/2, 0, w/2, h);  // vertical
>    gdk_draw_line(da->window, gc, 0, h/2, w, h/2);  // horizontal
>    gdk_draw_line(da->window, gc, 0, 0, w, h);      // diagonal
>    gdk_draw_line(da->window, gc, 0, h, w, 0);      // diagonal
>  }
>  else
>  { // only a partial invalidation
>    // figure out what drawing commands to issue according
>    // to event->x, event->y, event->width, and event->height
>    // (for every combination possibility)
>    // not so hard for our mid-point lines, but for the diagonals?
>    // INSANE!
> 
>    // don't forget to include any user additions
>  }
>  return TRUE;
> }
> 
> This solution will cost us:
>   1) programming time to manage all possibilities and debug, with no real
> guarantee that it will work everywhere all the time.
>   2) extra CPU usage to make all computations to determine what should be
> redrawn.
>   3) extra CPU usage to re-draw what was already once drawn.

not necessarily. thats for two reasons:

    1) drawing extra pixels has its own costs, especially if the pixmap
is large (cache thrashing issues)
    2) GDK drawing routines will be looking at the GC clip mask anyway.
in your case its unset, but if it was set to the expose region(s) then
you would get the years of optimization that have gone into your "else"
case *inside* GDK/X11/Quartz/win32 etc. if you set the clip mask, you
can draw "arbitrarily" and only the correct sections will actual be
blitted to the screen.

As a footnote, although the pixmap is accessed on most systems directly
via shared memory, a pixmap is a server side object. if you want to do
this kind of thing very quickly, you'd be better offer drawing to a
pixbuf, then flushing the pixbuf to the window in expose. pixbufs are
client side objects, and thus cheaper to access.

> (And in the case where the entire drawing area is obscured and re-exposed,
> we have to draw the whole thing all over again!)
> 
> And you're saying that, for some reason I still don't quite understand,
> the above is proper GTK+ programming while the following is not?:

i'm not saying that its not "proper". for a particular class of
application, its definitely appropriate. but you were suggesting that
its the right way for almost all apps, and i was just pointing out that
this has performance costs and is often not the right way to handle
drawing.

your model makes sense when computing and doing the drawing is
complicated and expensive. there are clearly many apps that have this
issue. "my" model makes sense when computing and doing the drawing is
cheap. there are also many apps that have this model too. its what is
happening in any application that has no "image" widgets, for example. 
in addition, there is a variant of your model that falls between the
cracks - cases where the "drawing" simply involves blitting pre-computed
or pre-loaded data to the screen because it never changes. in such
cases, a modern GTK2 app would store this in a pixbuf and draw it to the
window in the expose handler. is this "your" method or "mine"? clearly,
it doesn't matter much.




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