pub struct GlyphAtlas {
pub size: u32,
pub pixels: Vec<u8>,
pub dirty: bool,
pub epoch: u64,
pub stamp: u64,
/* private fields */
}Expand description
How the page makes room. A slot handed out during a
frame is never moved or overwritten before that frame is presented:
the quads already emitted, the text templates built and the cell
tables filled all carry its texel rect, and nothing walks them again.
So a page that fills mid-frame is extended — doubled with its
pixels kept where they are, which leaves every texel rect valid, since
uv is in texels and the renderer divides by the page’s size at draw
time — and the reset that reclaims it waits for the next
begin_frame, before anything is emitted. The page then starts that
frame empty at its base size and holds that frame’s set alone; if the
set does not fit it, it is larger than the page and the page keeps the
growth. Most fills never get as far as mid-frame:
begin_frame sees one coming in the rows the last frames opened and
empties the page first. A page at MAX_ATLAS_SIZE cannot extend: there
the request is refused for this frame (the glyph is not drawn, an
image draws from a texture of its own) and the next frame, which
short asks for, starts on an empty page.
A page that began the frame empty and still refuses holds a set bigger
than itself, and the next frame would refuse the same. Its
refusals are kept, and until the page is next emptied the atlas
measures what each frame looks up: stamp moves every frame, so the
caches that keep slots look theirs up again, and each distinct slot’s
texels are counted once. A frame that wanted a refused glyph and whose
set fits in what the page held is short, and the next frame begins
on an empty page that takes it — the view has scrolled to a part of
the set. One that did not fit keeps the page as it is.
An emptied page is not drawn from again, but it is kept for the frame
that begins on the empty one. A glyph or shape that
frame looks up and the old page held is copied across, not
rasterized again: the frame after a reset is the whole visible set
looked up at once — kawoosh’s window, ~600 glyphs, was 2.5–5.3 ms of
rasterizing where the copy is a fraction of one. Only what the frame
looks up is copied, so the page still holds that frame’s set alone.
clear, for a raster mode that changed, keeps nothing.
Fields§
§size: u32§pixels: Vec<u8>RGBA, sizesize4.
dirty: boolSet when pixels changed since the renderer last consumed them.
epoch: u64Bumped whenever the page is replaced — reset, or resized — so renderers re-upload it whole and caches that stamped it re-look their slots up. A resize keeps every slot where it was.
stamp: u64What caches that keep slots across frames — text templates, cell
tables — key them on: it moves with epoch, and on every frame
while refusals are pending, so that those frames look every
slot they use up again and are measured.
Implementations§
Source§impl GlyphAtlas
impl GlyphAtlas
pub fn new() -> GlyphAtlas
pub fn with_size(size: u32) -> GlyphAtlas
Sourcepub fn begin_frame(&mut self)
pub fn begin_frame(&mut self)
A frame begins, before anything is emitted — the one point where
the page can be emptied without a quad sampling what it dropped.
It is emptied, back at its base size, when the last frame extended
it or was refused room (short) — and when it is about to fill:
fewer rows free than two frames open at the rate they lately have.
A set that turns
over a little each frame, a list scrolling through fonts, fills
the page every so often, and the rows foresee it, so the frame
that would have extended the page mid-emit — a page four times
the size, its rows copied, a texture made and uploaded twice —
begins on an empty one instead. A fill it does not foresee still
extends.
A page that needs emptying within two frames of the last time is too small for its set and the rate it turns over at, and grows instead: an extension is kept, and a page about to fill doubles with its slots in place. That is F83’s thrash, a set between one page and two, measured by what the page does rather than by which glyphs come back; a fill long after the last empties it.
A page with refusals pending is emptied when the last frame wanted one and its set fits (see the type’s note); otherwise the frame ahead is measured.
Sourcepub fn clear(&mut self)
pub fn clear(&mut self)
Drops every cached glyph and image (they re-rasterize on demand) and bumps the epoch so renderers re-upload. Used when the raster mode changes under the cache — between frames, never during one.
Sourcepub fn get_or_insert(
&mut self,
key: CacheKey,
raster: impl FnOnce() -> Option<RasterGlyph>,
) -> Option<GlyphSlot>
pub fn get_or_insert( &mut self, key: CacheKey, raster: impl FnOnce() -> Option<RasterGlyph>, ) -> Option<GlyphSlot>
Cached lookup; rasterizes on miss — or, the frame after the page
was emptied, copies what the old page held. None means
unrasterizable (e.g. whitespace) and is cached as such.
Sourcepub fn get_or_insert_synth(
&mut self,
ch: char,
w: u32,
h: u32,
coverage: impl FnOnce() -> Vec<u8>,
) -> Option<GlyphSlot>
pub fn get_or_insert_synth( &mut self, ch: char, w: u32, h: u32, coverage: impl FnOnce() -> Vec<u8>, ) -> Option<GlyphSlot>
Cached lookup for a shape drawn to a w × h cell;
coverage is called on a miss for w * h alpha bytes, which land
as a white mask the renderer tints like any glyph’s. None means
the cell does not fit a MAX_ATLAS_SIZE page.
Sourcepub fn get_or_insert_path(
&mut self,
key: u64,
w: u32,
h: u32,
coverage: impl FnOnce() -> Vec<u8>,
) -> Option<GlyphSlot>
pub fn get_or_insert_path( &mut self, key: u64, w: u32, h: u32, coverage: impl FnOnce() -> Vec<u8>, ) -> Option<GlyphSlot>
Cached lookup for a path’s mask under key (the hash of its ops,
scale, bin and paint — the caller’s to make); coverage is called
on a miss for w * h alpha bytes, which land as a white mask the
renderer tints like any glyph’s, or the mask is copied from the
page begin_frame emptied when that page held it. None means
the mask does not fit the page this frame, or no page at all; the
caller draws it from a texture of its own.
Sourcepub fn get_or_insert_gradient(
&mut self,
key: u64,
w: u32,
h: u32,
rgba: impl FnOnce() -> Vec<u8>,
) -> Option<GlyphSlot>
pub fn get_or_insert_gradient( &mut self, key: u64, w: u32, h: u32, rgba: impl FnOnce() -> Vec<u8>, ) -> Option<GlyphSlot>
Cached lookup for a gradient’s raster
(docs/adr/0042-a-gradient-is-an-image-the-core-paints.md): w × h
texels of straight RGBA under key, made by rgba on a miss and
copied across a reset like a path’s mask, whose table it shares —
the caller’s key is of a different domain. None when no page can
hold it.
Sourcepub fn has_path(&self, key: u64) -> bool
pub fn has_path(&self, key: u64) -> bool
Whether the page holds a mask under key this frame: for a test
of what a path’s second frame costs.
Sourcepub fn get_or_insert_image(
&mut self,
id: ImageId,
w: u32,
h: u32,
rgba: &[u8],
) -> Option<GlyphSlot>
pub fn get_or_insert_image( &mut self, id: ImageId, w: u32, h: u32, rgba: &[u8], ) -> Option<GlyphSlot>
Cached lookup for a registered image; blits rgba (wh4) on miss.
None means it can’t fit even a MAX_ATLAS_SIZE page.
Sourcepub fn evict_image(&mut self, id: ImageId)
pub fn evict_image(&mut self, id: ImageId)
Forget an image’s slot (its pixels are reclaimed at the next reset).
Call when the host removes the image from Resources.
Sourcepub fn retain_images(&mut self, live: impl Fn(ImageId) -> bool)
pub fn retain_images(&mut self, live: impl Fn(ImageId) -> bool)
Keeps the slots of the images live says still exist and forgets
the rest — how a window learns of removals made through another
window of its session.
Trait Implementations§
Source§impl Default for GlyphAtlas
impl Default for GlyphAtlas
Source§fn default() -> GlyphAtlas
fn default() -> GlyphAtlas
Auto Trait Implementations§
impl Freeze for GlyphAtlas
impl RefUnwindSafe for GlyphAtlas
impl Send for GlyphAtlas
impl Sync for GlyphAtlas
impl Unpin for GlyphAtlas
impl UnsafeUnpin for GlyphAtlas
impl UnwindSafe for GlyphAtlas
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
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.