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

124 lines
7.2 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.

#### Knowing When to Flip {#Heading8 align="center"}
There's a hitch, though, and that hitch is knowing exactly when it is
that the page has flipped. The page doesn't flip the instant that you
set the Start Address registers. The VGA loads the starting offset from
the Start Address registers once before starting each frame, then pays
those registers no nevermind until the next frame comes around. This
means that you can set the Start Address registers whenever you want—but
the page actually being displayed doesn't change until after the VGA
loads that new offset in preparation for the next frame.
The potential problem should be obvious. Suppose that page 1 is being
displayed, and you're updating page 0. You finish drawing to page 0, set
the Start Address registers to 0 to switch to displaying page 0, and
start updating page 1, which is no longer displayed. Or is it? If the
VGA was in the middle of the current frame, displaying page 1, when you
set the Start Address registers, then page 1 is going to be displayed
for the rest of the frame, no matter what you do with the Start Address
registers. If you start updating page 1 right away, any changes you make
may well show up on the screen, because page 0 hasn't yet flipped to
being displayed in place of page 1—and that defeats the whole purpose of
page flipping.
To avoid this problem, it is mandatory that you wait until you're sure
the page has flipped. The Start Address registers are, according to my
tests, loaded at the start of the Vertical Sync signal, although that
may not be the case with all VGA clones. The Vertical Sync status is
provided as bit 3 of the Input Status 1 register, so it would seem that
all you need to do to flip a page is set the new Start Address
registers, wait for the start of the Vertical Sync pulse that indicates
that the page has flipped, and be on your merry way.
Almost—but not quite. (Do I hear teeth gnashing in the background?) The
problem is this: Suppose that, by coincidence, you set one of the Start
Address registers just before the start of Vertical Sync, and the other
right after the start of Vertical Sync. Why, then, for one frame the
Start Address High value for one page would be mixed with the Start
Address Low value for the other page, and, depending on the start
address values, the whole screen could appear to shift any number of
pixels for a single, horrible frame. *This must never happen!* The
solution is to set the Start Address registers when you're certain
Vertical Sync is not about to start. The easiest way to know that is to
check for the Display Enable status (bit 0 of the Input Status 1
register) being active; that means that bitmap-controlled pixels are
being scanned onto the screen, and, since Vertical Sync happens in the
middle of the vertical non-display portion of the frame, Vertical Sync
can never be anywhere nearby if Display Enable is active. (Note that one
good alternative is to set up both pages with a start address that's a
multiple of 256, and just change the Start Address High register and
wait for Vertical Sync, with no Display Enable wait required.)
So, to flip pages, you must complete all drawing to the non-displayed
page, wait for Display Enable to be active, set the new start address,
and wait for Vertical Sync to be active. At that point, you can be fully
confident that the page that you just flipped off the screen is not
displayed and can safely (invisibly) be updated. A side benefit of page
flipping is that your program will automatically have a constant time
base, with the rate at which new screens are drawn synchronized to the
frame rate of the display (typically 60 or 70 Hz). However, complex
updates may take more than one frame to complete, especially on slower
processors; this can be compensated for by maintaining a count of new
screens drawn and cross-referencing that to the BIOS timer count
periodically, accelerating the overall pace of the animation (moving
farther each time and the like) if updates are happening too slowly.
#### Enter the Split Screen {#Heading9}
So far, I've discussed page flipping in 640x350 mode. There's a reason
for that: 640x350 is the highest-resolution standard mode in which
there's enough display memory for two full pages on a standard VGA. It's
possible to program the VGA to a non-standard 640x400 mode and still
have two full pages, but that's pretty much the limit. One 640x480 page
takes 38,400 bytes of display memory, and clearly there isn't enough
room in 64 K of display memory for two of *those* monster pages.
And yet, 640x480 is a wonderful mode in many ways. It offers a 1:1
aspect ratio (square pixels), and it provides by far the best resolution
of any 16-color mode. Surely there's *some* way to bring the visual
appeal of page flipping to this mode?
Surely there is—but it's an odd solution indeed. The VGA has a feature,
known as the *split screen,* that allows you to force the offset from
which the VGA fetches video data back to 0 after any desired scan line.
For example, you can program the VGA to scan through display memory as
usual until it finishes scan line number 338, and then get the first
byte of information for scan line number 339 from offset 0 in display
memory.
That, in turn, allows us to divvy up display memory into three areas, as
shown in Figure 44.2. The area from 0 to 11,279 is reserved for the
split screen, the area from 11,280 to 38,399 is used for page 0, and the
area from 38,400 to 65,519 is used for page 1. This allows page flipping
to be performed in the top 339 scan lines (about 70 percent) of the
screen, and leaves the bottom 141 scan lines for non-animation purposes,
such as showing scores, instructions, statuses, and suchlike. (Note that
the allocation of display memory and number of scan lines are dictated
by the desire to have as many page-flipped scan lines as possible; you
may, if you wish, have fewer page-flipped lines and reserve part of the
bitmap for other uses, such as off-screen storage for images.)
![](images/44-02.jpg)\
**Figure 44.2**  *Memory allocation for mode 12h page flipping.*
The sample program for this chapter uses the split screen and page
flipping exactly as described above. The playfield through which the
object bounces is the page-flipped portion of the screen, and the
rectangle at the bottom containing the bounce count and the instructions
is the split (that is, not animatable) portion of the screen. Of course,
to the user it all looks like one screen. There are no visible
boundaries between the two unless you choose to create them.
Very few animation applications use the entire screen for animation. If
you can get by with 339 scan lines of animation, split-screen page
flipping gives you the best combination of square pixels and high
resolution possible on a standard VGA.
So. Is VGA animation worth all the fuss? *Mais oui.* Run the sample
program; if you've never seen aggressive VGA animation before, you'll be
amazed at how smooth it can be. Not every square millimeter of every
animated screen must be in constant motion. Most graphics screens need a
little quiet space to display scores, coordinates, file names, or (if
all else fails) company logos. If you don't tell the user he's/she's
only getting 339 scan lines of animation, he'll/she'll probably never
know.