mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
533 lines
16 KiB
Rust
533 lines
16 KiB
Rust
use std::iter;
|
|
|
|
use crate::ray_tracing::AsBuildContext;
|
|
use wgpu::util::{BufferInitDescriptor, DeviceExt};
|
|
use wgpu::*;
|
|
use wgpu_test::{
|
|
fail, gpu_test, FailureCase, GpuTestConfiguration, TestParameters, TestingContext,
|
|
};
|
|
|
|
#[gpu_test]
|
|
static UNBUILT_BLAS: GpuTestConfiguration = GpuTestConfiguration::new()
|
|
.parameters(
|
|
TestParameters::default()
|
|
.test_features_limits()
|
|
.features(wgpu::Features::EXPERIMENTAL_RAY_TRACING_ACCELERATION_STRUCTURE)
|
|
// https://github.com/gfx-rs/wgpu/issues/6727
|
|
.skip(FailureCase::backend_adapter(wgpu::Backends::VULKAN, "AMD")),
|
|
)
|
|
.run_sync(unbuilt_blas);
|
|
|
|
fn unbuilt_blas(ctx: TestingContext) {
|
|
let as_ctx = AsBuildContext::new(
|
|
&ctx,
|
|
AccelerationStructureFlags::empty(),
|
|
AccelerationStructureFlags::empty(),
|
|
);
|
|
|
|
// Build the TLAS package with an unbuilt BLAS.
|
|
let mut encoder = ctx
|
|
.device
|
|
.create_command_encoder(&CommandEncoderDescriptor::default());
|
|
|
|
encoder.build_acceleration_structures([], [&as_ctx.tlas_package]);
|
|
|
|
fail(
|
|
&ctx.device,
|
|
|| {
|
|
ctx.queue.submit([encoder.finish()]);
|
|
},
|
|
None,
|
|
);
|
|
}
|
|
|
|
#[gpu_test]
|
|
static OUT_OF_ORDER_AS_BUILD: GpuTestConfiguration = GpuTestConfiguration::new()
|
|
.parameters(
|
|
TestParameters::default()
|
|
.test_features_limits()
|
|
.features(wgpu::Features::EXPERIMENTAL_RAY_TRACING_ACCELERATION_STRUCTURE)
|
|
// https://github.com/gfx-rs/wgpu/issues/6727
|
|
.skip(FailureCase::backend_adapter(wgpu::Backends::VULKAN, "AMD")),
|
|
)
|
|
.run_sync(out_of_order_as_build);
|
|
|
|
fn out_of_order_as_build(ctx: TestingContext) {
|
|
let as_ctx = AsBuildContext::new(
|
|
&ctx,
|
|
AccelerationStructureFlags::empty(),
|
|
AccelerationStructureFlags::empty(),
|
|
);
|
|
|
|
//
|
|
// Encode the TLAS build before the BLAS build, but submit them in the right order.
|
|
//
|
|
|
|
let mut encoder_tlas = ctx
|
|
.device
|
|
.create_command_encoder(&CommandEncoderDescriptor {
|
|
label: Some("TLAS 1"),
|
|
});
|
|
|
|
encoder_tlas.build_acceleration_structures([], [&as_ctx.tlas_package]);
|
|
|
|
let mut encoder_blas = ctx
|
|
.device
|
|
.create_command_encoder(&CommandEncoderDescriptor {
|
|
label: Some("BLAS 1"),
|
|
});
|
|
|
|
encoder_blas.build_acceleration_structures([&as_ctx.blas_build_entry()], []);
|
|
|
|
ctx.queue
|
|
.submit([encoder_blas.finish(), encoder_tlas.finish()]);
|
|
|
|
drop(as_ctx);
|
|
|
|
//
|
|
// Create a clean `AsBuildContext`
|
|
//
|
|
|
|
let as_ctx = AsBuildContext::new(
|
|
&ctx,
|
|
AccelerationStructureFlags::empty(),
|
|
AccelerationStructureFlags::empty(),
|
|
);
|
|
|
|
//
|
|
// Encode the BLAS build before the TLAS build, but submit them in the wrong order.
|
|
//
|
|
|
|
let mut encoder_blas = ctx
|
|
.device
|
|
.create_command_encoder(&CommandEncoderDescriptor {
|
|
label: Some("BLAS 2"),
|
|
});
|
|
|
|
encoder_blas.build_acceleration_structures([&as_ctx.blas_build_entry()], []);
|
|
|
|
let mut encoder_tlas = ctx
|
|
.device
|
|
.create_command_encoder(&CommandEncoderDescriptor {
|
|
label: Some("TLAS 2"),
|
|
});
|
|
|
|
encoder_tlas.build_acceleration_structures([], [&as_ctx.tlas_package]);
|
|
|
|
fail(
|
|
&ctx.device,
|
|
|| {
|
|
ctx.queue
|
|
.submit([encoder_tlas.finish(), encoder_blas.finish()]);
|
|
},
|
|
None,
|
|
);
|
|
}
|
|
|
|
#[gpu_test]
|
|
static OUT_OF_ORDER_AS_BUILD_USE: GpuTestConfiguration = GpuTestConfiguration::new()
|
|
.parameters(
|
|
TestParameters::default()
|
|
.test_features_limits()
|
|
.features(
|
|
wgpu::Features::EXPERIMENTAL_RAY_TRACING_ACCELERATION_STRUCTURE
|
|
| wgpu::Features::EXPERIMENTAL_RAY_QUERY,
|
|
)
|
|
// https://github.com/gfx-rs/wgpu/issues/6727
|
|
.skip(FailureCase::backend_adapter(wgpu::Backends::VULKAN, "AMD")),
|
|
)
|
|
.run_sync(out_of_order_as_build_use);
|
|
|
|
fn out_of_order_as_build_use(ctx: TestingContext) {
|
|
//
|
|
// Create a clean `AsBuildContext`
|
|
//
|
|
|
|
let as_ctx = AsBuildContext::new(
|
|
&ctx,
|
|
AccelerationStructureFlags::empty(),
|
|
AccelerationStructureFlags::empty(),
|
|
);
|
|
|
|
//
|
|
// Build in the right order, then rebuild the BLAS so the TLAS is invalid, then use the TLAS.
|
|
//
|
|
|
|
let mut encoder_blas = ctx
|
|
.device
|
|
.create_command_encoder(&CommandEncoderDescriptor {
|
|
label: Some("BLAS 1"),
|
|
});
|
|
|
|
encoder_blas.build_acceleration_structures([&as_ctx.blas_build_entry()], []);
|
|
|
|
let mut encoder_tlas = ctx
|
|
.device
|
|
.create_command_encoder(&CommandEncoderDescriptor {
|
|
label: Some("TLAS 1"),
|
|
});
|
|
|
|
encoder_tlas.build_acceleration_structures([], [&as_ctx.tlas_package]);
|
|
|
|
let mut encoder_blas2 = ctx
|
|
.device
|
|
.create_command_encoder(&CommandEncoderDescriptor {
|
|
label: Some("BLAS 2"),
|
|
});
|
|
|
|
encoder_blas2.build_acceleration_structures([&as_ctx.blas_build_entry()], []);
|
|
|
|
ctx.queue.submit([
|
|
encoder_blas.finish(),
|
|
encoder_tlas.finish(),
|
|
encoder_blas2.finish(),
|
|
]);
|
|
|
|
//
|
|
// Create shader to use tlas with
|
|
//
|
|
|
|
let shader = ctx
|
|
.device
|
|
.create_shader_module(include_wgsl!("shader.wgsl"));
|
|
let compute_pipeline = ctx
|
|
.device
|
|
.create_compute_pipeline(&ComputePipelineDescriptor {
|
|
label: None,
|
|
layout: None,
|
|
module: &shader,
|
|
entry_point: Some("basic_usage"),
|
|
compilation_options: Default::default(),
|
|
cache: None,
|
|
});
|
|
|
|
let bind_group = ctx.device.create_bind_group(&BindGroupDescriptor {
|
|
label: None,
|
|
layout: &compute_pipeline.get_bind_group_layout(0),
|
|
entries: &[BindGroupEntry {
|
|
binding: 0,
|
|
resource: BindingResource::AccelerationStructure(as_ctx.tlas_package.tlas()),
|
|
}],
|
|
});
|
|
|
|
//
|
|
// Use TLAS
|
|
//
|
|
|
|
let mut encoder_compute = ctx
|
|
.device
|
|
.create_command_encoder(&CommandEncoderDescriptor::default());
|
|
{
|
|
let mut pass = encoder_compute.begin_compute_pass(&ComputePassDescriptor {
|
|
label: None,
|
|
timestamp_writes: None,
|
|
});
|
|
pass.set_pipeline(&compute_pipeline);
|
|
pass.set_bind_group(0, Some(&bind_group), &[]);
|
|
pass.dispatch_workgroups(1, 1, 1)
|
|
}
|
|
|
|
fail(
|
|
&ctx.device,
|
|
|| {
|
|
ctx.queue.submit(Some(encoder_compute.finish()));
|
|
},
|
|
None,
|
|
);
|
|
}
|
|
|
|
#[gpu_test]
|
|
static EMPTY_BUILD: GpuTestConfiguration = GpuTestConfiguration::new()
|
|
.parameters(
|
|
TestParameters::default()
|
|
.test_features_limits()
|
|
.features(wgpu::Features::EXPERIMENTAL_RAY_TRACING_ACCELERATION_STRUCTURE),
|
|
)
|
|
.run_sync(empty_build);
|
|
fn empty_build(ctx: TestingContext) {
|
|
let mut encoder_safe = ctx
|
|
.device
|
|
.create_command_encoder(&CommandEncoderDescriptor {
|
|
label: Some("BLAS 1"),
|
|
});
|
|
|
|
encoder_safe.build_acceleration_structures(iter::empty(), iter::empty());
|
|
|
|
let mut encoder_unsafe = ctx
|
|
.device
|
|
.create_command_encoder(&CommandEncoderDescriptor {
|
|
label: Some("BLAS 1"),
|
|
});
|
|
|
|
// # SAFETY:
|
|
// we don't actually do anything so all the requirements are satisfied
|
|
unsafe {
|
|
encoder_unsafe.build_acceleration_structures_unsafe_tlas(iter::empty(), iter::empty());
|
|
}
|
|
|
|
ctx.queue
|
|
.submit([encoder_safe.finish(), encoder_unsafe.finish()]);
|
|
}
|
|
|
|
#[gpu_test]
|
|
static BUILD_WITH_TRANSFORM: GpuTestConfiguration = GpuTestConfiguration::new()
|
|
.parameters(
|
|
TestParameters::default()
|
|
.test_features_limits()
|
|
.features(wgpu::Features::EXPERIMENTAL_RAY_TRACING_ACCELERATION_STRUCTURE)
|
|
// https://github.com/gfx-rs/wgpu/issues/6727
|
|
.skip(FailureCase::backend_adapter(wgpu::Backends::VULKAN, "AMD")),
|
|
)
|
|
.run_sync(build_with_transform);
|
|
|
|
fn build_with_transform(ctx: TestingContext) {
|
|
let vertices = ctx.device.create_buffer_init(&BufferInitDescriptor {
|
|
label: None,
|
|
contents: &[0; size_of::<[[f32; 3]; 3]>()],
|
|
usage: BufferUsages::BLAS_INPUT,
|
|
});
|
|
|
|
let transform = ctx
|
|
.device
|
|
.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
|
label: Some("Vertex Buffer"),
|
|
contents: bytemuck::cast_slice(&[
|
|
1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0,
|
|
]),
|
|
usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::BLAS_INPUT,
|
|
});
|
|
|
|
let blas_size = BlasTriangleGeometrySizeDescriptor {
|
|
vertex_format: VertexFormat::Float32x3,
|
|
vertex_count: 3,
|
|
index_format: None,
|
|
index_count: None,
|
|
flags: AccelerationStructureGeometryFlags::empty(),
|
|
};
|
|
|
|
let blas = ctx.device.create_blas(
|
|
&CreateBlasDescriptor {
|
|
label: Some("BLAS"),
|
|
flags: AccelerationStructureFlags::PREFER_FAST_TRACE
|
|
| AccelerationStructureFlags::USE_TRANSFORM,
|
|
update_mode: AccelerationStructureUpdateMode::Build,
|
|
},
|
|
BlasGeometrySizeDescriptors::Triangles {
|
|
descriptors: vec![blas_size.clone()],
|
|
},
|
|
);
|
|
|
|
let tlas = ctx.device.create_tlas(&CreateTlasDescriptor {
|
|
label: Some("TLAS"),
|
|
max_instances: 1,
|
|
flags: AccelerationStructureFlags::PREFER_FAST_TRACE,
|
|
update_mode: AccelerationStructureUpdateMode::Build,
|
|
});
|
|
|
|
let mut tlas_package = TlasPackage::new(tlas);
|
|
tlas_package[0] = Some(TlasInstance::new(
|
|
&blas,
|
|
[1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0],
|
|
0,
|
|
0xFF,
|
|
));
|
|
|
|
let mut encoder_build = ctx
|
|
.device
|
|
.create_command_encoder(&CommandEncoderDescriptor {
|
|
label: Some("BUILD 1"),
|
|
});
|
|
|
|
encoder_build.build_acceleration_structures(
|
|
[&BlasBuildEntry {
|
|
blas: &blas,
|
|
geometry: BlasGeometries::TriangleGeometries(vec![BlasTriangleGeometry {
|
|
size: &blas_size,
|
|
vertex_buffer: &vertices,
|
|
first_vertex: 0,
|
|
vertex_stride: size_of::<[f32; 3]>() as BufferAddress,
|
|
index_buffer: None,
|
|
first_index: None,
|
|
transform_buffer: Some(&transform),
|
|
transform_buffer_offset: Some(0),
|
|
}]),
|
|
}],
|
|
[&tlas_package],
|
|
);
|
|
ctx.queue.submit([encoder_build.finish()]);
|
|
}
|
|
|
|
#[gpu_test]
|
|
static ONLY_BLAS_VERTEX_RETURN: GpuTestConfiguration = GpuTestConfiguration::new()
|
|
.parameters(
|
|
TestParameters::default()
|
|
.test_features_limits()
|
|
.features(
|
|
wgpu::Features::EXPERIMENTAL_RAY_TRACING_ACCELERATION_STRUCTURE
|
|
| wgpu::Features::EXPERIMENTAL_RAY_QUERY
|
|
| wgpu::Features::EXPERIMENTAL_RAY_HIT_VERTEX_RETURN,
|
|
)
|
|
// https://github.com/gfx-rs/wgpu/issues/6727
|
|
.skip(FailureCase::backend_adapter(wgpu::Backends::VULKAN, "AMD")),
|
|
)
|
|
.run_sync(only_blas_vertex_return);
|
|
|
|
fn only_blas_vertex_return(ctx: TestingContext) {
|
|
// Set up BLAS with TLAS
|
|
let as_ctx = AsBuildContext::new(
|
|
&ctx,
|
|
AccelerationStructureFlags::ALLOW_RAY_HIT_VERTEX_RETURN,
|
|
AccelerationStructureFlags::empty(),
|
|
);
|
|
|
|
let mut encoder_blas = ctx
|
|
.device
|
|
.create_command_encoder(&CommandEncoderDescriptor {
|
|
label: Some("BLAS 1"),
|
|
});
|
|
|
|
encoder_blas.build_acceleration_structures([&as_ctx.blas_build_entry()], []);
|
|
|
|
let mut encoder_tlas = ctx
|
|
.device
|
|
.create_command_encoder(&CommandEncoderDescriptor {
|
|
label: Some("TLAS 1"),
|
|
});
|
|
|
|
encoder_tlas.build_acceleration_structures([], [&as_ctx.tlas_package]);
|
|
|
|
ctx.queue
|
|
.submit([encoder_blas.finish(), encoder_tlas.finish()]);
|
|
|
|
// Create a bind-group containing a TLAS with a bind-group layout that requires vertex return,
|
|
// because only the BLAS and not the TLAS has `AccelerationStructureFlags::ALLOW_RAY_HIT_VERTEX_RETURN`
|
|
// this is invalid.
|
|
{
|
|
let bind_group_layout = ctx
|
|
.device
|
|
.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
|
label: None,
|
|
entries: &[BindGroupLayoutEntry {
|
|
binding: 0,
|
|
visibility: ShaderStages::COMPUTE,
|
|
ty: BindingType::AccelerationStructure {
|
|
vertex_return: true,
|
|
},
|
|
count: None,
|
|
}],
|
|
});
|
|
fail(
|
|
&ctx.device,
|
|
|| {
|
|
let _ = ctx.device.create_bind_group(&BindGroupDescriptor {
|
|
label: None,
|
|
layout: &bind_group_layout,
|
|
entries: &[BindGroupEntry {
|
|
binding: 0,
|
|
resource: BindingResource::AccelerationStructure(
|
|
as_ctx.tlas_package.tlas(),
|
|
),
|
|
}],
|
|
});
|
|
},
|
|
None,
|
|
);
|
|
// drop these
|
|
}
|
|
|
|
// We then use it with a shader that does not require vertex return which should succeed.
|
|
{
|
|
//
|
|
// Create shader to use tlas with
|
|
//
|
|
|
|
let shader = ctx
|
|
.device
|
|
.create_shader_module(include_wgsl!("shader.wgsl"));
|
|
let compute_pipeline = ctx
|
|
.device
|
|
.create_compute_pipeline(&ComputePipelineDescriptor {
|
|
label: None,
|
|
layout: None,
|
|
module: &shader,
|
|
entry_point: Some("basic_usage"),
|
|
compilation_options: Default::default(),
|
|
cache: None,
|
|
});
|
|
|
|
let bind_group = ctx.device.create_bind_group(&BindGroupDescriptor {
|
|
label: None,
|
|
layout: &compute_pipeline.get_bind_group_layout(0),
|
|
entries: &[BindGroupEntry {
|
|
binding: 0,
|
|
resource: BindingResource::AccelerationStructure(as_ctx.tlas_package.tlas()),
|
|
}],
|
|
});
|
|
|
|
//
|
|
// Use TLAS
|
|
//
|
|
|
|
let mut encoder_compute = ctx
|
|
.device
|
|
.create_command_encoder(&CommandEncoderDescriptor::default());
|
|
{
|
|
let mut pass = encoder_compute.begin_compute_pass(&ComputePassDescriptor {
|
|
label: None,
|
|
timestamp_writes: None,
|
|
});
|
|
pass.set_pipeline(&compute_pipeline);
|
|
pass.set_bind_group(0, Some(&bind_group), &[]);
|
|
pass.dispatch_workgroups(1, 1, 1)
|
|
}
|
|
|
|
ctx.queue.submit(Some(encoder_compute.finish()));
|
|
}
|
|
}
|
|
|
|
#[gpu_test]
|
|
static ONLY_TLAS_VERTEX_RETURN: GpuTestConfiguration = GpuTestConfiguration::new()
|
|
.parameters(
|
|
TestParameters::default()
|
|
.test_features_limits()
|
|
.features(
|
|
wgpu::Features::EXPERIMENTAL_RAY_TRACING_ACCELERATION_STRUCTURE
|
|
| wgpu::Features::EXPERIMENTAL_RAY_QUERY
|
|
| wgpu::Features::EXPERIMENTAL_RAY_HIT_VERTEX_RETURN,
|
|
)
|
|
// https://github.com/gfx-rs/wgpu/issues/6727
|
|
.skip(FailureCase::backend_adapter(wgpu::Backends::VULKAN, "AMD")),
|
|
)
|
|
.run_sync(only_tlas_vertex_return);
|
|
|
|
fn only_tlas_vertex_return(ctx: TestingContext) {
|
|
// Set up BLAS with TLAS
|
|
let as_ctx = AsBuildContext::new(
|
|
&ctx,
|
|
AccelerationStructureFlags::empty(),
|
|
AccelerationStructureFlags::ALLOW_RAY_HIT_VERTEX_RETURN,
|
|
);
|
|
|
|
let mut encoder_blas = ctx
|
|
.device
|
|
.create_command_encoder(&CommandEncoderDescriptor {
|
|
label: Some("BLAS 1"),
|
|
});
|
|
|
|
encoder_blas.build_acceleration_structures([&as_ctx.blas_build_entry()], []);
|
|
|
|
let mut encoder_tlas = ctx
|
|
.device
|
|
.create_command_encoder(&CommandEncoderDescriptor {
|
|
label: Some("TLAS 1"),
|
|
});
|
|
|
|
fail(
|
|
&ctx.device,
|
|
|| {
|
|
encoder_tlas.build_acceleration_structures([], [&as_ctx.tlas_package]);
|
|
},
|
|
None,
|
|
);
|
|
}
|