impl Global { // 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. pubfn 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());
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)?;
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;
for (package, tlas) in &mut tlas_lock_store { let package = package.take().unwrap();
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;
let first_byte_index = instance_buffer_staging_source.len();
letmut dependencies = Vec::new();
letmut instance_count = 0; for instance in package.instances.flatten() { if instance.custom_index >= (1u32 << 24u32) { return Err(BuildAccelerationStructureError::TlasInvalidCustomIndex(
tlas.error_ident(),
));
} let blas = hub.blas_s.get(instance.blas_id).get()?;
let scratch_size = match wgt::BufferSize::new(max(scratch_buffer_blas_size, scratch_buffer_tlas_size)) { // if the size is zero there is nothing to build
None => {
cmd_buf_data_guard.mark_successful(); return Ok(());
}
Some(size) => size,
};
let scratch_buffer =
ScratchBuffer::new(device, scratch_size).map_err(crate::device::DeviceError::from)?;
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,
},
};
letmut instance_buffer_barriers = Vec::new(); for &TlasStore {
internal: UnsafeTlasStore { ref tlas, .. }, ref range,
} in &tlas_storage
{ let size = match wgt::BufferSize::new((range.end - range.start) as u64) {
None => continue,
Some(size) => size,
};
instance_buffer_barriers.push(hal::BufferBarrier::<dyn hal::DynBuffer> {
buffer: tlas.instance_buffer.as_ref(),
usage: hal::StateTransition {
from: BufferUses::COPY_DST,
to: BufferUses::TOP_LEVEL_ACCELERATION_STRUCTURE_INPUT,
},
}); unsafe {
cmd_buf_raw.transition_buffers(&[hal::BufferBarrier::<dyn hal::DynBuffer> {
buffer: tlas.instance_buffer.as_ref(),
usage: hal::StateTransition {
from: BufferUses::MAP_READ,
to: BufferUses::COPY_DST,
},
}]); let temp = hal::BufferCopy {
src_offset: range.start as u64,
dst_offset: 0,
size,
};
cmd_buf_raw.copy_buffer_to_buffer( // the range whose size we just checked end is at (at that point in time) instance_buffer_staging_source.len() // and since instance_buffer_staging_source doesn't shrink we can un wrap this without a panic
staging_buffer.as_ref().unwrap().raw(),
tlas.instance_buffer.as_ref(),
&[temp],
);
}
}
impl CommandBufferMutable { // makes sure a blas is build before it is used pub(crate) fn validate_blas_actions(&self) -> Result<(), ValidateBlasActionsError> {
profiling::scope!("CommandEncoder::[submission]::validate_blas_actions"); letmut built = FastHashSet::default(); for action in &self.blas_actions { match &action.kind { crate::ray_tracing::BlasActionKind::Build(id) => {
built.insert(action.blas.tracker_index());
*action.blas.built_index.write() = Some(*id);
} crate::ray_tracing::BlasActionKind::Use => { if !built.contains(&action.blas.tracker_index())
&& (*action.blas.built_index.read()).is_none()
{ return Err(ValidateBlasActionsError::UsedUnbuilt(
action.blas.error_ident(),
));
}
}
}
}
Ok(())
}
// makes sure a tlas is built before it is used pub(crate) fn validate_tlas_actions(
&self,
snatch_guard: &SnatchGuard,
) -> Result<(), ValidateTlasActionsError> {
profiling::scope!("CommandEncoder::[submission]::validate_tlas_actions"); for action in &self.tlas_actions { match &action.kind { crate::ray_tracing::TlasActionKind::Build {
build_index,
dependencies,
} => {
*action.tlas.built_index.write() = Some(*build_index);
action.tlas.dependencies.write().clone_from(dependencies);
} crate::ray_tracing::TlasActionKind::Use => { let tlas_build_index = action.tlas.built_index.read(); let dependencies = action.tlas.dependencies.read();
if (*tlas_build_index).is_none() { return Err(ValidateTlasActionsError::UsedUnbuilt(
action.tlas.error_ident(),
));
} for blas in dependencies.deref() { let blas_build_index = *blas.built_index.read(); if blas_build_index.is_none() { return Err(ValidateTlasActionsError::UsedUnbuiltBlas(
action.tlas.error_ident(),
blas.error_ident(),
));
} if blas_build_index.unwrap() > tlas_build_index.unwrap() { return Err(ValidateTlasActionsError::BlasNewerThenTlas(
blas.error_ident(),
action.tlas.error_ident(),
));
}
blas.try_raw(snatch_guard)?;
}
}
}
}
Ok(())
}
}
///iterates over the blas iterator, and it's geometry, pushing the buffers into a storage vector (and also some validation). fn iter_blas<'a>(
blas_iter: impl Iterator<Item = BlasBuildEntry<'a>>,
cmd_buf_data: &mut CommandBufferMutable,
build_command_index: NonZeroU64,
buf_storage: &mut Vec<TriangleBufferStore<'a>>,
hub: &Hub,
) -> Result<(), BuildAccelerationStructureError> { letmut temp_buffer = Vec::new(); for entry in blas_iter { let blas = hub.blas_s.get(entry.blas_id).get()?;
cmd_buf_data.trackers.blas_s.insert_single(blas.clone());
match entry.geometries {
BlasGeometries::TriangleGeometries(triangle_geometries) => { for (i, mesh) in triangle_geometries.enumerate() { let size_desc = match &blas.sizes {
wgt::BlasGeometrySizeDescriptors::Triangles { descriptors } => descriptors,
}; if i >= size_desc.len() { return Err(BuildAccelerationStructureError::IncompatibleBlasBuildSizes(
blas.error_ident(),
));
} let size_desc = &size_desc[i];
/// Iterates over the buffers generated in [iter_blas], convert the barriers into hal barriers, and the triangles into [hal::AccelerationStructureEntries] (and also some validation). fn iter_buffers<'a, 'b>(
buf_storage: &'a mut Vec<TriangleBufferStore<'b>>,
snatch_guard: &'a SnatchGuard,
input_barriers: &mut Vec<hal::BufferBarrier<'a, dyn hal::DynBuffer>>,
cmd_buf_data: &mut CommandBufferMutable,
scratch_buffer_blas_size: &mut u64,
blas_storage: &mut Vec<BlasStore<'a>>,
hub: &Hub,
ray_tracing_scratch_buffer_alignment: u32,
) -> Result<(), BuildAccelerationStructureError> { letmut triangle_entries =
Vec::<hal::AccelerationStructureTriangles<dyn hal::DynBuffer>>::new(); for buf in buf_storage { let mesh = &buf.geometry; let vertex_buffer = { let vertex_buffer = buf.vertex_buffer.as_ref(); let vertex_raw = vertex_buffer.try_raw(snatch_guard)?;
vertex_buffer.check_usage(BufferUsages::BLAS_INPUT)?;
iflet Some(barrier) = buf
.vertex_transition
.take()
.map(|pending| pending.into_hal(vertex_buffer, snatch_guard))
{
input_barriers.push(barrier);
} if vertex_buffer.size
< (mesh.size.vertex_count + mesh.first_vertex) as u64 * mesh.vertex_stride
{ return Err(BuildAccelerationStructureError::InsufficientBufferSize(
vertex_buffer.error_ident(),
vertex_buffer.size,
(mesh.size.vertex_count + mesh.first_vertex) as u64 * mesh.vertex_stride,
));
} let vertex_buffer_offset = mesh.first_vertex as u64 * mesh.vertex_stride;
cmd_buf_data.buffer_memory_init_actions.extend(
vertex_buffer.initialization_status.read().create_action(
&hub.buffers.get(mesh.vertex_buffer).get()?,
vertex_buffer_offset
..(vertex_buffer_offset
+ mesh.size.vertex_count as u64 * mesh.vertex_stride),
MemoryInitKind::NeedsInitializedMemory,
),
);
vertex_raw
}; let index_buffer = iflet Some((refmut index_buffer, refmut index_pending)) =
buf.index_buffer_transition
{ let index_raw = index_buffer.try_raw(snatch_guard)?;
index_buffer.check_usage(BufferUsages::BLAS_INPUT)?;
iflet Some(barrier) = index_pending
.take()
.map(|pending| pending.into_hal(index_buffer, snatch_guard))
{
input_barriers.push(barrier);
} let index_stride = match mesh.size.index_format.unwrap() {
wgt::IndexFormat::Uint16 => 2,
wgt::IndexFormat::Uint32 => 4,
}; if mesh.index_buffer_offset.unwrap() % index_stride != 0 { return Err(BuildAccelerationStructureError::UnalignedIndexBufferOffset(
index_buffer.error_ident(),
));
} let index_buffer_size = mesh.size.index_count.unwrap() as u64 * index_stride;
if mesh.size.index_count.unwrap() % 3 != 0 { return Err(BuildAccelerationStructureError::InvalidIndexCount(
index_buffer.error_ident(),
mesh.size.index_count.unwrap(),
));
} if index_buffer.size
< mesh.size.index_count.unwrap() as u64 * index_stride
+ mesh.index_buffer_offset.unwrap()
{ return Err(BuildAccelerationStructureError::InsufficientBufferSize(
index_buffer.error_ident(),
index_buffer.size,
mesh.size.index_count.unwrap() as u64 * index_stride
+ mesh.index_buffer_offset.unwrap(),
));
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.