//! Generic pass functions that both compute and render passes need.
usecrate::binding_model::{BindError, BindGroup, ImmediateUploadError}; usecrate::command::encoder::EncodingState; usecrate::command::{
bind::Binder, memory_init::SurfacesInDiscardState, query::QueryResetMap, DebugGroupError,
QueryUseError,
}; usecrate::device::{Device, DeviceError, MissingFeatures}; usecrate::pipeline::LateSizedBufferGroup; usecrate::resource::{DestroyedResourceError, Labeled, ParentDevice, QuerySet}; usecrate::track::{ResourceUsageCompatibilityError, UsageScope}; usecrate::{api_log, binding_model}; use alloc::sync::Arc; use alloc::vec::Vec; use core::str; use thiserror::Error; use wgt::error::{ErrorType, WebGpuError}; use wgt::DynamicOffset;
#[derive(Clone, Debug, Error)] #[error( "Bind group index {index} is greater than the device's configured `max_bind_groups` limit {max}"
)] pubstruct BindGroupIndexOutOfRange { pub index: u32, pub max: u32,
}
#[derive(Clone, Debug, Error)] #[error("Pipeline must be set")] pubstruct MissingPipeline;
#[derive(Clone, Debug, Error)] #[error("Setting `values_offset` to be `None` is only for internal use in render bundles")] pubstruct InvalidValuesOffset;
/// Immediate texture inits required because of prior discards. Need to /// be inserted before texture reads. pub(crate) pending_discard_init_fixups: SurfacesInDiscardState,
iflet Some(bind_group) = bind_group { // Add the bind group to the tracker. This is done for both compute and // render passes, and is used to fail submission of the command buffer if // any resource in any of the bind groups has been destroyed, whether or // not the bind group is actually used by the pipeline. let bind_group = state.base.tracker.bind_groups.insert_single(bind_group);
if merge_bind_groups { // Merge the bind group's resources into the tracker. We only do this // for render passes. For compute passes it is done per dispatch in // [`flush_bindings`]. unsafe {
state.scope.merge_bind_group(&bind_group.used)?;
}
} //Note: stateless trackers are not merged: the lifetime reference // is held to the bind group itself.
state
.binder
.assign_group(index as usize, bind_group, &state.temp_offsets);
} else { if !state.temp_offsets.is_empty() { return Err(BindError::DynamicOffsetCountNotZero {
group: index,
actual: state.temp_offsets.len(),
}
.into());
}
state.binder.clear_group(index as usize);
};
Ok(())
}
/// Implementation of `flush_bindings` for both compute and render passes. /// /// See the compute pass version of `State::flush_bindings` for an explanation /// of some differences in handling the two types of passes. pub(super) fn flush_bindings_helper(state: &mut PassState) -> Result<(), DestroyedResourceError> { let start = state.binder.take_rebind_start_index(); let entries = state.binder.list_valid_with_start(start); let pipeline_layout = state.binder.pipeline_layout.as_ref().unwrap();
for (i, bind_group, dynamic_offsets) in entries {
state.base.buffer_memory_init_actions.extend(
bind_group.buffer_init_actions.iter().filter_map(|action| {
action
.buffer
.initialization_status
.read()
.check_action(action)
}),
); for action in bind_group.texture_init_actions.iter() {
state.pending_discard_init_fixups.extend(
state
.base
.texture_memory_actions
.register_init_action(action),
);
}
let used_resource = bind_group
.used
.acceleration_structures
.into_iter()
.map(|tlas| crate::ray_tracing::AsAction::UseTlas(tlas.clone()));
state.base.as_actions.extend(used_resource);
let raw_bg = bind_group.try_raw(state.base.snatch_guard)?; unsafe {
state.base.raw_encoder.set_bind_group(
pipeline_layout.raw(),
i as u32,
raw_bg,
dynamic_offsets,
);
}
}
Ok(())
}
pub(super) fn change_pipeline_layout<E, F: FnOnce()>(
state: &mut PassState,
pipeline_layout: &Arc<binding_model::PipelineLayout>,
late_sized_buffer_groups: &[LateSizedBufferGroup],
f: F,
) -> Result<(), E> where
E: From<DestroyedResourceError>,
{ if state
.binder
.change_pipeline_layout(pipeline_layout, late_sized_buffer_groups)
{
f();
let values_offset_usize = usize::try_from(values_offset)
.expect("`values_offset` is outside the bounds of `usize` (!?)"); if values_offset_usize > immediates_data.len() { return Err(ImmediateUploadError::ValueStartIndexOverrun {
start_index: values_offset,
data_size: immediates_data.len(),
}
.into());
}
// NOTE: The `validate_immediates_ranges` call above validates `size_bytes` is aligned. let size_immediate_elements = size_bytes / wgt::IMMEDIATE_DATA_ALIGNMENT; let size_immediate_elements_usize = usize::try_from(size_immediate_elements)
.expect("`size_immediate_elements` is outside the bounds of `usize` (!?)"); if size_immediate_elements_usize > immediates_data.len() - values_offset_usize { return Err(ImmediateUploadError::ValueEndIndexOverrun {
start_index: values_offset,
count: size_immediate_elements,
data_size: immediates_data.len(),
}
.into());
}
// NOTE: These additions are will not overflow, because we've validated the range above. let values_end_offset = values_offset_usize + size_immediate_elements_usize; let data_slice = &immediates_data[(values_offset_usize)..values_end_offset];
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.