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

128 lines
7.1 KiB
Markdown

#### Color Plane Manipulation {#Heading8}
The VGA provides a considerable amount of hardware assistance for
manipulating the four display memory planes. Two features illustrated by
the sample program are the ability to control which planes are written
to by a CPU write and the ability to copy four bytes—one from each
plane—with a single CPU read and a single CPU write.
The Map Mask register (SC register 2) selects which planes are written
to by CPU writes. If bit 0 of the Map Mask register is 1, then each byte
written by the CPU will be written to VGA memory plane 0, the plane that
provides the video data for the least significant bit of the palette RAM
address. If bit 0 of the Map Mask register is 0, then CPU writes will
not affect plane 0. Bits 1, 2, and 3 of the Map Mask register similarly
control CPU access to planes 1, 2, and 3, respectively. Any of the 16
possible combinations of enabled and disabled planes can be selected.
Beware, however, of writing to an area of memory that is not zeroed.
Planes that are disabled by the Map Mask register are not altered by CPU
writes, so old and new images can mix on the screen, producing unwanted
color effects as, say, three planes from the old image mix with one
plane from the new image. The sample program solves this by ensuring
that the memory written to is zeroed. A better way to set all planes at
once is provided by the set/reset capabilities of the VGA, which I'll
cover in Chapter 25.
The sample program writes the image of the colored ball to VGA memory by
enabling one plane at a time and writing the image of the ball for that
plane. Each image is written to the same VGA addresses; only the
destination plane, selected by the Map Mask register, is different. You
might think of the ball's image as consisting of four colored overlays,
which together make up a multicolored image. The sample program writes a
blank image to VGA memory by enabling all planes and writing a block of
zero bytes; the zero bytes are written to all four VGA planes
simultaneously.
The images are written to a nondisplayed portion of VGA memory in order
to take advantage of a useful VGA hardware feature, the ability to copy
all four planes at once. As shown by the image-loading code discussed
above, four different sets of reads and writes—and several **OUT**s as
well—are required to copy a multicolored image into VGA memory as would
be needed to draw the same image into a non-planar pixel buffer. This
causes unacceptably slow performance, all the more so because the wait
states that occur on accesses to VGA memory make it very desirable to
minimize display memory accesses, and because **OUT**s tend to be very
slow.
The solution is to take advantage of the VGA's write mode 1, which is
selected via bits 0 and 1 of the GC Mode register (GC register 5). (Be
careful to preserve bits 2-7 when setting bits 0 and 1, as is done in
Listing 23.1.) In write mode 1, a single **CPU** read loads the
addressed byte from all four planes into the VGA's four internal
latches, and a single **CPU** write writes the contents of the latches
to the four planes. During the write, the byte written by the **CPU** is
irrelevant.
The sample program uses write mode 1 to copy the images that were
previously drawn to the high end of VGA memory into a desired area of
display memory, all in a single block copy operation. This is an
excellent way to keep the number of reads, writes, and OUTs required to
manipulate the VGA's display memory low enough to allow real-time
drawing.
The Map Mask register can still mask out planes in write mode 1. All
four planes are copied in the sample program because the Map Mask
register is still 0Fh from when the blank image was created.
The animated images appear to move a bit jerkily because they are
byte-aligned and so must move a minimum of 8 pixels horizontally. This
is easily solved by storing rotated versions of all images in VGA
memory, and then in each instance drawing the correct rotation for the
pixel alignment at which the image is to be drawn; we'll see this
technique in action in Chapter 49.
Don't worry if you're not catching everything in this chapter on the
first pass; the VGA is a complicated beast, and learning about it is an
iterative process. We'll be going over these features again, in
different contexts, over the course of the rest of this book.
#### Page Flipping {#Heading9}
When animated graphics are drawn directly on the screen, with no
intermediate frame-composition stage, the image typically flickers
and/or ripples, an unavoidable result of modifying display memory at the
same time that it is being scanned for video data. The display memory of
the VGA makes it possible to perform page flipping, which eliminates
such problems. The basic premise of page flipping is that one area of
display memory is displayed while another is being modified. The
modifications never affect an area of memory as it is providing video
data, so no undesirable side effects occur. Once the modification is
complete, the modified buffer is selected for display, causing the
screen to change to the new image in a single frame's time, typically
1/60th or 1/70th of a second. The other buffer is then available for
modification.
As described above, the VGA has 64K per plane, enough to hold two pages
and more in 640x350 mode 10H, but not enough for two pages in 640x480
mode 12H. For page flipping, two non-overlapping areas of display memory
are needed. The sample program uses two 672x384 virtual pages, each
32,256 bytes long, one starting at A000:0000 and the other starting at
A000:7E00. Flipping between the pages is as simple as setting the start
address registers to point to one display area or the other—but, as it
turns out, that's not as simple as it sounds.
The timing of the switch between pages is critical to achieving
flicker-free animation. It is essential that the program never be
modifying an area of display memory as that memory is providing video
data. Achieving this is surprisingly complicated on the VGA, however.
The problem is as follows. The start address is latched by the VGA's
internal circuitry exactly once per frame, typically (but not always on
all clones) at the start of the vertical sync pulse. The vertical sync
status is, in fact, available as bit 3 of the Input Status 0 register,
addressable at 3BAH (in monochrome modes) or 3DAH (color).
Unfortunately, by the time the vertical sync status is observed by a
program, the start address for the next frame has already been latched,
having happened the instant the vertical sync pulse began. That means
that it's no good to wait for vertical sync to begin, then set the new
start address; if we did that, we'd have to wait until the *next*
vertical sync pulse to start drawing, because the page wouldn't flip
until then.
Clearly, what we want is to set the new start address, then wait for the
start of the vertical sync pulse, at which point we can be sure the page
has flipped. However, we can't just set the start address and wait,
because we might have the extreme misfortune to set one of the start
address registers before the start of vertical sync and the other after,
resulting in mismatched halves of the start address and a nasty jump of
the displayed image for one frame.