abrash-black-book/45-06.md
2013-12-30 20:26:41 +11:00

118 lines
6 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

The 640x400 mode I've described here isn't exactly earthshaking, but it
can come in handy for page flipping and CGA emulation, and I'm sure that
some of you will find it useful at one time or another.
### Another Interesting Twist on Page Flipping {#Heading9}
I've spent a fair amount of time exploring various ways to do animation.
I thought I had pegged all the possible ways to do animation:
exclusive-ORing; simply drawing and erasing objects; drawing objects
with a blank fringe to erase them at their old locations as they're
drawn; page flipping; and, finally, drawing to local memory and copying
the dirty (modified) rectangles to the screen, as I've discussed in this
chapter.
To my surprise, someone threw me an interesting and useful twist on
animation not long ago, which turned out to be a cross between page
flipping and dirty-rectangle animation. That someone was Serge Mathieu
of Concepteva Inc., in Rosemere, Quebec, who informed me that he designs
everything "from a game *point de vue*."
In normal page flipping, you display one page while you update the other
page. Then you display the new page while you update the other. This
works fine, but the need to keep two pages current can make for a lot of
bookkeeping and possibly extra drawing, especially in applications where
only some of the objects are redrawn each time.
Serge didn't care to do all that bookkeeping in his animation
applications, so he came up with the following approach, which I've
reworded, amplified, and slightly modified in the summary here:
**1.**  Set the start address to display page 0.
**2.**  Draw to page 1.
**3.**  Set the start address to display page 1 (the newly drawn page),
then wait for the leading edge of vertical sync, at which point the page
has flipped and it's safe to modify page 0.
**4.**  Copy, via the latches, from page 1 to page 0 the areas that
changed from the previous screen to the current one.
**5.**  Set the start address to display page 0, which is now identical
to page 1, then wait for the leading edge of vertical sync, at which
point the page has flipped and it's safe to modify page 1.
**6.**  Go to step 2.
The great benefit of Serge's approach is that the only page that is ever
actually drawn to (as opposed to being block-copied to) is page 1. Only
one page needs to be maintained, and the complications of maintaining
two separate pages vanish entirely. The performance of Serge's approach
may be better or worse than standard page flipping, depending on whether
a lot of extra work is required to maintain two pages or not. My guess
is that Serge's approach will usually be slower, owing to the
considerable amount of display-memory copying involved, and also to the
double page-flip per frame. There's no doubt, however, that Serge's
approach is simpler, and the resultant display quality is every bit as
good as standard page flipping. Given page flipping's fair degree of
complication, this approach is a valuable tool, especially for
less-experienced animation programmers.
An interesting variation on Serge's approach doesn't page flip nor wait
for vertical sync:
**1.**  Set the start address to display page 0.
**2.**  Draw to page 1.
**3.**  Copy, via the latches, the areas that changed from the last
screen to the current one from page 1 to page 0.
**4.**  Go to step 2.
This approach totally eliminates page flipping, which can consume a
great deal of time. The downside is that images may shear for one frame
if they're only partially copied when the raster beam reaches them. This
approach is basically a standard dirty-rectangle approach, except that
the drawing buffer is stored in display memory, rather than in system
memory. Whether this technique is faster than drawing to system memory
depends on whether the benefit you get from the VGA's hardware, such as
the Bit Mask, the ALUs, and especially the latches (for copying the
dirty rectangles) is sufficient to outweigh the extra display-memory
accesses involved in drawing and copying, since display memory is
notoriously slow.
Finally, I'd like to point out that in any scheme that involves changing
the display-memory start address, a clever trick can potentially reduce
the time spent waiting for pages to flip. Normally, it's necessary to
wait for display enable to be active, then set the two start address
registers, and finally wait for vertical sync to be active, so that you
know the new start address has taken effect. The start-address registers
must never be set around the time vertical sync is active (the new start
address is accepted at either the start or end of vertical sync on the
EGAs and VGAs I'm familiar with), because it would then be possible to
load a half-changed start address (one register loaded, the other not
yet loaded), and the screen would jump for a frame. Avoiding this
condition is the motivation for waiting for display enable, because
display enable is active only when vertical sync is not active and will
not become active for a long while.
Suppose, however, that you arrange your page start addresses so that
they both have a low-byte value of 0 (page 0 starts at 0000H, and page 1
starts at 8000H, for example). Page flipping can then be done simply by
setting the new high byte of the start address, then waiting for the
leading edge of vertical sync. This eliminates the need to wait for
display enable (the two bytes of the start address can never be
mismatched); page flipping will often involve less waiting, because
display enable becomes inactive long before vertical sync becomes
active. Using the above approach reclaims all the time between the end
of display enable and the start of vertical sync for doing useful work.
(The steps I've given for Serge's animation approach assume that the
single-byte approach is in use; that's why display enable is never
waited for.)
In the next chapter, I'll return to the original dirty-rectangle
algorithm presented in this chapter, and goose it a little with some
assembly, so that we can see what dirty-rectangle animation is really
made of. (Probably not dog hair....)