Initial conversion to markdown
This commit is contained in:
parent
a96a114403
commit
5e10794a24
362 changed files with 67353 additions and 0 deletions
131
63-04.md
Normal file
131
63-04.md
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
------------------------ --------------------------------- --------------------
|
||||
[Previous](63-03.html) [Table of Contents](index.html) [Next](64-01.html)
|
||||
------------------------ --------------------------------- --------------------
|
||||
|
||||
When it comes to implementation, however, transformation is quite
|
||||
different from three separate dot products and additions, because once
|
||||
again the magic number *three* is involved. Three separate dot products
|
||||
and additions would take 60 cycles if each were calculated using the
|
||||
unoptimized dot-product code of Listing 63.2, and would take 54 cycles
|
||||
if done one after the other using the faster dot-product code of Listing
|
||||
63.3, in each case followed by the a final addition per dot product.
|
||||
|
||||
When fully interleaved, however, only a single cycle is lost (again to
|
||||
the extra cycle of FST latency), and the cycle count drops to 34, as
|
||||
shown in Listing 63.6. This means that on a 100 MHz Pentium, it’s
|
||||
theoretically possible to do nearly 3,000,000 transforms per second,
|
||||
although that’s a purely hypothetical number, due to cache effects and
|
||||
set-up costs. Still, more than 1,000,000 transforms per second is
|
||||
certainly feasible; at a frame rate of 30 Hz, that’s an impressive
|
||||
30,000 transforms per frame.
|
||||
|
||||
**Listing 63.6 L63-6.ASM**
|
||||
|
||||
;optimized transformation: 34 cycles
|
||||
fld [vec0+0] ;starts & ends on cycle 0
|
||||
fmul [matrix+0] ;starts on cycle 1
|
||||
fld [vec0+0] ;starts & ends on cycle 2
|
||||
fmul [matrix+16] ;starts on cycle 3
|
||||
fld [vec0+0] ;starts & ends on cycle 4
|
||||
fmul [matrix+32] ;starts on cycle 5
|
||||
fld [vec0+4] ;starts & ends on cycle 6
|
||||
fmul [matrix+4] ;starts on cycle 7
|
||||
fld [vec0+4] ;starts & ends on cycle 8
|
||||
fmul [matrix+20] ;starts on cycle 9
|
||||
fld [vec0+4] ;starts & ends on cycle 10
|
||||
fmul [matrix+36] ;starts on cycle 11
|
||||
fxch st(2) ;no cost
|
||||
faddp st(5),st(0) ;starts on cycle 12
|
||||
faddp st(3),st(0) ;starts on cycle 13
|
||||
faddp st(1),st(0) ;starts on cycle 14
|
||||
fld [vec0+8] ;starts & ends on cycle 15
|
||||
fmul [matrix+8] ;starts on cycle 16
|
||||
fld [vec0+8] ;starts & ends on cycle 17
|
||||
fmul [matrix+24] ;starts on cycle 18
|
||||
fld [vec0+8] ;starts & ends on cycle 19
|
||||
fmul [matrix+40] ;starts on cycle 20
|
||||
fxch st(2) ;no cost
|
||||
faddp st(5),st(0) ;starts on cycle 21
|
||||
faddp st(3),st(0) ;starts on cycle 22
|
||||
faddp st(1),st(0) ;starts on cycle 23
|
||||
fxch st(2) ;no cost
|
||||
fadd [matrix+12] ;starts on cycle 24
|
||||
fxch st(1) ;starts on cycle 25
|
||||
fadd [matrix+28] ;starts on cycle 26
|
||||
fxch st(2) ;no cost
|
||||
fadd [matrix+44] ;starts on cycle 27
|
||||
fxch st(1) ;no cost
|
||||
fstp [vec1+0] ;starts on cycle 28,
|
||||
; ends on cycle 29
|
||||
fstp [vec1+8] ;starts on cycle 30,
|
||||
; ends on cycle 31
|
||||
fstp [vec1+4] ;starts on cycle 32,
|
||||
; ends on cycle 33
|
||||
|
||||
### Projection {#Heading10}
|
||||
|
||||
The final optimization we’ll look at is projection to screenspace.
|
||||
Projection itself is basically nothing more than a divide (to get 1/z),
|
||||
followed by two multiplies (to get x/z and y/z), so there wouldn’t seem
|
||||
to be much in the way of FP optimization possibilities there. However,
|
||||
remember that although FDIV has a latency of up to 39 cycles, it can
|
||||
overlap with integer instructions for all but one of those cycles. That
|
||||
means that if we can find enough independent integer work to do before
|
||||
we need the 1/z result, we can effectively reduce the cost of the FDIV
|
||||
to one cycle. Projection by itself doesn’t offer much with which to
|
||||
overlap, but other work such as clamping, window-relative adjustments,
|
||||
or 2-D clipping could be interleaved with the FDIV for the next point.
|
||||
|
||||
Another dramatic speed-up is possible by setting the precision of the
|
||||
FPU down to single precision via FLDCW, thereby cutting the time FDIV
|
||||
takes to a mere 19 cycles. I don’t have the space to discuss reduced
|
||||
precision in detail in this book, but be aware that along with
|
||||
potentially greater performance, it carries certain risks, as well. The
|
||||
reduced precision, which affects FADD, FSUB, FMUL, FDIV, and FSQRT, can
|
||||
cause subtle differences from the results you’d get using compiler
|
||||
defaults. If you use reduced precision, you should be on the alert for
|
||||
precision-related problems, such as clipped values that vary more than
|
||||
you’d expect from the precise clip point, or the need for using larger
|
||||
epsilons in comparisons for point-on-plane tests.
|
||||
|
||||
### Rounding Control {#Heading11}
|
||||
|
||||
Another useful area that I can note only in passing here is that of
|
||||
leaving the FPU in a particular rounding mode while performing bulk
|
||||
operations of some sort. For example, conversion to int via the FIST
|
||||
instruction requires that the FPU be in chop mode. Unfortunately, the
|
||||
FLDCW instruction must be used to get the FPU into and out of chop mode,
|
||||
and each FLDCW takes 7 cycles, meaning that compilers often take at
|
||||
least 14 cycles for each float-\>int conversion. In assembly, you can
|
||||
just set the rounding state (or, likewise, the precision, for faster
|
||||
FDIVs) once at the start of the loop, and save all those FLDCW cycles
|
||||
each time through the loop. This is even more true for **ceil()**, which
|
||||
many compilers implement as horrendously inefficient subroutines, even
|
||||
though there are rounding modes for both **ceil()** and **floor()**.
|
||||
Again, though, be aware that results of FP calculations will be subtly
|
||||
different from compiler default behavior while chop, ceil, or floor mode
|
||||
is in effect.
|
||||
|
||||
A final note: There are some speed-ups to be had by manipulating FP
|
||||
variables with integer instructions. Check out Chris Hecker’s column in
|
||||
the February/March 1996 issue of *Game Developer* for details.
|
||||
|
||||
### A Farewell to 3-D Fixed-Point {#Heading12}
|
||||
|
||||
As with most optimizations, there are both benefits and hazards to
|
||||
floating-point acceleration, especially pedal-to-the-metal optimizations
|
||||
such as the last few I’ve mentioned. Nonetheless, I’ve found
|
||||
floating-point to be generally both more robust and easier to use than
|
||||
fixed-point even with those maximum optimizations. Now that
|
||||
floating-point is fast enough for real time, I don’t expect to be doing
|
||||
a whole lot of fixed-point 3-D math from here on out.
|
||||
|
||||
And I won’t miss it a bit.
|
||||
|
||||
------------------------ --------------------------------- --------------------
|
||||
[Previous](63-03.html) [Table of Contents](index.html) [Next](64-01.html)
|
||||
------------------------ --------------------------------- --------------------
|
||||
|
||||
* * * * *
|
||||
|
||||
Graphics Programming Black Book © 2001 Michael Abrash
|
||||
Loading…
Reference in a new issue