Improving drawing performance by taking advantage of coalesced updates.
Mac OS X 10.4 introduces a new behavior of coalescing updates that enables Quartz to more efficiently update the frame buffer during each display refresh. In addition to increasing system efficiency, coalescing updates improves visual consistency and eliminates "tearing" during scrolling and animation. To coalesce updates, the Quartz window server composites all window buffers into a single offscreen frame buffer before flushing it to the screen. When your application issues a command to flush, the system doesn't actually flush that content until the next available display refresh. This allows all updates for multiple applications to happen at the same time. Window server operations (window resize or move, for example) are handled in the same manner—coalesced into a system-wide screen update.
How does this affect applications?
The majority of applications gain the benefit of coalesced updates, however, there are some situations where it can cause performance regressions. Regressions tend to fall into two categories:
Over-flushing: Applications that draw and flush much faster than the display refresh are throttled down to the refresh rate. Ideally, applications should not draw faster than the display refresh, as it would be wasting time drawing pixels the user won't see on the display. Once a window has been drawn into and flushed the buffer needs to be locked in preparation for window server access, so an application can do anything it likes until that flush makes it to the screen except draw into the buffer again. If an application tries to draw immediately after a flush it will block until that flush actually completes, so if the application just misses a frame sync it has to wait around until the next one, and won't be able to start drawing the next frame in the meantime.
Extended Drawing Interval: If an animation spends more time in its drawing routine than it takes for the screen to refresh, then it will become throttled to some factor of the refresh rate. So, if the refresh rate was 60 fps and the animation can run at most 55 fps, it will be throttled down to 30 fps.
What tools can I use to tell if an application is being affected by coalesced updates?
If an application that has been built and linked on Mac OS X 10.4 and later is spending more time drawing than the same application built and linked on a previous system, then it is probably being affected by coalesced updates. There are two tools that can be used to verify if an application is or isn't being affected by coalesced updates, Quartz Debug and Instruments.
Quartz Debug is a debugging tool for the Quartz graphics system with several powerful features to help you identify a number of graphics display and performance problems. Once the Mac OS X developer tools have been installed, the Quartz Debug application is located in: /Developer/Applications/Performance Tools/. To see the affect of effects of coalesced updates on applications, including CFM applications and applications linked on systems previous to 10.4, enable forced beam synchronization in Quartz Debug. An application that is being affected by coalesced updates will have a lowered frame rate when beam synchronization is enabled than when beam synchronization is disabled, and often will have increased CPU usage. To learn more about using Quartz Debug to see the effect of coalesced updates see Q&A 1234, Debugging Graphics with QuartzDebug.
Instruments is a profiling tool included with the Mac OS X developer tools distribution. Instruments can be used to profile an application and see if too much time is being spent in drawing operations, signaling that an application is having its updates coalesced. Once the Mac OS X developer tools have been installed, the Instruments profiling tool is located on the system at: /Developer/Applications/. If needed, use Quartz Debug to force beam synchronization then, in Instruments, sample your application using the "Time Profiler" instrument. If you see time more time spent in the
CGContext drawing operations than you do with beam synchronization disabled, your application is having its updates coalesced.
To learn more about using Instruments for profiling please see the Instruments User Guide.
To applications, this doesn't really change what they should be doing; it just enforces what has been recommended in the past.
Flush once per update event.
Consider periodic updates when live resizing and scrolling, and if needed draw lower quality results.
While an application can get the current screen's refresh rate, the recommendation is to assume a refresh rate of 60 Hz.
Applications in general shouldn't draw or flush faster than the user can see. Most animations only need a refresh rate of 30 fps, if an animation needs to update more often, then a timer should be used to limit animation rates to the refresh rate or less.
Avoid, if possible, the functions that request an immediate flush to the screen. Applications drawing with Quartz should use
In Cocoa use
setNeedsDisplay:to request an update for a view instead of the more immediate
display:, and in Carbon's HIToolBox use
HIViewSetNeedsDisplayInRegioninstead of the immediate
In drawing routines, do all calculations then draw, minimizing the amount of time between first touching the context and being done with it. In windows that have complex drawing routines, this will minimize the time waiting for a context that is being flushed to be released for more drawing.
It is a good idea for animations and screen updates to be time based and frame-limited in order to work best with coalesced updates. That is, they must make a fixed amount of progress per unit of time, rather than per frame, and they must not attempt to run at a rate greater than the refresh rate.
Applications that are displaying more than a single animation at a time in one window need to arrange for all animations in a window to run off of the same timer, updating in the same round in the runloop, and flushing together.
Decouple your visualization engine from your data engine so that neither engine will impede the other. Avoid network or disk access that would block the UI.
A last resort
If your application cannot adopt any of the above solutions, it is possible to disable coalesced updates for your application. To disable coalesced updates for your application, set the key
CGDisableCoalescedUpdates to the CFBoolean value of true in your Info.plist dictionary as shown in Listing 1. This key will only disable coalesced updates for applications running on Mac OS X 10.4.4 or later.
Listing 1 Using
CGDisableCoalescedUpdates, in an applications Info.plist, to disable coalesced updates on 10.4.4 and later.
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>CFBundleExecutable</key> <string>GraphicsApp</string> <key>CFBundleName</key> <string>GraphicsApp</string> ... <key>CGDisableCoalescedUpdates</key> <true/> ... <key>CFBundlePackageType</key> <string>APPL</string> <key>CFBundleSignature</key> <string>grap</string> <key>CFBundleVersion</key> <string>1.0</string> </dict> </plist>
Document Revision History
Editorial. Grammar and spelling fixes.
Changed the CGDisableCoalescedUpdates key's value in the Info.plist listing to a CFBoolean true.
New document that describes how to achieve the maximum frame rate in your Mac OS X application