[comp.sys.next] DPS buffer swapping animation

pts@mendel.acc.Virginia.EDU (Paul T. Shannon) (12/04/90)

I received such helpful responses to my last question about Display
Postscript that I now ask another.  

A common animation technique (used by SGI gl, for instance) is to draw
to a hidden buffer, and then to issue a 'swapbuffers' command which
displays the previously hidden buffer after the next vertical retrace.
This allows for an entire, possibly complex image to appear on the
screen at once, rather than serially as its parts on drawn.  

I've had some excellent suggestions about the NeXT's blit chip, and
the program /usr/bin/blit (used by /etc/rc at boot), and a promising
portable bit map program from William Lewis.  But before I dig into
these, does anyone know of buffer swapping techniques in DPS?  My
books and manuals didn't help.   Though it's a choice some may question,
I'm doing this work without the appkit, in order to get the greatest
possible control of timing during animation.

 - Paul Shannon
   pts@virginia.edu

scott@NIC.GAC.EDU (Scott Hess) (12/05/90)

In article <1990Dec4.141356.6065@murdoch.acc.Virginia.EDU> pts@mendel.acc.Virginia.EDU (Paul T. Shannon) writes:
   A common animation technique (used by SGI gl, for instance) is to draw
   to a hidden buffer, and then to issue a 'swapbuffers' command which
   displays the previously hidden buffer after the next vertical retrace.
   This allows for an entire, possibly complex image to appear on the
   screen at once, rather than serially as its parts on drawn.

This _might_ be trivial.  Depends on what you want . . .

Within DPS on the NeXT, there are three types of buffering for windows:
Nonretained, Retained, and Buffered.  Nonretained is like most generic
X windows in that you have to respond to exposed events and redraw
things.  The only data ever stored from draws is data which actually
appears in the video buffer.  As such, Nonretained is by far the fastest
mode, though (IMHO) quite ugly, especially when animating something.

Buffered windows are sort of like double-buffering.  You draw into
an off-screen area, which is then flushed to the screen via
flushgraphics (in DPS) or flushWindow (in appkit - invokes
flushgraphics) call.  This means that you can draw and draw and draw,
and nothing appears until you tell it to flush.  The windowserver is
smart enough to only update portions which need it (ie, redrawn,
visible portions).  With Buffered windows, the programmer need not
worry about redrawing newly-exposed areas of the window, the window
server just redraws out of the buffer.  This type of window is
also provided in X, but many servers do not implement it.

In between these types are Retained windows.  Retained windows
retain that area of the window which is not visible in buffers,
while drawing visible areas directly to the screen.  This
(hopefully) gives the speed advantages of Nonretained, while giving
the conveinience of Buffered (not receiving and handling expose
events).  Retained windows aren't all that great for animation,
either, though you sometimes need it for speed.

Under NextStep2.0, there is supposed to be a call which will
change a window from Buffered to Retained, and vice verse.  This
is supposedly used heavily in such objects as Text and ScrollView
to speed up scrolling operations.  That's why you can now see the
redraw occuring when you use page-scrolls in ScrollViews and the
like.

Heck.  I'm almost there, so I'll give some hints for using these
varying types of windows . . .

Many UI objects expect to be in Buffered windows.  For instance,
Scrollbars (and thus ScrollView).  I'm sure there are "hidden"
dependancies in others, too.  The best way to find out is to
watch the postscript output (run program with -NXShowPS),
though many people cannot follow that (takes some work).

Why would you care?  Well, say you have a UI object which expects
to be in a Buffered window.  That means that when it redraws,
it will send off a flushWindow to its window.  So, if you
do some drawing, which might modify that object in it's course,
you can end up getting inadvertant flushWindow calls, thus revealing
areas which you didn't want the user to see.  I had lots of this
type of problem when optimizing Stuart's output, since I use
Scrollbars and Buffered windows . . .

Another point that's important with Buffered windows is that the
windowserver keeps a simple rectangle which describes the modified
portion of the bitmap.  So, it is in your best interest to know where
that rectangle is, and to think out output beforehand.  For instance,
if you have a large window (say, 600x600), and draw something in
each of the four corners, it might be much faster to follow each
corner's drawing with a flushWindow, so that only a couple small
rectangle are flushed, rather than one huge on.  Of course, that
may defeat the purpose (say, if all the corners must change
simultaneously), but you get the idea.

   I've had some excellent suggestions about the NeXT's blit chip, and

???  I don't think NeXT _has_ a blit chip!  If they do, I want to know
more . . .

   the program /usr/bin/blit (used by /etc/rc at boot), and a promising

I very much doubt that program will help.  I believe that it runs
outside of the appkit, which means that few (if any) programs
can use it.  Besides the fact that it is undocumented . . .

   portable bit map program from William Lewis.  But before I dig into
   these, does anyone know of buffer swapping techniques in DPS?  My
   books and manuals didn't help.   Though it's a choice some may question,
   I'm doing this work without the appkit, in order to get the greatest
   possible control of timing during animation.

Well, without the appkit?  What are you doing it in, then?  Direct
DPS programming?  This can be done in the appkit just fine.  As long
as you keep the windowserver around, you should do alright with
using Buffered windows.  I suspect, though, that you could do
whatever it is within the appkit.  If it turns out that you really
cannot, you are using the wrong machine.

If you _really_ want full control, you might want to try writing your
program to run as loginhook for the loginwindow.  This would allow
you to dispense with almost everything.  Disconnect the network,
and you need not worry about mail or anything messing you up.
Of course, that's not that useful without two machines and nfs,
who wants to keep loggin out and back in . . . .

Then again, if you are this worried about speed, talk to NeXT.
Depending on your time frame, a NextDimension might be what you need.
One possibility is to pre-draw all the animation frames and let JPEG
magic take care of speed.  Also, the 32-bit deep windows also
are supposed to have a mode in which you can treat them as 2 16-bit
deep buffers, and do standard dual-page animation with them.  The
i860 should remove alot of the concerns about speed, as long as
you don't run too many programs at a time.  Of course, you have to
wait for this . . .

scott hess
scott@gac.edu
Independent NeXT Developer	(Stuart)
GAC Undergrad			(Horrid.  Simply Horrid.  I mean the work!)
<I still speak for nobody>