Skip to main content

ResourceGraph

Struct ResourceGraph 

Source
pub struct ResourceGraph {
    graph: Dag<Node>,
}
Expand description

A directed acyclic graph of wgpu resources.

Every edge points from a dependency to a resource built from it, so the dependents of a node are exactly the nodes reachable from it. The graph refuses an edge that would close a cycle, which is what lets Self::maintain rebuild its dirty nodes in dependency order.

Fields§

§graph: Dag<Node>

Implementations§

Source§

impl ResourceGraph

Source

pub fn new() -> Self

Create an empty graph.

Source

pub fn len(&self) -> usize

Number of resources in the graph.

A resource no id holds any more is still counted until the next Self::maintain collects it.

Source

pub fn is_empty(&self) -> bool

Whether the graph holds no resources.

Source

pub fn info(&self) -> ResourceGraphInfo

The graph’s shape as plain data.

Counts what Self::len counts: a resource nothing holds any more is still included until the next Self::maintain collects it.

Source

pub fn resource_infos(&self) -> Vec<ResourceInfo>

Every resource slot, in node-slot order, as plain data.

The serialisable counterpart of Self::nodes: same order and same count, but reporting the id rather than borrowing the wgpu resource.

Source

pub fn nodes(&self) -> impl Iterator<Item = NodeInfo<'_>>

Every resource in the graph, in node-slot order.

Each node’s id is stable while the resource lives, so a caller can report it, sort by it, and resolve it back with Self::resolve. The walk covers every slot the graph has ever used, so it costs the peak node count rather than the current one.

A resource no id holds any more is still listed until the next Self::maintain collects it, exactly as Self::len counts it.

Source

pub fn resolve(&self, id: ResId) -> Option<ResHandle>

The handle a ResId names, or None when no resource is there or nothing holds it any more.

The handle is erased — its kind is only known from the resource — and holds one strong reference, so resolving an id keeps the resource alive like any other handle does. An id whose slot has been recycled no longer resolves, which is what keeps a stale id from naming a later resource; a resource nothing holds is on its way out at the next Self::maintain and cannot be named again, so the call reports None rather than inventing a reference to it.

Source

pub fn insert<R: ResourceKind>( &mut self, resource: R, rebuild: Option<Rebuild>, ) -> ResHandle<R>

Add resource and return an id holding one strong reference to it.

The resource lives while any id to it does, and while any node built from it does; Self::maintain collects it once both are gone. So a caller that keeps the returned id keeps the resource, and one that drops it — without a dependent — gives the resource up.

The kind of the returned id is the resource’s own: graph.insert(buffer, None) yields a buffer id, and insert(Virtual, None) a virtual one. The node is added at once; declare what it was built from with Self::add_dependency.

Pass a Rebuild recipe for a derived resource — a bind group, say — that Self::maintain rebuilds once one of its inputs is replaced. The recipe reads its inputs back out of the graph by id, so declare them with Self::add_dependency as well: the edges decide when to rebuild, and the recipe decides what to build from. None is a resource the graph cannot build again on its own.

Source

pub fn add_dependency<D, R>( &mut self, dependent: &ResHandle<R>, dependency: &ResHandle<D>, )

Record that the resource behind dependent was built from the one behind dependency, so replacing or rebuilding the latter reaches the former.

The dependency may be of any kind: one bind group is built from buffers, a view and a sampler all at once. Call this once per input; declaring the same pair twice records one edge, since a node depends on another once or not at all.

The dependent holds one strong reference to the dependency on behalf of the edge, so a resource counts its dependents among the references that keep it alive: a resource nothing else holds lives exactly while something is built from it. Declaring the same edge twice records it once, and so takes one reference, not two.

An optional input is the caller’s to skip — if let Some(id) = ... around the call, which reads the way the id itself does — rather than something this method silently ignores: an absent dependency is a decision about the caller’s graph, not an edge.

§Panics

Panics if the edge would close a cycle. A cycle means the declared dependencies are not a build order at all, so it is refused where it is declared rather than corrupting a later walk.

Source

pub fn get<R: ResourceKind>(&self, id: &ResHandle<R>) -> Option<&R>

Borrow the resource behind id.

The id says what it names, so this is the buffer, texture, view, sampler or bind group itself; the erased ResHandle<Resource> is how a caller reads a resource whose kind it does not know. None when the id is unknown — nothing else can make it fail, since an id only ever names a resource of its own kind.

Source

pub fn replace<R: ResourceKind>( &mut self, id: &ResHandle<R>, resource: impl Into<R>, ) -> Option<R>

Replace the resource behind id and mark it — and every resource transitively built from it — dirty.

The replacement has to be of the id’s own kind: a node never changes kind, so an id that names a buffer cannot come to name a sampler.

Returns the previous handle, or None if id is unknown.

Source

fn replace_resource( &mut self, node: NodeId, resource: Resource, ) -> Option<Resource>

Swap the resource stored at node, marking it and its dependents dirty, and hand back what was there.

Source

pub fn maintain(&mut self)

Bring the graph up to date: collect the resources nothing holds any more, and rebuild what is dirty.

Call this once per frame before reading the resources, so that every change made since the last call takes effect at a single point rather than at each change.

A resource is collected once nothing holds it: no ResHandle names it and no node is built from it. Dropping the last id to a resource — or to a node built from it — is what gives the resource up, and this pass is where that takes effect. There is no removal call: a resource some id or some dependent still holds stays, and one nothing holds goes.

Collecting a node releases the references it held on its own dependencies, which may leave one of those with nothing holding it either. The sweep therefore repeats until a pass collects nothing, so a chain of resources that only a dropped consumer kept alive goes in one call.

The passes run in a fixed order:

  1. Every resource nothing holds is collected, repeating until nothing more is.
  2. Every dirty resource with a recipe is rebuilt, in dependency order so that a rebuild sees its already-rebuilt inputs.

Collecting before rebuilding means a resource that is about to be collected is never rebuilt, and a dirty node without a recipe stays dirty: the graph cannot build it again by itself.

Source

pub fn dependencies<R>( &self, id: &ResHandle<R>, ) -> impl Iterator<Item = ResHandle> + '_

The immediate dependencies recorded for id.

A node’s inputs may be of any kind, so the ids come back erased. Each id is a strong reference in its own right: holding one keeps the input alive, exactly as holding any other id does.

Source

fn id_for(&self, node: NodeId) -> ResHandle

An id to node, taking one more strong reference to it.

The caller asks about the dependency of a node it holds an id to, so the dependent’s own reference to that dependency is still in place and the upgrade cannot fail.

Source

fn rebuild_dirty(&mut self)

Rebuild every dirty resource that has a recipe, in dependency order.

Dependents are visited after their dependencies, so a rebuild observes already-updated inputs.

Source

fn mark_dependents_dirty(&mut self, node: NodeId)

Mark node and every node built from it dirty.

Trait Implementations§

Source§

impl Debug for ResourceGraph

Source§

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

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

impl Default for ResourceGraph

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

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
§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<T> Downcast<T> for T

§

fn downcast(&self) -> &T

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
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> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

§

impl<T, S> SimdFrom<T, S> for T
where S: Simd,

§

fn simd_from(_simd: S, value: T) -> T

§

impl<F, T, S> SimdInto<T, S> for F
where T: SimdFrom<F, S>, S: Simd,

§

fn simd_into(self, simd: S) -> T

Source§

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

Source§

type Error = !

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

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

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

Source§

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.
§

impl<T> Upcast<T> for T

§

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

§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more