ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
zoom_tiles.c
Go to the documentation of this file.
1
22
23#ifdef __has_include
24#if __has_include("ra8_tile_cache.h")
51#define ZOOM_HAVE_TILES
52#endif
53#endif
54
55#ifdef ZOOM_HAVE_TILES
56
57#include "zoom_tiles.h"
58
59#include <stdint.h>
60#include <string.h>
61
62#include "ra8_attributes.h"
63#include "ra8_check.h"
64#include "ra8_err.h"
65#include "ra8_tile_cache.h"
66#include "ra8_ui.h"
67#include "zoom.h"
68
70static const char* const s_tag = "zoom_tiles";
71
72/* zoom_tiles_prefetch forwards a zoom_pan_t straight into the cache's
73 * ra8_tile_pan_dir_t rather than switching over it. That is only sound while the
74 * two enumerations agree value for value, so the agreement is pinned here rather
75 * than asserted in prose -- a renumbering of either enum fails the build instead
76 * of quietly warming the wrong edge. */
77static_assert((uint8_t)k_zoom_pan_none == (uint8_t)k_ra8_tile_pan_none,
78 "zoom_pan_t and ra8_tile_pan_dir_t must agree: none");
79static_assert((uint8_t)k_zoom_pan_left == (uint8_t)k_ra8_tile_pan_left,
80 "zoom_pan_t and ra8_tile_pan_dir_t must agree: left");
81static_assert((uint8_t)k_zoom_pan_right == (uint8_t)k_ra8_tile_pan_right,
82 "zoom_pan_t and ra8_tile_pan_dir_t must agree: right");
83static_assert((uint8_t)k_zoom_pan_up == (uint8_t)k_ra8_tile_pan_up,
84 "zoom_pan_t and ra8_tile_pan_dir_t must agree: up");
85static_assert((uint8_t)k_zoom_pan_down == (uint8_t)k_ra8_tile_pan_down,
86 "zoom_pan_t and ra8_tile_pan_dir_t must agree: down");
87
108typedef enum : uint16_t {
109 k_zoom_tiles_native_level = 0U,
110} zoom_tiles_key_t;
111
125typedef struct {
126 uint32_t x;
127 uint32_t y;
128 uint32_t w;
129 uint32_t h;
130} zoom_tile_span_t;
131
160static void internal_tile_copy(const ra8_tile_t* tile,
161 uint32_t org_x,
162 uint32_t org_y,
163 const zoom_tile_span_t* span,
164 uint8_t* out,
165 uint32_t stride)
166{
167 const uint32_t x0 = (span->x > org_x) ? span->x : org_x;
168 const uint32_t y0 = (span->y > org_y) ? span->y : org_y;
169 const uint32_t tx_end = org_x + (uint32_t)tile->width;
170 const uint32_t ty_end = org_y + (uint32_t)tile->height;
171 const uint32_t x1 = ((span->x + span->w) < tx_end) ? (span->x + span->w) : tx_end;
172 const uint32_t y1 = ((span->y + span->h) < ty_end) ? (span->y + span->h) : ty_end;
173 for (uint32_t sy = y0; sy < y1; ++sy) {
174 const uint8_t* srow = &tile->pixels[((sy - org_y) * (uint32_t)tile->width) + (x0 - org_x)];
175 uint8_t* drow = &out[((sy - span->y) * stride) + (x0 - span->x)];
176 (void)memcpy(drow, srow, (size_t)(x1 - x0));
177 }
178}
179
211static ra8_err_t internal_tile_fetch(zoom_tile_src_t* ts,
212 uint16_t tx,
213 uint16_t ty,
214 const zoom_tile_span_t* span,
215 uint8_t* out,
216 uint32_t stride)
217{
218 const ra8_tile_key_t key = {
219 .image_id = ts->image_id,
220 .tile_x = tx,
221 .tile_y = ty,
222 .zoom = (uint16_t)k_zoom_tiles_native_level,
223 .reserved = 0U,
224 };
225 ra8_tile_t tile = {};
226 RA8_RETURN_ON_ERROR(ra8_tile_cache_get(ts->cache, &key, &tile), s_tag, "tile fetch");
227
228 const uint32_t org_x = (uint32_t)tx * (uint32_t)ts->tile_w;
229 const uint32_t org_y = (uint32_t)ty * (uint32_t)ts->tile_h;
230 const uint32_t exp_w =
231 ((org_x + (uint32_t)ts->tile_w) > ts->width) ? (ts->width - org_x) : (uint32_t)ts->tile_w;
232 const uint32_t exp_h =
233 ((org_y + (uint32_t)ts->tile_h) > ts->height) ? (ts->height - org_y) : (uint32_t)ts->tile_h;
234 /* Decision: a tile that did not decode to the declared gray8 geometry is a
235 * format mismatch, not a picture (2 conditions). */
236 if (((uint32_t)tile.width != exp_w) || ((uint32_t)tile.height != exp_h)) {
237 (void)ra8_tile_cache_put(ts->cache, tile.pixels);
238 ra8_log_error(s_tag, "tile decoded to an unexpected extent (wrong bpp or geometry)");
240 }
241 internal_tile_copy(&tile, org_x, org_y, span, out, stride);
242 return ra8_tile_cache_put(ts->cache, tile.pixels);
243}
244
246 ra8_tile_cache_t* cache,
247 uint32_t image_id,
248 uint32_t width,
249 uint32_t height,
250 uint16_t tile_w,
251 uint16_t tile_h)
252{
253 RA8_CHECK_NULL_PTR(ts, s_tag, "binding must not be nullptr");
254 RA8_CHECK_NULL_PTR(cache, s_tag, "tile cache must not be nullptr");
255 /* Decision: every extent and tile edge must be non-zero (4 conditions). */
256 if ((width == 0U) || (height == 0U) || (tile_w == 0U) || (tile_h == 0U)) {
257 ra8_log_error(s_tag, "image extent and tile edges must all be non-zero");
259 }
260 const uint32_t cols = ((width + (uint32_t)tile_w) - 1U) / (uint32_t)tile_w;
261 const uint32_t rows = ((height + (uint32_t)tile_h) - 1U) / (uint32_t)tile_h;
262 /* Decision: the derived grid must fit the cache key's 16-bit tile indices. */
263 if ((cols > (uint32_t)UINT16_MAX) || (rows > (uint32_t)UINT16_MAX)) {
264 ra8_log_error(s_tag, "derived tile grid exceeds the 16-bit tile index range");
266 }
267 ts->cache = cache;
268 ts->image_id = image_id;
269 ts->width = width;
270 ts->height = height;
271 ts->tile_w = tile_w;
272 ts->tile_h = tile_h;
273 ts->tile_cols = (uint16_t)cols;
274 ts->tile_rows = (uint16_t)rows;
275 return k_ra8_ok;
276}
277
279{
280 RA8_CHECK_NULL_PTR(ts, s_tag, "binding must not be nullptr");
281 RA8_CHECK_NULL_PTR(out, s_tag, "source out must not be nullptr");
282 RA8_CHECK_NULL_PTR(ts->cache, s_tag, "binding was never initialised");
283 return zoom_source_init(out, zoom_tile_read, ts, ts->width, ts->height);
284}
285
316static ra8_err_t internal_walk_tile_row(zoom_tile_src_t* ts,
317 uint16_t ty,
318 uint16_t tx0,
319 uint16_t tx1,
320 const zoom_tile_span_t* span,
321 uint8_t* out,
322 uint32_t stride)
323{
324 for (uint16_t tx = tx0; tx <= tx1; ++tx) {
325 RA8_RETURN_ON_ERROR(internal_tile_fetch(ts, tx, ty, span, out, stride), s_tag, "tile copy");
326 }
327 return k_ra8_ok;
328}
329
358static ra8_err_t internal_walk_tiles(zoom_tile_src_t* ts,
359 const ra8_tile_rect_t* tiles,
360 const zoom_tile_span_t* span,
361 uint8_t* out,
362 uint32_t stride)
363{
364 for (uint16_t ty = tiles->ty0; ty <= tiles->ty1; ++ty) {
365 RA8_RETURN_ON_ERROR(internal_walk_tile_row(ts, ty, tiles->tx0, tiles->tx1, span, out, stride),
366 s_tag,
367 "tile row");
368 }
369 return k_ra8_ok;
370}
371
403static ra8_err_t internal_read_rect_ok(const zoom_tile_src_t* ts,
404 uint32_t x,
405 uint32_t y,
406 uint32_t w,
407 uint32_t h,
408 uint32_t out_stride)
409{
410 /* Decision: an empty rectangle, or one narrower than its own stride, is a
411 * caller defect rather than something to clamp (3 conditions). */
412 if ((w == 0U) || (h == 0U) || (out_stride < w)) {
413 ra8_log_error(s_tag, "read rect must be non-empty and fit its stride");
415 }
416 /* Decision: the rectangle must lie wholly inside the bound image. */
417 if (((x + w) > ts->width) || ((y + h) > ts->height)) {
418 ra8_log_error(s_tag, "read rect leaves the bound image");
420 }
421 return k_ra8_ok;
422}
423
424ra8_err_t zoom_tile_read(void* ctx,
425 uint32_t x,
426 uint32_t y,
427 uint32_t w,
428 uint32_t h,
429 uint8_t* out,
430 uint32_t out_stride)
431{
432 RA8_CHECK_NULL_PTR(ctx, s_tag, "read ctx must not be nullptr");
433 RA8_CHECK_NULL_PTR(out, s_tag, "read destination must not be nullptr");
435 RA8_CHECK_NULL_PTR(ts->cache, s_tag, "binding was never initialised");
436 RA8_RETURN_ON_ERROR(internal_read_rect_ok(ts, x, y, w, h, out_stride), s_tag, "read rect check");
437
438 ra8_tile_rect_t tiles = {};
440 y,
441 w,
442 h,
443 ts->tile_w,
444 ts->tile_h,
445 ts->tile_cols,
446 ts->tile_rows,
447 &tiles),
448 s_tag,
449 "pixel rect to tile rect");
450
451 const zoom_tile_span_t span = {.x = x, .y = y, .w = w, .h = h};
452 return internal_walk_tiles(ts, &tiles, &span, out, out_stride);
453}
454
456 const zoom_view_t* v,
457 zoom_pan_t dir,
458 uint16_t max_tiles,
459 uint16_t* out_warmed)
460{
461 RA8_CHECK_NULL_PTR(ts, s_tag, "binding must not be nullptr");
462 RA8_CHECK_NULL_PTR(v, s_tag, "view must not be nullptr");
463 RA8_CHECK_NULL_PTR(ts->cache, s_tag, "binding was never initialised");
464
465 ra8_ui_rect_t win = {};
466 RA8_RETURN_ON_ERROR(zoom_view_window(v, &win), s_tag, "visible window");
467
468 ra8_tile_rect_t tiles = {};
470 (uint32_t)win.y,
471 (uint32_t)win.w,
472 (uint32_t)win.h,
473 ts->tile_w,
474 ts->tile_h,
475 ts->tile_cols,
476 ts->tile_rows,
477 &tiles),
478 s_tag,
479 "visible window to tile rect");
480
481 const ra8_tile_prefetch_req_t req = {
482 .image_id = ts->image_id,
483 .view = tiles,
484 .tile_cols = ts->tile_cols,
485 .tile_rows = ts->tile_rows,
486 .zoom = (uint16_t)k_zoom_tiles_native_level,
487 .max_tiles = max_tiles,
488 .dir = (ra8_tile_pan_dir_t)dir,
489 };
490 return ra8_tile_cache_prefetch_pan(ts->cache, &req, out_warmed);
491}
492
493#endif /* ZOOM_HAVE_TILES */
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_RETURN_ON_ERROR(err, tag, message)
Early return on error, propagating the code upward.
Definition ra8_check.h:184
#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_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_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
void * memcpy(void *dst, const void *src, size_t n)
Copy memory area between non-overlapping regions.
#define ra8_log_error(tag, message)
RA8 log error.
Definition ra8_log.h:335
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_tile_pan_dir_t
Direction of viewport travel, for predictive pan prefetch.
@ 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.
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.
Bounded UI interaction core: hit-testing, screen stack, paging.
Tile-cache state (caller-owned; treat as private).
Identifies one decoded image tile.
A predictive pan-prefetch request: what is visible + where it heads.
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 tx0
Leftmost visible tile column (inclusive).
A pinned view of a cached tile returned by ra8_tile_cache_get.
const uint8_t * pixels
Decoded tile pixels (cell payload).
uint16_t height
Decoded tile height in pixels.
uint16_t width
Decoded tile width in pixels.
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
A magnifiable full-resolution image behind the gray8 sub-rect seam.
Definition zoom.h:296
A tiled gray8 image, its grid, and the cache that pages it.
Definition zoom_tiles.h:72
uint16_t tile_cols
Derived tile columns.
Definition zoom_tiles.h:79
ra8_tile_cache_t * cache
Borrowed, initialised tile cache.
Definition zoom_tiles.h:73
uint16_t tile_w
Tile width, pixels.
Definition zoom_tiles.h:77
uint16_t tile_rows
Derived tile rows.
Definition zoom_tiles.h:80
uint16_t tile_h
Tile height, pixels.
Definition zoom_tiles.h:78
uint32_t width
Full-resolution image width, pixels.
Definition zoom_tiles.h:75
uint32_t image_id
Tile-cache key image id for this image.
Definition zoom_tiles.h:74
uint32_t height
Full-resolution image height, pixels.
Definition zoom_tiles.h:76
Live viewport: where it is looking, how magnified, and what it owes the panel.
Definition zoom.h:472
Tap-to-zoom image viewer: viewport state machine + tiled magnifying render (#478).
ra8_err_t zoom_source_init(zoom_source_t *out, zoom_read_fn read, void *ctx, uint32_t width, uint32_t height)
Bind a gray8 sub-rectangle reader and its extent as a magnifiable source.
Definition zoom.c:375
ra8_err_t zoom_view_window(const zoom_view_t *v, ra8_ui_rect_t *out)
The source rectangle currently visible, in source pixels.
Definition zoom.c:645
zoom_pan_t
Discrete pan direction for tap-band navigation.
Definition zoom.h:222
@ k_zoom_pan_right
Viewport travels toward +x.
Definition zoom.h:225
@ k_zoom_pan_left
Viewport travels toward -x.
Definition zoom.h:224
@ k_zoom_pan_none
No movement.
Definition zoom.h:223
@ k_zoom_pan_down
Viewport travels toward +y.
Definition zoom.h:227
@ k_zoom_pan_up
Viewport travels toward -y.
Definition zoom.h:226
Bind a tiled gray8 atlas behind an ra8_tile_cache as a zoom source (#478).
ra8_err_t zoom_tiles_prefetch(zoom_tile_src_t *ts, const zoom_view_t *v, zoom_pan_t dir, uint16_t max_tiles, uint16_t *out_warmed)
Warm the tiles one pan step beyond what a view currently shows.
ra8_err_t zoom_tile_read(void *ctx, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint8_t *out, uint32_t out_stride)
zoom_read_fn over a tiled atlas paged by an ra8_tile_cache.
ra8_err_t zoom_tile_src_bind(zoom_tile_src_t *ts, zoom_source_t *out)
Present a bound tiled image to the zoom engine as a zoom_source_t.
ra8_err_t zoom_tile_src_init(zoom_tile_src_t *ts, ra8_tile_cache_t *cache, uint32_t image_id, uint32_t width, uint32_t height, uint16_t tile_w, uint16_t tile_h)
Bind a tiled image and its cache, deriving the tile grid.