Files
2025-02-23 14:06:34 -05:00

187 lines
6.3 KiB
Rust

use std::time::Duration;
use wgpu::wgt::BufferDescriptor;
use wgpu::{
include_wgsl, BindGroupDescriptor, BindGroupEntry, BindingResource, BufferUsages,
ComputePassDescriptor, ComputePipelineDescriptor, DownlevelFlags, Extent3d, Features, MapMode,
Origin3d, PollType, TexelCopyBufferInfo, TexelCopyBufferLayout, TexelCopyTextureInfo,
TextureAspect, TextureDescriptor, TextureDimension, TextureFormat, TextureUsages,
};
use wgpu_macros::gpu_test;
use wgpu_test::{GpuTestConfiguration, TestParameters, TestingContext};
#[gpu_test]
static TEXTURE_BINDING: GpuTestConfiguration = GpuTestConfiguration::new()
.parameters(
TestParameters::default()
.test_features_limits()
.downlevel_flags(DownlevelFlags::WEBGPU_TEXTURE_FORMAT_SUPPORT)
.features(Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES),
)
.run_sync(texture_binding);
fn texture_binding(ctx: TestingContext) {
let texture = ctx.device.create_texture(&TextureDescriptor {
label: None,
size: Extent3d {
width: 1,
height: 1,
depth_or_array_layers: 1,
},
mip_level_count: 1,
sample_count: 1,
dimension: TextureDimension::D2,
format: TextureFormat::Rg32Float,
usage: TextureUsages::STORAGE_BINDING,
view_formats: &[],
});
let shader = ctx
.device
.create_shader_module(include_wgsl!("shader.wgsl"));
let pipeline = ctx
.device
.create_compute_pipeline(&ComputePipelineDescriptor {
label: None,
layout: None,
module: &shader,
entry_point: None,
compilation_options: Default::default(),
cache: None,
});
let bind = ctx.device.create_bind_group(&BindGroupDescriptor {
label: None,
layout: &pipeline.get_bind_group_layout(0),
entries: &[BindGroupEntry {
binding: 0,
resource: BindingResource::TextureView(&texture.create_view(&Default::default())),
}],
});
let mut encoder = ctx.device.create_command_encoder(&Default::default());
{
let mut pass = encoder.begin_compute_pass(&ComputePassDescriptor::default());
pass.set_pipeline(&pipeline);
pass.set_bind_group(0, &bind, &[]);
pass.dispatch_workgroups(1, 1, 1);
}
ctx.queue.submit([encoder.finish()]);
}
#[gpu_test]
static SINGLE_SCALAR_LOAD: GpuTestConfiguration = GpuTestConfiguration::new()
.parameters(
TestParameters::default()
.test_features_limits()
.downlevel_flags(DownlevelFlags::WEBGPU_TEXTURE_FORMAT_SUPPORT)
.features(Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES),
)
.run_sync(single_scalar_load);
fn single_scalar_load(ctx: TestingContext) {
let texture_read = ctx.device.create_texture(&TextureDescriptor {
label: None,
size: Extent3d {
width: 1,
height: 1,
depth_or_array_layers: 1,
},
mip_level_count: 1,
sample_count: 1,
dimension: TextureDimension::D2,
format: TextureFormat::R32Float,
usage: TextureUsages::STORAGE_BINDING,
view_formats: &[],
});
let texture_write = ctx.device.create_texture(&TextureDescriptor {
label: None,
size: Extent3d {
width: 1,
height: 1,
depth_or_array_layers: 1,
},
mip_level_count: 1,
sample_count: 1,
dimension: TextureDimension::D2,
format: TextureFormat::Rgba32Float,
usage: TextureUsages::STORAGE_BINDING | TextureUsages::COPY_SRC,
view_formats: &[],
});
let buffer = ctx.device.create_buffer(&BufferDescriptor {
label: None,
size: size_of::<[f32; 4]>() as wgpu::BufferAddress,
usage: BufferUsages::MAP_READ | BufferUsages::COPY_DST,
mapped_at_creation: false,
});
let shader = ctx
.device
.create_shader_module(include_wgsl!("single_scalar.wgsl"));
let pipeline = ctx
.device
.create_compute_pipeline(&ComputePipelineDescriptor {
label: None,
layout: None,
module: &shader,
entry_point: None,
compilation_options: Default::default(),
cache: None,
});
let bind = ctx.device.create_bind_group(&BindGroupDescriptor {
label: None,
layout: &pipeline.get_bind_group_layout(0),
entries: &[
BindGroupEntry {
binding: 0,
resource: BindingResource::TextureView(
&texture_write.create_view(&Default::default()),
),
},
BindGroupEntry {
binding: 1,
resource: BindingResource::TextureView(
&texture_read.create_view(&Default::default()),
),
},
],
});
let mut encoder = ctx.device.create_command_encoder(&Default::default());
{
let mut pass = encoder.begin_compute_pass(&ComputePassDescriptor::default());
pass.set_pipeline(&pipeline);
pass.set_bind_group(0, &bind, &[]);
pass.dispatch_workgroups(1, 1, 1);
}
encoder.copy_texture_to_buffer(
TexelCopyTextureInfo {
texture: &texture_write,
mip_level: 0,
origin: Origin3d::ZERO,
aspect: TextureAspect::All,
},
TexelCopyBufferInfo {
buffer: &buffer,
layout: TexelCopyBufferLayout {
offset: 0,
bytes_per_row: None,
rows_per_image: None,
},
},
Extent3d {
width: 1,
height: 1,
depth_or_array_layers: 1,
},
);
ctx.queue.submit([encoder.finish()]);
let (send, recv) = std::sync::mpsc::channel();
buffer.slice(..).map_async(MapMode::Read, move |res| {
res.unwrap();
send.send(()).expect("Thread should wait for receive");
});
// Poll to run map.
ctx.device.poll(PollType::Wait).unwrap();
recv.recv_timeout(Duration::from_secs(10))
.expect("mapping should not take this long");
let val = *bytemuck::from_bytes::<[f32; 4]>(&buffer.slice(..).get_mapped_range());
assert_eq!(val, [0.0, 0.0, 0.0, 1.0]);
}