Skip to content

release: v0.34.10 - #387

Merged
kolkov merged 4 commits into
mainfrom
release/v0.34.10
Nov 8, 2026
Merged

kolkov merged 4 commits into
mainfrom
release/v0.34.10

Conversation

@kolkov

@kolkov kolkov commented Nov 8, 2026

Copy link
Copy Markdown
Contributor

A patch for frame-batching consumers and a security update of naga.

Fixed

  • Queue.Submit accepts resources released after recording (P1-CORE-020, gogpu#461). Release() on a texture, texture view, bind group or buffer is a drop, not WebGPU's destroy(): the command buffer that recorded the resource holds a reference and keeps it alive until its work completes, as Rust wgpu does. Submit rejected such a command buffer with ErrSubmitTextureDestroyed, ErrSubmitBufferDestroyed or ErrSubmitBindGroupDestroyed, so an application that records a frame into one encoder and releases resources before the frame's submit got an error and an empty frame. Submit now rejects only work that can no longer run (a lost device, an ended surface acquisition); a texture released after a Queue.WriteTexture still receives the write, and still gets its barriers.
  • A sampler stays alive while a bind group that binds it can still be used. Sampler.Release destroyed the sampler after the last submitted work, even while a recorded but not yet submitted bind group named it (a use-after-free on Vulkan, VUID-vkDestroySampler-sampler-01082). Samplers are now reference counted, and a bind group holds its samplers as it holds its texture views. CreateBindGroup rejects a released sampler with ErrReleased.
  • A texture view keeps its texture alive, as in Rust wgpu. A texture released while a view of it was still in use was destroyed under work recorded through the view afterwards (VUID-vkDestroyImage-image-01000).
  • Device release destroys every deferred resource, including the textures, views and samplers that a destroyed bind group or view was the last to hold.
  • Vulkan: bind groups with dynamic-offset buffers allocate from valid descriptor pools (P2-VK-016, found in gogpu#461). A layout with a dynamic uniform or storage buffer could get its descriptor set from a pool created without that descriptor type: the validation layer reported WARNING-CoreValidation-AllocateDescriptorSets-WrongType, and drivers that follow VK_KHR_maintenance1 fail the allocation. Every pool now holds both dynamic buffer types.

Security

  • naga v0.21.5: fixes an out-of-memory denial of service where a ~200-byte WGSL swizzle chain made the shader parser allocate without bound (naga P1-WGSL-109; in every naga since v0.15.0).

Known issues

  • A QuerySet and a PipelineLayout released while submitted work still uses them can be destroyed before that work completes (the query set after ResolveQuerySet or timestamp writes; the layout under later SetBindGroup calls on a pipeline created from it). Until the next patch, keep both alive until the submissions that use them have completed.

…plers outlive their users

Release() is Rust's drop, not WebGPU's destroy() (ADR-056): recorded work holds
a reference, so the resource stays alive until that work completes. Submit
rejected a command buffer whose texture, view, bind group or buffer had been
released after recording, because its validation read the user's release flag.
A consumer that records a frame into one encoder and frees resources before
the frame's submit (gogpu#461) got ErrSubmit*Destroyed and an empty frame.

Submit now rejects only what can no longer run, as Rust wgpu-core's
check_destroyed / try_inner / try_raw do (device/queue.rs:2130-2180): a buffer
whose HAL buffer is gone, a texture whose device is gone or whose surface
acquisition ended, or a resource without a reference count that Release
already destroyed. Texture.recordedHAL is the boundary for recorded work; the
submit-time barrier resolver and the pending-write flush use it too, so a
released texture still gets its barriers and its queued writes.

The old Submit check had been hiding three lifetime holes, now closed:
- Sampler.Release destroyed the HAL sampler after the last submitted work,
  while a recorded but unsubmitted bind group still named it
  (VUID-vkDestroySampler-sampler-01082). Samplers are reference counted, a
  bind group holds each sampler it binds (Rust BindGroup holds Arc<Sampler>),
  and CreateBindGroup rejects a released sampler instead of reviving it.
- A texture view did not hold its texture, so a texture released while a view
  was alive was destroyed under work recorded through the view later
  (VUID-vkDestroyImage-image-01000). The view now holds its texture's
  reference, as Rust's TextureView holds Arc<Texture> parent.
- DestroyQueue.FlushAll ran one pass, so a destroy that released the next
  link of a chain (bind group -> view -> texture) at device release left it
  undestroyed. It now repeats until the queue is empty.

Tests, each failing on the code before it: hal/allbackends
TestReleaseBeforeSubmit{BufferCopy,TextureCopy,BindGroup},
TestReleaseTextureWhileViewAlive and TestReleasedSamplerCannotBeBound read
back results on every backend, with the Vulkan synchronization validation
layer failing on any error; core TestDestroyQueue_FlushAllDrainsChains. The
submit validation tests that asserted the old behaviour now assert the new
one; the two that pinned the precedence between bind-group and resource errors
are removed with the bind-group release check.
naga v0.21.5 fixes P1-WGSL-109: a ~200-byte WGSL swizzle chain made the
parser allocate without bound (out-of-memory denial of service), in every naga
since v0.15.0, v0.21.4 included. naga's gate showed byte-identical output on
291 shaders, so this is a plain dependency update.
Descriptor pools are shared between bind group layouts: Allocate serves a
layout from any existing pool first, so every pool carries every descriptor
type. The dynamic uniform and storage buffer types were the exception, added
only when the layout that created the pool used them. A layout with a dynamic
buffer then got its set from a pool without that type: the validation layer
reports WARNING-CoreValidation-AllocateDescriptorSets-WrongType, and drivers
that follow VK_KHR_maintenance1 return VK_ERROR_OUT_OF_POOL_MEMORY. Found by
gogpu's Vulkan validation run of its frame batching (gogpu#461).

Both dynamic types now get a baseline in every pool, as storage images do;
Rust wgpu-hal sizes its pools from descriptor counts that include them.

The allbackends Vulkan validation capture now fails a test on validation
warnings too, not only errors: the layer reports this spec violation as a
warning, which is why the suite never saw it.
TestDynamicBufferBindGroupsAfterPlainOnes fails on the code before.
@codecov

codecov Bot commented Nov 8, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 85.93750% with 9 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
sampler_native.go 75.00% 2 Missing and 1 partial ⚠️
device_native.go 90.47% 1 Missing and 1 partial ⚠️
queue_native.go 66.66% 1 Missing and 1 partial ⚠️
texture_native.go 80.00% 0 Missing and 2 partials ⚠️

📢 Thoughts on this report? Let us know!

@kolkov
kolkov merged commit 22f0497 into main Nov 8, 2026
16 checks passed
@kolkov
kolkov deleted the release/v0.34.10 branch November 8, 2026 11:40
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.

1 participant