122 lines
6.8 KiB
Markdown
122 lines
6.8 KiB
Markdown
---
|
|
title: Michael Abrash's Graphics Programming Black Book, Special Edition
|
|
author: Michael Abrash
|
|
date: '1997-07-01'
|
|
isbn: '1576101746'
|
|
publisher: The Coriolis Group
|
|
category: 'Web and Software Development: Game Development,Web and Software Development:
|
|
Graphics and Multimedia Development'
|
|
chapter: '34'
|
|
pages: 641-643
|
|
---
|
|
|
|
#### Loading the DAC via the BIOS {#Heading5}
|
|
|
|
The DAC can be loaded either directly or through subfunctions 10H (for a
|
|
single DAC register) or 12H (for a block of DAC registers) of the BIOS
|
|
video service interrupt 10H, function 10H, described in Chapter 33. For
|
|
cycling the contents of the entire DAC, the block-load function (invoked
|
|
by executing `INT` 10H with AH = 10H and AL = 12H to load a block of
|
|
CX DAC locations, starting at location BX, from the block of RGB
|
|
triplets—3 bytes per triplet—starting at ES:DX into the DAC) would be
|
|
the better of the two, due to the considerably greater efficiency of
|
|
calling the BIOS once rather than 256 times. At any rate, we'd like to
|
|
use one or the other of the BIOS functions for color cycling, because we
|
|
know that whenever possible, one should use a BIOS function in
|
|
preference to accessing hardware directly, in the interests of avoiding
|
|
compatibility problems. In the case of color cycling, however, it is
|
|
emphatically *not* possible to use either of the BIOS functions, for
|
|
they have problems. Serious problems.
|
|
|
|
The difficulty is this: IBM's BIOS specification describes exactly how
|
|
the parameters passed to the BIOS control the loading of DAC locations,
|
|
and all clone BIOSes meet that specification scrupulously, which is to
|
|
say that if you invoke `INT` 10H, function 10H, subfunction 12H with a
|
|
given set of parameters, you can be sure that you will end up with the
|
|
same values loaded into the same DAC locations on all VGAs from all
|
|
vendors. IBM's spec does *not*, however, describe whether vertical
|
|
retrace should be waited for before loading the DAC, nor does it mention
|
|
whether video should be left enabled while loading the DAC, leaving
|
|
cloners to choose whatever approach they desire—and, alas, every VGA
|
|
cloner seems to have selected a different approach.
|
|
|
|
I tested four clone VGAs from different manufacturers, some in a 20 MHz
|
|
386 machine and some in a 10 MHz 286 machine. Two of the four waited for
|
|
vertical retrace before loading the DAC; two didn't. Two of the four
|
|
blanked the display while loading the DAC, resulting in flickering bars
|
|
across the screen. One showed speckled pixels spattered across the top
|
|
of the screen while the DAC was being loaded. Also, not one was able to
|
|
load all 256 DAC locations without showing *some* sort of garbage on the
|
|
screen for at least one frame, but that's not the BIOS's fault; it's a
|
|
problem endemic to the VGA.
|
|
|
|
> 
|
|
> These findings lead me inexorably to the conclusion that the BIOS should
|
|
> not be used to load the DAC dynamically. That is, if you're loading the
|
|
> DAC just once in preparation for a graphics session—sort of a DAC mode
|
|
> set—by all means load by way of the BIOS. No one will care that some
|
|
> garbage is displayed for a single frame; heck, I have boards that bounce
|
|
> and flicker and show garbage every time I do a mode set, and the amount
|
|
> of garbage produced by loading the DAC once is far less noticeable. If,
|
|
> however, you intend to load the DAC repeatedly for color cycling, avoid
|
|
> the BIOS DAC load functions like the plague. They will bring you only
|
|
> heartache.
|
|
|
|
As but one example of the unsuitability of the BIOS DAC-loading
|
|
functions for color cycling, imagine that you want to cycle all 256
|
|
colors 70 times a second, which is once per frame. In order to
|
|
accomplish that, you would normally wait for the start of the vertical
|
|
sync signal (marking the end of the frame), then call the BIOS to load
|
|
the DAC. On some boards—boards with BIOSes that don't wait for vertical
|
|
sync before loading the DAC—that will work pretty well; you will, in
|
|
fact, load the DAC once a frame. On other boards, however, it will work
|
|
very poorly indeed; your program will wait for the start of vertical
|
|
sync, and then the BIOS will wait for the start of the next vertical
|
|
sync, with the result being that the DAC gets loaded only once every
|
|
*two* frames. Sadly, there's no way, short of actually profiling the
|
|
performance of BIOS DAC loads, for you to know which sort of BIOS is
|
|
installed in a particular computer, so unless you can always control the
|
|
brand of VGA your software will run on, you really can't afford to color
|
|
cycle by calling the BIOS.
|
|
|
|
Which is not to say that loading the DAC directly is a picnic either, as
|
|
we'll see next.
|
|
|
|
#### Loading the DAC Directly {#Heading6}
|
|
|
|
So we must load the DAC directly in order to perform color cycling. The
|
|
DAC is loaded directly by sending (with an `OUT` instruction) the
|
|
number of the DAC location to be loaded to the DAC Write Index register
|
|
at 3C8H and then performing three `OUT`s to write an RGB triplet to
|
|
the DAC Data register at 3C9H. This approach must be repeated 256 times
|
|
to load the entire DAC, requiring over a thousand `OUT`s in all.
|
|
|
|
There is another, somewhat faster approach, but one that has its risks.
|
|
After an RGB triplet is written to the DAC Data register, the DAC Write
|
|
Index register automatically increments to point to the next DAC
|
|
location, and this repeats indefinitely as successive RGB triplets are
|
|
written to the DAC. By taking advantage of this feature, the entire DAC
|
|
can be loaded with just 769 `OUT`s: one `OUT` to the DAC Write Index
|
|
register and 768 `OUT`s to the DAC Data register.
|
|
|
|
So what's the drawback? Well, imagine that as you're loading the DAC, an
|
|
interrupt-driven TSR (such as a program switcher or multitasker)
|
|
activates and writes to the DAC; you could end up with quite a mess on
|
|
the screen, especially when your program resumes and continues writing
|
|
to the DAC—but in all likelihood to the wrong locations. No problem, you
|
|
say; just disable interrupts for the duration. Good idea—but it takes
|
|
much longer to load the DAC than interrupts should be disabled for. If,
|
|
on the other hand, you set the index for each DAC location separately,
|
|
you can disable interrupts 256 times, once as each DAC location is
|
|
loaded, without problems.
|
|
|
|
As I commented in the last chapter, I don't have any gruesome tale to
|
|
relate that mandates taking the slower but safer road and setting the
|
|
index for each DAC location separately while interrupts are disabled.
|
|
I'm merely hypothesizing as to what ghastly mishaps *could*. happen.
|
|
However, it's been my experience that anything that can happen on the PC
|
|
*does* happen eventually; there are just too dang many PCs out there for
|
|
it to be otherwise. However, load the DAC any way you like; just don't
|
|
blame me if you get a call from someone who's claims that your program
|
|
sometimes turns their screen into something resembling month-old yogurt.
|
|
It's not really your fault, of course—but try explaining that to *them!*
|