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
impl ResourceGraph
Sourcepub fn len(&self) -> usize
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.
Sourcepub fn info(&self) -> ResourceGraphInfo
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.
Sourcepub fn resource_infos(&self) -> Vec<ResourceInfo>
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.
Sourcepub fn nodes(&self) -> impl Iterator<Item = NodeInfo<'_>>
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.
Sourcepub fn resolve(&self, id: ResId) -> Option<ResHandle>
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.
Sourcepub fn insert<R: ResourceKind>(
&mut self,
resource: R,
rebuild: Option<Rebuild>,
) -> ResHandle<R>
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.
Sourcepub fn add_dependency<D, R>(
&mut self,
dependent: &ResHandle<R>,
dependency: &ResHandle<D>,
)
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.
Sourcepub fn get<R: ResourceKind>(&self, id: &ResHandle<R>) -> Option<&R>
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.
Sourcepub fn replace<R: ResourceKind>(
&mut self,
id: &ResHandle<R>,
resource: impl Into<R>,
) -> Option<R>
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.
Sourcefn replace_resource(
&mut self,
node: NodeId,
resource: Resource,
) -> Option<Resource>
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.
Sourcepub fn maintain(&mut self)
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:
- Every resource nothing holds is collected, repeating until nothing more is.
- 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.
Sourcepub fn dependencies<R>(
&self,
id: &ResHandle<R>,
) -> impl Iterator<Item = ResHandle> + '_
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.
Sourcefn id_for(&self, node: NodeId) -> ResHandle
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.
Sourcefn rebuild_dirty(&mut self)
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.
Sourcefn mark_dependents_dirty(&mut self, node: NodeId)
fn mark_dependents_dirty(&mut self, node: NodeId)
Mark node and every node built from it dirty.
Trait Implementations§
Source§impl Debug for ResourceGraph
impl Debug for ResourceGraph
Auto Trait Implementations§
impl !RefUnwindSafe for ResourceGraph
impl !Send for ResourceGraph
impl !Sync for ResourceGraph
impl !UnwindSafe for ResourceGraph
impl Forget for ResourceGraph
impl Freeze for ResourceGraph
impl Unpin for ResourceGraph
impl UnsafeUnpin for ResourceGraph
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
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 moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
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