|
ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
|
Fixed-RAM-budget image-tile cache with LRU eviction (Layer 3b, #147). More...
Go to the source code of this file.
Data Structures | |
| struct | ra8_tile_key_t |
| Identifies one decoded image tile. More... | |
| struct | ra8_tile_dims_t |
| Per-cell user descriptor: the decoded tile dimensions. More... | |
| struct | ra8_tile_t |
| A pinned view of a cached tile returned by ra8_tile_cache_get. More... | |
| struct | ra8_tile_cache_cfg_t |
| Caller-supplied storage + decoder for ra8_tile_cache_init. More... | |
| struct | ra8_tile_cache_t |
| Tile-cache state (caller-owned; treat as private). More... | |
| struct | ra8_tile_rect_t |
| An inclusive rectangle of tile grid coordinates (the visible tiles). More... | |
| struct | ra8_tile_prefetch_req_t |
| A predictive pan-prefetch request: what is visible + where it heads. More... | |
Typedefs | |
| typedef ra8_err_t(* | ra8_tile_decode_fn) (void *ctx, const ra8_tile_key_t *key, uint8_t *cell, uint32_t cell_bytes, uint16_t *out_w, uint16_t *out_h) |
| Decode an image tile into a cache cell (decode-on-miss DIP seam). | |
Enumerations | |
| enum | ra8_tile_pan_dir_t : uint8_t { k_ra8_tile_pan_none = 0U , k_ra8_tile_pan_left = 1U , k_ra8_tile_pan_right = 2U , k_ra8_tile_pan_up = 3U , k_ra8_tile_pan_down = 4U } |
| Direction of viewport travel, for predictive pan prefetch. More... | |
Functions | |
| ra8_err_t | ra8_tile_rect_of_pixels (uint32_t px, uint32_t py, uint32_t pw, uint32_t ph, uint16_t tile_w, uint16_t tile_h, uint16_t tile_cols, uint16_t tile_rows, ra8_tile_rect_t *out) |
| Convert a pixel rectangle into the inclusive tile rectangle covering it. | |
| ra8_err_t | ra8_tile_cache_init (ra8_tile_cache_t *tc, const ra8_tile_cache_cfg_t *cfg) |
| Initialise a tile cache over caller-supplied storage. | |
| ra8_err_t | ra8_tile_cache_get (ra8_tile_cache_t *tc, const ra8_tile_key_t *key, ra8_tile_t *out_tile) |
Get (and pin) the decoded tile for key. | |
| ra8_err_t | ra8_tile_cache_put (ra8_tile_cache_t *tc, const uint8_t *pixels) |
| Release one pin on a tile previously returned by ra8_tile_cache_get. | |
| uint32_t | ra8_tile_cache_capacity (const ra8_tile_cache_t *tc) |
| Report the number of cells the cache can hold. | |
| ra8_err_t | ra8_tile_cache_prefetch (ra8_tile_cache_t *tc, const ra8_tile_key_t *key) |
| Warm one tile into the cache without holding a pin (read-ahead). | |
| ra8_err_t | ra8_tile_cache_prefetch_pan (ra8_tile_cache_t *tc, const ra8_tile_prefetch_req_t *req, uint16_t *out_warmed) |
| Predictively warm the tiles one step ahead of a panning viewport. | |
| ra8_err_t | ra8_tile_cache_stats (const ra8_tile_cache_t *tc, uint32_t *out_hits, uint32_t *out_misses, uint32_t *out_evictions) |
| Report the cache hit / miss / eviction counters. | |
Fixed-RAM-budget image-tile cache with LRU eviction (Layer 3b, #147).
The image counterpart of the #147 glyph atlas: a tile cache so the reader can pan/zoom a comic page or a large illustration far bigger than RAM (CBZ/CBR, full-bleed covers) while resident decoded-pixel memory stays bounded. A tile is keyed by (image_id, tile_x, tile_y, zoom) and the cache returns a pinned view of the decoded pixels; a miss decodes the tile region into a free/evicted cell through a caller-supplied decoder (an stb_image-backed decoder in production – see the bare-metal arena/TLS notes around ::ra8_img_arena – and a synthetic generator in tests).
Like ::ra8_glyph_atlas, this is a thin typed facade over the reusable ::ra8_keycache (key bytes + cell bytes + render-on-miss + pin/unpin): the tile key is the cache key, the decoded tile is the cell payload, and the decoded width/height ride in the per-cell user descriptor (ra8_tile_dims_t). Tiles differ from glyphs only in scale – cells are large (a 64x64 RGB565 tile is 8 KiB), so the budget yields fewer cells. Eviction is LRU with pinned-cell skip: the tiles composited into the current frame are pinned while on screen, so a scroll cannot evict a tile still being blitted. Edge tiles may decode smaller than a full tile; the decoder reports the true out_w/out_h.
Zero allocation (NASA P10 Rule 3): the caller provides the cell storage, the key storage, the per-cell dimension descriptors, the per-cell link metadata, and the hash buckets, carved once from a tier ::ra8_arena / ::ra8_slab at init (tile pixels in SDRAM; the metadata in DTCM for the hot path).
Definition in file ra8_tile_cache.h.
| typedef ra8_err_t(* ra8_tile_decode_fn) (void *ctx, const ra8_tile_key_t *key, uint8_t *cell, uint32_t cell_bytes, uint16_t *out_w, uint16_t *out_h) |
Decode an image tile into a cache cell (decode-on-miss DIP seam).
| [in] | ctx | Opaque decoder context (decode_ctx from the config). |
| [in] | key | The tile to decode. |
| [out] | cell | Destination pixel buffer (cell_bytes writable). |
| [in] | cell_bytes | Cell capacity in bytes. |
| [out] | out_w | Decoded tile width in pixels. |
| [out] | out_h | Decoded tile height in pixels. |
Definition at line 125 of file ra8_tile_cache.h.
| enum ra8_tile_pan_dir_t : uint8_t |
Direction of viewport travel, for predictive pan prefetch.
ra8_tile_cache_prefetch_pan warms the tile row or column one step ahead of the visible rectangle in this direction. k_ra8_tile_pan_none warms nothing (a still viewport, or a pan that did not move).
Definition at line 180 of file ra8_tile_cache.h.
|
nodiscard |
Report the number of cells the cache can hold.
The cache capacity in tiles, used by a pan-prefetch caller to size its residency budget (spare = capacity - currently-visible tiles) so a prefetch cannot evict an on-screen tile.
| [in] | tc | Initialised cache. |
tc is NULL / uninitialised. | 0 | tc was NULL or was never ra8_tile_cache_init'd. |
| >0 | The configured cell count. |
Definition at line 177 of file ra8_tile_cache.c.
References ra8_keycache_cfg_t::cell_count, ra8_keycache_cfg_t::cell_mem, ra8_keycache_t::cfg, and ra8_tile_cache_t::kc.
Referenced by mg_reader_prefetch().
|
nodiscard |
Get (and pin) the decoded tile for key.
On a hit the cell is moved to the MRU and pinned. On a miss an unpinned LRU victim is evicted, the tile is decoded into the cell, inserted, and pinned. The returned pixels stay valid until ra8_tile_cache_put.
| [in] | tc | Initialised cache. |
| [in] | key | Tile to fetch. |
| [out] | out_tile | Receives the pinned tile view. |
| k_ra8_ok | Tile resident and pinned; *out_tile set. |
| k_ra8_err_null_ptr | tc, key, or out_tile was NULL. |
| k_ra8_err_no_mem | Every cell is pinned (cannot evict for the miss). |
| k_ra8_err_* | The decoder failed (returned verbatim). |
Definition at line 155 of file ra8_tile_cache.c.
References ra8_keycache_view_t::data, ra8_tile_dims_t::h, k_ra8_ok, ra8_tile_cache_t::kc, RA8_CHECK_NULL_PTR, ra8_keycache_get(), s_tag, ra8_keycache_view_t::user, and ra8_tile_dims_t::w.
Referenced by internal_draw_band(), internal_warm_band(), mem_tile_touch(), and mg_render_page().
|
nodiscard |
Initialise a tile cache over caller-supplied storage.
| [out] | tc | Cache state to populate (zero-initialised by the caller). |
| [in] | cfg | Storage + decoder configuration. |
| k_ra8_ok | Cache ready; all cells cold. |
| k_ra8_err_null_ptr | tc, cfg, or a required cfg pointer NULL. |
| k_ra8_err_invalid_size | cell_count, cell_bytes, or bucket_count 0. |
Definition at line 131 of file ra8_tile_cache.c.
References ra8_keycache_cfg_t::bucket_count, ra8_tile_cache_cfg_t::bucket_count, ra8_keycache_cfg_t::buckets, ra8_tile_cache_cfg_t::buckets, ra8_keycache_cfg_t::cell_bytes, ra8_tile_cache_cfg_t::cell_bytes, ra8_keycache_cfg_t::cell_count, ra8_tile_cache_cfg_t::cell_count, ra8_keycache_cfg_t::cell_mem, ra8_tile_cache_cfg_t::cell_mem, ra8_tile_cache_cfg_t::decode, ra8_tile_cache_t::decode, ra8_tile_cache_cfg_t::decode_ctx, ra8_tile_cache_t::decode_ctx, ra8_tile_cache_cfg_t::dims, internal_tile_decode(), ra8_tile_cache_t::kc, ra8_keycache_cfg_t::key_bytes, ra8_keycache_cfg_t::key_mem, ra8_tile_cache_cfg_t::keys, memset(), ra8_keycache_cfg_t::meta, ra8_tile_cache_cfg_t::meta, RA8_CHECK_NULL_PTR, ra8_keycache_init(), ra8_keycache_cfg_t::render, ra8_keycache_cfg_t::render_ctx, s_tag, ra8_keycache_cfg_t::user_bytes, and ra8_keycache_cfg_t::user_mem.
Referenced by ez_bind_page(), internal_wire(), ls_open_strip(), mem_run_tiles(), and mg_setup_cache().
|
nodiscard |
Warm one tile into the cache without holding a pin (read-ahead).
Decode-on-miss + immediate unpin, so on return the tile is resident but evictable. A thin typed facade over ra8_keycache_prefetch: warming changes only residency, never the pixels a later ra8_tile_cache_get returns, so rendered output is unchanged and goldens hold.
| [in,out] | tc | Initialised cache. |
| [in] | key | Tile to warm (fully initialised; zero-fill before setting). |
| k_ra8_ok | The tile is resident and unpinned (warmed or hit). |
| k_ra8_err_null_ptr | tc or key was NULL. |
| k_ra8_err_no_mem | Every cell is pinned (cannot evict to warm). |
| k_ra8_err_* | The decoder failed (returned verbatim). |
Definition at line 188 of file ra8_tile_cache.c.
References ra8_tile_cache_t::kc, RA8_CHECK_NULL_PTR, ra8_keycache_prefetch(), and s_tag.
Referenced by ra8_tile_cache_prefetch_pan().
|
nodiscard |
Predictively warm the tiles one step ahead of a panning viewport.
On a pan, warms the tile row or column immediately beyond req->view in req->dir, so the next tiles the viewport exposes are resident before they are needed – the image counterpart of ::ra8_book_src_prefetch_chapter's text read-ahead. The lead edge is clamped to the tile grid (req->tile_cols / req->tile_rows): a pan already at the image edge warms nothing. The number of tiles warmed is bounded by req->max_tiles (the caller's spare-capacity budget) and by the edge length, so the prefetch cannot exceed the cache budget or evict an on-screen tile. Best-effort: each tile is warmed with ra8_tile_cache_prefetch and a per-tile failure stops the sweep without failing the call, so a pan never errors because read-ahead could not complete.
| [in,out] | tc | Initialised cache. |
| [in] | req | The visible rectangle + direction + budget. |
| [out] | out_warmed | Tiles warmed by this call (may be NULL). |
| k_ra8_ok | The sweep ran (0 or more tiles warmed). |
| k_ra8_err_null_ptr | tc or req was NULL. |
| k_ra8_err_invalid_arg | req->view is not tx0<=tx1 / ty0<=ty1, or a bound lies outside the tile grid. |
Definition at line 329 of file ra8_tile_cache.c.
References priv_pan_line_t::count, ra8_tile_prefetch_req_t::image_id, internal_pan_line(), internal_validate_req(), k_ra8_ok, ra8_tile_prefetch_req_t::max_tiles, RA8_CHECK_NULL_PTR, ra8_tile_cache_prefetch(), s_tag, priv_pan_line_t::step_x, priv_pan_line_t::step_y, priv_pan_line_t::x, priv_pan_line_t::y, and ra8_tile_prefetch_req_t::zoom.
Referenced by mg_reader_prefetch().
|
nodiscard |
Release one pin on a tile previously returned by ra8_tile_cache_get.
| [in] | tc | Initialised cache. |
| [in] | pixels | The pixels pointer from a returned ra8_tile_t. |
| k_ra8_ok | Pin released. |
| k_ra8_err_null_ptr | tc or pixels was NULL. |
| k_ra8_err_invalid_arg | pixels is not a cell of this cache, or the cell was not pinned. |
Definition at line 170 of file ra8_tile_cache.c.
References ra8_tile_cache_t::kc, RA8_CHECK_NULL_PTR, ra8_keycache_put(), and s_tag.
Referenced by internal_draw_band(), internal_warm_band(), mem_tile_touch(), and mg_render_page().
|
nodiscard |
Report the cache hit / miss / eviction counters.
| [in] | tc | Initialised cache. |
| [out] | out_hits | Hits so far (may be NULL). |
| [out] | out_misses | Misses so far (may be NULL). |
| [out] | out_evictions | Evictions so far (may be NULL). |
| k_ra8_ok | Counters reported. |
| k_ra8_err_null_ptr | tc was NULL. |
| k_ra8_err_invalid_state | The cache was not initialised. |
Definition at line 364 of file ra8_tile_cache.c.
References ra8_keycache_cfg_t::cell_mem, ra8_keycache_t::cfg, k_ra8_err_invalid_state, ra8_tile_cache_t::kc, RA8_CHECK_NULL_PTR, ra8_keycache_stats(), and s_tag.
Referenced by ez_scene_selftest(), and mem_run_tiles().
|
nodiscard |
Convert a pixel rectangle into the inclusive tile rectangle covering it.
The producer ra8_tile_rect_t never had. Every consumer that needed "which tiles does this viewport touch?" open-coded the same four divisions in its own app, so the residency question was answered in a slightly different place from the prefetch that acts on it. Answering it once, here, is what lets a zoom viewer state its resident set and warm its lead edge from the same number.
The result is clamped to the tile grid, so a rectangle that runs past the image edge yields the last tile rather than an out-of-grid index the prefetch would then have to re-clamp. An empty rectangle (pw == 0 or ph == 0) is rejected rather than collapsed: a viewport showing no pixels is a caller defect, and silently returning tile (0,0) would understate residency.
| [in] | px | Rectangle left edge, source pixels. |
| [in] | py | Rectangle top edge, source pixels. |
| [in] | pw | Rectangle width, source pixels (> 0). |
| [in] | ph | Rectangle height, source pixels (> 0). |
| [in] | tile_w | Tile width, pixels (> 0). |
| [in] | tile_h | Tile height, pixels (> 0). |
| [in] | tile_cols | Tile columns in the image (> 0; the clamp bound). |
| [in] | tile_rows | Tile rows in the image (> 0; the clamp bound). |
| [out] | out | Receives the inclusive tile rectangle. |
| k_ra8_ok | out spans exactly the covering tiles. |
| k_ra8_err_null_ptr | out is NULL. |
| k_ra8_err_invalid_arg | An extent or a grid dimension is zero. |
out addresses writable storage for one ra8_tile_rect_t. out.Definition at line 103 of file ra8_tile_cache.c.
References internal_clamp_tile(), k_ra8_err_invalid_arg, k_ra8_ok, RA8_CHECK_NULL_PTR, ra8_log_error, s_tag, ra8_tile_rect_t::tx0, ra8_tile_rect_t::tx1, ra8_tile_rect_t::ty0, and ra8_tile_rect_t::ty1.