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

104 lines
5.4 KiB
Markdown

The interesting aspects of Listing 31.1 are three. First, the
**Set320x400Mode** subroutine selects 320x400 256-color mode. This is
accomplished by performing a mode 13H mode set followed by then putting
the VGA into standard planar byte mode. **Set320x400Mode** zeros display
memory as well. It's necessary to clear display memory even after a mode
13H mode set because the mode 13H mode set clears only the 64K of
display memory that can be accessed in that mode, leaving 192K of
display memory untouched.
The second interesting aspect of Listing 31.1 is the **WritePixel**
subroutine, which draws a colored pixel at any *x,y* addressable
location on the screen. Although it may not be obvious because I've
optimized the code a little, the process of drawing a pixel is
remarkably simple. First, the pixel's display memory address is
calculated as
*address*=(*y* \* (SCREEN\_WIDTH / 4)) + (*x* / 4)
which might be more recognizable as:
*address*=((*y* \* SCREEN\_WIDTH) + *x*) / 4
(There are 4 pixels at each display memory address in 320x400 mode,
hence the division by 4.) Then the pixel's plane is calculated as
*plane*=*x* and 3
which is equivalent to:
*plane*=*x* modulo 4
The pixel's color is then written to the addressed byte in the addressed
plane. That's all there is to it!
The third item of interest in Listing 31.1 is the **ReadPixel**
subroutine. **ReadPixel** is virtually identical to **WritePixel**, save
that in **ReadPixel** the Read Map register is programmed with a plane
number, while **WritePixel** uses a plane *mask* to set the Map Mask
register. Of course, that difference merely reflects a fundamental
difference in the operation of the two registers. (If that's Greek to
you, refer back to Chapters 23-30 for a refresher on VGA programming.)
**ReadPixel** isn't used in Listing 31.1, but I've included it because,
as I said above, the read and write pixel functions together can support
a whole host of more complex graphics functions.
How does 320x400 256-color mode stack up as regards performance? As it
turns out, the programming model of 320x400 mode is actually pretty good
for pixel drawing, pretty much on a par with the model of mode 13H. When
you run Listing 31.1, you'll no doubt notice that the lines are drawn
quite rapidly. (In fact, the drawing could be considerably faster still
with a dedicated line-drawing subroutine, which would avoid the
multiplication associated with each pixel in Listing 31.1.)
In 320x400 mode, the calculation of the memory address is not
significantly slower than in mode 13H, and the calculation and selection
of the target plane is quickly accomplished. As with mode 13H, 320x400
mode benefits tremendously from the byte-per-pixel organization of
256-color mode, which eliminates the need for the time-consuming
pixel-masking of the 16-color modes. Most important, byte-per-pixel
modes never require read-modify-write operations (which can be extremely
slow due to display memory wait states) in order to clip and draw
pixels. To draw a pixel, you just store its color in display memory—what
could be simpler?
More sophisticated operations than pixel drawing are less easy to
accomplish in 320x400 mode, but with a little ingenuity it is possible
to implement a reasonably efficient version of just about any useful
graphics function. A fast line draw for 320x400 256-color mode would be
simple (although not as fast as would be possible in mode 13H). Fast
image copies could be implemented by copying one-quarter of the image to
one plane, one-quarter to the next plane, and so on for all four planes,
thereby eliminating the **OUT** per pixel that sequential processing
requires. If you're really into performance, you could store your images
with all the bytes for plane 0 grouped together, followed by all the
bytes for plane 1, and so on. That would allow a single **REP MOVS**
instruction to copy all the bytes for a given plane, with just four
**REP MOVS** instructions copying the whole image. In a number of cases,
in fact, 320x400 256-color mode can actually be much faster than mode
13H, because the VGA's hardware can be used to draw four or even eight
pixels with a single access; I'll return to the topic of
high-performance programming in 256-color modes other than mode 13H
("non-chain 4" modes) in Chapter 47.
It's all a bit complicated, but as I say, you should be able to design
an adequately fast—and often *very* fast—version for 320x400 mode of
whatever graphics function you need. If you're not all that concerned
with speed, **WritePixel** and **ReadPixel** should meet your needs.
### Two 256-Color Pages {#Heading7}
Listing 31.2 demonstrates the two pages of 320x400 256-color mode by
drawing slanting color bars in page 0, then drawing color bars slanting
the other way in page 1 and flipping to page 1 on the next key press.
(Note that page 1 is accessed starting at offset 8000H in display
memory, and is—unsurprisingly—displayed by setting the start address to
8000H.) Finally, Listing 31.2 draws vertical color bars in page 0 and
flips back to page 0 when another key is pressed.
The color bar routines don't use the **WritePixel** subroutine from
Listing 31.1; they go straight to display memory instead for improved
speed. As I mentioned above, better speed yet could be achieved by a
color-bar algorithm that draws all the pixels in plane 0, then all the
pixels in plane 1, and so on, thereby avoiding the overhead of
constantly reprogramming the Map Mask register.