Merge pull request 'perf(ui): per-shelf dirty spans for tight font-atlas uploads (#129)' (#147) from claude/issue-129 into master

This commit is contained in:
catbot 2026-06-18 15:36:33 +02:00
commit a4fdbf7d30
2 changed files with 51 additions and 28 deletions

View file

@ -102,9 +102,12 @@ export namespace Crafter {
std::vector<std::uint8_t> staging;
#endif
// `dirty` stays the cheap "is there anything to flush?" flag the
// renderer polls each frame; `dirtyRect` carries the bounds Update
// copies. The two are always set and cleared together (dirty ==
// !dirtyRect.Empty()).
// renderer polls each frame; it is the OR of every dirty span Update
// copies. `dirtyRect` is the *whole-atlas* span — used only for the
// one-shot zero-clear in Initialize; per-glyph dirt is tracked tight
// per shelf (Shelf::dirty) instead of inflating one tall union box
// across scattered shelves (#129). `dirty` and the spans are always
// armed and cleared together.
bool dirty = false;
DirtyRect dirtyRect;
@ -131,7 +134,11 @@ export namespace Crafter {
}
private:
struct Shelf { int y = 0; int height = 0; int cursorX = 0; };
// A shelf packs glyphs left-to-right at a fixed top (`y`). Its `dirty`
// span therefore stays naturally tight: a contiguous X run capped by
// the shelf height — far smaller than a union box spanning every
// shelf a frame happened to touch.
struct Shelf { int y = 0; int height = 0; int cursorX = 0; DirtyRect dirty; };
std::vector<Shelf> shelves_;
int nextShelfY_ = 0;
@ -149,6 +156,8 @@ export namespace Crafter {
};
std::unordered_map<Key, Glyph, KeyHash> cache_;
bool ShelfPlace(int w, int h, int& outX, int& outY);
// On success, outShelf is the index into shelves_ of the placed
// glyph, so the caller can mark that shelf's dirty span.
bool ShelfPlace(int w, int h, int& outX, int& outY, int& outShelf);
};
}