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

121 lines
6.6 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

Chapter 58\
Heinlein's Crystal Ball, Spock's Brain, and the 9-Cycle Dare {#Heading1}
-------------------------------------------------------------
### Using the Whole-Brain Approach to Accelerate Texture Mapping {#Heading2}
I've had the pleasure recently of rereading several of the works of
Robert A. Heinlein, and I'm as impressed as I was as a teenager—but in a
different way. The first time around, I was wowed by the sheer romance
of technology married to powerful stories; this time, I'm struck most of
all by The Master's remarkable prescience. "Blowups Happen" is about the
risks of nuclear power, and their effects on human psychology—written
before a chain reaction had ever happened on this planet. "Solution
Unsatisfactory" is about the unsolvable dilemma—ultimate offense, no
defense—posed by atomic weapons; this in 1941. And in *Between Planets*
(1951), consider this minor bit of action:
> The doctor's phone regretted politely that Dr. Jefferson was not at
> home and requested him to leave a message. He was dictating it when a
> warm voice interrupted: I'm at home to you, Donald. Where are you,
> lad?'
Predicting the widespread use of answering machines is perhaps not so
remarkable, but foreseeing that they would be used for call screening
is; technology is much easier to extrapolate than are social patterns.
Even so, Heinlein was no prophet; his crystal ball was just a little
less fuzzy than ours. The aforementioned call in *Between Planets* was
placed on a viewphone; while that technology has indeed come to pass,
its widespread use has not. The ultimate weapon in "Solution
Unsatisfactory" was radioactive dust, not nuclear bombs, and we have
somehow survived nearly 50 years of nuclear weapons without either
acquiring a world dictator or destroying ourselves. Slide rules are all
over the place in Heinlein's works, and in one story (the name now lost
to memory), an astronaut straps himself into a massive integral
calculator; computers are nowhere to be found.
Most telling, I think, is that in "Blowups Happen," the engineers
running the nuclear power plant—at considerable risk to both body and
sanity—are the best of the best, highly skilled in math and required to
ride the nuclear reaction on a second-to-second basis, with the risk of
an explosion that might end life on Earth, and would surely kill them,
if they slip. Contrast that with our present-day reality of nuclear
plants run by generally competent technicians, with the occasional
report of shoddy maintenance and bored power-plant employees using
drugs, playing games, and falling asleep while on duty. Heinlein's
universe makes for a better story, of course, but, more than that, it
shows the filters and biases through which he viewed the world. At least
in print, Heinlein was an unwavering believer in science, technology,
and rationality, and in his stories it is usually the engineers and
scientists who are the heroes and push civilization forward, often
kicking and screaming. In the real world, I have rarely observed that to
be the case.
But of course Heinlein was hardly the only person to have his or her
perceptions of the universe, past, present, or future, blurred by his
built-in assumptions; you and I, as programmers, are also on that
list—and probably pretty near the top, at that. Performance programming
is basically a process of going from the general to the specific,
special-casing the code so that it does just what it has to, and no
more. The greatest impediment to this process is seeing the problem in
terms of what the code currently does, or what you already know, thereby
ignoring many possible solutions. Put another way, how you look at an
optimization problem determines how you'll solve it; your assumptions
may speed and simplify the process, but they are also your limitations.
Consider, for example, how a seemingly intractable problem becomes
eminently tractable the instant you learn that someone else has solved
it.
As Exhibit \#1, I present my experience with speeding up the texture
mapper in X-Sharp.
### Texture Mapping Redux {#Heading3}
We've spent the previous several chapters exploring the X Sharp graphics
library, something I built over time as a serious exercise in 3-D
graphics. When X-Sharp reached the point at which we left it at the end
of the previous chapter, I was rather pleased with it—with one
exception.
My last addition to X-Sharp was a *texture mapper,* a routine that
warped and rotated any desired bitmap to map onto an arbitrary convex
polygon. Texture mappers are critical to good 3-D games; just a few
texture-mapped polygons, backed with well-drawn bitmaps, can represent
more detail and look more realistic than dozens or even hundreds of
solid-color polygons. My X-Sharp texture mapper was in reasonable
assembly—pretty good code, by most standards!—and I felt comfortable
with my implementation; but then I got a letter from John Miles, who was
at the time getting seriously into 3-D and is now the author of a 3-D
game library. (Yes, you can license it from his company, Non-Linear
Arts, if you'd like; John can be reached at 70322.2457@compuserve.com.)
John wrote me as follows: "Hmm, so *that's* how texture-mapping works.
But 3 jumps *per pixel?* Hmph!"
It was the "Hmph" that really got to me.
#### Left-Brain Optimization {#Heading4}
That was the first shot of juice for my optimizer (or at least blow to
my ego, which can be just as productive). John went on to say he had
gotten texture mapping down to 9 cycles per pixel and one jump per
*scanline* on a 486 (all cycle times will be for the 486 unless
otherwise noted); given that my code took, on average, about 44 cycles
and 2 taken jumps (plus 1 not taken) per pixel, I had a long way to go.
The inner loop of my original texture-mapping code is shown in Listing
58.1. All this code does is draw a single texture-mapped scanline, as
shown in Figure 58.1; an outer loop runs through all the scanlines in
whatever polygon is being drawn. I immediately saw that I could
eliminate nearly 10 percent of the cycles by unrolling the loop;
obviously, John had done that, else there's no way he could branch only
once per scanline. (By the way, branching only once per scanline via a
fully unrolled loop is not generally recommended. A branch every few
pixels costs relatively little, and the cache effects of fully unrolled
code are *not* good.) I quickly came up with several other ways to speed
up the code, but soon realized that all the clever coding in the world
wasn't going to get me within 100 percent of John's performance so long
as I had to cycle from one plane to the next for every pixel.
![](images/58-01.jpg)\
**Figure 58.1**  *Texture mapping a single horizontal scanline.*