ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
comic_tiles.h File Reference

Tile an oversized comic page through the JOF atlas + ra8_tile_cache so a CBZ/CBR page larger than the whole-decode arena opens and zooms (#344). More...

#include <stddef.h>
#include <stdint.h>
#include "jof.h"
#include "jof_produce.h"
#include "ra8_err.h"
#include "ra8_tile_cache.h"
Include dependency graph for comic_tiles.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  comic_tiles_import_cfg_t
 Import-time transcode knobs, work arena, and destination atlas store. More...
struct  comic_tile_reader_t
 One comic tile reader: owned tile cache, atlas store, bound page. More...

Enumerations

enum  comic_tiles_const_t : uint8_t { k_comic_tiles_decoded_bpp = 4U }
 Fixed constants for the comic tiling budget estimate. More...

Functions

ra8_err_t comic_tiles_footprint (const uint8_t *enc, size_t len, uint16_t *out_w, uint16_t *out_h, uint64_t *out_decoded_bytes)
 Read a comic page's decoded footprint from its encoded header (#344).
bool comic_tiles_over_budget (uint64_t decoded_bytes, uint64_t budget_bytes)
 Decide whether a page's decoded footprint exceeds the resident budget.
ra8_err_t comic_tiles_init (comic_tile_reader_t *r, const ra8_tile_cache_cfg_t *storage, uint8_t *scratch, uint32_t scratch_cap)
 Initialise a comic tile reader over caller-supplied tile-cache storage.
ra8_err_t comic_tiles_import (comic_tile_reader_t *r, const uint8_t *enc, size_t enc_len, const comic_tiles_import_cfg_t *cfg)
 Transcode one encoded comic page to a JOF atlas and bind it for tiling.
ra8_err_t comic_tiles_info (const comic_tile_reader_t *r, jof_info_t *out_info)
 Report the bound page's parsed atlas geometry (#344).
ra8_err_t comic_tiles_tile (comic_tile_reader_t *r, uint16_t tile_x, uint16_t tile_y, ra8_tile_t *out_tile)
 Get (and pin) one decoded tile of the bound page (#344).
ra8_err_t comic_tiles_release (comic_tile_reader_t *r, const uint8_t *pixels)
 Release one pin taken by comic_tiles_tile (#344).

Detailed Description

Tile an oversized comic page through the JOF atlas + ra8_tile_cache so a CBZ/CBR page larger than the whole-decode arena opens and zooms (#344).

Tag
[Ring 4 / Domain] {World: NS}

comic streams a page's encoded bytes out of a CBZ/CBR archive and the reader hands them to ra8_img_decode_blit, which decodes the whole image with stb_image into a bump arena. A page whose decoded size exceeds that arena cannot be opened at all, and there is no sub-rect access, so the loupe cannot magnify a comic page. That whole-page cap is exactly the case jof was built for and is already wired to the EPUB path (epub_tile_binder_import), but not to comics – #344.

This module is the comic analogue of that EPUB binder, reusing the same tiling infrastructure rather than reinventing it: it does not implement a new decoder, atlas, or cache. On open it transcodes one page's encoded bytes through jof_produce() into a caller-supplied atlas store (an SDRAM memstore), then pages the produced full-resolution tiles through ra8_tile_cache – decode-on-demand, one bounded read plus one bounded inflate per tile miss (jof_read_tile()), resident decoded pixels bounded by the cache cell budget regardless of the page size, no downscaling.

Size-thresholded front end (design: image_pipeline_unification.md S5)
Tiling a small page is pure overhead – a footer, an index, per-tile framing and a cache lookup to save nothing, because the whole image is resident after the first pan anyway. The reader therefore keeps the existing whole-decode fast path for pages under a resident-budget threshold (expressed in decoded bytes, not pixels – comic_tiles_over_budget) and only routes a page whose decoded footprint exceeds the budget through this tile path. Pages that already fit render byte-identically to before.
One page at a time (single source, epoch-keyed)
A comic reader shows one page; a page turn re-imports. comic_tiles_import resets the atlas store and rebinds a single source, bumping an internal epoch that namespaces the tile-cache key so a re-import can never return a stale tile of the previous page. All storage is caller-owned; there is no heap (NASA P10 Rule 3).
comic_tiles_init(&r, &tile_cache_storage, scratch, sizeof scratch);
uint16_t w = 0U;
uint16_t h = 0U;
uint64_t decoded = 0U;
if ((comic_tiles_footprint(enc, enc_len, &w, &h, &decoded) == k_ra8_ok) &&
comic_tiles_over_budget(decoded, k_resident_budget_bytes)) {
comic_tiles_import(&r, enc, enc_len, &import_cfg); // tile it
ra8_tile_t tile = {};
comic_tiles_tile(&r, tile_x, tile_y, &tile); // page/zoom a sub-rect
// ... blit tile.pixels ...
} else {
ra8_img_decode_blit(&arena, enc, enc_len, 0, 0, box_w, box_h, nullptr, nullptr);
}
ra8_err_t comic_tiles_tile(comic_tile_reader_t *r, uint16_t tile_x, uint16_t tile_y, ra8_tile_t *out_tile)
Get (and pin) one decoded tile of the bound page (#344).
ra8_err_t comic_tiles_import(comic_tile_reader_t *r, const uint8_t *enc, size_t enc_len, const comic_tiles_import_cfg_t *cfg)
Transcode one encoded comic page to a JOF atlas and bind it for tiling.
ra8_err_t comic_tiles_footprint(const uint8_t *enc, size_t len, uint16_t *out_w, uint16_t *out_h, uint64_t *out_decoded_bytes)
Read a comic page's decoded footprint from its encoded header (#344).
bool comic_tiles_over_budget(uint64_t decoded_bytes, uint64_t budget_bytes)
Decide whether a page's decoded footprint exceeds the resident budget.
ra8_err_t comic_tiles_init(comic_tile_reader_t *r, const ra8_tile_cache_cfg_t *storage, uint8_t *scratch, uint32_t scratch_cap)
Initialise a comic tile reader over caller-supplied tile-cache storage.
ra8_err_t comic_tiles_release(comic_tile_reader_t *r, const uint8_t *pixels)
Release one pin taken by comic_tiles_tile (#344).
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
ra8_err_t ra8_img_decode_blit(ra8_img_arena_t *arena, const uint8_t *bytes, size_t len, int32_t dst_x, int32_t dst_y, int32_t box_w, int32_t box_h, int32_t *out_w, int32_t *out_h)
Decode bytes and blit it, scaled to fit, into the bound framebuffer.
One comic tile reader: owned tile cache, atlas store, bound page.
A pinned view of a cached tile returned by ra8_tile_cache_get.
const uint8_t * pixels
Decoded tile pixels (cell payload).
Note
Not thread-safe; the single-threaded reader loop serialises access.
The JOF producer transcodes baseline JPEG / non-interlaced 8-bit PNG (and WebP when a webp_work arena is supplied); a page in any other encoding reports k_ra8_err_not_supported from comic_tiles_footprint / comic_tiles_import and the caller keeps the whole-decode path.
See also
jof.h The JOF atlas format + tile reader.
jof_produce.h The import-time transcode producer.
ra8_tile_cache.h The decode-on-demand tile cache.
epub_img_tiles.h The EPUB tile binder this mirrors.
comic.h The CBZ/CBR page reader that supplies the bytes.
Since
Version 0.1.0

Definition in file comic_tiles.h.

Enumeration Type Documentation

◆ comic_tiles_const_t

enum comic_tiles_const_t : uint8_t

Fixed constants for the comic tiling budget estimate.

The whole-decode fast path decodes to RGB (stb_image), so a page's worst-case resident footprint is estimated at four bytes per pixel – an over-estimate that keeps a marginal page on the safe (tiling) side of the threshold rather than risking a whole-decode arena overflow.

Since
Version 0.1.0
Enumerator
k_comic_tiles_decoded_bpp 

Bytes/pixel used for the budget estimate.

Definition at line 103 of file comic_tiles.h.

Function Documentation

◆ comic_tiles_footprint()

ra8_err_t comic_tiles_footprint ( const uint8_t * enc,
size_t len,
uint16_t * out_w,
uint16_t * out_h,
uint64_t * out_decoded_bytes )
nodiscard

Read a comic page's decoded footprint from its encoded header (#344).

Sniffs the encoded page's dimensions without decoding its body (via jof_probe_dims(), the exact JPEG/PNG/WebP set the producer accepts) and reports the worst-case decoded byte count (w * h * k_comic_tiles_decoded_bpp) the whole-decode arena would have to hold. The caller compares it against its resident budget with comic_tiles_over_budget to choose the tile path or the whole-decode fast path.

Parameters
[in]encEncoded page bytes (non-NULL).
[in]lenReadable byte count at enc (> 0).
[out]out_wReceives the page width in pixels (non-NULL).
[out]out_hReceives the page height in pixels (non-NULL).
[out]out_decoded_bytesReceives the worst-case decoded footprint (non-NULL).
Returns
ra8_err_t Error code.
Return values
k_ra8_okFootprint reported; all outputs written.
k_ra8_err_null_ptrA required pointer argument was NULL.
k_ra8_err_invalid_sizelen is 0, or a probed dimension is out of range.
k_ra8_err_not_supportedThe page is not a JPEG/PNG/WebP the producer tiles.
k_ra8_err_*Propagated from the per-format probe.
Precondition
enc holds len readable bytes.
out_w, out_h and out_decoded_bytes are writable.
Postcondition
On k_ra8_ok every output is populated from the page header.
On any error no output is relied upon.
Note
Thread-safe: pure read of enc.
See also
comic_tiles_over_budget()
Since
Version 0.1.0

Referenced by cm_comic_tiled_selfcheck().

◆ comic_tiles_import()

ra8_err_t comic_tiles_import ( comic_tile_reader_t * r,
const uint8_t * enc,
size_t enc_len,
const comic_tiles_import_cfg_t * cfg )
nodiscard

Transcode one encoded comic page to a JOF atlas and bind it for tiling.

Streams enc through jof_produce() into cfg->atlas (a memstore), validates the produced atlas with jof_parse(), and binds it as the reader's single source under a fresh epoch. After a successful import comic_tiles_tile pages the page's full-resolution tiles on demand – the #344 goal: a comic page larger than the whole-decode arena renders without a whole-image decode and without downscaling. Re-importing (a page turn) resets the store and bumps the epoch so no stale tile of the previous page survives.

Parameters
[in,out]rReader from comic_tiles_init.
[in]encEncoded page bytes (JPEG/PNG/WebP; non-NULL).
[in]enc_lenLength of enc (> 0).
[in]cfgTranscode knobs + work arena + atlas store (non-NULL).
Returns
ra8_err_t Error code.
Return values
k_ra8_okPage transcoded and bound; tiles servable.
k_ra8_err_null_ptrA required pointer argument was NULL.
k_ra8_err_invalid_argZero tile geometry or unknown codec.
k_ra8_err_invalid_sizePage exceeds the caps, grid exceeds the tile cap, or an arena/store is too small.
k_ra8_err_not_supportedPage not JPEG/PNG/WebP, WebP with no webp_work, or an unsupported variant.
k_ra8_err_protocol_errorMalformed / hostile source structure.
k_ra8_err_validation_failedProducer or atlas validation failed.
k_ra8_err_*Propagated from the producer / store.
Precondition
r came from comic_tiles_init.
cfg->work is sized per jof_work_bytes() for the same caps.
Postcondition
On success the page's tiles are servable and r->bound is true.
On any error r->bound is false and no tile may be fetched.
Note
Not thread-safe.
See also
comic_tiles_tile()
Since
Version 0.1.0

Referenced by cm_comic_tiled_selfcheck().

◆ comic_tiles_info()

ra8_err_t comic_tiles_info ( const comic_tile_reader_t * r,
jof_info_t * out_info )
nodiscard

Report the bound page's parsed atlas geometry (#344).

Parameters
[in]rReader with a page bound by comic_tiles_import.
[out]out_infoReceives the atlas geometry (non-NULL).
Returns
ra8_err_t Error code.
Return values
k_ra8_okGeometry reported.
k_ra8_err_null_ptrr or out_info is NULL.
k_ra8_err_invalid_stateNo page is bound.
Precondition
r is initialised; out_info is writable.
A page was bound via comic_tiles_import.
Postcondition
On success *out_info holds the bound page geometry.
On failure *out_info is unmodified.
Note
Not thread-safe.
Since
Version 0.1.0

Referenced by cm_comic_tiled_selfcheck().

◆ comic_tiles_init()

ra8_err_t comic_tiles_init ( comic_tile_reader_t * r,
const ra8_tile_cache_cfg_t * storage,
uint8_t * scratch,
uint32_t scratch_cap )
nodiscard

Initialise a comic tile reader over caller-supplied tile-cache storage.

Wires storage into the owned ::ra8_tile_cache whose decode-on-miss is this module's JOF tile reader. The storage decode / decode_ctx fields are ignored (the reader sets them); every other field (cell memory + geometry + key/dim/meta arrays + hash buckets) is the caller's and must out-live the reader. scratch stages one stored (compressed) tile during a deflate decode-on-miss: size it with jof_stored_bound() over the cell size; a reader paging only raw atlases may pass NULL/0.

Parameters
[out]rReader to populate (zero-initialised by the caller).
[in]storageTile-cache storage config; decode/decode_ctx unused.
[in]scratchStored-tile staging buffer (may be NULL for raw-only).
[in]scratch_capCapacity of scratch, bytes.
Returns
ra8_err_t Error code.
Return values
k_ra8_okReader ready; no page imported yet.
k_ra8_err_null_ptrr or storage (or a required array) NULL.
k_ra8_err_invalid_sizeA zero cell/bucket geometry in storage.
Precondition
r points at zeroed storage.
storage arrays and scratch out-live the reader.
Postcondition
On success the cache is empty and no page is bound.
On failure r is left unusable.
Note
Not thread-safe.
See also
comic_tiles_import()
Since
Version 0.1.0

Referenced by cm_comic_tiled_selfcheck().

◆ comic_tiles_over_budget()

bool comic_tiles_over_budget ( uint64_t decoded_bytes,
uint64_t budget_bytes )
nodiscard

Decide whether a page's decoded footprint exceeds the resident budget.

The size-threshold decision expressed in decoded bytes: a page is worth tiling only when the budget is a real (non-zero) ceiling AND the page's decoded footprint would overrun it. A zero budget means "never tile" (the whole-decode path is unconditional), so a mis-configured budget fails safe rather than tiling everything.

Parameters
[in]decoded_bytesPage's worst-case decoded footprint (from footprint()).
[in]budget_bytesResident decode budget in bytes (0 = never tile).
Returns
Whether the page should be routed through the tile path.
Return values
trueThe budget is non-zero and the page overruns it.
falseThe budget is zero, or the page fits it.
Precondition
decoded_bytes came from comic_tiles_footprint (or is 0).
budget_bytes is the caller's resident decode budget.
Postcondition
No state is modified (pure function).
The result depends only on the two arguments.
Note
Thread-safe: pure.
See also
comic_tiles_footprint()
Since
Version 0.1.0

Referenced by cm_comic_tiled_selfcheck().

◆ comic_tiles_release()

ra8_err_t comic_tiles_release ( comic_tile_reader_t * r,
const uint8_t * pixels )
nodiscard

Release one pin taken by comic_tiles_tile (#344).

Parameters
[in]rReader with a page bound.
[in]pixelsThe pixels pointer from a returned ra8_tile_t.
Returns
ra8_err_t Error code.
Return values
k_ra8_okPin released.
k_ra8_err_null_ptrr or pixels is NULL.
k_ra8_err_invalid_argpixels is not a pinned cell of this reader.
Precondition
pixels came from comic_tiles_tile on this reader.
r is initialised.
Postcondition
On success the cell's pin count dropped by one.
On any error no state changed.
Note
Not thread-safe.
Since
Version 0.1.0

Referenced by cm_ct_hash_tiles().

◆ comic_tiles_tile()

ra8_err_t comic_tiles_tile ( comic_tile_reader_t * r,
uint16_t tile_x,
uint16_t tile_y,
ra8_tile_t * out_tile )
nodiscard

Get (and pin) one decoded tile of the bound page (#344).

Builds the tile-cache key (epoch, tile_x, tile_y) and fetches it through the owned cache. On a miss the tile's stored stream is read off the atlas store and decoded into one cache cell (jof_read_tile()); on a hit the cell is reused. The returned pixels are tightly packed (out_tile->width * bpp bytes per row) and stay valid until comic_tiles_release. Edge tiles report their true (smaller) size. This is the sub-rect access the loupe needs: magnifying a region fetches only the tiles under it, full resolution.

Parameters
[in]rReader with a page bound.
[in]tile_xTile column, [0, info.tile_cols).
[in]tile_yTile row, [0, info.tile_rows).
[out]out_tileReceives the pinned tile view (non-NULL).
Returns
ra8_err_t Error code.
Return values
k_ra8_okTile resident + pinned; *out_tile set.
k_ra8_err_null_ptrr or out_tile is NULL.
k_ra8_err_invalid_stateNo page is bound.
k_ra8_err_out_of_rangetile_x / tile_y outside the grid.
k_ra8_err_no_memEvery cell is pinned, or the tile exceeds the cell / scratch budget.
k_ra8_err_validation_failedThe atlas backing is corrupt.
Precondition
r has a page bound via comic_tiles_import.
The caller will comic_tiles_release the returned tile.
Postcondition
On success the cell's pin count grew by one.
On any error no new pin is held.
Note
Not thread-safe.
See also
comic_tiles_release()
Since
Version 0.1.0

Referenced by cm_ct_hash_tiles().