游戏性能优化手册
本手册供后续开发与 Goal 任务复用。2026-10-12 第一轮与第二轮实测保留在渲染性能记录,这里整理已经验证的方法与下一步计划。第二轮已处理指定本机机位的 macOS 残余尾帧与主要预热等待;下方的新优先级仍需独立测量,不能把已有样本当成所有设备和区域的保证。
后续轮次按本手册执行性能与美术分阶段对照;新的卡通色块、颜色反差墨线及步行弹性见画面氛围指南。画面改动后的最终版本也必须重新测量,不能沿用此前性能版本的结果。
已处理与下一轮优先级
- macOS 指定机位的约 25 ms 尾帧已处理。 回调/限帧准入修正后,最终三组 30 秒样本的 P99 中位数 25.8→19.8 ms,超过 22 ms 的帧 552→0。CPU 主矩阵样本为 6.6→5.8 ms,但较早仅性能补丁的交替对照为 5.8→5.9 ms,不能宣布原生 CPU 稳定加速。
- WebGPU 重复预热成本已减少。 四朝向实际绘制准备、让出主线程、状态恢复和加载后时钟重对齐后,出生点三次独立预热中位数 2,460.7→404.0 ms,真实就绪 16.006→13.919 秒;首次转视角 P99 18.7→18.7 ms,超过 50 ms 的帧 0→0。
- 主矩阵画面版本已纳入 A/B。 浏览器与两个真实联机客户端回归中帧间隔保持;持续 WebGPU 的世界渲染提交 CPU 6.9→7.2 ms,约增加 4.3%。该计量排除最终呈现,不能当成墨线的独立 GPU 成本或零成本证明。矩阵后的共享 HDR/相机所有权安全补丁已通过两项真实 GPU 恢复回归、定向单测、重新构建及生产功能回归;最后安全版本补测的三组独立首次转视角与一组新联机对照也已通过,预热 2,803.9→467.0 ms、真实就绪 17.284→15.094 秒。两组版本与系统窗口分别报告,不混合计算收益。
| 顺序 | 已知证据 | 先做的调查 | 验收重点 |
|---|---|---|---|
| 1. 扩展帧预算与新画面的代价 | 本机 macOS 主矩阵 P99 19.7–20.0 ms,仍高于 60 FPS 的 16.7 ms;WebGPU 提交 CPU 本组约增加 4.3% | 在 30/60/90/120/144 Hz、不同实际 GPU/呈现路径上对齐回调、准入、逻辑、整帧提交、GPU与 GC;单独量化 HDR/墨线和独立城市呈现 | 验证限帧与重复回调边界;报告 P95/P99、预算超限比例、CPU/GPU及显存,避免把局部墙钟当成整帧成本 |
| 2. 继续缩短完整就绪 | 主矩阵预热约 404 ms、就绪约 13.9 秒;最后安全版本另一个系统窗口预热约 467 ms、就绪约 15.1 秒,两组分别报告 | 按阶段测地图/布局、模块、场景/物理构建、GPU 初始化与首帧,继续移除重复工作和不必要串行;保留新区域管线准备 | 真正可操作时间与首分钟卡顿一起验收;新进程/资源版本完整冻结,不提前移动 ready 标记 |
| 3. 新区域与宽视角 | 转视角峰值约 390 次绘制/12.9 万三角形,超过既有局部场景目标;新区域未充分覆盖 | 补跨区域骑行、河面、昼夜、镜面、步行/骑行与破坏状态样本,再按热点检查合批、索引/矩阵上传、对象更新和资源创建 | 保持原几何、可见性、阴影、水面、MSAA、实际分辨率与物理行为,复核整个渲染帧的工作量 |
| 4. 公网与长期运行 | RTT 1.6–3.3 ms 仅来自本地开发服务器;没有证明堆内存减少 | 测真实 Steam/云端 WAN、抖动、断线重连、主机角色变化,以及长时间游玩和重复进出房间后的资源保留 | 状态与实际连接一致;RTT 无伪造;资源释放后不持续增长;帧耗时和同步恢复符合各自条件 |
第二轮已用回调/准入记录解释和修复本机的这一类尾帧;新的症状仍应重新区分限帧、缓存、GC、GPU与系统调度,不能套用同一原因。裁剪函数局部 profile 改善不能替代整个游戏的结果。第三项中的旧 <300 calls / <90,000 triangles 目标有指定场景和计量范围,不把医院的合格结果外推至整张城市,也不放宽目标掩盖宽视角超限。
联机记录中的 11.80→15.23 秒来自双客户端页面加载、建房/加入、准备和点击开始的串行流程,结束于点击开始后、确认 running 前。它是流程耗时,不能当成单客户端或首个可操作帧的精确加载时间。
固定优化流程
- 冻结基线和问题场景。 保存提交与未提交改动、资源版本、依赖、设备和实际后端;固定位置、相机轨迹、时间/天气、模式和帧率设置。先证明脚本能触发用户遇到的卡顿。
- 分别测首次进入与持续游玩。 同时保留可操作时间、帧间隔分布、长帧、提交 CPU、绘制量和错误。根据所选帧率解释帧预算:60 FPS 约 16.7 ms,30 FPS 约 33.3 ms。
- 提出可证伪的原因。 每次探针只区分一个问题,例如“回调准时到达,但限帧拒绝”或“新材质首次绘制触发编译”。CPU、GPU、加载与网络问题分别取证。
- 只改已证实的热点。 缓存、合批、异步准备、Worker 或上传优化都应有对应证据。涉及真实时序或失效边界时,先补能复现问题的回归测试。
- 正式 A/B 与诊断采样分开。 每版至少三组,交替前后顺序;异常时反向复测。串行运行,不与构建、其他浏览器测试或 GPU 捕获争用设备。
- 验证画面、行为与清理,再报告收益。 按变更范围运行类型、相关测试、构建及现有预算;记录代价、失败和未覆盖环境。验收门槛应在改动前根据目标与重复基线波动确定,不能看完结果再选择有利指标。
这种先测量、定位最耗资源的工作、再重复验证的流程与 Electron 官方性能指南一致。主进程避免阻塞式 I/O/IPC,渲染线程的重 CPU 工作是否移到 Worker,要连同传输、同步和调度成本一起验证。
A/B 怎么运行
在游戏源码仓库运行 pnpm benchmark:camera,结果留在 Git 外。工具使用真实 Chromium/Electron GPU 和实际相机输入;desktop 是原生窗口 harness,生产包装、preload、Steam IPC 仍需独立验证。
# 持续街区:同一进程内三轮;前后必须使用相同参数
pnpm benchmark:camera --platform=browser --backend=webgpu --scenario=district --duration=60000 --rounds=3 --output=/tmp/gza-perf-current-webgpu
pnpm benchmark:camera --platform=browser --backend=webgl --scenario=district --duration=30000 --rounds=3 --output=/tmp/gza-perf-current-webgl
pnpm benchmark:camera --platform=desktop --backend=webgl --scenario=district --duration=30000 --rounds=3 --output=/tmp/gza-perf-current-macos
# 首次转视角:一个独立样本;运行三次并使用不同输出目录
pnpm benchmark:camera --platform=browser --backend=webgpu --scenario=district --cold=true --position=spawn --duration=15000 --rounds=1 --output=/tmp/gza-perf-first-look-1
# 联机首次进入:一个新房间样本;同样独立运行三次
pnpm benchmark:camera --platform=browser --backend=webgpu --scenario=city --duration=10000 --rounds=1 --output=/tmp/gza-perf-city-1--rounds=3 会复用同一进程/房间。冷启动和联机新房间需要三次独立命令,每次 --rounds=1;新进程也不保证操作系统或 GPU 驱动缓存完全冷。10 秒联机样本只用于早期卡顿,持续联机还需另建正常游玩路径,保证采样全程仍为 running。
Windows 跨街区骑行可使用 --motion=route --route=canton-tower,tit-north,kecun,liyuan --duration=360000 --rounds=1 --frame-rate=90 --min-fps=60,与 --platform=desktop --backend=webgl 组合。路线通过普通骑行输入、真实碰撞查询及必要倒车完成,保留警察拦停;起点只在计时前设置,路线完成后提前结束采样。正式前后对照仍需至少三组独立进程、交替顺序,基线不传 --min-fps 以保留失败数据,但必须检查路线确实完成。
--min-fps 同时要求实际骑行和路线进度至少一公里、横向或纵向跨度至少 500 米、计划路线完成、游戏仍在游玩、实际后端一致及缓冲未改变;最低值来自实际采样中的完整一秒窗口,包含空窗口,末尾不足一秒不参与统计。失败 JSON 也会保存,不能用原地等待的高帧率替代长途验收。90 FPS 是本机在 60 FPS 上限边界留出余量的已有设置,增加绘制频率,不能推导其他设备均能达到同样帧率;保留默认上限并另列实际质量与功耗等代价。
--baseline=/absolute/frozen/apps/dayun-kicker 可替换工具加载的应用 src/。当前脚本仍使用当前工作区的依赖、共享包、开发服务器和资源;涉及这些内容的改动应分别运行完整冻结的基线/优化工作区,不能只用此选项声称完整版本对比。基线也须使用相同计量版本和轨迹。
--profile=true、--trace=true、--pacing=true 仅用于诊断,输出单列。正式采样关闭它们及完整 GPU 分析,轻量面板也保持关闭,由基准工具采集。面板开/关的额外成本需另做专门对比。
--heap-diagnostic=true 在采样结束后执行一次强制回收,另列回收前后 JS 堆读数并标记诊断用途。它不证明长期稳定,也不能与未强制回收的正式样本混算内存收益;正式性能采样关闭此项。
样本与报告规则
- 记录操作系统、芯片/GPU、运行时版本、实际 WebGL/WebGPU、窗口/DPR/缓冲尺寸、帧率上限、光照、路径、客户端数、系统负载与交换内存。选择了 WebGPU 不等于实际使用 WebGPU。
- 校验实际相机旋转、帧数/CPU 样本非空、游戏状态有效及运行时错误。无效样本单独记录并查因,不混进结果;实际后端不匹配必须拒绝比较。
- 保存每轮 FPS、P50/P95/P99/最大帧间隔、超过目标帧预算的比例、超过 50 ms 的次数或每分钟发生率,以及 CPU、加载、绘制量与资源数据。当前工具原始间隔可用于另算帧预算比例;不要把它写成面板已经提供的字段。
- 报告每轮值、各轮统计值的中位数和波动范围。长帧合计必须对应相同采样时长;时长不同时比较发生率。P99 是帧间隔统计,不是“99% 的帧都满足帧预算”的保证。
- 分清开发环境、原生 harness 与正式打包客户端。发布预算合格不等于所有区域帧率合格;本地 RTT、桌面模拟手机和单一 GPU 不能代表公网、实体手机或其他设备。
- 公开文档只保留汇总、方法、成本和限制;私有源码、原始日志与可能含账号或请求信息的 trace 留在私有位置。
本轮可复用的最佳实践
计量边界必须明确
轻量面板由真实游戏渲染循环记录,避免独立 rAF 把回调次数当成游戏帧数。当前 FPS 使用最近最多 120 个间隔,P95/P99/长帧使用最近最多 4,096 个间隔;加载预热不混入游玩窗口。面板约 500 ms 刷新,关闭后停止采样。字段、UI 及开发诊断边界见 UI 组件约定。
formatVersion: 2 的渲染提交 CPU 是一次世界渲染函数的墙钟时间,包含嵌套阴影/水面,排除游戏逻辑和最终呈现。它不等于整帧 CPU 使用率或 GPU 耗时;不能逐层累加嵌套 renderer.render(),也不能将 CPU 与 GPU 时间直接相加成帧间隔。计量边界改变后,旧数字要标记不可直接比较。
骑行工具另列 cpuTotal:街区渲染回调从入口到最终呈现结束的墙钟时间,包含逻辑、自动骑行控制和渲染,排除未开启的可选后视镜步骤。它与原有 cpu 分开统计,仍不是进程 CPU 使用率或 GPU 时间;沿用同一计量版本和输入轨迹才能作前后对照。
用 Chrome Performance 的帧、主线程、合成及调用栈调查长帧。正式游戏帧耗时验收以目标 GPU/设备的实际游玩为主;LCP/INP 等网页指标与节流启动测试保留各自用途,不替代相机移动验收。
预热要连同加载代价验收
新着色器首次使用可能产生编译卡顿。Three.js Renderer 提供 compileAsync();WebGLRenderer 的实现利用可用的 KHR_parallel_shader_compile 扩展。预编译前需配置对应场景的光照与环境。
本项目第二轮使用四朝向的实际世界、阴影、水面与真实呈现目标绘制准备所需管线,减少了重复显式编译;不能由 API 名称推断某个准备步骤一定必要。准备前同步实际 framebuffer 大小,并在阶段间让出主线程;过程中暂停正常循环,结束或失败时恢复相机、可见性、原水面状态、渲染目标与采样状态,完成后重对齐游戏时钟。共享 target 的等待与取消还必须遵守所有权,不能在持有者尚未归还时开始另一次呈现或释放。不能假设一次准备覆盖未来所有材质、视角和区域,也不能提前移动 ready 标记隐藏仍不可操作的时间。
缓存、合批与上传要保留正确性
静态结果只在真实依赖未变化时复用。透视相机的面朝向取决于视点位置,纯旋转不会改变该判断;正交相机取决于视向。视锥仍随旋转变化,破坏、材质 side、镜像相机、层级和相机生命周期都有自己的失效条件,不能将所有裁剪一起跳过。
按证据选用实例化/合批。InstancedMesh 和 BatchedMesh 能减少绘制提交,但批次变大可能增加实际可见三角形或更新工作;同时验收提交 CPU、GPU、绘制量、包围盒、单体破坏及反射/阴影。沿用现有几何,不以降画质达到目标。
未变的矩阵、索引和资源可避免重复上传,但要保留 GPU 所需的有效更新协议。参考算法比对裁剪结果;长时间样本检查额外缓存的内存成本。一次 heap 读数不能证明收益,用 Chrome 内存工具 区分持续保留与正常 GC 波动;Three.js 资源按所有权调用 dispose,不能释放仍被其他场景复用的资源。
限帧、诊断与联网有独立边界
- 限帧器的提前容差用于准入,不能算入已过期截止时间的推进;第二轮将本机原生回调的准入余量定为至多 2 ms,并增加重复回调保护,加载长暂停后重新对齐。该值来自本轮时序证据,不能当成所有设备的通用常量。覆盖目标帧率、60/120/144 Hz、时间量化、重复回调及接近截止点的回归,再以真实原生回调验证。
- 完整 GPU 查询按需、能力探测、异步读取;不以阻塞
finish/readPixels补测。取消、超时、场景退出和设备丢失时清理钩子与自有查询,并检查渲染 pass 是否还引用已释放 QuerySet。生产仅保留已授权的轻量面板。 - RTT 来自确认回包与单调时钟;不支持、未采样或过期时显示不可用。快照年龄/同步 Hz 与 RTT 分开,快照间隔不能推导真实丢包率。pending 探针有上限和 TTL,切换房间/角色后重置,迟到回包不得污染新会话。
- 网络恢复后重新建立同步频率窗口,避免加载或断线空档长期稀释读数;HUD 低频刷新,异步 getter 避免重叠和迟到更新。
- 诊断界面沿用共享组件、token 和按需加载;优化不得擅自提高启动包体、资源或场景预算。保留失败记录与环境差异。
风格改动也要测量
卡通化的目标与取样边界见画面氛围指南。九个共享颜色样本不等于零成本,独立城市新增的 HDR target/呈现也不同于街区已有 pass 内的计算。将仅性能补丁与最终美术版本分别冻结,最后再对完整交付版本复测;记录真实 CPU/GPU、加载、显存与画面。明确颜色反差墨线、深度/法线轮廓和材质着色各自的能力,保留减少动态效果偏好及模拟/显示所有权。
可复用的 Goal 模板
每轮聚焦一个优先问题,在开始前补全范围和验收门槛。下面模板不会自动创建新 Goal。
为 GZA 创建性能优化 Goal:优先解决 macOS 桌面持续转视角的残余尾帧。
先读 docs/game-performance-playbook.md 与最近的渲染性能验收记录,冻结完整基线。
先用同机位、同相机轨迹的重复样本定位 rAF/限帧、逻辑、渲染提交、GPU/呈现或 GC 的原因,再优化已证实的热点。
保持几何、材质效果、阴影、水面、MSAA、实际缓冲尺寸、帧率设置和物理频率。
以 macOS 实际发布后端验收,并回归浏览器 WebGL/WebGPU、联机及首次进入场景。
根据基线波动先约定 P95/P99、长帧发生率和允许的 CPU/加载代价;每版至少三组正式 A/B,异常反向复测。
诊断采样与正式验收分开;相关功能、画面、资源清理、类型、构建与原有预算通过后才报告完成。
记录每轮数据、真实就绪时间、成本、失败和未覆盖设备/公网环境,并更新公开汇总。项目特定路径、预算和实测记录保留在本手册;可跨游戏复用的诊断与测量方法以后再抽成通用 skill,避免将一次设备上的结果写成永久保证。
Godot 三层反馈(2026-10-15)
Godot 原型现在先跑定向逻辑 / 测试入口解析检查,再做有门槛的短窗筛选,候选有效后才运行完整三单和长途。第一层本机约 3.3 秒;最新有效的一对 30 秒短窗连同准备约 92 秒。首次静态合批缓存约 43–50 秒 / 版另计,不承诺所有设备相同时长,也不把较小覆盖的筛选当成完整验收加速。
- 每次修改:按影响范围检查碰撞、踹飞、伤害、存档及相关时序。保持能复现具体问题的红 / 绿信号,避免每次重复无关的 GPU、菜单或公网检查。
- 候选筛选:冻结完整游戏输入,普通骑行 / 战斗输入,正常生命、HUD / 自动存档,初始 300 只。默认前/后、后/前最多两轮各 30 秒;首个候选窗口未满足既定 60 FPS 门槛,就停止剩余窗口并保留失败。短窗通过仅允许进一步测试,不能宣布迁移或长期稳定。
- 完整验收:只有同游戏、同测试工具 / GDScript 入口及同路线 hash 的成功筛选记录才能放行。三单和 >6.5km 路线仍保持独立进程、各版三轮、串行交替顺序;真实伤害下死亡失败。候选一窗失败即取消剩余长测,不截掉窗口内的坏帧,不改预算。
测试工具增量读取日志,正式窗口不截图或跑 profiler。原生采样前退出编辑器和其他 Godot 进程,GPU 串行锁避免本工具重叠;仍不能自动隔离其他应用。运行中校验真实绘制,回调继续而绘制停止时尽早拒收,先修正原因再用新目录重跑,不无限自动重试。输入、代码、依赖及资源前后 hash 核对继续保留。
本轮候选没有通过短窗门槛,故没有执行新碰撞版本的完整三单 / 长途验收,Three.js 保留。第三层工具入口存在不等于第三层已经端到端验证通过。数据和失败边界见渲染性能记录。
同版本校准与窗口条件
比较性能回落前,先用同一冻结版本复跑短窗,区分代码差异与机器 /呈现波动。焦点、后台 CPU 与整机 GPU 必须在窗口中观察;失焦窗口保留全部坏帧,但不放行前台对比或后续长测。请求前台不等于持续前台,不持续抢占用户焦点。
派生静态缓存 /导入文件的新增也属于输入变化。首次生成属于准备,应记录代价,再创建新冻结工程;不能在正式采样结束后重新封存同一目录来补齐证明。物理步数使用帧时间窗口内的差值,启动和预热步数不能掩盖窗口内丢步。
采样器也记录自身开销。整机 GPU OS 计数器不等于游戏 GPU 时间;不可用写 unavailable,不能写零。局部查询微测提速不等于游戏 FPS 提升。未生成完整结果、焦点条件不符或稳定性门槛失败时,保留失败,不自动重试到成功,不继续昂贵验收。最新案例见渲染性能记录。