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

102 lines
7.8 KiB
Markdown

#### 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.
------------------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
![](images/i.jpg) *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!*