CLIM mail archive

[Prev][Next][Index][Thread]

Incremental Redisplay Performance



    Date: Mon, 2 Mar 1992 21:33 EST
    From: will taylor <taylor@charon.arc.nasa.gov>
	
    A typical redisplay using this technique takes less than a second, while the default
    redisplay took about 8 seconds (for a 50 node graph).

    This experience reinforces my hope that CLIM 2.0's implementation and documentation
    will place more emphasis on incremental redisplay performance -- with the default 
    redisplay functionality my UI was just about unusable.  With my modificaitons the 
    UI demonstrates the advertised claims of CLIM.

***New message.  I made a mistake in the code I supplied.  Sorry.***

This reply is just meant to provide a few more bits of information.
Please don't think that I am in any way trying to defend the terrible
performance of CLIM's incremental redisplay.

In general, any output record might overlap with some other output
record.  Therefore, when deciding what to redraw, CLIM must check to
make sure that there are no "erased" output records that overlap any
output records that have not changed.  Due to the representation of
output record coordinates (which are maintained relative to the
coordinates of their parent), this augmentation of the "draw" set runs
in O(m*n*d) time, where m is the number of output records in the
entire tree, n is the number of output records in the erase set, and d
is the depth of the tree.  By changing the representation of output
record coordinates, this algorithm could be reduced to O(m*n), but at
the cost of slowing a few other less common operations down.

So the :CHECK-OVERLAPPING argument was added to REDISPLAY is to tell
incremental redisplay whether or not it should check for overlapping
sibling output records.  As you observed, in some cases, inhibiting
this check can cause a dramatic performance improvement - it replaces
an O(m*n*d) algorithm (or O(m*n) in the best case) with *nothing*.
You can get away with this because you yourself know that nothing
overlaps anything else.  Unfortunately, CLIM does not know this and
cannot make the same judgment.

I confess that I agonized over what the default value for CHECK-OVERLAPPING
should be.  On the one hand, if I had made it be NIL, some cases of
incremental redisplay would simply not behave correctly, and the
programmer would have no way of knowing why it did not work.  On the
other hand, having decided to make the default be T, sometimes
incremental redisplay is much too slow.  One thing that is clear is that
there should be a way to specify the value of CHECK-OVERLAPPING for
incrementally redisplayed panes.

Here is a kludgy patch that implements it.  I have not tested this in
CLIM 1.0, just in CLIM 1.1.  Use :INCREMENTAL-REDISPLAY '(T :CHECK-OVERLAPPING NIL)
in your pane.

--------
(defun redisplay-frame-pane-internal (frame pane description &optional force-p)
  (let* ((options (pane-descriptor-options description))
	 (display-function (getf options :display-function))
	 (ir (getf options :incremental-redisplay))
	 (redisplay-p (if (listp ir) (first ir) ir))
	 (check-overlapping (or (atom ir)	;default is T
				(getf (rest ir) :check-overlapping t)))
	 (redisplay-record
	   (and redisplay-p
		(let ((history (output-recording-stream-output-record pane)))
		  (when history
		    #+compulsive-redisplay
		    (when (> (output-record-element-count history) 1)
		      (cerror "Clear the output history and proceed"
			      "Why is there more than one element in this redisplay pane?")
		      (window-clear pane))
		    (unless (zerop (output-record-element-count history))
		      (output-record-element history 0)))))))
    ;; We're trying to get bits on the screen.
    (cond ((dummy-pane-p pane)
	   ;; Give everyone a chance to update the title bar
	   (when (eql (pane-descriptor-type description) :title)
	     (display-title frame pane)))
	  (t
	   (when *frame-layout-changing-p*
	     (setq force-p t))
	   (unless *sizing-application-frame*
	     (unless (member pane (slot-value frame 'initialized-panes))
	       (setq force-p t)
	       (push pane (slot-value frame 'initialized-panes))))
	   (with-simple-restart (nil "Skip redisplaying pane ~S" pane)
	     (loop
	       (with-simple-restart (nil "Retry displaying pane ~S" pane)
		 (return
		   (cond (display-function
			  ;; If there's a display function, call it to generate new contents.
			  (cond (redisplay-p
				 (cond ((or (null redisplay-record) force-p)
					(when force-p
					  (window-clear pane))
					(call-redisplay-function
					  display-function frame pane))
				       (t (redisplay redisplay-record pane
						     :check-overlapping check-overlapping))))
				((or force-p
				     (getf options :display-after-commands t))
				 (unless (and (not force-p)
					      (eq (getf options :display-after-commands)
						  ':no-clear))
				   (window-clear pane))
				 (call-display-function display-function frame pane)))
			  (force-output pane))
			 (force-p
			  ;; If refilling from scratch, give the application a chance
			  ;; to draw stuff
			  (frame-replay frame pane))
			 ;; Otherwise do nothing, the bits will still be on display
			 ;; and will be refreshed properly if there's a damage event.
			 )))))))))


Follow-Ups: References:

Main Index | Thread Index