mirror of
https://github.com/gfx-rs/wgpu.git
synced 2025-12-08 21:26:17 +00:00
[wgpu] Blas compaction (#7285)
Co-authored-by: Connor Fitzgerald <connorwadefitzgerald@gmail.com>
This commit is contained in:
parent
efbac5dfba
commit
73eb83ded1
@ -94,6 +94,7 @@ Naga now infers the correct binding layout when a resource appears only in an as
|
|||||||
|
|
||||||
#### General
|
#### General
|
||||||
|
|
||||||
|
- 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).
|
- 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).
|
- 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).
|
||||||
|
|
||||||
|
|||||||
@ -34,6 +34,53 @@ Before a [`Tlas`] is used in a shader it must
|
|||||||
- have all [`Blas`]es that it was last built with to have last been built in either the same build as
|
- have all [`Blas`]es that it was last built with to have last been built in either the same build as
|
||||||
this [`Tlas`] or an earlier build call.
|
this [`Tlas`] or an earlier build call.
|
||||||
|
|
||||||
|
### [`Blas`] compaction
|
||||||
|
|
||||||
|
Once a [`Blas`] has been built, it can be compacted. Acceleration structures are allocated conservatively, without
|
||||||
|
knowing the exact data that is inside them. Once a [`Blas`] has been built, the driver can make data specific
|
||||||
|
optimisations to make the [`BLAS`] smaller. To begin compaction call [`Blas::prepare_compaction_async`] on it. This
|
||||||
|
method waits until all builds operating on the [`Blas`] are finished, prepares the [`Blas`] to be compacted, and runs
|
||||||
|
the given callback. To check whether the [`Blas`] is ready, you can also call [`Blas::ready_for_compaction`] instead of
|
||||||
|
waiting for the callback (useful if you are asynchronously compacting a large number of [`Blas`]es). Submitting a
|
||||||
|
rebuild of a [`Blas`] terminates any [`Blas::prepare_compaction_async`], preventing the callback from being called, and
|
||||||
|
making the [`Blas`] no longer ready to compact. Once a [`Blas`] is ready for compaction, it can be compacted using
|
||||||
|
[`Queue::compact_blas`] this returns the new compacted [`Blas`], which is independent of the [`Blas`] passed in. The
|
||||||
|
other [`Blas`] can be used for other things, including being rebuilt without affecting the new [`Blas`]. The returned
|
||||||
|
[`Blas`] behaves largely like the [`Blas`] it was created from, except that it can be neither rebuilt, nor compacted
|
||||||
|
again.
|
||||||
|
|
||||||
|
An example of compaction being run when [`Blas`]es are ready, this would be in a situation when memory was not a major
|
||||||
|
problem, otherwise (e.g. if you get an out of memory error) you should compact immediately (and switching all
|
||||||
|
non-compacted [`Blas`]es to compacted ones).
|
||||||
|
```rust
|
||||||
|
use std::iter;
|
||||||
|
use wgpu::Blas;
|
||||||
|
|
||||||
|
struct BlasToBeCompacted {
|
||||||
|
blas: Blas,
|
||||||
|
/// The index into the TlasInstance this BLAS is used in.
|
||||||
|
tlas_index: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render(/*whatever args you need to render*/) {
|
||||||
|
/* additional code to prepare the renderer */
|
||||||
|
//An iterator of whatever BLASes you have called `prepare_compaction_async` on.
|
||||||
|
let blas_s_pending_compaction: impl Iterator<Item = BlasToBeCompacted> = iter::empty();
|
||||||
|
for blas_to_be_compacted in blas_s_pending_compaction {
|
||||||
|
if blas_to_be_compacted.blas.ready_for_compaction() {
|
||||||
|
let compacted_blas = queue.compact_blas(&blas_to_be_compacted.blas);
|
||||||
|
tlas_instance[blas_to_be_compacted.tlas_index].set_blas(&compacted_blas);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut encoder =
|
||||||
|
device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
|
||||||
|
/* do other preparations on th TlasInstance.*/
|
||||||
|
encoder.build_acceleration_structures(iter::empty(), iter::once(&tlas_package));
|
||||||
|
/* more render code */
|
||||||
|
queue.submit(Some(encoder.finish()));
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
[`Device::create_blas`]: https://wgpu.rs/doc/wgpu/struct.Device.html#method.create_blas
|
[`Device::create_blas`]: https://wgpu.rs/doc/wgpu/struct.Device.html#method.create_blas
|
||||||
[`Device::create_tlas`]: https://wgpu.rs/doc/wgpu/struct.Device.html#method.create_tlas
|
[`Device::create_tlas`]: https://wgpu.rs/doc/wgpu/struct.Device.html#method.create_tlas
|
||||||
[`Tlas`]: https://wgpu.rs/doc/wgpu/struct.Tlas.html
|
[`Tlas`]: https://wgpu.rs/doc/wgpu/struct.Tlas.html
|
||||||
@ -41,6 +88,9 @@ Before a [`Tlas`] is used in a shader it must
|
|||||||
[`TlasInstance`]: https://wgpu.rs/doc/wgpu/struct.TlasInstance.html
|
[`TlasInstance`]: https://wgpu.rs/doc/wgpu/struct.TlasInstance.html
|
||||||
[`TlasPackage`]: https://wgpu.rs/doc/wgpu/struct.TlasPackage.html
|
[`TlasPackage`]: https://wgpu.rs/doc/wgpu/struct.TlasPackage.html
|
||||||
[`TlasPackage::tlas`]: https://wgpu.rs/doc/wgpu/struct.TlasPackage.html#method.tlas
|
[`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
|
||||||
|
|
||||||
## `naga`'s raytracing API:
|
## `naga`'s raytracing API:
|
||||||
|
|
||||||
|
|||||||
@ -3,9 +3,9 @@ use std::pin::Pin;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use wgpu::custom::{
|
use wgpu::custom::{
|
||||||
AdapterInterface, ComputePipelineInterface, DeviceInterface, DispatchAdapter, DispatchDevice,
|
AdapterInterface, ComputePipelineInterface, DeviceInterface, DispatchAdapter, DispatchBlas,
|
||||||
DispatchQueue, DispatchShaderModule, DispatchSurface, InstanceInterface, QueueInterface,
|
DispatchDevice, DispatchQueue, DispatchShaderModule, DispatchSurface, InstanceInterface,
|
||||||
RequestAdapterFuture, ShaderModuleInterface,
|
QueueInterface, RequestAdapterFuture, ShaderModuleInterface,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@ -346,6 +346,10 @@ impl QueueInterface for CustomQueue {
|
|||||||
) {
|
) {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn compact_blas(&self, _blas: &DispatchBlas) -> (Option<u64>, DispatchBlas) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|||||||
@ -41,6 +41,160 @@ fn unbuilt_blas(ctx: TestingContext) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[gpu_test]
|
||||||
|
static UNBUILT_BLAS_COMPACTION: GpuTestConfiguration = GpuTestConfiguration::new()
|
||||||
|
.parameters(
|
||||||
|
TestParameters::default()
|
||||||
|
.test_features_limits()
|
||||||
|
.features(wgpu::Features::EXPERIMENTAL_RAY_TRACING_ACCELERATION_STRUCTURE)
|
||||||
|
// https://github.com/gfx-rs/wgpu/issues/6727
|
||||||
|
.skip(FailureCase::backend_adapter(wgpu::Backends::VULKAN, "AMD")),
|
||||||
|
)
|
||||||
|
.run_sync(unbuilt_blas_compaction);
|
||||||
|
|
||||||
|
fn unbuilt_blas_compaction(ctx: TestingContext) {
|
||||||
|
let as_ctx = AsBuildContext::new(
|
||||||
|
&ctx,
|
||||||
|
AccelerationStructureFlags::ALLOW_COMPACTION,
|
||||||
|
AccelerationStructureFlags::empty(),
|
||||||
|
);
|
||||||
|
|
||||||
|
fail(
|
||||||
|
&ctx.device,
|
||||||
|
|| {
|
||||||
|
// Prepare checks the BLAS has been built
|
||||||
|
as_ctx.blas.prepare_compaction_async(|_| {})
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[gpu_test]
|
||||||
|
static BLAS_COMPACTION_WITHOUT_FLAGS: GpuTestConfiguration = GpuTestConfiguration::new()
|
||||||
|
.parameters(
|
||||||
|
TestParameters::default()
|
||||||
|
.test_features_limits()
|
||||||
|
.features(wgpu::Features::EXPERIMENTAL_RAY_TRACING_ACCELERATION_STRUCTURE)
|
||||||
|
// https://github.com/gfx-rs/wgpu/issues/6727
|
||||||
|
.skip(FailureCase::backend_adapter(wgpu::Backends::VULKAN, "AMD")),
|
||||||
|
)
|
||||||
|
.run_sync(blas_compaction_without_flags);
|
||||||
|
|
||||||
|
fn blas_compaction_without_flags(ctx: TestingContext) {
|
||||||
|
let as_ctx = AsBuildContext::new(
|
||||||
|
&ctx,
|
||||||
|
AccelerationStructureFlags::empty(),
|
||||||
|
AccelerationStructureFlags::empty(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut encoder = ctx
|
||||||
|
.device
|
||||||
|
.create_command_encoder(&CommandEncoderDescriptor::default());
|
||||||
|
|
||||||
|
encoder.build_acceleration_structures([&as_ctx.blas_build_entry()], []);
|
||||||
|
|
||||||
|
ctx.queue.submit([encoder.finish()]);
|
||||||
|
|
||||||
|
fail(
|
||||||
|
&ctx.device,
|
||||||
|
|| {
|
||||||
|
// Prepare checks whether te BLAS is able to be compacted
|
||||||
|
as_ctx.blas.prepare_compaction_async(|_| {})
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[gpu_test]
|
||||||
|
static UNPREPARED_BLAS_COMPACTION: GpuTestConfiguration = GpuTestConfiguration::new()
|
||||||
|
.parameters(
|
||||||
|
TestParameters::default()
|
||||||
|
.test_features_limits()
|
||||||
|
.features(wgpu::Features::EXPERIMENTAL_RAY_TRACING_ACCELERATION_STRUCTURE)
|
||||||
|
// https://github.com/gfx-rs/wgpu/issues/6727
|
||||||
|
.skip(FailureCase::backend_adapter(wgpu::Backends::VULKAN, "AMD")),
|
||||||
|
)
|
||||||
|
.run_sync(unprepared_blas_compaction);
|
||||||
|
|
||||||
|
fn unprepared_blas_compaction(ctx: TestingContext) {
|
||||||
|
let as_ctx = AsBuildContext::new(
|
||||||
|
&ctx,
|
||||||
|
AccelerationStructureFlags::ALLOW_COMPACTION,
|
||||||
|
AccelerationStructureFlags::empty(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut encoder = ctx
|
||||||
|
.device
|
||||||
|
.create_command_encoder(&CommandEncoderDescriptor::default());
|
||||||
|
|
||||||
|
encoder.build_acceleration_structures([&as_ctx.blas_build_entry()], []);
|
||||||
|
|
||||||
|
ctx.queue.submit([encoder.finish()]);
|
||||||
|
|
||||||
|
fail(&ctx.device, || ctx.queue.compact_blas(&as_ctx.blas), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[gpu_test]
|
||||||
|
static BLAS_COMPACTION: GpuTestConfiguration = GpuTestConfiguration::new()
|
||||||
|
.parameters(
|
||||||
|
TestParameters::default()
|
||||||
|
.test_features_limits()
|
||||||
|
.features(wgpu::Features::EXPERIMENTAL_RAY_TRACING_ACCELERATION_STRUCTURE)
|
||||||
|
// https://github.com/gfx-rs/wgpu/issues/6727
|
||||||
|
.skip(FailureCase::backend_adapter(wgpu::Backends::VULKAN, "AMD")),
|
||||||
|
)
|
||||||
|
.run_sync(blas_compaction);
|
||||||
|
|
||||||
|
fn blas_compaction(ctx: TestingContext) {
|
||||||
|
let as_ctx = AsBuildContext::new(
|
||||||
|
&ctx,
|
||||||
|
AccelerationStructureFlags::ALLOW_COMPACTION,
|
||||||
|
AccelerationStructureFlags::empty(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut encoder = ctx
|
||||||
|
.device
|
||||||
|
.create_command_encoder(&CommandEncoderDescriptor::default());
|
||||||
|
|
||||||
|
// Build the BLAS to be compacted (so compaction is valid).
|
||||||
|
encoder.build_acceleration_structures([&as_ctx.blas_build_entry()], []);
|
||||||
|
|
||||||
|
ctx.queue.submit([encoder.finish()]);
|
||||||
|
|
||||||
|
// Prepare the BLAS to be compacted.
|
||||||
|
let (send, recv) = std::sync::mpsc::channel();
|
||||||
|
as_ctx.blas.prepare_compaction_async(move |res| {
|
||||||
|
res.unwrap();
|
||||||
|
send.send(()).unwrap();
|
||||||
|
});
|
||||||
|
|
||||||
|
// On native this will trigger the callback.
|
||||||
|
ctx.device.poll(PollType::Wait).unwrap();
|
||||||
|
// Check that the callback actually gets called (this test will timeout if it doesn't).
|
||||||
|
recv.recv().unwrap();
|
||||||
|
// This should return true because the callback has been called, and we haven't rebuilt the BLAS
|
||||||
|
assert!(as_ctx.blas.ready_for_compaction());
|
||||||
|
|
||||||
|
let compacted = ctx.queue.compact_blas(&as_ctx.blas);
|
||||||
|
|
||||||
|
// This actually executes the compact call.
|
||||||
|
ctx.queue.submit([]);
|
||||||
|
|
||||||
|
let mut fail_encoder = ctx
|
||||||
|
.device
|
||||||
|
.create_command_encoder(&CommandEncoderDescriptor::default());
|
||||||
|
|
||||||
|
// Try to build the compacted BLAS, this should fail.
|
||||||
|
let mut build_entry = as_ctx.blas_build_entry();
|
||||||
|
build_entry.blas = &compacted;
|
||||||
|
|
||||||
|
fail(
|
||||||
|
&ctx.device,
|
||||||
|
|| fail_encoder.build_acceleration_structures([&build_entry], []),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[gpu_test]
|
#[gpu_test]
|
||||||
static OUT_OF_ORDER_AS_BUILD: GpuTestConfiguration = GpuTestConfiguration::new()
|
static OUT_OF_ORDER_AS_BUILD: GpuTestConfiguration = GpuTestConfiguration::new()
|
||||||
.parameters(
|
.parameters(
|
||||||
|
|||||||
@ -22,7 +22,9 @@ use crate::{
|
|||||||
TlasBuildEntry, TlasInstance, TlasPackage, TraceBlasBuildEntry, TraceBlasGeometries,
|
TlasBuildEntry, TlasInstance, TlasPackage, TraceBlasBuildEntry, TraceBlasGeometries,
|
||||||
TraceBlasTriangleGeometry, TraceTlasInstance, TraceTlasPackage,
|
TraceBlasTriangleGeometry, TraceTlasInstance, TraceTlasPackage,
|
||||||
},
|
},
|
||||||
resource::{AccelerationStructure, Blas, Buffer, Labeled, StagingBuffer, Tlas},
|
resource::{
|
||||||
|
AccelerationStructure, Blas, BlasCompactState, Buffer, Labeled, StagingBuffer, Tlas,
|
||||||
|
},
|
||||||
scratch::ScratchBuffer,
|
scratch::ScratchBuffer,
|
||||||
snatch::SnatchGuard,
|
snatch::SnatchGuard,
|
||||||
track::PendingTransition,
|
track::PendingTransition,
|
||||||
@ -335,10 +337,16 @@ impl Global {
|
|||||||
|
|
||||||
let cmd_buf_raw = cmd_buf_data.encoder.open()?;
|
let cmd_buf_raw = cmd_buf_data.encoder.open()?;
|
||||||
|
|
||||||
|
let mut blas_s_compactable = Vec::new();
|
||||||
let mut descriptors = Vec::new();
|
let mut descriptors = Vec::new();
|
||||||
|
|
||||||
for storage in &blas_storage {
|
for storage in &blas_storage {
|
||||||
descriptors.push(map_blas(storage, scratch_buffer.raw(), &snatch_guard)?);
|
descriptors.push(map_blas(
|
||||||
|
storage,
|
||||||
|
scratch_buffer.raw(),
|
||||||
|
&snatch_guard,
|
||||||
|
&mut blas_s_compactable,
|
||||||
|
)?);
|
||||||
}
|
}
|
||||||
|
|
||||||
build_blas(
|
build_blas(
|
||||||
@ -348,6 +356,7 @@ impl Global {
|
|||||||
input_barriers,
|
input_barriers,
|
||||||
&descriptors,
|
&descriptors,
|
||||||
scratch_buffer_barrier,
|
scratch_buffer_barrier,
|
||||||
|
blas_s_compactable,
|
||||||
);
|
);
|
||||||
|
|
||||||
if tlas_present {
|
if tlas_present {
|
||||||
@ -664,10 +673,16 @@ impl Global {
|
|||||||
|
|
||||||
let cmd_buf_raw = cmd_buf_data.encoder.open()?;
|
let cmd_buf_raw = cmd_buf_data.encoder.open()?;
|
||||||
|
|
||||||
|
let mut blas_s_compactable = Vec::new();
|
||||||
let mut descriptors = Vec::new();
|
let mut descriptors = Vec::new();
|
||||||
|
|
||||||
for storage in &blas_storage {
|
for storage in &blas_storage {
|
||||||
descriptors.push(map_blas(storage, scratch_buffer.raw(), &snatch_guard)?);
|
descriptors.push(map_blas(
|
||||||
|
storage,
|
||||||
|
scratch_buffer.raw(),
|
||||||
|
&snatch_guard,
|
||||||
|
&mut blas_s_compactable,
|
||||||
|
)?);
|
||||||
}
|
}
|
||||||
|
|
||||||
build_blas(
|
build_blas(
|
||||||
@ -677,6 +692,7 @@ impl Global {
|
|||||||
input_barriers,
|
input_barriers,
|
||||||
&descriptors,
|
&descriptors,
|
||||||
scratch_buffer_barrier,
|
scratch_buffer_barrier,
|
||||||
|
blas_s_compactable,
|
||||||
);
|
);
|
||||||
|
|
||||||
if tlas_present {
|
if tlas_present {
|
||||||
@ -794,6 +810,15 @@ impl CommandBufferMutable {
|
|||||||
|
|
||||||
command_index_guard.next_acceleration_structure_build_command_index += 1;
|
command_index_guard.next_acceleration_structure_build_command_index += 1;
|
||||||
for blas in build.blas_s_built.iter() {
|
for blas in build.blas_s_built.iter() {
|
||||||
|
let mut state_lock = blas.compacted_state.lock();
|
||||||
|
*state_lock = match *state_lock {
|
||||||
|
BlasCompactState::Compacted => {
|
||||||
|
unreachable!("Should be validated out in build.")
|
||||||
|
}
|
||||||
|
// Reset the compacted state to idle. This means any prepares, before mapping their
|
||||||
|
// internal buffer, will terminate.
|
||||||
|
_ => BlasCompactState::Idle,
|
||||||
|
};
|
||||||
*blas.built_index.write() = Some(build_command_index);
|
*blas.built_index.write() = Some(build_command_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1215,6 +1240,10 @@ fn map_blas<'a>(
|
|||||||
storage: &'a BlasStore<'_>,
|
storage: &'a BlasStore<'_>,
|
||||||
scratch_buffer: &'a dyn hal::DynBuffer,
|
scratch_buffer: &'a dyn hal::DynBuffer,
|
||||||
snatch_guard: &'a SnatchGuard,
|
snatch_guard: &'a SnatchGuard,
|
||||||
|
blases_compactable: &mut Vec<(
|
||||||
|
&'a dyn hal::DynBuffer,
|
||||||
|
&'a dyn hal::DynAccelerationStructure,
|
||||||
|
)>,
|
||||||
) -> Result<
|
) -> Result<
|
||||||
hal::BuildAccelerationStructureDescriptor<
|
hal::BuildAccelerationStructureDescriptor<
|
||||||
'a,
|
'a,
|
||||||
@ -1231,12 +1260,27 @@ fn map_blas<'a>(
|
|||||||
if blas.update_mode == wgt::AccelerationStructureUpdateMode::PreferUpdate {
|
if blas.update_mode == wgt::AccelerationStructureUpdateMode::PreferUpdate {
|
||||||
log::info!("only rebuild implemented")
|
log::info!("only rebuild implemented")
|
||||||
}
|
}
|
||||||
|
let raw = blas.try_raw(snatch_guard)?;
|
||||||
|
|
||||||
|
let state_lock = blas.compacted_state.lock();
|
||||||
|
if let BlasCompactState::Compacted = *state_lock {
|
||||||
|
return Err(BuildAccelerationStructureError::CompactedBlas(
|
||||||
|
blas.error_ident(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if blas
|
||||||
|
.flags
|
||||||
|
.contains(wgpu_types::AccelerationStructureFlags::ALLOW_COMPACTION)
|
||||||
|
{
|
||||||
|
blases_compactable.push((blas.compaction_buffer.as_ref().unwrap().as_ref(), raw));
|
||||||
|
}
|
||||||
Ok(hal::BuildAccelerationStructureDescriptor {
|
Ok(hal::BuildAccelerationStructureDescriptor {
|
||||||
entries,
|
entries,
|
||||||
mode: hal::AccelerationStructureBuildMode::Build,
|
mode: hal::AccelerationStructureBuildMode::Build,
|
||||||
flags: blas.flags,
|
flags: blas.flags,
|
||||||
source_acceleration_structure: None,
|
source_acceleration_structure: None,
|
||||||
destination_acceleration_structure: blas.try_raw(snatch_guard)?,
|
destination_acceleration_structure: raw,
|
||||||
scratch_buffer,
|
scratch_buffer,
|
||||||
scratch_buffer_offset: *scratch_buffer_offset,
|
scratch_buffer_offset: *scratch_buffer_offset,
|
||||||
})
|
})
|
||||||
@ -1253,6 +1297,10 @@ fn build_blas<'a>(
|
|||||||
dyn hal::DynAccelerationStructure,
|
dyn hal::DynAccelerationStructure,
|
||||||
>],
|
>],
|
||||||
scratch_buffer_barrier: hal::BufferBarrier<dyn hal::DynBuffer>,
|
scratch_buffer_barrier: hal::BufferBarrier<dyn hal::DynBuffer>,
|
||||||
|
blas_s_for_compaction: Vec<(
|
||||||
|
&'a dyn hal::DynBuffer,
|
||||||
|
&'a dyn hal::DynAccelerationStructure,
|
||||||
|
)>,
|
||||||
) {
|
) {
|
||||||
unsafe {
|
unsafe {
|
||||||
cmd_buf_raw.transition_buffers(&input_barriers);
|
cmd_buf_raw.transition_buffers(&input_barriers);
|
||||||
@ -1279,6 +1327,20 @@ fn build_blas<'a>(
|
|||||||
|
|
||||||
let mut source_usage = hal::AccelerationStructureUses::empty();
|
let mut source_usage = hal::AccelerationStructureUses::empty();
|
||||||
let mut destination_usage = hal::AccelerationStructureUses::empty();
|
let mut destination_usage = hal::AccelerationStructureUses::empty();
|
||||||
|
for &(buf, blas) in blas_s_for_compaction.iter() {
|
||||||
|
unsafe {
|
||||||
|
cmd_buf_raw.transition_buffers(&[hal::BufferBarrier {
|
||||||
|
buffer: buf,
|
||||||
|
usage: hal::StateTransition {
|
||||||
|
from: BufferUses::ACCELERATION_STRUCTURE_QUERY,
|
||||||
|
to: BufferUses::ACCELERATION_STRUCTURE_QUERY,
|
||||||
|
},
|
||||||
|
}])
|
||||||
|
}
|
||||||
|
unsafe { cmd_buf_raw.read_acceleration_structure_compact_size(blas, buf) }
|
||||||
|
destination_usage |= hal::AccelerationStructureUses::COPY_SRC;
|
||||||
|
}
|
||||||
|
|
||||||
if blas_present {
|
if blas_present {
|
||||||
source_usage |= hal::AccelerationStructureUses::BUILD_OUTPUT;
|
source_usage |= hal::AccelerationStructureUses::BUILD_OUTPUT;
|
||||||
destination_usage |= hal::AccelerationStructureUses::BUILD_INPUT
|
destination_usage |= hal::AccelerationStructureUses::BUILD_INPUT
|
||||||
|
|||||||
@ -8,7 +8,8 @@ use crate::{
|
|||||||
queue::{EncoderInFlight, SubmittedWorkDoneClosure, TempResource},
|
queue::{EncoderInFlight, SubmittedWorkDoneClosure, TempResource},
|
||||||
DeviceError,
|
DeviceError,
|
||||||
},
|
},
|
||||||
resource::{Buffer, Texture, Trackable},
|
ray_tracing::BlasCompactReadyPendingClosure,
|
||||||
|
resource::{Blas, Buffer, Texture, Trackable},
|
||||||
snatch::SnatchGuard,
|
snatch::SnatchGuard,
|
||||||
SubmissionIndex,
|
SubmissionIndex,
|
||||||
};
|
};
|
||||||
@ -32,6 +33,9 @@ struct ActiveSubmission {
|
|||||||
/// Buffers to be mapped once this submission has completed.
|
/// Buffers to be mapped once this submission has completed.
|
||||||
mapped: Vec<Arc<Buffer>>,
|
mapped: Vec<Arc<Buffer>>,
|
||||||
|
|
||||||
|
/// BLASes to have their compacted size read back once this submission has completed.
|
||||||
|
compact_read_back: Vec<Arc<Blas>>,
|
||||||
|
|
||||||
/// Command buffers used by this submission, and the encoder that owns them.
|
/// Command buffers used by this submission, and the encoder that owns them.
|
||||||
///
|
///
|
||||||
/// [`wgpu_hal::Queue::submit`] requires the submitted command buffers to
|
/// [`wgpu_hal::Queue::submit`] requires the submitted command buffers to
|
||||||
@ -101,6 +105,23 @@ impl ActiveSubmission {
|
|||||||
|
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if this submission contains the given blas.
|
||||||
|
///
|
||||||
|
/// This only uses constant-time operations.
|
||||||
|
pub fn contains_blas(&self, blas: &Blas) -> bool {
|
||||||
|
for encoder in &self.encoders {
|
||||||
|
if encoder.trackers.blas_s.contains(blas) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if encoder.pending_blas_s.contains_key(&blas.tracker_index()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Error)]
|
#[derive(Clone, Debug, Error)]
|
||||||
@ -159,6 +180,10 @@ pub(crate) struct LifetimeTracker {
|
|||||||
/// queue submission still in flight.
|
/// queue submission still in flight.
|
||||||
ready_to_map: Vec<Arc<Buffer>>,
|
ready_to_map: Vec<Arc<Buffer>>,
|
||||||
|
|
||||||
|
/// BLASes the user has asked us to prepare to compact, and which are not used by any
|
||||||
|
/// queue submission still in flight.
|
||||||
|
ready_to_compact: Vec<Arc<Blas>>,
|
||||||
|
|
||||||
/// Queue "on_submitted_work_done" closures that were initiated for while there is no
|
/// Queue "on_submitted_work_done" closures that were initiated for while there is no
|
||||||
/// currently pending submissions. These cannot be immediately invoked as they
|
/// currently pending submissions. These cannot be immediately invoked as they
|
||||||
/// must happen _after_ all mapped buffer callbacks are mapped, so we defer them
|
/// must happen _after_ all mapped buffer callbacks are mapped, so we defer them
|
||||||
@ -171,6 +196,7 @@ impl LifetimeTracker {
|
|||||||
Self {
|
Self {
|
||||||
active: Vec::new(),
|
active: Vec::new(),
|
||||||
ready_to_map: Vec::new(),
|
ready_to_map: Vec::new(),
|
||||||
|
ready_to_compact: Vec::new(),
|
||||||
work_done_closures: SmallVec::new(),
|
work_done_closures: SmallVec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -185,6 +211,7 @@ impl LifetimeTracker {
|
|||||||
self.active.push(ActiveSubmission {
|
self.active.push(ActiveSubmission {
|
||||||
index,
|
index,
|
||||||
mapped: Vec::new(),
|
mapped: Vec::new(),
|
||||||
|
compact_read_back: Vec::new(),
|
||||||
encoders,
|
encoders,
|
||||||
work_done_closures: SmallVec::new(),
|
work_done_closures: SmallVec::new(),
|
||||||
});
|
});
|
||||||
@ -207,6 +234,19 @@ impl LifetimeTracker {
|
|||||||
maybe_submission_index
|
maybe_submission_index
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn prepare_compact(&mut self, blas: &Arc<Blas>) -> Option<SubmissionIndex> {
|
||||||
|
// Determine which BLASes are ready to map, and which must wait for the GPU.
|
||||||
|
let submission = self.active.iter_mut().rev().find(|a| a.contains_blas(blas));
|
||||||
|
|
||||||
|
let maybe_submission_index = submission.as_ref().map(|s| s.index);
|
||||||
|
|
||||||
|
submission
|
||||||
|
.map_or(&mut self.ready_to_compact, |a| &mut a.compact_read_back)
|
||||||
|
.push(blas.clone());
|
||||||
|
|
||||||
|
maybe_submission_index
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the submission index of the most recent submission that uses the
|
/// Returns the submission index of the most recent submission that uses the
|
||||||
/// given buffer.
|
/// given buffer.
|
||||||
pub fn get_buffer_latest_submission_index(&self, buffer: &Buffer) -> Option<SubmissionIndex> {
|
pub fn get_buffer_latest_submission_index(&self, buffer: &Buffer) -> Option<SubmissionIndex> {
|
||||||
@ -270,6 +310,7 @@ impl LifetimeTracker {
|
|||||||
let mut work_done_closures: SmallVec<_> = self.work_done_closures.drain(..).collect();
|
let mut work_done_closures: SmallVec<_> = self.work_done_closures.drain(..).collect();
|
||||||
for a in self.active.drain(..done_count) {
|
for a in self.active.drain(..done_count) {
|
||||||
self.ready_to_map.extend(a.mapped);
|
self.ready_to_map.extend(a.mapped);
|
||||||
|
self.ready_to_compact.extend(a.compact_read_back);
|
||||||
for encoder in a.encoders {
|
for encoder in a.encoders {
|
||||||
// This involves actually decrementing the ref count of all command buffer
|
// This involves actually decrementing the ref count of all command buffer
|
||||||
// resources, so can be _very_ expensive.
|
// resources, so can be _very_ expensive.
|
||||||
@ -343,4 +384,25 @@ impl LifetimeTracker {
|
|||||||
}
|
}
|
||||||
pending_callbacks
|
pending_callbacks
|
||||||
}
|
}
|
||||||
|
/// Read back compact sizes from the BLASes in `self.ready_to_compact`.
|
||||||
|
///
|
||||||
|
/// Return a list of mapping notifications to send.
|
||||||
|
///
|
||||||
|
/// See the documentation for [`LifetimeTracker`] for details.
|
||||||
|
#[must_use]
|
||||||
|
pub(crate) fn handle_compact_read_back(&mut self) -> Vec<BlasCompactReadyPendingClosure> {
|
||||||
|
if self.ready_to_compact.is_empty() {
|
||||||
|
return Vec::new();
|
||||||
|
}
|
||||||
|
let mut pending_callbacks: Vec<BlasCompactReadyPendingClosure> =
|
||||||
|
Vec::with_capacity(self.ready_to_compact.len());
|
||||||
|
|
||||||
|
for blas in self.ready_to_compact.drain(..) {
|
||||||
|
match blas.read_back_compact_size() {
|
||||||
|
Some(cb) => pending_callbacks.push(cb),
|
||||||
|
None => continue,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pending_callbacks
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,7 @@ use crate::{
|
|||||||
binding_model,
|
binding_model,
|
||||||
hub::Hub,
|
hub::Hub,
|
||||||
id::{BindGroupLayoutId, PipelineLayoutId},
|
id::{BindGroupLayoutId, PipelineLayoutId},
|
||||||
|
ray_tracing::BlasCompactReadyPendingClosure,
|
||||||
resource::{
|
resource::{
|
||||||
Buffer, BufferAccessError, BufferAccessResult, BufferMapOperation, Labeled,
|
Buffer, BufferAccessError, BufferAccessResult, BufferMapOperation, Labeled,
|
||||||
ResourceErrorIdent,
|
ResourceErrorIdent,
|
||||||
@ -156,6 +157,7 @@ pub type BufferMapPendingClosure = (BufferMapOperation, BufferAccessResult);
|
|||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct UserClosures {
|
pub struct UserClosures {
|
||||||
pub mappings: Vec<BufferMapPendingClosure>,
|
pub mappings: Vec<BufferMapPendingClosure>,
|
||||||
|
pub blas_compact_ready: Vec<BlasCompactReadyPendingClosure>,
|
||||||
pub submissions: SmallVec<[queue::SubmittedWorkDoneClosure; 1]>,
|
pub submissions: SmallVec<[queue::SubmittedWorkDoneClosure; 1]>,
|
||||||
pub device_lost_invocations: SmallVec<[DeviceLostInvocation; 1]>,
|
pub device_lost_invocations: SmallVec<[DeviceLostInvocation; 1]>,
|
||||||
}
|
}
|
||||||
@ -163,6 +165,7 @@ pub struct UserClosures {
|
|||||||
impl UserClosures {
|
impl UserClosures {
|
||||||
fn extend(&mut self, other: Self) {
|
fn extend(&mut self, other: Self) {
|
||||||
self.mappings.extend(other.mappings);
|
self.mappings.extend(other.mappings);
|
||||||
|
self.blas_compact_ready.extend(other.blas_compact_ready);
|
||||||
self.submissions.extend(other.submissions);
|
self.submissions.extend(other.submissions);
|
||||||
self.device_lost_invocations
|
self.device_lost_invocations
|
||||||
.extend(other.device_lost_invocations);
|
.extend(other.device_lost_invocations);
|
||||||
@ -179,6 +182,11 @@ impl UserClosures {
|
|||||||
callback(status);
|
callback(status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (mut operation, status) in self.blas_compact_ready {
|
||||||
|
if let Some(callback) = operation.take() {
|
||||||
|
callback(status);
|
||||||
|
}
|
||||||
|
}
|
||||||
for closure in self.submissions {
|
for closure in self.submissions {
|
||||||
closure();
|
closure();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
use alloc::{boxed::Box, sync::Arc, vec, vec::Vec};
|
use alloc::{boxed::Box, string::ToString, sync::Arc, vec, vec::Vec};
|
||||||
use core::{
|
use core::{
|
||||||
iter,
|
iter,
|
||||||
mem::{self, ManuallyDrop},
|
mem::{self, ManuallyDrop},
|
||||||
|
num::NonZeroU64,
|
||||||
ptr::NonNull,
|
ptr::NonNull,
|
||||||
sync::atomic::Ordering,
|
sync::atomic::Ordering,
|
||||||
};
|
};
|
||||||
|
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
use wgt::AccelerationStructureFlags;
|
||||||
|
|
||||||
use super::{life::LifetimeTracker, Device};
|
use super::{life::LifetimeTracker, Device};
|
||||||
use crate::device::resource::CommandIndices;
|
use crate::device::resource::CommandIndices;
|
||||||
#[cfg(feature = "trace")]
|
#[cfg(feature = "trace")]
|
||||||
use crate::device::trace::Action;
|
use crate::device::trace::Action;
|
||||||
use crate::scratch::ScratchBuffer;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
api_log,
|
api_log,
|
||||||
command::{
|
command::{
|
||||||
@ -25,16 +25,19 @@ use crate::{
|
|||||||
device::{DeviceError, WaitIdleError},
|
device::{DeviceError, WaitIdleError},
|
||||||
get_lowest_common_denom,
|
get_lowest_common_denom,
|
||||||
global::Global,
|
global::Global,
|
||||||
id::{self, QueueId},
|
id::{self, BlasId, QueueId},
|
||||||
init_tracker::{has_copy_partial_init_tracker_coverage, TextureInitRange},
|
init_tracker::{has_copy_partial_init_tracker_coverage, TextureInitRange},
|
||||||
lock::{rank, Mutex, MutexGuard, RwLockWriteGuard},
|
lock::{rank, Mutex, MutexGuard, RwLock, RwLockWriteGuard},
|
||||||
|
ray_tracing::{BlasCompactReadyPendingClosure, CompactBlasError},
|
||||||
resource::{
|
resource::{
|
||||||
Buffer, BufferAccessError, BufferMapState, DestroyedBuffer, DestroyedResourceError,
|
AccelerationStructure, Blas, BlasCompactState, Buffer, BufferAccessError, BufferMapState,
|
||||||
DestroyedTexture, Fallible, FlushedStagingBuffer, InvalidResourceError, Labeled,
|
DestroyedBuffer, DestroyedResourceError, DestroyedTexture, Fallible, FlushedStagingBuffer,
|
||||||
ParentDevice, ResourceErrorIdent, StagingBuffer, Texture, TextureInner, Trackable,
|
InvalidResourceError, Labeled, ParentDevice, ResourceErrorIdent, StagingBuffer, Texture,
|
||||||
|
TextureInner, Trackable, TrackingData,
|
||||||
},
|
},
|
||||||
resource_log,
|
resource_log,
|
||||||
snatch::SnatchGuard,
|
scratch::ScratchBuffer,
|
||||||
|
snatch::{SnatchGuard, Snatchable},
|
||||||
track::{self, Tracker, TrackerIndex},
|
track::{self, Tracker, TrackerIndex},
|
||||||
FastHashMap, SubmissionIndex,
|
FastHashMap, SubmissionIndex,
|
||||||
};
|
};
|
||||||
@ -116,16 +119,23 @@ impl Queue {
|
|||||||
) -> (
|
) -> (
|
||||||
SmallVec<[SubmittedWorkDoneClosure; 1]>,
|
SmallVec<[SubmittedWorkDoneClosure; 1]>,
|
||||||
Vec<super::BufferMapPendingClosure>,
|
Vec<super::BufferMapPendingClosure>,
|
||||||
|
Vec<BlasCompactReadyPendingClosure>,
|
||||||
bool,
|
bool,
|
||||||
) {
|
) {
|
||||||
let mut life_tracker = self.lock_life();
|
let mut life_tracker = self.lock_life();
|
||||||
let submission_closures = life_tracker.triage_submissions(submission_index);
|
let submission_closures = life_tracker.triage_submissions(submission_index);
|
||||||
|
|
||||||
let mapping_closures = life_tracker.handle_mapping(snatch_guard);
|
let mapping_closures = life_tracker.handle_mapping(snatch_guard);
|
||||||
|
let blas_closures = life_tracker.handle_compact_read_back();
|
||||||
|
|
||||||
let queue_empty = life_tracker.queue_empty();
|
let queue_empty = life_tracker.queue_empty();
|
||||||
|
|
||||||
(submission_closures, mapping_closures, queue_empty)
|
(
|
||||||
|
submission_closures,
|
||||||
|
mapping_closures,
|
||||||
|
blas_closures,
|
||||||
|
queue_empty,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,7 +230,7 @@ impl Drop for Queue {
|
|||||||
drop(fence);
|
drop(fence);
|
||||||
|
|
||||||
let snatch_guard = self.device.snatchable_lock.read();
|
let snatch_guard = self.device.snatchable_lock.read();
|
||||||
let (submission_closures, mapping_closures, queue_empty) =
|
let (submission_closures, mapping_closures, blas_compact_ready_closures, queue_empty) =
|
||||||
self.maintain(last_successful_submission_index, &snatch_guard);
|
self.maintain(last_successful_submission_index, &snatch_guard);
|
||||||
drop(snatch_guard);
|
drop(snatch_guard);
|
||||||
|
|
||||||
@ -228,6 +238,7 @@ impl Drop for Queue {
|
|||||||
|
|
||||||
let closures = crate::device::UserClosures {
|
let closures = crate::device::UserClosures {
|
||||||
mappings: mapping_closures,
|
mappings: mapping_closures,
|
||||||
|
blas_compact_ready: blas_compact_ready_closures,
|
||||||
submissions: submission_closures,
|
submissions: submission_closures,
|
||||||
device_lost_invocations: SmallVec::new(),
|
device_lost_invocations: SmallVec::new(),
|
||||||
};
|
};
|
||||||
@ -275,6 +286,8 @@ pub(crate) struct EncoderInFlight {
|
|||||||
pub(crate) pending_buffers: FastHashMap<TrackerIndex, Arc<Buffer>>,
|
pub(crate) pending_buffers: FastHashMap<TrackerIndex, Arc<Buffer>>,
|
||||||
/// These are the textures that have been tracked by `PendingWrites`.
|
/// These are the textures that have been tracked by `PendingWrites`.
|
||||||
pub(crate) pending_textures: FastHashMap<TrackerIndex, Arc<Texture>>,
|
pub(crate) pending_textures: FastHashMap<TrackerIndex, Arc<Texture>>,
|
||||||
|
/// These are the BLASes that have been tracked by `PendingWrites`.
|
||||||
|
pub(crate) pending_blas_s: FastHashMap<TrackerIndex, Arc<Blas>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A private command encoder for writes made directly on the device
|
/// A private command encoder for writes made directly on the device
|
||||||
@ -312,6 +325,7 @@ pub(crate) struct PendingWrites {
|
|||||||
temp_resources: Vec<TempResource>,
|
temp_resources: Vec<TempResource>,
|
||||||
dst_buffers: FastHashMap<TrackerIndex, Arc<Buffer>>,
|
dst_buffers: FastHashMap<TrackerIndex, Arc<Buffer>>,
|
||||||
dst_textures: FastHashMap<TrackerIndex, Arc<Texture>>,
|
dst_textures: FastHashMap<TrackerIndex, Arc<Texture>>,
|
||||||
|
copied_blas_s: FastHashMap<TrackerIndex, Arc<Blas>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PendingWrites {
|
impl PendingWrites {
|
||||||
@ -322,6 +336,7 @@ impl PendingWrites {
|
|||||||
temp_resources: Vec::new(),
|
temp_resources: Vec::new(),
|
||||||
dst_buffers: FastHashMap::default(),
|
dst_buffers: FastHashMap::default(),
|
||||||
dst_textures: FastHashMap::default(),
|
dst_textures: FastHashMap::default(),
|
||||||
|
copied_blas_s: FastHashMap::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -335,6 +350,11 @@ impl PendingWrites {
|
|||||||
.insert(texture.tracker_index(), texture.clone());
|
.insert(texture.tracker_index(), texture.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn insert_blas(&mut self, blas: &Arc<Blas>) {
|
||||||
|
self.copied_blas_s
|
||||||
|
.insert(blas.tracker_index(), blas.clone());
|
||||||
|
}
|
||||||
|
|
||||||
pub fn contains_buffer(&self, buffer: &Arc<Buffer>) -> bool {
|
pub fn contains_buffer(&self, buffer: &Arc<Buffer>) -> bool {
|
||||||
self.dst_buffers.contains_key(&buffer.tracker_index())
|
self.dst_buffers.contains_key(&buffer.tracker_index())
|
||||||
}
|
}
|
||||||
@ -361,6 +381,7 @@ impl PendingWrites {
|
|||||||
if self.is_recording {
|
if self.is_recording {
|
||||||
let pending_buffers = mem::take(&mut self.dst_buffers);
|
let pending_buffers = mem::take(&mut self.dst_buffers);
|
||||||
let pending_textures = mem::take(&mut self.dst_textures);
|
let pending_textures = mem::take(&mut self.dst_textures);
|
||||||
|
let pending_blas_s = mem::take(&mut self.copied_blas_s);
|
||||||
|
|
||||||
let cmd_buf = unsafe { self.command_encoder.end_encoding() }
|
let cmd_buf = unsafe { self.command_encoder.end_encoding() }
|
||||||
.map_err(|e| device.handle_hal_error(e))?;
|
.map_err(|e| device.handle_hal_error(e))?;
|
||||||
@ -385,11 +406,13 @@ impl PendingWrites {
|
|||||||
),
|
),
|
||||||
pending_buffers,
|
pending_buffers,
|
||||||
pending_textures,
|
pending_textures,
|
||||||
|
pending_blas_s,
|
||||||
};
|
};
|
||||||
Ok(Some(encoder))
|
Ok(Some(encoder))
|
||||||
} else {
|
} else {
|
||||||
self.dst_buffers.clear();
|
self.dst_buffers.clear();
|
||||||
self.dst_textures.clear();
|
self.dst_textures.clear();
|
||||||
|
self.copied_blas_s.clear();
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1228,6 +1251,7 @@ impl Queue {
|
|||||||
.indirect_draw_validation_resources,
|
.indirect_draw_validation_resources,
|
||||||
pending_buffers: FastHashMap::default(),
|
pending_buffers: FastHashMap::default(),
|
||||||
pending_textures: FastHashMap::default(),
|
pending_textures: FastHashMap::default(),
|
||||||
|
pending_blas_s: FastHashMap::default(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1381,6 +1405,84 @@ impl Queue {
|
|||||||
//TODO: flush pending writes
|
//TODO: flush pending writes
|
||||||
self.lock_life().add_work_done_closure(closure)
|
self.lock_life().add_work_done_closure(closure)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn compact_blas(&self, blas: &Arc<Blas>) -> Result<Arc<Blas>, CompactBlasError> {
|
||||||
|
profiling::scope!("Queue::compact_blas");
|
||||||
|
api_log!("Queue::compact_blas");
|
||||||
|
|
||||||
|
self.same_device_as(blas.as_ref())?;
|
||||||
|
|
||||||
|
let device = blas.device.clone();
|
||||||
|
|
||||||
|
let snatch_guard = device.snatchable_lock.read();
|
||||||
|
|
||||||
|
let BlasCompactState::Ready { size } = *blas.compacted_state.lock() else {
|
||||||
|
return Err(CompactBlasError::BlasNotReady);
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut size_info = blas.size_info;
|
||||||
|
size_info.acceleration_structure_size = size;
|
||||||
|
|
||||||
|
let mut pending_writes = self.pending_writes.lock();
|
||||||
|
let cmd_buf_raw = pending_writes.activate();
|
||||||
|
|
||||||
|
let raw = unsafe {
|
||||||
|
device
|
||||||
|
.raw()
|
||||||
|
.create_acceleration_structure(&hal::AccelerationStructureDescriptor {
|
||||||
|
label: None,
|
||||||
|
size: size_info.acceleration_structure_size,
|
||||||
|
format: hal::AccelerationStructureFormat::BottomLevel,
|
||||||
|
allow_compaction: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
.map_err(DeviceError::from_hal)?;
|
||||||
|
|
||||||
|
let src_raw = blas.try_raw(&snatch_guard)?;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
cmd_buf_raw.copy_acceleration_structure_to_acceleration_structure(
|
||||||
|
src_raw,
|
||||||
|
raw.as_ref(),
|
||||||
|
wgt::AccelerationStructureCopy::Compact,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
let handle = unsafe {
|
||||||
|
device
|
||||||
|
.raw()
|
||||||
|
.get_acceleration_structure_device_address(raw.as_ref())
|
||||||
|
};
|
||||||
|
|
||||||
|
drop(snatch_guard);
|
||||||
|
|
||||||
|
let mut command_indices_lock = device.command_indices.write();
|
||||||
|
command_indices_lock.next_acceleration_structure_build_command_index += 1;
|
||||||
|
let built_index =
|
||||||
|
NonZeroU64::new(command_indices_lock.next_acceleration_structure_build_command_index)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let new_blas = Arc::new(Blas {
|
||||||
|
raw: Snatchable::new(raw),
|
||||||
|
device: device.clone(),
|
||||||
|
size_info,
|
||||||
|
sizes: blas.sizes.clone(),
|
||||||
|
flags: blas.flags & !AccelerationStructureFlags::ALLOW_COMPACTION,
|
||||||
|
update_mode: blas.update_mode,
|
||||||
|
// Bypass the submit checks which update this because we don't submit this normally.
|
||||||
|
built_index: RwLock::new(rank::BLAS_BUILT_INDEX, Some(built_index)),
|
||||||
|
handle,
|
||||||
|
label: blas.label.clone() + " compacted",
|
||||||
|
tracking_data: TrackingData::new(blas.device.tracker_indices.blas_s.clone()),
|
||||||
|
compaction_buffer: None,
|
||||||
|
compacted_state: Mutex::new(rank::BLAS_COMPACTION_STATE, BlasCompactState::Compacted),
|
||||||
|
});
|
||||||
|
|
||||||
|
pending_writes.insert_blas(blas);
|
||||||
|
pending_writes.insert_blas(&new_blas);
|
||||||
|
|
||||||
|
Ok(new_blas)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Global {
|
impl Global {
|
||||||
@ -1535,6 +1637,57 @@ impl Global {
|
|||||||
let result = queue.on_submitted_work_done(closure);
|
let result = queue.on_submitted_work_done(closure);
|
||||||
result.unwrap_or(0) // '0' means no wait is necessary
|
result.unwrap_or(0) // '0' means no wait is necessary
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn queue_compact_blas(
|
||||||
|
&self,
|
||||||
|
queue_id: QueueId,
|
||||||
|
blas_id: BlasId,
|
||||||
|
id_in: Option<BlasId>,
|
||||||
|
) -> (BlasId, Option<u64>, Option<CompactBlasError>) {
|
||||||
|
api_log!("Queue::compact_blas {queue_id:?}, {blas_id:?}");
|
||||||
|
|
||||||
|
let fid = self.hub.blas_s.prepare(id_in);
|
||||||
|
|
||||||
|
let queue = self.hub.queues.get(queue_id);
|
||||||
|
let blas = self.hub.blas_s.get(blas_id);
|
||||||
|
let device = &queue.device;
|
||||||
|
|
||||||
|
// TODO: Tracing
|
||||||
|
|
||||||
|
let error = 'error: {
|
||||||
|
match device.require_features(
|
||||||
|
wgpu_types::Features::EXPERIMENTAL_RAY_TRACING_ACCELERATION_STRUCTURE,
|
||||||
|
) {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(err) => break 'error err.into(),
|
||||||
|
}
|
||||||
|
|
||||||
|
let blas = match blas.get() {
|
||||||
|
Ok(blas) => blas,
|
||||||
|
Err(err) => break 'error err.into(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let new_blas = match queue.compact_blas(&blas) {
|
||||||
|
Ok(blas) => blas,
|
||||||
|
Err(err) => break 'error err,
|
||||||
|
};
|
||||||
|
|
||||||
|
// We should have no more errors after this because we have marked the command encoder as successful.
|
||||||
|
let old_blas_size = blas.size_info.acceleration_structure_size;
|
||||||
|
let new_blas_size = new_blas.size_info.acceleration_structure_size;
|
||||||
|
let handle = new_blas.handle;
|
||||||
|
|
||||||
|
let id = fid.assign(Fallible::Valid(new_blas));
|
||||||
|
|
||||||
|
api_log!("CommandEncoder::compact_blas {blas_id:?} (size: {old_blas_size}) -> {id:?} (size: {new_blas_size})");
|
||||||
|
|
||||||
|
return (id, Some(handle), None);
|
||||||
|
};
|
||||||
|
|
||||||
|
let id = fid.assign(Fallible::Invalid(Arc::new(error.to_string())));
|
||||||
|
|
||||||
|
(id, None, Some(error))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_command_buffer(
|
fn validate_command_buffer(
|
||||||
|
|||||||
@ -1,19 +1,24 @@
|
|||||||
use alloc::{string::ToString as _, sync::Arc, vec::Vec};
|
use alloc::{string::ToString as _, sync::Arc, vec::Vec};
|
||||||
use core::mem::ManuallyDrop;
|
use core::mem::{size_of, ManuallyDrop};
|
||||||
|
|
||||||
use crate::api_log;
|
|
||||||
#[cfg(feature = "trace")]
|
#[cfg(feature = "trace")]
|
||||||
use crate::device::trace;
|
use crate::device::trace;
|
||||||
use crate::lock::rank;
|
use crate::device::DeviceError;
|
||||||
use crate::resource::{Fallible, TrackingData};
|
|
||||||
use crate::snatch::Snatchable;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
api_log,
|
||||||
device::Device,
|
device::Device,
|
||||||
global::Global,
|
global::Global,
|
||||||
id::{self, BlasId, TlasId},
|
id::{self, BlasId, TlasId},
|
||||||
lock::RwLock,
|
lock::RwLock,
|
||||||
|
lock::{rank, Mutex},
|
||||||
|
ray_tracing::BlasPrepareCompactError,
|
||||||
ray_tracing::{CreateBlasError, CreateTlasError},
|
ray_tracing::{CreateBlasError, CreateTlasError},
|
||||||
resource, LabelHelpers,
|
resource,
|
||||||
|
resource::{
|
||||||
|
BlasCompactCallback, BlasCompactState, Fallible, InvalidResourceError, TrackingData,
|
||||||
|
},
|
||||||
|
snatch::Snatchable,
|
||||||
|
LabelHelpers,
|
||||||
};
|
};
|
||||||
use hal::AccelerationStructureTriangleIndices;
|
use hal::AccelerationStructureTriangleIndices;
|
||||||
use wgt::Features;
|
use wgt::Features;
|
||||||
@ -105,12 +110,32 @@ impl Device {
|
|||||||
label: blas_desc.label.as_deref(),
|
label: blas_desc.label.as_deref(),
|
||||||
size: size_info.acceleration_structure_size,
|
size: size_info.acceleration_structure_size,
|
||||||
format: hal::AccelerationStructureFormat::BottomLevel,
|
format: hal::AccelerationStructureFormat::BottomLevel,
|
||||||
// change this once compaction is implemented in wgpu-core
|
allow_compaction: blas_desc
|
||||||
allow_compaction: false,
|
.flags
|
||||||
|
.contains(wgpu_types::AccelerationStructureFlags::ALLOW_COMPACTION),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
.map_err(|e| self.handle_hal_error_with_nonfatal_oom(e))?;
|
.map_err(|e| self.handle_hal_error_with_nonfatal_oom(e))?;
|
||||||
|
|
||||||
|
let compaction_buffer = if blas_desc
|
||||||
|
.flags
|
||||||
|
.contains(wgpu_types::AccelerationStructureFlags::ALLOW_COMPACTION)
|
||||||
|
{
|
||||||
|
Some(ManuallyDrop::new(unsafe {
|
||||||
|
self.raw()
|
||||||
|
.create_buffer(&hal::BufferDescriptor {
|
||||||
|
label: Some("(wgpu internal) compaction read-back buffer"),
|
||||||
|
size: size_of::<wgpu_types::BufferAddress>() as wgpu_types::BufferAddress,
|
||||||
|
usage: wgpu_types::BufferUses::ACCELERATION_STRUCTURE_QUERY
|
||||||
|
| wgpu_types::BufferUses::MAP_READ,
|
||||||
|
memory_flags: hal::MemoryFlags::PREFER_COHERENT,
|
||||||
|
})
|
||||||
|
.map_err(DeviceError::from_hal)?
|
||||||
|
}))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
let handle = unsafe {
|
let handle = unsafe {
|
||||||
self.raw()
|
self.raw()
|
||||||
.get_acceleration_structure_device_address(raw.as_ref())
|
.get_acceleration_structure_device_address(raw.as_ref())
|
||||||
@ -127,6 +152,8 @@ impl Device {
|
|||||||
label: blas_desc.label.to_string(),
|
label: blas_desc.label.to_string(),
|
||||||
built_index: RwLock::new(rank::BLAS_BUILT_INDEX, None),
|
built_index: RwLock::new(rank::BLAS_BUILT_INDEX, None),
|
||||||
tracking_data: TrackingData::new(self.tracker_indices.blas_s.clone()),
|
tracking_data: TrackingData::new(self.tracker_indices.blas_s.clone()),
|
||||||
|
compaction_buffer,
|
||||||
|
compacted_state: Mutex::new(rank::BLAS_COMPACTION_STATE, BlasCompactState::Idle),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -311,4 +338,43 @@ impl Global {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn blas_prepare_compact_async(
|
||||||
|
&self,
|
||||||
|
blas_id: BlasId,
|
||||||
|
callback: Option<BlasCompactCallback>,
|
||||||
|
) -> Result<crate::SubmissionIndex, BlasPrepareCompactError> {
|
||||||
|
profiling::scope!("Blas::prepare_compact_async");
|
||||||
|
api_log!("Blas::prepare_compact_async {blas_id:?}");
|
||||||
|
|
||||||
|
let hub = &self.hub;
|
||||||
|
|
||||||
|
let compact_result = match hub.blas_s.get(blas_id).get() {
|
||||||
|
Ok(blas) => blas.prepare_compact_async(callback),
|
||||||
|
Err(e) => Err((callback, e.into())),
|
||||||
|
};
|
||||||
|
|
||||||
|
match compact_result {
|
||||||
|
Ok(submission_index) => Ok(submission_index),
|
||||||
|
Err((mut callback, err)) => {
|
||||||
|
if let Some(callback) = callback.take() {
|
||||||
|
callback(Err(err.clone()));
|
||||||
|
}
|
||||||
|
Err(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ready_for_compaction(&self, blas_id: BlasId) -> Result<bool, InvalidResourceError> {
|
||||||
|
profiling::scope!("Blas::prepare_compact_async");
|
||||||
|
api_log!("Blas::prepare_compact_async {blas_id:?}");
|
||||||
|
|
||||||
|
let hub = &self.hub;
|
||||||
|
|
||||||
|
let blas = hub.blas_s.get(blas_id).get()?;
|
||||||
|
|
||||||
|
let lock = blas.compacted_state.lock();
|
||||||
|
|
||||||
|
Ok(matches!(*lock, BlasCompactState::Ready { .. }))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -541,6 +541,7 @@ impl Device {
|
|||||||
(
|
(
|
||||||
user_closures.submissions,
|
user_closures.submissions,
|
||||||
user_closures.mappings,
|
user_closures.mappings,
|
||||||
|
user_closures.blas_compact_ready,
|
||||||
queue_empty,
|
queue_empty,
|
||||||
) = queue_result
|
) = queue_result
|
||||||
};
|
};
|
||||||
|
|||||||
@ -148,6 +148,7 @@ define_lock_ranks! {
|
|||||||
rank TEXTURE_CLEAR_MODE "Texture::clear_mode" followed by { }
|
rank TEXTURE_CLEAR_MODE "Texture::clear_mode" followed by { }
|
||||||
rank TEXTURE_VIEWS "Texture::views" followed by { }
|
rank TEXTURE_VIEWS "Texture::views" followed by { }
|
||||||
rank BLAS_BUILT_INDEX "Blas::built_index" followed by { }
|
rank BLAS_BUILT_INDEX "Blas::built_index" followed by { }
|
||||||
|
rank BLAS_COMPACTION_STATE "Blas::compaction_size" followed by { }
|
||||||
rank TLAS_BUILT_INDEX "Tlas::built_index" followed by { }
|
rank TLAS_BUILT_INDEX "Tlas::built_index" followed by { }
|
||||||
rank TLAS_DEPENDENCIES "Tlas::dependencies" followed by { }
|
rank TLAS_DEPENDENCIES "Tlas::dependencies" followed by { }
|
||||||
rank BUFFER_POOL "BufferPool::buffers" followed by { }
|
rank BUFFER_POOL "BufferPool::buffers" followed by { }
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
// - lazy instance buffer allocation
|
// - lazy instance buffer allocation
|
||||||
// - maybe share scratch and instance staging buffer allocation
|
// - maybe share scratch and instance staging buffer allocation
|
||||||
// - partial instance buffer uploads (api surface already designed with this in mind)
|
// - partial instance buffer uploads (api surface already designed with this in mind)
|
||||||
|
// - Batch BLAS read-backs (if it shows up in performance).
|
||||||
// - ([non performance] extract function in build (rust function extraction with guards is a pain))
|
// - ([non performance] extract function in build (rust function extraction with guards is a pain))
|
||||||
|
|
||||||
use alloc::{boxed::Box, sync::Arc, vec::Vec};
|
use alloc::{boxed::Box, sync::Arc, vec::Vec};
|
||||||
@ -17,8 +18,8 @@ use crate::{
|
|||||||
device::{DeviceError, MissingFeatures},
|
device::{DeviceError, MissingFeatures},
|
||||||
id::{BlasId, BufferId, TlasId},
|
id::{BlasId, BufferId, TlasId},
|
||||||
resource::{
|
resource::{
|
||||||
Blas, DestroyedResourceError, InvalidResourceError, MissingBufferUsageError,
|
Blas, BlasCompactCallback, BlasPrepareCompactResult, DestroyedResourceError,
|
||||||
ResourceErrorIdent, Tlas,
|
InvalidResourceError, MissingBufferUsageError, ResourceErrorIdent, Tlas,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -117,6 +118,9 @@ pub enum BuildAccelerationStructureError {
|
|||||||
#[error("Blas {0:?} index formats are different, creation format: {1:?}, provided: {2:?}")]
|
#[error("Blas {0:?} index formats are different, creation format: {1:?}, provided: {2:?}")]
|
||||||
DifferentBlasIndexFormats(ResourceErrorIdent, Option<IndexFormat>, Option<IndexFormat>),
|
DifferentBlasIndexFormats(ResourceErrorIdent, Option<IndexFormat>, Option<IndexFormat>),
|
||||||
|
|
||||||
|
#[error("Blas {0:?} is compacted and so cannot be built")]
|
||||||
|
CompactedBlas(ResourceErrorIdent),
|
||||||
|
|
||||||
#[error("Blas {0:?} build sizes require index buffer but none was provided")]
|
#[error("Blas {0:?} build sizes require index buffer but none was provided")]
|
||||||
MissingIndexBuffer(ResourceErrorIdent),
|
MissingIndexBuffer(ResourceErrorIdent),
|
||||||
|
|
||||||
@ -259,3 +263,42 @@ pub struct TraceTlasPackage {
|
|||||||
pub instances: Vec<Option<TraceTlasInstance>>,
|
pub instances: Vec<Option<TraceTlasInstance>>,
|
||||||
pub lowest_unmodified: u32,
|
pub lowest_unmodified: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Error)]
|
||||||
|
pub enum BlasPrepareCompactError {
|
||||||
|
#[error(transparent)]
|
||||||
|
Device(#[from] DeviceError),
|
||||||
|
#[error(transparent)]
|
||||||
|
InvalidResource(#[from] InvalidResourceError),
|
||||||
|
#[error("Compaction is already being prepared")]
|
||||||
|
CompactionPreparingAlready,
|
||||||
|
#[error("Cannot compact an already compacted BLAS")]
|
||||||
|
DoubleCompaction,
|
||||||
|
#[error("BLAS is not yet built")]
|
||||||
|
NotBuilt,
|
||||||
|
#[error("BLAS does not support compaction (is AccelerationStructureFlags::ALLOW_COMPACTION missing?)")]
|
||||||
|
CompactionUnsupported,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Error)]
|
||||||
|
pub enum CompactBlasError {
|
||||||
|
#[error(transparent)]
|
||||||
|
Encoder(#[from] EncoderStateError),
|
||||||
|
|
||||||
|
#[error(transparent)]
|
||||||
|
Device(#[from] DeviceError),
|
||||||
|
|
||||||
|
#[error(transparent)]
|
||||||
|
InvalidResource(#[from] InvalidResourceError),
|
||||||
|
|
||||||
|
#[error(transparent)]
|
||||||
|
DestroyedResource(#[from] DestroyedResourceError),
|
||||||
|
|
||||||
|
#[error(transparent)]
|
||||||
|
MissingFeatures(#[from] MissingFeatures),
|
||||||
|
|
||||||
|
#[error("BLAS was not prepared for compaction")]
|
||||||
|
BlasNotReady,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type BlasCompactReadyPendingClosure = (Option<BlasCompactCallback>, BlasPrepareCompactResult);
|
||||||
|
|||||||
@ -2,12 +2,11 @@ use alloc::{borrow::Cow, borrow::ToOwned as _, boxed::Box, string::String, sync:
|
|||||||
use core::{
|
use core::{
|
||||||
borrow::Borrow,
|
borrow::Borrow,
|
||||||
fmt,
|
fmt,
|
||||||
mem::{self, ManuallyDrop},
|
mem::{self, size_of, ManuallyDrop},
|
||||||
num::NonZeroU64,
|
num::NonZeroU64,
|
||||||
ops::Range,
|
ops::Range,
|
||||||
ptr::NonNull,
|
ptr::NonNull,
|
||||||
};
|
};
|
||||||
|
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use wgt::TextureSelector;
|
use wgt::TextureSelector;
|
||||||
@ -28,6 +27,7 @@ use crate::{
|
|||||||
},
|
},
|
||||||
init_tracker::{BufferInitTracker, TextureInitTracker},
|
init_tracker::{BufferInitTracker, TextureInitTracker},
|
||||||
lock::{rank, Mutex, RwLock},
|
lock::{rank, Mutex, RwLock},
|
||||||
|
ray_tracing::{BlasCompactReadyPendingClosure, BlasPrepareCompactError},
|
||||||
resource_log,
|
resource_log,
|
||||||
snatch::{SnatchGuard, Snatchable},
|
snatch::{SnatchGuard, Snatchable},
|
||||||
timestamp_normalization::TimestampNormalizationBindGroup,
|
timestamp_normalization::TimestampNormalizationBindGroup,
|
||||||
@ -1974,6 +1974,45 @@ pub(crate) trait AccelerationStructure: Trackable {
|
|||||||
) -> Result<&'a dyn hal::DynAccelerationStructure, DestroyedResourceError>;
|
) -> Result<&'a dyn hal::DynAccelerationStructure, DestroyedResourceError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type BlasPrepareCompactResult = Result<(), BlasPrepareCompactError>;
|
||||||
|
|
||||||
|
#[cfg(send_sync)]
|
||||||
|
pub type BlasCompactCallback = Box<dyn FnOnce(BlasPrepareCompactResult) + Send + 'static>;
|
||||||
|
#[cfg(not(send_sync))]
|
||||||
|
pub type BlasCompactCallback = Box<dyn FnOnce(BlasPrepareCompactResult) + 'static>;
|
||||||
|
|
||||||
|
pub(crate) struct BlasPendingCompact {
|
||||||
|
pub(crate) op: Option<BlasCompactCallback>,
|
||||||
|
// hold the parent alive while the mapping is active
|
||||||
|
pub(crate) _parent_blas: Arc<Blas>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for BlasPendingCompact {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("BlasPendingCompact")
|
||||||
|
.field("op", &())
|
||||||
|
.field("_parent_blas", &self._parent_blas)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) enum BlasCompactState {
|
||||||
|
/// Created from a compact operation.
|
||||||
|
Compacted,
|
||||||
|
/// Waiting for GPU to be done before mapping to get compacted size
|
||||||
|
Waiting(BlasPendingCompact),
|
||||||
|
/// Ready to be compacted
|
||||||
|
Ready { size: wgt::BufferAddress },
|
||||||
|
/// Ready to prepare to compact.
|
||||||
|
Idle,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(send_sync)]
|
||||||
|
unsafe impl Send for BlasCompactState {}
|
||||||
|
#[cfg(send_sync)]
|
||||||
|
unsafe impl Sync for BlasCompactState {}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Blas {
|
pub struct Blas {
|
||||||
pub(crate) raw: Snatchable<Box<dyn hal::DynAccelerationStructure>>,
|
pub(crate) raw: Snatchable<Box<dyn hal::DynAccelerationStructure>>,
|
||||||
@ -1987,17 +2026,26 @@ pub struct Blas {
|
|||||||
/// The `label` from the descriptor used to create the resource.
|
/// The `label` from the descriptor used to create the resource.
|
||||||
pub(crate) label: String,
|
pub(crate) label: String,
|
||||||
pub(crate) tracking_data: TrackingData,
|
pub(crate) tracking_data: TrackingData,
|
||||||
|
pub(crate) compaction_buffer: Option<ManuallyDrop<Box<dyn hal::DynBuffer>>>,
|
||||||
|
pub(crate) compacted_state: Mutex<BlasCompactState>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for Blas {
|
impl Drop for Blas {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
resource_log!("Destroy raw {}", self.error_ident());
|
resource_log!("Destroy raw {}", self.error_ident());
|
||||||
// SAFETY: We are in the Drop impl, and we don't use self.raw anymore after this point.
|
// SAFETY: We are in the Drop impl, and we don't use self.raw or self.compaction_buffer anymore after this point.
|
||||||
if let Some(raw) = self.raw.take() {
|
if let Some(raw) = self.raw.take() {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.device.raw().destroy_acceleration_structure(raw);
|
self.device.raw().destroy_acceleration_structure(raw);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if let Some(mut raw) = self.compaction_buffer.take() {
|
||||||
|
unsafe {
|
||||||
|
self.device
|
||||||
|
.raw()
|
||||||
|
.destroy_buffer(ManuallyDrop::take(&mut raw))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2013,6 +2061,107 @@ impl AccelerationStructure for Blas {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Blas {
|
||||||
|
pub(crate) fn prepare_compact_async(
|
||||||
|
self: &Arc<Self>,
|
||||||
|
op: Option<BlasCompactCallback>,
|
||||||
|
) -> Result<SubmissionIndex, (Option<BlasCompactCallback>, BlasPrepareCompactError)> {
|
||||||
|
let device = &self.device;
|
||||||
|
if let Err(e) = device.check_is_valid() {
|
||||||
|
return Err((op, e.into()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.built_index.read().is_none() {
|
||||||
|
return Err((op, BlasPrepareCompactError::NotBuilt));
|
||||||
|
}
|
||||||
|
|
||||||
|
if !self
|
||||||
|
.flags
|
||||||
|
.contains(wgt::AccelerationStructureFlags::ALLOW_COMPACTION)
|
||||||
|
{
|
||||||
|
return Err((op, BlasPrepareCompactError::CompactionUnsupported));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut state = self.compacted_state.lock();
|
||||||
|
*state = match *state {
|
||||||
|
BlasCompactState::Compacted => {
|
||||||
|
return Err((op, BlasPrepareCompactError::DoubleCompaction))
|
||||||
|
}
|
||||||
|
BlasCompactState::Waiting(_) => {
|
||||||
|
return Err((op, BlasPrepareCompactError::CompactionPreparingAlready))
|
||||||
|
}
|
||||||
|
BlasCompactState::Ready { .. } => {
|
||||||
|
return Err((op, BlasPrepareCompactError::CompactionPreparingAlready))
|
||||||
|
}
|
||||||
|
BlasCompactState::Idle => BlasCompactState::Waiting(BlasPendingCompact {
|
||||||
|
op,
|
||||||
|
_parent_blas: self.clone(),
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
let submit_index = if let Some(queue) = device.get_queue() {
|
||||||
|
queue.lock_life().prepare_compact(self).unwrap_or(0) // '0' means no wait is necessary
|
||||||
|
} else {
|
||||||
|
// We can safely unwrap below since we just set the `compacted_state` to `BlasCompactState::Waiting`.
|
||||||
|
let (mut callback, status) = self.read_back_compact_size().unwrap();
|
||||||
|
if let Some(callback) = callback.take() {
|
||||||
|
callback(status);
|
||||||
|
}
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(submit_index)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This function returns [`None`] only if [`Self::compacted_state`] is not [`BlasCompactState::Waiting`].
|
||||||
|
#[must_use]
|
||||||
|
pub(crate) fn read_back_compact_size(&self) -> Option<BlasCompactReadyPendingClosure> {
|
||||||
|
let mut state = self.compacted_state.lock();
|
||||||
|
let pending_compact = match mem::replace(&mut *state, BlasCompactState::Idle) {
|
||||||
|
BlasCompactState::Waiting(pending_mapping) => pending_mapping,
|
||||||
|
// Compaction cancelled e.g. by rebuild
|
||||||
|
BlasCompactState::Idle => return None,
|
||||||
|
BlasCompactState::Ready { .. } => {
|
||||||
|
unreachable!("This should be validated out by `prepare_for_compaction`")
|
||||||
|
}
|
||||||
|
_ => panic!("No pending mapping."),
|
||||||
|
};
|
||||||
|
let status = {
|
||||||
|
let compaction_buffer = self.compaction_buffer.as_ref().unwrap().as_ref();
|
||||||
|
unsafe {
|
||||||
|
let map_res = self.device.raw().map_buffer(
|
||||||
|
compaction_buffer,
|
||||||
|
0..size_of::<wgpu_types::BufferAddress>() as wgt::BufferAddress,
|
||||||
|
);
|
||||||
|
match map_res {
|
||||||
|
Ok(mapping) => {
|
||||||
|
if !mapping.is_coherent {
|
||||||
|
// Clippy complains about this because it might not be intended, but
|
||||||
|
// this is intentional.
|
||||||
|
#[expect(clippy::single_range_in_vec_init)]
|
||||||
|
self.device.raw().flush_mapped_ranges(
|
||||||
|
compaction_buffer,
|
||||||
|
&[0..size_of::<wgpu_types::BufferAddress>() as wgt::BufferAddress],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let size = core::ptr::read_unaligned(
|
||||||
|
mapping.ptr.as_ptr().cast::<wgt::BufferAddress>(),
|
||||||
|
);
|
||||||
|
self.device.raw().unmap_buffer(compaction_buffer);
|
||||||
|
if self.size_info.acceleration_structure_size != 0 {
|
||||||
|
debug_assert_ne!(size, 0);
|
||||||
|
}
|
||||||
|
*state = BlasCompactState::Ready { size };
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Err(err) => Err(BlasPrepareCompactError::from(DeviceError::from_hal(err))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Some((pending_compact.op, status))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
crate::impl_resource_type!(Blas);
|
crate::impl_resource_type!(Blas);
|
||||||
crate::impl_labeled!(Blas);
|
crate::impl_labeled!(Blas);
|
||||||
crate::impl_parent_device!(Blas);
|
crate::impl_parent_device!(Blas);
|
||||||
|
|||||||
59
wgpu-core/src/track/blas.rs
Normal file
59
wgpu-core/src/track/blas.rs
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
use crate::{
|
||||||
|
resource::{Blas, Trackable},
|
||||||
|
track::metadata::ResourceMetadata,
|
||||||
|
};
|
||||||
|
use alloc::sync::Arc;
|
||||||
|
|
||||||
|
/// A tracker that holds tracks BLASes.
|
||||||
|
///
|
||||||
|
/// This is mostly a safe shell around [`ResourceMetadata`]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) struct BlasTracker {
|
||||||
|
metadata: ResourceMetadata<Arc<Blas>>,
|
||||||
|
size: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlasTracker {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
metadata: ResourceMetadata::new(),
|
||||||
|
size: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Inserts a single resource into the resource tracker.
|
||||||
|
///
|
||||||
|
/// Returns a reference to the newly inserted resource.
|
||||||
|
/// (This allows avoiding a clone/reference count increase in many cases.)
|
||||||
|
pub fn insert_single(&mut self, resource: Arc<Blas>) -> &Arc<Blas> {
|
||||||
|
let index = resource.tracker_index().as_usize();
|
||||||
|
self.allow_index(index);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
// # SAFETY: we just allowed this resource, which makes the metadata object larger if
|
||||||
|
// it's not in bounds
|
||||||
|
self.metadata.insert(index, resource)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the size of all the vectors inside the tracker.
|
||||||
|
///
|
||||||
|
/// Must be called with the highest possible Texture ID before
|
||||||
|
/// all unsafe functions are called.
|
||||||
|
pub fn set_size(&mut self, size: usize) {
|
||||||
|
self.size = size;
|
||||||
|
self.metadata.set_size(size)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extend the vectors to let the given index be valid.
|
||||||
|
fn allow_index(&mut self, index: usize) {
|
||||||
|
if index >= self.size {
|
||||||
|
self.set_size(index + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if the tracker owns the given texture.
|
||||||
|
pub fn contains(&self, blas: &Blas) -> bool {
|
||||||
|
self.metadata.contains(blas.tracker_index().as_usize())
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -95,6 +95,7 @@ Device <- CommandBuffer = insert(device.start, device.end, buffer.start, buffer.
|
|||||||
[`UsageScope`]: https://gpuweb.github.io/gpuweb/#programming-model-synchronization
|
[`UsageScope`]: https://gpuweb.github.io/gpuweb/#programming-model-synchronization
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
mod blas;
|
||||||
mod buffer;
|
mod buffer;
|
||||||
mod metadata;
|
mod metadata;
|
||||||
mod range;
|
mod range;
|
||||||
@ -107,6 +108,7 @@ use crate::{
|
|||||||
pipeline,
|
pipeline,
|
||||||
resource::{self, Labeled, ResourceErrorIdent},
|
resource::{self, Labeled, ResourceErrorIdent},
|
||||||
snatch::SnatchGuard,
|
snatch::SnatchGuard,
|
||||||
|
track::blas::BlasTracker,
|
||||||
};
|
};
|
||||||
|
|
||||||
use alloc::{sync::Arc, vec::Vec};
|
use alloc::{sync::Arc, vec::Vec};
|
||||||
@ -601,7 +603,7 @@ impl DeviceTracker {
|
|||||||
pub(crate) struct Tracker {
|
pub(crate) struct Tracker {
|
||||||
pub buffers: BufferTracker,
|
pub buffers: BufferTracker,
|
||||||
pub textures: TextureTracker,
|
pub textures: TextureTracker,
|
||||||
pub blas_s: StatelessTracker<resource::Blas>,
|
pub blas_s: BlasTracker,
|
||||||
pub tlas_s: StatelessTracker<resource::Tlas>,
|
pub tlas_s: StatelessTracker<resource::Tlas>,
|
||||||
pub views: StatelessTracker<resource::TextureView>,
|
pub views: StatelessTracker<resource::TextureView>,
|
||||||
pub bind_groups: StatelessTracker<binding_model::BindGroup>,
|
pub bind_groups: StatelessTracker<binding_model::BindGroup>,
|
||||||
@ -616,7 +618,7 @@ impl Tracker {
|
|||||||
Self {
|
Self {
|
||||||
buffers: BufferTracker::new(),
|
buffers: BufferTracker::new(),
|
||||||
textures: TextureTracker::new(),
|
textures: TextureTracker::new(),
|
||||||
blas_s: StatelessTracker::new(),
|
blas_s: BlasTracker::new(),
|
||||||
tlas_s: StatelessTracker::new(),
|
tlas_s: StatelessTracker::new(),
|
||||||
views: StatelessTracker::new(),
|
views: StatelessTracker::new(),
|
||||||
bind_groups: StatelessTracker::new(),
|
bind_groups: StatelessTracker::new(),
|
||||||
|
|||||||
@ -7565,8 +7565,8 @@ bitflags::bitflags!(
|
|||||||
/// Allow for incremental updates (no change in size), currently this is unimplemented
|
/// Allow for incremental updates (no change in size), currently this is unimplemented
|
||||||
/// and will build as normal (this is fine, update vs build should be unnoticeable)
|
/// and will build as normal (this is fine, update vs build should be unnoticeable)
|
||||||
const ALLOW_UPDATE = 1 << 0;
|
const ALLOW_UPDATE = 1 << 0;
|
||||||
/// Allow the acceleration structure to be compacted in a copy operation, the function
|
/// Allow the acceleration structure to be compacted in a copy operation
|
||||||
/// to compact is not currently implemented.
|
/// (`Blas::prepare_for_compaction`, `CommandEncoder::compact_blas`).
|
||||||
const ALLOW_COMPACTION = 1 << 1;
|
const ALLOW_COMPACTION = 1 << 1;
|
||||||
/// Optimize for fast ray tracing performance, recommended if the geometry is unlikely
|
/// Optimize for fast ray tracing performance, recommended if the geometry is unlikely
|
||||||
/// to change (e.g. in a game: non-interactive scene geometry)
|
/// to change (e.g. in a game: non-interactive scene geometry)
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
use alloc::{boxed::Box, vec::Vec};
|
use alloc::{boxed::Box, vec::Vec};
|
||||||
|
|
||||||
use wgt::WasmNotSendSync;
|
use wgt::{WasmNotSend, WasmNotSendSync};
|
||||||
|
|
||||||
use crate::dispatch;
|
use crate::dispatch;
|
||||||
use crate::{Buffer, Label};
|
use crate::{Buffer, Label};
|
||||||
@ -216,3 +216,49 @@ pub struct ContextBlasBuildEntry<'a> {
|
|||||||
#[expect(dead_code)]
|
#[expect(dead_code)]
|
||||||
pub(crate) geometries: ContextBlasGeometries<'a>,
|
pub(crate) geometries: ContextBlasGeometries<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Error occurred when trying to asynchronously prepare a blas for compaction.
|
||||||
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||||
|
pub struct BlasAsyncError;
|
||||||
|
static_assertions::assert_impl_all!(BlasAsyncError: Send, Sync);
|
||||||
|
|
||||||
|
impl core::fmt::Display for BlasAsyncError {
|
||||||
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"Error occurred when trying to asynchronously prepare a blas for compaction"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl core::error::Error for BlasAsyncError {}
|
||||||
|
|
||||||
|
impl Blas {
|
||||||
|
/// Asynchronously prepares this BLAS for compaction. The callback is called once all builds
|
||||||
|
/// using this BLAS are finished and the BLAS is compactable. This can be checked using
|
||||||
|
/// [`Blas::ready_for_compaction`]. Rebuilding this BLAS will reset its compacted state, and it
|
||||||
|
/// will need to be prepared again.
|
||||||
|
///
|
||||||
|
/// ### Interaction with other functions
|
||||||
|
/// On native, `queue.submit(..)` and polling devices (that is calling `instance.poll_all` or
|
||||||
|
/// `device.poll`) with [`PollType::Poll`] may call the callback. On native, polling devices with
|
||||||
|
/// [`PollType::Wait`] (or [`PollType::WaitForSubmissionIndex`] with a submission index greater
|
||||||
|
/// than the last submit the BLAS was used in) will guarantee callback is called.
|
||||||
|
///
|
||||||
|
/// [`PollType::Poll`]: wgpu_types::PollType::Poll
|
||||||
|
/// [`PollType::Wait`]: wgpu_types::PollType::Wait
|
||||||
|
/// [`PollType::WaitForSubmissionIndex`]: wgpu_types::PollType::WaitForSubmissionIndex
|
||||||
|
pub fn prepare_compaction_async(
|
||||||
|
&self,
|
||||||
|
callback: impl FnOnce(Result<(), BlasAsyncError>) + WasmNotSend + 'static,
|
||||||
|
) {
|
||||||
|
self.inner.prepare_compact_async(Box::new(callback));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks whether this BLAS is ready for compaction. The returned value is `true` if
|
||||||
|
/// [`Blas::prepare_compaction_async`]'s callback was called with a non-error value, otherwise
|
||||||
|
/// this is `false`.
|
||||||
|
pub fn ready_for_compaction(&self) -> bool {
|
||||||
|
self.inner.ready_for_compaction()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -301,4 +301,17 @@ impl Queue {
|
|||||||
hal_queue_callback(None)
|
hal_queue_callback(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Compact a BLAS, it must have had [`Blas::prepare_compaction_async`] called on it and had the
|
||||||
|
/// callback provided called.
|
||||||
|
///
|
||||||
|
/// The returned BLAS is more restricted than a normal BLAS because it may not be rebuilt or
|
||||||
|
/// compacted.
|
||||||
|
pub fn compact_blas(&self, blas: &Blas) -> Blas {
|
||||||
|
let (handle, dispatch) = self.inner.compact_blas(&blas.inner);
|
||||||
|
Blas {
|
||||||
|
handle,
|
||||||
|
inner: dispatch,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,7 +27,10 @@ use wgt::Backends;
|
|||||||
use js_sys::Promise;
|
use js_sys::Promise;
|
||||||
use wasm_bindgen::{prelude::*, JsCast};
|
use wasm_bindgen::{prelude::*, JsCast};
|
||||||
|
|
||||||
use crate::{dispatch, Blas, SurfaceTargetUnsafe, Tlas};
|
use crate::{
|
||||||
|
dispatch::{self, BlasCompactCallback},
|
||||||
|
Blas, SurfaceTargetUnsafe, Tlas,
|
||||||
|
};
|
||||||
|
|
||||||
use defined_non_null_js_value::DefinedNonNullJsValue;
|
use defined_non_null_js_value::DefinedNonNullJsValue;
|
||||||
|
|
||||||
@ -2581,6 +2584,13 @@ impl dispatch::QueueInterface for WebQueue {
|
|||||||
fn on_submitted_work_done(&self, _callback: dispatch::BoxSubmittedWorkDoneCallback) {
|
fn on_submitted_work_done(&self, _callback: dispatch::BoxSubmittedWorkDoneCallback) {
|
||||||
unimplemented!("on_submitted_work_done is not yet implemented");
|
unimplemented!("on_submitted_work_done is not yet implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn compact_blas(
|
||||||
|
&self,
|
||||||
|
_blas: &dispatch::DispatchBlas,
|
||||||
|
) -> (Option<u64>, dispatch::DispatchBlas) {
|
||||||
|
unimplemented!("Raytracing not implemented for web")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
impl Drop for WebQueue {
|
impl Drop for WebQueue {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
@ -2727,7 +2737,14 @@ impl Drop for WebTexture {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl dispatch::BlasInterface for WebBlas {}
|
impl dispatch::BlasInterface for WebBlas {
|
||||||
|
fn prepare_compact_async(&self, _callback: BlasCompactCallback) {
|
||||||
|
unimplemented!("Raytracing not implemented for web")
|
||||||
|
}
|
||||||
|
fn ready_for_compaction(&self) -> bool {
|
||||||
|
unimplemented!("Raytracing not implemented for web")
|
||||||
|
}
|
||||||
|
}
|
||||||
impl Drop for WebBlas {
|
impl Drop for WebBlas {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
// no-op
|
// no-op
|
||||||
|
|||||||
@ -11,13 +11,16 @@ use core::{error::Error, fmt, future::ready, ops::Range, pin::Pin, ptr::NonNull,
|
|||||||
|
|
||||||
use arrayvec::ArrayVec;
|
use arrayvec::ArrayVec;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use wgc::{command::bundle_ffi::*, error::ContextErrorSource, pipeline::CreateShaderModuleError};
|
use wgc::{
|
||||||
|
command::bundle_ffi::*, error::ContextErrorSource, pipeline::CreateShaderModuleError,
|
||||||
|
resource::BlasPrepareCompactResult,
|
||||||
|
};
|
||||||
use wgt::WasmNotSendSync;
|
use wgt::WasmNotSendSync;
|
||||||
|
|
||||||
use crate::util::Mutex;
|
use crate::util::Mutex;
|
||||||
use crate::{
|
use crate::{
|
||||||
api,
|
api,
|
||||||
dispatch::{self, BufferMappedRangeInterface},
|
dispatch::{self, BlasCompactCallback, BufferMappedRangeInterface},
|
||||||
BindingResource, Blas, BufferBinding, BufferDescriptor, CompilationInfo, CompilationMessage,
|
BindingResource, Blas, BufferBinding, BufferDescriptor, CompilationInfo, CompilationMessage,
|
||||||
CompilationMessageType, ErrorSource, Features, Label, LoadOp, MapMode, Operations,
|
CompilationMessageType, ErrorSource, Features, Label, LoadOp, MapMode, Operations,
|
||||||
ShaderSource, SurfaceTargetUnsafe, TextureDescriptor, Tlas,
|
ShaderSource, SurfaceTargetUnsafe, TextureDescriptor, Tlas,
|
||||||
@ -644,7 +647,7 @@ pub struct CoreCommandEncoder {
|
|||||||
pub struct CoreBlas {
|
pub struct CoreBlas {
|
||||||
pub(crate) context: ContextWgpuCore,
|
pub(crate) context: ContextWgpuCore,
|
||||||
id: wgc::id::BlasId,
|
id: wgc::id::BlasId,
|
||||||
// error_sink: ErrorSink,
|
error_sink: ErrorSink,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -1547,7 +1550,7 @@ impl dispatch::DeviceInterface for CoreDevice {
|
|||||||
CoreBlas {
|
CoreBlas {
|
||||||
context: self.context.clone(),
|
context: self.context.clone(),
|
||||||
id,
|
id,
|
||||||
// error_sink: Arc::clone(&self.error_sink),
|
error_sink: Arc::clone(&self.error_sink),
|
||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
)
|
)
|
||||||
@ -1931,6 +1934,27 @@ impl dispatch::QueueInterface for CoreQueue {
|
|||||||
.0
|
.0
|
||||||
.queue_on_submitted_work_done(self.id, callback);
|
.queue_on_submitted_work_done(self.id, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn compact_blas(&self, blas: &dispatch::DispatchBlas) -> (Option<u64>, dispatch::DispatchBlas) {
|
||||||
|
let (id, handle, error) =
|
||||||
|
self.context
|
||||||
|
.0
|
||||||
|
.queue_compact_blas(self.id, blas.as_core().id, None);
|
||||||
|
|
||||||
|
if let Some(cause) = error {
|
||||||
|
self.context
|
||||||
|
.handle_error_nolabel(&self.error_sink, cause, "Queue::compact_blas");
|
||||||
|
}
|
||||||
|
(
|
||||||
|
handle,
|
||||||
|
CoreBlas {
|
||||||
|
context: self.context.clone(),
|
||||||
|
id,
|
||||||
|
error_sink: Arc::clone(&self.error_sink),
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for CoreQueue {
|
impl Drop for CoreQueue {
|
||||||
@ -2102,7 +2126,39 @@ impl Drop for CoreTexture {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl dispatch::BlasInterface for CoreBlas {}
|
impl dispatch::BlasInterface for CoreBlas {
|
||||||
|
fn prepare_compact_async(&self, callback: BlasCompactCallback) {
|
||||||
|
let callback: Option<wgc::resource::BlasCompactCallback> =
|
||||||
|
Some(Box::new(|status: BlasPrepareCompactResult| {
|
||||||
|
let res = status.map_err(|_| crate::BlasAsyncError);
|
||||||
|
callback(res);
|
||||||
|
}));
|
||||||
|
|
||||||
|
match self.context.0.blas_prepare_compact_async(self.id, callback) {
|
||||||
|
Ok(_) => (),
|
||||||
|
Err(cause) => self.context.handle_error_nolabel(
|
||||||
|
&self.error_sink,
|
||||||
|
cause,
|
||||||
|
"Blas::prepare_compact_async",
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ready_for_compaction(&self) -> bool {
|
||||||
|
match self.context.0.ready_for_compaction(self.id) {
|
||||||
|
Ok(ready) => ready,
|
||||||
|
Err(cause) => {
|
||||||
|
self.context.handle_error_nolabel(
|
||||||
|
&self.error_sink,
|
||||||
|
cause,
|
||||||
|
"Blas::ready_for_compaction",
|
||||||
|
);
|
||||||
|
// A BLAS is definitely not ready for compaction if it's not valid
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Drop for CoreBlas {
|
impl Drop for CoreBlas {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
|
|||||||
@ -54,6 +54,11 @@ pub type BufferMapCallback = Box<dyn FnOnce(Result<(), crate::BufferAsyncError>)
|
|||||||
#[cfg(not(send_sync))]
|
#[cfg(not(send_sync))]
|
||||||
pub type BufferMapCallback = Box<dyn FnOnce(Result<(), crate::BufferAsyncError>) + 'static>;
|
pub type BufferMapCallback = Box<dyn FnOnce(Result<(), crate::BufferAsyncError>) + 'static>;
|
||||||
|
|
||||||
|
#[cfg(send_sync)]
|
||||||
|
pub type BlasCompactCallback = Box<dyn FnOnce(Result<(), crate::BlasAsyncError>) + Send + 'static>;
|
||||||
|
#[cfg(not(send_sync))]
|
||||||
|
pub type BlasCompactCallback = Box<dyn FnOnce(Result<(), crate::BlasAsyncError>) + 'static>;
|
||||||
|
|
||||||
// remove when rust 1.86
|
// remove when rust 1.86
|
||||||
#[cfg_attr(not(custom), expect(dead_code))]
|
#[cfg_attr(not(custom), expect(dead_code))]
|
||||||
pub trait AsAny {
|
pub trait AsAny {
|
||||||
@ -222,6 +227,8 @@ pub trait QueueInterface: CommonTraits {
|
|||||||
|
|
||||||
fn get_timestamp_period(&self) -> f32;
|
fn get_timestamp_period(&self) -> f32;
|
||||||
fn on_submitted_work_done(&self, callback: BoxSubmittedWorkDoneCallback);
|
fn on_submitted_work_done(&self, callback: BoxSubmittedWorkDoneCallback);
|
||||||
|
|
||||||
|
fn compact_blas(&self, blas: &DispatchBlas) -> (Option<u64>, DispatchBlas);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ShaderModuleInterface: CommonTraits {
|
pub trait ShaderModuleInterface: CommonTraits {
|
||||||
@ -250,7 +257,10 @@ pub trait TextureInterface: CommonTraits {
|
|||||||
|
|
||||||
fn destroy(&self);
|
fn destroy(&self);
|
||||||
}
|
}
|
||||||
pub trait BlasInterface: CommonTraits {}
|
pub trait BlasInterface: CommonTraits {
|
||||||
|
fn prepare_compact_async(&self, callback: BlasCompactCallback);
|
||||||
|
fn ready_for_compaction(&self) -> bool;
|
||||||
|
}
|
||||||
pub trait TlasInterface: CommonTraits {}
|
pub trait TlasInterface: CommonTraits {}
|
||||||
pub trait QuerySetInterface: CommonTraits {}
|
pub trait QuerySetInterface: CommonTraits {}
|
||||||
pub trait PipelineLayoutInterface: CommonTraits {}
|
pub trait PipelineLayoutInterface: CommonTraits {}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user