[robustness] Font atlas has no eviction/repack; ShelfPlace fails permanently once full #55

Open
opened 2026-06-16 16:51:32 +02:00 by jorijnvdgraaf · 0 comments

Subsystem: Font / FontAtlas
Location: implementations/Crafter.Graphics-FontAtlas.cpp:51-70, 93-98
Impact: MEDIUM (robustness, not perf) · Effort: Large · Not hot path (post-fill)

Problem

One-way shelf allocator; once the 1024^2 atlas fills, new glyphs never place. For multi-font/CJK/many-size workloads the atlas silently degrades. Correction to original finding: failed glyphs are not cached as empty (Ensure returns at line 97 before the emplace), so every unplaceable glyph is re-rasterized via stbtt_GetCodepointSDF every frame, never cached. The caller continues skipping the glyph including its advance, so text collapses/shifts rather than rendering blank.

Proposed fix

LRU eviction + free-list, or grow-and-repack + skyline packer. At minimum, do not re-rasterize unplaceable glyphs every frame.

Correctness caveat

A grow/repack that reallocates the image changes the descriptor the GPU samples — needs a frame-fence wait or double-buffering; naive in-place repack mid-frame is a read-during-write hazard. CPU-side repack + dirty=true + deferred Update between frames is safe.

**Subsystem:** Font / FontAtlas **Location:** `implementations/Crafter.Graphics-FontAtlas.cpp:51-70, 93-98` **Impact:** MEDIUM (robustness, not perf) · **Effort:** Large · Not hot path (post-fill) ### Problem One-way shelf allocator; once the 1024^2 atlas fills, new glyphs never place. For multi-font/CJK/many-size workloads the atlas silently degrades. Correction to original finding: failed glyphs are **not** cached as empty (`Ensure` returns at line 97 before the emplace), so every unplaceable glyph is **re-rasterized via `stbtt_GetCodepointSDF` every frame**, never cached. The caller `continue`s skipping the glyph *including its advance*, so text collapses/shifts rather than rendering blank. ### Proposed fix LRU eviction + free-list, or grow-and-repack + skyline packer. At minimum, do not re-rasterize unplaceable glyphs every frame. ### Correctness caveat A grow/repack that reallocates the image changes the descriptor the GPU samples — needs a frame-fence wait or double-buffering; naive in-place repack mid-frame is a read-during-write hazard. CPU-side repack + `dirty=true` + deferred `Update` between frames is safe.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Catcrafts/Crafter.Graphics#55
No description provided.