From c1dd8dbae03cf921714a62720b492fbefba7bc8d Mon Sep 17 00:00:00 2001 From: SweetSophia Date: Fri, 4 Sep 2026 21:14:45 +0200 Subject: [PATCH 1/3] fix: do not delete pooled offscreen GPU objects on release CubismOffscreenRenderTarget_WebGL borrows colorBuffer and framebuffer from CubismWebGLOffscreenManager. release() already returns the slot via stopUsingRenderTexture(); deleting the GPU objects here double-frees the pool and can delete previousFramebuffer when it was stored as a fallback. Clear local handles only. The manager still owns deleteTexture / deleteFramebuffer on stale trim and context teardown. --- src/rendering/cubismoffscreenrendertarget_webgl.ts | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/rendering/cubismoffscreenrendertarget_webgl.ts b/src/rendering/cubismoffscreenrendertarget_webgl.ts index d1efae0..c1b9792 100644 --- a/src/rendering/cubismoffscreenrendertarget_webgl.ts +++ b/src/rendering/cubismoffscreenrendertarget_webgl.ts @@ -215,14 +215,12 @@ export class CubismOffscreenRenderTarget_WebGL extends CubismRenderTarget_WebGL ); } - if (this._colorBuffer && this._gl) { - this._gl.deleteTexture(this._colorBuffer); - this._colorBuffer = null; - } - if (this._renderTexture && this._gl) { - this._gl.deleteFramebuffer(this._renderTexture); - this._renderTexture = null; - } + // Color buffer and framebuffer are borrowed from CubismWebGLOffscreenManager. + // The manager owns GPU lifetime (releaseStaleRenderTextures / context teardown). + // Deleting them here double-frees the pool slot and can delete previousFramebuffer + // when setOffscreenRenderTarget stored it as a fallback. + this._colorBuffer = null; + this._renderTexture = null; if (this._webGLOffscreenManager != null) { this._webGLOffscreenManager = null; From 44f7512fc85521fe5fa0496208411a4ed96d193b Mon Sep 17 00:00:00 2001 From: SweetSophia Date: Sat, 5 Sep 2026 03:16:06 +0200 Subject: [PATCH 2/3] fix: destroy locally owned offscreen targets on release release() must not delete GPU objects borrowed from CubismWebGLOffscreenManager. Instances initialized via inherited createRenderTarget() still own their texture/FBO, so destroy those locally created resources instead of dropping the only references. --- .../cubismoffscreenrendertarget_webgl.ts | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/rendering/cubismoffscreenrendertarget_webgl.ts b/src/rendering/cubismoffscreenrendertarget_webgl.ts index c1b9792..1bb2254 100644 --- a/src/rendering/cubismoffscreenrendertarget_webgl.ts +++ b/src/rendering/cubismoffscreenrendertarget_webgl.ts @@ -204,8 +204,10 @@ export class CubismOffscreenRenderTarget_WebGL extends CubismRenderTarget_WebGL } public release(): void { + const borrowedFromManager = this._webGLOffscreenManager != null; + if ( - this._webGLOffscreenManager != null && + borrowedFromManager && this._gl != null && this._renderTexture != null ) { @@ -215,12 +217,18 @@ export class CubismOffscreenRenderTarget_WebGL extends CubismRenderTarget_WebGL ); } - // Color buffer and framebuffer are borrowed from CubismWebGLOffscreenManager. - // The manager owns GPU lifetime (releaseStaleRenderTextures / context teardown). - // Deleting them here double-frees the pool slot and can delete previousFramebuffer - // when setOffscreenRenderTarget stored it as a fallback. - this._colorBuffer = null; - this._renderTexture = null; + if (borrowedFromManager) { + // Color buffer and framebuffer are borrowed from CubismWebGLOffscreenManager. + // The manager owns GPU lifetime (releaseStaleRenderTextures / context teardown). + // Deleting them here double-frees the pool slot and can delete previousFramebuffer + // when setOffscreenRenderTarget stored it as a fallback. + this._colorBuffer = null; + this._renderTexture = null; + } else if (this._gl) { + // Inherited createRenderTarget() locally owns the texture/FBO + // (_modelRenderTargets). destroyRenderTarget() is the matching owner. + this.destroyRenderTarget(); + } if (this._webGLOffscreenManager != null) { this._webGLOffscreenManager = null; From ed4fb81385a0a6c4a41bc532051275b0c8705812 Mon Sep 17 00:00:00 2001 From: SweetSophia Date: Sat, 5 Sep 2026 03:27:58 +0200 Subject: [PATCH 3/3] fix: do not destroy pooled offscreen targets in renderer teardown CubismRenderer_WebGL.release() called destroyRenderTarget() on _offscreenList, which are borrowed from CubismWebGLOffscreenManager via setOffscreenRenderTarget(). That deleted pool GPU objects and could delete previousFramebuffer. Route teardown through release() so borrowed handles are returned, not destroyed. --- src/rendering/cubismrenderer_webgl.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/rendering/cubismrenderer_webgl.ts b/src/rendering/cubismrenderer_webgl.ts index 9520878..293ebe7 100644 --- a/src/rendering/cubismrenderer_webgl.ts +++ b/src/rendering/cubismrenderer_webgl.ts @@ -741,7 +741,8 @@ export class CubismRenderer_WebGL extends CubismRenderer { for (let i = 0; i < this._offscreenList.length; i++) { if (this._offscreenList[i] != null && this._offscreenList[i].isValid()) { - this._offscreenList[i].destroyRenderTarget(); + // プールから借用した GPU オブジェクトは destroy しない + this._offscreenList[i].release(); } } this._offscreenList.length = 0;