wgpu/tests/tests/wgpu-gpu/transient.rs
Opstic f0209e3db8
Add support for transient textures on Vulkan and Metal (#8247)
Co-authored-by: Connor Fitzgerald <connorwadefitzgerald@gmail.com>
2025-10-16 19:50:01 +00:00

159 lines
5.5 KiB
Rust

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);
});