Major changes
Optional vertex buffer slots
This allows gaps in VertexState's buffers and adds support for unbinding vertex buffers, bringing us in compliance with the WebGPU spec. As a result of this, VertexState's buffers field now has type of &[Option<VertexBufferLayout>]. To migrate, wrap vertex buffer layouts in Some:
let vertex_state = wgpu::VertexState {
module: &vs_module,
entry_point: Some("vs_main"),
compilation_options: wgpu::PipelineCompilationOptions::default(),
buffers: &[
- &vertex_buffer_layout
+ Some(&vertex_buffer_layout)
],
};Integer shader I/O no longer defaults to @interpolate(flat)
To align with the shading language specifications, naga no longer assumes that integer-typed shader I/O should have flat interpolation, i.e., should not be interpolated. Even though flat interpolation is the only choice for integer I/O, it must be still specified explicitly.
WGSL:
struct FragmentInput {
@location(0) tex_coord: vec2<f32>,
- @location(1) index: i32,
+ @location(1) @interpolate(flat) index: i32,
}GLSL:
-layout(location = 1) in int index;
+layout(location = 1) flat in int index;By @andyleiserson in #9321.
Empty buffer slices are now permitted
Creating a BufferSlice with a length of 0 no longer causes a panic.
Empty buffer slices can be:
- Instantiated
- Mapped (the result is an empty slice of bytes)
Empty buffer slices cannot be:
- Used in buffer bindings
- Passed to
set_index_bufferorset_vertex_buffer
#3170 tracks making it possible to pass a zero-size BufferSlice to set_vertex_buffer and set_index_buffer in the future.
Zero-size buffer bindings are still not permitted. BufferBinding and BindingResource now implement TryFrom<BufferSlice> instead of From<BufferSlice>. The TryFrom conversion will fail if the slice is zero-size.
-let slice = buffer.slice(0..0); // panic!
-let mapping = BufferBinding::from(slice); // infallible
+let slice = buffer.slice(0..0); // okay
+let mapping = BufferBinding::try_from(slice).unwrap(); // panicRelatedly, BufferSlice::size() now returns BufferAddress (u64) instead of BufferSize (NonZero<u64>), since an empty slice has size 0.
By @beholdnec in #8505.
Surface color space selection (HDR output)
Surfaces can now be configured with an explicit color space, enabling HDR and wide-gamut output where the platform supports it. SurfaceConfiguration has a new color_space field, and SurfaceCapabilities reports the supported color spaces for every supported format in a new format_capabilities field. SurfaceColorSpace::is_hdr() classifies a color space (the extended-range and PQ/HLG spaces are HDR) so you can branch after picking one.
The new SurfaceColorSpace::Auto default reproduces wgpu's historical behavior (extended linear scRGB for Rgba16Float where supported, sRGB otherwise; never a wide-gamut or HDR color space). To migrate, add the field:
let config = wgpu::SurfaceConfiguration {
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
format: surface_format,
+ color_space: wgpu::SurfaceColorSpace::Auto,
..
};Support by backend:
| Color space / feature | Vulkan | DX12 | Metal | WebGPU | GLES |
|---|---|---|---|---|---|
Srgb |
✅ | ✅ | ✅ | ✅ | ✅ |
ExtendedSrgb |
✅¹ | ❌ | ✅ | ✅ | ❌ |
ExtendedSrgbLinear (scRGB) |
✅¹ | ✅ | ✅ | ❌ | ❌ |
DisplayP3 |
✅¹ | ❌ | ✅ | ✅ | ❌ |
ExtendedDisplayP3 |
❌ | ❌ | ✅ | ✅ | ❌ |
Bt2100Pq (HDR10) |
✅¹ | ✅ | ✅ | ❌ | ❌ |
Bt2100Hlg |
✅¹ | ❌ | ✅ | ❌ | ❌ |
¹ Vulkan support for extended color spaces depends on the driver/platform.
The current state of HDR on the current monitor can be queried with Surface::display_hdr_info.
For wgpu-hal users: hal::SurfaceConfiguration gained a color_space field (never Auto), and hal::SurfaceCapabilities::formats is now Vec<SurfaceFormatCapabilities> instead of Vec<TextureFormat>.
A new standalone example, examples/standalone/03_hdr_surface, prints a surface's (format, color space) capabilities and renders an HDR luminance test pattern through the most capable color space available.
By @stuartparmenter in #9658.
New naga-types crate
To better re-use code between internal crates and prepare for future additions, there is a new crate called naga-types which contains some useful datatypes used by naga and wgpu, without pulling in naga itself.
Some types have changed canonical locations, but are re-exported in their previous places, so there should not be any breaking changes caused by this.
By @inner-daemons in #9434.
Added/New Features
General
- Add
StagingBelt::finish_and_recall_on_submit, a convenience that combinesfinishandrecallby deferring the buffer re-map viaCommandEncoder::map_buffer_on_submit, so no explicitrecall()call is needed after submission. By @ruihe774. - Implement
i16/u1616-bit integer support in WGSL shaders, gated behindFeatures::SHADER_I16andenable wgpu_int16;. Supported on Vulkan, Metal, and DX12 (SM 6.2+). By @JMS55 in #9412. - Add BLAS support for procedural AABB geometry (
BlasGeometrySizeDescriptors::AABBs,BlasAabbGeometry, and related descriptors). By @dylanblokhuis in #9290 - Added "limit bucketing" functionality which can adjust adapter limits and features to match one of several pre-defined buckets. This is controlled by the new
apply_limit_bucketsmember inRequestAdapterOptions, which isfalseby default. By @andyleiserson in #9119. - Make
wgpu_types::texture::format::TextureChannelaccessible aswgpu::TextureChannel. By @TornaxO7 in #9349. - Add support for
per_vertexin Metal and DX12, as well as some validation forper_vertex, and a new enable extension,wgpu_per_vertex. By @inner-daemons in #9219. - Add
ComputePassversion ofCommandEncoder::transition_resourcesthat allows intra-pass transitions. By @wingertge in #9371. Device::create_texture_from_halnow takes an explicitinitial_state: wgt::TextureUsesparameter declaring the state the wrapped foreign resource is already in. Previously the tracker hard-codedTextureUses::UNINITIALIZEDfor the wrapped texture, which is a content-discarding transition under the Vulkan spec. This affected zero-copy hardware-decoded video imports on the platforms where compressed modifiers are used. To migrate, passwgpu::TextureUses::UNINITIALIZEDto preserve the previous behaviour:By @AdrianEddy in #9496.let texture = unsafe { - device.create_texture_from_hal::<Vulkan>(hal_texture, &desc) + device.create_texture_from_hal::<Vulkan>(hal_texture, &desc, wgpu::TextureUses::UNINITIALIZED) };- Add
as_customto many new API types and exposeTlas::lowest_unmodified(letting custom backends perform partial TLAS updates), increasing the capabilities of custom backends. Also fixed render bundles on custom backends. By @inner-daemons in #9605. - Extend
copy_texture_to_textureto allow copying a single plane of a multi-planar source (NV12, P010) into a single-plane destination of the matching format (e.g. NV12Plane0→R8Unorm, NV12Plane1→Rg8Unorm).copy_sizeis interpreted in plane texels, not luma texels. By @AdrianEddy in #9551. - Added
InstanceFlags::STRICT_WEBGPU_COMPLIANCEflag, which restricts the available feature set to the one defined by the WebGPU specification. By @teoxoy in #9586. - Implemented
QuerySet::destroyby @sagudev in #9671 - Add
QuerySet::tyandQuerySet::countgetters. By @sagudev in #9672. - Implemented query set initialization tracking, ensuring unwritten query slots resolve to 0; avoiding UB. By @teoxoy in #9664.
- Add
Surface::display_hdr_info, a read-only snapshot of the backing display's HDR characteristics (luminance in nits, EDR headroom, primaries, bit depth, and a coarse dynamic-range/gamut bucket) for tone-mapping.DisplayHdrInfo::tone_map_headroom()folds it into the one multiplier most tone-mappers want; whether to request an HDR surface at all is a separate, capability question answered bySurfaceCapabilities, not by this live value. Populated on DX12 and Vulkan on Windows, Metal on macOS, and the web. By @stuartparmenter. - Added
Limits::max_buffers_and_acceleration_structures_per_shader_stage, a combined limit for all buffer types (storage, uniform, vertex buffers, and acceleration structures) that share Metal's buffer argument table. On Metal withoutInstanceFlags::STRICT_WEBGPU_COMPLIANCEset, the new limit and the individual per-type limits (max_storage_buffers_per_shader_stage,max_uniform_buffers_per_shader_stage,max_vertex_buffers,max_acceleration_structures_per_shader_stage) are set to 29. By @teoxoy in #9709.
naga
- Add
spirv-outray tracing pipelines. By @Vecvec in #9085. - Add
naga::front::wgsl::ParseError::notes(). By @kwillemsen in #9572. - Add MSL support for cooperative matrix multiply-add with lower-precision A/B operands and a higher-precision accumulator/result, such as
coopMultiplyAdd(f16, f16, f32) -> f32. By @seddonm1 in #9629.
DX12
- Added support for mesh shaders in naga's HLSL writer, completing DX12 support for mesh shaders. By @inner-daemons in #8752.
- Added
dx12::Queue::add_wait_fence/add_signal_fence(and matchingremove_*companions). They stageID3D12CommandQueue::Wait/Signalcalls on the nextQueue::submit. The wait calls are issued before the submit'sExecuteCommandLists, the signal calls after wgpu's ownSignal(signal_fence, signal_value). Cross-API interop crates use this to GPU-side gate / publish wgpu submits against foreign-API fences. By @AdrianEddy in #9463. - Added
dx12::Texture::with_plane_sliceso cross-API importers can wrap one plane of a multi-plane DXGI resource (e.g.DXGI_FORMAT_NV12) as a single-plane wgpu texture. By @AdrianEddy in #9551.
Vulkan
- Add
vulkan::Queue::add_wait_semaphoreandvulkan::Queue::remove_wait_semaphore. Lets external producers (CUDA / OpenCL / D3D12 imported viaVK_KHR_external_semaphore_*) be waited on at the nextQueue::submitcall without a CPU block. By @AdrianEddy in #9461. - Add
vulkan::Device::texture_from_dmabuf_fd()for importing DMA-buf textures on Linux, withVULKAN_EXTERNAL_MEMORY_FDandVULKAN_EXTERNAL_MEMORY_DMA_BUFfeature flags. By @todo in #9412. - Add support for
RawWindowHandle::Drmon Unix, conditional on thedrmfeature.- DRM support by @rectalogic in #9182.
- Conditional compilation by @jimblandy in #9390
- Add
wgpu_hal::vulkan::Buffer::raw_handle()for retrieving the underlyingvk::Bufferresource. By @WillowGriffiths in #9459.
Metal
- Add
metal::Queue::add_wait_event/add_signal_event(withremove_*companions) to stageMTLSharedEventwaits/signals on the nextQueue::submit, for GPU-side interop with foreign APIs. Waits run on an internal CB committed before user CBs. By @AdrianEddy in #9483. - Unconditionally enable
Features::CLIP_DISTANCES. By @ErichDonGubler in #9270. - Added full support for mesh shaders, including in WGSL shaders. By @inner-daemons in #8739.
- Added support for bindless storage buffers (buffer binding arrays) on Metal. By @mate-h in #9081.
- Added
DropCallbacks to Metal textures. By @jerzywilczek in #9634.
GLES
- Added support for GLSL passthrough. By @inner-daemons in #9064.
- Implement
Adapter::new_external()for WebGL2 (just like EGL/WGL) to import an external WebGL2 rendering context, and expose the imported context back throughAdapter::adapter_context()/Device::context(). By @pepperoni505 in #9438. - Add
gles::Device::buffer_from_rawfor wrapping an externally-owned GL buffer as awgpu_hal::gles::Buffer. By @AdrianEddy in #9550. - Advertise
Features::TEXTURE_FORMAT_16BIT_NORMon OpenGL, including storage-texture usage where the driver supports it. By @AdrianEddy in #9601.
Changes
General
SurfaceTexture::present()has been replaced byQueue::present(surface_texture). By @inner-daemons and @atlv24 in #9361.Features::CLIP_DISTANCE,naga::Capabilities::CLIP_DISTANCE, andnaga::BuiltIn::ClipDistancehave been renamed toCLIP_DISTANCESandClipDistances(viz., pluralized) as appropriate, to match the WebGPU spec. By @ErichDonGubler in #9267.- Added more granular limits for mesh shaders. By @inner-daemons in #8739.
- Added new
InvalidWorkgroupSizeError, which is now used byDrawError::InvalidGroupSizeandStageError::InvalidWorkgroupSize. By @andyleiserson in #9357. - Zero-size
Queue::write_buffernow returns an error if the offset is invalid or the buffer lacksCOPY_DST. By @39ali in #9374. Buffer::get_mapped_rangeand variants now returnResult<_, MapRangeError>>instead of panicking, in line with WebGPU spec. By @atlv24 in #9281.- Passthrough shaders now require a list of entry points when being created. by @inner-daemons in #9064.
- BREAKING: The
dispatchanddispatch_indirectmethods on pass and bundle encoders have been renamed todispatch_workgroupsanddispatch_workgroups_indirect, respectively, to match the WebGPU spec. By @ErichDonGubler in #9362. LoadOp::DontCarecan no longer be deserialized, and theLoadOpDontCaretoken no longer implementsDefault. This ensures thatDontCarecan only be used withunsafe, as intended. By @kpreid in #9428.- Minor changes to various error enums to support improved validation. By @andyleiserson in #9357, #9363, and #9425:
- Added new
InvalidWorkgroupSizeError, which is now used byDrawError::InvalidGroupSizeandStageError::InvalidWorkgroupSize. - Added
BuildAccelerationStructureErrorvariantOffsetLimitedTo4GBand changedIndirectBufferOverrunto contain offset and size rather than start and end offsets. IndexFormat::byte_sizenow returnsu32instead ofusize.
- Added new
- BREAKING:
map_labelhelpers have changed slightly. By @beicause and @andyleiserson in #9480, #9481, and #9526.TextureDescriptor::map_label_and_view_formatsandSurfaceConfiguration::map_view_formatsnow takeFnOnce(&V)instead ofFnOnce(V).- All
map_labelhelpers exceptCreateShaderModuleDescriptorPassthroughnow have the signaturemap_label<'a, K>(&'a self, fun: impl FnOnce(&'a L) -> K)(previously the lifetimes were implicit and thus could differ).
- Relaxed locking within
wgpu-coreto enable queue submission processing on one thread to proceed while another thread is blocked in a device poll. To facilitate this,wgpu-halfences are now internally synchronized. By @Vecvec in #9475. AdapterInfo::transient_saves_memorynow isOption<bool>instead ofbool. It isNoneon web andSomeon native platforms. By @beicause in #9568.- BREAKING:
TextureUsages::TRANSIENTis renamed toTextureUsages::TRANSIENT_ATTACHMENTand brought in line with WebGPU spec. Transient textures may now only be used withLoadOp::ClearorLoadOp::DontCare(if it is available) andStoreOp::Discard. By @beicause in #9568. - Added missing
Debugimplementations across the public API (includingTextureBlitterand its builder,SurfaceTarget,ErrorScopeGuard, andQueueWriteBufferView) and enabled themissing_debug_implementationslint. By @euclio in #9730 and @kpreid in #9744.
naga
- Switched from using an
intersectorto using anintersection_queryon metal so AABBs and non-opaque triangles can be handled. By @Vecvec in #9304. - Guard against invalid calls to ray query functions on Metal. By @Vecvec in #9442.
Validation
- Add clip distances validation for
maxInterStageShaderVariables. By @ErichDonGubler in #8762. This may break some existing programs, but it compiles with the WebGPU spec. - Bring immediates in line with webgpu spec. By @atlv24 in #9280.
- Validate
LoadOpandStoreOpareNonefor attachments without corresponding depth or stencil aspect. By @beicause in #9567.
DX12
Bug Fixes
General
- Fix
SYNC-HAZARD-WRITE-AFTER-PRESENTon Vulkan when a surface texture is presented without being rendered to. By @inner-daemons and @atlv24 in #9361. - Fix incorrect checks for dynamic binding bounds when calling an encoder's
set_bind_groupin passes and bundles. By @ErichDonGubler in #9308. - Writes from
Queue::write_bufferare now flushed by calls toBuffer::map_asyncfor that same buffer, to prevent reading stale data.on_submitted_work_donealso now flushes pending writes. By @andyleiserson in #9307. - Fix missing dependency feature activations when building wgpu-hal with gles/dx12 in isolation. By @Wumpf in #9325
- Increase recursion limits to please
-Znext-solver. By @nazar-pc in #9609 - Stencil clear and reference values are now truncated to 8 bits. By @beicause in #9607.
- Fixed missing initialization of other aspects when writing to a single aspect of a multi-aspect texture. By @andyleiserson in #9626.
- Fix process abort when a
SurfaceTextureis dropped during panic unwind betweenget_current_textureandQueue::present. The acquired texture reference is now released without calling HAL discard. By @hack3rmann in #9678. - Fixed incorrect initialization tracking for 3D textures. By @andyleiserson in #9765.
naga
- Fixed atomic load and store operations being incorrectly generated as non-atomic memory accesses in GLSL and HLSL. By @CldStlkr in #9242.
- Fixed overflow detection and argument domain validation for
acosh,length,normalize, andpowin constant evaluation. By @ecoricemon in #9249. - Naga no longer allows derivative operations on
f16. WGSL does not currently allow this, although it may be added in the future. By @andyleiserson in #9154. - Disallow direct access to atomic variables in WGSL front-end (e.g.
let x = myAtomic;). By @ecoricemon in #9262. - Fixed handling of unterminated block comments. By @BKDaugherty in #9356.
- Enforce that
@must_useappear only on function declarations. By @dnsn021 in #9367. - Fix typo in
naga::back::msl::Error::UnsupportedWritable*variant names. By @ErichDonGubler in #9376. - Added support for
enable wgpu_binding_array;. By @39ali in #9298. - Ability to disable integer division safety checks on Vulkan and Metal. By @kvark in #9443.
- [hlsl] more
matCx2fixes. By @teoxoy in #9507. - Fix
packSnorm2x16andpackUnorm2x16swap in the GLSL frontend. By @treylutton in #9675. - Fixed WGSL loop-local
vardeclarations without explicit initializers so they are zero-initialized each iteration. By @ruihe774 in #9592. - Fixed logic errors in the ray query spirv writer. By @Vecvec in #9731.
DX12
- Fixed use of a texture view without
TextureUsage::TEXTURE_BINDINGas a read-only depth attachment. By @andyleiserson in #9346. - Fixed a
debug_assertduring stride validation for indirect multi draw. By @kristoff3r in #9332 - Fixed stencil values read with
textureLoadappearing in G instead of R. By @andyleiserson in #9520. - Fixed some cases where the
textureNum{Layers,Levels,Samples}functions returned incorrect results. By @andyleiserson in #9542. - Fixed
map_texture_format_for_copypanicking on(planar_format, single_plane_aspect)during buffer<->texture transfers, andTextureView::subresource_indexpreviously being hard-coded to plane 0. By @AdrianEddy in #9551. - Fixed partially-bound texture and storage-texture binding arrays (
PARTIALLY_BOUND_BINDING_ARRAY) reading garbage increate_bind_group. By @holg in #9653.
Vulkan
- Fixed
SHADER_I16not enablingstorage_buffer16_bit_accessorstorage_input_output16, causing Vulkan validation errors when using 16-bit integers in buffers. By @JMS55 in #9412. - Fixed validation errors when frames take longer than the specified swapchain acquire timeout. By @atlv24 in #9405.
- Fixed limits on Mesa's Honeykrisp / Asahi Linux. By @im-0 in #9393.
- Fixed vkAcquireNextImage fence being awaited on non-Windows platforms causing frametime spikes on nvidia drivers. By @cohaereo in #9486.
- Fixed alignment and
MatrixStridefor mat2x2 in SPIR-V uniform blocks. By @39ali #9369. - Fixed loading of
libvulkan.soon OpenHarmony (target_env = "ohos"). By @jschwe in #9649. - Fixed
VUID-RuntimeSpirv-vulkanMemoryModel-06265validation errors by enablingvulkanMemoryModelDeviceScopewhenever the Vulkan memory model is enabled, since the SPIR-V backend emits storage atomics withDevicescope. By @francisdb in #9741. - Fixed some cases where out-of-memory errors were reported incorrectly. By @andyleiserson in #9643 and #9747.
- Fixed signed integer
%(and%=) returning the wrong result for negative operands in the SPIR-V backend, e.g.-1 % 768yielding255instead of-1on NVIDIA.OpSRemis poison for negative operands in the Vulkan SPIR-V environment withoutVK_KHR_maintenance8, even though WGSL defines%for these operands, so signed remainder is now always lowered asa - b * (a / b). By @mstampfli in #9674.
Metal
- Detect BC texture support on newer iOS, tvOS, and visionOS devices. By @bmisiak in #9656.
- Fix crash on fence creation when running in a MacOS Seatbelt sandbox. By @Wumpf in #9415
- Improved command buffer completion handling. By @39ali in #9328.
- Wait using a condition variable, instead of polling.
- Fixed a hang in
Device::poll(PollType::wait_indefinitely())when a Metal command buffer exits with an error.
- Fixed structure field names incorrectly ignoring reserved keywords in the Metal (MSL) backend. By @39ali #9379.
- Restore the
Queue::as_rawmethod, which was removed without good reason in v29. It now returns&ProtocolObject<dyn MTLCommandQueue>. By @andyleiserson in #9560.
WebGPU
- Expose the underlying JS handles of WebGPU-backed resources via new
as_webgpuaccessors onTexture,TextureView,Buffer,Queue, andDevice, returningOption<&wgpu::webgpu::Gpu*>. This is the WebGPU counterpart ofas_hal(which returnsNoneon the WebGPU backend, since WebGPU is not awgpu_halAPI). The vendored handle types are re-exported under the newwgpu::webgpumodule. By @AdrianEddy in #9530 - Add
Device::create_texture_from_webgpu_handle(texture, desc, drop_callback)for wrapping a foreignwebgpu::GpuTexture(e.g. a canvasgetCurrentTexture()result) as awgpu::Texturewithout copy. Use thedrop_callbackto decide if you want to callGpuTexture.destroy()when wgpu is done with the texture. By @AdrianEddy in #9530
Dependency Updates
WebGPU
- Upgrade vendored
wasm-bindgenWebGPU bindings to 0.2.115 and adapt thewebgpubackend to the new API.ExternalImageSource::VideoFrameno longer requires--cfg=web_sys_unstable_apis, asweb_sys::VideoFrameis now stable. The GLES backend still requires the cfg to uploadVideoFrames, sinceglowstill needs to adapt. By @evilpie in #9090.
Testing/Internal
- We now use
tombias our TOML formatter instead oftaplo, which has been unmaintained for some time. If you currently usetaploas part of your workflow, we recommend you migrate, or change your editor settings while working with wgpu.