Skip to content

fix(core): preserve instance buffer during resource gc#3065

Open
sun-nocat wants to merge 1 commit into
dev/2.0from
xingyi/fix-instance-buffer-gc
Open

fix(core): preserve instance buffer during resource gc#3065
sun-nocat wants to merge 1 commit into
dev/2.0from
xingyi/fix-instance-buffer-gc

Conversation

@sun-nocat

@sun-nocat sun-nocat commented Jul 12, 2026

Copy link
Copy Markdown

Summary

  • keep the render pipeline's engine-owned instance buffer alive during ordinary resource-manager garbage collection
  • preserve explicit buffer destruction through BatcherManager.destroy() and engine teardown
  • add a focused Chromium regression test for both lifetime guarantees

Root cause

InstanceBuffer retained its GPU Buffer through 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 destroyed GLBuffer, causing repeated bindBuffer failures and WebGL context loss.

Validation

  • HEADLESS=true pnpm exec vitest run tests/src/core/RenderPipeline/InstanceBuffer.test.ts
  • pnpm run b:module
  • pnpm run b:types
  • pnpm run lint (0 errors)
  • git diff --check

Fixes #3064

Summary by CodeRabbit

  • Bug Fixes

    • Prevented active rendering buffers from being prematurely reclaimed during resource cleanup.
    • Ensured buffers are released correctly when the rendering system is shut down.
  • Tests

    • Added coverage verifying buffer persistence during cleanup and proper destruction during teardown.

@sun-nocat sun-nocat requested a review from GuoLei1990 July 12, 2026 15:55
@coderabbitai

coderabbitai Bot commented Jul 12, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 8f8aa2ea-a535-408b-b16a-5ebd09a1b39d

📥 Commits

Reviewing files that changed from the base of the PR and between 75af66f and 207d035.

📒 Files selected for processing (2)
  • packages/core/src/RenderPipeline/InstanceBuffer.ts
  • tests/src/core/RenderPipeline/InstanceBuffer.test.ts

Walkthrough

InstanceBuffer.setLayout() marks its allocated buffer as ignored by resource garbage collection. A regression test verifies that GC preserves the buffer and that batcher destruction eventually releases it.

Changes

Instance buffer lifetime

Layer / File(s) Summary
GC lifetime and regression coverage
packages/core/src/RenderPipeline/InstanceBuffer.ts, tests/src/core/RenderPipeline/InstanceBuffer.test.ts
Allocated instance buffers are excluded from ordinary GC, and tests verify survival through GC followed by destruction during batcher teardown.

Estimated code review effort: 1 (Trivial) | ~5 minutes

Poem

I’m a bunny with buffers tucked safely away,
GC hops past them through each busy day.
When the batcher says, “Time to depart,”
They’re cleaned up neatly, right from the start.
Hop, hop—safe rendering!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: keeping InstanceBuffer alive during resource GC.
Linked Issues check ✅ Passed The fix marks the engine-owned buffer as GC-ignored and adds a regression test covering GC survival and explicit destruction.
Out of Scope Changes check ✅ Passed The only code changes are the targeted lifetime fix and its regression test, with no unrelated scope creep.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch xingyi/fix-instance-buffer-gc

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Jul 12, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 79.54%. Comparing base (75af66f) to head (207d035).

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              
Flag Coverage Δ
unittests 79.54% <100.00%> (+0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@GuoLei1990 GuoLei1990 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

总结

InstanceBuffer 持有的 BufferBatcherManager 引擎侧直属对象、_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 的资源跳过 destroyResourceManager.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=0destroy(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/:66PrimitiveChunk.tsBasicRenderPipeline.ts 皆然)。吹毛求疵,不阻塞。

干净的小修复,落点在根因层,测试是链路金标准。LGTM。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants