From 56d648a5bf8bc24fbf144fe53d9d2894690b0b05 Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Fri, 19 Sep 2025 03:48:33 -0400 Subject: [PATCH 01/49] Preliminary implementation --- examples/features/src/msaa_line/mod.rs | 28 +++++++++++++++----------- wgpu-core/src/conv.rs | 8 ++++++++ wgpu-core/src/instance.rs | 1 + wgpu-hal/src/lib.rs | 3 +++ wgpu-hal/src/metal/adapter.rs | 10 ++++++++- wgpu-hal/src/metal/device.rs | 10 ++++++++- wgpu-hal/src/metal/mod.rs | 1 + wgpu-hal/src/vulkan/adapter.rs | 5 +++-- wgpu-hal/src/vulkan/conv.rs | 6 ++++++ wgpu-hal/src/vulkan/device.rs | 8 +++++++- wgpu-types/src/features.rs | 11 ++++++++++ wgpu-types/src/lib.rs | 4 ++++ 12 files changed, 78 insertions(+), 17 deletions(-) diff --git a/examples/features/src/msaa_line/mod.rs b/examples/features/src/msaa_line/mod.rs index 71c6b277c4b..3a0db339b1f 100644 --- a/examples/features/src/msaa_line/mod.rs +++ b/examples/features/src/msaa_line/mod.rs @@ -112,7 +112,7 @@ impl Example { sample_count, dimension: wgpu::TextureDimension::D2, format: config.view_formats[0], - usage: wgpu::TextureUsages::RENDER_ATTACHMENT, + usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::TRANSIENT, label: None, view_formats: &[], }; @@ -128,6 +128,10 @@ impl crate::framework::Example for Example { wgpu::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES } + fn required_features() -> wgpu::Features { + wgpu::Features::TRANSIENT_ATTACHMENTS + } + fn init( config: &wgpu::SurfaceConfiguration, _adapter: &wgpu::Adapter, @@ -214,6 +218,17 @@ impl crate::framework::Example for Example { } } + fn resize( + &mut self, + config: &wgpu::SurfaceConfiguration, + device: &wgpu::Device, + _queue: &wgpu::Queue, + ) { + self.config = config.clone(); + self.multisampled_framebuffer = + Example::create_multisampled_framebuffer(device, config, self.sample_count); + } + #[expect(clippy::single_match)] fn update(&mut self, event: winit::event::WindowEvent) { match event { @@ -246,17 +261,6 @@ impl crate::framework::Example for Example { } } - fn resize( - &mut self, - config: &wgpu::SurfaceConfiguration, - device: &wgpu::Device, - _queue: &wgpu::Queue, - ) { - self.config = config.clone(); - self.multisampled_framebuffer = - Example::create_multisampled_framebuffer(device, config, self.sample_count); - } - fn render(&mut self, view: &wgpu::TextureView, device: &wgpu::Device, queue: &wgpu::Queue) { if self.rebuild_bundle { self.bundle = Example::create_bundle( diff --git a/wgpu-core/src/conv.rs b/wgpu-core/src/conv.rs index 3aca805659c..ac45677e46e 100644 --- a/wgpu-core/src/conv.rs +++ b/wgpu-core/src/conv.rs @@ -124,6 +124,10 @@ pub fn map_texture_usage( wgt::TextureUses::STORAGE_ATOMIC, usage.contains(wgt::TextureUsages::STORAGE_ATOMIC), ); + u.set( + wgt::TextureUses::TRANSIENT, + usage.contains(wgt::TextureUsages::TRANSIENT), + ); u } @@ -183,6 +187,10 @@ pub fn map_texture_usage_from_hal(uses: wgt::TextureUses) -> wgt::TextureUsages wgt::TextureUsages::STORAGE_ATOMIC, uses.contains(wgt::TextureUses::STORAGE_ATOMIC), ); + u.set( + wgt::TextureUsages::TRANSIENT, + uses.contains(wgt::TextureUses::TRANSIENT), + ); u } diff --git a/wgpu-core/src/instance.rs b/wgpu-core/src/instance.rs index 4344622311d..618f5910f0a 100644 --- a/wgpu-core/src/instance.rs +++ b/wgpu-core/src/instance.rs @@ -706,6 +706,7 @@ impl Adapter { wgt::TextureUsages::STORAGE_ATOMIC, caps.contains(Tfc::STORAGE_ATOMIC), ); + allowed_usages.set(wgt::TextureUsages::TRANSIENT, caps.contains(Tfc::TRANSIENT)); let mut flags = wgt::TextureFormatFeatureFlags::empty(); flags.set( diff --git a/wgpu-hal/src/lib.rs b/wgpu-hal/src/lib.rs index b4255a6c811..deeae966717 100644 --- a/wgpu-hal/src/lib.rs +++ b/wgpu-hal/src/lib.rs @@ -1675,6 +1675,9 @@ bitflags!( const COPY_SRC = 1 << 15; /// Format can be copied to. const COPY_DST = 1 << 16; + + /// Format can be created as transient. + const TRANSIENT = 1 << 17; } ); diff --git a/wgpu-hal/src/metal/adapter.rs b/wgpu-hal/src/metal/adapter.rs index 47ffbd3c6c1..fa1d48287b9 100644 --- a/wgpu-hal/src/metal/adapter.rs +++ b/wgpu-hal/src/metal/adapter.rs @@ -149,7 +149,7 @@ impl crate::Adapter for super::Adapter { | msaa_count | Tfc::MULTISAMPLE_RESOLVE; - let extra = match format { + let mut extra = match format { Tf::R8Unorm | Tf::R16Float | Tf::Rgba8Unorm | Tf::Rgba16Float => { read_write_tier2_if | all_caps } @@ -352,6 +352,11 @@ impl crate::Adapter for super::Adapter { } }; + extra.set( + Tfc::TRANSIENT, + self.shared.private_caps.supports_memoryless_storage, + ); + Tfc::COPY_SRC | Tfc::COPY_DST | Tfc::SAMPLED | Tfc::STORAGE_READ_ONLY | extra } @@ -902,6 +907,7 @@ impl super::PrivateCapabilities { && (device.supports_family(MTLGPUFamily::Apple7) || device.supports_family(MTLGPUFamily::Mac2)), supports_shared_event: version.at_least((10, 14), (12, 0), os_is_mac), + supports_memoryless_storage: version.at_least((11, 0), (10, 0), os_is_mac), } } @@ -1001,6 +1007,8 @@ impl super::PrivateCapabilities { features.insert(F::SUBGROUP | F::SUBGROUP_BARRIER); } + features.set(F::TRANSIENT_ATTACHMENTS, self.supports_memoryless_storage); + features } diff --git a/wgpu-hal/src/metal/device.rs b/wgpu-hal/src/metal/device.rs index dd5d05b6d50..5ccbda62240 100644 --- a/wgpu-hal/src/metal/device.rs +++ b/wgpu-hal/src/metal/device.rs @@ -452,13 +452,21 @@ impl crate::Device for super::Device { } }; + let mtl_storage_mode = if desc.usage.contains(wgt::TextureUses::TRANSIENT) + && self.features.contains(wgt::Features::TRANSIENT_ATTACHMENTS) + { + MTLStorageMode::Memoryless + } else { + MTLStorageMode::Private + }; + descriptor.set_texture_type(mtl_type); descriptor.set_width(desc.size.width as u64); descriptor.set_height(desc.size.height as u64); descriptor.set_mipmap_level_count(desc.mip_level_count as u64); descriptor.set_pixel_format(mtl_format); descriptor.set_usage(conv::map_texture_usage(desc.format, desc.usage)); - descriptor.set_storage_mode(MTLStorageMode::Private); + descriptor.set_storage_mode(mtl_storage_mode); let raw = self.shared.device.lock().new_texture(&descriptor); if raw.as_ptr().is_null() { diff --git a/wgpu-hal/src/metal/mod.rs b/wgpu-hal/src/metal/mod.rs index 00223b2f778..b844cd9278b 100644 --- a/wgpu-hal/src/metal/mod.rs +++ b/wgpu-hal/src/metal/mod.rs @@ -300,6 +300,7 @@ struct PrivateCapabilities { int64_atomics: bool, float_atomics: bool, supports_shared_event: bool, + supports_memoryless_storage: bool, } #[derive(Clone, Debug)] diff --git a/wgpu-hal/src/vulkan/adapter.rs b/wgpu-hal/src/vulkan/adapter.rs index 0ebf1fec9a4..985537ea587 100644 --- a/wgpu-hal/src/vulkan/adapter.rs +++ b/wgpu-hal/src/vulkan/adapter.rs @@ -560,7 +560,8 @@ impl PhysicalDeviceFeatures { | F::PIPELINE_CACHE | F::SHADER_EARLY_DEPTH_TEST | F::TEXTURE_ATOMIC - | F::EXPERIMENTAL_PASSTHROUGH_SHADERS; + | F::EXPERIMENTAL_PASSTHROUGH_SHADERS + | F::TRANSIENT_ATTACHMENTS; let mut dl_flags = Df::COMPUTE_SHADERS | Df::BASE_VERTEX @@ -2445,7 +2446,7 @@ impl crate::Adapter for super::Adapter { }; let features = properties.optimal_tiling_features; - let mut flags = Tfc::empty(); + let mut flags = Tfc::TRANSIENT; flags.set( Tfc::SAMPLED, features.contains(vk::FormatFeatureFlags::SAMPLED_IMAGE), diff --git a/wgpu-hal/src/vulkan/conv.rs b/wgpu-hal/src/vulkan/conv.rs index e6bcb20ca75..34939121be0 100644 --- a/wgpu-hal/src/vulkan/conv.rs +++ b/wgpu-hal/src/vulkan/conv.rs @@ -259,6 +259,9 @@ pub fn map_texture_usage(usage: wgt::TextureUses) -> vk::ImageUsageFlags { ) { flags |= vk::ImageUsageFlags::STORAGE; } + if usage.contains(wgt::TextureUses::TRANSIENT) { + flags |= vk::ImageUsageFlags::TRANSIENT_ATTACHMENT; + } flags } @@ -348,6 +351,9 @@ pub fn map_vk_image_usage(usage: vk::ImageUsageFlags) -> wgt::TextureUses { | wgt::TextureUses::STORAGE_READ_WRITE | wgt::TextureUses::STORAGE_ATOMIC; } + if usage.contains(vk::ImageUsageFlags::TRANSIENT_ATTACHMENT) { + bits |= wgt::TextureUses::TRANSIENT; + } bits } diff --git a/wgpu-hal/src/vulkan/device.rs b/wgpu-hal/src/vulkan/device.rs index 1297e57f09b..22c6f5b456f 100644 --- a/wgpu-hal/src/vulkan/device.rs +++ b/wgpu-hal/src/vulkan/device.rs @@ -1264,13 +1264,19 @@ impl crate::Device for super::Device { unsafe { self.shared.raw.destroy_image(image.raw, None) }; })?; + let mut alloc_usage = gpu_alloc::UsageFlags::FAST_DEVICE_ACCESS; + alloc_usage.set( + gpu_alloc::UsageFlags::TRANSIENT, + desc.usage.contains(wgt::TextureUses::TRANSIENT), + ); + let block = unsafe { self.mem_allocator.lock().alloc( &*self.shared, gpu_alloc::Request { size: image.requirements.size, align_mask: image.requirements.alignment - 1, - usage: gpu_alloc::UsageFlags::FAST_DEVICE_ACCESS, + usage: alloc_usage, memory_types: image.requirements.memory_type_bits & self.valid_ash_memory_types, }, ) diff --git a/wgpu-types/src/features.rs b/wgpu-types/src/features.rs index 397de544d6d..6b19b701f14 100644 --- a/wgpu-types/src/features.rs +++ b/wgpu-types/src/features.rs @@ -1231,6 +1231,17 @@ bitflags_array! { /// /// [`Device::create_shader_module_passthrough`]: https://docs.rs/wgpu/latest/wgpu/struct.Device.html#method.create_shader_module_passthrough const EXPERIMENTAL_PASSTHROUGH_SHADERS = 1 << 52; + + /// Allows transient attachments to be created with [`TextureUsages::TRANSIENT`] + /// + /// Supported platforms + /// - Vulkan + /// - Metal + /// + /// This is a native only feature + /// + /// [`TextureUsages::TRANSIENT`]: super::TextureUsages::TRANSIENT + const TRANSIENT_ATTACHMENTS = 1 << 53; } /// Features that are not guaranteed to be supported. diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 7674c0a95d8..c5dc58e1821 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -5610,6 +5610,8 @@ bitflags::bitflags! { // /// Allows a texture to be used with image atomics. Requires [`Features::TEXTURE_ATOMIC`]. const STORAGE_ATOMIC = 1 << 16; + /// Allows a texture to be transient. Requires [`Features::TRANSIENT_ATTACHMENTS`]. + const TRANSIENT = 1 << 17; } } @@ -5664,6 +5666,8 @@ bitflags::bitflags! { /// Flag used by the wgpu-core texture tracker to say that the tracker does not know the state of the sub-resource. /// This is different from UNINITIALIZED as that says the tracker does know, but the texture has not been initialized. const UNKNOWN = 1 << 13; + /// Transient image + const TRANSIENT = 1 << 14; } } From 598259c6c8fce3a6c8d3daca9e967b9fde3db719 Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Fri, 19 Sep 2025 03:52:32 -0400 Subject: [PATCH 02/49] oops --- examples/features/src/msaa_line/mod.rs | 28 +++++++++++--------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/examples/features/src/msaa_line/mod.rs b/examples/features/src/msaa_line/mod.rs index 3a0db339b1f..71c6b277c4b 100644 --- a/examples/features/src/msaa_line/mod.rs +++ b/examples/features/src/msaa_line/mod.rs @@ -112,7 +112,7 @@ impl Example { sample_count, dimension: wgpu::TextureDimension::D2, format: config.view_formats[0], - usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::TRANSIENT, + usage: wgpu::TextureUsages::RENDER_ATTACHMENT, label: None, view_formats: &[], }; @@ -128,10 +128,6 @@ impl crate::framework::Example for Example { wgpu::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES } - fn required_features() -> wgpu::Features { - wgpu::Features::TRANSIENT_ATTACHMENTS - } - fn init( config: &wgpu::SurfaceConfiguration, _adapter: &wgpu::Adapter, @@ -218,17 +214,6 @@ impl crate::framework::Example for Example { } } - fn resize( - &mut self, - config: &wgpu::SurfaceConfiguration, - device: &wgpu::Device, - _queue: &wgpu::Queue, - ) { - self.config = config.clone(); - self.multisampled_framebuffer = - Example::create_multisampled_framebuffer(device, config, self.sample_count); - } - #[expect(clippy::single_match)] fn update(&mut self, event: winit::event::WindowEvent) { match event { @@ -261,6 +246,17 @@ impl crate::framework::Example for Example { } } + fn resize( + &mut self, + config: &wgpu::SurfaceConfiguration, + device: &wgpu::Device, + _queue: &wgpu::Queue, + ) { + self.config = config.clone(); + self.multisampled_framebuffer = + Example::create_multisampled_framebuffer(device, config, self.sample_count); + } + fn render(&mut self, view: &wgpu::TextureView, device: &wgpu::Device, queue: &wgpu::Queue) { if self.rebuild_bundle { self.bundle = Example::create_bundle( From 9ec9242d4fc8c307db62f158684f21b13fc3a495 Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Fri, 19 Sep 2025 05:02:38 -0400 Subject: [PATCH 03/49] Better implementation --- wgpu-core/src/device/resource.rs | 4 ++++ wgpu-core/src/instance.rs | 1 - wgpu-hal/src/lib.rs | 3 --- wgpu-hal/src/metal/adapter.rs | 7 +------ wgpu-hal/src/metal/device.rs | 4 +--- wgpu-hal/src/vulkan/adapter.rs | 2 +- wgpu-types/src/lib.rs | 2 +- 7 files changed, 8 insertions(+), 15 deletions(-) diff --git a/wgpu-core/src/device/resource.rs b/wgpu-core/src/device/resource.rs index 7d5898ecc2d..0f111ff9b57 100644 --- a/wgpu-core/src/device/resource.rs +++ b/wgpu-core/src/device/resource.rs @@ -4464,6 +4464,10 @@ impl Device { { format_features.flags.set(tfsc::FILTERABLE, false); } + format_features.allowed_usages.set( + wgt::TextureUsages::TRANSIENT, + self.features.contains(wgt::Features::TRANSIENT_ATTACHMENTS), + ); format_features } diff --git a/wgpu-core/src/instance.rs b/wgpu-core/src/instance.rs index 618f5910f0a..4344622311d 100644 --- a/wgpu-core/src/instance.rs +++ b/wgpu-core/src/instance.rs @@ -706,7 +706,6 @@ impl Adapter { wgt::TextureUsages::STORAGE_ATOMIC, caps.contains(Tfc::STORAGE_ATOMIC), ); - allowed_usages.set(wgt::TextureUsages::TRANSIENT, caps.contains(Tfc::TRANSIENT)); let mut flags = wgt::TextureFormatFeatureFlags::empty(); flags.set( diff --git a/wgpu-hal/src/lib.rs b/wgpu-hal/src/lib.rs index deeae966717..b4255a6c811 100644 --- a/wgpu-hal/src/lib.rs +++ b/wgpu-hal/src/lib.rs @@ -1675,9 +1675,6 @@ bitflags!( const COPY_SRC = 1 << 15; /// Format can be copied to. const COPY_DST = 1 << 16; - - /// Format can be created as transient. - const TRANSIENT = 1 << 17; } ); diff --git a/wgpu-hal/src/metal/adapter.rs b/wgpu-hal/src/metal/adapter.rs index fa1d48287b9..4eb195a79d1 100644 --- a/wgpu-hal/src/metal/adapter.rs +++ b/wgpu-hal/src/metal/adapter.rs @@ -149,7 +149,7 @@ impl crate::Adapter for super::Adapter { | msaa_count | Tfc::MULTISAMPLE_RESOLVE; - let mut extra = match format { + let extra = match format { Tf::R8Unorm | Tf::R16Float | Tf::Rgba8Unorm | Tf::Rgba16Float => { read_write_tier2_if | all_caps } @@ -352,11 +352,6 @@ impl crate::Adapter for super::Adapter { } }; - extra.set( - Tfc::TRANSIENT, - self.shared.private_caps.supports_memoryless_storage, - ); - Tfc::COPY_SRC | Tfc::COPY_DST | Tfc::SAMPLED | Tfc::STORAGE_READ_ONLY | extra } diff --git a/wgpu-hal/src/metal/device.rs b/wgpu-hal/src/metal/device.rs index 5ccbda62240..8c69372f3b8 100644 --- a/wgpu-hal/src/metal/device.rs +++ b/wgpu-hal/src/metal/device.rs @@ -452,9 +452,7 @@ impl crate::Device for super::Device { } }; - let mtl_storage_mode = if desc.usage.contains(wgt::TextureUses::TRANSIENT) - && self.features.contains(wgt::Features::TRANSIENT_ATTACHMENTS) - { + let mtl_storage_mode = if desc.usage.contains(wgt::TextureUses::TRANSIENT) { MTLStorageMode::Memoryless } else { MTLStorageMode::Private diff --git a/wgpu-hal/src/vulkan/adapter.rs b/wgpu-hal/src/vulkan/adapter.rs index 985537ea587..bb1a3084fbb 100644 --- a/wgpu-hal/src/vulkan/adapter.rs +++ b/wgpu-hal/src/vulkan/adapter.rs @@ -2446,7 +2446,7 @@ impl crate::Adapter for super::Adapter { }; let features = properties.optimal_tiling_features; - let mut flags = Tfc::TRANSIENT; + let mut flags = Tfc::empty(); flags.set( Tfc::SAMPLED, features.contains(vk::FormatFeatureFlags::SAMPLED_IMAGE), diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index c5dc58e1821..b7702ae94c1 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -5666,7 +5666,7 @@ bitflags::bitflags! { /// Flag used by the wgpu-core texture tracker to say that the tracker does not know the state of the sub-resource. /// This is different from UNINITIALIZED as that says the tracker does know, but the texture has not been initialized. const UNKNOWN = 1 << 13; - /// Transient image + /// Transient image. const TRANSIENT = 1 << 14; } } From 2185cd81ad2690407974c3349242b3e64453aca9 Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Fri, 19 Sep 2025 05:33:17 -0400 Subject: [PATCH 04/49] Add entry in `CHANGELOG.md` --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a0df9e6da4e..0ca5f58b111 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -166,6 +166,8 @@ By @cwfitzgerald in [#8162](https://github.com/gfx-rs/wgpu/pull/8162). - Added support for external textures based on WebGPU's [`GPUExternalTexture`](https://www.w3.org/TR/webgpu/#gpuexternaltexture). These allow shaders to transparently operate on potentially multiplanar source texture data in either RGB or YCbCr formats via WGSL's `texture_external` type. This is gated behind the `Features::EXTERNAL_TEXTURE` feature, which is currently only supported on DX12. By @jamienicol in [#4386](https://github.com/gfx-rs/wgpu/issues/4386). +- Added support for transient textures on Vulkan and Metal, gated behind the `Features::TRANSIENT_ATTACHMENTS` feature. By @Opstic in [#8247](https://github.com/gfx-rs/wgpu/pull/8247) + ### Changes #### General From 625bf3b96afd28adc7b27d1a5c6ac5f87a21da2e Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Sat, 20 Sep 2025 01:38:19 -0400 Subject: [PATCH 05/49] Remove `Feature::TRANSIENT_ATTACHMENTS` and add validation --- wgpu-core/src/command/render.rs | 13 +++++++++++++ wgpu-core/src/device/resource.rs | 15 +++++++++++---- wgpu-core/src/instance.rs | 1 + wgpu-core/src/resource.rs | 3 +++ wgpu-hal/src/metal/adapter.rs | 2 -- wgpu-hal/src/vulkan/adapter.rs | 3 +-- wgpu-types/src/features.rs | 11 ----------- wgpu-types/src/lib.rs | 2 +- 8 files changed, 30 insertions(+), 20 deletions(-) diff --git a/wgpu-core/src/command/render.rs b/wgpu-core/src/command/render.rs index bf19edf7921..a040c5ca3fd 100644 --- a/wgpu-core/src/command/render.rs +++ b/wgpu-core/src/command/render.rs @@ -625,6 +625,8 @@ pub enum ColorAttachmentError { mip_level: u32, depth_or_array_layer: u32, }, + #[error("Color attachment's usage cannot contain {0:?} if StoreOp is {1:?}")] + InvalidUsageForStoreOp(TextureUsages, StoreOp), } impl WebGpuError for ColorAttachmentError { @@ -1585,6 +1587,17 @@ impl Global { let view = texture_views.get(*view_id).get()?; view.same_device(device)?; + if view.desc.usage.contains(TextureUsages::TRANSIENT) + && *store_op != StoreOp::Discard + { + return Err(RenderPassErrorInner::ColorAttachment( + ColorAttachmentError::InvalidUsageForStoreOp( + TextureUsages::TRANSIENT, + *store_op, + ), + )); + } + let resolve_target = if let Some(resolve_target_id) = resolve_target { let rt_arc = texture_views.get(*resolve_target_id).get()?; rt_arc.same_device(device)?; diff --git a/wgpu-core/src/device/resource.rs b/wgpu-core/src/device/resource.rs index 0f111ff9b57..ee465e52cb5 100644 --- a/wgpu-core/src/device/resource.rs +++ b/wgpu-core/src/device/resource.rs @@ -1262,6 +1262,17 @@ impl Device { } } + if desc.usage.contains(wgt::TextureUsages::TRANSIENT) { + let extra_usage = + desc.usage - wgt::TextureUsages::TRANSIENT - wgt::TextureUsages::RENDER_ATTACHMENT; + if !extra_usage.is_empty() { + return Err(CreateTextureError::IncompatibleUsage( + wgt::TextureUsages::TRANSIENT, + extra_usage, + )); + } + } + let format_features = self .describe_format_features(desc.format) .map_err(|error| CreateTextureError::MissingFeatures(desc.format, error))?; @@ -4464,10 +4475,6 @@ impl Device { { format_features.flags.set(tfsc::FILTERABLE, false); } - format_features.allowed_usages.set( - wgt::TextureUsages::TRANSIENT, - self.features.contains(wgt::Features::TRANSIENT_ATTACHMENTS), - ); format_features } diff --git a/wgpu-core/src/instance.rs b/wgpu-core/src/instance.rs index 4344622311d..b72effd6993 100644 --- a/wgpu-core/src/instance.rs +++ b/wgpu-core/src/instance.rs @@ -706,6 +706,7 @@ impl Adapter { wgt::TextureUsages::STORAGE_ATOMIC, caps.contains(Tfc::STORAGE_ATOMIC), ); + allowed_usages |= wgt::TextureUsages::TRANSIENT; let mut flags = wgt::TextureFormatFeatureFlags::empty(); flags.set( diff --git a/wgpu-core/src/resource.rs b/wgpu-core/src/resource.rs index 8d51298a711..c189d60eaed 100644 --- a/wgpu-core/src/resource.rs +++ b/wgpu-core/src/resource.rs @@ -1509,6 +1509,8 @@ pub enum CreateTextureError { CreateTextureView(#[from] CreateTextureViewError), #[error("Invalid usage flags {0:?}")] InvalidUsage(wgt::TextureUsages), + #[error("Texture usage {0:?} is not compatible with texture usage {1:?}")] + IncompatibleUsage(wgt::TextureUsages, wgt::TextureUsages), #[error(transparent)] InvalidDimension(#[from] TextureDimensionError), #[error("Depth texture ({1:?}) can't be created as {0:?}")] @@ -1564,6 +1566,7 @@ impl WebGpuError for CreateTextureError { Self::MissingDownlevelFlags(e) => e, Self::InvalidUsage(_) + | Self::IncompatibleUsage(_, _) | Self::InvalidDepthDimension(_, _) | Self::InvalidCompressedDimension(_, _) | Self::InvalidMipLevelCount { .. } diff --git a/wgpu-hal/src/metal/adapter.rs b/wgpu-hal/src/metal/adapter.rs index 4eb195a79d1..17164e3c120 100644 --- a/wgpu-hal/src/metal/adapter.rs +++ b/wgpu-hal/src/metal/adapter.rs @@ -1002,8 +1002,6 @@ impl super::PrivateCapabilities { features.insert(F::SUBGROUP | F::SUBGROUP_BARRIER); } - features.set(F::TRANSIENT_ATTACHMENTS, self.supports_memoryless_storage); - features } diff --git a/wgpu-hal/src/vulkan/adapter.rs b/wgpu-hal/src/vulkan/adapter.rs index bb1a3084fbb..0ebf1fec9a4 100644 --- a/wgpu-hal/src/vulkan/adapter.rs +++ b/wgpu-hal/src/vulkan/adapter.rs @@ -560,8 +560,7 @@ impl PhysicalDeviceFeatures { | F::PIPELINE_CACHE | F::SHADER_EARLY_DEPTH_TEST | F::TEXTURE_ATOMIC - | F::EXPERIMENTAL_PASSTHROUGH_SHADERS - | F::TRANSIENT_ATTACHMENTS; + | F::EXPERIMENTAL_PASSTHROUGH_SHADERS; let mut dl_flags = Df::COMPUTE_SHADERS | Df::BASE_VERTEX diff --git a/wgpu-types/src/features.rs b/wgpu-types/src/features.rs index 6b19b701f14..397de544d6d 100644 --- a/wgpu-types/src/features.rs +++ b/wgpu-types/src/features.rs @@ -1231,17 +1231,6 @@ bitflags_array! { /// /// [`Device::create_shader_module_passthrough`]: https://docs.rs/wgpu/latest/wgpu/struct.Device.html#method.create_shader_module_passthrough const EXPERIMENTAL_PASSTHROUGH_SHADERS = 1 << 52; - - /// Allows transient attachments to be created with [`TextureUsages::TRANSIENT`] - /// - /// Supported platforms - /// - Vulkan - /// - Metal - /// - /// This is a native only feature - /// - /// [`TextureUsages::TRANSIENT`]: super::TextureUsages::TRANSIENT - const TRANSIENT_ATTACHMENTS = 1 << 53; } /// Features that are not guaranteed to be supported. diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index b7702ae94c1..9370f164774 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -5610,7 +5610,7 @@ bitflags::bitflags! { // /// Allows a texture to be used with image atomics. Requires [`Features::TEXTURE_ATOMIC`]. const STORAGE_ATOMIC = 1 << 16; - /// Allows a texture to be transient. Requires [`Features::TRANSIENT_ATTACHMENTS`]. + /// Allows a texture to be transient. No-op on platforms other than Vulkan and Metal. const TRANSIENT = 1 << 17; } } From 5644cd2b0261bcb8af2b061c47b0cc5ec3130ab4 Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Sat, 20 Sep 2025 02:14:51 -0400 Subject: [PATCH 06/49] Remove `#[cfg(windows)]` from `find_memory_type_index` --- wgpu-hal/src/vulkan/device.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/wgpu-hal/src/vulkan/device.rs b/wgpu-hal/src/vulkan/device.rs index 22c6f5b456f..659569cdd71 100644 --- a/wgpu-hal/src/vulkan/device.rs +++ b/wgpu-hal/src/vulkan/device.rs @@ -648,7 +648,6 @@ impl super::Device { } } - #[cfg(windows)] fn find_memory_type_index( &self, type_bits_req: u32, From 6c3d11b7e9edb7d181a18c494b8a772a1d6c33e9 Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Sat, 20 Sep 2025 02:48:43 -0400 Subject: [PATCH 07/49] Tries to find a memory type that contains `MemoryPropertyFlags::LAZILY_ALLOCATED` and applies it --- wgpu-hal/src/vulkan/device.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/wgpu-hal/src/vulkan/device.rs b/wgpu-hal/src/vulkan/device.rs index 659569cdd71..e082975731c 100644 --- a/wgpu-hal/src/vulkan/device.rs +++ b/wgpu-hal/src/vulkan/device.rs @@ -737,7 +737,14 @@ impl super::Device { // VK_ERROR_COMPRESSION_EXHAUSTED_EXT super::map_host_device_oom_and_ioca_err(err) } - let req = unsafe { self.shared.raw.get_image_memory_requirements(raw) }; + let mut req = unsafe { self.shared.raw.get_image_memory_requirements(raw) }; + + if desc.usage.contains(wgt::TextureUses::TRANSIENT) { + let mem_type_index = self.find_memory_type_index(req.memory_type_bits, vk::MemoryPropertyFlags::LAZILY_ALLOCATED); + if let Some(mem_type_index) = mem_type_index { + req.memory_type_bits = 1 << mem_type_index; + } + } Ok(ImageWithoutMemory { raw, @@ -1263,19 +1270,13 @@ impl crate::Device for super::Device { unsafe { self.shared.raw.destroy_image(image.raw, None) }; })?; - let mut alloc_usage = gpu_alloc::UsageFlags::FAST_DEVICE_ACCESS; - alloc_usage.set( - gpu_alloc::UsageFlags::TRANSIENT, - desc.usage.contains(wgt::TextureUses::TRANSIENT), - ); - let block = unsafe { self.mem_allocator.lock().alloc( &*self.shared, gpu_alloc::Request { size: image.requirements.size, align_mask: image.requirements.alignment - 1, - usage: alloc_usage, + usage: gpu_alloc::UsageFlags::FAST_DEVICE_ACCESS, memory_types: image.requirements.memory_type_bits & self.valid_ash_memory_types, }, ) From aafa05e29376827f0d71be5ba01b1f950978b22c Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Sat, 20 Sep 2025 03:48:13 -0400 Subject: [PATCH 08/49] `cargo fmt` --- wgpu-hal/src/vulkan/device.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/wgpu-hal/src/vulkan/device.rs b/wgpu-hal/src/vulkan/device.rs index e082975731c..70901780143 100644 --- a/wgpu-hal/src/vulkan/device.rs +++ b/wgpu-hal/src/vulkan/device.rs @@ -740,7 +740,10 @@ impl super::Device { let mut req = unsafe { self.shared.raw.get_image_memory_requirements(raw) }; if desc.usage.contains(wgt::TextureUses::TRANSIENT) { - let mem_type_index = self.find_memory_type_index(req.memory_type_bits, vk::MemoryPropertyFlags::LAZILY_ALLOCATED); + let mem_type_index = self.find_memory_type_index( + req.memory_type_bits, + vk::MemoryPropertyFlags::LAZILY_ALLOCATED, + ); if let Some(mem_type_index) = mem_type_index { req.memory_type_bits = 1 << mem_type_index; } From 703bf2661cef77ecd521af79a5a9cab1a3034821 Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Sat, 20 Sep 2025 03:50:07 -0400 Subject: [PATCH 09/49] Add check in Metal for `MTLStorageMode::Memoryless` support --- wgpu-hal/src/metal/device.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/wgpu-hal/src/metal/device.rs b/wgpu-hal/src/metal/device.rs index 8c69372f3b8..d56544950bd 100644 --- a/wgpu-hal/src/metal/device.rs +++ b/wgpu-hal/src/metal/device.rs @@ -452,7 +452,9 @@ impl crate::Device for super::Device { } }; - let mtl_storage_mode = if desc.usage.contains(wgt::TextureUses::TRANSIENT) { + let mtl_storage_mode = if desc.usage.contains(wgt::TextureUses::TRANSIENT) + && self.shared.private_caps.supports_memoryless_storage + { MTLStorageMode::Memoryless } else { MTLStorageMode::Private From 02201f420dbffca6cb50bbadfbcc89ab39103ad7 Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Sat, 20 Sep 2025 04:03:20 -0400 Subject: [PATCH 10/49] Apply `TextureUsages::TRANSIENT` to relevant examples --- examples/features/src/msaa_line/mod.rs | 2 +- examples/features/src/shadow/mod.rs | 2 +- examples/features/src/skybox/mod.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/features/src/msaa_line/mod.rs b/examples/features/src/msaa_line/mod.rs index 71c6b277c4b..491d68c771e 100644 --- a/examples/features/src/msaa_line/mod.rs +++ b/examples/features/src/msaa_line/mod.rs @@ -112,7 +112,7 @@ impl Example { sample_count, dimension: wgpu::TextureDimension::D2, format: config.view_formats[0], - usage: wgpu::TextureUsages::RENDER_ATTACHMENT, + usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::TRANSIENT, label: None, view_formats: &[], }; diff --git a/examples/features/src/shadow/mod.rs b/examples/features/src/shadow/mod.rs index b89d2c902dc..09df6382456 100644 --- a/examples/features/src/shadow/mod.rs +++ b/examples/features/src/shadow/mod.rs @@ -192,7 +192,7 @@ impl Example { sample_count: 1, dimension: wgpu::TextureDimension::D2, format: Self::DEPTH_FORMAT, - usage: wgpu::TextureUsages::RENDER_ATTACHMENT, + usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::TRANSIENT, label: None, view_formats: &[], }); diff --git a/examples/features/src/skybox/mod.rs b/examples/features/src/skybox/mod.rs index 699f6615ba9..470f5f10acd 100644 --- a/examples/features/src/skybox/mod.rs +++ b/examples/features/src/skybox/mod.rs @@ -80,7 +80,7 @@ impl Example { sample_count: 1, dimension: wgpu::TextureDimension::D2, format: Self::DEPTH_FORMAT, - usage: wgpu::TextureUsages::RENDER_ATTACHMENT, + usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::TRANSIENT, label: None, view_formats: &[], }); From c1c04ec20ed868cd10ccea0a28367f2d98376b15 Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Sat, 20 Sep 2025 04:05:15 -0400 Subject: [PATCH 11/49] Improve documentation by @cwfitzgerald Co-authored-by: Connor Fitzgerald --- wgpu-types/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 9370f164774..6a62883fd37 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -5666,7 +5666,7 @@ bitflags::bitflags! { /// Flag used by the wgpu-core texture tracker to say that the tracker does not know the state of the sub-resource. /// This is different from UNINITIALIZED as that says the tracker does know, but the texture has not been initialized. const UNKNOWN = 1 << 13; - /// Transient image. + /// Transient texture that may not have any backing memory. Not a resource state stored in the trackers, only used for passing down usages to create_texture. const TRANSIENT = 1 << 14; } } From 77bf9afe06a5e7bba573be9172180a060e196f85 Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Sat, 20 Sep 2025 04:05:43 -0400 Subject: [PATCH 12/49] Improve error message by @cwfitzgerald Co-authored-by: Connor Fitzgerald --- wgpu-core/src/command/render.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wgpu-core/src/command/render.rs b/wgpu-core/src/command/render.rs index a040c5ca3fd..ab101e8db98 100644 --- a/wgpu-core/src/command/render.rs +++ b/wgpu-core/src/command/render.rs @@ -625,7 +625,7 @@ pub enum ColorAttachmentError { mip_level: u32, depth_or_array_layer: u32, }, - #[error("Color attachment's usage cannot contain {0:?} if StoreOp is {1:?}")] + #[error("Color attachment's usage contains {0:?}. This can only be used with StoreOp::Discard, but the provided store op was {1:?}")] InvalidUsageForStoreOp(TextureUsages, StoreOp), } From faea1c3473b9607a6bafece9573b32c752d5e47a Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Sat, 20 Sep 2025 04:08:39 -0400 Subject: [PATCH 13/49] Move `TextureUses::TRANSIENT` to `1 << 12` --- wgpu-types/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 6a62883fd37..72febae737a 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -5649,6 +5649,8 @@ bitflags::bitflags! { /// Image atomic enabled storage. /// cbindgen:ignore const STORAGE_ATOMIC = 1 << 11; + /// Transient texture that may not have any backing memory. Not a resource state stored in the trackers, only used for passing down usages to create_texture. + const TRANSIENT = 1 << 12; /// The combination of states that a texture may be in _at the same time_. /// cbindgen:ignore const INCLUSIVE = Self::COPY_SRC.bits() | Self::RESOURCE.bits() | Self::DEPTH_STENCIL_READ.bits(); @@ -5662,12 +5664,10 @@ bitflags::bitflags! { const ORDERED = Self::INCLUSIVE.bits() | Self::COLOR_TARGET.bits() | Self::DEPTH_STENCIL_WRITE.bits() | Self::STORAGE_READ_ONLY.bits(); /// Flag used by the wgpu-core texture tracker to say a texture is in different states for every sub-resource - const COMPLEX = 1 << 12; + const COMPLEX = 1 << 13; /// Flag used by the wgpu-core texture tracker to say that the tracker does not know the state of the sub-resource. /// This is different from UNINITIALIZED as that says the tracker does know, but the texture has not been initialized. - const UNKNOWN = 1 << 13; - /// Transient texture that may not have any backing memory. Not a resource state stored in the trackers, only used for passing down usages to create_texture. - const TRANSIENT = 1 << 14; + const UNKNOWN = 1 << 14; } } From 56b395698d197d15d2a9ff009203b993cd6c6f52 Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Sat, 20 Sep 2025 04:20:20 -0400 Subject: [PATCH 14/49] Improve `TextureUsages` docs --- wgpu-types/src/lib.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 72febae737a..20f35239832 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -5601,6 +5601,7 @@ bitflags::bitflags! { /// Allows a texture to be a [`BindingType::StorageTexture`] in a bind group. const STORAGE_BINDING = 1 << 3; /// Allows a texture to be an output attachment of a render pass. + /// NOTE: Consider adding ['TextureUsages::TRANSIENT'] if the contents are not reused. const RENDER_ATTACHMENT = 1 << 4; // @@ -5610,7 +5611,9 @@ bitflags::bitflags! { // /// Allows a texture to be used with image atomics. Requires [`Features::TEXTURE_ATOMIC`]. const STORAGE_ATOMIC = 1 << 16; - /// Allows a texture to be transient. No-op on platforms other than Vulkan and Metal. + /// Hints to the backend that the contents of this texture will not be used in another pass to potentially reduce memory usage and bandwidth. + /// No-op on platforms other than Vulkan and Metal. + /// Incompatible with ALL other usages except [`TextureUsages::RENDER_ATTACHMENT`] const TRANSIENT = 1 << 17; } } From 15ded86b8b8f558f5942834ca9d421d406ee6f09 Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Sat, 20 Sep 2025 06:10:39 -0400 Subject: [PATCH 15/49] Better wording --- wgpu-types/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 20f35239832..ddc6b65a152 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -5611,7 +5611,7 @@ bitflags::bitflags! { // /// Allows a texture to be used with image atomics. Requires [`Features::TEXTURE_ATOMIC`]. const STORAGE_ATOMIC = 1 << 16; - /// Hints to the backend that the contents of this texture will not be used in another pass to potentially reduce memory usage and bandwidth. + /// Specifies the contents of this texture will not be used in another pass to potentially reduce memory usage and bandwidth. /// No-op on platforms other than Vulkan and Metal. /// Incompatible with ALL other usages except [`TextureUsages::RENDER_ATTACHMENT`] const TRANSIENT = 1 << 17; From e0280d94fc2b9f392276dc09bc1308e0b13ef69f Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Sat, 20 Sep 2025 06:14:00 -0400 Subject: [PATCH 16/49] Add `StoreOp` requirement --- wgpu-types/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index ddc6b65a152..9a6da0610ab 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -5613,7 +5613,8 @@ bitflags::bitflags! { const STORAGE_ATOMIC = 1 << 16; /// Specifies the contents of this texture will not be used in another pass to potentially reduce memory usage and bandwidth. /// No-op on platforms other than Vulkan and Metal. - /// Incompatible with ALL other usages except [`TextureUsages::RENDER_ATTACHMENT`] + /// Incompatible with ALL other usages except [`TextureUsages::RENDER_ATTACHMENT`]. + /// Requires [`StoreOp::Discard`]. const TRANSIENT = 1 << 17; } } From 01776c828efacd8bf2b7311a92a856b73436b70e Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Sat, 20 Sep 2025 06:20:04 -0400 Subject: [PATCH 17/49] Allow `TextureUsages::TRANSIENT` in `guaranteed_format_features` --- wgpu-types/src/lib.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 9a6da0610ab..1e02402776c 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -3148,7 +3148,7 @@ impl TextureFormat { #[rustfmt::skip] // lets make a nice table let ( mut flags, - allowed_usages, + mut allowed_usages, ) = match *self { Self::R8Unorm => (msaa_resolve, attachment), Self::R8Snorm => ( none, basic), @@ -3253,6 +3253,8 @@ impl TextureFormat { allowed_usages.contains(TextureUsages::STORAGE_ATOMIC), ); + allowed_usages |= TextureUsages::TRANSIENT; + TextureFormatFeatures { allowed_usages, flags, From 607ed01b6bad106445999164a090b63c2031378f Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Sat, 20 Sep 2025 06:30:16 -0400 Subject: [PATCH 18/49] Improve error message --- wgpu-core/src/command/render.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/wgpu-core/src/command/render.rs b/wgpu-core/src/command/render.rs index ab101e8db98..2791fa44c6a 100644 --- a/wgpu-core/src/command/render.rs +++ b/wgpu-core/src/command/render.rs @@ -625,8 +625,8 @@ pub enum ColorAttachmentError { mip_level: u32, depth_or_array_layer: u32, }, - #[error("Color attachment's usage contains {0:?}. This can only be used with StoreOp::Discard, but the provided store op was {1:?}")] - InvalidUsageForStoreOp(TextureUsages, StoreOp), + #[error("Color attachment's usage contains {0:?}. This can only be used with StoreOp::{1:?}, but was provided StoreOp::{2:?}")] + InvalidUsageForStoreOp(TextureUsages, StoreOp, StoreOp), } impl WebGpuError for ColorAttachmentError { @@ -1593,6 +1593,7 @@ impl Global { return Err(RenderPassErrorInner::ColorAttachment( ColorAttachmentError::InvalidUsageForStoreOp( TextureUsages::TRANSIENT, + StoreOp::Discard, *store_op, ), )); From ef922ef221b2280204d9c9b1433864b0522ad905 Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Sat, 20 Sep 2025 17:54:29 -0400 Subject: [PATCH 19/49] Add `TextureUses::TRANSIENT` to GL backend's `render_usage` --- wgpu-hal/src/gles/device.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wgpu-hal/src/gles/device.rs b/wgpu-hal/src/gles/device.rs index dda5525c61c..d06ace3ced4 100644 --- a/wgpu-hal/src/gles/device.rs +++ b/wgpu-hal/src/gles/device.rs @@ -734,7 +734,8 @@ impl crate::Device for super::Device { let render_usage = wgt::TextureUses::COLOR_TARGET | wgt::TextureUses::DEPTH_STENCIL_WRITE - | wgt::TextureUses::DEPTH_STENCIL_READ; + | wgt::TextureUses::DEPTH_STENCIL_READ + | wgt::TextureUses::TRANSIENT; let format_desc = self.shared.describe_texture_format(desc.format); let inner = if render_usage.contains(desc.usage) From 54c4cc0deef9e77aea5a9aece7fad94c9c14ea5c Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Sat, 20 Sep 2025 19:10:23 -0400 Subject: [PATCH 20/49] Improve docs --- wgpu-core/src/command/render.rs | 2 +- wgpu-types/src/lib.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/wgpu-core/src/command/render.rs b/wgpu-core/src/command/render.rs index 2791fa44c6a..b53364fc4c8 100644 --- a/wgpu-core/src/command/render.rs +++ b/wgpu-core/src/command/render.rs @@ -625,7 +625,7 @@ pub enum ColorAttachmentError { mip_level: u32, depth_or_array_layer: u32, }, - #[error("Color attachment's usage contains {0:?}. This can only be used with StoreOp::{1:?}, but was provided StoreOp::{2:?}")] + #[error("Color attachment's usage contains {0:?}. This can only be used with StoreOp::{1:?}, but StoreOp::{2:?} was provided")] InvalidUsageForStoreOp(TextureUsages, StoreOp, StoreOp), } diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 1e02402776c..5b0b7c77e80 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -5603,7 +5603,8 @@ bitflags::bitflags! { /// Allows a texture to be a [`BindingType::StorageTexture`] in a bind group. const STORAGE_BINDING = 1 << 3; /// Allows a texture to be an output attachment of a render pass. - /// NOTE: Consider adding ['TextureUsages::TRANSIENT'] if the contents are not reused. + /// + /// Consider adding ['TextureUsages::TRANSIENT'] if the contents are not reused. const RENDER_ATTACHMENT = 1 << 4; // From f50b0981b363de1e565c148c3fb5d08e7b7c2614 Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Sat, 20 Sep 2025 19:13:30 -0400 Subject: [PATCH 21/49] Add validation tests --- tests/tests/wgpu-validation/api/texture.rs | 93 ++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/tests/tests/wgpu-validation/api/texture.rs b/tests/tests/wgpu-validation/api/texture.rs index 01c88c7bdf7..e378e6b252c 100644 --- a/tests/tests/wgpu-validation/api/texture.rs +++ b/tests/tests/wgpu-validation/api/texture.rs @@ -508,3 +508,96 @@ fn copy_buffer_to_texture_forbidden_format_aspect() { ); } } + +/// Ensures that attempting to create a texture with [`wgpu::TextureUsages::TRANSIENT`] +/// and its unsupported usages fails validation. +#[test] +fn transient_invalid_usage() { + let (device, _queue) = wgpu::Device::noop(&wgpu::DeviceDescriptor::default()); + + let size = wgpu::Extent3d { + width: 256, + height: 256, + depth_or_array_layers: 1, + }; + + let invalid_usages = [ + wgpu::TextureUsages::COPY_SRC, + wgpu::TextureUsages::COPY_DST, + wgpu::TextureUsages::TEXTURE_BINDING, + wgpu::TextureUsages::STORAGE_BINDING, + wgpu::TextureUsages::STORAGE_ATOMIC, + ]; + + for usage in invalid_usages { + let invalid_texture_descriptor = wgpu::TextureDescriptor { + label: None, + size, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: wgpu::TextureFormat::Rgba8Unorm, + usage: wgpu::TextureUsages::TRANSIENT | usage, + view_formats: &[], + }; + fail( + &device, + || { + device.create_texture(&invalid_texture_descriptor) + }, + Some(&format!("Texture usage TextureUsages(TRANSIENT) is not compatible with texture usage {usage:?}")), + ); + } +} + +/// Ensures that attempting to use a texture of [`wgpu::TextureUsages::TRANSIENT`] +/// with [`wgpu::StoreOp::Store`] fails validation. +#[test] +fn transient_invalid_storeop() { + let (device, _queue) = wgpu::Device::noop(&wgpu::DeviceDescriptor::default()); + + let size = wgpu::Extent3d { + width: 256, + height: 256, + depth_or_array_layers: 1, + }; + + let transient_texture = device.create_texture(&wgpu::TextureDescriptor { + label: None, + size, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: wgpu::TextureFormat::Rgba8Unorm, + usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::TRANSIENT, + view_formats: &[], + }); + + fail( + &device, + || { + let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }); + + let invalid_render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: None, + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + view: &transient_texture.create_view(&wgpu::TextureViewDescriptor::default()), + depth_slice: None, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT), + store: wgpu::StoreOp::Store, + }, + })], + depth_stencil_attachment: None, + timestamp_writes: None, + occlusion_query_set: None, + }); + + drop(invalid_render_pass); + + encoder.finish() + }, + Some("Color attachment's usage contains TextureUsages(TRANSIENT). This can only be used with StoreOp::Discard, but StoreOp::Store was provided") + ); +} From df228e041b31afaa80a4156b2467471d4d6edab0 Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Sun, 21 Sep 2025 00:54:31 -0400 Subject: [PATCH 22/49] Fix `TextureUsages::TRANSIENT` docs formatting --- wgpu-types/src/lib.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 5b0b7c77e80..4701d15f60d 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -5615,8 +5615,11 @@ bitflags::bitflags! { /// Allows a texture to be used with image atomics. Requires [`Features::TEXTURE_ATOMIC`]. const STORAGE_ATOMIC = 1 << 16; /// Specifies the contents of this texture will not be used in another pass to potentially reduce memory usage and bandwidth. + /// /// No-op on platforms other than Vulkan and Metal. + /// /// Incompatible with ALL other usages except [`TextureUsages::RENDER_ATTACHMENT`]. + /// /// Requires [`StoreOp::Discard`]. const TRANSIENT = 1 << 17; } From f6f2de8edc9095a1c76ade3d1e29a0f897f89b5b Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Sun, 21 Sep 2025 01:56:39 -0400 Subject: [PATCH 23/49] Add `supports_transient` flag in `AdapterInfo` --- wgpu-hal/src/dx12/adapter.rs | 1 + wgpu-hal/src/gles/adapter.rs | 1 + wgpu-hal/src/metal/mod.rs | 1 + wgpu-hal/src/noop/mod.rs | 1 + wgpu-hal/src/vulkan/adapter.rs | 10 ++++++++++ wgpu-types/src/lib.rs | 2 ++ 6 files changed, 16 insertions(+) diff --git a/wgpu-hal/src/dx12/adapter.rs b/wgpu-hal/src/dx12/adapter.rs index 6dce0ce97f0..b37651c3fb6 100644 --- a/wgpu-hal/src/dx12/adapter.rs +++ b/wgpu-hal/src/dx12/adapter.rs @@ -142,6 +142,7 @@ impl super::Adapter { } }, driver_info: String::new(), + supports_transient: false, }; let mut options = Direct3D12::D3D12_FEATURE_DATA_D3D12_OPTIONS::default(); diff --git a/wgpu-hal/src/gles/adapter.rs b/wgpu-hal/src/gles/adapter.rs index 806f5567ba2..4c427ed35bc 100644 --- a/wgpu-hal/src/gles/adapter.rs +++ b/wgpu-hal/src/gles/adapter.rs @@ -189,6 +189,7 @@ impl super::Adapter { driver: "".to_owned(), driver_info: version, backend: wgt::Backend::Gl, + supports_transient: false, } } diff --git a/wgpu-hal/src/metal/mod.rs b/wgpu-hal/src/metal/mod.rs index b844cd9278b..51827920f23 100644 --- a/wgpu-hal/src/metal/mod.rs +++ b/wgpu-hal/src/metal/mod.rs @@ -159,6 +159,7 @@ impl crate::Instance for Instance { driver: String::new(), driver_info: String::new(), backend: wgt::Backend::Metal, + supports_transient: shared.private_caps.supports_memoryless_storage, }, features: shared.private_caps.features(), capabilities: shared.private_caps.capabilities(), diff --git a/wgpu-hal/src/noop/mod.rs b/wgpu-hal/src/noop/mod.rs index abd7c628a98..109804a5be6 100644 --- a/wgpu-hal/src/noop/mod.rs +++ b/wgpu-hal/src/noop/mod.rs @@ -140,6 +140,7 @@ pub fn adapter_info() -> wgt::AdapterInfo { driver: String::from("wgpu"), driver_info: String::new(), backend: wgt::Backend::Noop, + supports_transient: true, } } diff --git a/wgpu-hal/src/vulkan/adapter.rs b/wgpu-hal/src/vulkan/adapter.rs index 0ebf1fec9a4..085f71245c9 100644 --- a/wgpu-hal/src/vulkan/adapter.rs +++ b/wgpu-hal/src/vulkan/adapter.rs @@ -1638,6 +1638,15 @@ impl super::Instance { let (phd_capabilities, phd_features) = self.shared.inspect(phd); + let mem_properties = { + profiling::scope!("vkGetPhysicalDeviceMemoryProperties"); + unsafe { + self.shared.raw.get_physical_device_memory_properties(phd) + } + }; + let memory_types = &mem_properties.memory_types_as_slice(); + let supports_lazily_allocated = memory_types.iter().find(|mem| mem.property_flags.contains(vk::MemoryPropertyFlags::LAZILY_ALLOCATED)).is_some(); + let info = wgt::AdapterInfo { name: { phd_capabilities @@ -1677,6 +1686,7 @@ impl super::Instance { .to_owned() }, backend: wgt::Backend::Vulkan, + supports_transient: supports_lazily_allocated, }; let (available_features, mut downlevel_flags) = phd_features.to_wgpu(&self.shared.raw, phd, &phd_capabilities); diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 4701d15f60d..98324766c3c 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -1414,6 +1414,8 @@ pub struct AdapterInfo { pub driver_info: String, /// Backend used for device pub backend: Backend, + /// Supports [`TextureUsages::TRANSIENT`] + pub supports_transient: bool, } /// Hints to the device about the memory allocation strategy. From c28ea1a8e97e9af727023347f22904a2a53a8e23 Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Sun, 21 Sep 2025 01:59:00 -0400 Subject: [PATCH 24/49] oops --- wgpu-core/src/pipeline_cache.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/wgpu-core/src/pipeline_cache.rs b/wgpu-core/src/pipeline_cache.rs index 8f4e65cfed1..3e29d3e0a26 100644 --- a/wgpu-core/src/pipeline_cache.rs +++ b/wgpu-core/src/pipeline_cache.rs @@ -322,6 +322,7 @@ mod tests { driver: String::new(), driver_info: String::new(), backend: wgt::Backend::Vulkan, + supports_transient: true, }; // IMPORTANT: If these tests fail, then you MUST increment HEADER_VERSION From cb248c52b3c52bb39528a30db71c6d88f2d4b92c Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Sun, 21 Sep 2025 02:00:11 -0400 Subject: [PATCH 25/49] =?UTF-8?q?=F0=9F=93=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- wgpu-hal/src/vulkan/adapter.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/wgpu-hal/src/vulkan/adapter.rs b/wgpu-hal/src/vulkan/adapter.rs index 085f71245c9..add761ba171 100644 --- a/wgpu-hal/src/vulkan/adapter.rs +++ b/wgpu-hal/src/vulkan/adapter.rs @@ -1640,12 +1640,15 @@ impl super::Instance { let mem_properties = { profiling::scope!("vkGetPhysicalDeviceMemoryProperties"); - unsafe { - self.shared.raw.get_physical_device_memory_properties(phd) - } + unsafe { self.shared.raw.get_physical_device_memory_properties(phd) } }; let memory_types = &mem_properties.memory_types_as_slice(); - let supports_lazily_allocated = memory_types.iter().find(|mem| mem.property_flags.contains(vk::MemoryPropertyFlags::LAZILY_ALLOCATED)).is_some(); + let supports_lazily_allocated = memory_types + .iter() + .any(|mem| { + mem.property_flags + .contains(vk::MemoryPropertyFlags::LAZILY_ALLOCATED) + }); let info = wgt::AdapterInfo { name: { From 1a09f3c2d04397553a7754a0e011afe5edb5508d Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Sun, 21 Sep 2025 04:53:35 -0400 Subject: [PATCH 26/49] Formatting --- wgpu-hal/src/vulkan/adapter.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/wgpu-hal/src/vulkan/adapter.rs b/wgpu-hal/src/vulkan/adapter.rs index add761ba171..175e2c19db2 100644 --- a/wgpu-hal/src/vulkan/adapter.rs +++ b/wgpu-hal/src/vulkan/adapter.rs @@ -1643,12 +1643,10 @@ impl super::Instance { unsafe { self.shared.raw.get_physical_device_memory_properties(phd) } }; let memory_types = &mem_properties.memory_types_as_slice(); - let supports_lazily_allocated = memory_types - .iter() - .any(|mem| { - mem.property_flags - .contains(vk::MemoryPropertyFlags::LAZILY_ALLOCATED) - }); + let supports_lazily_allocated = memory_types.iter().any(|mem| { + mem.property_flags + .contains(vk::MemoryPropertyFlags::LAZILY_ALLOCATED) + }); let info = wgt::AdapterInfo { name: { From 0e7295044cbcc701f21079c12cdf28408e93be28 Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Sun, 21 Sep 2025 04:54:27 -0400 Subject: [PATCH 27/49] Fix WebGPU compile --- wgpu/src/backend/webgpu.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/wgpu/src/backend/webgpu.rs b/wgpu/src/backend/webgpu.rs index 920ad58ba17..8363e68fca7 100644 --- a/wgpu/src/backend/webgpu.rs +++ b/wgpu/src/backend/webgpu.rs @@ -1691,6 +1691,7 @@ impl dispatch::AdapterInterface for WebAdapter { driver: String::new(), driver_info: String::new(), backend: wgt::Backend::BrowserWebGpu, + supports_transient: false, } } From 3d063d7eb43f3e776662f7a1d1ed7e1fa3855286 Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Sun, 21 Sep 2025 06:59:47 -0400 Subject: [PATCH 28/49] Add simple transient test case Renders a single triangle with transient texture as target to make sure nothing is wrong --- tests/tests/wgpu-gpu/main.rs | 2 + tests/tests/wgpu-gpu/transient.rs | 156 ++++++++++++++++++++++++++++++ 2 files changed, 158 insertions(+) create mode 100644 tests/tests/wgpu-gpu/transient.rs diff --git a/tests/tests/wgpu-gpu/main.rs b/tests/tests/wgpu-gpu/main.rs index d461845e92b..e08d396b95d 100644 --- a/tests/tests/wgpu-gpu/main.rs +++ b/tests/tests/wgpu-gpu/main.rs @@ -64,6 +64,7 @@ mod texture_view_creation; mod timestamp_normalization; mod timestamp_query; mod transfer; +mod transient; mod transition_resources; mod vertex_formats; mod vertex_indices; @@ -134,6 +135,7 @@ fn all_tests() -> Vec { timestamp_normalization::all_tests(&mut tests); timestamp_query::all_tests(&mut tests); transfer::all_tests(&mut tests); + transient::all_tests(&mut tests); transition_resources::all_tests(&mut tests); vertex_formats::all_tests(&mut tests); vertex_indices::all_tests(&mut tests); diff --git a/tests/tests/wgpu-gpu/transient.rs b/tests/tests/wgpu-gpu/transient.rs new file mode 100644 index 00000000000..8cf6dcc656b --- /dev/null +++ b/tests/tests/wgpu-gpu/transient.rs @@ -0,0 +1,156 @@ +use wgpu_test::{gpu_test, GpuTestConfiguration, GpuTestInitializer, TestParameters}; + +pub fn all_tests(vec: &mut Vec) { + vec.push(RESOLVE_WITH_TRANSIENT); +} + +#[gpu_test] +static RESOLVE_WITH_TRANSIENT: GpuTestConfiguration = GpuTestConfiguration::new() + .parameters(TestParameters::default()) + .run_async(|ctx| async move { + const SIZE: wgpu::Extent3d = wgpu::Extent3d { + width: 256, + height: 256, + depth_or_array_layers: 1, + }; + + let shader_src = " + @vertex + fn vs_main(@builtin(vertex_index) index: u32) -> @builtin(position) vec4f { + let positions: array = array( + vec2f(-1.0, -1.0), + vec2f(-1.0, 3.0), + vec2f(3.0, -1.0) + ); + return vec4f(positions[index], 0.0, 1.0); + } + + @fragment + fn fs_main() -> @location(0) vec4f { + return vec4f(1.0); + } + "; + + let shader = ctx + .device + .create_shader_module(wgpu::ShaderModuleDescriptor { + label: None, + source: wgpu::ShaderSource::Wgsl(shader_src.into()), + }); + + let pipeline_desc = wgpu::RenderPipelineDescriptor { + label: None, + layout: None, + vertex: wgpu::VertexState { + buffers: &[], + module: &shader, + entry_point: Some("vs_main"), + compilation_options: Default::default(), + }, + primitive: wgpu::PrimitiveState::default(), + depth_stencil: None, + multisample: wgpu::MultisampleState { + count: 4, + mask: !0, + alpha_to_coverage_enabled: false, + }, + fragment: Some(wgpu::FragmentState { + module: &shader, + entry_point: Some("fs_main"), + compilation_options: Default::default(), + targets: &[Some(wgpu::ColorTargetState { + format: wgpu::TextureFormat::Rgba8Unorm, + blend: None, + write_mask: wgpu::ColorWrites::ALL, + })], + }), + multiview: None, + cache: None, + }; + let pipeline = ctx.device.create_render_pipeline(&pipeline_desc); + + let transient_texture = ctx.device.create_texture(&wgpu::TextureDescriptor { + label: None, + size: SIZE, + mip_level_count: 1, + sample_count: 4, + dimension: wgpu::TextureDimension::D2, + format: wgpu::TextureFormat::Rgba8Unorm, + usage: wgpu::TextureUsages::RENDER_ATTACHMENT, + view_formats: &[], + }); + + let target_texture = ctx.device.create_texture(&wgpu::TextureDescriptor { + label: None, + size: SIZE, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: wgpu::TextureFormat::Rgba8Unorm, + usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_SRC, + view_formats: &[], + }); + + let readback_buffer = ctx.device.create_buffer(&wgpu::BufferDescriptor { + label: None, + size: 256 * 256 * 4, + usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::MAP_READ, + mapped_at_creation: false, + }); + + let mut encoder = ctx + .device + .create_command_encoder(&wgpu::CommandEncoderDescriptor::default()); + + { + let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: None, + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + view: &transient_texture.create_view(&wgpu::TextureViewDescriptor::default()), + depth_slice: None, + resolve_target: Some( + &target_texture.create_view(&wgpu::TextureViewDescriptor::default()), + ), + ops: wgpu::Operations { + load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT), + store: wgpu::StoreOp::Store, + }, + })], + depth_stencil_attachment: None, + timestamp_writes: None, + occlusion_query_set: None, + }); + + rpass.set_pipeline(&pipeline); + rpass.draw(0..3, 0..1); + } + + encoder.copy_texture_to_buffer( + wgpu::TexelCopyTextureInfo { + texture: &target_texture, + mip_level: 0, + origin: wgpu::Origin3d { x: 0, y: 0, z: 0 }, + aspect: wgpu::TextureAspect::All, + }, + wgpu::TexelCopyBufferInfo { + buffer: &readback_buffer, + layout: wgpu::TexelCopyBufferLayout { + offset: 0, + bytes_per_row: Some(256 * 4), + rows_per_image: Some(256), + }, + }, + SIZE, + ); + + ctx.queue.submit([encoder.finish()]); + + let slice = readback_buffer.slice(..); + slice.map_async(wgpu::MapMode::Read, |_| ()); + + ctx.async_poll(wgpu::PollType::wait()).await.unwrap(); + + let data = slice.get_mapped_range(); + let succeeded = data.iter().all(|b| *b == u8::MAX); + assert!(succeeded); + }); From 69d81105d931b6b3fe2b2e9d302f9dfcfee95de9 Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Sun, 21 Sep 2025 07:15:07 -0400 Subject: [PATCH 29/49] Actually use the transient flag in test --- tests/tests/wgpu-gpu/transient.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tests/wgpu-gpu/transient.rs b/tests/tests/wgpu-gpu/transient.rs index 8cf6dcc656b..8b48ca9e36f 100644 --- a/tests/tests/wgpu-gpu/transient.rs +++ b/tests/tests/wgpu-gpu/transient.rs @@ -76,7 +76,7 @@ static RESOLVE_WITH_TRANSIENT: GpuTestConfiguration = GpuTestConfiguration::new( sample_count: 4, dimension: wgpu::TextureDimension::D2, format: wgpu::TextureFormat::Rgba8Unorm, - usage: wgpu::TextureUsages::RENDER_ATTACHMENT, + usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::TRANSIENT, view_formats: &[], }); From 4598ebddc33469d5dd48db9b04198dd6961eb45c Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Sun, 21 Sep 2025 07:24:58 -0400 Subject: [PATCH 30/49] Well that was a nice demonstration of validation --- tests/tests/wgpu-gpu/transient.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tests/wgpu-gpu/transient.rs b/tests/tests/wgpu-gpu/transient.rs index 8b48ca9e36f..72cafe3259b 100644 --- a/tests/tests/wgpu-gpu/transient.rs +++ b/tests/tests/wgpu-gpu/transient.rs @@ -113,7 +113,7 @@ static RESOLVE_WITH_TRANSIENT: GpuTestConfiguration = GpuTestConfiguration::new( ), ops: wgpu::Operations { load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT), - store: wgpu::StoreOp::Store, + store: wgpu::StoreOp::Discard, }, })], depth_stencil_attachment: None, From dfb60debbacd7d2fca6236bc79300d424ecf31e3 Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Sun, 21 Sep 2025 18:42:03 -0400 Subject: [PATCH 31/49] Update `CHANGELOG.md` --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d1bf460ed2..c915cbb3317 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -166,7 +166,7 @@ By @cwfitzgerald in [#8162](https://github.com/gfx-rs/wgpu/pull/8162). - Added support for external textures based on WebGPU's [`GPUExternalTexture`](https://www.w3.org/TR/webgpu/#gpuexternaltexture). These allow shaders to transparently operate on potentially multiplanar source texture data in either RGB or YCbCr formats via WGSL's `texture_external` type. This is gated behind the `Features::EXTERNAL_TEXTURE` feature, which is currently only supported on DX12. By @jamienicol in [#4386](https://github.com/gfx-rs/wgpu/issues/4386). -- Added support for transient textures on Vulkan and Metal, gated behind the `Features::TRANSIENT_ATTACHMENTS` feature. By @Opstic in [#8247](https://github.com/gfx-rs/wgpu/pull/8247) +- Added support for transient textures on Vulkan and Metal. By @opstic in [#8247](https://github.com/gfx-rs/wgpu/pull/8247) ### Changes From 8182e41eb73e2bc325033ebb0ebd903470e755cc Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Tue, 23 Sep 2025 23:46:05 -0400 Subject: [PATCH 32/49] Use proper formatting for documentation --- wgpu-types/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 98324766c3c..77ffa4d7198 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -5606,7 +5606,7 @@ bitflags::bitflags! { const STORAGE_BINDING = 1 << 3; /// Allows a texture to be an output attachment of a render pass. /// - /// Consider adding ['TextureUsages::TRANSIENT'] if the contents are not reused. + /// Consider adding [`TextureUsages::TRANSIENT`] if the contents are not reused. const RENDER_ATTACHMENT = 1 << 4; // From b6e05b11afe6c31f6299aea997009f6cf7257385 Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Thu, 25 Sep 2025 00:29:35 -0400 Subject: [PATCH 33/49] Improve validation usage filtering by @cwfitzgerald Co-authored-by: Connor Fitzgerald --- tests/tests/wgpu-validation/api/texture.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/tests/tests/wgpu-validation/api/texture.rs b/tests/tests/wgpu-validation/api/texture.rs index e378e6b252c..50a4bebf549 100644 --- a/tests/tests/wgpu-validation/api/texture.rs +++ b/tests/tests/wgpu-validation/api/texture.rs @@ -521,13 +521,7 @@ fn transient_invalid_usage() { depth_or_array_layers: 1, }; - let invalid_usages = [ - wgpu::TextureUsages::COPY_SRC, - wgpu::TextureUsages::COPY_DST, - wgpu::TextureUsages::TEXTURE_BINDING, - wgpu::TextureUsages::STORAGE_BINDING, - wgpu::TextureUsages::STORAGE_ATOMIC, - ]; + let invalid_usages = wgpu::TextureUsages::all() - wgpu::TextureUsages::RENDER_ATTACHMENT - wgpu::TextureUsages::TRANSIENT; for usage in invalid_usages { let invalid_texture_descriptor = wgpu::TextureDescriptor { From 1332b31be1902b6f37a77190c29926a6525395e7 Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Thu, 25 Sep 2025 00:39:04 -0400 Subject: [PATCH 34/49] Improve documentation by @cwfitzgerald Co-authored-by: Connor Fitzgerald --- wgpu-types/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 77ffa4d7198..8310450875b 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -5618,7 +5618,8 @@ bitflags::bitflags! { const STORAGE_ATOMIC = 1 << 16; /// Specifies the contents of this texture will not be used in another pass to potentially reduce memory usage and bandwidth. /// - /// No-op on platforms other than Vulkan and Metal. + /// No-op on platforms on platforms that do not benefit from transient textures. + /// Generally mobile and Apple chips care about this. /// /// Incompatible with ALL other usages except [`TextureUsages::RENDER_ATTACHMENT`]. /// From 88b5cd4bdfbcf09c9922563d2dd62556d1b66f5b Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Thu, 25 Sep 2025 00:39:27 -0400 Subject: [PATCH 35/49] Improve documentation by @cwfitzgerald Co-authored-by: Connor Fitzgerald --- wgpu-types/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 8310450875b..745d844b4b8 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -1414,7 +1414,7 @@ pub struct AdapterInfo { pub driver_info: String, /// Backend used for device pub backend: Backend, - /// Supports [`TextureUsages::TRANSIENT`] + /// If true, adding [`TextureUsages::TRANSIENT`] will decrease memory usage. pub supports_transient: bool, } From 99ff738d97c05ee5056ec6fba664b6d6127b1ff9 Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Fri, 26 Sep 2025 12:48:18 -0400 Subject: [PATCH 36/49] Limit `supports_memoryless_storage` to Apple Silicon --- wgpu-hal/src/metal/adapter.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/wgpu-hal/src/metal/adapter.rs b/wgpu-hal/src/metal/adapter.rs index 17164e3c120..16b2e2b963e 100644 --- a/wgpu-hal/src/metal/adapter.rs +++ b/wgpu-hal/src/metal/adapter.rs @@ -902,7 +902,12 @@ impl super::PrivateCapabilities { && (device.supports_family(MTLGPUFamily::Apple7) || device.supports_family(MTLGPUFamily::Mac2)), supports_shared_event: version.at_least((10, 14), (12, 0), os_is_mac), - supports_memoryless_storage: version.at_least((11, 0), (10, 0), os_is_mac), + // https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf#page=3 + supports_memoryless_storage: if family_check { + device.supports_family(MTLGPUFamily::Apple2) || device.supports_family(MTLGPUFamily::Metal4) + } else { + version.at_least((11, 0), (10, 0), os_is_mac) + }, } } From 305a8fa84d1f4f2dcd29f6c598fcd7cd7780c4fa Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Fri, 26 Sep 2025 12:49:54 -0400 Subject: [PATCH 37/49] `cargo fmt` --- tests/tests/wgpu-validation/api/texture.rs | 4 +++- wgpu-hal/src/metal/adapter.rs | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/tests/wgpu-validation/api/texture.rs b/tests/tests/wgpu-validation/api/texture.rs index 50a4bebf549..56af9db74fe 100644 --- a/tests/tests/wgpu-validation/api/texture.rs +++ b/tests/tests/wgpu-validation/api/texture.rs @@ -521,7 +521,9 @@ fn transient_invalid_usage() { depth_or_array_layers: 1, }; - let invalid_usages = wgpu::TextureUsages::all() - wgpu::TextureUsages::RENDER_ATTACHMENT - wgpu::TextureUsages::TRANSIENT; + let invalid_usages = wgpu::TextureUsages::all() + - wgpu::TextureUsages::RENDER_ATTACHMENT + - wgpu::TextureUsages::TRANSIENT; for usage in invalid_usages { let invalid_texture_descriptor = wgpu::TextureDescriptor { diff --git a/wgpu-hal/src/metal/adapter.rs b/wgpu-hal/src/metal/adapter.rs index 16b2e2b963e..8a1536eb2a5 100644 --- a/wgpu-hal/src/metal/adapter.rs +++ b/wgpu-hal/src/metal/adapter.rs @@ -904,7 +904,8 @@ impl super::PrivateCapabilities { supports_shared_event: version.at_least((10, 14), (12, 0), os_is_mac), // https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf#page=3 supports_memoryless_storage: if family_check { - device.supports_family(MTLGPUFamily::Apple2) || device.supports_family(MTLGPUFamily::Metal4) + device.supports_family(MTLGPUFamily::Apple2) + || device.supports_family(MTLGPUFamily::Metal4) } else { version.at_least((11, 0), (10, 0), os_is_mac) }, From a3d8e86f804317e2de75c82226ebfa7f78481ff3 Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Fri, 26 Sep 2025 12:50:31 -0400 Subject: [PATCH 38/49] Move `TextureUsages::TRANSIENT` in `guaranteed_format_features` --- wgpu-types/src/lib.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 745d844b4b8..e277baf69be 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -3122,7 +3122,7 @@ impl TextureFormat { // Flags let basic = TextureUsages::COPY_SRC | TextureUsages::COPY_DST | TextureUsages::TEXTURE_BINDING; - let attachment = basic | TextureUsages::RENDER_ATTACHMENT; + let attachment = basic | TextureUsages::RENDER_ATTACHMENT | TextureUsages::TRANSIENT; let storage = basic | TextureUsages::STORAGE_BINDING; let binding = TextureUsages::TEXTURE_BINDING; let all_flags = attachment | storage | binding; @@ -3255,8 +3255,6 @@ impl TextureFormat { allowed_usages.contains(TextureUsages::STORAGE_ATOMIC), ); - allowed_usages |= TextureUsages::TRANSIENT; - TextureFormatFeatures { allowed_usages, flags, From 193a13815b6ca79b4547ac265197d65d9a76efc7 Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Fri, 26 Sep 2025 12:54:02 -0400 Subject: [PATCH 39/49] Remove unnecessary `mut` --- wgpu-types/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 8c05a7f80af..785d369e120 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -3150,7 +3150,7 @@ impl TextureFormat { #[rustfmt::skip] // lets make a nice table let ( mut flags, - mut allowed_usages, + allowed_usages, ) = match *self { Self::R8Unorm => (msaa_resolve, attachment), Self::R8Snorm => ( none, basic), From 440964fe2f4f9cd5a2c937ab82e9b76ef0a2cc76 Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Fri, 26 Sep 2025 13:03:10 -0400 Subject: [PATCH 40/49] `MTLGPUFamily::Metal4` doesn't exist yet in the version on `metal` we're using --- wgpu-hal/src/metal/adapter.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/wgpu-hal/src/metal/adapter.rs b/wgpu-hal/src/metal/adapter.rs index 8a1536eb2a5..4e1be2509c1 100644 --- a/wgpu-hal/src/metal/adapter.rs +++ b/wgpu-hal/src/metal/adapter.rs @@ -905,7 +905,6 @@ impl super::PrivateCapabilities { // https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf#page=3 supports_memoryless_storage: if family_check { device.supports_family(MTLGPUFamily::Apple2) - || device.supports_family(MTLGPUFamily::Metal4) } else { version.at_least((11, 0), (10, 0), os_is_mac) }, From 59118fb1abc7d0c008dfb4f7e08a656a3247ac33 Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Mon, 6 Oct 2025 19:43:38 -0400 Subject: [PATCH 41/49] Improve transient support hint naming --- wgpu-core/src/pipeline_cache.rs | 2 +- wgpu-hal/src/dx12/adapter.rs | 2 +- wgpu-hal/src/gles/adapter.rs | 2 +- wgpu-hal/src/metal/mod.rs | 2 +- wgpu-hal/src/noop/mod.rs | 2 +- wgpu-hal/src/vulkan/adapter.rs | 2 +- wgpu-types/src/lib.rs | 2 +- wgpu/src/backend/webgpu.rs | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/wgpu-core/src/pipeline_cache.rs b/wgpu-core/src/pipeline_cache.rs index 3e29d3e0a26..a406716968f 100644 --- a/wgpu-core/src/pipeline_cache.rs +++ b/wgpu-core/src/pipeline_cache.rs @@ -322,7 +322,7 @@ mod tests { driver: String::new(), driver_info: String::new(), backend: wgt::Backend::Vulkan, - supports_transient: true, + transient_saves_memory: true, }; // IMPORTANT: If these tests fail, then you MUST increment HEADER_VERSION diff --git a/wgpu-hal/src/dx12/adapter.rs b/wgpu-hal/src/dx12/adapter.rs index c49c015913e..0a08e1d9884 100644 --- a/wgpu-hal/src/dx12/adapter.rs +++ b/wgpu-hal/src/dx12/adapter.rs @@ -142,7 +142,7 @@ impl super::Adapter { } }, driver_info: String::new(), - supports_transient: false, + transient_saves_memory: false, }; let mut options = Direct3D12::D3D12_FEATURE_DATA_D3D12_OPTIONS::default(); diff --git a/wgpu-hal/src/gles/adapter.rs b/wgpu-hal/src/gles/adapter.rs index 4c427ed35bc..dc73ae51207 100644 --- a/wgpu-hal/src/gles/adapter.rs +++ b/wgpu-hal/src/gles/adapter.rs @@ -189,7 +189,7 @@ impl super::Adapter { driver: "".to_owned(), driver_info: version, backend: wgt::Backend::Gl, - supports_transient: false, + transient_saves_memory: false, } } diff --git a/wgpu-hal/src/metal/mod.rs b/wgpu-hal/src/metal/mod.rs index 51827920f23..0dead249b8f 100644 --- a/wgpu-hal/src/metal/mod.rs +++ b/wgpu-hal/src/metal/mod.rs @@ -159,7 +159,7 @@ impl crate::Instance for Instance { driver: String::new(), driver_info: String::new(), backend: wgt::Backend::Metal, - supports_transient: shared.private_caps.supports_memoryless_storage, + transient_saves_memory: shared.private_caps.supports_memoryless_storage, }, features: shared.private_caps.features(), capabilities: shared.private_caps.capabilities(), diff --git a/wgpu-hal/src/noop/mod.rs b/wgpu-hal/src/noop/mod.rs index 109804a5be6..bcec8a48897 100644 --- a/wgpu-hal/src/noop/mod.rs +++ b/wgpu-hal/src/noop/mod.rs @@ -140,7 +140,7 @@ pub fn adapter_info() -> wgt::AdapterInfo { driver: String::from("wgpu"), driver_info: String::new(), backend: wgt::Backend::Noop, - supports_transient: true, + transient_saves_memory: true, } } diff --git a/wgpu-hal/src/vulkan/adapter.rs b/wgpu-hal/src/vulkan/adapter.rs index 09fa9a709de..ba50eed76f0 100644 --- a/wgpu-hal/src/vulkan/adapter.rs +++ b/wgpu-hal/src/vulkan/adapter.rs @@ -1691,7 +1691,7 @@ impl super::Instance { .to_owned() }, backend: wgt::Backend::Vulkan, - supports_transient: supports_lazily_allocated, + transient_saves_memory: supports_lazily_allocated, }; let (available_features, mut downlevel_flags) = phd_features.to_wgpu(&self.shared.raw, phd, &phd_capabilities); diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 785d369e120..d81c0d03c08 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -1415,7 +1415,7 @@ pub struct AdapterInfo { /// Backend used for device pub backend: Backend, /// If true, adding [`TextureUsages::TRANSIENT`] will decrease memory usage. - pub supports_transient: bool, + pub transient_saves_memory: bool, } /// Hints to the device about the memory allocation strategy. diff --git a/wgpu/src/backend/webgpu.rs b/wgpu/src/backend/webgpu.rs index 8363e68fca7..979afdf8af0 100644 --- a/wgpu/src/backend/webgpu.rs +++ b/wgpu/src/backend/webgpu.rs @@ -1691,7 +1691,7 @@ impl dispatch::AdapterInterface for WebAdapter { driver: String::new(), driver_info: String::new(), backend: wgt::Backend::BrowserWebGpu, - supports_transient: false, + transient_saves_memory: false, } } From d711c117ef21b01205286d5437704d2697ad0311 Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Mon, 6 Oct 2025 19:45:25 -0400 Subject: [PATCH 42/49] Correct `AdapterInfo` for `noop` backend --- wgpu-hal/src/noop/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wgpu-hal/src/noop/mod.rs b/wgpu-hal/src/noop/mod.rs index bcec8a48897..2fb2445dbc6 100644 --- a/wgpu-hal/src/noop/mod.rs +++ b/wgpu-hal/src/noop/mod.rs @@ -140,7 +140,7 @@ pub fn adapter_info() -> wgt::AdapterInfo { driver: String::from("wgpu"), driver_info: String::new(), backend: wgt::Backend::Noop, - transient_saves_memory: true, + transient_saves_memory: false, } } From 64a7e3266fc0b1ca838b83b6161ab17b56c1ca0e Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Mon, 6 Oct 2025 22:01:51 -0400 Subject: [PATCH 43/49] Fix compile --- tests/tests/wgpu-gpu/transient.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tests/wgpu-gpu/transient.rs b/tests/tests/wgpu-gpu/transient.rs index 72cafe3259b..7b28ccdecbb 100644 --- a/tests/tests/wgpu-gpu/transient.rs +++ b/tests/tests/wgpu-gpu/transient.rs @@ -148,7 +148,7 @@ static RESOLVE_WITH_TRANSIENT: GpuTestConfiguration = GpuTestConfiguration::new( let slice = readback_buffer.slice(..); slice.map_async(wgpu::MapMode::Read, |_| ()); - ctx.async_poll(wgpu::PollType::wait()).await.unwrap(); + ctx.async_poll(wgpu::PollType::wait_indefinitely()).await.unwrap(); let data = slice.get_mapped_range(); let succeeded = data.iter().all(|b| *b == u8::MAX); From b1b9bb572a02e403547fe0101d4d0c8fbe173545 Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Mon, 6 Oct 2025 22:04:37 -0400 Subject: [PATCH 44/49] `cargo fmt` --- tests/tests/wgpu-gpu/transient.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/tests/wgpu-gpu/transient.rs b/tests/tests/wgpu-gpu/transient.rs index 7b28ccdecbb..072f9415559 100644 --- a/tests/tests/wgpu-gpu/transient.rs +++ b/tests/tests/wgpu-gpu/transient.rs @@ -148,7 +148,9 @@ static RESOLVE_WITH_TRANSIENT: GpuTestConfiguration = GpuTestConfiguration::new( let slice = readback_buffer.slice(..); slice.map_async(wgpu::MapMode::Read, |_| ()); - ctx.async_poll(wgpu::PollType::wait_indefinitely()).await.unwrap(); + ctx.async_poll(wgpu::PollType::wait_indefinitely()) + .await + .unwrap(); let data = slice.get_mapped_range(); let succeeded = data.iter().all(|b| *b == u8::MAX); From 052ba984e01827b8fcc253fb3d362a55499e54bc Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Wed, 8 Oct 2025 00:38:13 -0400 Subject: [PATCH 45/49] Allow `TextureUsages::TRANSIENT` along with `TextureUsages::RENDER_ATTACHMENT` --- wgpu-core/src/instance.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/wgpu-core/src/instance.rs b/wgpu-core/src/instance.rs index b72effd6993..4f5c831736c 100644 --- a/wgpu-core/src/instance.rs +++ b/wgpu-core/src/instance.rs @@ -699,14 +699,13 @@ impl Adapter { ), ); allowed_usages.set( - wgt::TextureUsages::RENDER_ATTACHMENT, + wgt::TextureUsages::RENDER_ATTACHMENT | wgt::TextureUsages::TRANSIENT, caps.intersects(Tfc::COLOR_ATTACHMENT | Tfc::DEPTH_STENCIL_ATTACHMENT), ); allowed_usages.set( wgt::TextureUsages::STORAGE_ATOMIC, caps.contains(Tfc::STORAGE_ATOMIC), ); - allowed_usages |= wgt::TextureUsages::TRANSIENT; let mut flags = wgt::TextureFormatFeatureFlags::empty(); flags.set( From d3701bce8874b6b1b703263959a69911525af783 Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Wed, 8 Oct 2025 00:46:10 -0400 Subject: [PATCH 46/49] Disallow `TextureUsages::TRANSIENT` if `TextureUsages::RENDER_ATTACHMENT` isn't present. --- wgpu-core/src/device/resource.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/wgpu-core/src/device/resource.rs b/wgpu-core/src/device/resource.rs index 2b87eea04bb..326fbb17ea1 100644 --- a/wgpu-core/src/device/resource.rs +++ b/wgpu-core/src/device/resource.rs @@ -1275,6 +1275,11 @@ impl Device { } if desc.usage.contains(wgt::TextureUsages::TRANSIENT) { + if !desc.usage.contains(wgt::TextureUsages::RENDER_ATTACHMENT) { + return Err(CreateTextureError::InvalidUsage( + wgt::TextureUsages::TRANSIENT, + )); + } let extra_usage = desc.usage - wgt::TextureUsages::TRANSIENT - wgt::TextureUsages::RENDER_ATTACHMENT; if !extra_usage.is_empty() { From 653e1a281e85a9be05a326f63b0dd5c89e91f56d Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Wed, 8 Oct 2025 00:47:12 -0400 Subject: [PATCH 47/49] Update docs --- wgpu-types/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 62f1de6d95a..574e9bfbfe1 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -5630,7 +5630,7 @@ bitflags::bitflags! { /// No-op on platforms on platforms that do not benefit from transient textures. /// Generally mobile and Apple chips care about this. /// - /// Incompatible with ALL other usages except [`TextureUsages::RENDER_ATTACHMENT`]. + /// Incompatible with ALL other usages except [`TextureUsages::RENDER_ATTACHMENT`] and requires it. /// /// Requires [`StoreOp::Discard`]. const TRANSIENT = 1 << 17; From 48b76ff0cdf3f3aa96054e5e2fbf3b0c17946f76 Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Wed, 8 Oct 2025 01:10:16 -0400 Subject: [PATCH 48/49] Update validation test --- tests/tests/wgpu-validation/api/texture.rs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/tests/tests/wgpu-validation/api/texture.rs b/tests/tests/wgpu-validation/api/texture.rs index 56af9db74fe..6779a10581f 100644 --- a/tests/tests/wgpu-validation/api/texture.rs +++ b/tests/tests/wgpu-validation/api/texture.rs @@ -533,7 +533,7 @@ fn transient_invalid_usage() { sample_count: 1, dimension: wgpu::TextureDimension::D2, format: wgpu::TextureFormat::Rgba8Unorm, - usage: wgpu::TextureUsages::TRANSIENT | usage, + usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::TRANSIENT | usage, view_formats: &[], }; fail( @@ -544,6 +544,24 @@ fn transient_invalid_usage() { Some(&format!("Texture usage TextureUsages(TRANSIENT) is not compatible with texture usage {usage:?}")), ); } + + let invalid_texture_descriptor = wgpu::TextureDescriptor { + label: None, + size, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: wgpu::TextureFormat::Rgba8Unorm, + usage: wgpu::TextureUsages::TRANSIENT, + view_formats: &[], + }; + fail( + &device, + || { + device.create_texture(&invalid_texture_descriptor) + }, + Some("Invalid usage flags TextureUsages(TRANSIENT)"), + ); } /// Ensures that attempting to use a texture of [`wgpu::TextureUsages::TRANSIENT`] From bbfb1ebc5e1242abeef21f7eedcb520b70e56a9a Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Wed, 8 Oct 2025 04:38:19 -0400 Subject: [PATCH 49/49] `cargo fmt` --- tests/tests/wgpu-validation/api/texture.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/tests/tests/wgpu-validation/api/texture.rs b/tests/tests/wgpu-validation/api/texture.rs index 6779a10581f..00525420375 100644 --- a/tests/tests/wgpu-validation/api/texture.rs +++ b/tests/tests/wgpu-validation/api/texture.rs @@ -538,9 +538,7 @@ fn transient_invalid_usage() { }; fail( &device, - || { - device.create_texture(&invalid_texture_descriptor) - }, + || device.create_texture(&invalid_texture_descriptor), Some(&format!("Texture usage TextureUsages(TRANSIENT) is not compatible with texture usage {usage:?}")), ); } @@ -557,9 +555,7 @@ fn transient_invalid_usage() { }; fail( &device, - || { - device.create_texture(&invalid_texture_descriptor) - }, + || device.create_texture(&invalid_texture_descriptor), Some("Invalid usage flags TextureUsages(TRANSIENT)"), ); }