jackiw@cs.swarthmore.edu (Nick Jackiw) (03/07/90)
In Inside Mac V and in various places in the techNotes, it states that CopyBits
is optimized for cases in which rowBytes is a multiple of four and in which
the bitmaps are aligned. I recently did some testing on a (wide) sample of
arbitrary bitmaps, and came up with the following interesting timings:
o Worst case ranges from about 102-105% of average case.
(Which is to say: the average case is about as bad as you can get)
o Best case (perfect alignment) ranges from about 54-72% of average case.
(i. e. Alignment has a *substantial* payoff.)
Remember, alignment (keeping the bit-index the same between corresponding
bits in the source bitmap and the destination) is only useful under several
conditions:
o You're always copying part of the source into one and only one
corresponding part of the destination.
o The source and destination are at the same bitdepth, if you're
working in color.
o For any given copy, the srcRect and destRect are of the same
dimension (though not necessarily the same coordinates).
A good example of when alignment is useful: storing an offscreen bitmap
containing the image to be painted into a window. Alignment will only
change (and the offscreen map be recomputed) if the window is moved.
A good example of when alignment won't help at all: storing the image
of a spaceship offscreen which can be copyBitted anywhere into the window.
("Anywhere"=any of 32 bit positions=alignment will only help you in 1/32
of your copies. Of course, you could store 32 differently-aligned spaceship
copies offscreen, and choose the appropriate one to blit based on the
dest rect.)
-------
The following function might be useful for cases when you want to create
an offscreen bitmap for copying to a window. Specify the window (which
must already be created and in its proper location) in destWindow, and
the bounds of the desired offscreen window (in the local coordinate
system of destWindow). InitAlignedBitmap will generate the bitmap,
tacking enough "slack" onto the left edge of the bitmap (i. e. by extending
the bounds) to guarantee that any bit in theBits is aligned with the
corresponding bit in the window's local coordinate system. This will
guarantee you best case performance.
------
Lastly, a note or two:
o If User moves the window, you'll need to recompute and redraw
the bitmap. You can dispose the old one and call this function
again, if you like, or you can modify this one to SetPtrSize
on the existing baseAddr ptr. You may want to change the code
to generate handles, instead of ptrs, but remember to lock and
derefence them before drawing. Growing a window doesn't change
the alignment (e. g. local [0,0] is still in the same place as
it was pre-grow; therefore so is offscreen [0,0].)
o Color doesn't complicate things (multiply by pixDepth before
determining rowBytes, and don't forget to set the high bit),
but multiple screens and multiple pixel depths do. In that you
can only be in alignment with one of the multiple screens at a
time (or only *guarantee* that you'll be so), you'll have to
choose between aligning for the screen which is deepest (which
you'll want to do if your offscreen bitmap should be complexly
colored), or for the screen which has the maximum destWindow area
on it (which will optimize for speed over color fidelity). Once
you've figured out which GDevice to align to, plug in its pixMap
for screenBits, below.
Enjoy.
--------
function InitAlignedBitMap(var theBits:Bitmap;destWindow:WindowPtr):boolean;
{By Nick Jackiw}
{Allocates storage for a bitmap the bounds of which have been set before}
{calling. The bitmap will be long-word aligned with the coordinate system}
{of the bit image which contains the destWindow.}
var
oldPort: GrafPtr;
aPoint: point;
bitOffset: integer; {# of bits we need to expand the offscreen map by}
begin
GetPort(oldPort); {Switch to desired port, for local->global conversion}
SetPort(destWindow);
aPoint := theBits.bounds.topLeft;
LocalToGlobal(aPoint);
bitOffset := (aPoint.h - ScreenBits.bounds.left) mod 32;
if bitOffset < 0 then
bitOffset := 32 + bitOffset;
with theBits.bounds do
left := left - bitOffset;{Expand dest bitmap by appropriate # of bits}
with theBits do
with bounds do
begin
rowBytes := ((right - left + 31) div 32) * 4;
baseAddr := NewPtr(rowBytes * (bottom - top));
InitAlignedBitMap := baseAddr <> nil
end;
SetPort(oldPort)
end;
--
+-------------------+-jackiw@cs.swarthmore.edu / !rutgers!bpa!swatsun!jackiw-+
| nicholas jackiw | jackiw%campus.swarthmore.edu@swarthmr.bitnet |
+-------------------+-VGP/MathDept/Swarthmore College, Swarthmore, PA 19081--+
"Ah...I've got this CHRONIC pain." _True Believer_
pepke@gw.scri.fsu.edu (Eric Pepke) (03/07/90)
In article <S5XF99Q@xavier.swarthmore.edu> jackiw@cs.swarthmore.edu (Nick Jackiw) writes: > A good example of when alignment won't help at all: storing the image > of a spaceship offscreen which can be copyBitted anywhere into the window. > ("Anywhere"=any of 32 bit positions=alignment will only help you in 1/32 > of your copies. Of course, you could store 32 differently-aligned spaceship > copies offscreen, and choose the appropriate one to blit based on the > dest rect.) I sometimes use an intermediate approach for offscreen bitmaps (not pixmaps). I keep an extra longword on the right of the bitmap on each row. When it comes time to plop this on the screen, I preshift the bits using a tight assembly loop. Of course, this only really helps when the bitmaps are pretty large. Eric Pepke INTERNET: pepke@gw.scri.fsu.edu Supercomputer Computations Research Institute MFENET: pepke@fsu Florida State University SPAN: scri::pepke Tallahassee, FL 32306-4052 BITNET: pepke@fsu Disclaimer: My employers seldom even LISTEN to my opinions. Meta-disclaimer: Any society that needs disclaimers has too many lawyers.