Re: [gtk-list] Re: gdk_draw_* and friends



Once upon a (long) time, Owen Taylor wrote:

> Antonio Campos <acampos@ceronet.com> writes:
>
> > Owen Taylor wrote:
> >
> > > Dan Kressin <dkressin@gb.frontiernet.net> writes:
> > >
> > > > Antonio Campos wrote:
> > > > >
> > > > > Digging randomly through the gdk.h include file, I stopped at
> > > > > gdk_draw_* functions. I noticed the functions:
> > > > [snip]
> > > > > and of course:
> > > > > gdk_draw_rectangle             (*)
> > > > > gdk_draw_arc                        (*)
> > > > >
> > > > > Then, I realized than X has more drawing functions...
> > > > > I issued an "apropos", and XDrawRectangles, XDrawArcs appeared.
> > > > >
> > > > > Then I thought why shouldn't gdk wrap these two X drawing functions as
> > > > > well.
> > > > > If I'm correct, these two functions are used to send the X Server a
> > > > > bunch of rectangles or arcs, which is a very useful thing because the X
> > > > > Server may communicate with the clients through a network.
> > > > >
> > > > > So, wouldn't be nice to add two more functions to gdk?
> > > >
> > > > They do, in fact, save on network traffic over multiple *Arc or
> > > > *Rectangle calls.
> > >
> > > Yes for Arc, no for Rectangle. (Look at the implementation
> > > of XDrawRectangle if you don't believe me. Xlib is smart
> > > enough to batch up multiple consecutive DrawRectangle
> > > requests.)
> > >
> >
> > But when the XDrawRectangles function is there, there must be a reason to use
> > it.
>
> Hmmm, I could point to quite a few functions in GTK+ that there
> is no reason to use. Xlib is not immune from the same thing.
> XDrawRectangles might be convenient if you wanted to, say, draw
> the same set of rectangles over and over again, but the question
> is trading off convenience for complexity.
>
> > At least the XDrawRectangles avoids invoking a lot of XDrawRectangle calls. So
> > even with a local X server, it could be faster.
>
> Yes it _could_ be faster, but without benchmarks...
>
> > > > I actually wrote and submitted the code to implement
> > > > the plural versions of those functions back in the early days of the 1.1
> > > > series, but I guess it never got accepted by the powers that be.  Not
> > > > entirely sure why.
> > > >
> > > > Owen?  I think you were the one that told me how to submit the code via
> > > > ftp, any idea why it was never included?
> > >
> > > I believe at the same time, I asked for benchmarks proving that
> > > there is a significant gain (E.g., "I can draw 50,000 arcs a second
> > > using XDrawArcs, but only 20,000 a second using XDrawArc".)
> > > Maybe you did send such benchmarks and I just missed them...
> > >
> > > I'm rather hesitant to complicate the drawing interfaces in
> > > GDK (for 1.3, this is a VTable that every Drawable implementation
> > > must implement and must also be supported on every platform)
> > > more than necesary.
> > >
> >
> > I don't think that adding two functions and two types (gdkarc and
> > gdkrectangle) to GDK is complicating too much the drawing interface.
> > Besides this, then why do we need gdk_draw_points, gdk_draw_lines or
> > gdk_draw_segments?. Following you, one simply could call a lot of
> > gdk_draw_point, ...
>
> Well, from my perspective the existing functions are there because
> they are there when I took over GDK. It probably has something
> to do with what functions Peter needed for the GIMP. And he
> may or may not have been aware of the batching characteristics
> of Xlib. Drawing many points lines and segments is most likely
> more common than drawing many rectangles or arcs, certainly.
>
> > I think that the API is more rationale if every drawing primitive for point,
> > line, segment, rectangle, arc has his plural counterpart.
>
> Well, that is an argument that is convinces me a bit. But then,
> by logical extensions we'd want gdk_draw_polygons, gdk_draw_strings,
> gdk_draw_pixmaps...
>
> > An even is more rationale to avoid the filled argument for gdk_draw_rectangle
> > and gdk_draw_arc, because that should come from the graphics context passed as
> > argument to the function. (Maybe this was made because Win32 graphics contexts
> > don't have this filled argument?
>
> Xlib doesn't have the filled argument in the GC either. It uses separate
> requests for filled and unfilled rectangles.
>
> . I don't know, but anyway we have a wrapper
> > to GCs, the GDK graphics contexts. So I don't understand the problem).
> > Even you may say that the plural versions weren't added to GDK because Win32
> > or other platforms where gdk could be ported don't support a function like
> > XDrawRectangles or XDrawArcs. Well, in this case, gdk_draw_rectangles (for
> > that versions) could simply call gdk_draw_rectangle in a loop.
>
> No, the fact that they aren't natively supported on a different platform
> wasn't my objection. But I'd like to evaluate future additions to
> GDK based on "do they make sense as part of a cross-platform API for
> drawing and windowing systems", not "does Xlib have them".
>
> > To sum up, I don't see the problem to add these two functions, and I don't
> > think these could make the API much more fatter. At the contrary, I think
> > these functions could make the drawings faster (I don't know how much faster,
> > but even if the were a little faster, they should be useful).
>
> I don't consider "a little faster" an argument for API additions,
> especially for uncommon operations (and how often do people
> draw large groups of arcs or rectangles -- almost never, really)
>
> The arguments for adding such things for the API are:
>
>  - They make operations possible that were not otherwise possible
>
>  - They make common operations more convenient
>
>  - They are a really big performance win (for uncommon operations,
>    that probably means factor of at least 2)
>
>  - They make things more consistent (e.g., we added in the
>    reset of the GdkFunction  modes, though they are  mostly
>    completely useless.
>
> The first two being more important than the second two.
>
> Arguments against adding things to the GDK API:
>
>  - They only make sense on one platform (not necessarily a fatal
>    argument by itself against adding features, but they possibly should
>    be in a platform-specific header, or the user should just use
>    the native API
>
>  - They increase the size and complexity of the API
>
>  - They make things less consistent
>
> I haven't made a final decision on this point. But I hope the
> above explains my thinking on such an issue a bit more.
>
> Regards,
>                                         Owen
>
> --
> To unsubscribe: mail -s unsubscribe gtk-list-request@redhat.com < /dev/null

Well, I tried to do some benchmarks with the attached program (I hope it's not
wrong), and surprisingly it thrown out the following results on a Pentium 233 MMX
on SVGA/S3 Server:

Starting GDK single argcs test
time with GDK for drawing single arcs: 5.94557 secs
Starting X single argcs test
time with X for drawing single arcs: 5.94776 secs
Starting GDK single rectangles test
time with GDK for drawing single rectangles: 7.02543 secs
Starting X single rectangles test
time with X for drawing single rectangles: 7.02569 secs
Starting X multiple arcs test
time with X for drawing multiple arcs: 5.95786 secs

As we can see, drawing multiple arcs (that is, arranging them into an array and
sending them in a single call to the X Server) is even slower than drawing them one
by one.!!!
It seems to me that the Server is clever enough to handle single calls for drawing
single arcs very fast.

What is more, I repeated the test on a Pentium 166 MMX with the X Banshee Server
reachable through a 10 MBits Ethernet card on a Pentium II 350 Mhz, and it thrown:

Starting GDK single argcs test
time with GDK for drawing single arcs: 6.01995 secs
Starting X single argcs test
time with X for drawing single arcs: 6.02037 secs
Starting GDK single rectangles test
time with GDK for drawing single rectangles: 7.01755 secs
Starting X single rectangles test
time with X for drawing single rectangles: 7.01946 secs
Starting X multiple arcs test
time with X for drawing multiple arcs: 6.02676 secs

Again, drawing multiple arcs with a single call was a little slower that drawing
them one by one.
Surprising!!!

So, now I think that adding gdk_draw_rectangles and gdk_draw_arcs may have no use
indeed.
What does elseone think?
#include <gtk/gtk.h>
#include <gdk/gdkprivate.h>
#include <sys/time.h>
#include <unistd.h>
#include <stdio.h>

#define ITERATIONS		1000

gint exposure(GtkWidget *widget,GdkEventExpose *event)
{
  GdkPixmap *pixmap=(GdkPixmap *) gtk_object_get_user_data(GTK_OBJECT(widget));

  gdk_draw_pixmap(widget->window,
		  widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
		  pixmap,
		  0,0,
		  0,0,
		  640,480);		  		
  return FALSE;
}

int main( int   argc, 
          char *argv[] )
{
  GtkWidget *window;
  GtkWidget *drawing_area;
  GdkPixmap *pixmap;

  gtk_init (&argc, &argv);

  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  gtk_window_set_title (GTK_WINDOW(window), "Drawing Velocity Test");

  gtk_signal_connect (GTK_OBJECT (window), "destroy",
		      GTK_SIGNAL_FUNC (gtk_main_quit), NULL);

  drawing_area = gtk_drawing_area_new ();
  gtk_drawing_area_size (GTK_DRAWING_AREA (drawing_area), 640, 480);
  gtk_container_add(GTK_CONTAINER(window),drawing_area);

//  gtk_widget_set_usize(GTK_WIDGET(window),640,480);

  gtk_widget_set_events(GTK_WIDGET(drawing_area),GDK_EXPOSURE_MASK);

  gtk_signal_connect(GTK_OBJECT(drawing_area),"expose_event",GTK_SIGNAL_FUNC(exposure),NULL);

  gtk_widget_realize(drawing_area);		

  pixmap = gdk_pixmap_new(drawing_area->window,640,480,-1);		

  gtk_object_set_user_data(GTK_OBJECT(drawing_area),(gpointer) pixmap);

  gdk_draw_rectangle(pixmap,
  		     window->style->white_gc,
  		     TRUE,  //filled
  		     0,0,
  		     640,480);

  {  		       	
    struct timeval told,tnew;
    struct timezone tz;
    GdkWindowPrivate *drawable_private=(GdkWindowPrivate*) pixmap;
    GdkGCPrivate *gc_private= (GdkGCPrivate*) window->style->black_gc;
    XArc arcs[ITERATIONS];
    int i;

    // Single argcs test
    fprintf(stderr,"Starting GDK single argcs test\n");
    gdk_flush();
    gettimeofday(&told,&tz);
    for (i=0; i<ITERATIONS; i++)	
      gdk_draw_arc(pixmap,
   	           window->style->black_gc,
  	           TRUE, //filled
  	           0,0,
 	           640,480,
  	           0,360*64);
    gdk_flush();
    gettimeofday(&tnew,&tz);
    fprintf(stderr,"time with GDK for drawing single arcs: %.5f secs\n",tnew.tv_sec+tnew.tv_usec/(float) 1e6-told.tv_sec-told.tv_usec/(float) 1e6);

    fprintf(stderr,"Starting X single argcs test\n");
    XSync(drawable_private->xdisplay,True);
    gettimeofday(&told,&tz);

    for (i=0; i<ITERATIONS; i++)
      XFillArc (drawable_private->xdisplay, drawable_private->xwindow,
	        gc_private->xgc, 0, 0, 640, 480, 0, 360*64);

    XSync(drawable_private->xdisplay,True);
    gettimeofday(&tnew,&tz);
    fprintf(stderr,"time with X for drawing single arcs: %.5f secs\n",tnew.tv_sec+tnew.tv_usec/(float) 1e6-told.tv_sec-told.tv_usec/(float) 1e6);	

    //Single rectangles test
    fprintf(stderr,"Starting GDK single rectangles test\n");
    gdk_flush();
    gettimeofday(&told,&tz);
    for (i=0; i<ITERATIONS; i++)	
      gdk_draw_rectangle(pixmap,
   	           window->style->black_gc,
  	           TRUE, //filled
  	           0,0,
 	           640,480);
    gdk_flush();
    gettimeofday(&tnew,&tz);
    fprintf(stderr,"time with GDK for drawing single rectangles: %.5f secs\n",tnew.tv_sec+tnew.tv_usec/(float) 1e6-told.tv_sec-told.tv_usec/(float) 1e6);

    fprintf(stderr,"Starting X single rectangles test\n");
    XSync(drawable_private->xdisplay,True);
    gettimeofday(&told,&tz);

    for (i=0; i<ITERATIONS; i++)
      XFillRectangle (drawable_private->xdisplay, drawable_private->xwindow,
	              gc_private->xgc, 0, 0, 640, 480);

    XSync(drawable_private->xdisplay,True);
    gettimeofday(&tnew,&tz);
    fprintf(stderr,"time with X for drawing single rectangles: %.5f secs\n",tnew.tv_sec+tnew.tv_usec/(float) 1e6-told.tv_sec-told.tv_usec/(float) 1e6);

    // X Multiple arcs test
    fprintf(stderr,"Starting X multiple arcs test\n");

    for (i=0; i<ITERATIONS; i++)
    {
      arcs[i].x=0;
      arcs[i].y=0;
      arcs[i].width=640;
      arcs[i].height=480;
      arcs[i].angle1=0;
      arcs[i].angle2=360*64;
    }

    XSync(drawable_private->xdisplay,True);
    gettimeofday(&told,&tz);

    XFillArcs (drawable_private->xdisplay, drawable_private->xwindow,
	        gc_private->xgc, arcs, ITERATIONS);

    XSync(drawable_private->xdisplay,True);
    gettimeofday(&tnew,&tz);
    fprintf(stderr,"time with X for drawing multiple arcs: %.5f secs\n",tnew.tv_sec+tnew.tv_usec/(float) 1e6-told.tv_sec-told.tv_usec/(float) 1e6);	
  }  	
		
  gtk_widget_show_all (window);

  gtk_main ();

  return 0;
}
/* example-end */


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