ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ez_scene.c
Go to the documentation of this file.
1
18
19#include "ez_scene.h"
20
21#include <stddef.h>
22#include <stdint.h>
23
24#include "ra8_check.h"
25#include "ra8_err.h"
26#include "ra8_gfx.h"
27#include "ra8_tile_cache.h"
28#include "ra8_ui.h"
29#include "zoom.h"
30#include "zoom_tiles.h"
31
33static const char* const s_tag = "ereader_zoom";
34
35/*
36 * ::k_ez_cells is DERIVED from the panel and tile geometry, never hand-picked
37 * (#338). At 1:1 the 1024x552 content window over 256x256 tiles straddles at
38 * most ceil(1024/256)+1 = 5 columns and ceil(552/256)+1 = 4 rows; the enum
39 * carries one more column than that so a horizontal pan step (which is nearly a
40 * whole viewport) still finds the union of before/after resident. Sizing the
41 * cache to that frame plus one tile of margin on each axis means a pan
42 * re-decodes only the newly exposed row or column, never a tile still on screen.
43 * The first assert fails the build if the derivation is ever undercut; the
44 * second bounds the resident arena so it cannot silently balloon.
45 */
46static_assert((uint64_t)k_ez_cells >= ((uint64_t)k_ez_view_cols * (uint64_t)k_ez_view_rows),
47 "tile cache is smaller than the 1:1 viewport tile demand: re-derive k_ez_cells "
48 "from the panel + tile geometry so a single-step pan cannot thrash (#338)");
49static_assert((uint64_t)k_ez_cells * (uint64_t)k_ez_cell_bytes <= (uint64_t)k_ez_cell_budget_bytes,
50 "resident tile arena exceeds its SDRAM budget");
51static_assert((k_ez_page_w % k_ez_tile_edge) == 0U,
52 "page width must tile exactly: the demo asserts a full-tile geometry");
53static_assert((k_ez_page_h % k_ez_tile_edge) == 0U,
54 "page height must tile exactly: the demo asserts a full-tile geometry");
55/*
56 * The composite scratch is sized for the WIDEST viewport and shared by both
57 * views, which is only sound while the packed buffer can hold a full strip of
58 * that width. 1024 x 16 rows packed at 2 px/byte is exactly k_ez_packed_bytes.
59 */
60static_assert((uint64_t)k_ez_packed_bytes >= (((uint64_t)k_ez_strip_bytes + 1U) / 2U),
61 "packed scratch cannot hold one dithered strip of the widest viewport");
62static_assert((uint64_t)k_ez_lens_edge < (uint64_t)k_ez_row_bytes,
63 "the loupe must be narrower than the shared composite row buffer");
64
98
112typedef enum : uint32_t {
113 k_ez_col_bar = 0x00222222U,
114 k_ez_col_ind = 0x00DDDDDDU,
115 k_ez_col_dim = 0x00555555U,
116 k_ez_col_lens = 0x00000000U,
118
132typedef enum : uint32_t {
133 k_ez_fnv_offset = 2166136261U,
134 k_ez_fnv_prime = 16777619U,
135} ez_fnv_t;
136
151typedef enum : uint16_t {
157
158uint8_t ez_page_sample(uint32_t x, uint32_t y)
159{
160 /* A TRIANGLE wave, not a sawtooth: a sawtooth's wrap is a real tone
161 * discontinuity in the source, and it would read on the panel as exactly the
162 * banding artefact this demo exists to show the dither removing. */
163 const uint32_t phase = ((x >> (uint32_t)k_ez_grad_shift) + (y >> (uint32_t)k_ez_grad_shift)) &
164 (uint32_t)k_ez_grad_wrap;
165 const uint32_t band =
166 (phase <= (uint32_t)k_ez_grad_mask) ? phase : ((uint32_t)k_ez_grad_wrap - phase);
167 const bool on_rule = ((y & (uint32_t)k_ez_rule_mask) < (uint32_t)k_ez_rule_thick);
168 const bool inked =
169 (((x >> (uint32_t)k_ez_word_shift) & (uint32_t)k_ez_word_mask) != (uint32_t)k_ez_word_blank);
170 if (on_rule && inked) {
171 return (uint8_t)k_ez_ink;
172 }
173 return (uint8_t)((uint32_t)k_ez_bg_lo + band);
174}
175
194static void ez_fill_tile(uint8_t* cell, uint32_t org_x, uint32_t org_y)
195{
196 for (uint32_t r = 0U; r < (uint32_t)k_ez_tile_edge; ++r) {
197 uint8_t* row = &cell[(size_t)r * (size_t)k_ez_tile_edge];
198 for (uint32_t c = 0U; c < (uint32_t)k_ez_tile_edge; ++c) {
199 row[c] = ez_page_sample(org_x + c, org_y + r);
200 }
201 }
202}
203
205 const ra8_tile_key_t* key,
206 uint8_t* cell,
207 uint32_t cell_bytes,
208 uint16_t* out_w,
209 uint16_t* out_h)
210{
211 (void)ctx;
212 RA8_CHECK_NULL_PTR(key, s_tag, "tile key must not be nullptr");
213 RA8_CHECK_NULL_PTR(cell, s_tag, "tile cell must not be nullptr");
214 RA8_CHECK_NULL_PTR(out_w, s_tag, "out_w must not be nullptr");
215 RA8_CHECK_NULL_PTR(out_h, s_tag, "out_h must not be nullptr");
216 if (cell_bytes < (uint32_t)k_ez_cell_bytes) {
217 ra8_log_error(s_tag, "tile cell is smaller than one page tile");
218 return k_ra8_err_no_mem;
219 }
220 const uint32_t org_x = (uint32_t)key->tile_x * (uint32_t)k_ez_tile_edge;
221 const uint32_t org_y = (uint32_t)key->tile_y * (uint32_t)k_ez_tile_edge;
222 if ((org_x >= (uint32_t)k_ez_page_w) || (org_y >= (uint32_t)k_ez_page_h)) {
223 ra8_log_error(s_tag, "tile key names a tile outside the page");
225 }
226 ez_fill_tile(cell, org_x, org_y);
227 *out_w = (uint16_t)k_ez_tile_edge;
228 *out_h = (uint16_t)k_ez_tile_edge;
229 return k_ra8_ok;
230}
231
232ra8_ui_rect_t ez_content_rect(int32_t fb_w, int32_t fb_h)
233{
234 const ra8_ui_rect_t r = {
235 .x = 0,
236 .y = (int32_t)k_ez_status_h,
237 .w = fb_w,
238 .h = fb_h - (int32_t)k_ez_status_h,
239 };
240 return r;
241}
242
256{
257 const ra8_ui_rect_t r = {
258 .x = content.x + ((content.w - (int32_t)k_ez_lens_edge) / 2),
259 .y = content.y + ((content.h - (int32_t)k_ez_lens_edge) / 2),
260 .w = (int32_t)k_ez_lens_edge,
261 .h = (int32_t)k_ez_lens_edge,
262 };
263 return r;
264}
265
279{
280 const zoom_scratch_t sc = {
281 .row = cfg->row,
282 .row_cap = (uint32_t)k_ez_row_bytes,
283 .strip = cfg->strip,
284 .strip_cap = (uint32_t)k_ez_strip_bytes,
285 .packed = cfg->packed,
286 .packed_cap = (uint32_t)k_ez_packed_bytes,
287 };
288 return sc;
289}
290
309{
310 RA8_CHECK_NULL_PTR(cfg->row, s_tag, "row scratch must not be nullptr");
311 RA8_CHECK_NULL_PTR(cfg->strip, s_tag, "strip scratch must not be nullptr");
312 RA8_CHECK_NULL_PTR(cfg->packed, s_tag, "packed scratch must not be nullptr");
313 return k_ra8_ok;
314}
315
330{
331 RA8_CHECK_NULL_PTR(cfg->fb, s_tag, "framebuffer must not be nullptr");
332 RA8_CHECK_NULL_PTR(cfg->cell_mem, s_tag, "cell_mem must not be nullptr");
333 RA8_CHECK_NULL_PTR(cfg->meta, s_tag, "meta must not be nullptr");
334 RA8_CHECK_NULL_PTR(cfg->keys, s_tag, "keys must not be nullptr");
335 RA8_CHECK_NULL_PTR(cfg->dims, s_tag, "dims must not be nullptr");
336 RA8_CHECK_NULL_PTR(cfg->buckets, s_tag, "buckets must not be nullptr");
337 return ez_cfg_scratch_ok(cfg);
338}
339
355{
356 const zoom_scratch_t scratch = ez_scratch_of(cfg);
357 const zoom_view_cfg_t page_cfg = {
358 .src = s->src,
359 .scratch = scratch,
360 .dst = s->content,
361 .scale = (uint8_t)k_zoom_scale_min,
362 .scale_max = (uint8_t)k_ez_page_scale_max,
363 .policy = k_zoom_policy_responsive,
364 .settle_ms = 0U,
365 .focus_x = 0,
366 .focus_y = 0,
367 };
368 RA8_RETURN_ON_ERROR(zoom_view_open(&s->page, &page_cfg), s_tag, "page view open");
369
370 const ra8_ui_rect_t lens = ez_lens_rect(s->content);
371 const zoom_view_cfg_t lens_cfg = {
372 .src = s->src,
373 .scratch = scratch,
374 .dst = lens,
375 .scale = (uint8_t)k_ez_lens_scale_min,
376 .scale_max = (uint8_t)k_ez_lens_scale_max,
377 .policy = k_zoom_policy_responsive,
378 .settle_ms = 0U,
379 .focus_x = 0,
380 .focus_y = 0,
381 };
382 return zoom_view_open(&s->lens, &lens_cfg);
383}
384
404{
405 const ra8_tile_cache_cfg_t cache_cfg = {
406 .cell_mem = cfg->cell_mem,
407 .cell_bytes = (uint32_t)k_ez_cell_bytes,
408 .cell_count = (uint32_t)k_ez_cells,
409 .meta = cfg->meta,
410 .keys = cfg->keys,
411 .dims = cfg->dims,
412 .buckets = cfg->buckets,
413 .bucket_count = (uint32_t)k_ez_buckets,
414 .decode = ez_tile_decode,
415 .decode_ctx = nullptr,
416 };
417 RA8_RETURN_ON_ERROR(ra8_tile_cache_init(&s->cache, &cache_cfg), s_tag, "tile cache init");
419 &s->cache,
420 (uint32_t)k_ez_image_id,
421 (uint32_t)k_ez_page_w,
422 (uint32_t)k_ez_page_h,
423 (uint16_t)k_ez_tile_edge,
424 (uint16_t)k_ez_tile_edge),
425 s_tag,
426 "tiled source init");
427 return zoom_tile_src_bind(&s->tiles, &s->src);
428}
429
431{
432 RA8_CHECK_NULL_PTR(s, s_tag, "scene must not be nullptr");
433 RA8_CHECK_NULL_PTR(cfg, s_tag, "cfg must not be nullptr");
434 s->lens_on = false;
435 RA8_RETURN_ON_ERROR(ez_cfg_ptrs_ok(cfg), s_tag, "cfg pointer check");
436 if ((cfg->fb_w <= (int32_t)k_ez_lens_edge) ||
437 (cfg->fb_h <= ((int32_t)k_ez_status_h + (int32_t)k_ez_lens_edge))) {
438 ra8_log_error(s_tag, "framebuffer is too small for the demo layout");
440 }
441 s->fb = cfg->fb;
442 s->fb_bytes = cfg->fb_bytes;
443 s->fb_w = cfg->fb_w;
444 s->fb_h = cfg->fb_h;
445 s->content = ez_content_rect(cfg->fb_w, cfg->fb_h);
446
447 RA8_RETURN_ON_ERROR(ez_bind_page(s, cfg), s_tag, "page binding");
448 return ez_open_views(s, cfg);
449}
450
451ez_zone_t ez_zone_hit(const ez_scene_t* s, int32_t x, int32_t y)
452{
453 if (s == nullptr) {
454 return k_ez_zone_none;
455 }
456 if (y < (int32_t)k_ez_status_h) {
457 return k_ez_zone_toggle;
458 }
459 if (!ra8_ui_rect_contains(&s->content, x, y)) {
460 return k_ez_zone_none;
461 }
462 const ra8_ui_rect_t lens = ez_lens_rect(s->content);
463 if (s->lens_on && ra8_ui_rect_contains(&lens, x, y)) {
464 return k_ez_zone_lens;
465 }
466 if (x < (s->content.x + (int32_t)k_ez_edge_band)) {
467 return k_ez_zone_pan_left;
468 }
469 if (x >= ((s->content.x + s->content.w) - (int32_t)k_ez_edge_band)) {
470 return k_ez_zone_pan_right;
471 }
472 if (y < (s->content.y + (int32_t)k_ez_edge_band)) {
473 return k_ez_zone_pan_up;
474 }
475 if (y >= ((s->content.y + s->content.h) - (int32_t)k_ez_edge_band)) {
476 return k_ez_zone_pan_down;
477 }
478 return k_ez_zone_zoom;
479}
480
496static bool ez_apply_pan(ez_scene_t* s, ez_zone_t zone, uint32_t now_ms)
497{
499 switch (zone) {
501 dir = k_zoom_pan_left;
502 break;
504 dir = k_zoom_pan_right;
505 break;
506 case k_ez_zone_pan_up:
507 dir = k_zoom_pan_up;
508 break;
510 dir = k_zoom_pan_down;
511 break;
512 default:
513 return false;
514 }
515 ra8_ui_rect_t before = {};
516 ra8_ui_rect_t after = {};
517 (void)zoom_view_window(&s->page, &before);
518 if (zoom_view_pan_dir(&s->page, dir, now_ms) != k_ra8_ok) {
519 return false;
520 }
521 (void)zoom_view_window(&s->page, &after);
522 if ((after.x == before.x) && (after.y == before.y)) {
523 return false;
524 }
525 /* Idle-window read-ahead: warm the tiles the next step in this direction
526 * will expose, out of the cache's spare margin (#341). */
527 (void)ez_scene_prefetch(s, dir, nullptr);
528 return true;
529}
530
531bool ez_scene_tap(ez_scene_t* s, int32_t x, int32_t y, uint32_t now_ms)
532{
533 if (s == nullptr) {
534 return false;
535 }
536 const ez_zone_t zone = ez_zone_hit(s, x, y);
537 if (zone == k_ez_zone_toggle) {
538 s->lens_on = !s->lens_on;
539 /* The loupe covers page pixels, so opening or closing it damages the whole
540 * content rectangle -- damage the engine cannot see, because neither the
541 * anchor nor the scale moved. Say so explicitly: a pan of (0, 0) would
542 * correctly report "nothing moved" and the lens would never be flushed to
543 * an e-ink panel (a continuously-scanned LCD would hide the bug entirely). */
544 return zoom_view_invalidate(&s->page, now_ms) == k_ra8_ok;
545 }
546 if (zone == k_ez_zone_lens) {
547 const uint8_t next =
549 return zoom_view_set_scale(&s->lens, next, x, y, now_ms) == k_ra8_ok;
550 }
551 if (zone == k_ez_zone_zoom) {
552 const uint8_t next =
554 return zoom_view_set_scale(&s->page, next, x, y, now_ms) == k_ra8_ok;
555 }
556 return ez_apply_pan(s, zone, now_ms);
557}
558
574{
576 ra8_gfx_rect(0, 0, s->fb_w, (int32_t)k_ez_status_h, (uint32_t)k_ez_col_bar, true),
577 s_tag,
578 "status bar fill");
579 const int32_t top = ((int32_t)k_ez_status_h - (int32_t)k_ez_ind_block) / 2;
580 const int32_t pitch = (int32_t)k_ez_ind_block + (int32_t)k_ez_ind_gap;
581 for (int32_t i = 0; i < (int32_t)k_ez_page_scale_max; ++i) {
582 const uint32_t colour =
583 (i < (int32_t)s->page.scale) ? (uint32_t)k_ez_col_ind : (uint32_t)k_ez_col_dim;
584 RA8_RETURN_ON_ERROR(ra8_gfx_rect(top + (i * pitch),
585 top,
586 (int32_t)k_ez_ind_block,
587 (int32_t)k_ez_ind_block,
588 colour,
589 true),
590 s_tag,
591 "zoom indicator block");
592 }
593 return k_ra8_ok;
594}
595
610{
611 for (int32_t i = 0; i < (int32_t)k_ez_lens_border; ++i) {
613 lens.y + i,
614 lens.w - (2 * i),
615 lens.h - (2 * i),
616 (uint32_t)k_ez_col_lens,
617 false),
618 s_tag,
619 "lens border");
620 }
621 return k_ra8_ok;
622}
623
625{
626 RA8_CHECK_NULL_PTR(s, s_tag, "scene must not be nullptr");
627 RA8_CHECK_NULL_PTR(s->src.read, s_tag, "scene source must not be nullptr");
628 RA8_RETURN_ON_ERROR(zoom_view_render(&s->page), s_tag, "page render");
629 if (s->lens_on) {
630 RA8_RETURN_ON_ERROR(zoom_view_render(&s->lens), s_tag, "lens render");
632 }
633 return ez_draw_status(s);
634}
635
655static void ez_choose_plan(const ez_scene_t* s,
656 const zoom_present_t* page_plan,
657 const zoom_present_t* lens_plan,
658 ez_present_t* out)
659{
660 if (page_plan->present) {
661 out->rect = s->content;
662 out->quality = (page_plan->refresh == k_zoom_refresh_quality);
663 out->present = true;
664 return;
665 }
666 if (lens_plan->present && s->lens_on) {
667 /* The partial-update case: only the lens box changed, so only the lens box
668 * is flushed -- 102400 pixels instead of the content area's 565248. */
669 out->rect = ez_lens_rect(s->content);
670 out->quality = (lens_plan->refresh == k_zoom_refresh_quality);
671 out->present = true;
672 return;
673 }
674 out->present = false;
675}
676
678{
679 RA8_CHECK_NULL_PTR(s, s_tag, "scene must not be nullptr");
680 RA8_CHECK_NULL_PTR(out, s_tag, "present out must not be nullptr");
681 zoom_present_t page_plan = {};
682 zoom_present_t lens_plan = {};
683 RA8_RETURN_ON_ERROR(zoom_view_present(&s->page, &page_plan), s_tag, "page present");
684 RA8_RETURN_ON_ERROR(zoom_view_present(&s->lens, &lens_plan), s_tag, "lens present");
685 ez_choose_plan(s, &page_plan, &lens_plan, out);
686 return k_ra8_ok;
687}
688
689bool ez_scene_tick(ez_scene_t* s, uint32_t now_ms)
690{
691 if (s == nullptr) {
692 return false;
693 }
694 const bool page_due = zoom_view_tick(&s->page, now_ms);
695 const bool lens_due = zoom_view_tick(&s->lens, now_ms);
696 if (page_due) {
697 return true;
698 }
699 if (lens_due) {
700 return s->lens_on;
701 }
702 return false;
703}
704
705ra8_err_t ez_scene_prefetch(ez_scene_t* s, zoom_pan_t dir, uint16_t* out_warmed)
706{
707 RA8_CHECK_NULL_PTR(s, s_tag, "scene must not be nullptr");
708 RA8_CHECK_NULL_PTR(s->tiles.cache, s_tag, "scene tile source must be bound");
709 return zoom_tiles_prefetch(&s->tiles, &s->page, dir, (uint16_t)k_ez_prefetch_max, out_warmed);
710}
711
712uint32_t ez_fnv1a(const void* buf, uint32_t len)
713{
714 uint32_t hash = (uint32_t)k_ez_fnv_offset;
715 if (buf == nullptr) {
716 return hash;
717 }
718 const uint8_t* bytes = (const uint8_t*)buf;
719 for (uint32_t i = 0U; i < len; ++i) {
720 hash ^= (uint32_t)bytes[i];
721 hash *= (uint32_t)k_ez_fnv_prime;
722 }
723 return hash;
724}
725
740static ra8_err_t ez_render_and_hash(ez_scene_t* s, uint32_t* out_hash)
741{
742 RA8_RETURN_ON_ERROR(ez_scene_render(s), s_tag, "selftest render");
743 ez_present_t plan = {};
744 RA8_RETURN_ON_ERROR(ez_scene_present(s, &plan), s_tag, "selftest present");
745 *out_hash = ez_fnv1a(s->fb, s->fb_bytes);
746 return k_ra8_ok;
747}
748
767{
769 s_tag,
770 "selftest pan");
772 s_tag,
773 "selftest prefetch");
774 return ez_render_and_hash(s, &out->crc_pan);
775}
776
794{
796 (uint8_t)k_ez_st_scale,
797 (int32_t)k_ez_st_focus_x,
798 (int32_t)k_ez_st_focus_y,
799 (uint32_t)k_ez_st_t0),
800 s_tag,
801 "selftest zoom");
802 return ez_render_and_hash(s, &out->crc_2x);
803}
804
824{
825 s->lens_on = true;
827 s_tag,
828 "selftest lens dirty");
830 s_tag,
831 "selftest page dirty");
832 return ez_render_and_hash(s, &out->crc_lens);
833}
834
854{
855 RA8_RETURN_ON_ERROR(ez_render_and_hash(s, &out->crc_1x), s_tag, "selftest 1:1");
856 RA8_RETURN_ON_ERROR(ez_selftest_pan(s, out), s_tag, "selftest pan stage");
857 RA8_RETURN_ON_ERROR(ez_selftest_zoom(s, out), s_tag, "selftest zoom stage");
858 return ez_selftest_lens(s, out);
859}
860
862{
863 RA8_CHECK_NULL_PTR(s, s_tag, "scene must not be nullptr");
864 RA8_CHECK_NULL_PTR(out, s_tag, "selftest out must not be nullptr");
865
866 RA8_RETURN_ON_ERROR(ez_selftest_stages(s, out), s_tag, "selftest stages");
867 return ra8_tile_cache_stats(&s->cache, &out->hits, &out->misses, &out->evictions);
868}
ra8_ui_rect_t ez_content_rect(int32_t fb_w, int32_t fb_h)
The content rectangle: the panel less the status bar.
Definition ez_scene.c:232
ez_tone_t
Gray8 tones and the shift/mask geometry of the procedural page.
Definition ez_scene.c:86
@ k_ez_grad_mask
Gradient span above k_ez_bg_lo.
Definition ez_scene.c:89
@ k_ez_word_mask
Words per group - 1 (one blank per group).
Definition ez_scene.c:95
@ k_ez_rule_mask
Rule pitch - 1, rows.
Definition ez_scene.c:92
@ k_ez_ink
Rule (text) tone.
Definition ez_scene.c:91
@ k_ez_grad_shift
Pixels per gradient step (1 << shift).
Definition ez_scene.c:88
@ k_ez_word_blank
Group index left blank (the inter-word gap).
Definition ez_scene.c:96
@ k_ez_word_shift
Word run length (1 << shift), columns.
Definition ez_scene.c:94
@ k_ez_rule_thick
Rule thickness, rows.
Definition ez_scene.c:93
@ k_ez_bg_lo
Darkest background tone.
Definition ez_scene.c:87
@ k_ez_grad_wrap
Triangle-wave period - 1 (2 * span + 1).
Definition ez_scene.c:90
ez_zone_t ez_zone_hit(const ez_scene_t *s, int32_t x, int32_t y)
Classify a tap by the zone it lands in.
Definition ez_scene.c:451
static ra8_err_t ez_selftest_stages(ez_scene_t *s, ez_selftest_t *out)
Run the four scripted self-check stages in order.
Definition ez_scene.c:853
static ra8_err_t ez_selftest_zoom(ez_scene_t *s, ez_selftest_t *out)
Self-check stage 3: 2x about a fixed panel point.
Definition ez_scene.c:793
ez_selftest_step_t
The scripted self-check's fixed inputs.
Definition ez_scene.c:151
@ k_ez_st_focus_y
Panel row the 2x step keeps fixed.
Definition ez_scene.c:153
@ k_ez_st_t0
Timestamp handed to every step (ms).
Definition ez_scene.c:155
@ k_ez_st_scale
Magnification the 2x step selects.
Definition ez_scene.c:154
@ k_ez_st_focus_x
Panel column the 2x step keeps fixed.
Definition ez_scene.c:152
static ra8_err_t ez_draw_status(const ez_scene_t *s)
Paint the status bar and its block zoom indicator.
Definition ez_scene.c:573
bool ez_scene_tick(ez_scene_t *s, uint32_t now_ms)
Advance both views' settle timers; report whether a repaint is due.
Definition ez_scene.c:689
ra8_err_t ez_scene_prefetch(ez_scene_t *s, zoom_pan_t dir, uint16_t *out_warmed)
Warm the tiles one pan step ahead of the page viewport.
Definition ez_scene.c:705
static void ez_choose_plan(const ez_scene_t *s, const zoom_present_t *page_plan, const zoom_present_t *lens_plan, ez_present_t *out)
Pick the flush rectangle from the two views' drained plans.
Definition ez_scene.c:655
uint8_t ez_page_sample(uint32_t x, uint32_t y)
Sample the procedural full-resolution page at one pixel.
Definition ez_scene.c:158
static ra8_err_t ez_open_views(ez_scene_t *s, const ez_scene_cfg_t *cfg)
Open both viewports over the bound page source.
Definition ez_scene.c:354
static ra8_ui_rect_t ez_lens_rect(ra8_ui_rect_t content)
The loupe box: a square centred in the content rectangle.
Definition ez_scene.c:255
static ra8_err_t ez_cfg_scratch_ok(const ez_scene_cfg_t *cfg)
Validate the three composite-scratch pointers.
Definition ez_scene.c:308
ra8_err_t ez_tile_decode(void *ctx, const ra8_tile_key_t *key, uint8_t *cell, uint32_t cell_bytes, uint16_t *out_w, uint16_t *out_h)
ra8_tile_decode_fn that materialises one page tile from the sampler.
Definition ez_scene.c:204
static ra8_err_t ez_bind_page(ez_scene_t *s, const ez_scene_cfg_t *cfg)
Wire the tile cache over the borrowed storage and bind it as a source.
Definition ez_scene.c:403
ra8_err_t ez_scene_selftest(ez_scene_t *s, ez_selftest_t *out)
Drive the scene through the scripted boot self-check.
Definition ez_scene.c:861
static ra8_err_t ez_draw_lens_chrome(ra8_ui_rect_t lens)
Paint the loupe's border so the lens reads as a lens, not a seam.
Definition ez_scene.c:609
static ra8_err_t ez_render_and_hash(ez_scene_t *s, uint32_t *out_hash)
Render the scene and hash the framebuffer it produced.
Definition ez_scene.c:740
ra8_err_t ez_scene_present(ez_scene_t *s, ez_present_t *out)
Take the pending flush plan for whichever view changed.
Definition ez_scene.c:677
uint32_t ez_fnv1a(const void *buf, uint32_t len)
FNV-1a-32 over a byte range (the framebuffer hash).
Definition ez_scene.c:712
static ra8_err_t ez_selftest_lens(ez_scene_t *s, ez_selftest_t *out)
Self-check stage 4: open the loupe over the magnified page.
Definition ez_scene.c:823
static zoom_scratch_t ez_scratch_of(const ez_scene_cfg_t *cfg)
Build the shared composite-scratch descriptor from a configuration.
Definition ez_scene.c:278
ra8_err_t ez_scene_render(ez_scene_t *s)
Repaint the content area, the loupe (when open) and the status bar.
Definition ez_scene.c:624
static bool ez_apply_pan(ez_scene_t *s, ez_zone_t zone, uint32_t now_ms)
Apply a pan zone to the page viewport.
Definition ez_scene.c:496
static void ez_fill_tile(uint8_t *cell, uint32_t org_x, uint32_t org_y)
Write one whole tile's pixels from the procedural page sampler.
Definition ez_scene.c:194
static ra8_err_t ez_selftest_pan(ez_scene_t *s, ez_selftest_t *out)
Self-check stage 2: one right-pan step at 1:1, with read-ahead.
Definition ez_scene.c:766
ez_chrome_t
Chrome colours, in the 0x00RRGGBB space ra8_gfx down-converts from.
Definition ez_scene.c:112
@ k_ez_col_dim
Unlit zoom-indicator block.
Definition ez_scene.c:115
@ k_ez_col_ind
Lit zoom-indicator block.
Definition ez_scene.c:114
@ k_ez_col_bar
Status-bar fill.
Definition ez_scene.c:113
@ k_ez_col_lens
Loupe border.
Definition ez_scene.c:116
static ra8_err_t ez_cfg_ptrs_ok(const ez_scene_cfg_t *cfg)
Validate the borrowed storage a scene configuration must carry.
Definition ez_scene.c:329
ez_fnv_t
FNV-1a-32 parameters.
Definition ez_scene.c:132
@ k_ez_fnv_prime
FNV-1a-32 prime.
Definition ez_scene.c:134
@ k_ez_fnv_offset
FNV-1a-32 offset basis.
Definition ez_scene.c:133
ra8_err_t ez_scene_init(ez_scene_t *s, const ez_scene_cfg_t *cfg)
Wire the tile cache, the tiled source and both viewports.
Definition ez_scene.c:430
bool ez_scene_tap(ez_scene_t *s, int32_t x, int32_t y, uint32_t now_ms)
Apply a tap to the scene.
Definition ez_scene.c:531
Tap-to-zoom demo scene: tiled 12 MP page, zoom viewport, loupe (#478).
@ k_ez_page_scale_max
Page-view ladder ceiling.
Definition ez_scene.h:119
@ k_ez_lens_scale_max
Loupe ladder ceiling.
Definition ez_scene.h:121
@ k_ez_lens_scale_min
Loupe ladder floor.
Definition ez_scene.h:120
ra8_err_t ez_tile_decode(void *ctx, const ra8_tile_key_t *key, uint8_t *cell, uint32_t cell_bytes, uint16_t *out_w, uint16_t *out_h)
ra8_tile_decode_fn that materialises one page tile from the sampler.
Definition ez_scene.c:204
@ k_ez_page_w
Source page width, pixels.
Definition ez_scene.h:74
@ k_ez_image_id
Tile-cache key image id for the page.
Definition ez_scene.h:77
@ k_ez_tile_edge
Tile edge, pixels (gray8 => 64 KiB/tile).
Definition ez_scene.h:76
@ k_ez_page_h
Source page height, pixels.
Definition ez_scene.h:75
@ k_ez_row_bytes
One source row at the widest viewport.
Definition ez_scene.h:196
@ k_ez_strip_bytes
gray8 destination strip (16 rows).
Definition ez_scene.h:197
@ k_ez_packed_bytes
The strip packed to 4 bpp.
Definition ez_scene.h:198
@ k_ez_lens_edge
Loupe box edge, pixels.
Definition ez_scene.h:96
@ k_ez_status_h
Status bar height, pixels.
Definition ez_scene.h:95
@ k_ez_ind_gap
Gap between indicator blocks, pixels.
Definition ez_scene.h:100
@ k_ez_lens_border
Loupe chrome thickness, pixels.
Definition ez_scene.h:97
@ k_ez_ind_block
Zoom-indicator block edge, pixels.
Definition ez_scene.h:99
@ k_ez_edge_band
Pan tap-band depth at each edge.
Definition ez_scene.h:98
ez_zone_t
Tap zones of the demo's discrete touch scheme.
Definition ez_scene.h:138
@ k_ez_zone_none
Nothing under the tap.
Definition ez_scene.h:139
@ k_ez_zone_lens
Inside the loupe: cycle its magnification.
Definition ez_scene.h:145
@ k_ez_zone_pan_up
Top band: page travels up.
Definition ez_scene.h:142
@ k_ez_zone_pan_left
Left band: page travels left.
Definition ez_scene.h:140
@ k_ez_zone_toggle
Status bar: open / close the loupe.
Definition ez_scene.h:146
@ k_ez_zone_zoom
Centre: cycle the page magnification.
Definition ez_scene.h:144
@ k_ez_zone_pan_right
Right band: page travels right.
Definition ez_scene.h:141
@ k_ez_zone_pan_down
Bottom band: page travels down.
Definition ez_scene.h:143
@ k_ez_buckets
Cache hash buckets (>= cells).
Definition ez_scene.h:173
@ k_ez_view_cols
1:1 tile columns a frame straddles, plus one.
Definition ez_scene.h:169
@ k_ez_cell_budget_bytes
SDRAM the cache may claim.
Definition ez_scene.h:174
@ k_ez_prefetch_max
Lead-edge tiles per pan.
Definition ez_scene.h:175
@ k_ez_view_rows
1:1 tile rows a frame straddles, plus one.
Definition ez_scene.h:170
@ k_ez_cell_bytes
One gray8 tile, bytes.
Definition ez_scene.h:168
@ k_ez_cells
Cells.
Definition ez_scene.h:172
static const char * s_tag
Logging / check tag.
Definition ra8_app.c:17
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_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
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
Software 2D graphics primitives layered on top of a caller-ownedframebuffer (DRW / D/AVE 2D / GLCDC r...
ra8_err_t ra8_gfx_rect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color, bool filled)
Draw an axis-aligned rectangle.
#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_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_init(ra8_tile_cache_t *tc, const ra8_tile_cache_cfg_t *cfg)
Initialise a tile cache over caller-supplied storage.
Bounded UI interaction core: hit-testing, screen stack, paging.
bool ra8_ui_rect_contains(const ra8_ui_rect_t *r, int32_t px, int32_t py)
Test whether a point lies inside a rectangle.
Definition ra8_ui.c:34
What the scene asks the panel to flush, and how well.
Definition ez_scene.h:283
ra8_ui_rect_t rect
Panel rectangle to flush.
Definition ez_scene.h:284
bool quality
True: full 16-level GC16.
Definition ez_scene.h:285
bool present
False: nothing changed; do not flush.
Definition ez_scene.h:286
Everything ez_scene_init needs: storage and framebuffer geometry.
Definition ez_scene.h:252
ra8_tile_key_t * keys
k_ez_cells key entries.
Definition ez_scene.h:259
int32_t fb_h
Framebuffer height, pixels.
Definition ez_scene.h:256
uint8_t * packed
k_ez_packed_bytes packed strip.
Definition ez_scene.h:264
int32_t * buckets
k_ez_buckets hash-bucket heads.
Definition ez_scene.h:261
int32_t fb_w
Framebuffer width, pixels.
Definition ez_scene.h:255
uint8_t * cell_mem
k_ez_cells * k_ez_cell_bytes bytes.
Definition ez_scene.h:257
uint32_t fb_bytes
Framebuffer size, bytes.
Definition ez_scene.h:254
uint8_t * row
k_ez_row_bytes composite row.
Definition ez_scene.h:262
ra8_tile_dims_t * dims
k_ez_cells dimension entries.
Definition ez_scene.h:260
ra8_keycache_cell_t * meta
k_ez_cells link-metadata entries.
Definition ez_scene.h:258
void * fb
Framebuffer base (hashed by the golden).
Definition ez_scene.h:253
uint8_t * strip
k_ez_strip_bytes composite strip.
Definition ez_scene.h:263
The whole demo: one tiled page, one zoom viewport, one loupe.
Definition ez_scene.h:222
ra8_ui_rect_t content
The content rectangle (page.dst).
Definition ez_scene.h:228
zoom_view_t lens
Loupe over the same page, magnified more.
Definition ez_scene.h:227
ra8_tile_cache_t cache
Page cache (decode-on-miss = the sampler).
Definition ez_scene.h:223
zoom_tile_src_t tiles
Tiled-source binding over that cache.
Definition ez_scene.h:224
bool lens_on
The loupe is open.
Definition ez_scene.h:233
zoom_source_t src
The page as a zoom source.
Definition ez_scene.h:225
int32_t fb_h
Framebuffer height, pixels.
Definition ez_scene.h:232
zoom_view_t page
Full-content zoom viewport.
Definition ez_scene.h:226
const void * fb
Framebuffer base, for the golden hash.
Definition ez_scene.h:229
int32_t fb_w
Framebuffer width, pixels.
Definition ez_scene.h:231
uint32_t fb_bytes
Framebuffer size, bytes.
Definition ez_scene.h:230
Deterministic boot self-check results (the app's golden numbers).
Definition ez_scene.h:305
uint32_t misses
Tile-cache misses (decodes).
Definition ez_scene.h:311
uint32_t crc_1x
Hash after the opening 1:1 render.
Definition ez_scene.h:306
uint32_t crc_pan
Hash after one right-pan step at 1:1.
Definition ez_scene.h:307
uint32_t evictions
Tile-cache evictions.
Definition ez_scene.h:312
uint32_t crc_2x
Hash after zooming to 2x at a fixed point.
Definition ez_scene.h:308
uint32_t crc_lens
Hash after opening the 4x loupe.
Definition ez_scene.h:309
uint16_t warmed
Tiles warmed by the pan read-ahead.
Definition ez_scene.h:313
uint32_t hits
Tile-cache hits over the whole sequence.
Definition ez_scene.h:310
Caller-supplied storage + decoder for ra8_tile_cache_init.
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).
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
What the reader must flush, and with which waveform.
Definition zoom.h:371
zoom_refresh_t refresh
Waveform class for that flush.
Definition zoom.h:373
bool present
False: nothing changed, do not flush at all.
Definition zoom.h:374
Caller-owned composite buffers – the module's entire memory footprint.
Definition zoom.h:335
zoom_read_fn read
gray8 sub-rectangle reader (never NULL once bound).
Definition zoom.h:297
ra8_tile_cache_t * cache
Borrowed, initialised tile cache.
Definition zoom_tiles.h:73
Everything zoom_view_open needs; nothing it does not.
Definition zoom.h:404
uint8_t scale
Current integer magnification.
Definition zoom.h:481
Tap-to-zoom image viewer: viewport state machine + tiled magnifying render (#478).
@ k_zoom_policy_responsive
Fast during a burst, quality once settled.
Definition zoom.h:204
ra8_err_t zoom_view_invalidate(zoom_view_t *v, uint32_t now_ms)
Declare the viewport's pixels stale for a reason the engine cannot see.
Definition zoom.c:514
@ k_zoom_scale_min
1:1 – one source pixel per panel pixel.
Definition zoom.h:118
ra8_err_t zoom_view_pan_dir(zoom_view_t *v, zoom_pan_t dir, uint32_t now_ms)
Pan by a discrete step in one direction (the tap-band interaction).
Definition zoom.c:614
bool zoom_view_tick(zoom_view_t *v, uint32_t now_ms)
Advance the settle timer; promote a bi-level view to full quality.
Definition zoom.c:664
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
ra8_err_t zoom_view_present(zoom_view_t *v, zoom_present_t *out)
Take the pending flush plan, clearing it.
Definition zoom.c:684
uint8_t zoom_scale_cycle(uint8_t scale, uint8_t min, uint8_t max)
Next magnification on the doubling ladder, wrapping back to the minimum.
Definition zoom.c:539
ra8_err_t zoom_view_render(zoom_view_t *v)
Composite the visible window into the bound ra8_gfx framebuffer.
ra8_err_t zoom_view_open(zoom_view_t *v, const zoom_view_cfg_t *cfg)
Open a viewport onto a source, centred on a source-pixel focus.
Definition zoom.c:482
@ k_zoom_refresh_quality
Settled: panel GC16 (all 16 levels, slow).
Definition zoom.h:176
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
ra8_err_t zoom_view_set_scale(zoom_view_t *v, uint8_t scale, int32_t focus_x, int32_t focus_y, uint32_t now_ms)
Set the magnification, keeping a panel point fixed under the finger.
Definition zoom.c:556
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_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.