Initial conversion to markdown
This commit is contained in:
parent
a96a114403
commit
5e10794a24
362 changed files with 67353 additions and 0 deletions
129
04-10.md
Normal file
129
04-10.md
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
------------------------ --------------------------------- --------------------
|
||||
[Previous](04-09.html) [Table of Contents](index.html) [Next](05-01.html)
|
||||
------------------------ --------------------------------- --------------------
|
||||
|
||||
------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
 *A line-drawing subroutine, which executes perhaps a dozen instructions for each display memory access, generally loses less performance to the display adapter cycle-eater than does a block-copy or scrolling subroutine that uses **REP MOVS** instructions. Scaled and three-dimensional graphics, which spend a great deal of time performing calculations (often using very slow floating-point arithmetic), tend to suffer less.*
|
||||
------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
In addition, code that accesses display memory infrequently tends to
|
||||
suffer only about half of the maximum display memory wait states,
|
||||
because on average such code will access display memory halfway between
|
||||
one available display memory access slot and the next. As a result, code
|
||||
that accesses display memory less intensively than the code in Listing
|
||||
4.11 will on average lose 4 or 5 rather than 8-plus cycles to the
|
||||
display adapter cycle-eater on each memory access.
|
||||
|
||||
Nonetheless, the display adapter cycle-eater always takes its toll on
|
||||
graphics code. Interestingly, that toll becomes much higher on ATs and
|
||||
80386 machines because while those computers can execute many more
|
||||
instructions per microsecond than can the 8088-based PC, it takes just
|
||||
as long to access display memory on those computers as on the 8088-based
|
||||
PC. Remember, the limited speed of access to a graphics adapter is an
|
||||
inherent characteristic of the adapter, so the fastest computer around
|
||||
can’t access display memory one iota faster than the adapter will allow.
|
||||
|
||||
#### What to Do about the Display Adapter Cycle-Eater? {#Heading22}
|
||||
|
||||
What can we do about the display adapter cycle-eater? Well, we can
|
||||
minimize display memory accesses whenever possible. In particular, we
|
||||
can try to avoid read/modify/write display memory operations of the sort
|
||||
used to mask individual pixels and clip images. Why? Because
|
||||
read/modify/write operations require two display memory accesses (one
|
||||
read and one write) each time display memory is manipulated. Instead, we
|
||||
should try to use writes of the sort that set all the pixels in a given
|
||||
byte of display memory at once, since such writes don’t require
|
||||
accompanying read accesses. The key here is that only half as many
|
||||
display memory accesses are required to write a byte to display memory
|
||||
as are required to read a byte from display memory, mask part of it off
|
||||
and alter the rest, and write the byte back to display memory. Half as
|
||||
many display memory accesses means half as many display memory wait
|
||||
states.
|
||||
|
||||
------------------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
 *Moreover, 486s and Pentiums, as well as recent Super VGAs, employ write-caching schemes that make display memory writes considerably faster than display memory reads.*
|
||||
------------------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
Along the same line, the display adapter cycle-eater makes the popular
|
||||
exclusive-OR animation technique, which requires paired reads and writes
|
||||
of display memory, less-than-ideal for the PC. Exclusive-OR animation
|
||||
should be avoided in favor of simply writing images to display memory
|
||||
whenever possible.
|
||||
|
||||
Another principle for display adapter programming on the 8088 is to
|
||||
perform multiple accesses to display memory very rapidly, in order to
|
||||
make use of as many of the scarce accesses to display memory as
|
||||
possible. This is especially important when many large images need to be
|
||||
drawn quickly, since only by using virtually every available display
|
||||
memory access can many bytes be written to display memory in a short
|
||||
period of time. Repeated string instructions are ideal for making
|
||||
maximum use of display memory accesses; of course, repeated string
|
||||
instructions can only be used on whole bytes, so this is another point
|
||||
in favor of modifying display memory a byte at a time. (On faster
|
||||
processors, however, display memory is so slow that it often pays to do
|
||||
several instructions worth of work between display memory accesses, to
|
||||
take advantage of cycles that would otherwise be wasted on the wait
|
||||
states.)
|
||||
|
||||
It would be handy to explore the display adapter cycle-eater issue in
|
||||
depth, with lots of example code and execution timings, but alas, I
|
||||
don’t have the space for that right now. For the time being, all you
|
||||
really need to know about the display adapter cycle-eater is that on the
|
||||
8088 you can lose more than 8 cycles of execution time on each access to
|
||||
display memory. For intensive access to display memory, the loss really
|
||||
can be as high as 8cycles (and up to 50, 100, or even more on 486s and
|
||||
Pentiums paired with slow VGAs), while for average graphics code the
|
||||
loss is closer to 4 cycles; in either case, the impact on performance is
|
||||
significant. There is only one way to discover just how significant the
|
||||
impact of the display adapter cycle-eater is for any particular graphics
|
||||
code, and that is of course to measure the performance of that code.
|
||||
|
||||
#### Cycle-Eaters: A Summary {#Heading23}
|
||||
|
||||
We’ve covered a great deal of sophisticated material in this chapter, so
|
||||
don’t feel bad if you haven’t understood everything you’ve read; it will
|
||||
all become clear from further reading, especially once you study, time,
|
||||
and tune code that you have written yourself. What’s really important is
|
||||
that you come away from this chapter understanding that on the 8088:
|
||||
|
||||
- The 8-bit bus cycle-eater causes each access to a word-sized operand
|
||||
to be 4 cycles longer than an equivalent access to a byte-sized
|
||||
operand.
|
||||
- The prefetch queue cycle-eater can cause instruction execution times
|
||||
to be as much as four times longer than the officially documented
|
||||
cycle times.
|
||||
- The DRAM refresh cycle-eater slows most PC code, with performance
|
||||
reductions ranging as high as 8.33 percent.
|
||||
- The display adapter cycle-eater typically doubles and can more than
|
||||
triple the length of the standard 4-cycle access to display memory,
|
||||
with intensive display memory access suffering most.
|
||||
|
||||
This basic knowledge about cycle-eaters puts you in a good position to
|
||||
understand the results reported by the Zen timer, and that means that
|
||||
you’re well on your way to writing high-performance assembler code.
|
||||
|
||||
#### What Does It All Mean? {#Heading24}
|
||||
|
||||
There you have it: life under the programming interface. It’s not a
|
||||
particularly pretty picture for the inhabitants of that strange realm
|
||||
where hardware and software meet are little-known cycle-eaters that sap
|
||||
the speed from your unsuspecting code. Still, some of those cycle-eaters
|
||||
can be minimized by keeping instructions short, using the registers,
|
||||
using byte-sized memory operands, and accessing display memory as little
|
||||
as possible. None of the cycle-eaters can be eliminated, and dynamic RAM
|
||||
refresh can scarcely be addressed at all; still, aren’t you better off
|
||||
knowing how fast your code *really* runs—and why—than you were reading
|
||||
the official execution times and guessing? And while specific
|
||||
cycle-eaters vary in importance on later x86-family processors, with
|
||||
some cycle-eaters vanishing altogether and new ones appearing, the
|
||||
concept that understanding these obscure gremlins is a key to
|
||||
performance remains unchanged, as we’ll see again and again in later
|
||||
chapters.
|
||||
|
||||
------------------------ --------------------------------- --------------------
|
||||
[Previous](04-09.html) [Table of Contents](index.html) [Next](05-01.html)
|
||||
------------------------ --------------------------------- --------------------
|
||||
|
||||
* * * * *
|
||||
|
||||
Graphics Programming Black Book © 2001 Michael Abrash
|
||||
Loading…
Reference in a new issue