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

Strip composite for the tap-to-zoom viewer: magnify, re-dither, blit (#478). More...

#include <stdint.h>
#include <string.h>
#include "ra8_attributes.h"
#include "ra8_check.h"
#include "ra8_err.h"
#include "ra8_gfx.h"
#include "ra8_gfx_dither.h"
#include "zoom.h"
#include "zoom_internal.h"
Include dependency graph for zoom_render.c:

Go to the source code of this file.

Enumerations

enum  zoom_blit_t : uint8_t {
  k_zoom_blit_origin = 0U ,
  k_zoom_blit_native = 1U
}
 Fixed arguments of the per-strip packed-gray4 blit. More...

Functions

static void internal_expand_row (const zoom_view_t *v, const zoom_axis_t *ax, uint8_t *drow)
 Replicate one source row across the covered destination columns.
static ra8_err_t internal_fill_row (zoom_view_t *v, const zoom_axis_t *ax, int32_t plane_y, uint8_t *drow, int32_t *cached_sy)
 Composite one destination row: decide coverage, fault, replicate.
static ra8_err_t internal_fill_strip (zoom_view_t *v, const zoom_axis_t *ax, int32_t top, int32_t rows, int32_t *cached_sy)
 Build one gray8 destination strip: background fill, then per-row composite.
static ra8_err_t internal_emit_strip (zoom_view_t *v, const zoom_axis_t *ax, int32_t top, int32_t rows, int32_t *cached_sy)
 One strip, end to end: magnify, re-dither at plane phase, blit.
static ra8_err_t internal_render_ready (const zoom_view_t *v)
 Whether a view is in a state that can be composited at all.
ra8_err_t zoom_view_render (zoom_view_t *v)
 Composite the visible window into the bound ra8_gfx framebuffer.

Variables

static const char *const s_tag = "zoom_render"
 Component tag for RA8_CHECK_* log lines.

Detailed Description

Strip composite for the tap-to-zoom viewer: magnify, re-dither, blit (#478).

The render half of zoom.h. It never holds the visible window: a 1024x600 gray8 window would be 600 KiB and cannot be allocated (NASA P10 Rule 3), so the viewport is composited in horizontal strips of at most zoom_view_t::strip_rows destination rows and the resident cost is O(dst.w * strip_rows).

Each strip goes through the same three steps:

  1. Magnify. Nearest-neighbour replication straight into the destination grid, one source row read per distinct source row (consecutive destination rows at zoom n share a source row, and the row buffer is reused rather than re-faulted). Uncovered pixels are filled with k_zoom_bg_gray, so the caller never pre-clears the viewport.
  2. Re-dither at the destination resolution, not the source's. The issue asks for the retained gray8 to be "re-dithered at the current zoom": if the source were dithered and then magnified, a 4x view would show 4x4 blue-noise blobs. Dithering after magnification keeps the grain one panel pixel wide at every zoom. The mask phase is the magnified-plane coordinate, so a given image pixel keeps its threshold as the viewport moves – panning does not re-roll the grain (see the zoom.h docblock).
  3. Blit the packed 4 bpp strip through ra8_gfx_blit_gray4_zoom at native scale. The magnification has already happened, so this call is a nibble-unpack and clipped store – the same tested primitive the shelf loupe uses, rather than a second pixel path.

Every operation is integer arithmetic over source bytes and a const mask, so a framebuffer hash of the result is identical on the unit-test host, in ra8_emulator and on silicon.

[Ring 4 / Domain] {World: NS}

Since
0.1.0

Definition in file zoom_render.c.

Enumeration Type Documentation

◆ zoom_blit_t

enum zoom_blit_t : uint8_t

Fixed arguments of the per-strip packed-gray4 blit.

The strip is already at destination resolution when it reaches ra8_gfx_blit_gray4_zoom, so the blit magnifies by k_zoom_blit_native (1) and takes the whole strip from its origin. Naming them keeps the call self-describing and keeps the "no magic numbers" rule honest at the one place a reader would otherwise have to count arguments.

Invariant
k_zoom_blit_native == 1: this module owns the magnification itself.
Example:
w, rows, k_zoom_blit_native, x, y);
ra8_err_t ra8_gfx_blit_gray4_zoom(const uint8_t *src, int32_t src_w, int32_t src_h, int32_t sx, int32_t sy, int32_t sw, int32_t sh, int32_t zoom, int32_t dst_x, int32_t dst_y)
Nearest-neighbour integer-zoom blit of a sub-rectangle of a packed 4-bit grayscale image into the fra...
@ k_zoom_blit_origin
Sub-rect origin inside the packed strip.
Definition zoom_render.c:80
@ k_zoom_blit_native
Blit magnification (the strip is already sized).
Definition zoom_render.c:81
See also
zoom_view_render
Since
0.1.0
Enumerator
k_zoom_blit_origin 

Sub-rect origin inside the packed strip.

k_zoom_blit_native 

Blit magnification (the strip is already sized).

Definition at line 79 of file zoom_render.c.

Function Documentation

◆ internal_emit_strip()

ra8_err_t internal_emit_strip ( zoom_view_t * v,
const zoom_axis_t * ax,
int32_t top,
int32_t rows,
int32_t * cached_sy )
static

One strip, end to end: magnify, re-dither at plane phase, blit.

The three-step pipeline the file docblock describes, kept together so zoom_view_render is only the strip loop. The dither phase is the magnified-plane origin of this strip, which is what makes the grain belong to the image rather than to the panel.

Parameters
[in,out]vOpen view.
[in]axResolved horizontal axis for this frame.
[in]topDestination row of the strip's first line.
[in]rowsRows in this strip (>= 1).
[in,out]cached_sySource row currently held in v->scratch.row, or -1.
Returns
ra8_err_t Error code.
Return values
k_ra8_okThe strip is on the framebuffer.
k_ra8_err_*Propagated verbatim from the source reader or ra8_gfx.
Precondition
ra8_gfx_init has bound a framebuffer.
top + rows <= v->dst.h.
Postcondition
On k_ra8_ok destination rows [top, top + rows) of v->dst are painted.
On failure nothing past the failing step was written.
Note
Not thread-safe; writes the single ra8_gfx framebuffer binding.
See also
internal_fill_strip
Since
0.1.0

Definition at line 269 of file zoom_render.c.

References zoom_view_t::anchor_x, zoom_view_t::anchor_y, zoom_view_t::dst, internal_fill_strip(), k_zoom_blit_native, k_zoom_blit_origin, zoom_scratch_t::packed, zoom_scratch_t::packed_cap, ra8_gfx_blit_gray4_zoom(), ra8_gfx_dither_gray8_to_gray4(), RA8_RETURN_ON_ERROR, s_tag, zoom_view_t::scratch, zoom_scratch_t::strip, ra8_ui_rect_t::w, ra8_ui_rect_t::x, and ra8_ui_rect_t::y.

Referenced by zoom_view_render().

◆ internal_expand_row()

void internal_expand_row ( const zoom_view_t * v,
const zoom_axis_t * ax,
uint8_t * drow )
static

Replicate one source row across the covered destination columns.

The horizontal half of the nearest-neighbour magnify: destination offset d shows plane column anchor_x + d, hence source column (anchor_x + d) / scale, which is an index into the row buffer once the axis' own s0 is subtracted. Columns outside [d0, d1) are letterbox and are left at the background fill the caller wrote.

Parameters
[in]vOpen view (supplies the anchor, scale and row buffer).
[in]axResolved horizontal axis for this frame.
[out]drowOne destination strip row, at least v->dst.w bytes.
Returns
Nothing.
Precondition
v->scratch.row holds source columns [ax->s0, ax->s0 + ax->count).
drow addresses at least v->dst.w writable bytes.
Postcondition
Every destination offset in [ax->d0, ax->d1) holds its source sample.
No offset outside that half-open span is written.
Note
Not thread-safe (writes drow); pure with respect to v.
See also
priv_zoom_axis
Since
0.1.0

Definition at line 109 of file zoom_render.c.

References zoom_view_t::anchor_x, zoom_axis_t::d0, zoom_scratch_t::row, zoom_axis_t::s0, zoom_view_t::scale, and zoom_view_t::scratch.

Referenced by internal_fill_row().

◆ internal_fill_row()

ra8_err_t internal_fill_row ( zoom_view_t * v,
const zoom_axis_t * ax,
int32_t plane_y,
uint8_t * drow,
int32_t * cached_sy )
static

Composite one destination row: decide coverage, fault, replicate.

Where a destination row decides what it is. A row above the image, below it, or on an axis with no horizontal coverage is letterbox and returns having written nothing – the caller has already filled it with the background. A covered row reads its source row only when it differs from the one already in the row buffer, which at zoom n is once per n destination rows and never twice across a strip boundary, since cached_sy carries over.

Parameters
[in,out]vOpen view (its row scratch is written).
[in]axResolved horizontal axis for this frame.
[in]plane_yMagnified-plane row this destination row shows.
[out]drowThe destination strip row, pre-filled with background.
[in,out]cached_sySource row currently held in v->scratch.row, or -1.
Returns
ra8_err_t Error code.
Return values
k_ra8_okThe row is composited, or is letterbox and left alone.
k_ra8_err_*Propagated verbatim from the source reader.
Precondition
v is open and its scratch capacities were validated at open.
drow holds at least v->dst.w writable bytes.
Postcondition
On k_ra8_ok every covered offset of drow holds its source sample.
On failure *cached_sy is -1, so a retry cannot reuse a partial row.
Note
Not thread-safe.
See also
internal_expand_row
Since
0.1.0

Definition at line 154 of file zoom_render.c.

References zoom_axis_t::count, zoom_source_t::ctx, zoom_source_t::height, internal_expand_row(), k_ra8_ok, ra8_log_error_val, zoom_source_t::read, zoom_scratch_t::row, zoom_axis_t::s0, s_tag, zoom_view_t::scale, zoom_view_t::scratch, and zoom_view_t::src.

Referenced by internal_fill_strip().

◆ internal_fill_strip()

ra8_err_t internal_fill_strip ( zoom_view_t * v,
const zoom_axis_t * ax,
int32_t top,
int32_t rows,
int32_t * cached_sy )
static

Build one gray8 destination strip: background fill, then per-row composite.

The background fill is unconditional and covers the whole strip in one pass, so a letterbox row needs no second visit and the caller never has to pre-clear the viewport. The horizontal-coverage test is settled here, once per strip, rather than per row: it is constant across the frame, and a zero-width row would violate the source seam's w > 0 contract if it ever reached zoom_read_fn. Everything else is internal_fill_row's decision.

Parameters
[in,out]vOpen view (its row/strip scratch is written).
[in]axResolved horizontal axis for this frame.
[in]topDestination row of the strip's first line.
[in]rowsRows in this strip (>= 1).
[in,out]cached_sySource row currently held in v->scratch.row, or -1.
Returns
ra8_err_t Error code.
Return values
k_ra8_okThe strip holds rows composited destination lines.
k_ra8_err_*Propagated verbatim from the source reader.
Precondition
v is open and its scratch capacities were validated at open.
top + rows <= v->dst.h.
Postcondition
On k_ra8_ok v->scratch.strip[0 .. rows*dst.w) is fully defined.
On failure the strip is partially written and must not be blitted.
Note
Not thread-safe.
See also
internal_fill_row
Since
0.1.0

Definition at line 219 of file zoom_render.c.

References zoom_view_t::anchor_y, zoom_axis_t::count, zoom_view_t::dst, internal_fill_row(), k_ra8_ok, k_zoom_bg_gray, memset(), RA8_RETURN_ON_ERROR, s_tag, zoom_view_t::scratch, zoom_scratch_t::strip, and ra8_ui_rect_t::w.

Referenced by internal_emit_strip().

◆ internal_render_ready()

ra8_err_t internal_render_ready ( const zoom_view_t * v)
static

Whether a view is in a state that can be composited at all.

Split out of zoom_view_render so the render body is the strip loop and nothing else. The strip-height check is not defensive padding: it is the loop bound, and a zero would make the strip loop fail to advance (NASA P10 Rule 2).

Parameters
[in]vCandidate view.
Returns
ra8_err_t Error code.
Return values
k_ra8_okThe view can be rendered.
k_ra8_err_null_ptrv is NULL, or its source seam is.
k_ra8_err_invalid_statev is closed, or was never opened properly.
Precondition
None – NULL is an accepted input and is reported.
The caller has not yet touched the framebuffer.
Postcondition
No state is modified.
On k_ra8_ok v->strip_rows >= 1, so the strip loop terminates.
Note
Not thread-safe (logs).
See also
zoom_view_render
Since
0.1.0

Definition at line 324 of file zoom_render.c.

References zoom_view_t::active, k_ra8_err_invalid_state, k_ra8_ok, RA8_CHECK_NULL_PTR, ra8_log_error, zoom_source_t::read, s_tag, zoom_view_t::src, and zoom_view_t::strip_rows.

Referenced by zoom_view_render().

◆ zoom_view_render()

ra8_err_t zoom_view_render ( zoom_view_t * v)
nodiscard

Composite the visible window into the bound ra8_gfx framebuffer.

The render pipeline, one horizontal strip at a time (see the file docblock for why strips): magnify the source into the gray8 strip by nearest-neighbour replication, blue-noise dither the strip at magnified-plane phase so the grain belongs to the image rather than the panel, pack it to 4 bpp, and blit it. Every destination pixel of zoom_view_t::dst is written – image where the source covers it, k_zoom_bg_gray in the letterbox – so the caller never has to pre-clear the viewport.

The whole path is integer arithmetic over the source bytes and a const mask, so the output is byte-identical on the unit-test host, in ra8_emulator and on silicon. That is what makes a framebuffer hash a usable golden.

Parameters
[in,out]vOpen view.
Returns
ra8_err_t Error code.
Return values
k_ra8_okThe viewport was painted.
k_ra8_err_null_ptrv is NULL.
k_ra8_err_invalid_statev is not open.
k_ra8_err_*Propagated verbatim from the source reader or ra8_gfx.
Precondition
ra8_gfx_init has bound a framebuffer.
v was opened by zoom_view_open.
Postcondition
On k_ra8_ok every pixel of v->dst inside the framebuffer has been written.
The ra8_gfx clip rectangle is left exactly as the caller set it.
Note
Not thread-safe; writes through the single ra8_gfx framebuffer binding. Honours the caller's clip, so a lens can be masked to a rounded box.
Example:
if (zoom_view_render(&view) != k_ra8_ok) { er_show_error(); }
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
ra8_err_t zoom_view_render(zoom_view_t *v)
Composite the visible window into the bound ra8_gfx framebuffer.
See also
zoom_view_present
Since
0.1.0

Definition at line 339 of file zoom_render.c.

References zoom_view_t::anchor_x, zoom_view_t::dst, ra8_ui_rect_t::h, internal_emit_strip(), internal_render_ready(), k_ra8_ok, priv_zoom_axis(), RA8_RETURN_ON_ERROR, s_tag, zoom_view_t::scale, zoom_view_t::src, zoom_view_t::strip_rows, ra8_ui_rect_t::w, and zoom_source_t::width.

Referenced by ez_scene_render().

Variable Documentation

◆ s_tag

const char* const s_tag = "zoom_render"
static

Component tag for RA8_CHECK_* log lines.

Definition at line 55 of file zoom_render.c.