pub(super) struct LifetimeTracker<A: Api> {
    mapped: Vec<Stored<BufferId>>,
    pub future_suspected_buffers: Vec<Stored<BufferId>>,
    pub future_suspected_textures: Vec<Stored<TextureId>>,
    pub suspected_resources: SuspectedResources,
    active: Vec<ActiveSubmission<A>>,
    free_resources: NonReferencedResources<A>,
    ready_to_map: Vec<Valid<BufferId>>,
    work_done_closures: SmallVec<[SubmittedWorkDoneClosure; 1]>,
}
Expand description

Resource tracking for a device.

Host mapping buffers

A buffer cannot be mapped until all active queue submissions that use it have completed. To that end:

  • Each buffer’s LifeGuard::submission_index records the index of the most recent queue submission that uses that buffer.

  • Calling map_async adds the buffer to self.mapped, and changes Buffer::map_state to prevent it from being used in any new submissions.

  • When the device is polled, the following LifetimeTracker methods decide what should happen next:

    1. triage_mapped drains self.mapped, checking the submission index of each buffer against the queue submissions that have finished execution. Buffers used by submissions still in flight go in self.active[index].mapped, and the rest go into self.ready_to_map.

    2. triage_submissions moves entries in self.active[i] for completed submissions to self.ready_to_map. At this point, both self.active and self.ready_to_map are up to date with the given submission index.

    3. handle_mapping drains self.ready_to_map and actually maps the buffers, collecting a list of notification closures to call. But any buffers that were dropped by the user get moved to self.free_resources.

    4. cleanup frees everything in free_resources.

Only self.mapped holds a RefCount for the buffer; it is dropped by triage_mapped.

Fields§

§mapped: Vec<Stored<BufferId>>

Resources that the user has requested be mapped, but which are used by queue submissions still in flight.

§future_suspected_buffers: Vec<Stored<BufferId>>

Buffers can be used in a submission that is yet to be made, by the means of write_buffer(), so we have a special place for them.

§future_suspected_textures: Vec<Stored<TextureId>>

Textures can be used in the upcoming submission by write_texture.

§suspected_resources: SuspectedResources

Resources whose user handle has died (i.e. drop/destroy has been called) and will likely be ready for destruction soon.

§active: Vec<ActiveSubmission<A>>

Resources used by queue submissions still in flight. One entry per submission, with older submissions appearing before younger.

Entries are added by track_submission and drained by LifetimeTracker::triage_submissions. Lots of methods contribute data to particular entries.

§free_resources: NonReferencedResources<A>

Raw backend resources that are neither referenced nor used.

These are freed by LifeTracker::cleanup, which is called from periodic maintenance functions like Global::device_poll, and when a device is destroyed.

§ready_to_map: Vec<Valid<BufferId>>

Buffers the user has asked us to map, and which are not used by any queue submission still in flight.

§work_done_closures: SmallVec<[SubmittedWorkDoneClosure; 1]>

Queue “on_submitted_work_done” closures that were initiated for while there is no currently pending submissions. These cannot be immeidately invoked as they must happen after all mapped buffer callbacks are mapped, so we defer them here until the next time the device is maintained.

Implementations§

source§

impl<A: Api> LifetimeTracker<A>

source

pub fn new() -> Self

source

pub fn queue_empty(&self) -> bool

Return true if there are no queue submissions still in flight.

source

pub fn track_submission( &mut self, index: FenceValue, temp_resources: impl Iterator<Item = TempResource<A>>, encoders: Vec<EncoderInFlight<A>> )

Start tracking resources associated with a new queue submission.

source

pub fn post_submit(&mut self)

source

pub(crate) fn map(&mut self, value: Valid<BufferId>, ref_count: RefCount)

source

pub fn triage_submissions( &mut self, last_done: FenceValue, command_allocator: &Mutex<CommandAllocator<A>> ) -> SmallVec<[SubmittedWorkDoneClosure; 1]>

Sort out the consequences of completed submissions.

Assume that all submissions up through last_done have completed.

Return a list of SubmittedWorkDoneClosures to run.

source

pub fn cleanup(&mut self, device: &A::Device)

source

pub fn schedule_resource_destruction( &mut self, temp_resource: TempResource<A>, last_submit_index: FenceValue )

source

pub fn add_work_done_closure(&mut self, closure: SubmittedWorkDoneClosure)

source§

impl<A: HalApi> LifetimeTracker<A>

source

pub(super) fn triage_suspected<G: GlobalIdentityHandlerFactory>( &mut self, hub: &Hub<A, G>, trackers: &Mutex<Tracker<A>>, trace: Option<&Mutex<Trace>>, token: &mut Token<'_, Device<A>> )

Identify resources to free, according to trackers and self.suspected_resources.

Given trackers, the Tracker belonging to same Device as self, and hub, the Hub to which that Device belongs:

Remove from trackers each resource mentioned in self.suspected_resources. If trackers held the final reference to that resource, add it to the appropriate free list, to be destroyed by the hal:

Entrained resources

This function finds resources that are used only by other resources ready to be freed, and adds those to the free lists as well. For example, if there’s some texture T used only by some texture view TV, then if TV can be freed, T gets added to the free lists too.

Since wgpu-core resource ownership patterns are acyclic, we can visit each type that can be owned after all types that could possibly own it. This way, we can detect all free-able objects in a single pass, simply by starting with types that are roots of the ownership DAG (like render bundles) and working our way towards leaf types (like buffers).

source

pub(super) fn triage_mapped<G: GlobalIdentityHandlerFactory>( &mut self, hub: &Hub<A, G>, token: &mut Token<'_, Device<A>> )

Determine which buffers are ready to map, and which must wait for the GPU.

See the documentation for LifetimeTracker for details.

source

pub(super) fn handle_mapping<G: GlobalIdentityHandlerFactory>( &mut self, hub: &Hub<A, G>, raw: &A::Device, trackers: &Mutex<Tracker<A>>, token: &mut Token<'_, Device<A>> ) -> Vec<BufferMapPendingClosure>

Map the buffers in self.ready_to_map.

Return a list of mapping notifications to send.

See the documentation for LifetimeTracker for details.

Auto Trait Implementations§

§

impl<A> !RefUnwindSafe for LifetimeTracker<A>

§

impl<A> Send for LifetimeTracker<A>

§

impl<A> !Sync for LifetimeTracker<A>

§

impl<A> Unpin for LifetimeTracker<A>where <A as Api>::BindGroup: Unpin, <A as Api>::BindGroupLayout: Unpin, <A as Api>::Buffer: Unpin, <A as Api>::CommandBuffer: Unpin, <A as Api>::CommandEncoder: Unpin, <A as Api>::ComputePipeline: Unpin, <A as Api>::PipelineLayout: Unpin, <A as Api>::QuerySet: Unpin, <A as Api>::RenderPipeline: Unpin, <A as Api>::Sampler: Unpin, <A as Api>::Texture: Unpin, <A as Api>::TextureView: Unpin,

§

impl<A> !UnwindSafe for LifetimeTracker<A>

Blanket Implementations§

source§

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

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

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

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

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

source§

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

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for Twhere 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 Twhere 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 Twhere 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> WasmNotSend for Twhere T: Send,