ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_tile_cache.h File Reference

Fixed-RAM-budget image-tile cache with LRU eviction (Layer 3b, #147). More...

#include <stdint.h>
#include "ra8_err.h"
#include "ra8_keycache.h"
Include dependency graph for ra8_tile_cache.h:
This graph shows which files directly or indirectly include this file:

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.

Detailed Description

Fixed-RAM-budget image-tile cache with LRU eviction (Layer 3b, #147).

Tag
[Ring 2 / Core] {World: NS}

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).

Note
Not thread-safe; the decoder is single-threaded.
Since
0.1.0

Definition in file ra8_tile_cache.h.

Typedef Documentation

◆ ra8_tile_decode_fn

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).

Parameters
[in]ctxOpaque decoder context (decode_ctx from the config).
[in]keyThe tile to decode.
[out]cellDestination pixel buffer (cell_bytes writable).
[in]cell_bytesCell capacity in bytes.
[out]out_wDecoded tile width in pixels.
[out]out_hDecoded tile height in pixels.
Returns
ra8_err_t k_ra8_ok on success (with the decoded pixels fitting cell_bytes); any error aborts the get with that code.
Since
0.1.0

Definition at line 125 of file ra8_tile_cache.h.

Enumeration Type Documentation

◆ ra8_tile_pan_dir_t

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).

See also
ra8_tile_cache_prefetch_pan
Since
0.1.0
Enumerator
k_ra8_tile_pan_none 

No travel: prefetch is a no-op.

k_ra8_tile_pan_left 

Warm the column left of the viewport.

k_ra8_tile_pan_right 

Warm the column right of the viewport.

k_ra8_tile_pan_up 

Warm the row above the viewport.

k_ra8_tile_pan_down 

Warm the row below the viewport.

Definition at line 180 of file ra8_tile_cache.h.

Function Documentation

◆ ra8_tile_cache_capacity()

uint32_t ra8_tile_cache_capacity ( const ra8_tile_cache_t * tc)
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.

Parameters
[in]tcInitialised cache.
Returns
uint32_t The cell count, or 0 if tc is NULL / uninitialised.
Return values
0tc was NULL or was never ra8_tile_cache_init'd.
>0The configured cell count.
Precondition
tc was populated by ra8_tile_cache_init (else 0 is returned).
None beyond the above.
Postcondition
No cache state is mutated.
The result is the exact configured cell count.
Note
Thread-safe with respect to a quiescent cache (pure read).
Since
0.1.0

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().

◆ ra8_tile_cache_get()

ra8_err_t ra8_tile_cache_get ( ra8_tile_cache_t * tc,
const ra8_tile_key_t * key,
ra8_tile_t * out_tile )
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.

Parameters
[in]tcInitialised cache.
[in]keyTile to fetch.
[out]out_tileReceives the pinned tile view.
Returns
ra8_err_t Error code.
Return values
k_ra8_okTile resident and pinned; *out_tile set.
k_ra8_err_null_ptrtc, key, or out_tile was NULL.
k_ra8_err_no_memEvery cell is pinned (cannot evict for the miss).
k_ra8_err_*The decoder failed (returned verbatim).
Precondition
tc was populated by ra8_tile_cache_init.
The caller will ra8_tile_cache_put the returned tile.
Postcondition
On success the cell's pin count increased by one.
On any non-ok return no new pin is held.
Note
Not thread-safe.
Since
0.1.0

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().

◆ ra8_tile_cache_init()

ra8_err_t ra8_tile_cache_init ( ra8_tile_cache_t * tc,
const ra8_tile_cache_cfg_t * cfg )
nodiscard

Initialise a tile cache over caller-supplied storage.

Parameters
[out]tcCache state to populate (zero-initialised by the caller).
[in]cfgStorage + decoder configuration.
Returns
ra8_err_t Error code.
Return values
k_ra8_okCache ready; all cells cold.
k_ra8_err_null_ptrtc, cfg, or a required cfg pointer NULL.
k_ra8_err_invalid_sizecell_count, cell_bytes, or bucket_count 0.
Precondition
cfg's arrays cover their sizes and out-live the cache.
cfg->decode is non-NULL.
Postcondition
On success the cache is empty and buckets are cleared.
On any non-ok return tc is left unbound.
Note
Not thread-safe.
Since
0.1.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().

◆ ra8_tile_cache_prefetch()

ra8_err_t ra8_tile_cache_prefetch ( ra8_tile_cache_t * tc,
const ra8_tile_key_t * key )
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.

Parameters
[in,out]tcInitialised cache.
[in]keyTile to warm (fully initialised; zero-fill before setting).
Returns
ra8_err_t Error code.
Return values
k_ra8_okThe tile is resident and unpinned (warmed or hit).
k_ra8_err_null_ptrtc or key was NULL.
k_ra8_err_no_memEvery cell is pinned (cannot evict to warm).
k_ra8_err_*The decoder failed (returned verbatim).
Precondition
tc was populated by ra8_tile_cache_init.
key names a valid tile of a decodable image.
Postcondition
On success the tile is resident with pin count zero.
On any non-ok return no pin is held.
Note
Not thread-safe. Single-threaded read-ahead only.
See also
ra8_tile_cache_prefetch_pan()
Since
0.1.0

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().

◆ ra8_tile_cache_prefetch_pan()

ra8_err_t ra8_tile_cache_prefetch_pan ( ra8_tile_cache_t * tc,
const ra8_tile_prefetch_req_t * req,
uint16_t * out_warmed )
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.

Parameters
[in,out]tcInitialised cache.
[in]reqThe visible rectangle + direction + budget.
[out]out_warmedTiles warmed by this call (may be NULL).
Returns
ra8_err_t Error code.
Return values
k_ra8_okThe sweep ran (0 or more tiles warmed).
k_ra8_err_null_ptrtc or req was NULL.
k_ra8_err_invalid_argreq->view is not tx0<=tx1 / ty0<=ty1, or a bound lies outside the tile grid.
Precondition
tc was populated by ra8_tile_cache_init.
req->view is a valid inclusive rectangle inside the tile grid.
Postcondition
On success at most req->max_tiles lead-edge tiles are resident.
No on-screen (already-visible) tile is evicted by this call.
Note
Not thread-safe. Single-threaded read-ahead only.
See also
ra8_tile_cache_prefetch()
Since
0.1.0

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().

◆ ra8_tile_cache_put()

ra8_err_t ra8_tile_cache_put ( ra8_tile_cache_t * tc,
const uint8_t * pixels )
nodiscard

Release one pin on a tile previously returned by ra8_tile_cache_get.

Parameters
[in]tcInitialised cache.
[in]pixelsThe pixels pointer from a returned ra8_tile_t.
Returns
ra8_err_t Error code.
Return values
k_ra8_okPin released.
k_ra8_err_null_ptrtc or pixels was NULL.
k_ra8_err_invalid_argpixels is not a cell of this cache, or the cell was not pinned.
Precondition
pixels came from ra8_tile_cache_get on this cache and is still pinned.
tc was populated by ra8_tile_cache_init.
Postcondition
On success the cell's pin count decreased by one.
On any non-ok return no state changed.
Note
Not thread-safe.
Since
0.1.0

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().

◆ ra8_tile_cache_stats()

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 )
nodiscard

Report the cache hit / miss / eviction counters.

Parameters
[in]tcInitialised cache.
[out]out_hitsHits so far (may be NULL).
[out]out_missesMisses so far (may be NULL).
[out]out_evictionsEvictions so far (may be NULL).
Returns
ra8_err_t Error code.
Return values
k_ra8_okCounters reported.
k_ra8_err_null_ptrtc was NULL.
k_ra8_err_invalid_stateThe cache was not initialised.
Precondition
tc was populated by ra8_tile_cache_init.
At least one output pointer is non-NULL to be useful.
Postcondition
On success the requested counters are written.
No cache state is mutated.
Note
Thread-safe with respect to a quiescent cache (pure read).
Since
0.1.0

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().

◆ ra8_tile_rect_of_pixels()

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 )
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.

Parameters
[in]pxRectangle left edge, source pixels.
[in]pyRectangle top edge, source pixels.
[in]pwRectangle width, source pixels (> 0).
[in]phRectangle height, source pixels (> 0).
[in]tile_wTile width, pixels (> 0).
[in]tile_hTile height, pixels (> 0).
[in]tile_colsTile columns in the image (> 0; the clamp bound).
[in]tile_rowsTile rows in the image (> 0; the clamp bound).
[out]outReceives the inclusive tile rectangle.
Returns
ra8_err_t Error code.
Return values
k_ra8_okout spans exactly the covering tiles.
k_ra8_err_null_ptrout is NULL.
k_ra8_err_invalid_argAn extent or a grid dimension is zero.
Precondition
out addresses writable storage for one ra8_tile_rect_t.
The tile geometry describes the same image the pixel rectangle indexes.
Postcondition
out->tx0 <= out->tx1 < tile_cols and out->ty0 <= out->ty1 < tile_rows.
Every pixel of the rectangle inside the image lies in a tile of out.
Note
Pure integer arithmetic; thread-safe.
Example:
ra8_ui_rect_t win = {};
(void)ra8_zoom_view_window(&view, &win);
ra8_tile_rect_t tiles = {};
(void)ra8_tile_rect_of_pixels((uint32_t)win.x, (uint32_t)win.y,
(uint32_t)win.w, (uint32_t)win.h,
tile_w, tile_h, tile_cols, tile_rows, &tiles);
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.
An inclusive rectangle of tile grid coordinates (the visible tiles).
Axis-aligned rectangle in framebuffer pixel coordinates.
Definition ra8_ui.h:72
int32_t w
Width (pixels, >= 0).
Definition ra8_ui.h:75
int32_t h
Height (pixels, >= 0).
Definition ra8_ui.h:76
int32_t x
Left edge (pixels).
Definition ra8_ui.h:73
int32_t y
Top edge (pixels).
Definition ra8_ui.h:74
See also
ra8_tile_cache_prefetch_pan()
Since
0.1.0

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.