本文档记录目前 PrototypeMachinery(Forge 1.12.2 / Java 8) 客户端渲染侧已经落地的性能优化与调优开关,方便维护者:
- 快速理解“为什么这么做”
- 快速定位“该改哪个开关/哪段代码”
- 读懂 HUD 指标,排查重建抖动、VBO 上传、DirectBuffer 占用等问题
更偏“渲染管线时序与 Bloom 顺序保证”的设计/现状说明请看:docs/RenderingSystem_SecureAssets.md
- TESR(
MachineBlockEntitySpecialRenderer)只负责 提交(submit) 渲染任务/缓冲,不直接做 draw。 MachineRenderDispatcher.flush()在 TESR batch 之后统一执行绘制:- 先
DEFAULT(不透明) - 再
TRANSPARENT(半透明) - Bloom 在可用时延后到 GT Bloom 回调阶段(见
GregTechBloomHooks等桥接)
- 先
这个结构的核心目标是:
- 将昂贵的“构建(CPU)”与“绘制(GL 主线程)”解耦
- 用缓存把“每帧重复 upload/draw”压到最低
- 保证跨机器的透明/辉光绘制顺序一致
相关文件:
src/main/kotlin/client/impl/render/task/RenderTaskCache.ktsrc/main/kotlin/client/impl/render/task/RenderTaskOwnerKeys.kt
要点:
- RenderTaskCache 以 key 缓存构建产物,旧结果可继续绘制,新结果在后台构建完成后再替换。
- 为避免热路径
HashMap.getNode + equals()(以及每帧 data-class key 分配)带来的热点:- 引入
RenderTaskOwnerKeys对 owner key 做 intern(规范化复用) OwnerKey以 身份(identity) 作为等价关系(同一个 TE + slot + part),避免昂贵 equals。RenderTaskCache.removeByTe走RenderTaskOwnerKeys.removeByTe(te)的快速清理路径。
- 引入
适用范围:
- 大量 TESR/大结构时,key 访问频繁,HashMap 热点会非常明显。
相关文件:
src/main/kotlin/client/util/BufferBuilderPool.ktsrc/main/kotlin/client/util/NativeBuffers.kt
要点:
- 全局复用
BufferBuilder(其底层是 directByteBuffer),减少频繁 malloc/free 导致的抖动。 - 引入“过大 buffer(oversize)”的保留策略 + 过期/裁剪:
- 避免偶发超大模型把池子撑爆、或反复分配/释放导致 OS 级别的 RSS 抖动。
- HUD 会显示 direct 分配估算/池子占用,用于定位 DirectMemory OOM 与“池子被大 buffer 污染”。
相关文件:
src/main/kotlin/client/util/BufferBuilderVboCache.ktsrc/main/kotlin/client/util/ReusableVboUploader.kt
要点:
- 构建完成后的
BufferBuilder可绑定一个 GPU VBO(缓存上传结果),在缓存命中时避免glBufferData/VertexBuffer.bufferData的重复上传。 - 同时支持 VBO id 池化(减少
glGenBuffers/VertexBuffer.<init>开销),对“主线程 GL churn”热点有明显改善。
相关文件:
src/main/kotlin/client/util/ReusableVboUploader.kt
要点:
- 当需要把多个
BufferBuilder合并为一次 draw 时,优先走 scratch VBO 合并上传:- 小 ring(多个 VBO)减少“同一 VBO 被反复覆盖导致驱动等待”的概率。
- 默认使用 classic orphaning:
glBufferData(size, null)+glBufferSubData(...)。 - 在支持
glMapBufferRange时,可选MAP_RANGE_UNSYNC路径(实现上仍会先 orphan 再 map,避免覆盖 in-flight 数据)。
- 目标是减少 draw call 与减少无谓的 builder->scratch memcpy(支持直接写入 mapped VBO 的 slice 上传路径)。
渲染调优开关统一存放于 API:
src/main/kotlin/api/tuning/RenderTuning.kt
Forge 配置加载与热更新:
src/main/kotlin/common/config/PrototypeMachineryCommonConfig.kt/pm_config:src/main/kotlin/common/command/PmConfigServerCommand.kt
目前已存在的配置分类(category):
render_animationrender_mergerender_vbo_cacherender_gecko
- 进服/进单机后,先用
/pm_render_hud on打开 HUD。 - 使用
/pm_config list查看分类,/pm_config list <category>查看键。 - 用
/pm_config set <category> <name> <value>调整,再观察 HUD 的:- build queue
- cache hit/miss
- VBO bytes / direct bytes
- rebuild 频率
注意:
/pm_config是服务端命令(权限等级 2)。客户端渲染相关开关虽然“只在客户端使用”,但配置文件由服务端/单机一侧加载保存;在多人环境要注意权限与分发策略。
/pm_render_hud on|off|toggle- 指标来源:
RenderStats+RenderDebugHud
HUD 常见用途:
- 判断是否发生 构建抖动(build/s 指标持续很高)
- 判断 VBO cache 是否有效(命中率、重建次数)
- 判断 BufferBuilderPool 是否在反复 new/borrow(池子不足或被 trim)
- 判断动画 key 是否被自动限流(防止 smooth 动画引起的重建风暴)
/pm_render_stress [drawMultiplier]:重复 draw call(压测渲染线程/驱动),并配合动画限流观测。/pm_render_clear_caches [reason]:清空渲染侧缓存(用于验证“缓存命中/失效”是否符合预期)。
- TESR submit:
src/main/kotlin/client/impl/render/binding/MachineBlockEntitySpecialRenderer.kt - Flush 调度:
src/main/kotlin/client/impl/render/MachineRenderDispatcher.kt - HUD:
src/main/kotlin/client/impl/render/RenderDebugHud.kt - 统计:
src/main/kotlin/client/impl/render/RenderStats.kt - BufferBuilder 池:
src/main/kotlin/client/util/BufferBuilderPool.kt - VBO cache:
src/main/kotlin/client/util/BufferBuilderVboCache.kt - 调优对象:
src/main/kotlin/api/tuning/RenderTuning.kt