pub struct Device<A: HalApi> {
Show 25 fields raw: Option<A::Device>, pub(crate) adapter: Arc<Adapter<A>>, pub(crate) queue: OnceCell<Weak<Queue<A>>>, queue_to_drop: OnceCell<A::Queue>, pub(crate) zero_buffer: Option<A::Buffer>, pub(crate) info: ResourceInfo<Device<A>>, pub(crate) command_allocator: CommandAllocator<A>, pub(crate) active_submission_index: AtomicU64, pub(crate) fence: RwLock<Option<A::Fence>>, pub(crate) snatchable_lock: SnatchLock, pub(crate) valid: AtomicBool, pub(crate) trackers: Mutex<Tracker<A>>, pub(crate) tracker_indices: TrackerIndexAllocators, life_tracker: Mutex<LifetimeTracker<A>>, pub(crate) bgl_pool: ResourcePool<EntryMap, BindGroupLayout<A>>, pub(crate) alignments: Alignments, pub(crate) limits: Limits, pub(crate) features: Features, pub(crate) downlevel: DownlevelCapabilities, pub(crate) instance_flags: InstanceFlags, pub(crate) pending_writes: Mutex<Option<PendingWrites<A>>>, pub(crate) deferred_destroy: Mutex<Vec<DeferredDestroy<A>>>, pub(crate) trace: Mutex<Option<Trace>>, pub(crate) usage_scopes: Mutex<Vec<(BufferUsageScope<A>, TextureUsageScope<A>)>>, temp_suspected: Mutex<Option<ResourceMaps<A>>>,
}
Expand description

Structure describing a logical device. Some members are internally mutable, stored behind mutexes.

TODO: establish clear order of locking for these: life_tracker, trackers, render_passes, pending_writes, trace.

Currently, the rules are:

  1. life_tracker is locked after hub.devices, enforced by the type system
  2. self.trackers is locked last (unenforced)
  3. self.trace is locked last (unenforced)

Right now avoid locking twice same resource or registry in a call execution and minimize the locking to the minimum scope possible Unless otherwise specified, no lock may be acquired while holding another lock. This means that you must inspect function calls made while a lock is held to see what locks the callee may try to acquire.

As far as this point: device_maintain_ids locks Device::lifetime_tracker, and calls… triage_suspected locks Device::trackers, and calls… Registry::unregister locks Registry::storage

Important: When locking pending_writes please check that trackers is not locked trackers should be locked only when needed for the shortest time possible

Fields§

§raw: Option<A::Device>§adapter: Arc<Adapter<A>>§queue: OnceCell<Weak<Queue<A>>>§queue_to_drop: OnceCell<A::Queue>§zero_buffer: Option<A::Buffer>§info: ResourceInfo<Device<A>>§command_allocator: CommandAllocator<A>§active_submission_index: AtomicU64§fence: RwLock<Option<A::Fence>>§snatchable_lock: SnatchLock§valid: AtomicBool

Is this device valid? Valid is closely associated with “lose the device”, which can be triggered by various methods, including at the end of device destroy, and by any GPU errors that cause us to no longer trust the state of the device. Ideally we would like to fold valid into the storage of the device itself (for example as an Error enum), but unfortunately we need to continue to be able to retrieve the device in poll_devices to determine if it can be dropped. If our internal accesses of devices were done through ref-counted references and external accesses checked for Error enums, we wouldn’t need this. For now, we need it. All the call sites where we check it are areas that should be revisited if we start using ref-counted references for internal access.

§trackers: Mutex<Tracker<A>>

All live resources allocated with this Device.

Has to be locked temporarily only (locked last) and never before pending_writes

§tracker_indices: TrackerIndexAllocators§life_tracker: Mutex<LifetimeTracker<A>>§bgl_pool: ResourcePool<EntryMap, BindGroupLayout<A>>

Pool of bind group layouts, allowing deduplication.

§alignments: Alignments§limits: Limits§features: Features§downlevel: DownlevelCapabilities§instance_flags: InstanceFlags§pending_writes: Mutex<Option<PendingWrites<A>>>§deferred_destroy: Mutex<Vec<DeferredDestroy<A>>>§trace: Mutex<Option<Trace>>§usage_scopes: Mutex<Vec<(BufferUsageScope<A>, TextureUsageScope<A>)>>§temp_suspected: Mutex<Option<ResourceMaps<A>>>

Temporary storage, cleared at the start of every call, retained only to save allocations.

Implementations§

source§

impl<A: HalApi> Device<A>

source

pub(crate) fn raw(&self) -> &A::Device

source

pub(crate) fn require_features( &self, feature: Features ) -> Result<(), MissingFeatures>

source

pub(crate) fn require_downlevel_flags( &self, flags: DownlevelFlags ) -> Result<(), MissingDownlevelFlags>

source§

impl<A: HalApi> Device<A>

source

pub(crate) fn new( raw_device: A::Device, raw_queue: &A::Queue, adapter: &Arc<Adapter<A>>, desc: &DeviceDescriptor<'_>, trace_path: Option<&Path>, instance_flags: InstanceFlags ) -> Result<Self, CreateDeviceError>

source

pub fn is_valid(&self) -> bool

source

pub fn check_is_valid(&self) -> Result<(), DeviceError>

source

pub(crate) fn release_queue(&self, queue: A::Queue)

source

pub(crate) fn lock_life<'a>(&'a self) -> MutexGuard<'a, LifetimeTracker<A>>

source

pub(crate) fn deferred_resource_destruction(&self)

Run some destroy operations that were deferred.

Destroying the resources requires taking a write lock on the device’s snatch lock, so a good reason for deferring resource destruction is when we don’t know for sure how risky it is to take the lock (typically, it shouldn’t be taken from the drop implementation of a reference-counted structure). The snatch lock must not be held while this function is called.

source

pub fn get_queue(&self) -> Option<Arc<Queue<A>>>

source

pub fn set_queue(&self, queue: Arc<Queue<A>>)

source

pub(crate) fn maintain<'this>( &'this self, fence_guard: RwLockReadGuard<'_, Option<A::Fence>>, maintain: Maintain<WrappedSubmissionIndex>, snatch_guard: SnatchGuard<'_> ) -> Result<(UserClosures, bool), WaitIdleError>

Check this device for completed commands.

The maintain argument tells how the maintenance function should behave, either blocking or just polling the current state of the gpu.

Return a pair (closures, queue_empty), where:

  • closures is a list of actions to take: mapping buffers, notifying the user

  • queue_empty is a boolean indicating whether there are more queue submissions still in flight. (We have to take the locks needed to produce this information for other reasons, so we might as well just return it to our callers.)

source

pub(crate) fn untrack(&self, trackers: &Tracker<A>)

source

pub(crate) fn create_buffer( self: &Arc<Self>, desc: &BufferDescriptor<'_>, transient: bool ) -> Result<Buffer<A>, CreateBufferError>

source

pub(crate) fn create_texture_from_hal( self: &Arc<Self>, hal_texture: A::Texture, hal_usage: TextureUses, desc: &TextureDescriptor<'_>, format_features: TextureFormatFeatures, clear_mode: TextureClearMode<A> ) -> Texture<A>

source

pub fn create_buffer_from_hal( self: &Arc<Self>, hal_buffer: A::Buffer, desc: &BufferDescriptor<'_> ) -> Buffer<A>

source

pub(crate) fn create_texture( self: &Arc<Self>, adapter: &Adapter<A>, desc: &TextureDescriptor<'_> ) -> Result<Texture<A>, CreateTextureError>

source

pub(crate) fn create_texture_view( self: &Arc<Self>, texture: &Arc<Texture<A>>, desc: &TextureViewDescriptor<'_> ) -> Result<TextureView<A>, CreateTextureViewError>

source

pub(crate) fn create_sampler( self: &Arc<Self>, desc: &SamplerDescriptor<'_> ) -> Result<Sampler<A>, CreateSamplerError>

source

pub(crate) fn create_shader_module<'a>( self: &Arc<Self>, desc: &ShaderModuleDescriptor<'a>, source: ShaderModuleSource<'a> ) -> Result<ShaderModule<A>, CreateShaderModuleError>

source

pub(crate) unsafe fn create_shader_module_spirv<'a>( self: &Arc<Self>, desc: &ShaderModuleDescriptor<'a>, source: &'a [u32] ) -> Result<ShaderModule<A>, CreateShaderModuleError>

source

pub(crate) fn create_command_encoder( self: &Arc<Self>, label: &Label<'_> ) -> Result<CommandBuffer<A>, DeviceError>

source

pub(crate) fn make_late_sized_buffer_groups( shader_binding_sizes: &HashMap<ResourceBinding, BufferSize, BuildHasherDefault<FxHasher>>, layout: &PipelineLayout<A> ) -> ArrayVec<LateSizedBufferGroup, { hal::MAX_BIND_GROUPS }>

Generate information about late-validated buffer bindings for pipelines.

source

pub(crate) fn create_bind_group_layout( self: &Arc<Self>, label: &Label<'_>, entry_map: EntryMap, origin: Origin ) -> Result<BindGroupLayout<A>, CreateBindGroupLayoutError>

source

pub(crate) fn create_buffer_binding<'a>( self: &Arc<Self>, bb: &BufferBinding, binding: u32, decl: &BindGroupLayoutEntry, used_buffer_ranges: &mut Vec<BufferInitTrackerAction<A>>, dynamic_binding_info: &mut Vec<BindGroupDynamicBindingData>, late_buffer_binding_sizes: &mut HashMap<u32, BufferSize, BuildHasherDefault<FxHasher>>, used: &mut BindGroupStates<A>, storage: &'a Storage<Buffer<A>>, limits: &Limits, snatch_guard: &'a SnatchGuard<'a> ) -> Result<BufferBinding<'a, A>, CreateBindGroupError>

source

fn create_sampler_binding<'a>( self: &Arc<Self>, used: &BindGroupStates<A>, storage: &'a Storage<Sampler<A>>, id: Id<Sampler> ) -> Result<&'a Sampler<A>, CreateBindGroupError>

source

pub(crate) fn create_texture_binding<'a>( self: &Arc<Self>, binding: u32, decl: &BindGroupLayoutEntry, storage: &'a Storage<TextureView<A>>, id: Id<TextureView>, used: &mut BindGroupStates<A>, used_texture_ranges: &mut Vec<TextureInitTrackerAction<A>>, snatch_guard: &'a SnatchGuard<'a> ) -> Result<TextureBinding<'a, A>, CreateBindGroupError>

source

pub(crate) fn create_bind_group( self: &Arc<Self>, layout: &Arc<BindGroupLayout<A>>, desc: &BindGroupDescriptor<'_>, hub: &Hub<A> ) -> Result<BindGroup<A>, CreateBindGroupError>

source

pub(crate) fn check_array_binding( features: Features, count: Option<NonZeroU32>, num_bindings: usize ) -> Result<(), CreateBindGroupError>

source

pub(crate) fn texture_use_parameters( self: &Arc<Self>, binding: u32, decl: &BindGroupLayoutEntry, view: &TextureView<A>, expected: &'static str ) -> Result<(TextureUsages, TextureUses), CreateBindGroupError>

source

pub(crate) fn create_pipeline_layout( self: &Arc<Self>, desc: &PipelineLayoutDescriptor<'_>, bgl_registry: &Registry<BindGroupLayout<A>> ) -> Result<PipelineLayout<A>, CreatePipelineLayoutError>

source

pub(crate) fn derive_pipeline_layout( self: &Arc<Self>, implicit_context: Option<ImplicitPipelineContext>, derived_group_layouts: ArrayVec<EntryMap, { hal::MAX_BIND_GROUPS }>, bgl_registry: &Registry<BindGroupLayout<A>>, pipeline_layout_registry: &Registry<PipelineLayout<A>> ) -> Result<Arc<PipelineLayout<A>>, ImplicitLayoutError>

source

pub(crate) fn create_compute_pipeline( self: &Arc<Self>, desc: &ComputePipelineDescriptor<'_>, implicit_context: Option<ImplicitPipelineContext>, hub: &Hub<A> ) -> Result<ComputePipeline<A>, CreateComputePipelineError>

source

pub(crate) fn create_render_pipeline( self: &Arc<Self>, adapter: &Adapter<A>, desc: &RenderPipelineDescriptor<'_>, implicit_context: Option<ImplicitPipelineContext>, hub: &Hub<A> ) -> Result<RenderPipeline<A>, CreateRenderPipelineError>

source

pub unsafe fn create_pipeline_cache( self: &Arc<Self>, desc: &PipelineCacheDescriptor<'_> ) -> Result<PipelineCache<A>, CreatePipelineCacheError>

§Safety

The data field on desc must have previously been returned from crate::global::Global::pipeline_cache_get_data

source

pub(crate) fn get_texture_format_features( &self, adapter: &Adapter<A>, format: TextureFormat ) -> TextureFormatFeatures

source

pub(crate) fn describe_format_features( &self, adapter: &Adapter<A>, format: TextureFormat ) -> Result<TextureFormatFeatures, MissingFeatures>

source

pub(crate) fn wait_for_submit( &self, submission_index: FenceValue ) -> Result<(), WaitIdleError>

source

pub(crate) fn create_query_set( self: &Arc<Self>, desc: &QuerySetDescriptor<'_> ) -> Result<QuerySet<A>, CreateQuerySetError>

source

pub(crate) fn lose(&self, message: &str)

source

pub(crate) fn release_gpu_resources(&self)

source

pub(crate) fn new_usage_scope(&self) -> UsageScope<'_, A>

source

pub fn get_hal_counters(&self) -> HalCounters

source§

impl<A: HalApi> Device<A>

source

pub(crate) fn destroy_command_buffer(&self, cmd_buf: CommandBuffer<A>)

source

pub(crate) fn prepare_to_die(&self)

Wait for idle and remove resources that we can, before we die.

Trait Implementations§

source§

impl<A: HalApi> Debug for Device<A>

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl<A: HalApi> Drop for Device<A>

source§

fn drop(&mut self)

Executes the destructor for this type. Read more
source§

impl<A: HalApi> Resource for Device<A>

source§

const TYPE: &'static str = "Device"

§

type Marker = Device

source§

fn as_info(&self) -> &ResourceInfo<Self>

source§

fn as_info_mut(&mut self) -> &mut ResourceInfo<Self>

source§

fn label(&self) -> &str

Returns a string identifying this resource for logging and errors. Read more
source§

fn ref_count(self: &Arc<Self>) -> usize

source§

fn is_unique(self: &Arc<Self>) -> bool

source§

fn is_equal(self: &Arc<Self>, other: &Arc<Self>) -> bool

source§

fn error_ident(&self) -> ResourceErrorIdent

Auto Trait Implementations§

§

impl<A> !Freeze for Device<A>

§

impl<A> !RefUnwindSafe for Device<A>

§

impl<A> Send for Device<A>

§

impl<A> Sync for Device<A>

§

impl<A> Unpin for Device<A>
where A: Unpin, <A as Api>::Buffer: Unpin, <A as Api>::CommandBuffer: Unpin, <A as Api>::CommandEncoder: Unpin, <A as Api>::Device: Unpin, <A as Api>::Fence: Unpin, <A as Api>::Queue: Unpin,

§

impl<A> !UnwindSafe for Device<A>

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> Downcast<T> for T

source§

fn downcast(&self) -> &T

source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<T> Upcast<T> for T

source§

fn upcast(&self) -> Option<&T>

source§

impl<T> WasmNotSend for T
where T: Send,

source§

impl<T> WasmNotSendSync for T

source§

impl<T> WasmNotSync for T
where T: Sync,