mirror of
https://github.com/gfx-rs/wgpu.git
synced 2025-12-08 21:26:17 +00:00
Remove unsafe acceleration structure build (#7513)
This commit is contained in:
parent
645354a528
commit
aa427de4ea
@ -98,6 +98,8 @@ Naga now infers the correct binding layout when a resource appears only in an as
|
||||
- Support BLAS compaction in wgpu. By @Vecvec in [#7285](https://github.com/gfx-rs/wgpu/pull/7285).
|
||||
- Removed `MaintainBase` in favor of using `PollType`. By @waywardmonkeys in [#7508](https://github.com/gfx-rs/wgpu/pull/7508).
|
||||
- The `destroy` functions for buffers and textures in wgpu-core are now infallible. Previously, they returned an error if called multiple times for the same object. This only affects the wgpu-core API; the wgpu API already allowed multiple `destroy` calls. By @andyleiserson in [#7686](https://github.com/gfx-rs/wgpu/pull/7686) and [#7720](https://github.com/gfx-rs/wgpu/pull/7720).
|
||||
- Remove `CommandEncoder::build_acceleration_structures_unsafe_tlas` in favour of `as_hal` and apply
|
||||
simplifications allowed by this. By @Vecvec in [#7513](https://github.com/gfx-rs/wgpu/pull/7513)
|
||||
|
||||
#### Naga
|
||||
|
||||
|
||||
@ -21,9 +21,7 @@ can be found with their definitions.
|
||||
A [`Blas`] can be created with [`Device::create_blas`].
|
||||
A [`Tlas`] can be created with [`Device::create_tlas`].
|
||||
|
||||
Unless one is planning on using the unsafe building API (not recommended for beginners) a [`Tlas`] should be put inside
|
||||
a [`TlasPackage`]. After that a reference to the [`Tlas`] can be retrieved by calling [`TlasPackage::tlas`].
|
||||
This reference can be placed in a bind group to be used in a shader. A reference to a [`Blas`] can
|
||||
The [`Tlas`] reference can be placed in a bind group to be used in a shader. A reference to a [`Blas`] can
|
||||
be used to create [`TlasInstance`] alongside a transformation matrix, a custom index
|
||||
(this can be any data that should be given to the shader on a hit) which only the first 24
|
||||
bits may be set, and a mask to filter hits in the shader.
|
||||
@ -86,8 +84,6 @@ fn render(/*whatever args you need to render*/) {
|
||||
[`Tlas`]: https://wgpu.rs/doc/wgpu/struct.Tlas.html
|
||||
[`Blas`]: https://wgpu.rs/doc/wgpu/struct.Blas.html
|
||||
[`TlasInstance`]: https://wgpu.rs/doc/wgpu/struct.TlasInstance.html
|
||||
[`TlasPackage`]: https://wgpu.rs/doc/wgpu/struct.TlasPackage.html
|
||||
[`TlasPackage::tlas`]: https://wgpu.rs/doc/wgpu/struct.TlasPackage.html#method.tlas
|
||||
[`Blas::prepare_compaction_async`]: https://wgpu.rs/doc/wgpu/struct.Blas.html#method.prepare_compaction_async
|
||||
[`Blas::ready_for_compaction`]: https://wgpu.rs/doc/wgpu/struct.Blas.html#method.ready_for_compaction
|
||||
[`Queue::compact_blas`]: https://wgpu.rs/doc/wgpu/struct.Queue.html#method.compact_blas
|
||||
|
||||
@ -132,7 +132,7 @@ struct Example {
|
||||
vertex_buf: wgpu::Buffer,
|
||||
#[expect(dead_code)]
|
||||
index_buf: wgpu::Buffer,
|
||||
tlas_package: wgpu::TlasPackage,
|
||||
tlas: wgpu::Tlas,
|
||||
compute_pipeline: wgpu::ComputePipeline,
|
||||
compute_bind_group: wgpu::BindGroup,
|
||||
blit_pipeline: wgpu::RenderPipeline,
|
||||
@ -259,7 +259,7 @@ impl crate::framework::Example for Example {
|
||||
},
|
||||
);
|
||||
|
||||
let tlas = device.create_tlas(&wgpu::CreateTlasDescriptor {
|
||||
let mut tlas = device.create_tlas(&wgpu::CreateTlasDescriptor {
|
||||
label: None,
|
||||
flags: wgpu::AccelerationStructureFlags::PREFER_FAST_TRACE,
|
||||
update_mode: wgpu::AccelerationStructureUpdateMode::Build,
|
||||
@ -348,13 +348,11 @@ impl crate::framework::Example for Example {
|
||||
],
|
||||
});
|
||||
|
||||
let mut tlas_package = wgpu::TlasPackage::new(tlas);
|
||||
|
||||
let dist = 3.0;
|
||||
|
||||
for x in 0..side_count {
|
||||
for y in 0..side_count {
|
||||
tlas_package[(x + y * side_count) as usize] = Some(wgpu::TlasInstance::new(
|
||||
tlas[(x + y * side_count) as usize] = Some(wgpu::TlasInstance::new(
|
||||
&blas,
|
||||
affine_to_rows(&Affine3A::from_rotation_translation(
|
||||
Quat::from_rotation_y(45.9_f32.to_radians()),
|
||||
@ -389,7 +387,7 @@ impl crate::framework::Example for Example {
|
||||
},
|
||||
]),
|
||||
}),
|
||||
iter::once(&tlas_package),
|
||||
iter::once(&tlas),
|
||||
);
|
||||
|
||||
queue.submit(Some(encoder.finish()));
|
||||
@ -401,7 +399,7 @@ impl crate::framework::Example for Example {
|
||||
uniform_buf,
|
||||
vertex_buf,
|
||||
index_buf,
|
||||
tlas_package,
|
||||
tlas,
|
||||
compute_pipeline,
|
||||
compute_bind_group,
|
||||
blit_pipeline,
|
||||
@ -427,7 +425,7 @@ impl crate::framework::Example for Example {
|
||||
|
||||
let anim_time = self.animation_timer.time();
|
||||
|
||||
self.tlas_package[0].as_mut().unwrap().transform =
|
||||
self.tlas[0].as_mut().unwrap().transform =
|
||||
affine_to_rows(&Affine3A::from_rotation_translation(
|
||||
Quat::from_euler(
|
||||
glam::EulerRot::XYZ,
|
||||
@ -445,7 +443,7 @@ impl crate::framework::Example for Example {
|
||||
let mut encoder =
|
||||
device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
|
||||
|
||||
encoder.build_acceleration_structures(iter::empty(), iter::once(&self.tlas_package));
|
||||
encoder.build_acceleration_structures(iter::empty(), iter::once(&self.tlas));
|
||||
|
||||
{
|
||||
let mut cpass = encoder.begin_compute_pass(&wgpu::ComputePassDescriptor {
|
||||
|
||||
@ -99,7 +99,7 @@ struct Example {
|
||||
uniforms: Uniforms,
|
||||
uniform_buf: wgpu::Buffer,
|
||||
blas: wgpu::Blas,
|
||||
tlas_package: wgpu::TlasPackage,
|
||||
tlas: wgpu::Tlas,
|
||||
pipeline: wgpu::RenderPipeline,
|
||||
bind_group: wgpu::BindGroup,
|
||||
animation_timer: utils::AnimationTimer,
|
||||
@ -238,8 +238,6 @@ impl crate::framework::Example for Example {
|
||||
],
|
||||
});
|
||||
|
||||
let tlas_package = wgpu::TlasPackage::new(tlas);
|
||||
|
||||
let mut encoder =
|
||||
device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
|
||||
|
||||
@ -260,7 +258,7 @@ impl crate::framework::Example for Example {
|
||||
]),
|
||||
}),
|
||||
// iter::empty(),
|
||||
iter::once(&tlas_package),
|
||||
iter::once(&tlas),
|
||||
);
|
||||
|
||||
queue.submit(Some(encoder.finish()));
|
||||
@ -269,7 +267,7 @@ impl crate::framework::Example for Example {
|
||||
uniforms,
|
||||
uniform_buf,
|
||||
blas,
|
||||
tlas_package,
|
||||
tlas,
|
||||
pipeline,
|
||||
bind_group,
|
||||
animation_timer: utils::AnimationTimer::default(),
|
||||
@ -309,7 +307,7 @@ impl crate::framework::Example for Example {
|
||||
|
||||
for x in 0..side_count {
|
||||
for y in 0..side_count {
|
||||
let instance = self.tlas_package.index_mut((x + y * side_count) as usize);
|
||||
let instance = self.tlas.index_mut((x + y * side_count) as usize);
|
||||
|
||||
let x = x as f32 / (side_count - 1) as f32;
|
||||
let y = y as f32 / (side_count - 1) as f32;
|
||||
@ -341,7 +339,7 @@ impl crate::framework::Example for Example {
|
||||
let mut encoder =
|
||||
device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
|
||||
|
||||
encoder.build_acceleration_structures(iter::empty(), iter::once(&self.tlas_package));
|
||||
encoder.build_acceleration_structures(iter::empty(), iter::once(&self.tlas));
|
||||
|
||||
{
|
||||
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
|
||||
@ -121,7 +121,7 @@ impl<F: Future<Output = Option<wgpu::Error>>> Future for ErrorFuture<F> {
|
||||
|
||||
struct Example {
|
||||
rt_target: wgpu::Texture,
|
||||
tlas_package: wgpu::TlasPackage,
|
||||
tlas: wgpu::Tlas,
|
||||
compute_pipeline: wgpu::ComputePipeline,
|
||||
compute_bind_group: wgpu::BindGroup,
|
||||
blit_pipeline: wgpu::RenderPipeline,
|
||||
@ -250,7 +250,7 @@ impl crate::framework::Example for Example {
|
||||
},
|
||||
);
|
||||
|
||||
let tlas = device.create_tlas(&wgpu::CreateTlasDescriptor {
|
||||
let mut tlas = device.create_tlas(&wgpu::CreateTlasDescriptor {
|
||||
label: None,
|
||||
flags: wgpu::AccelerationStructureFlags::PREFER_FAST_TRACE
|
||||
| wgpu::AccelerationStructureFlags::ALLOW_RAY_HIT_VERTEX_RETURN,
|
||||
@ -340,13 +340,11 @@ impl crate::framework::Example for Example {
|
||||
],
|
||||
});
|
||||
|
||||
let mut tlas_package = wgpu::TlasPackage::new(tlas);
|
||||
|
||||
let dist = 3.0;
|
||||
|
||||
for x in 0..side_count {
|
||||
for y in 0..side_count {
|
||||
tlas_package[(x + y * side_count) as usize] = Some(wgpu::TlasInstance::new(
|
||||
tlas[(x + y * side_count) as usize] = Some(wgpu::TlasInstance::new(
|
||||
&blas,
|
||||
affine_to_rows(&Affine3A::from_rotation_translation(
|
||||
Quat::from_rotation_y(45.9_f32.to_radians()),
|
||||
@ -381,14 +379,14 @@ impl crate::framework::Example for Example {
|
||||
},
|
||||
]),
|
||||
}),
|
||||
iter::once(&tlas_package),
|
||||
iter::once(&tlas),
|
||||
);
|
||||
|
||||
queue.submit(Some(encoder.finish()));
|
||||
|
||||
Example {
|
||||
rt_target,
|
||||
tlas_package,
|
||||
tlas,
|
||||
compute_pipeline,
|
||||
compute_bind_group,
|
||||
blit_pipeline,
|
||||
@ -414,7 +412,7 @@ impl crate::framework::Example for Example {
|
||||
|
||||
let anim_time = self.animation_timer.time();
|
||||
|
||||
self.tlas_package[0].as_mut().unwrap().transform =
|
||||
self.tlas[0].as_mut().unwrap().transform =
|
||||
affine_to_rows(&Affine3A::from_rotation_translation(
|
||||
Quat::from_euler(
|
||||
glam::EulerRot::XYZ,
|
||||
@ -432,7 +430,7 @@ impl crate::framework::Example for Example {
|
||||
let mut encoder =
|
||||
device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
|
||||
|
||||
encoder.build_acceleration_structures(iter::empty(), iter::once(&self.tlas_package));
|
||||
encoder.build_acceleration_structures(iter::empty(), iter::once(&self.tlas));
|
||||
|
||||
{
|
||||
let mut cpass = encoder.begin_compute_pass(&wgpu::ComputePassDescriptor {
|
||||
|
||||
@ -308,7 +308,7 @@ fn load_scene(device: &wgpu::Device, queue: &wgpu::Queue) -> SceneComponents {
|
||||
struct Example {
|
||||
uniforms: Uniforms,
|
||||
uniform_buf: wgpu::Buffer,
|
||||
tlas_package: wgpu::TlasPackage,
|
||||
tlas: wgpu::Tlas,
|
||||
pipeline: wgpu::RenderPipeline,
|
||||
bind_group: wgpu::BindGroup,
|
||||
scene_components: SceneComponents,
|
||||
@ -370,8 +370,6 @@ impl crate::framework::Example for Example {
|
||||
max_instances: side_count * side_count,
|
||||
});
|
||||
|
||||
let tlas_package = wgpu::TlasPackage::new(tlas);
|
||||
|
||||
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||
label: None,
|
||||
source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(include_str!("shader.wgsl"))),
|
||||
@ -414,7 +412,7 @@ impl crate::framework::Example for Example {
|
||||
},
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 5,
|
||||
resource: tlas_package.as_binding(),
|
||||
resource: tlas.as_binding(),
|
||||
},
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 1,
|
||||
@ -438,7 +436,7 @@ impl crate::framework::Example for Example {
|
||||
Example {
|
||||
uniforms,
|
||||
uniform_buf,
|
||||
tlas_package,
|
||||
tlas,
|
||||
pipeline,
|
||||
bind_group,
|
||||
scene_components,
|
||||
@ -479,7 +477,7 @@ impl crate::framework::Example for Example {
|
||||
|
||||
for x in 0..side_count {
|
||||
for y in 0..side_count {
|
||||
let instance = self.tlas_package.index_mut(x + y * side_count);
|
||||
let instance = self.tlas.index_mut(x + y * side_count);
|
||||
|
||||
let blas_index = (x + y)
|
||||
% self
|
||||
@ -521,7 +519,7 @@ impl crate::framework::Example for Example {
|
||||
let mut encoder =
|
||||
device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
|
||||
|
||||
encoder.build_acceleration_structures(iter::empty(), iter::once(&self.tlas_package));
|
||||
encoder.build_acceleration_structures(iter::empty(), iter::once(&self.tlas));
|
||||
|
||||
{
|
||||
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
|
||||
@ -170,7 +170,7 @@ impl crate::framework::Example for Example {
|
||||
},
|
||||
);
|
||||
|
||||
let tlas = device.create_tlas(&wgpu::CreateTlasDescriptor {
|
||||
let mut tlas = device.create_tlas(&wgpu::CreateTlasDescriptor {
|
||||
label: None,
|
||||
flags: wgpu::AccelerationStructureFlags::PREFER_FAST_TRACE,
|
||||
update_mode: wgpu::AccelerationStructureUpdateMode::Build,
|
||||
@ -244,9 +244,7 @@ impl crate::framework::Example for Example {
|
||||
cache: None,
|
||||
});
|
||||
|
||||
let mut tlas_package = wgpu::TlasPackage::new(tlas);
|
||||
|
||||
tlas_package[0] = Some(wgpu::TlasInstance::new(
|
||||
tlas[0] = Some(wgpu::TlasInstance::new(
|
||||
&blas,
|
||||
[1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0],
|
||||
0,
|
||||
@ -272,7 +270,7 @@ impl crate::framework::Example for Example {
|
||||
},
|
||||
]),
|
||||
}),
|
||||
iter::once(&tlas_package),
|
||||
iter::once(&tlas),
|
||||
);
|
||||
|
||||
queue.submit(Some(encoder.finish()));
|
||||
@ -287,7 +285,7 @@ impl crate::framework::Example for Example {
|
||||
},
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 1,
|
||||
resource: tlas_package.as_binding(),
|
||||
resource: tlas.as_binding(),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
@ -5,13 +5,13 @@ use wgpu::{include_wgsl, BufferUsages, IndexFormat, SamplerDescriptor};
|
||||
use wgpu::{
|
||||
AccelerationStructureFlags, AccelerationStructureUpdateMode, BlasBuildEntry, BlasGeometries,
|
||||
BlasGeometrySizeDescriptors, BlasTriangleGeometry, BlasTriangleGeometrySizeDescriptor,
|
||||
CreateBlasDescriptor, CreateTlasDescriptor, TlasInstance, TlasPackage,
|
||||
CreateBlasDescriptor, CreateTlasDescriptor, Tlas, TlasInstance,
|
||||
};
|
||||
|
||||
use crate::utils;
|
||||
|
||||
struct Example {
|
||||
tlas_package: TlasPackage,
|
||||
tlas: Tlas,
|
||||
compute_pipeline: wgpu::ComputePipeline,
|
||||
blit_pipeline: wgpu::RenderPipeline,
|
||||
bind_group: wgpu::BindGroup,
|
||||
@ -146,16 +146,14 @@ impl crate::framework::Example for Example {
|
||||
},
|
||||
);
|
||||
|
||||
let tlas = device.create_tlas(&CreateTlasDescriptor {
|
||||
let mut tlas = device.create_tlas(&CreateTlasDescriptor {
|
||||
label: None,
|
||||
max_instances: 3,
|
||||
flags: AccelerationStructureFlags::PREFER_FAST_TRACE,
|
||||
update_mode: AccelerationStructureUpdateMode::Build,
|
||||
});
|
||||
|
||||
let mut tlas_package = TlasPackage::new(tlas);
|
||||
|
||||
tlas_package[0] = Some(TlasInstance::new(
|
||||
tlas[0] = Some(TlasInstance::new(
|
||||
&blas,
|
||||
Mat4::from_translation(Vec3 {
|
||||
x: 0.0,
|
||||
@ -170,7 +168,7 @@ impl crate::framework::Example for Example {
|
||||
0xff,
|
||||
));
|
||||
|
||||
tlas_package[1] = Some(TlasInstance::new(
|
||||
tlas[1] = Some(TlasInstance::new(
|
||||
&blas,
|
||||
Mat4::from_translation(Vec3 {
|
||||
x: -1.0,
|
||||
@ -185,7 +183,7 @@ impl crate::framework::Example for Example {
|
||||
0xff,
|
||||
));
|
||||
|
||||
tlas_package[2] = Some(TlasInstance::new(
|
||||
tlas[2] = Some(TlasInstance::new(
|
||||
&blas,
|
||||
Mat4::from_translation(Vec3 {
|
||||
x: 1.0,
|
||||
@ -233,7 +231,7 @@ impl crate::framework::Example for Example {
|
||||
transform_buffer_offset: None,
|
||||
}]),
|
||||
}),
|
||||
Some(&tlas_package),
|
||||
Some(&tlas),
|
||||
);
|
||||
|
||||
queue.submit(Some(encoder.finish()));
|
||||
@ -332,7 +330,7 @@ impl crate::framework::Example for Example {
|
||||
},
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 2,
|
||||
resource: wgpu::BindingResource::AccelerationStructure(tlas_package.tlas()),
|
||||
resource: wgpu::BindingResource::AccelerationStructure(&tlas),
|
||||
},
|
||||
],
|
||||
});
|
||||
@ -355,7 +353,7 @@ impl crate::framework::Example for Example {
|
||||
});
|
||||
|
||||
Self {
|
||||
tlas_package,
|
||||
tlas,
|
||||
compute_pipeline,
|
||||
blit_pipeline,
|
||||
bind_group,
|
||||
@ -376,7 +374,7 @@ impl crate::framework::Example for Example {
|
||||
fn update(&mut self, _event: winit::event::WindowEvent) {}
|
||||
|
||||
fn render(&mut self, view: &wgpu::TextureView, device: &wgpu::Device, queue: &wgpu::Queue) {
|
||||
self.tlas_package[0].as_mut().unwrap().transform =
|
||||
self.tlas[0].as_mut().unwrap().transform =
|
||||
Mat4::from_rotation_y(self.animation_timer.time())
|
||||
.transpose()
|
||||
.to_cols_array()[..12]
|
||||
@ -386,7 +384,7 @@ impl crate::framework::Example for Example {
|
||||
let mut encoder =
|
||||
device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
|
||||
|
||||
encoder.build_acceleration_structures(None, Some(&self.tlas_package));
|
||||
encoder.build_acceleration_structures(None, Some(&self.tlas));
|
||||
|
||||
{
|
||||
let mut cpass = encoder.begin_compute_pass(&wgpu::ComputePassDescriptor {
|
||||
|
||||
@ -120,44 +120,6 @@ impl GlobalPlay for wgc::global::Global {
|
||||
occlusion_query_set_id,
|
||||
);
|
||||
}
|
||||
trace::Command::BuildAccelerationStructuresUnsafeTlas { blas, tlas } => {
|
||||
let blas_iter = blas.iter().map(|x| {
|
||||
let geometries = match &x.geometries {
|
||||
wgc::ray_tracing::TraceBlasGeometries::TriangleGeometries(
|
||||
triangle_geometries,
|
||||
) => {
|
||||
let iter = triangle_geometries.iter().map(|tg| {
|
||||
wgc::ray_tracing::BlasTriangleGeometry {
|
||||
size: &tg.size,
|
||||
vertex_buffer: tg.vertex_buffer,
|
||||
index_buffer: tg.index_buffer,
|
||||
transform_buffer: tg.transform_buffer,
|
||||
first_vertex: tg.first_vertex,
|
||||
vertex_stride: tg.vertex_stride,
|
||||
first_index: tg.first_index,
|
||||
transform_buffer_offset: tg.transform_buffer_offset,
|
||||
}
|
||||
});
|
||||
wgc::ray_tracing::BlasGeometries::TriangleGeometries(Box::new(iter))
|
||||
}
|
||||
};
|
||||
wgc::ray_tracing::BlasBuildEntry {
|
||||
blas_id: x.blas_id,
|
||||
geometries,
|
||||
}
|
||||
});
|
||||
|
||||
if !tlas.is_empty() {
|
||||
log::error!("a trace of command_encoder_build_acceleration_structures_unsafe_tlas containing a tlas build is not replayable! skipping tlas build");
|
||||
}
|
||||
|
||||
self.command_encoder_build_acceleration_structures_unsafe_tlas(
|
||||
encoder,
|
||||
blas_iter,
|
||||
std::iter::empty(),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
trace::Command::BuildAccelerationStructures { blas, tlas } => {
|
||||
let blas_iter = blas.iter().map(|x| {
|
||||
let geometries = match &x.geometries {
|
||||
|
||||
@ -30,7 +30,7 @@ fn unbuilt_blas(ctx: TestingContext) {
|
||||
.device
|
||||
.create_command_encoder(&CommandEncoderDescriptor::default());
|
||||
|
||||
encoder.build_acceleration_structures([], [&as_ctx.tlas_package]);
|
||||
encoder.build_acceleration_structures([], [&as_ctx.tlas]);
|
||||
|
||||
fail(
|
||||
&ctx.device,
|
||||
@ -223,7 +223,7 @@ fn out_of_order_as_build(ctx: TestingContext) {
|
||||
label: Some("TLAS 1"),
|
||||
});
|
||||
|
||||
encoder_tlas.build_acceleration_structures([], [&as_ctx.tlas_package]);
|
||||
encoder_tlas.build_acceleration_structures([], [&as_ctx.tlas]);
|
||||
|
||||
let mut encoder_blas = ctx
|
||||
.device
|
||||
@ -266,7 +266,7 @@ fn out_of_order_as_build(ctx: TestingContext) {
|
||||
label: Some("TLAS 2"),
|
||||
});
|
||||
|
||||
encoder_tlas.build_acceleration_structures([], [&as_ctx.tlas_package]);
|
||||
encoder_tlas.build_acceleration_structures([], [&as_ctx.tlas]);
|
||||
|
||||
fail(
|
||||
&ctx.device,
|
||||
@ -321,7 +321,7 @@ fn out_of_order_as_build_use(ctx: TestingContext) {
|
||||
label: Some("TLAS 1"),
|
||||
});
|
||||
|
||||
encoder_tlas.build_acceleration_structures([], [&as_ctx.tlas_package]);
|
||||
encoder_tlas.build_acceleration_structures([], [&as_ctx.tlas]);
|
||||
|
||||
let mut encoder_blas2 = ctx
|
||||
.device
|
||||
@ -360,7 +360,7 @@ fn out_of_order_as_build_use(ctx: TestingContext) {
|
||||
layout: &compute_pipeline.get_bind_group_layout(0),
|
||||
entries: &[BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: BindingResource::AccelerationStructure(as_ctx.tlas_package.tlas()),
|
||||
resource: BindingResource::AccelerationStructure(&as_ctx.tlas),
|
||||
}],
|
||||
});
|
||||
|
||||
@ -421,7 +421,7 @@ fn out_of_order_as_build_use(ctx: TestingContext) {
|
||||
label: Some("TLAS 2"),
|
||||
});
|
||||
|
||||
encoder_tlas.build_acceleration_structures([], [&as_ctx.tlas_package]);
|
||||
encoder_tlas.build_acceleration_structures([], [&as_ctx.tlas]);
|
||||
|
||||
ctx.queue.submit([
|
||||
encoder_blas.finish(),
|
||||
@ -434,7 +434,7 @@ fn out_of_order_as_build_use(ctx: TestingContext) {
|
||||
layout: &compute_pipeline.get_bind_group_layout(0),
|
||||
entries: &[BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: BindingResource::AccelerationStructure(as_ctx.tlas_package.tlas()),
|
||||
resource: BindingResource::AccelerationStructure(&as_ctx.tlas),
|
||||
}],
|
||||
});
|
||||
|
||||
@ -481,20 +481,7 @@ fn empty_build(ctx: TestingContext) {
|
||||
|
||||
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()]);
|
||||
ctx.queue.submit([encoder_safe.finish()]);
|
||||
}
|
||||
|
||||
#[gpu_test]
|
||||
@ -545,15 +532,13 @@ fn build_with_transform(ctx: TestingContext) {
|
||||
},
|
||||
);
|
||||
|
||||
let tlas = ctx.device.create_tlas(&CreateTlasDescriptor {
|
||||
let mut 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(
|
||||
tlas[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,
|
||||
@ -580,7 +565,7 @@ fn build_with_transform(ctx: TestingContext) {
|
||||
transform_buffer_offset: Some(0),
|
||||
}]),
|
||||
}],
|
||||
[&tlas_package],
|
||||
[&tlas],
|
||||
);
|
||||
ctx.queue.submit([encoder_build.finish()]);
|
||||
}
|
||||
@ -622,7 +607,7 @@ fn only_blas_vertex_return(ctx: TestingContext) {
|
||||
label: Some("TLAS 1"),
|
||||
});
|
||||
|
||||
encoder_tlas.build_acceleration_structures([], [&as_ctx.tlas_package]);
|
||||
encoder_tlas.build_acceleration_structures([], [&as_ctx.tlas]);
|
||||
|
||||
ctx.queue
|
||||
.submit([encoder_blas.finish(), encoder_tlas.finish()]);
|
||||
@ -652,9 +637,7 @@ fn only_blas_vertex_return(ctx: TestingContext) {
|
||||
layout: &bind_group_layout,
|
||||
entries: &[BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: BindingResource::AccelerationStructure(
|
||||
as_ctx.tlas_package.tlas(),
|
||||
),
|
||||
resource: BindingResource::AccelerationStructure(&as_ctx.tlas),
|
||||
}],
|
||||
});
|
||||
},
|
||||
@ -688,7 +671,7 @@ fn only_blas_vertex_return(ctx: TestingContext) {
|
||||
layout: &compute_pipeline.get_bind_group_layout(0),
|
||||
entries: &[BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: BindingResource::AccelerationStructure(as_ctx.tlas_package.tlas()),
|
||||
resource: BindingResource::AccelerationStructure(&as_ctx.tlas),
|
||||
}],
|
||||
});
|
||||
|
||||
@ -753,7 +736,7 @@ fn only_tlas_vertex_return(ctx: TestingContext) {
|
||||
fail(
|
||||
&ctx.device,
|
||||
|| {
|
||||
encoder_tlas.build_acceleration_structures([], [&as_ctx.tlas_package]);
|
||||
encoder_tlas.build_acceleration_structures([], [&as_ctx.tlas]);
|
||||
},
|
||||
None,
|
||||
);
|
||||
|
||||
@ -7,7 +7,7 @@ use wgpu::{
|
||||
BlasBuildEntry, BlasGeometries, BlasGeometrySizeDescriptors, BlasTriangleGeometry,
|
||||
BlasTriangleGeometrySizeDescriptor, BufferAddress, BufferUsages, CommandEncoderDescriptor,
|
||||
ComputePassDescriptor, ComputePipelineDescriptor, CreateBlasDescriptor, CreateTlasDescriptor,
|
||||
PollType, TlasInstance, TlasPackage, VertexFormat,
|
||||
PollType, TlasInstance, VertexFormat,
|
||||
};
|
||||
use wgpu_macros::gpu_test;
|
||||
use wgpu_test::{FailureCase, GpuTestConfiguration, TestParameters, TestingContext};
|
||||
@ -49,16 +49,14 @@ fn acceleration_structure_use_after_free(ctx: TestingContext) {
|
||||
},
|
||||
);
|
||||
// Create the TLAS
|
||||
let tlas = ctx.device.create_tlas(&CreateTlasDescriptor {
|
||||
let mut tlas = ctx.device.create_tlas(&CreateTlasDescriptor {
|
||||
label: Some("tlas use after free"),
|
||||
max_instances: 1,
|
||||
flags: AccelerationStructureFlags::PREFER_FAST_TRACE,
|
||||
update_mode: AccelerationStructureUpdateMode::Build,
|
||||
});
|
||||
|
||||
// Put an unbuilt BLAS in the tlas package.
|
||||
let mut tlas_package = TlasPackage::new(tlas);
|
||||
tlas_package[0] = Some(TlasInstance::new(
|
||||
tlas[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,
|
||||
@ -95,7 +93,7 @@ fn acceleration_structure_use_after_free(ctx: TestingContext) {
|
||||
let mut encoder = ctx
|
||||
.device
|
||||
.create_command_encoder(&CommandEncoderDescriptor::default());
|
||||
encoder.build_acceleration_structures(iter::empty(), iter::once(&tlas_package));
|
||||
encoder.build_acceleration_structures(iter::empty(), iter::once(&tlas));
|
||||
ctx.queue.submit(Some(encoder.finish()));
|
||||
|
||||
// Create a compute shader that uses an AS.
|
||||
@ -118,12 +116,12 @@ fn acceleration_structure_use_after_free(ctx: TestingContext) {
|
||||
layout: &compute_pipeline.get_bind_group_layout(0),
|
||||
entries: &[BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: BindingResource::AccelerationStructure(tlas_package.tlas()),
|
||||
resource: BindingResource::AccelerationStructure(&tlas),
|
||||
}],
|
||||
});
|
||||
|
||||
// Drop the TLAS package and ensure that if it was going to die, it is dead.
|
||||
drop(tlas_package);
|
||||
drop(tlas);
|
||||
ctx.device.poll(PollType::Wait).unwrap();
|
||||
|
||||
// Run the pass with the bind group that references the TLAS package.
|
||||
|
||||
@ -3,7 +3,7 @@ use wgpu::util::BufferInitDescriptor;
|
||||
use wgpu::{
|
||||
util::DeviceExt, Blas, BlasBuildEntry, BlasGeometries, BlasGeometrySizeDescriptors,
|
||||
BlasTriangleGeometry, BlasTriangleGeometrySizeDescriptor, Buffer, CreateBlasDescriptor,
|
||||
CreateTlasDescriptor, TlasInstance, TlasPackage,
|
||||
CreateTlasDescriptor, Tlas, TlasInstance,
|
||||
};
|
||||
use wgpu::{
|
||||
AccelerationStructureFlags, AccelerationStructureGeometryFlags,
|
||||
@ -22,7 +22,7 @@ pub struct AsBuildContext {
|
||||
blas_size: BlasTriangleGeometrySizeDescriptor,
|
||||
blas: Blas,
|
||||
// Putting this last, forces the BLAS to die before the TLAS.
|
||||
tlas_package: TlasPackage,
|
||||
tlas: Tlas,
|
||||
}
|
||||
|
||||
impl AsBuildContext {
|
||||
@ -56,15 +56,14 @@ impl AsBuildContext {
|
||||
},
|
||||
);
|
||||
|
||||
let tlas = ctx.device.create_tlas(&CreateTlasDescriptor {
|
||||
let mut tlas = ctx.device.create_tlas(&CreateTlasDescriptor {
|
||||
label: Some("TLAS"),
|
||||
max_instances: 1,
|
||||
flags: AccelerationStructureFlags::PREFER_FAST_TRACE | additional_tlas_flags,
|
||||
update_mode: AccelerationStructureUpdateMode::Build,
|
||||
});
|
||||
|
||||
let mut tlas_package = TlasPackage::new(tlas);
|
||||
tlas_package[0] = Some(TlasInstance::new(
|
||||
tlas[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,
|
||||
@ -75,7 +74,7 @@ impl AsBuildContext {
|
||||
vertices,
|
||||
blas_size,
|
||||
blas,
|
||||
tlas_package,
|
||||
tlas,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -48,17 +48,15 @@ fn acceleration_structure_build(ctx: &TestingContext, use_index_buffer: bool) {
|
||||
},
|
||||
);
|
||||
|
||||
let tlas = device.create_tlas(&wgpu::CreateTlasDescriptor {
|
||||
let mut tlas = device.create_tlas(&wgpu::CreateTlasDescriptor {
|
||||
label: None,
|
||||
flags: wgpu::AccelerationStructureFlags::PREFER_FAST_TRACE,
|
||||
update_mode: wgpu::AccelerationStructureUpdateMode::Build,
|
||||
max_instances,
|
||||
});
|
||||
|
||||
let mut tlas_package = wgpu::TlasPackage::new(tlas);
|
||||
|
||||
for j in 0..max_instances {
|
||||
tlas_package[j as usize] = Some(wgpu::TlasInstance::new(
|
||||
tlas[j as usize] = Some(wgpu::TlasInstance::new(
|
||||
&blas,
|
||||
mesh_gen::affine_to_rows(&Affine3A::from_rotation_translation(
|
||||
Quat::from_rotation_y(45.9_f32.to_radians()),
|
||||
@ -90,7 +88,7 @@ fn acceleration_structure_build(ctx: &TestingContext, use_index_buffer: bool) {
|
||||
transform_buffer_offset: None,
|
||||
}]),
|
||||
}),
|
||||
iter::once(&tlas_package),
|
||||
iter::once(&tlas),
|
||||
);
|
||||
|
||||
ctx.queue.submit(Some(encoder.finish()));
|
||||
|
||||
@ -40,8 +40,7 @@ fn access_all_struct_members(ctx: TestingContext) {
|
||||
label: Some("Build"),
|
||||
});
|
||||
|
||||
encoder_build
|
||||
.build_acceleration_structures([&as_ctx.blas_build_entry()], [&as_ctx.tlas_package]);
|
||||
encoder_build.build_acceleration_structures([&as_ctx.blas_build_entry()], [&as_ctx.tlas]);
|
||||
|
||||
ctx.queue.submit([encoder_build.finish()]);
|
||||
|
||||
@ -69,7 +68,7 @@ fn access_all_struct_members(ctx: TestingContext) {
|
||||
entries: &[
|
||||
BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: BindingResource::AccelerationStructure(as_ctx.tlas_package.tlas()),
|
||||
resource: BindingResource::AccelerationStructure(&as_ctx.tlas),
|
||||
},
|
||||
BindGroupEntry {
|
||||
binding: 1,
|
||||
|
||||
@ -19,7 +19,7 @@ use crate::{
|
||||
init_tracker::MemoryInitKind,
|
||||
ray_tracing::{
|
||||
BlasBuildEntry, BlasGeometries, BlasTriangleGeometry, BuildAccelerationStructureError,
|
||||
TlasBuildEntry, TlasInstance, TlasPackage, TraceBlasBuildEntry, TraceBlasGeometries,
|
||||
TlasInstance, TlasPackage, TraceBlasBuildEntry, TraceBlasGeometries,
|
||||
TraceBlasTriangleGeometry, TraceTlasInstance, TraceTlasPackage,
|
||||
},
|
||||
resource::{
|
||||
@ -58,12 +58,6 @@ struct TlasStore<'a> {
|
||||
range: Range<usize>,
|
||||
}
|
||||
|
||||
struct TlasBufferStore {
|
||||
buffer: Arc<Buffer>,
|
||||
transition: Option<PendingTransition<BufferUses>>,
|
||||
entry: TlasBuildEntry,
|
||||
}
|
||||
|
||||
impl Global {
|
||||
pub fn command_encoder_mark_acceleration_structures_built(
|
||||
&self,
|
||||
@ -108,281 +102,6 @@ impl Global {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
// Currently this function is very similar to its safe counterpart, however certain parts of it are very different,
|
||||
// making for the two to be implemented differently, the main difference is this function has separate buffers for each
|
||||
// of the TLAS instances while the other has one large buffer
|
||||
// TODO: reconsider this function's usefulness once blas and tlas `as_hal` are added and some time has passed.
|
||||
pub fn command_encoder_build_acceleration_structures_unsafe_tlas<'a>(
|
||||
&self,
|
||||
command_encoder_id: CommandEncoderId,
|
||||
blas_iter: impl Iterator<Item = BlasBuildEntry<'a>>,
|
||||
tlas_iter: impl Iterator<Item = TlasBuildEntry>,
|
||||
) -> Result<(), BuildAccelerationStructureError> {
|
||||
profiling::scope!("CommandEncoder::build_acceleration_structures_unsafe_tlas");
|
||||
|
||||
let hub = &self.hub;
|
||||
|
||||
let cmd_buf = hub
|
||||
.command_buffers
|
||||
.get(command_encoder_id.into_command_buffer_id());
|
||||
|
||||
let device = &cmd_buf.device;
|
||||
|
||||
device.require_features(Features::EXPERIMENTAL_RAY_TRACING_ACCELERATION_STRUCTURE)?;
|
||||
|
||||
let mut build_command = AsBuild::default();
|
||||
|
||||
#[cfg(feature = "trace")]
|
||||
let trace_blas: Vec<TraceBlasBuildEntry> = blas_iter
|
||||
.map(|blas_entry| {
|
||||
let geometries = match blas_entry.geometries {
|
||||
BlasGeometries::TriangleGeometries(triangle_geometries) => {
|
||||
TraceBlasGeometries::TriangleGeometries(
|
||||
triangle_geometries
|
||||
.map(|tg| TraceBlasTriangleGeometry {
|
||||
size: tg.size.clone(),
|
||||
vertex_buffer: tg.vertex_buffer,
|
||||
index_buffer: tg.index_buffer,
|
||||
transform_buffer: tg.transform_buffer,
|
||||
first_vertex: tg.first_vertex,
|
||||
vertex_stride: tg.vertex_stride,
|
||||
first_index: tg.first_index,
|
||||
transform_buffer_offset: tg.transform_buffer_offset,
|
||||
})
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
};
|
||||
TraceBlasBuildEntry {
|
||||
blas_id: blas_entry.blas_id,
|
||||
geometries,
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
#[cfg(feature = "trace")]
|
||||
let trace_tlas: Vec<TlasBuildEntry> = tlas_iter.collect();
|
||||
#[cfg(feature = "trace")]
|
||||
if let Some(ref mut list) = cmd_buf.data.lock().get_inner().commands {
|
||||
list.push(
|
||||
crate::device::trace::Command::BuildAccelerationStructuresUnsafeTlas {
|
||||
blas: trace_blas.clone(),
|
||||
tlas: trace_tlas.clone(),
|
||||
},
|
||||
);
|
||||
if !trace_tlas.is_empty() {
|
||||
log::warn!("a trace of command_encoder_build_acceleration_structures_unsafe_tlas containing a tlas build is not replayable!");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "trace")]
|
||||
let blas_iter = trace_blas.iter().map(|blas_entry| {
|
||||
let geometries = match &blas_entry.geometries {
|
||||
TraceBlasGeometries::TriangleGeometries(triangle_geometries) => {
|
||||
let iter = triangle_geometries.iter().map(|tg| BlasTriangleGeometry {
|
||||
size: &tg.size,
|
||||
vertex_buffer: tg.vertex_buffer,
|
||||
index_buffer: tg.index_buffer,
|
||||
transform_buffer: tg.transform_buffer,
|
||||
first_vertex: tg.first_vertex,
|
||||
vertex_stride: tg.vertex_stride,
|
||||
first_index: tg.first_index,
|
||||
transform_buffer_offset: tg.transform_buffer_offset,
|
||||
});
|
||||
BlasGeometries::TriangleGeometries(Box::new(iter))
|
||||
}
|
||||
};
|
||||
BlasBuildEntry {
|
||||
blas_id: blas_entry.blas_id,
|
||||
geometries,
|
||||
}
|
||||
});
|
||||
|
||||
#[cfg(feature = "trace")]
|
||||
let tlas_iter = trace_tlas.iter();
|
||||
|
||||
let mut input_barriers = Vec::<hal::BufferBarrier<dyn hal::DynBuffer>>::new();
|
||||
let mut buf_storage = Vec::new();
|
||||
|
||||
let mut scratch_buffer_blas_size = 0;
|
||||
let mut blas_storage = Vec::new();
|
||||
let mut cmd_buf_data = cmd_buf.data.lock();
|
||||
let mut cmd_buf_data_guard = cmd_buf_data.record()?;
|
||||
let cmd_buf_data = &mut *cmd_buf_data_guard;
|
||||
|
||||
iter_blas(
|
||||
blas_iter,
|
||||
cmd_buf_data,
|
||||
&mut build_command,
|
||||
&mut buf_storage,
|
||||
hub,
|
||||
)?;
|
||||
|
||||
let snatch_guard = device.snatchable_lock.read();
|
||||
iter_buffers(
|
||||
&mut buf_storage,
|
||||
&snatch_guard,
|
||||
&mut input_barriers,
|
||||
cmd_buf_data,
|
||||
&mut scratch_buffer_blas_size,
|
||||
&mut blas_storage,
|
||||
hub,
|
||||
device.alignments.ray_tracing_scratch_buffer_alignment,
|
||||
)?;
|
||||
|
||||
let mut scratch_buffer_tlas_size = 0;
|
||||
let mut tlas_storage = Vec::<UnsafeTlasStore>::new();
|
||||
let mut tlas_buf_storage = Vec::new();
|
||||
|
||||
for entry in tlas_iter {
|
||||
let instance_buffer = hub.buffers.get(entry.instance_buffer_id).get()?;
|
||||
let data = cmd_buf_data.trackers.buffers.set_single(
|
||||
&instance_buffer,
|
||||
BufferUses::BOTTOM_LEVEL_ACCELERATION_STRUCTURE_INPUT,
|
||||
);
|
||||
tlas_buf_storage.push(TlasBufferStore {
|
||||
buffer: instance_buffer,
|
||||
transition: data,
|
||||
entry: entry.clone(),
|
||||
});
|
||||
}
|
||||
|
||||
for tlas_buf in &mut tlas_buf_storage {
|
||||
let entry = &tlas_buf.entry;
|
||||
let instance_buffer = {
|
||||
let (instance_buffer, instance_pending) =
|
||||
(&mut tlas_buf.buffer, &mut tlas_buf.transition);
|
||||
let instance_raw = instance_buffer.try_raw(&snatch_guard)?;
|
||||
instance_buffer.check_usage(BufferUsages::TLAS_INPUT)?;
|
||||
|
||||
if let Some(barrier) = instance_pending
|
||||
.take()
|
||||
.map(|pending| pending.into_hal(instance_buffer, &snatch_guard))
|
||||
{
|
||||
input_barriers.push(barrier);
|
||||
}
|
||||
instance_raw
|
||||
};
|
||||
|
||||
let tlas = hub.tlas_s.get(entry.tlas_id).get()?;
|
||||
cmd_buf_data.trackers.tlas_s.insert_single(tlas.clone());
|
||||
|
||||
build_command.tlas_s_built.push(TlasBuild {
|
||||
tlas: tlas.clone(),
|
||||
dependencies: Vec::new(),
|
||||
});
|
||||
|
||||
let scratch_buffer_offset = scratch_buffer_tlas_size;
|
||||
scratch_buffer_tlas_size += align_to(
|
||||
tlas.size_info.build_scratch_size as u32,
|
||||
device.alignments.ray_tracing_scratch_buffer_alignment,
|
||||
) as u64;
|
||||
|
||||
tlas_storage.push(UnsafeTlasStore {
|
||||
tlas,
|
||||
entries: hal::AccelerationStructureEntries::Instances(
|
||||
hal::AccelerationStructureInstances {
|
||||
buffer: Some(instance_buffer),
|
||||
offset: 0,
|
||||
count: entry.instance_count,
|
||||
},
|
||||
),
|
||||
scratch_buffer_offset,
|
||||
});
|
||||
}
|
||||
|
||||
let scratch_size =
|
||||
match wgt::BufferSize::new(max(scratch_buffer_blas_size, scratch_buffer_tlas_size)) {
|
||||
None => {
|
||||
cmd_buf_data_guard.mark_successful();
|
||||
return Ok(());
|
||||
}
|
||||
Some(size) => size,
|
||||
};
|
||||
|
||||
let scratch_buffer = ScratchBuffer::new(device, scratch_size)?;
|
||||
|
||||
let scratch_buffer_barrier = hal::BufferBarrier::<dyn hal::DynBuffer> {
|
||||
buffer: scratch_buffer.raw(),
|
||||
usage: hal::StateTransition {
|
||||
from: BufferUses::ACCELERATION_STRUCTURE_SCRATCH,
|
||||
to: BufferUses::ACCELERATION_STRUCTURE_SCRATCH,
|
||||
},
|
||||
};
|
||||
|
||||
let mut tlas_descriptors = Vec::new();
|
||||
|
||||
for UnsafeTlasStore {
|
||||
tlas,
|
||||
entries,
|
||||
scratch_buffer_offset,
|
||||
} in &tlas_storage
|
||||
{
|
||||
if tlas.update_mode == wgt::AccelerationStructureUpdateMode::PreferUpdate {
|
||||
log::info!("only rebuild implemented")
|
||||
}
|
||||
tlas_descriptors.push(hal::BuildAccelerationStructureDescriptor {
|
||||
entries,
|
||||
mode: hal::AccelerationStructureBuildMode::Build,
|
||||
flags: tlas.flags,
|
||||
source_acceleration_structure: None,
|
||||
destination_acceleration_structure: tlas.try_raw(&snatch_guard)?,
|
||||
scratch_buffer: scratch_buffer.raw(),
|
||||
scratch_buffer_offset: *scratch_buffer_offset,
|
||||
})
|
||||
}
|
||||
|
||||
let blas_present = !blas_storage.is_empty();
|
||||
let tlas_present = !tlas_storage.is_empty();
|
||||
|
||||
let cmd_buf_raw = cmd_buf_data.encoder.open()?;
|
||||
|
||||
let mut blas_s_compactable = Vec::new();
|
||||
let mut descriptors = Vec::new();
|
||||
|
||||
for storage in &blas_storage {
|
||||
descriptors.push(map_blas(
|
||||
storage,
|
||||
scratch_buffer.raw(),
|
||||
&snatch_guard,
|
||||
&mut blas_s_compactable,
|
||||
)?);
|
||||
}
|
||||
|
||||
build_blas(
|
||||
cmd_buf_raw,
|
||||
blas_present,
|
||||
tlas_present,
|
||||
input_barriers,
|
||||
&descriptors,
|
||||
scratch_buffer_barrier,
|
||||
blas_s_compactable,
|
||||
);
|
||||
|
||||
if tlas_present {
|
||||
unsafe {
|
||||
cmd_buf_raw.build_acceleration_structures(&tlas_descriptors);
|
||||
|
||||
cmd_buf_raw.place_acceleration_structure_barrier(
|
||||
hal::AccelerationStructureBarrier {
|
||||
usage: hal::StateTransition {
|
||||
from: hal::AccelerationStructureUses::BUILD_OUTPUT,
|
||||
to: hal::AccelerationStructureUses::SHADER_INPUT,
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
cmd_buf_data
|
||||
.temp_resources
|
||||
.push(TempResource::ScratchBuffer(scratch_buffer));
|
||||
|
||||
cmd_buf_data.as_actions.push(AsAction::Build(build_command));
|
||||
|
||||
cmd_buf_data_guard.mark_successful();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn command_encoder_build_acceleration_structures<'a>(
|
||||
&self,
|
||||
|
||||
@ -202,10 +202,6 @@ pub enum Command {
|
||||
timestamp_writes: Option<crate::command::PassTimestampWrites>,
|
||||
occlusion_query_set_id: Option<id::QuerySetId>,
|
||||
},
|
||||
BuildAccelerationStructuresUnsafeTlas {
|
||||
blas: Vec<crate::ray_tracing::TraceBlasBuildEntry>,
|
||||
tlas: Vec<crate::ray_tracing::TlasBuildEntry>,
|
||||
},
|
||||
BuildAccelerationStructures {
|
||||
blas: Vec<crate::ray_tracing::TraceBlasBuildEntry>,
|
||||
tlas: Vec<crate::ray_tracing::TraceTlasPackage>,
|
||||
|
||||
@ -31,7 +31,7 @@ static_assertions::assert_impl_all!(CreateBlasDescriptor<'_>: Send, Sync);
|
||||
|
||||
/// Safe instance for a [Tlas].
|
||||
///
|
||||
/// A TlasInstance may be made invalid, if a TlasInstance is invalid, any attempt to build a [TlasPackage] containing an
|
||||
/// A TlasInstance may be made invalid, if a TlasInstance is invalid, any attempt to build a [Tlas] containing an
|
||||
/// invalid TlasInstance will generate a validation error
|
||||
///
|
||||
/// Each one contains:
|
||||
@ -42,7 +42,6 @@ static_assertions::assert_impl_all!(CreateBlasDescriptor<'_>: Send, Sync);
|
||||
/// - A user accessible custom index
|
||||
///
|
||||
/// [Tlas]: crate::Tlas
|
||||
/// [TlasPackage]: crate::TlasPackage
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TlasInstance {
|
||||
pub(crate) blas: dispatch::DispatchBlas,
|
||||
|
||||
@ -1,10 +1,7 @@
|
||||
use core::ops::Range;
|
||||
|
||||
use crate::{
|
||||
api::{
|
||||
blas::BlasBuildEntry,
|
||||
tlas::{TlasBuildEntry, TlasPackage},
|
||||
},
|
||||
api::{blas::BlasBuildEntry, tlas::Tlas},
|
||||
*,
|
||||
};
|
||||
|
||||
@ -341,34 +338,12 @@ impl CommandEncoder {
|
||||
pub fn build_acceleration_structures<'a>(
|
||||
&mut self,
|
||||
blas: impl IntoIterator<Item = &'a BlasBuildEntry<'a>>,
|
||||
tlas: impl IntoIterator<Item = &'a TlasPackage>,
|
||||
tlas: impl IntoIterator<Item = &'a Tlas>,
|
||||
) {
|
||||
self.inner
|
||||
.build_acceleration_structures(&mut blas.into_iter(), &mut tlas.into_iter());
|
||||
}
|
||||
|
||||
/// Build bottom and top level acceleration structures.
|
||||
/// See [`CommandEncoder::build_acceleration_structures`] for the safe version and more details. All validation in [`CommandEncoder::build_acceleration_structures`] except that
|
||||
/// listed under tlas applies here as well.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// - The contents of the raw instance buffer must be valid for the underling api.
|
||||
/// - All bottom level acceleration structures, referenced in the raw instance buffer must be valid and built,
|
||||
/// when the corresponding top level acceleration structure is built. (builds may happen in the same invocation of this function).
|
||||
/// - At the time when the top level acceleration structure is used in a bind group, all associated bottom level acceleration structures must be valid,
|
||||
/// and built (no later than the time when the top level acceleration structure was built).
|
||||
pub unsafe fn build_acceleration_structures_unsafe_tlas<'a>(
|
||||
&mut self,
|
||||
blas: impl IntoIterator<Item = &'a BlasBuildEntry<'a>>,
|
||||
tlas: impl IntoIterator<Item = &'a TlasBuildEntry<'a>>,
|
||||
) {
|
||||
self.inner.build_acceleration_structures_unsafe_tlas(
|
||||
&mut blas.into_iter(),
|
||||
&mut tlas.into_iter(),
|
||||
);
|
||||
}
|
||||
|
||||
/// Transition resources to an underlying hal resource state.
|
||||
///
|
||||
/// This is an advanced, native-only API (no-op on web) that has two main use cases:
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use alloc::{boxed::Box, string::String, sync::Arc};
|
||||
use alloc::{boxed::Box, string::String, sync::Arc, vec};
|
||||
use core::{error, fmt, future::Future};
|
||||
|
||||
use crate::api::blas::{Blas, BlasGeometrySizeDescriptors, CreateBlasDescriptor};
|
||||
@ -603,10 +603,9 @@ impl Device {
|
||||
let tlas = self.inner.create_tlas(desc);
|
||||
|
||||
Tlas {
|
||||
shared: Arc::new(TlasShared {
|
||||
inner: tlas,
|
||||
max_instances: desc.max_instances,
|
||||
}),
|
||||
inner: tlas,
|
||||
instances: vec![None; desc.max_instances as usize],
|
||||
lowest_unmodified: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,36 +1,31 @@
|
||||
use alloc::{sync::Arc, vec, vec::Vec};
|
||||
use core::ops::{Index, IndexMut, Range};
|
||||
|
||||
use crate::{api::blas::TlasInstance, dispatch};
|
||||
use crate::{BindingResource, Buffer, Label};
|
||||
use crate::{BindingResource, Label};
|
||||
use alloc::vec::Vec;
|
||||
use core::ops::{Index, IndexMut, Range};
|
||||
use wgt::WasmNotSendSync;
|
||||
|
||||
/// Descriptor to create top level acceleration structures.
|
||||
pub type CreateTlasDescriptor<'a> = wgt::CreateTlasDescriptor<Label<'a>>;
|
||||
static_assertions::assert_impl_all!(CreateTlasDescriptor<'_>: Send, Sync);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct TlasShared {
|
||||
pub(crate) inner: dispatch::DispatchTlas,
|
||||
pub(crate) max_instances: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
/// Top Level Acceleration Structure (TLAS).
|
||||
///
|
||||
/// A TLAS contains a series of [TLAS instances], which are a reference to
|
||||
/// a BLAS and a transformation matrix placing the geometry in the world.
|
||||
///
|
||||
/// A TLAS contains TLAS instances in a device readable form, you cant interact
|
||||
/// A TLAS also contains an extra set of TLAS instances in a device readable form, you cant interact
|
||||
/// directly with these, instead you have to build the TLAS with [TLAS instances].
|
||||
///
|
||||
/// [TLAS instances]: TlasInstance
|
||||
pub struct Tlas {
|
||||
pub(crate) shared: Arc<TlasShared>,
|
||||
pub(crate) inner: dispatch::DispatchTlas,
|
||||
pub(crate) instances: Vec<Option<TlasInstance>>,
|
||||
pub(crate) lowest_unmodified: u32,
|
||||
}
|
||||
static_assertions::assert_impl_all!(Tlas: WasmNotSendSync);
|
||||
|
||||
crate::cmp::impl_eq_ord_hash_proxy!(Tlas => .shared.inner);
|
||||
crate::cmp::impl_eq_ord_hash_proxy!(Tlas => .inner);
|
||||
|
||||
impl Tlas {
|
||||
/// Returns the inner hal Acceleration Structure using a callback. The hal acceleration structure
|
||||
@ -51,7 +46,7 @@ impl Tlas {
|
||||
&mut self,
|
||||
hal_tlas_callback: F,
|
||||
) -> R {
|
||||
if let Some(tlas) = self.shared.inner.as_core_opt() {
|
||||
if let Some(tlas) = self.inner.as_core_opt() {
|
||||
unsafe { tlas.context.tlas_as_hal::<A, F, R>(tlas, hal_tlas_callback) }
|
||||
} else {
|
||||
hal_tlas_callback(None)
|
||||
@ -61,47 +56,7 @@ impl Tlas {
|
||||
#[cfg(custom)]
|
||||
/// Returns custom implementation of Tlas (if custom backend and is internally T)
|
||||
pub fn as_custom<T: crate::custom::TlasInterface>(&self) -> Option<&T> {
|
||||
self.shared.inner.as_custom()
|
||||
}
|
||||
}
|
||||
|
||||
/// Entry for a top level acceleration structure build.
|
||||
/// Used with raw instance buffers for an unvalidated builds.
|
||||
/// See [`TlasPackage`] for the safe version.
|
||||
pub struct TlasBuildEntry<'a> {
|
||||
/// Reference to the acceleration structure.
|
||||
pub tlas: &'a Tlas,
|
||||
/// Reference to the raw instance buffer, each instance is similar to [`TlasInstance`] but contains a handle to the BLAS.
|
||||
pub instance_buffer: &'a Buffer,
|
||||
/// Number of instances in the instance buffer.
|
||||
pub instance_count: u32,
|
||||
}
|
||||
static_assertions::assert_impl_all!(TlasBuildEntry<'_>: WasmNotSendSync);
|
||||
|
||||
/// The safe version of [`TlasBuildEntry`], containing [`TlasInstance`]s instead of a raw buffer.
|
||||
pub struct TlasPackage {
|
||||
pub(crate) tlas: Tlas,
|
||||
pub(crate) instances: Vec<Option<TlasInstance>>,
|
||||
pub(crate) lowest_unmodified: u32,
|
||||
}
|
||||
static_assertions::assert_impl_all!(TlasPackage: WasmNotSendSync);
|
||||
|
||||
impl TlasPackage {
|
||||
/// Construct [`TlasPackage`] consuming the [`Tlas`] (prevents modification of the [`Tlas`] without using this package).
|
||||
pub fn new(tlas: Tlas) -> Self {
|
||||
let max_instances = tlas.shared.max_instances;
|
||||
Self::new_with_instances(tlas, vec![None; max_instances as usize])
|
||||
}
|
||||
|
||||
/// Construct [`TlasPackage`] consuming the [`Tlas`] (prevents modification of the [`Tlas`] without using this package).
|
||||
/// This constructor moves the instances into the package (the number of instances needs to fit into tlas,
|
||||
/// otherwise when building a validation error will be raised).
|
||||
pub fn new_with_instances(tlas: Tlas, instances: Vec<Option<TlasInstance>>) -> Self {
|
||||
Self {
|
||||
tlas,
|
||||
lowest_unmodified: instances.len() as u32,
|
||||
instances,
|
||||
}
|
||||
self.inner.as_custom()
|
||||
}
|
||||
|
||||
/// Get a reference to all instances.
|
||||
@ -147,16 +102,11 @@ impl TlasPackage {
|
||||
///
|
||||
/// [`BindGroup`]: super::BindGroup
|
||||
pub fn as_binding(&self) -> BindingResource<'_> {
|
||||
BindingResource::AccelerationStructure(&self.tlas)
|
||||
}
|
||||
|
||||
/// Get a reference to the underling [`Tlas`].
|
||||
pub fn tlas(&self) -> &Tlas {
|
||||
&self.tlas
|
||||
BindingResource::AccelerationStructure(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<usize> for TlasPackage {
|
||||
impl Index<usize> for Tlas {
|
||||
type Output = Option<TlasInstance>;
|
||||
|
||||
fn index(&self, index: usize) -> &Self::Output {
|
||||
@ -164,7 +114,7 @@ impl Index<usize> for TlasPackage {
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<Range<usize>> for TlasPackage {
|
||||
impl Index<Range<usize>> for Tlas {
|
||||
type Output = [Option<TlasInstance>];
|
||||
|
||||
fn index(&self, index: Range<usize>) -> &Self::Output {
|
||||
@ -172,7 +122,7 @@ impl Index<Range<usize>> for TlasPackage {
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexMut<usize> for TlasPackage {
|
||||
impl IndexMut<usize> for Tlas {
|
||||
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
||||
let idx = self.instances.index_mut(index);
|
||||
if index as u32 + 1 > self.lowest_unmodified {
|
||||
@ -182,7 +132,7 @@ impl IndexMut<usize> for TlasPackage {
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexMut<Range<usize>> for TlasPackage {
|
||||
impl IndexMut<Range<usize>> for Tlas {
|
||||
fn index_mut(&mut self, index: Range<usize>) -> &mut Self::Output {
|
||||
let idx = self.instances.index_mut(index.clone());
|
||||
if index.end > self.lowest_unmodified as usize {
|
||||
|
||||
@ -3107,18 +3107,10 @@ impl dispatch::CommandEncoderInterface for WebCommandEncoder {
|
||||
unimplemented!("Raytracing not implemented for web");
|
||||
}
|
||||
|
||||
fn build_acceleration_structures_unsafe_tlas<'a>(
|
||||
&self,
|
||||
_blas: &mut dyn Iterator<Item = &'a crate::BlasBuildEntry<'a>>,
|
||||
_tlas: &mut dyn Iterator<Item = &'a crate::TlasBuildEntry<'a>>,
|
||||
) {
|
||||
unimplemented!("Raytracing not implemented for web");
|
||||
}
|
||||
|
||||
fn build_acceleration_structures<'a>(
|
||||
&self,
|
||||
_blas: &mut dyn Iterator<Item = &'a crate::BlasBuildEntry<'a>>,
|
||||
_tlas: &mut dyn Iterator<Item = &'a crate::TlasPackage>,
|
||||
_tlas: &mut dyn Iterator<Item = &'a crate::Tlas>,
|
||||
) {
|
||||
unimplemented!("Raytracing not implemented for web");
|
||||
}
|
||||
|
||||
@ -1241,7 +1241,7 @@ impl dispatch::DeviceInterface for CoreDevice {
|
||||
}
|
||||
BindingResource::AccelerationStructure(acceleration_structure) => {
|
||||
bm::BindingResource::AccelerationStructure(
|
||||
acceleration_structure.shared.inner.as_core().id,
|
||||
acceleration_structure.inner.as_core().id,
|
||||
)
|
||||
}
|
||||
},
|
||||
@ -2594,7 +2594,7 @@ impl dispatch::CommandEncoderInterface for CoreCommandEncoder {
|
||||
.map(|b| b.inner.as_core().id)
|
||||
.collect::<SmallVec<[_; 4]>>();
|
||||
let tlas = tlas
|
||||
.map(|t| t.shared.inner.as_core().id)
|
||||
.map(|t| t.inner.as_core().id)
|
||||
.collect::<SmallVec<[_; 4]>>();
|
||||
if let Err(cause) = self
|
||||
.context
|
||||
@ -2609,60 +2609,10 @@ impl dispatch::CommandEncoderInterface for CoreCommandEncoder {
|
||||
}
|
||||
}
|
||||
|
||||
fn build_acceleration_structures_unsafe_tlas<'a>(
|
||||
&self,
|
||||
blas: &mut dyn Iterator<Item = &'a crate::BlasBuildEntry<'a>>,
|
||||
tlas: &mut dyn Iterator<Item = &'a crate::TlasBuildEntry<'a>>,
|
||||
) {
|
||||
let blas = blas.map(|e: &crate::BlasBuildEntry<'_>| {
|
||||
let geometries = match e.geometry {
|
||||
crate::BlasGeometries::TriangleGeometries(ref triangle_geometries) => {
|
||||
let iter = triangle_geometries.iter().map(|tg| {
|
||||
wgc::ray_tracing::BlasTriangleGeometry {
|
||||
vertex_buffer: tg.vertex_buffer.inner.as_core().id,
|
||||
index_buffer: tg.index_buffer.map(|buf| buf.inner.as_core().id),
|
||||
transform_buffer: tg.transform_buffer.map(|buf| buf.inner.as_core().id),
|
||||
size: tg.size,
|
||||
transform_buffer_offset: tg.transform_buffer_offset,
|
||||
first_vertex: tg.first_vertex,
|
||||
vertex_stride: tg.vertex_stride,
|
||||
first_index: tg.first_index,
|
||||
}
|
||||
});
|
||||
wgc::ray_tracing::BlasGeometries::TriangleGeometries(Box::new(iter))
|
||||
}
|
||||
};
|
||||
wgc::ray_tracing::BlasBuildEntry {
|
||||
blas_id: e.blas.inner.as_core().id,
|
||||
geometries,
|
||||
}
|
||||
});
|
||||
|
||||
let tlas = tlas.into_iter().map(|e: &crate::TlasBuildEntry<'a>| {
|
||||
wgc::ray_tracing::TlasBuildEntry {
|
||||
tlas_id: e.tlas.shared.inner.as_core().id,
|
||||
instance_buffer_id: e.instance_buffer.inner.as_core().id,
|
||||
instance_count: e.instance_count,
|
||||
}
|
||||
});
|
||||
|
||||
if let Err(cause) = self
|
||||
.context
|
||||
.0
|
||||
.command_encoder_build_acceleration_structures_unsafe_tlas(self.id, blas, tlas)
|
||||
{
|
||||
self.context.handle_error_nolabel(
|
||||
&self.error_sink,
|
||||
cause,
|
||||
"CommandEncoder::build_acceleration_structures_unsafe_tlas",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn build_acceleration_structures<'a>(
|
||||
&self,
|
||||
blas: &mut dyn Iterator<Item = &'a crate::BlasBuildEntry<'a>>,
|
||||
tlas: &mut dyn Iterator<Item = &'a crate::TlasPackage>,
|
||||
tlas: &mut dyn Iterator<Item = &'a crate::Tlas>,
|
||||
) {
|
||||
let blas = blas.map(|e: &crate::BlasBuildEntry<'_>| {
|
||||
let geometries = match e.geometry {
|
||||
@ -2703,7 +2653,7 @@ impl dispatch::CommandEncoderInterface for CoreCommandEncoder {
|
||||
})
|
||||
});
|
||||
wgc::ray_tracing::TlasPackage {
|
||||
tlas_id: e.tlas.shared.inner.as_core().id,
|
||||
tlas_id: e.inner.as_core().id,
|
||||
instances: Box::new(instances),
|
||||
lowest_unmodified: e.lowest_unmodified,
|
||||
}
|
||||
|
||||
@ -336,15 +336,10 @@ pub trait CommandEncoderInterface: CommonTraits {
|
||||
tlas: &mut dyn Iterator<Item = &'a Tlas>,
|
||||
);
|
||||
|
||||
fn build_acceleration_structures_unsafe_tlas<'a>(
|
||||
&self,
|
||||
blas: &mut dyn Iterator<Item = &'a crate::BlasBuildEntry<'a>>,
|
||||
tlas: &mut dyn Iterator<Item = &'a crate::TlasBuildEntry<'a>>,
|
||||
);
|
||||
fn build_acceleration_structures<'a>(
|
||||
&self,
|
||||
blas: &mut dyn Iterator<Item = &'a crate::BlasBuildEntry<'a>>,
|
||||
tlas: &mut dyn Iterator<Item = &'a crate::TlasPackage>,
|
||||
tlas: &mut dyn Iterator<Item = &'a crate::Tlas>,
|
||||
);
|
||||
|
||||
fn transition_resources<'a>(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user