ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
epub_img_tiles.c
Go to the documentation of this file.
1
24
25/* Compile the binder only where the ra8_mem tile cache and the atlas reader
26 * are on the include path (reflow / ra8_mem consumers and the host test
27 * build). Otherwise empty. */
28#if __has_include("ra8_tile_cache.h") && __has_include("jof.h")
29
30#include "epub_img_tiles.h"
31
32#include <stddef.h>
33#include <stdint.h>
34#include <string.h>
35
36#include "epub.h"
37#include "epub_entry.h"
38#include "jof.h"
39#include "ra8_attributes.h"
40#include "ra8_check.h"
41#include "ra8_err.h"
42#include "ra8_tile_cache.h"
43
45static const char* const s_tag = "epub_img_tiles";
46
47/* ---------------------------------------------------------------------------
48 * Small helpers.
49 * ---------------------------------------------------------------------------
50 */
51
68static int32_t internal_find(const epub_tile_binder_t* binder, uint32_t image_id)
69{
70 for (uint8_t i = 0U; i < binder->source_count; ++i) {
71 if (binder->sources[i].image_id == image_id) {
72 return (int32_t)i;
73 }
74 }
75 return -1;
76}
77
97static ra8_err_t
98internal_entry_pread(void* ctx, uint64_t offset, uint8_t* buf, size_t len, size_t* got)
99{
100 const epub_tile_source_t* src = (const epub_tile_source_t*)ctx;
101 return epub_entry_pread(src->book, src->path, offset, buf, len, got);
102}
103
122static ra8_err_t internal_measure_entry(epub_book_t* book, const char* path, uint64_t* out_size)
123{
124 epub_entry_reader_t reader = {};
125 ra8_err_t err = epub_entry_open(book, path, &reader, out_size);
126 if (err != k_ra8_ok) {
127 return err;
128 }
129 err = epub_entry_close(&reader);
130 return err;
131}
132
133/* ---------------------------------------------------------------------------
134 * Tile decode-on-miss.
135 * ---------------------------------------------------------------------------
136 */
137
161static ra8_err_t internal_tile_decode(void* ctx,
162 const ra8_tile_key_t* key,
163 uint8_t* cell,
164 uint32_t cell_bytes,
165 uint16_t* out_w,
166 uint16_t* out_h)
167{
169 const int32_t si = internal_find(binder, key->image_id);
170 if (si < 0) {
171 return k_ra8_err_not_found; /* GCOVR_EXCL_LINE -- get() rejects unregistered ids before cache */
172 }
173 epub_tile_source_t* src = &binder->sources[si];
174 const jof_pread_fn pread = (src->book != nullptr) ? internal_entry_pread : src->pread;
175 void* pctx = (src->book != nullptr) ? (void*)src : src->pread_ctx;
176 const ra8_err_t err = jof_read_tile(pread,
177 pctx,
178 &src->info,
179 key->tile_x,
180 key->tile_y,
181 binder->scratch,
182 binder->scratch_cap,
183 cell,
184 cell_bytes,
185 out_w,
186 out_h);
187 if (err == k_ra8_err_invalid_size) {
188 return k_ra8_err_no_mem; /* tile exceeds the cell / scratch budget */
189 }
190 return err;
191}
192
193/* ---------------------------------------------------------------------------
194 * Public API -- tile binder.
195 * ---------------------------------------------------------------------------
196 */
197
199 const ra8_tile_cache_cfg_t* storage,
200 uint8_t* scratch,
201 uint32_t scratch_cap)
202{
203 RA8_CHECK_NULL_PTR(binder, s_tag, "binder must not be nullptr");
204 RA8_CHECK_NULL_PTR(storage, s_tag, "storage must not be nullptr");
205 (void)memset(binder, 0, sizeof(*binder));
206 binder->scratch = scratch;
207 binder->scratch_cap = (scratch != nullptr) ? scratch_cap : 0U;
208 ra8_tile_cache_cfg_t cfg = *storage;
210 cfg.decode_ctx = binder;
211 return ra8_tile_cache_init(&binder->cache, &cfg);
212}
213
231static ra8_err_t internal_check_slot(const epub_tile_binder_t* binder, uint32_t image_id)
232{
233 if (binder->source_count >= (uint8_t)k_epub_tile_max_sources) {
234 return k_ra8_err_no_mem;
235 }
236 if (internal_find(binder, image_id) >= 0) {
238 }
239 return k_ra8_ok;
240}
241
263static ra8_err_t internal_fill_book_source(epub_tile_source_t* src,
264 epub_book_t* book,
265 const char* path,
266 size_t plen,
267 uint32_t image_id)
268{
269 src->book = book;
270 src->image_id = image_id;
271 (void)memcpy(src->path, path, plen + 1U);
272 ra8_err_t err = internal_measure_entry(book, path, &src->total_size);
273 if (err == k_ra8_ok) {
274 err = jof_parse(internal_entry_pread, src, src->total_size, &src->info);
275 }
276 if (err != k_ra8_ok) {
277 (void)memset(src, 0, sizeof(*src));
278 }
279 return err;
280}
281
283 epub_book_t* book,
284 const char* path,
285 uint32_t image_id)
286{
287 RA8_CHECK_NULL_PTR(binder, s_tag, "binder must not be nullptr");
288 RA8_CHECK_NULL_PTR(book, s_tag, "book must not be nullptr");
289 RA8_CHECK_NULL_PTR(path, s_tag, "path must not be nullptr");
290 const size_t plen = strlen(path);
291 if ((plen == 0U) || (plen >= (size_t)k_epub_max_path_len)) {
293 }
294 ra8_err_t err = internal_check_slot(binder, image_id);
295 if (err != k_ra8_ok) {
296 return err;
297 }
298 epub_tile_source_t* src = &binder->sources[binder->source_count];
299 (void)memset(src, 0, sizeof(*src));
300 err = internal_fill_book_source(src, book, path, plen, image_id);
301 if (err != k_ra8_ok) {
302 return err;
303 }
304 binder->source_count++;
305 return k_ra8_ok;
306}
307
309 jof_pread_fn pread,
310 void* pread_ctx,
311 uint64_t total_size,
312 uint32_t image_id)
313{
314 RA8_CHECK_NULL_PTR(binder, s_tag, "binder must not be nullptr");
315 RA8_CHECK_NULL_PTR(pread, s_tag, "pread must not be nullptr");
316 ra8_err_t err = internal_check_slot(binder, image_id);
317 if (err != k_ra8_ok) {
318 return err;
319 }
320 epub_tile_source_t* src = &binder->sources[binder->source_count];
321 (void)memset(src, 0, sizeof(*src));
322 src->pread = pread;
323 src->pread_ctx = pread_ctx;
324 src->total_size = total_size;
325 src->image_id = image_id;
326 err = jof_parse(pread, pread_ctx, total_size, &src->info);
327 if (err != k_ra8_ok) {
328 (void)memset(src, 0, sizeof(*src));
329 return err;
330 }
331 binder->source_count++;
332 return k_ra8_ok;
333}
334
336epub_tile_binder_info(const epub_tile_binder_t* binder, uint32_t image_id, jof_info_t* out_info)
337{
338 RA8_CHECK_NULL_PTR(binder, s_tag, "binder must not be nullptr");
339 RA8_CHECK_NULL_PTR(out_info, s_tag, "out_info must not be nullptr");
340 const int32_t si = internal_find(binder, image_id);
341 if (si < 0) {
342 return k_ra8_err_not_found;
343 }
344 *out_info = binder->sources[si].info;
345 return k_ra8_ok;
346}
347
349 uint32_t image_id,
350 uint16_t tile_x,
351 uint16_t tile_y,
352 ra8_tile_t* out_tile)
353{
354 RA8_CHECK_NULL_PTR(binder, s_tag, "binder must not be nullptr");
355 RA8_CHECK_NULL_PTR(out_tile, s_tag, "out_tile must not be nullptr");
356 const int32_t si = internal_find(binder, image_id);
357 if (si < 0) {
358 return k_ra8_err_not_found;
359 }
360 const jof_info_t* info = &binder->sources[si].info;
361 if (tile_x >= info->tile_cols) {
363 }
364 if (tile_y >= info->tile_rows) {
366 }
367 const ra8_tile_key_t key = {.image_id = image_id, .tile_x = tile_x, .tile_y = tile_y};
368 return ra8_tile_cache_get(&binder->cache, &key, out_tile);
369}
370
371ra8_err_t epub_tile_binder_put(epub_tile_binder_t* binder, const uint8_t* pixels)
372{
373 RA8_CHECK_NULL_PTR(binder, s_tag, "binder must not be nullptr");
374 RA8_CHECK_NULL_PTR(pixels, s_tag, "pixels must not be nullptr");
375 return ra8_tile_cache_put(&binder->cache, pixels);
376}
377
379 uint32_t image_id,
380 const ra8_tile_rect_t* view,
382 uint16_t max_tiles,
383 uint16_t* out_warmed)
384{
385 RA8_CHECK_NULL_PTR(binder, s_tag, "binder must not be nullptr");
386 RA8_CHECK_NULL_PTR(view, s_tag, "view must not be nullptr");
387 const int32_t si = internal_find(binder, image_id);
388 if (si < 0) {
389 return k_ra8_err_not_found;
390 }
391 const jof_info_t* info = &binder->sources[si].info;
392 const ra8_tile_prefetch_req_t req = {.image_id = image_id,
393 .view = *view,
394 .tile_cols = info->tile_cols,
395 .tile_rows = info->tile_rows,
396 .zoom = 0U,
397 .max_tiles = max_tiles,
398 .dir = dir};
399 return ra8_tile_cache_prefetch_pan(&binder->cache, &req, out_warmed);
400}
401
402/* ---------------------------------------------------------------------------
403 * Public API -- reflow img loader.
404 * ---------------------------------------------------------------------------
405 */
406
424static ra8_err_t internal_loader_args_ok(const epub_img_loader_t* ld, uint32_t href_len)
425{
426 if (ld->book == nullptr) {
428 }
429 if (ld->scratch == nullptr) {
431 }
432 if (ld->scratch_cap == 0U) {
434 }
435 if (href_len == 0U) {
437 }
438 if (href_len >= (uint32_t)k_epub_max_path_len) {
440 }
441 return k_ra8_ok;
442}
443
463static ra8_err_t internal_loader_null_ok(const void* ctx,
464 const char* href,
465 const uint8_t** out_bytes,
466 const size_t* out_len)
467{
468 RA8_CHECK_NULL_PTR(ctx, s_tag, "ctx must not be nullptr");
469 RA8_CHECK_NULL_PTR(href, s_tag, "href must not be nullptr");
470 RA8_CHECK_NULL_PTR(out_bytes, s_tag, "out_bytes must not be nullptr");
471 RA8_CHECK_NULL_PTR(out_len, s_tag, "out_len must not be nullptr");
472 return k_ra8_ok;
473}
474
476 const char* href,
477 uint32_t href_len,
478 const uint8_t** out_bytes,
479 size_t* out_len)
480{
481 const ra8_err_t nz = internal_loader_null_ok(ctx, href, out_bytes, out_len);
482 if (nz != k_ra8_ok) {
483 return nz;
484 }
485 *out_len = 0U;
487 const ra8_err_t ok = internal_loader_args_ok(ld, href_len);
488 if (ok != k_ra8_ok) {
489 return ok;
490 }
491 char path[k_epub_max_path_len];
492 (void)memcpy(path, href, (size_t)href_len);
493 path[href_len] = '\0';
494
495 size_t got = 0U;
496 const ra8_err_t err = epub_get_resource(ld->book, path, ld->scratch, ld->scratch_cap, &got);
497 if (err != k_ra8_ok) {
498 return err;
499 }
500 *out_bytes = ld->scratch;
501 *out_len = got;
502 return k_ra8_ok;
503}
504
505#else
506/* ra8_mem tile cache / atlas reader not on the include path for this app: the
507 * EPUB image-tile binder is unused here. A single typedef keeps the
508 * translation unit non-empty. */
510#endif /* __has_include("ra8_tile_cache.h") && __has_include("jof.h") */
EPUB (.epub) reader and chapter iterator for ra8-firmware.
@ k_epub_max_path_len
Max href length (incl.
Definition epub.h:89
ra8_err_t epub_get_resource(epub_book_t *book, const char *path, uint8_t *out_buf, size_t max_len, size_t *got_len)
Copy the raw bytes of an arbitrary archive resource into the caller's buffer (#140 external styleshee...
Iterative, bounded-RAM ZIP-entry extraction for the EPUB reader (#231).
ra8_err_t epub_entry_pread(epub_book_t *book, const char *path, uint64_t offset, uint8_t *buf, size_t len, size_t *got)
Positioned read of a stored (uncompressed) archive entry – windowed random access in bounded RAM (#23...
Definition epub_entry.c:446
ra8_err_t epub_entry_close(epub_entry_reader_t *reader)
Tear down a streaming-entry cursor and release its inflate state (#231).
Definition epub_entry.c:392
ra8_err_t epub_entry_open(epub_book_t *book, const char *path, epub_entry_reader_t *out_reader, uint64_t *out_size)
Begin a bounded-RAM streaming extraction of one archive entry (#231).
Definition epub_entry.c:331
int epub_img_tiles_unused_translation_unit_t
Page a large in-EPUB image through ra8_tile_cache + a real reflow <img> loader off the streaming read...
ra8_err_t epub_tile_binder_add(epub_tile_binder_t *binder, epub_book_t *book, const char *path, uint32_t image_id)
Register a stored in-archive JOF atlas entry under image_id (#231).
ra8_err_t epub_tile_binder_info(const epub_tile_binder_t *binder, uint32_t image_id, jof_info_t *out_info)
Report a registered image's parsed geometry (#231).
ra8_err_t epub_tile_binder_add_ext(epub_tile_binder_t *binder, jof_pread_fn pread, void *pread_ctx, uint64_t total_size, uint32_t image_id)
Register an externally-backed JOF atlas under image_id (#231).
ra8_err_t epub_tile_binder_prefetch_pan(epub_tile_binder_t *binder, uint32_t image_id, const ra8_tile_rect_t *view, ra8_tile_pan_dir_t dir, uint16_t max_tiles, uint16_t *out_warmed)
Predictively warm the tiles one step ahead of a panning image (#341).
@ k_epub_tile_max_sources
Distinct images per binder.
ra8_err_t epub_reflow_img_load(void *ctx, const char *href, uint32_t href_len, const uint8_t **out_bytes, size_t *out_len)
Real reflow <img> byte loader off an EPUB book (#231).
ra8_err_t epub_tile_binder_init(epub_tile_binder_t *binder, const ra8_tile_cache_cfg_t *storage, uint8_t *scratch, uint32_t scratch_cap)
Initialise a tile binder over caller-supplied tile-cache storage (#231).
ra8_err_t epub_tile_binder_put(epub_tile_binder_t *binder, const uint8_t *pixels)
Release one pin taken by epub_tile_binder_get() (#231).
ra8_err_t epub_tile_binder_get(epub_tile_binder_t *binder, uint32_t image_id, uint16_t tile_x, uint16_t tile_y, ra8_tile_t *out_tile)
Get (and pin) one decoded tile of a registered image (#231).
JOF band-tile atlas: the display-native normalized image format (#231, shared with the longstrip scro...
ra8_err_t(* jof_pread_fn)(void *ctx, uint64_t offset, uint8_t *buf, size_t len, size_t *got)
Positioned-read seam over an atlas backing store (DIP).
Definition jof.h:241
ra8_err_t jof_read_tile(jof_pread_fn pread, void *pread_ctx, const jof_info_t *info, uint16_t tile_x, uint16_t tile_y, uint8_t *scratch, uint32_t scratch_cap, uint8_t *out_px, uint32_t out_cap, uint16_t *out_w, uint16_t *out_h)
Read + decode one tile into caller pixels, in bounded RAM.
Definition jof.c:637
ra8_err_t jof_parse(jof_pread_fn pread, void *pread_ctx, uint64_t total_size, jof_info_t *out_info)
Parse + validate a JOF atlas's header, footer and index bounds.
Definition jof.c:379
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_no_mem
Static buffer exhausted (no dynamic memory on this project).
Definition ra8_err.h:142
@ k_ra8_err_out_of_range
Sensor or peripheral output out of valid range.
Definition ra8_err.h:337
@ k_ra8_err_invalid_arg
Invalid function argument.
Definition ra8_err.h:152
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
@ k_ra8_err_not_found
Requested item not found (lookup / search missed).
Definition ra8_err.h:173
@ k_ra8_err_invalid_size
Invalid size parameter (too large, too small, or misaligned).
Definition ra8_err.h:167
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
static uint8_t internal_find(ra8_port_pin_t pin)
Find the row watching a pin.
void * memset(void *dst, int value, size_t n)
Fill memory with a constant byte value.
size_t strlen(const char *s)
Calculate string length.
void * memcpy(void *dst, const void *src, size_t n)
Copy memory area between non-overlapping regions.
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.
Fixed-RAM-budget image-tile cache with LRU eviction (Layer 3b, #147).
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_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.
ra8_tile_pan_dir_t
Direction of viewport travel, for predictive pan prefetch.
Opened EPUB book.
Definition epub.h:286
Forward streaming cursor over one ZIP entry – inflate in bounded RAM (#231).
Definition epub_entry.h:93
Context for the real reflow <img> loader (epub_reflow_img_load).
uint8_t * scratch
Caller-owned encoded-bytes scratch.
size_t scratch_cap
Scratch capacity (bounded RAM ceiling).
epub_book_t * book
Book to resolve <img src> hrefs against.
Binds up to k_epub_tile_max_sources images to one tile cache.
epub_tile_source_t sources[k_epub_tile_max_sources]
Registered images.
uint8_t * scratch
Stored-tile staging for deflate atlases.
ra8_tile_cache_t cache
Owned tile cache (decode wired to the binder).
uint32_t scratch_cap
Capacity of scratch.
uint8_t source_count
Registered image count.
One registered atlas image (private to the binder; treat as opaque).
jof_pread_fn pread
External atlas read seam, or NULL.
uint32_t image_id
Tile-cache key namespace for this image.
uint64_t total_size
Atlas byte length (backing size).
void * pread_ctx
Context for pread.
char path[k_epub_max_path_len]
Entry path (book-backed only).
epub_book_t * book
Owning book, or NULL for external atlas.
jof_info_t info
Parsed + validated atlas geometry.
Parsed + validated geometry of one JOF atlas.
Definition jof.h:208
uint16_t tile_rows
Ceil(height / tile_h) tile rows.
Definition jof.h:214
uint16_t tile_cols
Ceil(width / tile_w) tile columns.
Definition jof.h:213
Caller-supplied storage + decoder for ra8_tile_cache_init.
ra8_tile_decode_fn decode
Decode-on-miss callback.
void * decode_ctx
Opaque context passed to decode.
Identifies one decoded image tile.
uint16_t tile_y
Tile row index (in tile units).
uint16_t tile_x
Tile column index (in tile units).
uint32_t image_id
Source image identifier.
A predictive pan-prefetch request: what is visible + where it heads.
An inclusive rectangle of tile grid coordinates (the visible tiles).
A pinned view of a cached tile returned by ra8_tile_cache_get.