ttf.c: glyph raster cache, fixed slots, no allocation (item 4.3.7d)

Punch list §25 item 4.3.7d complete. ttf_raster_cache_get() looks up
(font, codepoint, size_px) in a caller-owned fixed slot array, evicting
round-robin once full, rasterizing into a slot on a miss.

Verified live in tools/ttftest.c: an identical (font, 'A', 24px) call
made twice returns was_hit=0 then was_hit=1, and the slot's own hits
counter reads exactly 1 afterward -- checked programmatically. A
different-codepoint call misses again, proving the key actually
discriminates. Wall-clock timing (miss 0.040ms vs hit 0.001ms) is
printed as informational corroboration only, not the load-bearing
check.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Robert Allan James
2026-08-10 22:31:56 -04:00
co-authored by Claude Sonnet 5
parent 095860251a
commit 2db4603d04
5 changed files with 219 additions and 2 deletions
+51
View File
@@ -218,6 +218,57 @@ int ttf_rasterize_glyph(const ttf_font_t *font, uint32_t glyph_index,
q48_16_t scale, q48_16_t origin_x, q48_16_t origin_y,
uint8_t fill_value, ttf_bitmap_t *out);
/* Glyph raster cache (FABRIC.md item 4.3.7d). Fixed-size, caller-owned
* slot array -- no allocation, same convention as the rest of this
* module. Every cached bitmap is a fixed TTF_CACHE_BITMAP_DIM square,
* rasterized with the fixed origin (TTF_CACHE_MARGIN,
* size_px + TTF_CACHE_MARGIN) -- i.e. glyph (0,0)/baseline sits at that
* pixel within the bitmap on every cache entry, not just fitted to each
* glyph's own bounding box. Callers positioning text (4.3.7e) need to
* know this fixed convention. */
#define TTF_CACHE_MAX_SIZE_PX 64
#define TTF_CACHE_MARGIN 8
#define TTF_CACHE_BITMAP_DIM (TTF_CACHE_MAX_SIZE_PX + TTF_CACHE_MARGIN * 2)
#define TTF_CACHE_BITMAP_BYTES (TTF_CACHE_BITMAP_DIM * TTF_CACHE_BITMAP_DIM)
typedef struct {
int valid;
const ttf_font_t *font;
uint32_t codepoint;
uint32_t size_px;
uint32_t width, height;
uint32_t hits; /* incremented on every cache hit; 4.3.7d's own
* "measurable" verification reads this. */
uint8_t pixels[TTF_CACHE_BITMAP_BYTES];
} ttf_raster_cache_slot_t;
typedef struct {
ttf_raster_cache_slot_t *slots;
uint32_t slot_count;
uint32_t evict_next; /* round-robin index used once every slot is full */
} ttf_raster_cache_t;
/** ttf_raster_cache_init - Bind a caller-supplied slot array to `cache`
* and mark every slot empty. */
void ttf_raster_cache_init(ttf_raster_cache_t *cache, ttf_raster_cache_slot_t *slots,
uint32_t slot_count);
/**
* ttf_raster_cache_get - Look up (font, codepoint, size_px); on a miss,
* rasterize and insert (evicting round-robin if every slot is full).
* `out` borrows the winning slot's buffer directly -- valid until that
* slot is evicted by a later call.
*
* @param was_hit If non-NULL, set to 1 on a cache hit, 0 if this call
* rasterized and inserted
* @return TTF_OK, TTF_ERR_UNSUPPORTED if size_px > TTF_CACHE_MAX_SIZE_PX,
* or a ttf_rasterize_glyph() TTF_ERR_* code on a miss that failed
* to rasterize
*/
int ttf_raster_cache_get(ttf_raster_cache_t *cache, const ttf_font_t *font,
uint32_t codepoint, uint32_t size_px,
ttf_bitmap_t *out, int *was_hit);
#ifdef __STARKERNEL__
#include "capsule.h"