pub struct ImageResidency { /* private fields */ }Expand description
The images resident in the atlas array, keyed by blob identity.
One per compiler (and so one per surface). Its frame clock is advanced by
begin_frame, which is also where the age-based reap
runs — before any of the frame’s own resolutions, so a rectangle freed this
frame is available to this frame’s allocations and its clear is ordered
ahead of their uploads.
It also owns the atlas allocator the glyph policy packs into — see this
module’s doc and allocator_mut.
Implementations§
Source§impl ImageResidency
impl ImageResidency
Sourcepub fn new(budget: AtlasBudget) -> Self
pub fn new(budget: AtlasBudget) -> Self
A residency over budget’s atlas geometry.
FRUST_ENGINE_NO_ATLAS is consulted here, once, rather than per
resolution: the switch is process-global and cached, so re-reading it on
a hot path would buy nothing but a lock. A residency constructed with
the switch set is exactly disabled.
Sourcepub fn disabled(budget: AtlasBudget) -> Self
pub fn disabled(budget: AtlasBudget) -> Self
A residency that refuses every image, allocating no atlas at all.
What FRUST_ENGINE_NO_ATLAS selects, and what a caller wanting the same
effect programmatically constructs. Every resolve
answers ImageSkip::AtlasDisabled, so image draws are dropped with a
logged reason rather than painted from an atlas that does not exist.
Sourcepub fn budget(&self) -> AtlasBudget
pub fn budget(&self) -> AtlasBudget
The atlas geometry this residency allocates within.
Sourcepub fn allocator(&self) -> &ImageCache
pub fn allocator(&self) -> &ImageCache
The single atlas allocator, for reading.
Enough to resolve a handle either side allocated
(ImageCache::get) or to count the layers created so far, without
the mutable borrow allocation needs.
Sourcepub fn allocator_mut(&mut self) -> &mut ImageCache
pub fn allocator_mut(&mut self) -> &mut ImageCache
The single atlas allocator, for allocating through.
This is the seam the glyph policy takes its slots from — see this
module’s doc for why one cache rather than two is a correctness
requirement. ImageIds and rectangles handed out through here and
through resolve come from the same packer and the
same id space, so a glyph and an image can never be given the same
handle or overlapping texels.
The contract a borrower keeps: allocate what you like, and
deallocate only handles you allocated yourself. This residency’s entry
map records the rectangles it allocated and nothing re-checks them;
freeing one of them from outside would leave an entry claiming a
rectangle the packer has since handed to someone else. Nothing here
enforces that, because the type the two sides must share is
vello_common’s own and cannot carry an ownership tag — the glyph
policy deallocates strictly inside glifo’s eviction, over the handles
in its own entry map.
Sourcepub fn is_disabled(&self) -> bool
pub fn is_disabled(&self) -> bool
Whether this residency refuses every image.
Sourcepub fn entry_count(&self) -> usize
pub fn entry_count(&self) -> usize
How many images are currently resident.
Sourcepub fn layers(&self) -> u32
pub fn layers(&self) -> u32
How many atlas layers have been created so far.
The array texture must be at least this deep before the frame’s uploads are written.
Read off the shared allocator rather than accumulated from this
residency’s own allocations, so a layer the glyph policy created
counts too: the two classes pack into one array, and an array sized to
the image half alone would refuse to hold the glyph half’s pages. The
count only ever grows — MultiAtlasManager appends layers and never
drops one — so a depth reported on an earlier frame stays valid.
Sourcepub fn skipped(&self) -> u64
pub fn skipped(&self) -> u64
How many resolutions have been refused over this residency’s lifetime.
Counts only images that could not be uploaded at all — a format or
extent the conversion refuses, a disabled atlas, or an atlas with no
room left and nothing evictable to make room with. A source merely
larger than one atlas layer is minified to fit, and one that displaced
another image is counted by
pressure_evictions instead; neither
reaches this counter.
Sourcepub fn pressure_evictions(&self) -> u64
pub fn pressure_evictions(&self) -> u64
How many resident images have been evicted to make room for another over this residency’s lifetime.
The price of never refusing a draw the atlas could hold something for: each one is an image that will re-upload the next frame it is drawn on. A steady screen leaves this at zero; a scroll through more distinct images than the atlas has rectangles for grows it once per displaced image, which is the signal that the budget — not the mechanism — is what a frame is paying for.
Sourcepub fn frame_pressure_evictions(&self) -> u64
pub fn frame_pressure_evictions(&self) -> u64
How many resident images the current frame has evicted to make room.
Zeroed by begin_frame, so a per-frame report reads
this rather than differencing
pressure_evictions itself.
Sourcepub fn minified(&self) -> u64
pub fn minified(&self) -> u64
How many sources have been downsampled to fit the atlas over this residency’s lifetime.
Observational, and the counter that makes “an image too large for the atlas is minified, not dropped” measurable rather than asserted.
Sourcepub fn evictions(&self) -> &[AtlasRegion]
pub fn evictions(&self) -> &[AtlasRegion]
The regions whose texels must be cleared before the pending uploads.
Pending rather than per-frame: an entry freed on a frame nobody serviced is still waiting to be cleared on the next one. Both kinds of eviction land here — the age-based reap at the head of a frame and a rectangle taken back under pressure mid-frame — so the consumer’s clear-then-upload contract covers the second without knowing it exists.
Sourcepub fn uploads(&self) -> &[ImageUpload]
pub fn uploads(&self) -> &[ImageUpload]
The regions whose texels must be written after the pending evictions.
Pending rather than per-frame: an image made resident on a frame that was refused is still waiting to be written on the next one.
Sourcepub fn plan(&self) -> (Vec<AtlasRegion>, Vec<ImageUpload>)
pub fn plan(&self) -> (Vec<AtlasRegion>, Vec<ImageUpload>)
A copy of the pending clear-then-write plan, evictions first.
A copy, not a drain: the plan stays pending until
acknowledge_plan says it was serviced against
a live atlas, so a frame refused after compiling re-emits the same plan
on the next frame rather than losing it (see the module doc). The upload
pixels are behind an Arc, so a re-emitted plan copies handles rather
than texels, and the steady-state plan is empty on both counts.
Sourcepub fn has_pending_plan(&self) -> bool
pub fn has_pending_plan(&self) -> bool
Whether any part of the pending plan is still unserviced.
Sourcepub fn acknowledge_plan(&mut self)
pub fn acknowledge_plan(&mut self)
Record that the pending plan reached the atlas array, clearing it.
Call this only once every region it names has actually been written or cleared. Calling it on a frame that was refused, or whose writes the array declined, is exactly the defect the pending plan exists to prevent: the entry map would go on claiming an image is resident whose texels are whatever the atlas texture happened to hold.
Sourcepub fn begin_frame(&mut self)
pub fn begin_frame(&mut self)
Advance the frame clock and reclaim everything unseen for
MAX_UNSEEN_FRAMES.
Call once at the head of a frame, before any resolve.
An unacknowledged plan deliberately survives this: the frame that was to
service it may have been refused, and dropping it here is what would turn
a refused frame into a permanently unwritten atlas region.
Sourcepub fn resolve(&mut self, data: &ImageData) -> Result<ResidentImage, ImageSkip>
pub fn resolve(&mut self, data: &ImageData) -> Result<ResidentImage, ImageSkip>
The atlas rectangle for data’s pixels, allocating and scheduling an
upload on the first frame that asks for it.
§Errors
Returns the ImageSkip naming why the image was refused. Every
refusal happens before any vello_common call that could assert on the
same condition, so an image the renderer cannot hold is a skipped draw
rather than a panicked frame (E17).