Re: please keep those gdk draw- functions

Espen S Johnsen <[email protected]> 02 Nov 2007 14:13:35 +0100
Newsgroups gmane.lisp.clg.devel
Message-ID <[email protected]>
Chisheng Huang <[email protected]> writes:

> The following comment is from gdk/gdk.lisp:
> 
> ;;; Drawable -- all the draw- functions are deprecated and will be
> ;;; removed, use cairo for drawing instead.
> 
> I'd like to plea to keep the support of these draw- functions in
> GDK as long as they are officially supported.  The index of deprecated
> symbols of GDK Reference Manual only listed 4 drawing functions:
> gdk_draw_pixmap, gdk_draw_string, gdk_draw_text, and gdk_draw_text_wc.

Keeping those function would be no problem. 

> Cairo is nice but is just too slow for statistical graphics.
> To draw 25,000 circles, GDK:DRAW-ARC takes 0.07 seconds and Cairo
> takes 6.01 seconds.  Timing code is attached at the end.

Cairo could definitely have been faster, but it isn't to bad either. I
am using it to render vector maps, which is a quite demanding task.
Among the techniques I use to achieve sufficient performance is doing
as much clipping and polygon simplification as possible in the Lisp code
and reducing the number of calls to stroke and fill. When rendering
curves one may also speed up things by setting the tolerance to a higher
value than default.

I am also rendering to offscreen buffers which are reused on subsequent
expose events and scaled/moved around to give the user the impression
of better performance.

Although I haven't done any real benchmarking, my impression is
that the performance is comparable to similar commercial available
systems. 

To see if it was possible to speed up the circle drawing code, I've did
a few test. The code and timings is included below. As you can see the
final version used 

Even if this still is more than 10 times longer time than the Gdk
version and without knowing how representative this test is for the
final application and what what would be acceptable rendering time, I
would have reconsidered using Cario. It has a much nicer API than the
Gdk drawing functions, the same code can be used to draw on screen and
to create Postscript/PDF output and the antialiased output is superior.

> this version of CAIRO-CIRCLES will kill CMUCL immediately when the length
> of CENTERS is 3000 or bigger.

I have also experienced this on some machines while on others it works
as expected, which has lead me to believe that it is a X server problem.
For this reason I am calling stroke for every 500th circle in the code below.


(defparameter *centers* (loop repeat 50000 collect (+ 10.0d0 (random 280))))

(defun cairo-circles-1 (da centers)
  (declare (optimize (speed 3) (safety 1)))  
  (write-line "Cairo, original")
  (gdk:with-cairo-context (cr (gtk:widget-window da))
    (setf (cairo:line-width cr) 1.0)
    (loop
       with 2pi = (* 2.0d0 pi)
       for (x y) on centers by #'cddr do
       (cairo:fast-arc cr x y 5.0d0 00d0 2pi)
       (cairo:close-path cr)
       (cairo:stroke cr))))

(defun cairo-circles-2 (da centers)
  (declare (optimize (speed 3) (safety 1)))  
  (write-line "Cairo, stroke every 500")
  (gdk:with-cairo-context (cr (gtk:widget-window da))
    (setf (cairo:line-width cr) 1.0)
    (loop
       with 2pi = (* 2.0d0 pi)
       for n from 0
       for (x y) on centers by #'cddr do
         (cairo:new-sub-path cr)
         (cairo:fast-arc cr x y 5.0d0 00d0 2pi)
         (cairo:close-path cr)
         (when (zerop (mod n 500))
           (cairo:stroke cr)))
    (cairo:stroke cr)))

(defun cairo-circles-3 (da centers)
  (declare (optimize (speed 3) (safety 1)))  
  (write-line "Cairo, stroke every 500, tolerance 1.0")
  (gdk:with-cairo-context (cr (gtk:widget-window da))
    (setf (cairo:tolerance cr) 1.0)
    (setf (cairo:line-width cr) 1.0)
    (loop
       with 2pi = (* 2.0d0 pi)
       for n from 0
       for (x y) on centers by #'cddr do
         (cairo:fast-arc cr x y 5.0d0 00d0 2pi)
         (cairo:close-path cr)
         (cairo:new-sub-path cr)
         (when (zerop (mod  n 500))
           (cairo:stroke cr)))
    (cairo:stroke cr)))

(defun circle-approximation (cr x0 y0 radius edges)
  (declare (double-float x0 y0 radius) (fixnum edges))
  (declare (optimize (speed 3) (safety 1)))
  (cairo:new-sub-path cr)
  (let ((delta (/ (* 2 pi) edges)))
    (declare (double-float delta))
    (loop
       for i from 0 below edges do 
       (let ((x (+ x0 (* radius (sin (* (+ 0.5 i) delta)))))
             (y (- y0 (* radius (cos (* (+ 0.5 i) delta))))))
         (cairo:fast-line-to cr x y))))
  (cairo:close-path cr))

(defun cairo-circles-4 (da centers)
  (declare (optimize (speed 3) (safety 1)))  
  (write-line "Cairo, circle approximation with 8 edges")
  (gdk:with-cairo-context (cr (gtk:widget-window da))
    (setf (cairo:line-width cr) 1.0)
    (loop
       for (x y) on centers by #'cddr do
         (circle-approximation cr x y 5.0d0 8)
         (cairo:stroke cr))))

(defun cairo-circles-5 (da centers)
  (declare (optimize (speed 3) (safety 1)))  
  (write-line "Cairo, circle approximation with 8 edges, stroke every 500")
  (gdk:with-cairo-context (cr (gtk:widget-window da))
    (setf (cairo:line-width cr) 1.0)
    (loop
       for n from 0
       for (x y) on centers by #'cddr do
         (circle-approximation cr x y 5.0d0 8)
         (when (zerop (mod n 500))
           (cairo:stroke cr)))
    (cairo:stroke cr)))

(defun test-all ()
  (test-circles 'gdk-circles)
  (test-circles 'cairo-circles-1)
  (test-circles 'cairo-circles-2)
  (test-circles 'cairo-circles-3)
  (test-circles 'cairo-circles-4)
  (test-circles 'cairo-circles-5)


* (test-all)
Cairo, original
Evaluation took:
  5.421 seconds of real time
  5.28833 seconds of user run time
  0.092006 seconds of system run time
  0 calls to %EVAL
  0 page faults and
  36,816 bytes consed.
Cairo, stroke every 500
Evaluation took:
  4.479 seconds of real time
  4.344272 seconds of user run time
  0.072004 seconds of system run time
  0 calls to %EVAL
  0 page faults and
  39,840 bytes consed.
Cairo, stroke every 500, tolerance 1.0
Evaluation took:
  2.323 seconds of real time
  2.200137 seconds of user run time
  0.044003 seconds of system run time
  0 calls to %EVAL
  0 page faults and
  35,968 bytes consed.
Cairo, circle approximation with 8 edges
Evaluation took:
  2.007 seconds of real time
  0.860053 seconds of user run time
  0.024002 seconds of system run time
  0 calls to %EVAL
  0 page faults and
  39,808 bytes consed.
Cairo, circle approximation with 8 edges, stroke every 500
Evaluation took:
  1.084 seconds of real time
  0.352022 seconds of user run time
  0.028001 seconds of system run time
  0 calls to %EVAL
  0 page faults and
  36,720 bytes consed.


-- 
Espen

-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >> http://get.splunk.com/