wgpu/tests/gpu-tests/buffer_usages.rs
2025-02-23 14:06:34 -05:00

187 lines
5.6 KiB
Rust

//! Tests for buffer usages validation.
use wgpu::BufferAddress;
use wgpu::{BufferUsages as Bu, MapMode as Ma};
use wgpu_test::{fail_if, gpu_test, GpuTestConfiguration, TestParameters, TestingContext};
const BUFFER_SIZE: BufferAddress = 1234;
const ALWAYS_VALID: &[Bu; 4] = &[
Bu::MAP_READ,
Bu::MAP_WRITE,
Bu::MAP_READ.union(Bu::COPY_DST),
Bu::MAP_WRITE.union(Bu::COPY_SRC),
];
// MAP_READ can only be paired with COPY_DST and MAP_WRITE can only be paired with COPY_SRC
// (unless Features::MAPPABlE_PRIMARY_BUFFERS is enabled).
const NEEDS_MAPPABLE_PRIMARY_BUFFERS: &[Bu; 7] = &[
Bu::MAP_READ.union(Bu::COPY_DST.union(Bu::COPY_SRC)),
Bu::MAP_WRITE.union(Bu::COPY_SRC.union(Bu::COPY_DST)),
Bu::MAP_READ.union(Bu::MAP_WRITE),
Bu::MAP_WRITE.union(Bu::MAP_READ),
Bu::MAP_READ.union(Bu::COPY_DST.union(Bu::STORAGE)),
Bu::MAP_WRITE.union(Bu::COPY_SRC.union(Bu::STORAGE)),
// these two require acceleration_structures feature
Bu::all().intersection(Bu::BLAS_INPUT.union(Bu::TLAS_INPUT).complement()),
];
const INVALID_BITS: Bu = Bu::from_bits_retain(0b1111111111111);
const ALWAYS_FAIL: &[Bu; 2] = &[Bu::empty(), INVALID_BITS];
fn try_create(ctx: TestingContext, usages: &[(bool, &[wgpu::BufferUsages])]) {
for (expect_validation_error, usage) in usages
.iter()
.flat_map(|&(expect_error, usages)| usages.iter().copied().map(move |u| (expect_error, u)))
{
fail_if(
&ctx.device,
expect_validation_error,
|| {
let _buffer = ctx.device.create_buffer(&wgpu::BufferDescriptor {
label: None,
size: BUFFER_SIZE,
usage,
mapped_at_creation: false,
});
},
None,
);
}
}
#[gpu_test]
static BUFFER_USAGE: GpuTestConfiguration = GpuTestConfiguration::new().run_sync(|ctx| {
try_create(
ctx,
&[
(false, ALWAYS_VALID),
(true, NEEDS_MAPPABLE_PRIMARY_BUFFERS),
(true, ALWAYS_FAIL),
],
);
});
#[gpu_test]
static BUFFER_USAGE_MAPPABLE_PRIMARY_BUFFERS: GpuTestConfiguration = GpuTestConfiguration::new()
.parameters(TestParameters::default().features(wgpu::Features::MAPPABLE_PRIMARY_BUFFERS))
.run_sync(|ctx| {
try_create(
ctx,
&[
(false, ALWAYS_VALID),
(false, NEEDS_MAPPABLE_PRIMARY_BUFFERS),
(true, ALWAYS_FAIL),
],
);
});
async fn map_test(
ctx: &TestingContext,
usage_type: &str,
map_mode_type: Ma,
before_unmap: bool,
before_destroy: bool,
after_unmap: bool,
after_destroy: bool,
) {
log::info!("map_test usage_type:{usage_type} map_mode_type:{:?} before_unmap:{before_unmap} before_destroy:{before_destroy} after_unmap:{after_unmap} after_destroy:{after_destroy}", map_mode_type);
let size = 8;
let usage = match usage_type {
"read" => Bu::COPY_DST | Bu::MAP_READ,
"write" => Bu::COPY_SRC | Bu::MAP_WRITE,
_ => Bu::from_bits(0).unwrap(),
};
let buffer_creation_validation_error = usage.is_empty();
let mut buffer = None;
fail_if(
&ctx.device,
buffer_creation_validation_error,
|| {
buffer = Some(ctx.device.create_buffer(&wgpu::BufferDescriptor {
label: None,
size,
usage,
mapped_at_creation: false,
}));
},
None,
);
if buffer_creation_validation_error {
return;
}
let buffer = buffer.unwrap();
let map_async_validation_error = buffer_creation_validation_error
|| (map_mode_type == Ma::Read && !usage.contains(Bu::MAP_READ))
|| (map_mode_type == Ma::Write && !usage.contains(Bu::MAP_WRITE));
fail_if(
&ctx.device,
map_async_validation_error,
|| {
buffer.slice(0..size).map_async(map_mode_type, |_| {});
},
None,
);
if map_async_validation_error {
return;
}
if before_unmap {
buffer.unmap();
}
if before_destroy {
buffer.destroy();
}
ctx.async_poll(wgpu::PollType::wait()).await.unwrap();
if !before_unmap && !before_destroy {
{
let view = buffer.slice(0..size).get_mapped_range();
assert!(!view.is_empty());
}
if after_unmap {
buffer.unmap();
}
if after_destroy {
buffer.destroy();
}
}
}
#[gpu_test]
static BUFFER_MAP_ASYNC_MAP_STATE: GpuTestConfiguration = GpuTestConfiguration::new()
.parameters(TestParameters::default().features(wgpu::Features::MAPPABLE_PRIMARY_BUFFERS))
.run_async(move |ctx| async move {
for usage_type in ["invalid", "read", "write"] {
for map_mode_type in [Ma::Read, Ma::Write] {
for before_unmap in [false, true] {
for before_destroy in [false, true] {
for after_unmap in [false, true] {
for after_destroy in [false, true] {
map_test(
&ctx,
usage_type,
map_mode_type,
before_unmap,
before_destroy,
after_unmap,
after_destroy,
)
.await
}
}
}
}
}
}
});