Skip to content

fix(device): drain GPU work before teardown#264

Merged
kolkov merged 1 commit into
gogpu:mainfrom
besmpl:besmpl/release-drain
Jul 22, 2026
Merged

fix(device): drain GPU work before teardown#264
kolkov merged 1 commit into
gogpu:mainfrom
besmpl:besmpl/release-drain

Conversation

@besmpl

@besmpl besmpl commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Summary

Make Device.Release wait for the HAL device to become idle before releasing pending writes, flushing deferred destruction, destroying pooled encoders, and finally destroying the core/HAL device.

The public WaitIdle method still rejects calls after release. Teardown uses a private waitIdle path because Release marks the device unavailable first, preventing concurrent new work while the final submission is drained.

Why

The previous order set the released bit and then called the public WaitIdle, which immediately returned ErrReleased. Deferred encoder-recycling callbacks could therefore remain queued while HAL destruction reclaimed the same command pools.

Validation

  • go test ./...
  • go test -race .
  • a lifecycle test proves WaitIdle happens before HAL Destroy

This is intentionally separate from the Android work; it fixes native teardown ordering on every backend.

Android integration relationship

This Android-independent change is one of five prerequisites replayed in #268. Its canonical candidate head is 6acfb1ea1cca1dc14d7ab0902931c678dc13e0a6; the corresponding replay in #268 ends at b2842f068d80d22eae297059aa983965965a9151. The #268 description records the current exact integration head and full replay map; it drops this replay after this PR merges. Rust-v29 typed surface parity remains separate in #273. Android runtime and release claims remain in #268.

@besmpl

besmpl commented Jul 15, 2026

Copy link
Copy Markdown
Contributor Author

Stacked consumer preview: #268 at exact head b11d2671e80081a191705c41c4e77e8b61472017 incorporates this PR's head 0ed17064f8c977f35d9b49b5cde0d0c69e867ecf (matching stable patch ID).

The preview remains explicitly draft/non-mergeable and will be rebased to Android-only commits after this prerequisite lands.

@besmpl
besmpl force-pushed the besmpl/release-drain branch from 0ed1706 to 6acfb1e Compare July 19, 2026 07:14
@codecov

codecov Bot commented Jul 19, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@kolkov kolkov 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.

Good catch. The released flag was short-circuiting WaitIdle() during Release(), meaning the GPU was never actually drained before staging buffers and encoders were destroyed — a real use-after-free risk on all backends, though most drivers mask it with internal refcounting.

The private waitIdle() approach is clean: preserves the public API guard while allowing teardown to drain properly. The reorder of queue.release() to after waitIdle() matches Rust wgpu's Queue::Drop ordering where pending_writes is dropped after the fence wait completes (queue.rs:53, 157-251).

The lifecycle test with noop backend embedding is a solid way to assert the [wait-idle, destroy] invariant without requiring real GPU hardware.

LGTM.

@kolkov
kolkov merged commit e96d691 into gogpu:main Jul 22, 2026
11 checks passed
kolkov added a commit that referenced this pull request Jul 22, 2026
* docs: update CONTRIBUTING.md — Smart Coding framework, AI-assisted policy, current project structure

* docs: CHANGELOG for merged prerequisite PRs (#264, #265, #266, #267, #269)
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