ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_tile_cache.c
Go to the documentation of this file.
1
21
22#include "ra8_tile_cache.h"
23
24#include <stddef.h>
25#include <stdint.h>
26#include <string.h>
27
28#include "ra8_attributes.h"
29#include "ra8_check.h"
30#include "ra8_err.h"
31#include "ra8_keycache.h"
32
34static const char* const s_tag = "ra8_tile_cache";
35
63internal_tile_decode(void* ctx, const void* key, uint8_t* cell, uint32_t cell_bytes, void* user)
64{
65 const ra8_tile_cache_t* tc = (const ra8_tile_cache_t*)ctx;
66 const ra8_tile_key_t* tk = (const ra8_tile_key_t*)key;
67 ra8_tile_dims_t* dims = (ra8_tile_dims_t*)user;
68 uint16_t w = 0;
69 uint16_t h = 0;
70 const ra8_err_t rerr = tc->decode(tc->decode_ctx, tk, cell, cell_bytes, &w, &h);
71 if (rerr != k_ra8_ok) {
72 return rerr;
73 }
74 dims->w = w;
75 dims->h = h;
76 return k_ra8_ok;
77}
78
97RA8_INTERNAL static uint16_t internal_clamp_tile(uint32_t index, uint16_t count)
98{
99 const uint32_t last = (uint32_t)count - 1U;
100 return (uint16_t)((index > last) ? last : index);
101}
102
104 uint32_t py,
105 uint32_t pw,
106 uint32_t ph,
107 uint16_t tile_w,
108 uint16_t tile_h,
109 uint16_t tile_cols,
110 uint16_t tile_rows,
111 ra8_tile_rect_t* out)
112{
113 RA8_CHECK_NULL_PTR(out, s_tag, "out rect must not be nullptr");
114 /* Decision: an empty pixel rectangle names no tiles (2 conditions). */
115 if ((pw == 0U) || (ph == 0U)) {
116 ra8_log_error(s_tag, "pixel rect must have a positive extent");
118 }
119 /* Decision: the tile geometry must describe a real grid (4 conditions). */
120 if ((tile_w == 0U) || (tile_h == 0U) || (tile_cols == 0U) || (tile_rows == 0U)) {
121 ra8_log_error(s_tag, "tile geometry must be non-zero on every axis");
123 }
124 out->tx0 = internal_clamp_tile(px / (uint32_t)tile_w, tile_cols);
125 out->ty0 = internal_clamp_tile(py / (uint32_t)tile_h, tile_rows);
126 out->tx1 = internal_clamp_tile(((px + pw) - 1U) / (uint32_t)tile_w, tile_cols);
127 out->ty1 = internal_clamp_tile(((py + ph) - 1U) / (uint32_t)tile_h, tile_rows);
128 return k_ra8_ok;
129}
130
132{
133 RA8_CHECK_NULL_PTR(tc, s_tag, "tc must not be nullptr");
134 RA8_CHECK_NULL_PTR(cfg, s_tag, "cfg must not be nullptr");
135 RA8_CHECK_NULL_PTR(cfg->decode, s_tag, "decode must not be nullptr");
136 (void)memset(tc, 0, sizeof(*tc));
137 tc->decode = cfg->decode;
138 tc->decode_ctx = cfg->decode_ctx;
139 ra8_keycache_cfg_t kcfg = {};
140 kcfg.cell_mem = cfg->cell_mem;
141 kcfg.cell_bytes = cfg->cell_bytes;
142 kcfg.cell_count = cfg->cell_count;
143 kcfg.key_mem = (uint8_t*)cfg->keys;
144 kcfg.key_bytes = (uint32_t)sizeof(ra8_tile_key_t);
145 kcfg.user_mem = (uint8_t*)cfg->dims;
146 kcfg.user_bytes = (uint32_t)sizeof(ra8_tile_dims_t);
147 kcfg.meta = cfg->meta;
148 kcfg.buckets = cfg->buckets;
149 kcfg.bucket_count = cfg->bucket_count;
151 kcfg.render_ctx = tc;
152 return ra8_keycache_init(&tc->kc, &kcfg);
153}
154
156{
157 RA8_CHECK_NULL_PTR(tc, s_tag, "tc must not be nullptr");
158 RA8_CHECK_NULL_PTR(key, s_tag, "key must not be nullptr");
159 RA8_CHECK_NULL_PTR(out_tile, s_tag, "out_tile must not be nullptr");
160 ra8_keycache_view_t v = {};
161 const ra8_err_t err = ra8_keycache_get(&tc->kc, key, &v);
162 if (err != k_ra8_ok) {
163 return err;
164 }
165 const ra8_tile_dims_t* dims = (const ra8_tile_dims_t*)v.user;
166 *out_tile = (ra8_tile_t){.pixels = v.data, .width = dims->w, .height = dims->h};
167 return k_ra8_ok;
168}
169
171{
172 RA8_CHECK_NULL_PTR(tc, s_tag, "tc must not be nullptr");
173 RA8_CHECK_NULL_PTR(pixels, s_tag, "pixels must not be nullptr");
174 return ra8_keycache_put(&tc->kc, pixels);
175}
176
178{
179 if (tc == nullptr) {
180 return 0U;
181 }
182 if (tc->kc.cfg.cell_mem == nullptr) {
183 return 0U; /* never initialised: report no capacity */
184 }
185 return tc->kc.cfg.cell_count;
186}
187
189{
190 RA8_CHECK_NULL_PTR(tc, s_tag, "tc must not be nullptr");
191 RA8_CHECK_NULL_PTR(key, s_tag, "key must not be nullptr");
192 return ra8_keycache_prefetch(&tc->kc, key);
193}
194
205typedef struct {
206 uint16_t x;
207 uint16_t y;
208 uint16_t step_x;
209 uint16_t step_y;
210 uint16_t count;
212
236{
237 const ra8_tile_rect_t v = req->view;
238 if (v.tx0 > v.tx1) {
240 }
241 if (v.ty0 > v.ty1) {
243 }
244 if ((uint32_t)v.tx1 >= (uint32_t)req->tile_cols) {
246 }
247 if ((uint32_t)v.ty1 >= (uint32_t)req->tile_rows) {
249 }
250 return k_ra8_ok;
251}
252
278{
279 const ra8_tile_rect_t v = req->view;
280 const uint16_t v_run = (uint16_t)((v.ty1 - v.ty0) + 1U);
281 const uint16_t h_run = (uint16_t)((v.tx1 - v.tx0) + 1U);
282 switch (req->dir) {
284 if (((uint32_t)v.tx1 + 1U) >= (uint32_t)req->tile_cols) {
285 return false;
286 }
287 *out = (priv_pan_line_t){.x = (uint16_t)(v.tx1 + 1U),
288 .y = v.ty0,
289 .step_x = 0U,
290 .step_y = 1U,
291 .count = v_run};
292 return true;
294 if (v.tx0 == 0U) {
295 return false;
296 }
297 *out = (priv_pan_line_t){.x = (uint16_t)(v.tx0 - 1U),
298 .y = v.ty0,
299 .step_x = 0U,
300 .step_y = 1U,
301 .count = v_run};
302 return true;
304 if (((uint32_t)v.ty1 + 1U) >= (uint32_t)req->tile_rows) {
305 return false;
306 }
307 *out = (priv_pan_line_t){.x = v.tx0,
308 .y = (uint16_t)(v.ty1 + 1U),
309 .step_x = 1U,
310 .step_y = 0U,
311 .count = h_run};
312 return true;
314 if (v.ty0 == 0U) {
315 return false;
316 }
317 *out = (priv_pan_line_t){.x = v.tx0,
318 .y = (uint16_t)(v.ty0 - 1U),
319 .step_x = 1U,
320 .step_y = 0U,
321 .count = h_run};
322 return true;
324 default:
325 return false;
326 }
327}
328
330 const ra8_tile_prefetch_req_t* req,
331 uint16_t* out_warmed)
332{
333 RA8_CHECK_NULL_PTR(tc, s_tag, "tc must not be nullptr");
334 RA8_CHECK_NULL_PTR(req, s_tag, "req must not be nullptr");
335 if (out_warmed != nullptr) {
336 *out_warmed = 0U;
337 }
338 const ra8_err_t verr = internal_validate_req(req);
339 if (verr != k_ra8_ok) {
340 return verr;
341 }
342 priv_pan_line_t line = {};
343 if (!internal_pan_line(req, &line)) {
344 return k_ra8_ok; /* at an image edge or not panning: nothing to warm */
345 }
346 const uint16_t cap = (uint16_t)((line.count < req->max_tiles) ? line.count : req->max_tiles);
347 uint16_t warmed = 0U;
348 for (uint16_t i = 0U; i < cap; ++i) {
349 const ra8_tile_key_t key = {.image_id = req->image_id,
350 .tile_x = (uint16_t)(line.x + (uint16_t)(line.step_x * i)),
351 .tile_y = (uint16_t)(line.y + (uint16_t)(line.step_y * i)),
352 .zoom = req->zoom};
353 if (ra8_tile_cache_prefetch(tc, &key) != k_ra8_ok) {
354 break; /* best-effort: a full/failed cache stops the sweep, not the pan */
355 }
356 warmed++;
357 }
358 if (out_warmed != nullptr) {
359 *out_warmed = warmed;
360 }
361 return k_ra8_ok;
362}
363
365 uint32_t* out_hits,
366 uint32_t* out_misses,
367 uint32_t* out_evictions)
368{
369 RA8_CHECK_NULL_PTR(tc, s_tag, "tc must not be nullptr");
370 if (tc->kc.cfg.cell_mem == nullptr) {
372 }
373 return ra8_keycache_stats(&tc->kc, out_hits, out_misses, out_evictions);
374}
static const char * s_tag
Logging / check tag.
Definition ra8_app.c:17
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
Validation and Error-Checking Macros for ra8-firmware.
#define RA8_CHECK_NULL_PTR(ptr, tag, message)
Reject nullptr pointer, returning k_ra8_err_null_ptr.
Definition ra8_check.h:243
Error Code Definitions for ra8-firmware.
@ k_ra8_err_invalid_arg
Invalid function argument.
Definition ra8_err.h:152
@ k_ra8_err_invalid_state
Module in wrong state for requested operation.
Definition ra8_err.h:161
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
void * memset(void *dst, int value, size_t n)
Fill memory with a constant byte value.
The one reusable hash + pin + evict cache engine (#147, #345).
ra8_err_t ra8_keycache_get(ra8_keycache_t *kc, const void *key, ra8_keycache_view_t *out_view)
Get (and pin) the cell for key, rendering it on a miss.
ra8_err_t ra8_keycache_stats(const ra8_keycache_t *kc, uint32_t *out_hits, uint32_t *out_misses, uint32_t *out_evictions)
Report the cache hit / miss / eviction counters.
ra8_err_t ra8_keycache_init(ra8_keycache_t *kc, const ra8_keycache_cfg_t *cfg)
Initialise a cache engine over caller-supplied storage.
ra8_err_t ra8_keycache_put(ra8_keycache_t *kc, const uint8_t *data)
Release one pin on a cell previously returned by ra8_keycache_get.
ra8_err_t ra8_keycache_prefetch(ra8_keycache_t *kc, const void *key)
Warm the cell for key into the cache without holding a pin.
#define ra8_log_error(tag, message)
RA8 log error.
Definition ra8_log.h:335
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_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.
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.
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.
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_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.
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.
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.
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.
static ra8_err_t internal_validate_req(const ra8_tile_prefetch_req_t *req)
Reject a structurally invalid prefetch request.
Fixed-RAM-budget image-tile cache with LRU eviction (Layer 3b, #147).
@ k_ra8_tile_pan_none
No travel: prefetch is a no-op.
@ k_ra8_tile_pan_up
Warm the row above the viewport.
@ k_ra8_tile_pan_down
Warm the row below the viewport.
@ k_ra8_tile_pan_left
Warm the column left of the viewport.
@ k_ra8_tile_pan_right
Warm the column right of the viewport.
The lead-edge tile run a pan prefetch walks (one row or one column).
uint16_t count
Tiles on the lead edge (pre-budget).
uint16_t step_y
Per-tile row delta (0 or 1).
uint16_t step_x
Per-tile column delta (0 or 1).
uint16_t y
First lead tile row.
uint16_t x
First lead tile column.
Caller-supplied storage + policy + renderer for ra8_keycache_init.
uint32_t bucket_count
Number of hash buckets (>= 1).
uint32_t user_bytes
Bytes per user descriptor (may be 0).
uint8_t * cell_mem
cell_count * cell_bytes of cell storage.
uint32_t cell_bytes
Bytes per cell (the rendered payload).
uint8_t * key_mem
cell_count * key_bytes of key storage.
int32_t * buckets
bucket_count hash-bucket heads.
uint32_t key_bytes
Bytes per key (>= 1).
ra8_keycache_cell_t * meta
cell_count link-metadata entries.
uint32_t cell_count
Number of cells.
void * render_ctx
Opaque context passed to render.
ra8_keycache_render_fn render
Render-on-miss callback.
uint8_t * user_mem
cell_count * user_bytes, or NULL if none.
ra8_keycache_cfg_t cfg
Configuration (copied at init).
A pinned view of a cached cell returned by ra8_keycache_get.
uint8_t * data
Cell payload (cell_bytes wide).
void * user
Per-cell user descriptor, or NULL.
Caller-supplied storage + decoder for ra8_tile_cache_init.
ra8_tile_dims_t * dims
cell_count dimension descriptors.
uint32_t cell_bytes
Bytes per cell (max decoded tile).
ra8_tile_decode_fn decode
Decode-on-miss callback.
uint8_t * cell_mem
cell_count * cell_bytes of tile storage.
uint32_t cell_count
Number of cells.
ra8_keycache_cell_t * meta
cell_count link-metadata entries.
uint32_t bucket_count
Number of hash buckets (>= 1).
ra8_tile_key_t * keys
cell_count key-storage entries.
void * decode_ctx
Opaque context passed to decode.
int32_t * buckets
bucket_count hash-bucket heads.
Tile-cache state (caller-owned; treat as private).
ra8_keycache_t kc
Underlying keyed-LRU cache.
void * decode_ctx
Caller's decoder context.
ra8_tile_decode_fn decode
Caller's tile decoder.
Per-cell user descriptor: the decoded tile dimensions.
uint16_t h
Decoded tile height in pixels.
uint16_t w
Decoded tile width in pixels.
Identifies one decoded image tile.
A predictive pan-prefetch request: what is visible + where it heads.
uint16_t max_tiles
Residency budget: warm at most this many.
ra8_tile_rect_t view
The tiles the viewport currently straddles.
uint16_t tile_rows
Image tile rows (lead-edge clamp bound).
uint16_t zoom
Zoom / mip level for the key (0 = native).
ra8_tile_pan_dir_t dir
Direction of viewport travel.
uint32_t image_id
Tile-cache key image id (the image panned).
uint16_t tile_cols
Image tile columns (lead-edge clamp bound).
An inclusive rectangle of tile grid coordinates (the visible tiles).
uint16_t ty0
Topmost visible tile row (inclusive).
uint16_t tx1
Rightmost visible tile column (inclusive).
uint16_t ty1
Bottommost visible tile row (inclusive).
uint16_t tx0
Leftmost visible tile column (inclusive).
A pinned view of a cached tile returned by ra8_tile_cache_get.