121 lines
6.6 KiB
Markdown
121 lines
6.6 KiB
Markdown
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.
|
||
|
||
\
|
||
**Figure 58.1** *Texture mapping a single horizontal scanline.*
|