From 207d03584c542a9b42e484e97e82a882f7555a1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=98=9F=E7=BF=8A?= Date: Sun, 12 Jul 2026 23:50:40 +0800 Subject: [PATCH 1/2] fix(core): preserve instance buffer during resource gc Refs #3064 --- .../core/src/RenderPipeline/InstanceBuffer.ts | 3 +++ .../RenderPipeline/InstanceBuffer.test.ts | 25 +++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 tests/src/core/RenderPipeline/InstanceBuffer.test.ts diff --git a/packages/core/src/RenderPipeline/InstanceBuffer.ts b/packages/core/src/RenderPipeline/InstanceBuffer.ts index 5d0d4368c2..3a7c6fa3f1 100644 --- a/packages/core/src/RenderPipeline/InstanceBuffer.ts +++ b/packages/core/src/RenderPipeline/InstanceBuffer.ts @@ -39,6 +39,9 @@ export class InstanceBuffer { this._intView = new Int32Array(this._data); this.buffer?.destroy(); this.buffer = new Buffer(this._engine, BufferBindFlag.ConstantBuffer, totalBytes, BufferUsage.Dynamic); + // This buffer is owned by BatcherManager rather than a component reference. + // ResourceManager.gc() must not reclaim it while the render pipeline is active. + this.buffer.isGCIgnored = true; } } diff --git a/tests/src/core/RenderPipeline/InstanceBuffer.test.ts b/tests/src/core/RenderPipeline/InstanceBuffer.test.ts new file mode 100644 index 0000000000..635ed15276 --- /dev/null +++ b/tests/src/core/RenderPipeline/InstanceBuffer.test.ts @@ -0,0 +1,25 @@ +import { WebGLEngine } from "@galacean/engine"; +import { afterEach, describe, expect, it } from "vitest"; + +describe("InstanceBuffer", () => { + let engine: WebGLEngine | undefined; + + afterEach(() => { + engine?.destroy(); + engine = undefined; + }); + + it("keeps its engine-owned buffer alive across resource-manager garbage collection", async () => { + engine = await WebGLEngine.create({ canvas: document.createElement("canvas") }); + const instanceBuffer = engine._batcherManager.instanceBuffer; + instanceBuffer.setLayout({ instanceFields: [], instanceMaxCount: 1, structSize: 16 }); + const buffer = instanceBuffer.buffer; + + engine.resourceManager.gc(); + + expect(buffer.destroyed).toBe(false); + + engine._batcherManager.destroy(); + expect(buffer.destroyed).toBe(true); + }); +}); From 882db26c963b220636c4cbbba6a422b1df19d943 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=98=9F=E7=BF=8A?= Date: Sat, 18 Jul 2026 00:14:26 +0800 Subject: [PATCH 2/2] chore(core): remove instance buffer comments --- packages/core/src/RenderPipeline/InstanceBuffer.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/core/src/RenderPipeline/InstanceBuffer.ts b/packages/core/src/RenderPipeline/InstanceBuffer.ts index 3a7c6fa3f1..6dbd2cb250 100644 --- a/packages/core/src/RenderPipeline/InstanceBuffer.ts +++ b/packages/core/src/RenderPipeline/InstanceBuffer.ts @@ -39,8 +39,6 @@ export class InstanceBuffer { this._intView = new Int32Array(this._data); this.buffer?.destroy(); this.buffer = new Buffer(this._engine, BufferBindFlag.ConstantBuffer, totalBytes, BufferUsage.Dynamic); - // This buffer is owned by BatcherManager rather than a component reference. - // ResourceManager.gc() must not reclaim it while the render pipeline is active. this.buffer.isGCIgnored = true; } }