ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
longstrip.c
Go to the documentation of this file.
1
19
20#include "longstrip.h"
21
22#include <stdint.h>
23
24#include "jof.h"
25#include "ra8_attributes.h"
26#include "ra8_check.h"
27#include "ra8_err.h"
28#include "ra8_tile_cache.h"
29
31static const char* const s_tag = "longstrip";
32
46typedef enum : uint8_t {
50 k_wt_zoom = 0U,
52
54 const ra8_tile_key_t* key,
55 uint8_t* cell,
56 uint32_t cell_bytes,
57 uint16_t* out_w,
58 uint16_t* out_h)
59{
60 RA8_CHECK_NULL_PTR(ctx, s_tag, "decode ctx must not be nullptr");
61 RA8_CHECK_NULL_PTR(key, s_tag, "key must not be nullptr");
62 RA8_CHECK_NULL_PTR(cell, s_tag, "cell must not be nullptr");
63 RA8_CHECK_NULL_PTR(out_w, s_tag, "out_w must not be nullptr");
64 RA8_CHECK_NULL_PTR(out_h, s_tag, "out_h must not be nullptr");
66 return jof_read_tile(dc->pread,
67 dc->pread_ctx,
68 &dc->info,
69 key->tile_x,
70 key->tile_y,
71 dc->scratch,
72 dc->scratch_cap,
73 cell,
74 cell_bytes,
75 out_w,
76 out_h);
77}
78
101static void internal_bind(longstrip_t* wt, const longstrip_cfg_t* cfg, const jof_info_t* info)
102{
103 wt->info = *info;
104 wt->canvas_w = info->width;
105 wt->canvas_h = info->height;
106 wt->band_h = info->tile_h;
107 wt->band_count = info->tile_rows;
108 wt->viewport_w = cfg->viewport_w;
109 wt->viewport_h = cfg->viewport_h;
110 wt->scroll_y = 0;
111 wt->max_scroll = (info->height > cfg->viewport_h)
112 ? (int32_t)((uint32_t)info->height - (uint32_t)cfg->viewport_h)
113 : 0;
114 wt->velocity = 0;
115 wt->cache = cfg->cache;
116 wt->image_id = cfg->image_id;
117 wt->blit = cfg->blit;
118 wt->blit_ctx = cfg->blit_ctx;
119}
120
145{
146 RA8_CHECK_NULL_PTR(wt, s_tag, "wt must not be nullptr");
147 RA8_CHECK_NULL_PTR(cfg, s_tag, "cfg must not be nullptr");
148 RA8_CHECK_NULL_PTR(cfg->pread, s_tag, "cfg->pread must not be nullptr");
149 RA8_CHECK_NULL_PTR(cfg->cache, s_tag, "cfg->cache must not be nullptr");
150 RA8_CHECK_NULL_PTR(cfg->blit, s_tag, "cfg->blit must not be nullptr");
151 return k_ra8_ok;
152}
153
155{
156 const ra8_err_t ptr_err = internal_check_ptrs(wt, cfg);
157 if (ptr_err != k_ra8_ok) {
158 return ptr_err;
159 }
160 /* Decision: reject a zero-area viewport (2 conditions -- MC/DC in tests). */
161 if ((cfg->viewport_w == 0U) || (cfg->viewport_h == 0U)) {
163 }
164 jof_info_t info = {};
165 const ra8_err_t err = jof_parse(cfg->pread, cfg->pread_ctx, cfg->atlas_size, &info);
166 if (err != k_ra8_ok) {
167 return err;
168 }
169 /* A longstrip strip is one full-width band column; anything else is not a
170 * scrollable strip. `jof_parse` derives tile_cols as
171 * ceil(width / tile_w), so `tile_w == width` already implies tile_cols == 1
172 * -- the full-width test alone is necessary and sufficient. */
173 if (info.tile_w != info.width) {
175 }
176 internal_bind(wt, cfg, &info);
177 return k_ra8_ok;
178}
179
180ra8_err_t longstrip_set_viewport(longstrip_t* wt, uint16_t viewport_w, uint16_t viewport_h)
181{
182 RA8_CHECK_NULL_PTR(wt, s_tag, "wt must not be nullptr");
183 /* Decision: reject a zero-area viewport (2 conditions -- MC/DC in tests). */
184 if ((viewport_w == 0U) || (viewport_h == 0U)) {
186 }
187 wt->viewport_w = viewport_w;
188 wt->viewport_h = viewport_h;
189 wt->max_scroll =
190 (wt->canvas_h > (uint32_t)viewport_h) ? (int32_t)(wt->canvas_h - (uint32_t)viewport_h) : 0;
192 return k_ra8_ok;
193}
194
195int32_t longstrip_clamp_scroll(const longstrip_t* wt, int32_t y)
196{
197 if (wt == nullptr) {
198 return 0;
199 }
200 const int32_t max = wt->max_scroll;
201 if (y < 0) {
202 y = 0;
203 } else if (y > max) {
204 y = max;
205 }
206 return y;
207}
208
209ra8_err_t longstrip_band_at_y(const longstrip_t* wt, uint32_t y, uint16_t* out_band)
210{
211 RA8_CHECK_NULL_PTR(wt, s_tag, "wt must not be nullptr");
212 RA8_CHECK_NULL_PTR(out_band, s_tag, "out_band must not be nullptr");
213 if (y >= wt->canvas_h) {
215 }
216 *out_band = (uint16_t)(y / (uint32_t)wt->band_h);
217 return k_ra8_ok;
218}
219
221 int32_t scroll_y,
222 uint16_t* out_first,
223 uint16_t* out_last)
224{
225 RA8_CHECK_NULL_PTR(wt, s_tag, "wt must not be nullptr");
226 RA8_CHECK_NULL_PTR(out_first, s_tag, "out_first must not be nullptr");
227 RA8_CHECK_NULL_PTR(out_last, s_tag, "out_last must not be nullptr");
228 const int32_t top = longstrip_clamp_scroll(wt, scroll_y);
229 const uint32_t bh = (uint32_t)wt->band_h;
230 const uint32_t first = (uint32_t)top / bh;
231 uint32_t bottom = (uint32_t)top + (uint32_t)wt->viewport_h - 1U;
232 if (bottom >= wt->canvas_h) {
233 bottom = wt->canvas_h - 1U;
234 }
235 uint32_t last = bottom / bh;
236 if (last >= (uint32_t)wt->band_count) {
237 last = (uint32_t)wt->band_count - 1U;
238 }
239 *out_first = (uint16_t)first;
240 *out_last = (uint16_t)last;
241 return k_ra8_ok;
242}
243
261static int32_t internal_sat_add(int32_t a, int32_t b)
262{
263 const int64_t sum = (int64_t)a + (int64_t)b;
264 if (sum > (int64_t)INT32_MAX) {
265 return INT32_MAX;
266 }
267 if (sum < (int64_t)INT32_MIN) {
268 return INT32_MIN;
269 }
270 return (int32_t)sum;
271}
272
274{
275 RA8_CHECK_NULL_PTR(wt, s_tag, "wt must not be nullptr");
277 /* Decision: pinned at either end stops a running fling (2 conditions). */
278 if ((wt->scroll_y == 0) || (wt->scroll_y == wt->max_scroll)) {
279 wt->velocity = 0;
280 }
281 return k_ra8_ok;
282}
283
285{
286 RA8_CHECK_NULL_PTR(wt, s_tag, "wt must not be nullptr");
287 wt->velocity = v0;
288 return k_ra8_ok;
289}
290
307static int32_t internal_apply_friction(int32_t v)
308{
309 return (int32_t)((v * (int32_t)k_wt_fling_num) / (int32_t)k_wt_fling_den);
310}
311
328static bool internal_at_top(const longstrip_t* wt)
329{
330 return wt->scroll_y <= 0;
331}
332
349static bool internal_at_bottom(const longstrip_t* wt)
350{
351 return wt->scroll_y >= wt->max_scroll;
352}
353
379{
380 return (wt->velocity < 0) ? internal_at_top(wt) : internal_at_bottom(wt);
381}
382
384{
385 if (wt == nullptr) {
386 return false;
387 }
388 if (wt->velocity == 0) {
389 return false;
390 }
393 /* Decision: come to rest when the speed hits zero or a boundary is reached. */
394 if ((wt->velocity == 0) || internal_fling_should_stop(wt)) {
395 wt->velocity = 0;
396 return false;
397 }
398 return true;
399}
400
417static void internal_warm_band(longstrip_t* wt, uint16_t band)
418{
419 ra8_tile_key_t key = {};
420 key.image_id = wt->image_id;
421 key.tile_x = (uint16_t)k_wt_tile_x;
422 key.tile_y = band;
423 key.zoom = (uint16_t)k_wt_zoom;
424 ra8_tile_t tile = {};
425 if (ra8_tile_cache_get(wt->cache, &key, &tile) == k_ra8_ok) {
426 (void)ra8_tile_cache_put(wt->cache, tile.pixels);
427 }
428}
429
431{
432 RA8_CHECK_NULL_PTR(wt, s_tag, "wt must not be nullptr");
433 uint16_t first = 0;
434 uint16_t last = 0;
435 const ra8_err_t err = longstrip_visible_bands(wt, wt->scroll_y, &first, &last);
436 if (err != k_ra8_ok) {
437 return err;
438 }
439 if (depth > (uint16_t)k_longstrip_max_prefetch) {
440 depth = (uint16_t)k_longstrip_max_prefetch;
441 }
442 const uint16_t visible_span = (uint16_t)((last - first) + 1U);
443 /* Decision: nothing to prefetch with zero depth or a strip that fits (2). */
444 if ((depth == 0U) || (wt->band_count <= visible_span)) {
445 return k_ra8_ok;
446 }
447 const bool downward = (wt->velocity >= 0);
448 for (uint16_t i = 1U; i <= depth; i++) { /* bounded by k_longstrip_max_prefetch */
449 uint16_t target = 0;
450 if (downward) {
451 const uint32_t t = (uint32_t)last + (uint32_t)i;
452 if (t >= (uint32_t)wt->band_count) {
453 break;
454 }
455 target = (uint16_t)t;
456 } else {
457 if (first < i) {
458 break;
459 }
460 target = (uint16_t)(first - i);
461 }
462 internal_warm_band(wt, target);
463 }
464 return k_ra8_ok;
465}
466
487 int32_t dst_y,
488 uint16_t band_h,
490{
491 int32_t top = (dst_y > 0) ? dst_y : 0;
492 int32_t bot = dst_y + (int32_t)band_h;
493 const int32_t vh = (int32_t)wt->viewport_h;
494 if (bot > vh) {
495 bot = vh;
496 }
497 if (bot > top) {
498 stats->covered_rows += (uint32_t)(bot - top);
499 }
500}
501
524static ra8_err_t
525internal_draw_band(longstrip_t* wt, uint16_t band, int32_t dst_x, longstrip_render_stats_t* stats)
526{
527 ra8_tile_key_t key = {};
528 key.image_id = wt->image_id;
529 key.tile_x = (uint16_t)k_wt_tile_x;
530 key.tile_y = band;
531 key.zoom = (uint16_t)k_wt_zoom;
532 ra8_tile_t tile = {};
533 if (ra8_tile_cache_get(wt->cache, &key, &tile) != k_ra8_ok) {
534 stats->skipped++; /* record a gap; the frame still completes */
535 return k_ra8_ok;
536 }
537 const int32_t dst_y = (int32_t)((uint32_t)band * (uint32_t)wt->band_h) - wt->scroll_y;
538 const ra8_err_t berr =
539 wt->blit(wt->blit_ctx, tile.pixels, tile.width, tile.height, wt->info.bpp, dst_x, dst_y);
540 if (berr == k_ra8_ok) {
541 stats->bands_drawn++;
542 internal_accumulate_coverage(wt, dst_y, tile.height, stats);
543 } else {
544 stats->skipped++;
545 }
546 const ra8_err_t perr = ra8_tile_cache_put(wt->cache, tile.pixels);
547 return (berr != k_ra8_ok) ? berr : perr;
548}
549
551{
552 RA8_CHECK_NULL_PTR(wt, s_tag, "wt must not be nullptr");
553 longstrip_render_stats_t local = {};
555 uint16_t first = 0;
556 uint16_t last = 0;
557 ra8_err_t err = longstrip_visible_bands(wt, wt->scroll_y, &first, &last);
558 if (err != k_ra8_ok) {
559 return err;
560 }
561 const int32_t dst_x = ((int32_t)wt->viewport_w - (int32_t)wt->canvas_w) / 2;
562 for (uint32_t b = (uint32_t)first; b <= (uint32_t)last; b++) { /* bounded by band_count */
563 err = internal_draw_band(wt, (uint16_t)b, dst_x, &local);
564 if (err != k_ra8_ok) {
565 break;
566 }
567 }
568 if (stats != nullptr) {
569 *stats = local;
570 }
571 return err;
572}
JOF band-tile atlas: the display-native normalized image format (#231, shared with the longstrip scro...
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
ra8_err_t longstrip_prefetch(longstrip_t *wt, uint16_t depth)
Warm the cache with bands just beyond the viewport, in scroll order.
Definition longstrip.c:430
ra8_err_t longstrip_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)
JOF-backed ra8_tile_decode_fn: page one band in on a cache miss.
Definition longstrip.c:53
static ra8_err_t internal_check_ptrs(const longstrip_t *wt, const longstrip_cfg_t *cfg)
Reject a NULL engine, config, or any NULL callback / cache it carries.
Definition longstrip.c:144
static void internal_accumulate_coverage(const longstrip_t *wt, int32_t dst_y, uint16_t band_h, longstrip_render_stats_t *stats)
Add the on-screen row span of one blitted band to the coverage.
Definition longstrip.c:486
static int32_t internal_sat_add(int32_t a, int32_t b)
Saturating signed 32-bit add: pins at the int32 limits, never wraps.
Definition longstrip.c:261
static ra8_err_t internal_draw_band(longstrip_t *wt, uint16_t band, int32_t dst_x, longstrip_render_stats_t *stats)
Fetch, composite and release one visible band; update stats.
Definition longstrip.c:525
ra8_err_t longstrip_scroll_by(longstrip_t *wt, int32_t delta)
Scroll by a signed pixel delta (a finger drag), clamping at the ends.
Definition longstrip.c:273
static bool internal_at_bottom(const longstrip_t *wt)
Report whether the viewport is pinned at the bottom of the strip.
Definition longstrip.c:349
ra8_err_t longstrip_visible_bands(const longstrip_t *wt, int32_t scroll_y, uint16_t *out_first, uint16_t *out_last)
Compute the inclusive visible band range for a scroll position.
Definition longstrip.c:220
wt_consts_t
Fixed engine constants (no magic numbers).
Definition longstrip.c:46
@ k_wt_tile_x
Longstrip band column index (single column).
Definition longstrip.c:49
@ k_wt_zoom
Native zoom / mip level.
Definition longstrip.c:50
@ k_wt_fling_num
Velocity retained per tick (numerator).
Definition longstrip.c:47
@ k_wt_fling_den
Velocity retention denominator.
Definition longstrip.c:48
int32_t longstrip_clamp_scroll(const longstrip_t *wt, int32_t y)
Clamp a candidate scroll position to the strip's legal range.
Definition longstrip.c:195
ra8_err_t longstrip_render(longstrip_t *wt, longstrip_render_stats_t *stats)
Composite every visible band at the current scroll position.
Definition longstrip.c:550
ra8_err_t longstrip_set_viewport(longstrip_t *wt, uint16_t viewport_w, uint16_t viewport_h)
Resize the viewport of an open strip and re-derive the scroll clamp.
Definition longstrip.c:180
ra8_err_t longstrip_open(longstrip_t *wt, const longstrip_cfg_t *cfg)
Open a longstrip strip over a parsed + validated JOF atlas.
Definition longstrip.c:154
static void internal_warm_band(longstrip_t *wt, uint16_t band)
Fetch a band into the cache then release it (warm, no held pin).
Definition longstrip.c:417
static bool internal_at_top(const longstrip_t *wt)
Report whether the viewport is pinned at the top of the strip.
Definition longstrip.c:328
ra8_err_t longstrip_fling(longstrip_t *wt, int32_t v0)
Start a momentum fling with initial velocity v0.
Definition longstrip.c:284
bool longstrip_tick(longstrip_t *wt)
Advance the fling one physics step (integer velocity + friction).
Definition longstrip.c:383
static void internal_bind(longstrip_t *wt, const longstrip_cfg_t *cfg, const jof_info_t *info)
Bind the parsed atlas geometry and config into the engine state.
Definition longstrip.c:101
ra8_err_t longstrip_band_at_y(const longstrip_t *wt, uint32_t y, uint16_t *out_band)
Report the band index containing canvas row y.
Definition longstrip.c:209
static int32_t internal_apply_friction(int32_t v)
Decay a velocity one friction step toward zero (magnitude down).
Definition longstrip.c:307
static bool internal_fling_should_stop(const longstrip_t *wt)
True when a fling has hit the boundary it is travelling toward.
Definition longstrip.c:378
Continuous vertical-scroll (longstrip / manhwa) reading mode over an JOF band-tile atlas (#289).
@ k_longstrip_max_prefetch
Max prefetch depth per call.
Definition longstrip.h:90
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_not_supported
Requested feature not compiled in, not wired, or not supported by this MCU variant.
Definition ra8_err.h:180
@ 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
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_put(ra8_tile_cache_t *tc, const uint8_t *pixels)
Release one pin on a tile previously returned by ra8_tile_cache_get.
Parsed + validated geometry of one JOF atlas.
Definition jof.h:208
uint8_t bpp
Bytes per pixel (1, 3 or 4).
Definition jof.h:215
uint16_t tile_w
Tile width, pixels.
Definition jof.h:211
uint16_t width
Image width, pixels.
Definition jof.h:209
uint16_t tile_rows
Ceil(height / tile_h) tile rows.
Definition jof.h:214
uint16_t tile_h
Tile height, pixels.
Definition jof.h:212
uint16_t height
Image height, pixels.
Definition jof.h:210
One-shot configuration handed to longstrip_open.
Definition longstrip.h:160
void * pread_ctx
Context for pread.
Definition longstrip.h:162
ra8_tile_cache_t * cache
Band cache (decode-on-miss = JOF).
Definition longstrip.h:164
uint16_t viewport_h
On-screen viewport height, pixels.
Definition longstrip.h:167
uint32_t image_id
Tile-cache key namespace for strip.
Definition longstrip.h:165
uint16_t viewport_w
On-screen viewport width, pixels.
Definition longstrip.h:166
jof_pread_fn pread
Atlas backing read seam.
Definition longstrip.h:161
uint64_t atlas_size
Atlas byte length (for parse).
Definition longstrip.h:163
longstrip_blit_fn blit
Band composite sink.
Definition longstrip.h:168
void * blit_ctx
Context for blit.
Definition longstrip.h:169
Context binding a JOF atlas to a ra8_tile_cache decode-on-miss.
Definition longstrip.h:137
uint8_t * scratch
Deflate staging (codec 1 only).
Definition longstrip.h:141
void * pread_ctx
Context for pread.
Definition longstrip.h:139
jof_pread_fn pread
Atlas backing read seam.
Definition longstrip.h:138
jof_info_t info
Parsed atlas geometry.
Definition longstrip.h:140
uint32_t scratch_cap
Capacity of scratch.
Definition longstrip.h:142
Per-frame render accounting returned by longstrip_render.
Definition longstrip.h:215
uint16_t skipped
Visible bands that failed to composite.
Definition longstrip.h:217
uint32_t covered_rows
Viewport rows covered by the drawn bands.
Definition longstrip.h:218
uint16_t bands_drawn
Visible bands composited this frame.
Definition longstrip.h:216
Opened longstrip-strip scroll state (caller-owned; treat as private).
Definition longstrip.h:185
int32_t max_scroll
Clamp ceiling (>= 0).
Definition longstrip.h:194
ra8_tile_cache_t * cache
Band cache.
Definition longstrip.h:196
uint32_t canvas_w
Strip width, pixels (== info.width).
Definition longstrip.h:187
jof_info_t info
Parsed atlas geometry.
Definition longstrip.h:186
uint32_t canvas_h
Strip height, pixels (== info.height).
Definition longstrip.h:188
uint32_t image_id
Tile-cache key namespace.
Definition longstrip.h:197
uint16_t band_count
Bands (== info.tile_rows).
Definition longstrip.h:190
uint16_t viewport_h
Viewport height, pixels.
Definition longstrip.h:192
uint16_t viewport_w
Viewport width, pixels.
Definition longstrip.h:191
uint16_t band_h
Band height, pixels (== info.tile_h).
Definition longstrip.h:189
int32_t scroll_y
Viewport top on the canvas, clamped.
Definition longstrip.h:193
longstrip_blit_fn blit
Band composite sink.
Definition longstrip.h:198
int32_t velocity
Fling velocity, px/tick (signed).
Definition longstrip.h:195
void * blit_ctx
Context for blit.
Definition longstrip.h:199
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).
uint16_t zoom
Zoom / mip level (0 = native).
uint32_t image_id
Source image identifier.
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.