Skip to main content

Module atlas

Module atlas 

Source
Expand description

The image atlas array, and the encoded-image record the strip shader reads it through.

Two halves, split on the same line the rest of crate::gpu is split on.

  • Pure decisions over plain values. The texture descriptor, the packing of an AtlasRegion and a sampler into a GpuEncodedImage, and the natural-to-device transform an image paint carries — all host-testable with no device.
  • One live-GPU type. AtlasArray owns the Rgba8Unorm D2Array texture the shader’s atlas_texture_array binding samples, grows it a layer at a time, writes newly resident regions and clears evicted ones.

§Why the atlas is not pooled

crate::gpu::targets pools every transient the engine allocates, on the rule that a target nothing outlives the frame should be reused rather than reallocated. The atlas is the opposite kind of resource: its whole purpose is that an image uploaded on one frame is still there on the next thousand, so it is owned outright for the life of the renderer and reclaimed a region at a time by crate::cache::images’s age-based reap. Handing it to the pool would make residency a lie.

§Growth and clearing

A wgpu texture’s array-layer count is fixed at creation, so growing the array means creating a deeper texture and copying every existing layer across — which is why the array carries COPY_SRC alongside COPY_DST. Growth is rare (a layer holds a whole mobile budget’s worth of images) and never shrinks: an atlas that grew to four layers under load keeps them.

§Why growth submits a command buffer of its own

That copy is the one piece of engine work that cannot ride the frame’s encoder. wgpu flushes the queued writes pending at a submit before the command buffers of that same submit, so a copy recorded into the frame’s encoder would execute after the frame’s own write_texture uploads and clears — restoring the pre-growth contents of every layer they had just written, permanently (residency schedules an upload on a miss, and the image is not a miss any more). Ordering is therefore established by submitting the copy on its own, ahead of the frame’s writes being issued at all.

That is a maintenance submit, not scene work: it carries one texture copy, no pass and no draw, and it happens only on the rare frame that grows the array. crate::renderer::EngineRenderer::encode’s contract that the engine never submits the caller’s encoder, and records no scene work anywhere else, is untouched — the caller’s encoder is neither read nor finished here.

Clearing an evicted region writes transparent texels through the queue rather than drawing a scissored pass. Both reach the same result; the queue write needs no pipeline, no render pass and no bind group, and eviction is a once-in-sixty-frames event whose cost is a zeroed staging buffer the size of the region.

§Rendering into the atlas

Everything above writes the atlas from the host. A glyph is different: it has no pixels until something rasterizes its outline, and glifo’s AtlasCacher::Enabled path does not rasterize one — it records the fills into a per-page AtlasCommandRecorder and leaves the pixels to whoever owns the atlas. AtlasRenderer is that owner on this tier: it replays each dirty page’s commands into a strip pass whose colour attachment is that page’s own array layer.

Three orderings make the difference between a correct glyph and a stale one, and all three are this type’s to keep.

  1. Clears before uploads. A rectangle an eviction freed can be handed straight back out to a different glyph on the same frame, so zeroing it after that glyph’s pixels landed would erase the glyph that just moved in. Both are queue writes, which execute in the order they are issued — so the order they are issued in is the whole guarantee.
  2. Both before the pass. wgpu flushes the writes queued at a submit before that submit’s command buffers, so a page’s replay pass sees the clears and the bitmap uploads already applied to the layer it composites onto, without anything having to be said about it.
  3. The pass before the scene’s. A glyph the scene pass samples out of the atlas has to be in the atlas by then, and the scene pass lives in an encoder this crate does not own and never submits. So the replay pass goes into an encoder of AtlasRenderer’s own and is submitted before it returns — the sanctioned exception to frust_gpu::CommandBuffer’s single-submit borrowing contract, named there as the glyph-atlas upload carve-out and the same one AtlasArray::ensure_layers already takes for the growth copy.

One submit per dirty page rather than one for all of them: the coverage a page’s strips index is uploaded to a shared alpha texture, and a second queue write to that texture in the same submit would overwrite the first before either pass ran. Pages are dirty only on a frame that missed a glyph, and there is one page in the overwhelming case, so the extra submit is a per-miss cost rather than a per-frame one.

§What the replay does not lower

Turning a recorded command stream into strips is compiler work, and crate::compile already depends on this module — so the lowering is a closure the caller supplies (AtlasRenderer::render_pending) rather than a dependency taken the other way. What this module contributes to it is push_solid_strips, the pure expansion of one solid-painted strip run into instances, which is the whole of an outline glyph’s lowering.

Structs§

AtlasArray
The atlas array texture, its view, and the layer count both were created at.
AtlasPageBuffers
One page’s lowered replay: the instances to draw and the coverage they index.
AtlasRenderReport
What one call to AtlasRenderer::render_pending serviced.
AtlasRenderer
The GPU home for glyph pixels: replays glifo’s recorded atlas commands into the atlas array’s own layers, and services the two pixel drains that have to be ordered around them.

Constants§

ATLAS_FORMAT
The texture format the atlas array stores premultiplied image texels in.
ATLAS_USAGES
The usages the atlas array is created with.
MAX_ATLAS_INDEX
The most atlas layers the encoded-image record’s atlas_index field can name (eight bits).

Functions§

atlas_layer_view_descriptor
The single-layer D2 view descriptor a render pass attaches one atlas layer through.
atlas_texture_descriptor
The descriptor for an atlas array of width x height texels over layers array layers.
atlas_view_descriptor
The D2Array view descriptor the strip shader’s atlas binding expects.
clear_rect_region
The atlas rectangle one of glifo’s pending clear rects names.
extend_mode
The shader’s extend-mode numbering.
lower_encoded_image
Lower one encoded image paint into the record the strip shader samples.
natural_to_dest
The affine mapping an image’s natural pixel rectangle (0, 0, width, height) onto dest, composed under transform.
pack_image_offset
Packs an image’s atlas offset into one word, x in the high half.
pack_image_params
Packs sampling quality (bits 0-1), the two extend modes (bits 2-3 and 4-5), the atlas layer (bits 6-13) and the source kind (bit 14) into one word.
pack_image_size
Packs an image’s width and height into one word, width in the high half.
pack_tint
The premultiplied colour and mode an optional tint packs to.
push_solid_strips
Expands one solid-painted strip run into the instances that draw it, appending to out.
region_byte_len
The bytes a region’s texels occupy — the length AtlasArray::write_region requires of its slice.
slot_region
The atlas rectangle one pending bitmap upload’s slot occupies.
x_y_advances
The per-pixel advances in image space an encoded image carries, derived from its already-inverted transform.