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

Fixed-budget image-tile cache – implementation (Layer 3b, #147). More...

#include "ra8_tile_cache.h"
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include "ra8_attributes.h"
#include "ra8_check.h"
#include "ra8_err.h"
#include "ra8_keycache.h"
Include dependency graph for ra8_tile_cache.c:

Go to the source code of this file.

Data Structures

struct  priv_pan_line_t
 The lead-edge tile run a pan prefetch walks (one row or one column). More...

Functions

static ra8_err_t internal_tile_decode (void *ctx, const void *key, uint8_t *cell, uint32_t cell_bytes, void *user)
 Decode trampoline: adapt ra8_tile_decode_fn to the keycache seam.
static uint16_t internal_clamp_tile (uint32_t index, uint16_t count)
 Clamp a tile index to the last valid index of a grid dimension.
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).
static ra8_err_t internal_validate_req (const ra8_tile_prefetch_req_t *req)
 Reject a structurally invalid prefetch request.
static bool internal_pan_line (const ra8_tile_prefetch_req_t *req, priv_pan_line_t *out)
 Compute the lead-edge tile run for a pan direction, or none at an edge.
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.

Variables

static const char *const s_tag = "ra8_tile_cache"
 Module log tag.

Detailed Description

Fixed-budget image-tile cache – implementation (Layer 3b, #147).

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

A thin typed facade over ::ra8_keycache, the image counterpart of ::ra8_glyph_atlas: the tile key is the cache key, the decoded tile is the cell payload, and the decoded width/height ride in the per-cell ra8_tile_dims_t user descriptor. A small decode trampoline adapts the public ra8_tile_decode_fn (out_w/out_h) to the keycache's render-on-miss seam (user descriptor) so the production stb_image-backed decoder and the test stubs are unchanged. All cache mechanics – the single LRU list, pinned-cell skip, hash chaining, eviction – live in ::ra8_keycache.

Definition in file ra8_tile_cache.c.

Function Documentation

◆ internal_clamp_tile()

uint16_t internal_clamp_tile ( uint32_t index,
uint16_t count )
static

Clamp a tile index to the last valid index of a grid dimension.

A rectangle that runs past the image edge names the last tile rather than an out-of-grid index the prefetch would have to re-clamp, so the clamp lives here, once, at the point the index is formed.

Parameters
[in]indexCandidate tile index.
[in]countTile count on that axis (> 0).
Returns
The index, or count - 1 when it ran past the grid.
Return values
indexThe index was already inside the grid.
count - 1The index addressed past the last tile.
Precondition
count is non-zero (validated by the caller).
index is a tile index, not a pixel coordinate.
Postcondition
The result is strictly less than count.
No state is modified (pure).
Note
Pure; thread-safe.
Since
0.1.0

Definition at line 97 of file ra8_tile_cache.c.

References RA8_INTERNAL.

Referenced by ra8_tile_rect_of_pixels().

◆ internal_pan_line()

bool internal_pan_line ( const ra8_tile_prefetch_req_t * req,
priv_pan_line_t * out )
static

Compute the lead-edge tile run for a pan direction, or none at an edge.

Selects the row/column one step beyond req->view in req->dir and clamps it to the tile grid: a pan already against the image edge (or k_ra8_tile_pan_none) yields no run. Each direction's edge test is an independent single-condition guard.

Parameters
[in]reqThe validated prefetch request.
[out]outReceives the lead-edge run when the return is true.
Returns
true if a lead edge exists to warm, false at an image edge / no pan.
Return values
true*out holds the run to walk.
falseNothing to warm (*out is untouched).
Precondition
req passed internal_validate_req; out is writable.
req->view lies inside the tile grid.
Postcondition
A true return leaves *out fully populated.
No cache or request state is modified.
Note
Pure; thread-safe.
Since
0.1.0

Definition at line 277 of file ra8_tile_cache.c.

References ra8_tile_prefetch_req_t::dir, k_ra8_tile_pan_down, k_ra8_tile_pan_left, k_ra8_tile_pan_none, k_ra8_tile_pan_right, k_ra8_tile_pan_up, RA8_INTERNAL, ra8_tile_prefetch_req_t::tile_cols, ra8_tile_prefetch_req_t::tile_rows, ra8_tile_rect_t::tx0, ra8_tile_rect_t::tx1, ra8_tile_rect_t::ty0, ra8_tile_rect_t::ty1, and ra8_tile_prefetch_req_t::view.

Referenced by ra8_tile_cache_prefetch_pan().

◆ internal_tile_decode()

ra8_err_t internal_tile_decode ( void * ctx,
const void * key,
uint8_t * cell,
uint32_t cell_bytes,
void * user )
static

Decode trampoline: adapt ra8_tile_decode_fn to the keycache seam.

Casts the keycache render context back to the owning cache, calls the caller's tile decoder for the cell, and on success records the decoded width/height into the cell's ra8_tile_dims_t descriptor.

Parameters
[in]ctxThe owning ra8_tile_cache_t (keycache render_ctx).
[in]keyThe ra8_tile_key_t to decode.
[out]cellDestination pixel buffer (cell_bytes writable).
[in]cell_bytesCell capacity in bytes.
[out]userThe cell's ra8_tile_dims_t descriptor.
Returns
ra8_err_t Error code.
Return values
k_ra8_okThe tile was decoded and the descriptor recorded.
k_ra8_err_*The caller's decoder error (descriptor left untouched).
Precondition
ctx and user are non-NULL (the keycache guarantees both here).
key points at a valid ra8_tile_key_t.
Postcondition
On success *user holds the decoded tile dimensions.
On failure the descriptor is not written.
Note
Not thread-safe.
Since
0.1.0

Definition at line 63 of file ra8_tile_cache.c.

References ra8_tile_cache_t::decode, ra8_tile_cache_t::decode_ctx, ra8_tile_dims_t::h, k_ra8_ok, and ra8_tile_dims_t::w.

Referenced by ra8_tile_cache_init().

◆ internal_validate_req()

ra8_err_t internal_validate_req ( const ra8_tile_prefetch_req_t * req)
static

Reject a structurally invalid prefetch request.

Each guard is an independent single-condition check kept intact here: the visible rectangle must be ordered (tx0<=tx1, ty0<=ty1) and lie inside the tile grid (tx1<tile_cols, ty1<tile_rows).

Parameters
[in]reqThe prefetch request to validate (non-NULL).
Returns
ra8_err_t Error code.
Return values
k_ra8_okThe request is well-formed.
k_ra8_err_invalid_argA rectangle bound is unordered or off-grid.
Precondition
req is non-NULL (the caller checked it).
req->view is the caller's visible tile rectangle.
Postcondition
No state is modified (pure validation).
A non-ok return means a bound was unordered or off-grid.
Note
Pure; thread-safe.
Since
0.1.0

Definition at line 235 of file ra8_tile_cache.c.

References k_ra8_err_invalid_arg, k_ra8_ok, RA8_INTERNAL, ra8_tile_prefetch_req_t::tile_cols, ra8_tile_prefetch_req_t::tile_rows, ra8_tile_rect_t::tx0, ra8_tile_rect_t::tx1, ra8_tile_rect_t::ty0, ra8_tile_rect_t::ty1, and ra8_tile_prefetch_req_t::view.

Referenced by ra8_tile_cache_prefetch_pan().

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

Variable Documentation

◆ s_tag

const char* const s_tag = "ra8_tile_cache"
static

Module log tag.

Definition at line 34 of file ra8_tile_cache.c.