fix(core): preserve instance buffer during resource gc#3065
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
Walkthrough
ChangesInstance buffer lifetime
Estimated code review effort: 1 (Trivial) | ~5 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## dev/2.0 #3065 +/- ##
===========================================
+ Coverage 79.52% 79.54% +0.01%
===========================================
Files 904 904
Lines 101168 101171 +3
Branches 11377 11381 +4
===========================================
+ Hits 80456 80476 +20
+ Misses 20528 20511 -17
Partials 184 184
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
GuoLei1990
left a comment
There was a problem hiding this comment.
总结
InstanceBuffer 持有的 Buffer 是 BatcherManager 引擎侧直属对象、_refCount 恒为 0 且此前无 isGCIgnored,因此暴露在 ResourceManager._gc() 面前——被回收后渲染管线仍复用已销毁的 wrapper,触发 bindBuffer 失败与 WebGL context loss(issue #3064,SwiftShader 可复现,严重)。修复给新建 buffer 打上 isGCIgnored = true,与引擎既有惯例完全一致,方向正确。
逐点核对(无 P0/P1/P2)
- 根因/机制正确:
Buffer extends GraphicsResource extends ReferResource,构造即注册进_referResourcePool(_gc遍历的池),_refCount=0且无 holder ⇒ 是_gc的销毁候选。_gc(false)对isGCIgnored的资源跳过destroy(ResourceManager.ts:506),修复精确命中。 - 惯例一致:与
ParticleGenerator.ts:547的 vertex instance buffer、ParticleBufferUtils.ts:85/95、RenderTargetPool、joint texture 等同一isGCIgnored模式;不是新机制。 - realloc 跟随:
setLayout增长时销毁旧 buffer + 新建,isGCIgnored=true每次都打在新 buffer 上,标记随当前 buffer 迁移,正确。 - 显式销毁不受影响:
BatcherManager.destroy() → InstanceBuffer.destroy() → buffer.destroy()是直接销毁路径,绕过 GC gate,teardown 正常。 - 修复完整:兄弟
PrimitiveChunk的 vertex/index buffer 由持有它们的Primitive._addReferCount(1)(PrimitiveChunk.ts:45)保护,本就不在_gc回收面,无需同类标记——本 PR 只需修InstanceBuffer这一处 refCount-less 的裸 buffer。 - 测试反向可证伪:
gc()后断言buffer.destroyed===false(无修复则_refCount=0被destroy(false,true)回收 ⇒destroyed===true⇒ FAIL);batcherManager.destroy()后断言destroyed===true,两条生命周期保证都守住。CI 全绿(build×3 / e2e 4/4 / lint / 单测)。
问题
- [P3] InstanceBuffer.ts:42-44 — 新增两行
//注释末尾都带句号(...component reference./...pipeline active.)。本目录//注释惯例为不加句号(同文件:35/:65/:66、PrimitiveChunk.ts、BasicRenderPipeline.ts皆然)。吹毛求疵,不阻塞。
干净的小修复,落点在根因层,测试是链路金标准。LGTM。
Summary
BatcherManager.destroy()and engine teardownRoot cause
InstanceBufferretained its GPUBufferthrough a plain engine-owned field, so it had no component reference count. Because the buffer was not excluded from ordinary resource GC,ResourceManager.gc()could destroy it while the render pipeline still held and reused the wrapper. The next upload then reached a destroyedGLBuffer, causing repeatedbindBufferfailures and WebGL context loss.Validation
HEADLESS=true pnpm exec vitest run tests/src/core/RenderPipeline/InstanceBuffer.test.tspnpm run b:modulepnpm run b:typespnpm run lint(0 errors)git diff --checkFixes #3064
Summary by CodeRabbit
Bug Fixes
Tests