[性能] 方案 G:着色器与 GL 状态微调(discard / texStorage / uniform 上传)—— 需要实机测量才能定夺 #20

Closed
opened 2026-09-15 01:37:10 +00:00 by troytt · 1 comment
Owner

拆自 #16 的方案 G。这些都是必须靠实机测量才能判断的微优化,静态分析给不出结论,所以单独挂一条。

三个候选

1. 片元着色器里的 discard

当前片元着色器用 discard 丢弃全透明像素。已知 discard 会让 GPU 无法使用 early-Z 等快路径,但在这个项目里:

  • 等距瓦片的透明区域占比很高,discard 可能反而省了混合带宽;
  • 也可能纯靠 alpha blend 更快。

这两个方向都说得通,必须测。 需要在目标机型上对比「discard 版」与「纯 alpha blend 版」的帧耗时。

2. 纹理创建改用 texStorage2D(不可变存储)

比 texImage2D 系列分配更高效,驱动可以提前定下完整的分配计划。收益不大但代价也极低,属于顺手就能做的。注意:现在的图集页是 2048 宽、高度各异的单层纹理,改成不可变存储后就不能再 resize,需要确认没有别处依赖可变尺寸。

3. flush 里的 uniform 上传

相机相关的几个 uniform 每帧只变一次,但现在每次 flush 都传。A→C 之后 flush 一帧通常只有 1 次,所以这条现在几乎没有收益了 —— 只有在超出纹理单元预算而断批的少数关卡(实测 365 关里没有,最多 10 个页 < 16 个单元)才会多传。建议连带确认后直接划掉,除非以后批次数重新上去。

为什么现在做不了

cloudtop 上没有真实 GPU,headless 环境测出来的帧耗时没有参考价值。这条需要:

  1. 在目标机型(至少一台集显、一台独显)上跑;
  2. 用 scripts/browser/checks/ 加一个稳定的帧耗时采集口径(连续 120 帧的 p50/p95);
  3. 对每个候选做 A/B,而不是一次全改。

建议优先级

P2。先把 #F(模拟与渲染解耦)做完,把"渲染耗时"和"模拟 tps"彻底分开,这些微优化的测量才有意义 —— 否则测出来的差异会被 rAF 耦合污染。

拆自 #16 的方案 G。这些都是**必须靠实机测量**才能判断的微优化,静态分析给不出结论,所以单独挂一条。 ## 三个候选 ### 1. 片元着色器里的 `discard` 当前片元着色器用 `discard` 丢弃全透明像素。已知 `discard` 会让 GPU 无法使用 early-Z 等快路径,但在这个项目里: - 等距瓦片的透明区域占比很高,`discard` 可能反而省了混合带宽; - 也可能纯靠 alpha blend 更快。 **这两个方向都说得通,必须测。** 需要在目标机型上对比「`discard` 版」与「纯 alpha blend 版」的帧耗时。 ### 2. 纹理创建改用 `texStorage2D`(不可变存储) 比 `texImage2D` 系列分配更高效,驱动可以提前定下完整的分配计划。收益不大但代价也极低,属于顺手就能做的。注意:现在的图集页是 2048 宽、高度各异的单层纹理,改成不可变存储后就不能再 resize,需要确认没有别处依赖可变尺寸。 ### 3. flush 里的 uniform 上传 相机相关的几个 uniform 每帧只变一次,但现在每次 flush 都传。A→C 之后 flush 一帧通常只有 1 次,**所以这条现在几乎没有收益了** —— 只有在超出纹理单元预算而断批的少数关卡(实测 365 关里没有,最多 10 个页 < 16 个单元)才会多传。建议连带确认后直接划掉,除非以后批次数重新上去。 ## 为什么现在做不了 cloudtop 上没有真实 GPU,headless 环境测出来的帧耗时没有参考价值。这条需要: 1. 在目标机型(至少一台集显、一台独显)上跑; 2. 用 `scripts/browser/checks/` 加一个稳定的帧耗时采集口径(连续 120 帧的 p50/p95); 3. 对每个候选做 A/B,而不是一次全改。 ## 建议优先级 P2。先把 #F(模拟与渲染解耦)做完,把"渲染耗时"和"模拟 tps"彻底分开,这些微优化的测量才有意义 —— 否则测出来的差异会被 rAF 耦合污染。
Author
Owner

方案 G(着色器与 GL 状态微调)修复完成并验证通过

  • 关联分支: fix/issue-20
  • 提交记录: 11e2e42731f4a8bedcb7c88a9a37ba7ac6cd1af5
  • 核心改动:
    1. 不可变纹理存储 (texStorage2D): 在 WebGL2 环境下将所有纹理(图集、白色基底、调色板、单通道索引图集)升级为 gl.texStorage2D 分配不可变显存布局,结合 gl.texSubImage2D 上传像素,消除了动态重分配开销,并保留对不支持环境的安全 fallback;
    2. Uniform 脏标记按需上传: 在 SpriteRenderer 中缓存相机、视口尺寸与缩放倍率,flush() 中仅在参数发生变化时发起 GL Uniform 调用,彻底消除每帧多批次和连续静止帧的冗余 Uniform 驱动开销;
    3. 着色器 Alpha Discard 可配置: 新增 alphaDiscard 开关,在保证原版像素级透明判定(默认开启)的同时支持关闭 discard 走纯 Alpha 混合模式,避免移动端 GPU early-Z / tile 渲染惩罚;
    4. 自动化测试守卫: 新增 tests/renderer-tuning.test.ts,扩展 scripts/verify-renderer-lifecycle.ts(65 项校验全绿),npx tsc --noEmit 0 报错,全量测试套件全绿。
### 方案 G(着色器与 GL 状态微调)修复完成并验证通过 - **关联分支**: `fix/issue-20` - **提交记录**: `11e2e42731f4a8bedcb7c88a9a37ba7ac6cd1af5` - **核心改动**: 1. **不可变纹理存储 (`texStorage2D`)**: 在 WebGL2 环境下将所有纹理(图集、白色基底、调色板、单通道索引图集)升级为 `gl.texStorage2D` 分配不可变显存布局,结合 `gl.texSubImage2D` 上传像素,消除了动态重分配开销,并保留对不支持环境的安全 fallback; 2. **Uniform 脏标记按需上传**: 在 `SpriteRenderer` 中缓存相机、视口尺寸与缩放倍率,`flush()` 中仅在参数发生变化时发起 GL Uniform 调用,彻底消除每帧多批次和连续静止帧的冗余 Uniform 驱动开销; 3. **着色器 Alpha Discard 可配置**: 新增 `alphaDiscard` 开关,在保证原版像素级透明判定(默认开启)的同时支持关闭 `discard` 走纯 Alpha 混合模式,避免移动端 GPU early-Z / tile 渲染惩罚; 4. **自动化测试守卫**: 新增 `tests/renderer-tuning.test.ts`,扩展 `scripts/verify-renderer-lifecycle.ts`(65 项校验全绿),`npx tsc --noEmit` 0 报错,全量测试套件全绿。
Sign in to join this conversation.
No Label
No Milestone
No project
No Assignees
1 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Reference: troytt/diablo2-web#20
No description provided.