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

Paged (demand-fetched) accessor mode for book over ra8_vmem (#163). More...

#include <stddef.h>
#include <stdint.h>
#include "book.h"
#include "ra8_err.h"
#include "ra8_vmem.h"
Include dependency graph for book_paged.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  book_src_t
 A book data source: resident (zero-copy) or paged (demand-fetched). More...

Functions

ra8_err_t book_src_resident (book_src_t *out, const void *base, uint32_t size)
 Bind a resident (already-inflated, fully resident) book as a source.
ra8_err_t book_src_paged (book_src_t *out, ra8_vmem_t *vm, uint32_t object_id, uint32_t frame_bytes, uint32_t size)
 Bind a paged book source over an ::ra8_vmem cache + ::ra8_vsource object.
ra8_err_t book_src_read (const book_src_t *src, uint32_t off, void *dst, uint32_t len)
 Copy a byte range out of a book source (resident memcpy or paged fault).
ra8_err_t book_src_image (const book_src_t *src, uint32_t idx, book_image_t *out_img)
 Read one image descriptor out of a book source (resident or paged).
ra8_err_t book_src_image_rect (const book_src_t *src, const book_image_t *img, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint8_t *out, uint32_t out_stride)
 Read a sub-rectangle of a raster image (4bpp or 8bpp) as gray8, row by row.
ra8_err_t book_chapter_text_src (const book_src_t *src, uint32_t chapter_idx, char *out, size_t cap, size_t *out_len)
 Extract one chapter's plain text from a book source (resident or paged).
ra8_err_t book_src_prefetch_chapter (const book_src_t *src, uint32_t chapter_idx)
 Warm the cache frame holding a chapter's first content bytes, without pinning it (single-threaded read-ahead for the display-flush idle window).

Detailed Description

Paged (demand-fetched) accessor mode for book over ra8_vmem (#163).

The default book accessors (book.h) are pure offset arithmetic over a fully-resident inflated blob – the right, zero-copy fast path for a book that fits the resident budget (and XIP-friendly). This sub-header adds the paged mode the #147/#162 memory hierarchy was built for: node / string / chapter lookups copy the needed bytes out of an ra8_vmem page cache on demand, so a GB-class EPUB / CBZ that does not fit RAM is read frame-by-frame with a bounded resident working set instead of a whole-blob inflate.

An book_src_t is the seam: it wraps either a resident blob base (zero-copy, identical to book.h) or an ra8_vmem cache fronting an ra8_vsource object (paged). Reads flow through book_src_read in both modes, and the DOM walkers (book_chapter_text_src) dispatch on the mode, so the reader uses one API and selects paged only when a book exceeds budget. The resident path is byte-for-byte identical to book_chapter_text(), so the ereader golden render stays unchanged for RAM-fitting books.

Note
Including this header pulls in ra8_vmem; the resident book.h API has no such dependency. Only consumers that page books need this file.
See also
book.h Resident (XIP) accessors + the on-disk format.
ra8_vmem.h The SLRU page cache the paged mode reads through.
ra8_vsource.h The backing-object registry the cache loads from.
Since
Version 0.1.0

Definition in file book_paged.h.

Function Documentation

◆ book_chapter_text_src()

ra8_err_t book_chapter_text_src ( const book_src_t * src,
uint32_t chapter_idx,
char * out,
size_t cap,
size_t * out_len )
nodiscard

Extract one chapter's plain text from a book source (resident or paged).

The source-aware counterpart of book_chapter_text(): same output contract (whitespace-collapsed text runs, a newline at each block-level element, not NUL-terminated), but reads the DOM through src so a paged book is walked frame-by-frame. In resident mode it delegates to book_chapter_text() and is byte-for-byte identical; in paged mode it copies each visited node and string out on demand, pinning only what it is reading.

Parameters
[in]srcBound book source.
[in]chapter_idxSpine chapter index (< src->hdr.chapter_count).
[out]outDestination text buffer (non-NULL).
[in]capCapacity of out in bytes.
[out]out_lenReceives the text byte length written.
Returns
ra8_err_t Error code.
Return values
k_ra8_okChapter text extracted.
k_ra8_err_null_ptrsrc, out, or out_len was NULL.
k_ra8_err_invalid_argchapter_idx is out of range.
k_ra8_err_invalid_sizeOutput did not fit cap, or DOM nesting exceeded the bounded walk stack.
k_ra8_err_*A page fault (paged mode only; returned verbatim).
Precondition
src was populated by book_src_resident() / book_src_paged().
chapter_idx is less than src->hdr.chapter_count.
Postcondition
On k_ra8_ok, out[0..*out_len) is the plain-text run (not NUL-terminated).
On error, out content is unspecified.
Note
Not thread-safe.
See also
book_chapter_text()
Since
Version 0.1.0

Definition at line 681 of file book_paged.c.

References book_src_t::base, book_chapter_text(), book_src_read(), book_header_t::chapter_count, book_header_t::chapter_off, book_src_t::hdr, internal_walk_text_paged(), k_ra8_err_invalid_arg, k_ra8_err_invalid_size, k_ra8_ok, book_header_t::node_count, RA8_CHECK_NULL_PTR, book_chapter_t::root_node, and s_tag_paged.

Referenced by sh_book_chapter_text().

◆ book_src_image()

ra8_err_t book_src_image ( const book_src_t * src,
uint32_t idx,
book_image_t * out_img )
nodiscard

Read one image descriptor out of a book source (resident or paged).

The source-aware counterpart of the resident-only book_images() accessor: resolves image idx to its blob offset (hdr.image_off + idx * sizeof(book_image_t)) and copies the 24-byte descriptor out through book_src_read, so a paged book faults the descriptor's frame in on demand. The descriptor names the image geometry and its data_off into the image pool; feed it to book_src_image_rect to read pixels. This is the library-owned replacement for open-coding the image-table stride in a consumer.

Parameters
[in]srcBound book source.
[in]idxImage-table index (< src->hdr.image_count).
[out]out_imgReceives the image descriptor.
Returns
ra8_err_t Error code.
Return values
k_ra8_okDescriptor copied into out_img.
k_ra8_err_null_ptrsrc or out_img was NULL.
k_ra8_err_invalid_argidx is at or past src->hdr.image_count.
k_ra8_err_*A page fault (paged mode only; returned verbatim).
Precondition
src was populated by book_src_resident() / book_src_paged().
out_img addresses writable storage for one book_image_t.
Postcondition
On k_ra8_ok, out_img holds the descriptor at idx.
On any non-ok return out_img content is unspecified.
Note
Not thread-safe.
See also
book_src_image_rect()
book_images()
Since
Version 0.1.0

Definition at line 314 of file book_paged.c.

References book_src_read(), book_src_t::hdr, book_header_t::image_count, book_header_t::image_off, k_ra8_err_invalid_arg, RA8_CHECK_NULL_PTR, and s_tag_paged.

Referenced by sh_gray4_image().

◆ book_src_image_rect()

ra8_err_t book_src_image_rect ( const book_src_t * src,
const book_image_t * img,
uint32_t x,
uint32_t y,
uint32_t w,
uint32_t h,
uint8_t * out,
uint32_t out_stride )
nodiscard

Read a sub-rectangle of a raster image (4bpp or 8bpp) as gray8, row by row.

Owns the image-pool addressing contract so consumers do not. Both raster depths of a k_book_image_gray4 entry are served, selected by the descriptor's book_image_pixfmt_t, and both yield one gray8 byte per output pixel so the renderer sees a single depth:

  • k_book_pixfmt_gray4: 2 pixels per byte, pixel (px,py) at flat nibble index py * width + px; each 4-bit sample is expanded to gray8 ((nib << 4) | nib). The odd-width nibble parity – where a row can start on either the high or low nibble of a pool byte – is handled here, once, instead of in every renderer. Each row is read in bounded packed spans (a fixed pixel budget per book_src_read).
  • k_book_pixfmt_gray8: 1 byte per pixel at flat index py * width + px; the row is the retained full-resolution continuous-tone source (#476) and is copied straight out with no unpack. This is the representation the zoom loupe magnifies and the e-ink dither (#477) re-quantises from – gray4 quantisation is not reversible, gray8 is not quantised at all.

The per-call read stays bounded by the rectangle regardless of the image width (book_src_read itself faults a paged source frame-by-frame), so the whole pool is never inflated. Rows are written at out_stride intervals, so out may be a window into a wider buffer.

Parameters
[in]srcBound book source.
[in]imgImage descriptor from book_src_image (format must be k_book_image_gray4; pixel_format selects the gray4 vs gray8 unpack).
[in]xSub-rect left edge in source pixels (x + w <= img->width).
[in]ySub-rect top edge in source pixels (y + h <= img->height).
[in]wSub-rect width in pixels (> 0, <= out_stride).
[in]hSub-rect height in pixels (> 0).
[out]outDestination gray8 buffer (>= out_stride * h bytes).
[in]out_strideBytes between successive output rows (>= w).
Returns
ra8_err_t Error code.
Return values
k_ra8_okThe wxh window was read into out as gray8.
k_ra8_err_null_ptrsrc, img, or out was NULL.
k_ra8_err_invalid_argimg is not a raster (SVG), its pixel_format is neither gray4 nor gray8, or w == 0, h == 0, or out_stride < w.
k_ra8_err_out_of_rangeThe sub-rect leaves the image, or the pool span it addresses leaves the blob.
k_ra8_err_*A page fault (paged mode only; returned verbatim).
Precondition
src was populated by book_src_resident() / book_src_paged().
out addresses at least out_stride * h writable bytes.
Postcondition
On k_ra8_ok, each out[r*out_stride + c] (0<=r<h, 0<=c<w) is the gray8 value of source pixel (x+c, y+r) (gray4 samples nibble-expanded, gray8 samples verbatim).
On any non-ok return out content is unspecified.
Note
Not thread-safe.
See also
book_src_image()
Since
Version 0.1.0

Definition at line 325 of file book_paged.c.

References book_image_pixfmt(), book_image_t::format, book_image_t::height, internal_book_image_row(), internal_book_image_row_gray8(), k_book_image_gray4, k_book_pixfmt_gray4, k_book_pixfmt_gray8, k_ra8_err_invalid_arg, k_ra8_err_out_of_range, k_ra8_ok, RA8_CHECK_NULL_PTR, s_tag_paged, and book_image_t::width.

Referenced by sh_gray4_fetch_row(), and sh_loupe_stage().

◆ book_src_paged()

ra8_err_t book_src_paged ( book_src_t * out,
ra8_vmem_t * vm,
uint32_t object_id,
uint32_t frame_bytes,
uint32_t size )
nodiscard

Bind a paged book source over an ::ra8_vmem cache + ::ra8_vsource object.

The demand-fetch path for books that do not fit the resident budget. The caller has already registered the book's bytes as an ::ra8_vsource paged (or XIP) object and initialised vm with ra8_vsource_loader. This reads the 100-byte header through the cache into book_src_t::hdr so header fields never fault thereafter.

Parameters
[out]outSource to populate (caller-owned).
[in]vmInitialised page cache fronting the book object (non-NULL).
[in]object_idThe book's ::ra8_vsource object id within vm's loader.
[in]frame_bytesvm's frame size in bytes (>= 2); used for slice math.
[in]sizeBlob length in bytes (> 0, == header total_size).
Returns
ra8_err_t Error code.
Return values
k_ra8_okSource bound in paged mode; header cached.
k_ra8_err_null_ptrout or vm was NULL.
k_ra8_err_invalid_sizesize was zero or frame_bytes was < 2.
k_ra8_err_*A page fault while reading the header (verbatim).
Precondition
vm was initialised with the book registered at object_id.
frame_bytes equals the frame size vm was configured with.
Postcondition
On success out->vm == vm, out->base == NULL, out->hdr is the header.
On any non-ok return out is left unbound.
Note
Not thread-safe; vm's pin/evict state is mutated by reads.
See also
book_src_resident()
Since
Version 0.1.0

Definition at line 61 of file book_paged.c.

References book_src_t::base, book_src_read(), book_src_t::frame_bytes, book_src_t::hdr, k_book_paged_min_frame, k_ra8_err_invalid_size, book_src_t::object_id, RA8_CHECK_NULL_PTR, s_tag_paged, book_src_t::size, and book_src_t::vm.

Referenced by sh_paged_bind().

◆ book_src_prefetch_chapter()

ra8_err_t book_src_prefetch_chapter ( const book_src_t * src,
uint32_t chapter_idx )
nodiscard

Warm the cache frame holding a chapter's first content bytes, without pinning it (single-threaded read-ahead for the display-flush idle window).

The reader-facing wrapper #207 wires into the flush-idle window: after rendering the current page and issuing the panel flush, warm the adjacent chapters (N+1 for forward reading, N-1 for a back-flip) so the next chapter-crossing page turn finds them resident. Resolves chapter_idx to the byte offset of its root DOM node – the first content range book_chapter_text_src reads for that chapter – and hands it to ra8_vmem_prefetch, which does a bounded get+put so the page ends resident but unpinned (SLRU/2Q probationary: a wrong read-ahead guess ages out before hot data, no prefetch backfire on a fast skim). Best-effort and transparent: warming only changes cache residency, never the bytes a later read returns, so rendered output is unchanged. Resident sources are already wholly in RAM and are rejected as a no-op.

Parameters
[in]srcBound (paged) book source.
[in]chapter_idxSpine chapter index to warm (< src->hdr.chapter_count).
Returns
ra8_err_t Error code (callers on the idle path typically discard it).
Return values
k_ra8_okThe chapter's root-node frame is resident, unpinned.
k_ra8_err_null_ptrsrc was NULL.
k_ra8_err_invalid_statesrc is resident (or unbound): nothing to page.
k_ra8_err_invalid_argchapter_idx is out of range.
k_ra8_err_*A chapter-record read or the warm faulted (verbatim).
Precondition
src was populated by book_src_paged() (paged mode, src->vm != NULL).
Called from the single owning context (e.g. the reader idle window).
Postcondition
On k_ra8_ok the chapter's first content frame is resident with a net-zero change to its pin count.
On any return no cache frame is left pinned by this call.
Note
Not thread-safe. Single-threaded read-ahead only.
Warming is transparent: it never alters the bytes a subsequent read sees.
See also
ra8_vmem_prefetch() The bounded get+put warm this maps a chapter to.
book_chapter_text_src() The demand read this warms ahead of.
Since
Version 0.1.0

Definition at line 721 of file book_paged.c.

References book_src_read(), book_header_t::chapter_count, book_header_t::chapter_off, book_src_t::hdr, k_ra8_err_invalid_arg, k_ra8_err_invalid_state, k_ra8_ok, book_header_t::node_off, book_src_t::object_id, RA8_CHECK_NULL_PTR, ra8_vmem_prefetch(), book_chapter_t::root_node, s_tag_paged, and book_src_t::vm.

Referenced by sh_reader_prefetch_adjacent().

◆ book_src_read()

ra8_err_t book_src_read ( const book_src_t * src,
uint32_t off,
void * dst,
uint32_t len )
nodiscard

Copy a byte range out of a book source (resident memcpy or paged fault).

The single read primitive both modes share. Resident mode is a memcpy(dst, base + off, len). Paged mode walks the range frame by frame: ra8_vmem_get pins the frame holding the current offset, the overlapping slice is copied to dst, and ra8_vmem_put releases it before advancing – so at most one frame is pinned at a time and the resident working set stays bounded regardless of len.

Parameters
[in]srcBound book source.
[in]offByte offset within the blob (off + len <= src->size).
[out]dstDestination buffer receiving len bytes (non-NULL).
[in]lenNumber of bytes to copy.
Returns
ra8_err_t Error code.
Return values
k_ra8_okBytes copied into dst.
k_ra8_err_null_ptrsrc or dst was NULL.
k_ra8_err_invalid_statesrc is bound to neither mode.
k_ra8_err_out_of_rangeoff + len exceeds src->size.
k_ra8_err_*A page fault (paged mode only; returned verbatim).
Precondition
src was populated by book_src_resident() / book_src_paged().
dst addresses at least len writable bytes.
Postcondition
On success dst[0..len) holds the blob bytes at off.
On any non-ok return dst content is unspecified and no pin is held.
Note
Not thread-safe.
Since
Version 0.1.0

Definition at line 141 of file book_paged.c.

References book_src_t::base, internal_book_src_read_paged(), k_ra8_err_invalid_state, k_ra8_err_out_of_range, k_ra8_ok, memcpy(), RA8_CHECK_NULL_PTR, s_tag_paged, book_src_t::size, and book_src_t::vm.

Referenced by book_chapter_text_src(), book_src_image(), book_src_paged(), book_src_prefetch_chapter(), internal_book_image_row(), internal_book_image_row_gray8(), internal_paged_emit_run(), internal_paged_node(), internal_paged_str_short(), sh_rabook_label(), and sh_src_string().

◆ book_src_resident()

ra8_err_t book_src_resident ( book_src_t * out,
const void * base,
uint32_t size )
nodiscard

Bind a resident (already-inflated, fully resident) book as a source.

The zero-copy fast path: book_src_t::base is set to base and reads become base + off, byte-for-byte identical to the book.h accessors. The header is copied into book_src_t::hdr.

Parameters
[out]outSource to populate (caller-owned).
[in]baseValidated .rabook blob base (non-NULL), as from book_open().
[in]sizeBlob length in bytes (> 0, == header total_size).
Returns
ra8_err_t Error code.
Return values
k_ra8_okSource bound in resident mode.
k_ra8_err_null_ptrout or base was NULL.
k_ra8_err_invalid_sizesize was zero.
Precondition
base was accepted by book_validate() / book_open().
out points at writable storage out-living the reads.
Postcondition
On success out->base == base, out->vm == NULL, out->hdr is the header.
On any non-ok return out is left unbound.
Note
Not thread-safe; reads over the immutable blob are otherwise re-entrant.
See also
book_src_paged()
Since
Version 0.1.0

Definition at line 45 of file book_paged.c.

References book_src_t::base, book_src_t::frame_bytes, book_src_t::hdr, k_ra8_err_invalid_size, k_ra8_ok, memcpy(), book_src_t::object_id, RA8_CHECK_NULL_PTR, s_tag_paged, book_src_t::size, and book_src_t::vm.