Skip to content

fix(webgpu): reset batchers when a frame is abandoned - #1609

Merged
obiot merged 2 commits into
masterfrom
webgpu-abandonframe-batchers
Aug 28, 2026
Merged

fix(webgpu): reset batchers when a frame is abandoned#1609
obiot merged 2 commits into
masterfrom
webgpu-abandonframe-batchers

Conversation

@obiot

@obiot obiot commented Aug 28, 2026

Copy link
Copy Markdown
Member

abandonFrame() finishes the command encoder without submitting, then frees every texture retired during that frame — correct in itself, since the draws referencing them died with the buffer:

this.currentPipeline = null;
// the recorded draws are dropped with the command buffer, so any
// texture retired during the frame can go now
this.destroyRetiredTextures();

But the batchers were left untouched, and a quad batcher's segmentEntries holds GPUTextureViews into exactly those textures. The next frame's composeSegmentGroup could then build a bind group over destroyed resources.

How it's reached

Any frame abandoned after a texture was replaced or unloaded mid-frame. A stage switch freeing the previous scene's assets is the ordinary way in — destroyTexture and the GPU_TEXTURE_CACHE_RESET handler both retire textures, and the batcher keeps its segment entries until its next flush, which an abandoned frame never reaches.

The normal submit path is safe: flush() resets the segment before queue.submit() frees anything. Only the abandon path skips that.

Fix

Reset every registered batcher before the retired textures are freed. That also drops the dead frame's queued vertices, current effect and material, and composed bind groups — none of which should replay into the next frame.

Tests

Three, using the established stub pattern in webgpu_mesh_depth.spec.js:

  • the reset happens before destroyRetiredTextures(), asserted on call order — getting this backwards frees the textures while entries still reference them
  • every registered batcher is reset, not just the quad one
  • the existing abandonFrame test, updated for the new batchers dependency

Two mutations, each caught: removing the reset (2 failures) and reordering it after the destroy (1).

Provenance

Found by an adversarial review of #1608, which flagged it as pre-existing and memo-neutral. Present on master since the backend landed; not a regression from any current PR.

Full suite 6331 passing / 262 files, root lint 0 errors.

🤖 Generated with Claude Code

https://claude.ai/code/session_012Aa37KGXZcnVrbn1yG4j1N

`abandonFrame()` finishes the command encoder without submitting, then frees
every texture retired during that frame — correct, since the draws referencing
them died with the buffer. But the batchers were left untouched, and a quad
batcher's segment entries hold `GPUTextureView`s into exactly those textures.
The next frame could then compose a bind group over destroyed resources.

Reached whenever a frame is abandoned after a texture was replaced or unloaded
mid-frame; a stage switch freeing the previous scene's assets is the ordinary
way in.

Every registered batcher is now reset before the retired textures are freed.
That also drops the dead frame's queued vertices, current effect and material,
and composed bind groups, none of which should replay into the next frame.

Found by an adversarial review of an unrelated change, and present on master
since the backend landed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012Aa37KGXZcnVrbn1yG4j1N
Copilot AI lite review requested due to automatic review settings August 28, 2026 06:09

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

None of those three entries were API changes. Two were consequences of what
the release ADDED — a scene that already set one of the six modes now renders
it — and the third records that 3D mesh rendering is UNCHANGED, which is the
opposite of a change.

The two substantive caveats, the per-draw capture and composite cost and the
drawMesh fallback, move onto the Added entry they belong to. `### Changed` is
for user-facing API changes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012Aa37KGXZcnVrbn1yG4j1N
Copilot AI review requested due to automatic review settings August 28, 2026 06:15

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@obiot
obiot merged commit 5e17030 into master Aug 28, 2026
8 of 9 checks passed
@obiot
obiot deleted the webgpu-abandonframe-batchers branch August 28, 2026 06:38
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