|
The windowing system on Mac OS X is different from that of previous Mac OS versions in several fundamental ways. The primary difference where QuickDraw is concerned is that drawing in a window port ends up in the window's back buffer and not on the screen. This shift and the underlying changes in QuickDraw necessary to make it possible have affected the performance characteristics of QuickDraw drawing code in some new and interesting ways. This technote will discuss some of the trouble spots and explain how to avoid them.
[Feb 13 2003]
|
Avoid triple buffering
Because drawing occurs in the window back buffer and not directly on
the screen, most of the motivation for doing your own double buffering
is no longer present. In the past, it was sometimes necessary to composite
your drawing into an offscreen GWorld and then copy it onto
the screen in one CopyBits operation in order to avoid
flickering and tearing. With Mac OS X, that extra buffer is not only
unnecessary, it will actually degrade performance due to the extra copy
required to move content from your offscreen to the window back buffer.
Don't double buffer on Mac OS X.
Back to top
Simplify dirty region updates
In order for QuickDraw to know which parts of the window back buffer to flush to the screen, every call to QuickDraw needs to record the region it dirties. When a drawing sequence consists of a number of small items contained within a well-known larger area, it is usually best to dirty the whole region at once rather than having every QuickDraw routine incrementally add to the dirty region. This way, you short-circuit the dirty region updating code inside each QuickDraw routine.
Assuming all the small QuickDraw operations are enclosed in a bigger rectangular region (bigRectRegion ), calling QDSetDirtyRegion(port, bigRectRegion) before making the first QuickDraw drawing operation dirties the whole rectangle at once, eliminating the need for the smaller QuickDraw calls to update the dirty region.
Setting the dirty region to a large rectangular region accomplishes two goals. First, it makes sure that the dirty region is rectangular, which greatly simplifies any subsequent region operations. Second, the large region encompasses all of the regions dirtied by the individual QuickDraw drawing calls, thus turning their dirty region updates into trivial intersection checks of the regions' bounding rectangles.
This technique is particularly handy for speeding up the drawing of complex vector graphics.
Back to top
Don't flush to the screen more often than necessary
For most applications, there is no need to flush more than 30 frames per second to obtain smooth animation. Flushing more often only results in additional CPU overhead and may end up slowing down the desired animation.
To control when flushing occurs you want to use a time-based strategy aimed at providing 30 fps:
// AbsoluteTime and UInt64 are in MacTypes.h
// The AbsoluteDeltaToNanoseconds call is in DriverServices.h
// The U64xyz APIs are in Math64.h
// QDFlushPortBuffer is in QuickDraw.h
// All are included in ApplicationServices.h
#include <ApplicationServices/ApplicationServices.h>
/* for about 30 frames/sec */
const UInt32 kMinNanosecsBetweenFlushes = 1E9 / 30;
static AbsoluteTime sLastFlush = { 0, 0 };
void framerateLimitedFlush ( CGrafPtr port )
{
AbsoluteTime curTime = UpTime();
Nanoseconds delta = AbsoluteDeltaToNanoseconds( curTime, sLastFlush );
if ( U64Compare( UnsignedWideToUInt64(delta),
U64SetU(kMinNanosecsBetweenFlushes)) > 0)
{
sLastFlush = curTime;
QDFlushPortBuffer(port, NULL);
}
}
|
Back to top
Summary
Mac OS X introduced some new performance characteristics for QuickDraw drawing, but the information presented here will help developers eliminate their graphics performance bottlenecks.
Back to top
Downloadables
|
Acrobat version of this Note (36K)
|
Download
|
Back to top
|