Remove unsafe acceleration structure build (#7513)

This commit is contained in:
Vecvec 2025-06-12 16:43:03 +12:00 committed by GitHub
parent 645354a528
commit aa427de4ea
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
23 changed files with 102 additions and 602 deletions

View File

@ -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

View File

@ -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

View File

@ -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 {

View File

@ -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 {

View File

@ -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 {

View File

@ -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 {

View File

@ -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(),
},
],
});

View File

@ -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 {

View File

@ -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 {

View File

@ -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,
);

View File

@ -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.

View File

@ -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,
}
}

View File

@ -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()));

View File

@ -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,

View File

@ -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,

View File

@ -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>,

View File

@ -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,

View File

@ -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:

View File

@ -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,
}
}
}

View File

@ -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 {

View File

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

View File

@ -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,
}

View File

@ -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>(