Skip to content
Open
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
56d648a
Preliminary implementation
opstic Sep 19, 2025
8c7dace
Merge branch 'gfx-rs:trunk' into transient
opstic Sep 19, 2025
598259c
oops
opstic Sep 19, 2025
9ec9242
Better implementation
opstic Sep 19, 2025
2185cd8
Add entry in `CHANGELOG.md`
opstic Sep 19, 2025
625bf3b
Remove `Feature::TRANSIENT_ATTACHMENTS` and add validation
opstic Sep 20, 2025
5644cd2
Remove `#[cfg(windows)]` from `find_memory_type_index`
opstic Sep 20, 2025
6c3d11b
Tries to find a memory type that contains `MemoryPropertyFlags::LAZIL…
opstic Sep 20, 2025
a16ec0c
Merge branch 'trunk' into transient
opstic Sep 20, 2025
aafa05e
`cargo fmt`
opstic Sep 20, 2025
703bf26
Add check in Metal for `MTLStorageMode::Memoryless` support
opstic Sep 20, 2025
02201f4
Apply `TextureUsages::TRANSIENT` to relevant examples
opstic Sep 20, 2025
c1c04ec
Improve documentation by @cwfitzgerald
opstic Sep 20, 2025
77bf9af
Improve error message by @cwfitzgerald
opstic Sep 20, 2025
faea1c3
Move `TextureUses::TRANSIENT` to `1 << 12`
opstic Sep 20, 2025
56b3956
Improve `TextureUsages` docs
opstic Sep 20, 2025
15ded86
Better wording
opstic Sep 20, 2025
e0280d9
Add `StoreOp` requirement
opstic Sep 20, 2025
01776c8
Allow `TextureUsages::TRANSIENT` in `guaranteed_format_features`
opstic Sep 20, 2025
607ed01
Improve error message
opstic Sep 20, 2025
ef922ef
Add `TextureUses::TRANSIENT` to GL backend's `render_usage`
opstic Sep 20, 2025
54c4cc0
Improve docs
opstic Sep 20, 2025
f50b098
Add validation tests
opstic Sep 20, 2025
df228e0
Fix `TextureUsages::TRANSIENT` docs formatting
opstic Sep 21, 2025
f6f2de8
Add `supports_transient` flag in `AdapterInfo`
opstic Sep 21, 2025
e30db54
Merge branch 'trunk' into transient
opstic Sep 21, 2025
c28ea1a
oops
opstic Sep 21, 2025
cb248c5
📎
opstic Sep 21, 2025
1a09f3c
Formatting
opstic Sep 21, 2025
0e72950
Fix WebGPU compile
opstic Sep 21, 2025
3d063d7
Add simple transient test case
opstic Sep 21, 2025
69d8110
Actually use the transient flag in test
opstic Sep 21, 2025
5b0eb92
Merge branch 'trunk' into transient
opstic Sep 21, 2025
4598ebd
Well that was a nice demonstration of validation
opstic Sep 21, 2025
dfb60de
Update `CHANGELOG.md`
opstic Sep 21, 2025
8182e41
Use proper formatting for documentation
opstic Sep 24, 2025
0124879
Merge branch 'trunk' into transient
opstic Sep 24, 2025
7af040e
Merge branch 'trunk' into transient
opstic Sep 24, 2025
b6e05b1
Improve validation usage filtering by @cwfitzgerald
opstic Sep 25, 2025
1332b31
Improve documentation by @cwfitzgerald
opstic Sep 25, 2025
88b5cd4
Improve documentation by @cwfitzgerald
opstic Sep 25, 2025
99ff738
Limit `supports_memoryless_storage` to Apple Silicon
opstic Sep 26, 2025
126e45b
Merge remote-tracking branch 'fork/transient' into transient
opstic Sep 26, 2025
305a8fa
`cargo fmt`
opstic Sep 26, 2025
a3d8e86
Move `TextureUsages::TRANSIENT` in `guaranteed_format_features`
opstic Sep 26, 2025
584f4f7
Merge branch 'trunk' into transient
opstic Sep 26, 2025
193a138
Remove unnecessary `mut`
opstic Sep 26, 2025
440964f
`MTLGPUFamily::Metal4` doesn't exist yet in the version on `metal` we…
opstic Sep 26, 2025
59118fb
Improve transient support hint naming
opstic Oct 6, 2025
d711c11
Correct `AdapterInfo` for `noop` backend
opstic Oct 6, 2025
146806b
Merge branch 'trunk' into transient
opstic Oct 7, 2025
64a7e32
Fix compile
opstic Oct 7, 2025
b1b9bb5
`cargo fmt`
opstic Oct 7, 2025
75ce4ad
Merge branch 'trunk' into transient
opstic Oct 8, 2025
052ba98
Allow `TextureUsages::TRANSIENT` along with `TextureUsages::RENDER_AT…
opstic Oct 8, 2025
d3701bc
Disallow `TextureUsages::TRANSIENT` if `TextureUsages::RENDER_ATTACHM…
opstic Oct 8, 2025
653e1a2
Update docs
opstic Oct 8, 2025
48b76ff
Update validation test
opstic Oct 8, 2025
bbfb1eb
`cargo fmt`
opstic Oct 8, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
13 changes: 13 additions & 0 deletions wgpu-core/src/command/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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)?;
Expand Down
8 changes: 8 additions & 0 deletions wgpu-core/src/conv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down Expand Up @@ -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
}

Expand Down
11 changes: 11 additions & 0 deletions wgpu-core/src/device/resource.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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))?;
Expand Down
1 change: 1 addition & 0 deletions wgpu-core/src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
3 changes: 3 additions & 0 deletions wgpu-core/src/resource.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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:?}")]
Expand Down Expand Up @@ -1564,6 +1566,7 @@ impl WebGpuError for CreateTextureError {
Self::MissingDownlevelFlags(e) => e,

Self::InvalidUsage(_)
| Self::IncompatibleUsage(_, _)
| Self::InvalidDepthDimension(_, _)
| Self::InvalidCompressedDimension(_, _)
| Self::InvalidMipLevelCount { .. }
Expand Down
1 change: 1 addition & 0 deletions wgpu-hal/src/metal/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -902,6 +902,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),
}
}

Expand Down
10 changes: 9 additions & 1 deletion wgpu-hal/src/metal/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -452,13 +452,21 @@ impl crate::Device for super::Device {
}
};

let mtl_storage_mode = if desc.usage.contains(wgt::TextureUses::TRANSIENT)
&& self.shared.private_caps.supports_memoryless_storage
{
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() {
Expand Down
1 change: 1 addition & 0 deletions wgpu-hal/src/metal/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@ struct PrivateCapabilities {
int64_atomics: bool,
float_atomics: bool,
supports_shared_event: bool,
supports_memoryless_storage: bool,
}

#[derive(Clone, Debug)]
Expand Down
6 changes: 6 additions & 0 deletions wgpu-hal/src/vulkan/conv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down Expand Up @@ -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
}

Expand Down
13 changes: 11 additions & 2 deletions wgpu-hal/src/vulkan/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -648,7 +648,6 @@ impl super::Device {
}
}

#[cfg(windows)]
fn find_memory_type_index(
&self,
type_bits_req: u32,
Expand Down Expand Up @@ -738,7 +737,17 @@ 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,
Expand Down
4 changes: 4 additions & 0 deletions wgpu-types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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. No-op on platforms other than Vulkan and Metal.
const TRANSIENT = 1 << 17;
}
}

Expand Down Expand Up @@ -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;
}
}

Expand Down
Loading