use thiserror::Error; use wgt::{math::align_to, BufferAddress, BufferUsages, ImageSubresourceRange, TextureAspect};
/// Error encountered while attempting a clear. #[derive(Clone, Debug, Error)] #[non_exhaustive] pubenum ClearError { #[error("To use clear_texture the CLEAR_TEXTURE feature needs to be enabled")]
MissingClearTextureFeature, #[error(transparent)]
DestroyedResource(#[from] DestroyedResourceError), #[error("{0} can not be cleared")]
NoValidTextureClearMode(ResourceErrorIdent), #[error("Buffer clear size {0:?} is not a multiple of `COPY_BUFFER_ALIGNMENT`")]
UnalignedFillSize(BufferAddress), #[error("Buffer offset {0:?} is not a multiple of `COPY_BUFFER_ALIGNMENT`")]
UnalignedBufferOffset(BufferAddress), #[error("Clear starts at offset {start_offset} with size of {requested_size}, but these added together exceed `u64::MAX`")]
OffsetPlusSizeExceeds64BitBounds {
start_offset: BufferAddress,
requested_size: BufferAddress,
}, #[error("Clear of {start_offset}..{end_offset} would end up overrunning the bounds of the buffer of size {buffer_size}")]
BufferOverrun {
start_offset: BufferAddress,
end_offset: BufferAddress,
buffer_size: BufferAddress,
}, #[error(transparent)]
MissingBufferUsage(#[from] MissingBufferUsageError), #[error("Texture lacks the aspects that were specified in the image subresource range. Texture with format {texture_format:?}, specified was {subresource_range_aspects:?}")]
MissingTextureAspect {
texture_format: wgt::TextureFormat,
subresource_range_aspects: TextureAspect,
}, #[error("Image subresource level range is outside of the texture's level range. texture range is {texture_level_range:?}, \
whereas subesource range specified start {subresource_base_mip_level} and count {subresource_mip_level_count:?}")]
InvalidTextureLevelRange {
texture_level_range: Range<u32>,
subresource_base_mip_level: u32,
subresource_mip_level_count: Option<u32>,
}, #[error("Image subresource layer range is outside of the texture's layer range. texture range is {texture_layer_range:?}, \
whereas subesource range specified start {subresource_base_array_layer} and count {subresource_array_layer_count:?}")]
InvalidTextureLayerRange {
texture_layer_range: Range<u32>,
subresource_base_array_layer: u32,
subresource_array_layer_count: Option<u32>,
}, #[error(transparent)]
Device(#[from] DeviceError), #[error(transparent)]
CommandEncoderError(#[from] CommandEncoderError), #[error(transparent)]
InvalidResource(#[from] InvalidResourceError),
}
let dst_pending = cmd_buf_data
.trackers
.buffers
.set_single(&dst_buffer, hal::BufferUses::COPY_DST);
let snatch_guard = dst_buffer.device.snatchable_lock.read(); let dst_raw = dst_buffer.try_raw(&snatch_guard)?;
dst_buffer.check_usage(BufferUsages::COPY_DST)?;
// Check if offset & size are valid. if offset % wgt::COPY_BUFFER_ALIGNMENT != 0 { return Err(ClearError::UnalignedBufferOffset(offset));
}
// Mark dest as initialized.
cmd_buf_data.buffer_memory_init_actions.extend(
dst_buffer.initialization_status.read().create_action(
&dst_buffer,
offset..end_offset,
MemoryInitKind::ImplicitlyInitialized,
),
);
// actual hal barrier & operation let dst_barrier = dst_pending.map(|pending| pending.into_hal(&dst_buffer, &snatch_guard)); let cmd_buf_raw = cmd_buf_data.encoder.open()?; unsafe {
cmd_buf_raw.transition_buffers(dst_barrier.as_slice());
cmd_buf_raw.clear_buffer(dst_raw, offset..end_offset);
}
let selector = TextureSelector {
mips: range.mip_range.clone(),
layers: range.layer_range.clone(),
};
// If we're in a texture-init usecase, we know that the texture is already // tracked since whatever caused the init requirement, will have caused the // usage tracker to be aware of the texture. Meaning, that it is safe to // call call change_replace_tracked if the life_guard is already gone (i.e. // the user no longer holds on to this texture). // // On the other hand, when coming via command_encoder_clear_texture, the // life_guard is still there since in order to call it a texture object is // needed. // // We could in theory distinguish these two scenarios in the internal // clear_texture api in order to remove this check and call the cheaper // change_replace_tracked whenever possible. let dst_barrier = texture_tracker
.set_single(dst_texture, selector, clear_usage)
.map(|pending| pending.into_hal(dst_raw))
.collect::<Vec<_>>(); unsafe {
encoder.transition_textures(&dst_barrier);
}
if texture_desc.format == wgt::TextureFormat::NV12 { // TODO: Currently COPY_DST for NV12 textures is unsupported. return;
}
// Gather list of zero_buffer copies and issue a single command then to perform them letmut zero_buffer_copy_regions = Vec::new(); let buffer_copy_pitch = alignments.buffer_copy_pitch.get() as u32; let (block_width, block_height) = texture_desc.format.block_dimensions(); let block_size = texture_desc.format.block_copy_size(None).unwrap();
let bytes_per_row_alignment = get_lowest_common_denom(buffer_copy_pitch, block_size);
for mip_level in range.mip_range { letmut mip_size = texture_desc.mip_level_size(mip_level).unwrap(); // Round to multiple of block size
mip_size.width = align_to(mip_size.width, block_width);
mip_size.height = align_to(mip_size.height, block_height);
let max_rows_per_copy = crate::device::ZERO_BUFFER_SIZE as u32 / bytes_per_row; // round down to a multiple of rows needed by the texture format let max_rows_per_copy = max_rows_per_copy / block_height * block_height;
assert!(
max_rows_per_copy > 0, "Zero buffer size is too small to fill a single row \
of a texture with format {:?} and desc {:?}",
texture_desc.format,
texture_desc.size
);
for array_layer in range.layer_range.clone() { // TODO: Only doing one layer at a time for volume textures right now. for z in z_range.clone() { // May need multiple copies for each subresource! However, we // assume that we never need to split a row. letmut num_rows_left = mip_size.height; while num_rows_left > 0 { let num_rows = num_rows_left.min(max_rows_per_copy);
zero_buffer_copy_regions.push(hal::BufferTextureCopy {
buffer_layout: wgt::TexelCopyBufferLayout {
offset: 0,
bytes_per_row: Some(bytes_per_row),
rows_per_image: None,
},
texture_base: hal::TextureCopyBase {
mip_level,
array_layer,
origin: wgt::Origin3d {
x: 0, // Always full rows
y: mip_size.height - num_rows_left,
z,
},
aspect: hal::FormatAspects::COLOR,
},
size: hal::CopyExtent {
width: mip_size.width, // full row
height: num_rows,
depth: 1, // Only single slice of volume texture at a time right now
},
});
let extent_base = wgt::Extent3d {
width: dst_texture.desc.size.width,
height: dst_texture.desc.size.height,
depth_or_array_layers: 1, // Only one layer is cleared at a time.
};
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.