use std::num::NonZeroU64; use std::{
borrow::{Borrow, Cow},
fmt::Debug,
mem::{self, ManuallyDrop},
ops::Range,
ptr::NonNull,
sync::Arc,
};
/// Information about the wgpu-core resource. /// /// Each type representing a `wgpu-core` resource, like [`Device`], /// [`Buffer`], etc., contains a `ResourceInfo` which contains /// its latest submission index and label. /// /// A resource may need to be retained for any of several reasons: /// and any lifetime logic will be handled by `Arc<Resource>` refcount /// /// - The user may hold a reference to it (via a `wgpu::Buffer`, say). /// /// - Other resources may depend on it (a texture view's backing /// texture, for example). /// /// - It may be used by commands sent to the GPU that have not yet /// finished execution. /// /// [`Device`]: crate::device::resource::Device /// [`Buffer`]: crate::resource::Buffer #[derive(Debug)] pub(crate) struct TrackingData {
tracker_index: TrackerIndex,
tracker_indices: Arc<SharedTrackerIndexAllocator>,
}
impl Drop for TrackingData { fn drop(&mutself) { self.tracker_indices.free(self.tracker_index);
}
}
pubtrait Labeled: ResourceType { /// Returns a string identifying this resource for logging and errors. /// /// It may be a user-provided string or it may be a placeholder from wgpu. /// /// It is non-empty unless the user-provided string was empty. fn label(&self) -> &str;
#[derive(Clone, Debug, Error)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[non_exhaustive] pubenum BufferAccessError { #[error(transparent)]
Device(#[from] DeviceError), #[error("Buffer map failed")]
Failed, #[error(transparent)]
DestroyedResource(#[from] DestroyedResourceError), #[error("Buffer is already mapped")]
AlreadyMapped, #[error("Buffer map is pending")]
MapAlreadyPending, #[error(transparent)]
MissingBufferUsage(#[from] MissingBufferUsageError), #[error("Buffer is not mapped")]
NotMapped, #[error( "Buffer map range must start aligned to `MAP_ALIGNMENT` and end to `COPY_BUFFER_ALIGNMENT`"
)]
UnalignedRange, #[error("Buffer offset invalid: offset {offset} must be multiple of 8")]
UnalignedOffset { offset: wgt::BufferAddress }, #[error("Buffer range size invalid: range_size {range_size} must be multiple of 4")]
UnalignedRangeSize { range_size: wgt::BufferAddress }, #[error("Buffer access out of bounds: index {index} would underrun the buffer (limit: {min})")]
OutOfBoundsUnderrun {
index: wgt::BufferAddress,
min: wgt::BufferAddress,
}, #[error( "Buffer access out of bounds: last index {index} would overrun the buffer (limit: {max})"
)]
OutOfBoundsOverrun {
index: wgt::BufferAddress,
max: wgt::BufferAddress,
}, #[error("Buffer map range start {start} is greater than end {end}")]
NegativeRange {
start: wgt::BufferAddress,
end: wgt::BufferAddress,
}, #[error("Buffer map aborted")]
MapAborted, #[error(transparent)]
InvalidResource(#[from] InvalidResourceError),
}
#[derive(Debug)] pub(crate) struct BufferPendingMapping { pub(crate) range: Range<wgt::BufferAddress>, pub(crate) op: BufferMapOperation, // hold the parent alive while the mapping is active pub(crate) _parent_buffer: Arc<Buffer>,
}
/// Checks that the given buffer usage contains the required buffer usage, /// returns an error otherwise. pub(crate) fn check_usage(
&self,
expected: wgt::BufferUsages,
) -> Result<(), MissingBufferUsageError> { ifself.usage.contains(expected) {
Ok(())
} else {
Err(MissingBufferUsageError {
res: self.error_ident(),
actual: self.usage,
expected,
})
}
}
/// Returns the mapping callback in case of error so that the callback can be fired outside /// of the locks that are held in this function. pub(crate) fn map_async( self: &Arc<Self>,
offset: wgt::BufferAddress,
size: Option<wgt::BufferAddress>,
op: BufferMapOperation,
) -> Result<SubmissionIndex, (BufferMapOperation, BufferAccessError)> { let range_size = iflet Some(size) = size {
size
} elseif offset > self.size { 0
} else { self.size - offset
};
// TODO: we are ignoring the transition here, I think we need to add a barrier // at the end of the submission
device
.trackers
.lock()
.buffers
.set_single(self, internal_use);
let submit_index = iflet Some(queue) = device.get_queue() {
queue.lock_life().map(self).unwrap_or(0) // '0' means no wait is necessary
} else { // We can safely unwrap below since we just set the `map_state` to `BufferMapState::Waiting`. let (mut operation, status) = self.map(&device.snatchable_lock.read()).unwrap(); iflet Some(callback) = operation.callback.take() {
callback(status);
} 0
};
Ok(submit_index)
}
/// This function returns [`None`] only if [`Self::map_state`] is not [`BufferMapState::Waiting`]. #[must_use] pub(crate) fn map(&self, snatch_guard: &SnatchGuard) -> Option<BufferMapPendingClosure> { // This _cannot_ be inlined into the match. If it is, the lock will be held // open through the whole match, resulting in a deadlock when we try to re-lock // the buffer back to active. let mapping = mem::replace(&mut *self.map_state.lock(), BufferMapState::Idle); let pending_mapping = match mapping {
BufferMapState::Waiting(pending_mapping) => pending_mapping, // Mapping cancelled
BufferMapState::Idle => return None, // Mapping queued at least twice by map -> unmap -> map // and was already successfully mapped below
BufferMapState::Active { .. } => {
*self.map_state.lock() = mapping; return None;
}
_ => panic!("No pending mapping."),
}; let status = if pending_mapping.range.start != pending_mapping.range.end { let host = pending_mapping.op.host; let size = pending_mapping.range.end - pending_mapping.range.start; matchcrate::device::map_buffer( self,
pending_mapping.range.start,
size,
host,
snatch_guard,
) {
Ok(mapping) => {
*self.map_state.lock() = BufferMapState::Active {
mapping,
range: pending_mapping.range.clone(),
host,
};
Ok(())
}
Err(e) => Err(e),
}
} else {
*self.map_state.lock() = BufferMapState::Active {
mapping: hal::BufferMapping {
ptr: NonNull::dangling(),
is_coherent: true,
},
range: pending_mapping.range,
host: pending_mapping.op.host,
};
Ok(())
};
Some((pending_mapping.op, status))
}
// Note: This must not be called while holding a lock. pub(crate) fn unmap( self: &Arc<Self>, #[cfg(feature = "trace")] buffer_id: BufferId,
) -> Result<(), BufferAccessError> { iflet Some((mut operation, status)) = self.unmap_inner( #[cfg(feature = "trace")]
buffer_id,
)? { iflet Some(callback) = operation.callback.take() {
callback(status);
}
}
#[derive(Clone, Debug, Error)] #[non_exhaustive] pubenum CreateBufferError { #[error(transparent)]
Device(#[from] DeviceError), #[error("Failed to map buffer while creating: {0}")]
AccessError(#[from] BufferAccessError), #[error("Buffers that are mapped at creation have to be aligned to `COPY_BUFFER_ALIGNMENT`")]
UnalignedSize, #[error("Invalid usage flags {0:?}")]
InvalidUsage(wgt::BufferUsages), #[error("`MAP` usage can only be combined with the opposite `COPY`, requested {0:?}")]
UsageMismatch(wgt::BufferUsages), #[error("Buffer size {requested} is greater than the maximum buffer size ({maximum})")]
MaxBufferSize { requested: u64, maximum: u64 }, #[error(transparent)]
MissingDownlevelFlags(#[from] MissingDownlevelFlags), #[error("Failed to create bind group for indirect buffer validation: {0}")]
IndirectValidationBindGroup(DeviceError),
}
/// A buffer that has been marked as destroyed and is staged for actual deletion soon. #[derive(Debug)] pubstruct DestroyedBuffer {
raw: ManuallyDrop<Box<dyn hal::DynBuffer>>,
device: Arc<Device>,
label: String,
bind_groups: WeakVec<BindGroup>, #[cfg(feature = "indirect-validation")]
raw_indirect_validation_bind_group: Option<Box<dyn hal::DynBindGroup>>,
}
resource_log!("Destroy raw Buffer (destroyed) {:?}", self.label()); // SAFETY: We are in the Drop impl and we don't use self.raw anymore after this point. let raw = unsafe { ManuallyDrop::take(&mutself.raw) }; unsafe {
hal::DynDevice::destroy_buffer(self.device.raw(), raw);
}
}
}
#[cfg(send_sync)] unsafeimpl Send for StagingBuffer {} #[cfg(send_sync)] unsafeimpl Sync for StagingBuffer {}
/// A temporary buffer, consumed by the command that uses it. /// /// A [`StagingBuffer`] is designed for one-shot uploads of data to the GPU. It /// is always created mapped, and the command that uses it destroys the buffer /// when it is done. /// /// [`StagingBuffer`]s can be created with [`queue_create_staging_buffer`] and /// used with [`queue_write_staging_buffer`]. They are also used internally by /// operations like [`queue_write_texture`] that need to upload data to the GPU, /// but that don't belong to any particular wgpu command buffer. /// /// Used `StagingBuffer`s are accumulated in [`Device::pending_writes`], to be /// freed once their associated operation's queue submission has finished /// execution. /// /// [`queue_create_staging_buffer`]: Global::queue_create_staging_buffer /// [`queue_write_staging_buffer`]: Global::queue_write_staging_buffer /// [`queue_write_texture`]: Global::queue_write_texture /// [`Device::pending_writes`]: crate::device::Device #[derive(Debug)] pubstruct StagingBuffer {
raw: Box<dyn hal::DynBuffer>,
device: Arc<Device>, pub(crate) size: wgt::BufferSize,
is_coherent: bool,
ptr: NonNull<u8>,
}
/// SAFETY: You must not call any functions of `self` /// until you stopped using the returned pointer. pub(crate) unsafefn ptr(&self) -> NonNull<u8> { self.ptr
}
pub(crate) fn write(&mutself, data: &[u8]) {
assert!(data.len() >= self.size.get() as usize); // SAFETY: With the assert above, all of `copy_nonoverlapping`'s // requirements are satisfied. unsafe {
core::ptr::copy_nonoverlapping(
data.as_ptr(), self.ptr.as_ptr(), self.size.get() as usize,
);
}
}
/// SAFETY: The offsets and size must be in-bounds. pub(crate) unsafefn write_with_offset(
&mutself,
data: &[u8],
src_offset: isize,
dst_offset: isize,
size: usize,
) { unsafe {
core::ptr::copy_nonoverlapping(
data.as_ptr().offset(src_offset), self.ptr.as_ptr().offset(dst_offset),
size,
);
}
}
impl Drop for FlushedStagingBuffer { fn drop(&mutself) {
resource_log!("Destroy raw StagingBuffer"); // SAFETY: We are in the Drop impl and we don't use self.raw anymore after this point. let raw = unsafe { ManuallyDrop::take(&mutself.raw) }; unsafe { self.device.raw().destroy_buffer(raw) };
}
}
#[derive(Debug)] pubenum TextureClearMode {
BufferCopy, // View for clear via RenderPass for every subsurface (mip/layer/slice)
RenderPass {
clear_views: SmallVec<[ManuallyDrop<Box<dyn hal::DynTextureView>>; 1]>,
is_color: bool,
},
Surface {
clear_view: ManuallyDrop<Box<dyn hal::DynTextureView>>,
}, // Texture can't be cleared, attempting to do so will cause panic. // (either because it is impossible for the type of texture or it is being destroyed)
None,
}
#[derive(Debug)] pubstruct Texture { pub(crate) inner: Snatchable<TextureInner>, pub(crate) device: Arc<Device>, pub(crate) desc: wgt::TextureDescriptor<(), Vec<wgt::TextureFormat>>, pub(crate) hal_usage: hal::TextureUses, pub(crate) format_features: wgt::TextureFormatFeatures, pub(crate) initialization_status: RwLock<TextureInitTracker>, pub(crate) full_range: TextureSelector, /// The `label` from the descriptor used to create the resource. pub(crate) label: String, pub(crate) tracking_data: TrackingData, pub(crate) clear_mode: TextureClearMode, pub(crate) views: Mutex<WeakVec<TextureView>>, pub(crate) bind_groups: Mutex<WeakVec<BindGroup>>,
}
/// Checks that the given texture usage contains the required texture usage, /// returns an error otherwise. pub(crate) fn check_usage(
&self,
expected: wgt::TextureUsages,
) -> Result<(), MissingTextureUsageError> { ifself.desc.usage.contains(expected) {
Ok(())
} else {
Err(MissingTextureUsageError {
res: self.error_ident(),
actual: self.desc.usage,
expected,
})
}
}
}
impl Drop for Texture { fn drop(&mutself) { matchself.clear_mode {
TextureClearMode::Surface { refmut clear_view, ..
} => { // SAFETY: We are in the Drop impl and we don't use clear_view anymore after this point. let raw = unsafe { ManuallyDrop::take(clear_view) }; unsafe { self.device.raw().destroy_texture_view(raw);
}
}
TextureClearMode::RenderPass { refmut clear_views,
..
} => {
clear_views.iter_mut().for_each(|clear_view| { // SAFETY: We are in the Drop impl and we don't use clear_view anymore after this point. let raw = unsafe { ManuallyDrop::take(clear_view) }; unsafe { self.device.raw().destroy_texture_view(raw);
}
});
}
_ => {}
};
iflet Some(TextureInner::Native { raw }) = self.inner.take() {
resource_log!("Destroy raw {}", self.error_ident()); unsafe { self.device.raw().destroy_texture(raw);
}
}
}
}
/// # Safety /// /// - The raw texture handle must not be manually destroyed pubunsafefn texture_as_hal<A: HalApi, F: FnOnce(Option<&A::Texture>) -> R, R>(
&self,
id: TextureId,
hal_texture_callback: F,
) -> R {
profiling::scope!("Texture::as_hal");
let hub = &self.hub;
iflet Ok(texture) = hub.textures.get(id).get() { let snatch_guard = texture.device.snatchable_lock.read(); let hal_texture = texture.raw(&snatch_guard); let hal_texture = hal_texture
.as_ref()
.and_then(|it| it.as_any().downcast_ref());
hal_texture_callback(hal_texture)
} else {
hal_texture_callback(None)
}
}
/// # Safety /// /// - The raw texture view handle must not be manually destroyed pubunsafefn texture_view_as_hal<A: HalApi, F: FnOnce(Option<&A::TextureView>) -> R, R>(
&self,
id: TextureViewId,
hal_texture_view_callback: F,
) -> R {
profiling::scope!("TextureView::as_hal");
let hub = &self.hub;
iflet Ok(texture_view) = hub.texture_views.get(id).get() { let snatch_guard = texture_view.device.snatchable_lock.read(); let hal_texture_view = texture_view.raw(&snatch_guard); let hal_texture_view = hal_texture_view
.as_ref()
.and_then(|it| it.as_any().downcast_ref());
hal_texture_view_callback(hal_texture_view)
} else {
hal_texture_view_callback(None)
}
}
/// # Safety /// /// - The raw adapter handle must not be manually destroyed pubunsafefn adapter_as_hal<A: HalApi, F: FnOnce(Option<&A::Adapter>) -> R, R>(
&self,
id: AdapterId,
hal_adapter_callback: F,
) -> R {
profiling::scope!("Adapter::as_hal");
let hub = &self.hub; let adapter = hub.adapters.get(id); let hal_adapter = adapter.raw.adapter.as_any().downcast_ref();
hal_adapter_callback(hal_adapter)
}
/// # Safety /// /// - The raw device handle must not be manually destroyed pubunsafefn device_as_hal<A: HalApi, F: FnOnce(Option<&A::Device>) -> R, R>(
&self,
id: DeviceId,
hal_device_callback: F,
) -> R {
profiling::scope!("Device::as_hal");
let device = self.hub.devices.get(id); let hal_device = device.raw().as_any().downcast_ref();
hal_device_callback(hal_device)
}
/// # Safety /// /// - The raw fence handle must not be manually destroyed pubunsafefn device_fence_as_hal<A: HalApi, F: FnOnce(Option<&A::Fence>) -> R, R>(
&self,
id: DeviceId,
hal_fence_callback: F,
) -> R {
profiling::scope!("Device::fence_as_hal");
let device = self.hub.devices.get(id); let fence = device.fence.read();
hal_fence_callback(fence.as_any().downcast_ref())
}
/// # Safety /// - The raw surface handle must not be manually destroyed pubunsafefn surface_as_hal<A: HalApi, F: FnOnce(Option<&A::Surface>) -> R, R>(
&self,
id: SurfaceId,
hal_surface_callback: F,
) -> R {
profiling::scope!("Surface::as_hal");
let surface = self.surfaces.get(id); let hal_surface = surface
.raw(A::VARIANT)
.and_then(|surface| surface.as_any().downcast_ref());
hal_surface_callback(hal_surface)
}
/// # Safety /// /// - The raw command encoder handle must not be manually destroyed pubunsafefn command_encoder_as_hal_mut<
A: HalApi,
F: FnOnce(Option<&mut A::CommandEncoder>) -> R,
R,
>(
&self,
id: CommandEncoderId,
hal_command_encoder_callback: F,
) -> R {
profiling::scope!("CommandEncoder::as_hal");
let hub = &self.hub;
let cmd_buf = hub.command_buffers.get(id.into_command_buffer_id()); letmut cmd_buf_data = cmd_buf.data.lock(); let cmd_buf_data_guard = cmd_buf_data.record();
iflet Ok(mut cmd_buf_data_guard) = cmd_buf_data_guard { let cmd_buf_raw = cmd_buf_data_guard
.encoder
.open()
.ok()
.and_then(|encoder| encoder.as_any_mut().downcast_mut()); let ret = hal_command_encoder_callback(cmd_buf_raw);
cmd_buf_data_guard.mark_successful();
ret
} else {
hal_command_encoder_callback(None)
}
}
}
/// A texture that has been marked as destroyed and is staged for actual deletion soon. #[derive(Debug)] pubstruct DestroyedTexture {
raw: ManuallyDrop<Box<dyn hal::DynTexture>>,
views: WeakVec<TextureView>,
bind_groups: WeakVec<BindGroup>,
device: Arc<Device>,
label: String,
}
resource_log!("Destroy raw Texture (destroyed) {:?}", self.label()); // SAFETY: We are in the Drop impl and we don't use self.raw anymore after this point. let raw = unsafe { ManuallyDrop::take(&mutself.raw) }; unsafe { self.device.raw().destroy_texture(raw);
}
}
}
#[derive(Clone, Copy, Debug)] pubenum TextureErrorDimension {
X,
Y,
Z,
}
#[derive(Clone, Debug, Error)] #[non_exhaustive] pubenum TextureDimensionError { #[error("Dimension {0:?} is zero")]
Zero(TextureErrorDimension), #[error("Dimension {dim:?} value {given} exceeds the limit of {limit}")]
LimitExceeded {
dim: TextureErrorDimension,
given: u32,
limit: u32,
}, #[error("Sample count {0} is invalid")]
InvalidSampleCount(u32), #[error("Width {width} is not a multiple of {format:?}'s block width ({block_width})")]
NotMultipleOfBlockWidth {
width: u32,
block_width: u32,
format: wgt::TextureFormat,
}, #[error("Height {height} is not a multiple of {format:?}'s block height ({block_height})")]
NotMultipleOfBlockHeight {
height: u32,
block_height: u32,
format: wgt::TextureFormat,
}, #[error( "Width {width} is not a multiple of {format:?}'s width multiple requirement ({multiple})"
)]
WidthNotMultipleOf {
width: u32,
multiple: u32,
format: wgt::TextureFormat,
}, #[error("Height {height} is not a multiple of {format:?}'s height multiple requirement ({multiple})")]
HeightNotMultipleOf {
height: u32,
multiple: u32,
format: wgt::TextureFormat,
}, #[error("Multisampled texture depth or array layers must be 1, got {0}")]
MultisampledDepthOrArrayLayer(u32),
}
#[derive(Clone, Debug, Error)] #[non_exhaustive] pubenum CreateTextureError { #[error(transparent)]
Device(#[from] DeviceError), #[error(transparent)]
CreateTextureView(#[from] CreateTextureViewError), #[error("Invalid usage flags {0:?}")]
InvalidUsage(wgt::TextureUsages), #[error(transparent)]
InvalidDimension(#[from] TextureDimensionError), #[error("Depth texture ({1:?}) can't be created as {0:?}")]
InvalidDepthDimension(wgt::TextureDimension, wgt::TextureFormat), #[error("Compressed texture ({1:?}) can't be created as {0:?}")]
InvalidCompressedDimension(wgt::TextureDimension, wgt::TextureFormat), #[error( "Texture descriptor mip level count {requested} is invalid, maximum allowed is {maximum}"
)]
InvalidMipLevelCount { requested: u32, maximum: u32 }, #[error( "Texture usages {0:?} are not allowed on a texture of type {1:?}{downlevel_suffix}",
downlevel_suffix = if *.2 { " due to downlevel restrictions" } else { "" }
)]
InvalidFormatUsages(wgt::TextureUsages, wgt::TextureFormat, bool), #[error("The view format {0:?} is not compatible with texture format {1:?}, only changing srgb-ness is allowed.")]
InvalidViewFormat(wgt::TextureFormat, wgt::TextureFormat), #[error("Texture usages {0:?} are not allowed on a texture of dimensions {1:?}")]
InvalidDimensionUsages(wgt::TextureUsages, wgt::TextureDimension), #[error("Texture usage STORAGE_BINDING is not allowed for multisampled textures")]
InvalidMultisampledStorageBinding, #[error("Format {0:?} does not support multisampling")]
InvalidMultisampledFormat(wgt::TextureFormat), #[error("Sample count {0} is not supported by format {1:?} on this device. The WebGPU spec guarantees {2:?} samples are supported by this format. With the TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES feature your device supports {3:?}.")]
InvalidSampleCount(u32, wgt::TextureFormat, Vec<u32>, Vec<u32>), #[error("Multisampled textures must have RENDER_ATTACHMENT usage")]
MultisampledNotRenderAttachment, #[error("Texture format {0:?} can't be used due to missing features")]
MissingFeatures(wgt::TextureFormat, #[source] MissingFeatures), #[error(transparent)]
MissingDownlevelFlags(#[from] MissingDownlevelFlags),
}
/// Describes a [`TextureView`]. #[derive(Clone, Debug, Default, Eq, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", serde(default))] pubstruct TextureViewDescriptor<'a> { /// Debug label of the texture view. /// /// This will show up in graphics debuggers for easy identification. pub label: Label<'a>, /// Format of the texture view, or `None` for the same format as the texture /// itself. /// /// At this time, it must be the same the underlying format of the texture. pub format: Option<wgt::TextureFormat>, /// The dimension of the texture view. /// /// - For 1D textures, this must be `D1`. /// - For 2D textures it must be one of `D2`, `D2Array`, `Cube`, or `CubeArray`. /// - For 3D textures it must be `D3`. pub dimension: Option<wgt::TextureViewDimension>, /// The allowed usage(s) for the texture view. Must be a subset of the usage flags of the texture. /// If not provided, defaults to the full set of usage flags of the texture. pub usage: Option<wgt::TextureUsages>, /// Range within the texture that is accessible via this view. pub range: wgt::ImageSubresourceRange,
}
#[derive(Debug, Copy, Clone, Error)] pubenum TextureViewNotRenderableReason { #[error("The texture this view references doesn't include the RENDER_ATTACHMENT usage. Provided usages: {0:?}")]
Usage(wgt::TextureUsages), #[error("The dimension of this texture view is not 2D. View dimension: {0:?}")]
Dimension(wgt::TextureViewDimension), #[error("This texture view has more than one mipmap level. View mipmap levels: {0:?}")]
MipLevelCount(u32), #[error("This texture view has more than one array layer. View array layers: {0:?}")]
ArrayLayerCount(u32), #[error( "The aspects of this texture view are a subset of the aspects in the original texture. Aspects: {0:?}"
)]
Aspects(hal::FormatAspects),
}
#[derive(Debug)] pubstruct TextureView { pub(crate) raw: Snatchable<Box<dyn hal::DynTextureView>>, // if it's a surface texture - it's none pub(crate) parent: Arc<Texture>, pub(crate) device: Arc<Device>, pub(crate) desc: HalTextureViewDescriptor, pub(crate) format_features: wgt::TextureFormatFeatures, /// This is `Err` only if the texture view is not renderable pub(crate) render_extent: Result<wgt::Extent3d, TextureViewNotRenderableReason>, pub(crate) samples: u32, pub(crate) selector: TextureSelector, /// The `label` from the descriptor used to create the resource. pub(crate) label: String, pub(crate) tracking_data: TrackingData,
}
impl Drop for TextureView { fn drop(&mutself) { iflet Some(raw) = self.raw.take() {
resource_log!("Destroy raw {}", self.error_ident()); unsafe { self.device.raw().destroy_texture_view(raw);
}
}
}
}
/// Describes a [`Sampler`] #[derive(Clone, Debug, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pubstruct SamplerDescriptor<'a> { /// Debug label of the sampler. /// /// This will show up in graphics debuggers for easy identification. pub label: Label<'a>, /// How to deal with out of bounds accesses in the u (i.e. x) direction pub address_modes: [wgt::AddressMode; 3], /// How to filter the texture when it needs to be magnified (made larger) pub mag_filter: wgt::FilterMode, /// How to filter the texture when it needs to be minified (made smaller) pub min_filter: wgt::FilterMode, /// How to filter between mip map levels pub mipmap_filter: wgt::FilterMode, /// Minimum level of detail (i.e. mip level) to use pub lod_min_clamp: f32, /// Maximum level of detail (i.e. mip level) to use pub lod_max_clamp: f32, /// If this is enabled, this is a comparison sampler using the given comparison function. pub compare: Option<wgt::CompareFunction>, /// Must be at least 1. If this is not 1, all filter modes must be linear. pub anisotropy_clamp: u16, /// Border color to use when address_mode is /// [`AddressMode::ClampToBorder`](wgt::AddressMode::ClampToBorder) pub border_color: Option<wgt::SamplerBorderColor>,
}
#[derive(Debug)] pubstruct Sampler { pub(crate) raw: ManuallyDrop<Box<dyn hal::DynSampler>>, pub(crate) device: Arc<Device>, /// The `label` from the descriptor used to create the resource. pub(crate) label: String, pub(crate) tracking_data: TrackingData, /// `true` if this is a comparison sampler pub(crate) comparison: bool, /// `true` if this is a filtering sampler pub(crate) filtering: bool,
}
impl Drop for Sampler { fn drop(&mutself) {
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. let raw = unsafe { ManuallyDrop::take(&mutself.raw) }; unsafe { self.device.raw().destroy_sampler(raw);
}
}
}
#[derive(Clone, Debug, Error)] #[non_exhaustive] pubenum CreateSamplerError { #[error(transparent)]
Device(#[from] DeviceError), #[error("Invalid lodMinClamp: {0}. Must be greater or equal to 0.0")]
InvalidLodMinClamp(f32), #[error("Invalid lodMaxClamp: {lod_max_clamp}. Must be greater or equal to lodMinClamp (which is {lod_min_clamp}).")]
InvalidLodMaxClamp {
lod_min_clamp: f32,
lod_max_clamp: f32,
}, #[error("Invalid anisotropic clamp: {0}. Must be at least 1.")]
InvalidAnisotropy(u16), #[error("Invalid filter mode for {filter_type:?}: {filter_mode:?}. When anistropic clamp is not 1 (it is {anisotropic_clamp}), all filter modes must be linear.")]
InvalidFilterModeWithAnisotropy {
filter_type: SamplerFilterErrorType,
filter_mode: wgt::FilterMode,
anisotropic_clamp: u16,
}, #[error(transparent)]
MissingFeatures(#[from] MissingFeatures),
}
#[derive(Clone, Debug, Error)] #[non_exhaustive] pubenum CreateQuerySetError { #[error(transparent)]
Device(#[from] DeviceError), #[error("QuerySets cannot be made with zero queries")]
ZeroCount, #[error("{count} is too many queries for a single QuerySet. QuerySets cannot be made more than {maximum} queries.")]
TooManyQueries { count: u32, maximum: u32 }, #[error(transparent)]
MissingFeatures(#[from] MissingFeatures),
}
#[derive(Debug)] pubstruct QuerySet { pub(crate) raw: ManuallyDrop<Box<dyn hal::DynQuerySet>>, pub(crate) device: Arc<Device>, /// The `label` from the descriptor used to create the resource. pub(crate) label: String, pub(crate) tracking_data: TrackingData, pub(crate) desc: wgt::QuerySetDescriptor<()>,
}
impl Drop for QuerySet { fn drop(&mutself) {
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. let raw = unsafe { ManuallyDrop::take(&mutself.raw) }; unsafe { self.device.raw().destroy_query_set(raw);
}
}
}
#[derive(Debug)] pubstruct Blas { pub(crate) raw: Snatchable<Box<dyn hal::DynAccelerationStructure>>, pub(crate) device: Arc<Device>, pub(crate) size_info: hal::AccelerationStructureBuildSizes, pub(crate) sizes: wgt::BlasGeometrySizeDescriptors, pub(crate) flags: wgt::AccelerationStructureFlags, pub(crate) update_mode: wgt::AccelerationStructureUpdateMode, pub(crate) built_index: RwLock<Option<NonZeroU64>>, pub(crate) handle: u64, /// The `label` from the descriptor used to create the resource. pub(crate) label: String, pub(crate) tracking_data: TrackingData,
}
impl Drop for Blas { fn drop(&mutself) {
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. iflet Some(raw) = self.raw.take() { unsafe { self.device.raw().destroy_acceleration_structure(raw);
}
}
}
}
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.