mirror of
https://github.com/gfx-rs/wgpu.git
synced 2025-12-08 21:26:17 +00:00
Add support for transient textures on Vulkan and Metal (#8247)
Co-authored-by: Connor Fitzgerald <connorwadefitzgerald@gmail.com>
This commit is contained in:
parent
7fdc5f1086
commit
f0209e3db8
@ -275,6 +275,8 @@ By @wumpf in [#8282](https://github.com/gfx-rs/wgpu/pull/8282), [#8285](https://
|
||||
|
||||
- Expose `naga::front::wgsl::UnimplementedEnableExtension`. By @ErichDonGubler in [#8237](https://github.com/gfx-rs/wgpu/pull/8237).
|
||||
|
||||
- Added support for transient textures on Vulkan and Metal. By @opstic in [#8247](https://github.com/gfx-rs/wgpu/pull/8247)
|
||||
|
||||
### Changes
|
||||
|
||||
#### General
|
||||
|
||||
@ -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: &[],
|
||||
};
|
||||
|
||||
@ -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: &[],
|
||||
});
|
||||
|
||||
@ -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: &[],
|
||||
});
|
||||
|
||||
@ -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;
|
||||
@ -135,6 +136,7 @@ fn all_tests() -> Vec<wgpu_test::GpuTestInitializer> {
|
||||
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);
|
||||
|
||||
158
tests/tests/wgpu-gpu/transient.rs
Normal file
158
tests/tests/wgpu-gpu/transient.rs
Normal file
@ -0,0 +1,158 @@
|
||||
use wgpu_test::{gpu_test, GpuTestConfiguration, GpuTestInitializer, TestParameters};
|
||||
|
||||
pub fn all_tests(vec: &mut Vec<GpuTestInitializer>) {
|
||||
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<vec2f, 3> = array<vec2f, 3>(
|
||||
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 | wgpu::TextureUsages::TRANSIENT,
|
||||
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::Discard,
|
||||
},
|
||||
})],
|
||||
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_indefinitely())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let data = slice.get_mapped_range();
|
||||
let succeeded = data.iter().all(|b| *b == u8::MAX);
|
||||
assert!(succeeded);
|
||||
});
|
||||
@ -496,3 +496,106 @@ 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::all()
|
||||
- wgpu::TextureUsages::RENDER_ATTACHMENT
|
||||
- wgpu::TextureUsages::TRANSIENT;
|
||||
|
||||
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::RENDER_ATTACHMENT | 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:?}")),
|
||||
);
|
||||
}
|
||||
|
||||
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`]
|
||||
/// 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")
|
||||
);
|
||||
}
|
||||
|
||||
@ -629,6 +629,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::{1:?}, but StoreOp::{2:?} was provided")]
|
||||
InvalidUsageForStoreOp(TextureUsages, StoreOp, StoreOp),
|
||||
}
|
||||
|
||||
impl WebGpuError for ColorAttachmentError {
|
||||
@ -1585,6 +1587,18 @@ 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,
|
||||
StoreOp::Discard,
|
||||
*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)?;
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
||||
@ -1274,6 +1274,22 @@ 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() {
|
||||
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))?;
|
||||
|
||||
@ -699,7 +699,7 @@ 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(
|
||||
|
||||
@ -322,6 +322,7 @@ mod tests {
|
||||
driver: String::new(),
|
||||
driver_info: String::new(),
|
||||
backend: wgt::Backend::Vulkan,
|
||||
transient_saves_memory: true,
|
||||
};
|
||||
|
||||
// IMPORTANT: If these tests fail, then you MUST increment HEADER_VERSION
|
||||
|
||||
@ -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 { .. }
|
||||
|
||||
@ -142,6 +142,7 @@ impl super::Adapter {
|
||||
}
|
||||
},
|
||||
driver_info: String::new(),
|
||||
transient_saves_memory: false,
|
||||
};
|
||||
|
||||
let mut options = Direct3D12::D3D12_FEATURE_DATA_D3D12_OPTIONS::default();
|
||||
|
||||
@ -189,6 +189,7 @@ impl super::Adapter {
|
||||
driver: "".to_owned(),
|
||||
driver_info: version,
|
||||
backend: wgt::Backend::Gl,
|
||||
transient_saves_memory: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -902,6 +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),
|
||||
// https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf#page=3
|
||||
supports_memoryless_storage: if family_check {
|
||||
device.supports_family(MTLGPUFamily::Apple2)
|
||||
} else {
|
||||
version.at_least((11, 0), (10, 0), os_is_mac)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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() {
|
||||
|
||||
@ -159,6 +159,7 @@ impl crate::Instance for Instance {
|
||||
driver: String::new(),
|
||||
driver_info: String::new(),
|
||||
backend: wgt::Backend::Metal,
|
||||
transient_saves_memory: shared.private_caps.supports_memoryless_storage,
|
||||
},
|
||||
features: shared.private_caps.features(),
|
||||
capabilities: shared.private_caps.capabilities(),
|
||||
@ -300,6 +301,7 @@ struct PrivateCapabilities {
|
||||
int64_atomics: bool,
|
||||
float_atomics: bool,
|
||||
supports_shared_event: bool,
|
||||
supports_memoryless_storage: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
||||
@ -140,6 +140,7 @@ pub fn adapter_info() -> wgt::AdapterInfo {
|
||||
driver: String::from("wgpu"),
|
||||
driver_info: String::new(),
|
||||
backend: wgt::Backend::Noop,
|
||||
transient_saves_memory: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1642,6 +1642,16 @@ 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().any(|mem| {
|
||||
mem.property_flags
|
||||
.contains(vk::MemoryPropertyFlags::LAZILY_ALLOCATED)
|
||||
});
|
||||
|
||||
let info = wgt::AdapterInfo {
|
||||
name: {
|
||||
phd_capabilities
|
||||
@ -1681,6 +1691,7 @@ impl super::Instance {
|
||||
.to_owned()
|
||||
},
|
||||
backend: wgt::Backend::Vulkan,
|
||||
transient_saves_memory: supports_lazily_allocated,
|
||||
};
|
||||
let (available_features, mut downlevel_flags) =
|
||||
phd_features.to_wgpu(&self.shared.raw, phd, &phd_capabilities);
|
||||
|
||||
@ -260,6 +260,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
|
||||
}
|
||||
|
||||
@ -349,6 +352,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
|
||||
}
|
||||
|
||||
|
||||
@ -649,7 +649,6 @@ impl super::Device {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn find_memory_type_index(
|
||||
&self,
|
||||
type_bits_req: u32,
|
||||
@ -739,7 +738,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,
|
||||
|
||||
@ -1415,6 +1415,8 @@ pub struct AdapterInfo {
|
||||
pub driver_info: String,
|
||||
/// Backend used for device
|
||||
pub backend: Backend,
|
||||
/// If true, adding [`TextureUsages::TRANSIENT`] to a texture will decrease memory usage.
|
||||
pub transient_saves_memory: bool,
|
||||
}
|
||||
|
||||
/// Hints to the device about the memory allocation strategy.
|
||||
@ -3121,7 +3123,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;
|
||||
@ -5612,6 +5614,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.
|
||||
///
|
||||
/// Consider adding [`TextureUsages::TRANSIENT`] if the contents are not reused.
|
||||
const RENDER_ATTACHMENT = 1 << 4;
|
||||
|
||||
//
|
||||
@ -5621,6 +5625,15 @@ 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 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`] and requires it.
|
||||
///
|
||||
/// Requires [`StoreOp::Discard`].
|
||||
const TRANSIENT = 1 << 17;
|
||||
}
|
||||
}
|
||||
|
||||
@ -5658,6 +5671,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();
|
||||
@ -5671,10 +5686,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;
|
||||
const UNKNOWN = 1 << 14;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1710,6 +1710,7 @@ impl dispatch::AdapterInterface for WebAdapter {
|
||||
driver: String::new(),
|
||||
driver_info: String::new(),
|
||||
backend: wgt::Backend::BrowserWebGpu,
|
||||
transient_saves_memory: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user