libwebsockets/READMEs/README.display-list.md
Andy Green e3dca87f23 lws_display: add display list / DLO support
This adds optional display list support to lws_display, using DLOs (Display
List Objects).  DLOs for rectangle / rounded rectangle (with circle as the
degenerate case), PNGs, JPEG and compressed, antialiased bitmapped fonts
and text primitives are provided.

Logical DLOs are instantiated on heap and listed into an lws_display_list
owner, DLOs handle attributes like position, bounding box, colour +
opacity, and local error diffusion backing buffer.

When the display list is complete, it can be rasterized a line at a time,
with scoped error diffusion resolved, such that no allocation for the
framebuffer is required at any point.  DLOs are freed as the rasterization
moves beyond their bounding box.

Adds a platform registry binding names and other metadata to lws_display
fonts / PNGs / JPEGs.  Provides registration, destruction and best match
selection apis.
2022-03-25 08:18:29 +00:00

149 lines
5.4 KiB
Markdown

# lws_display_list
`lws_display_list` is a modernized 1970s-style Display List of graphic
primitives held in an `lws_dll2` list of Display List Objects (DLOs).
Provided DLO primitives are:
- filled rectangle (with individually controllable rounded corners)
- PNG (1:1 and original orientation only, transparency supported)
- JPEG (1:1 and original orientation only)
- utf-8 text areas (using compressed, antialiased mcufonts)
The aim of it is to process some other representation to describe the
logical scene completely using DLOs in memory, discard the earlier
representation and then rasterize the Display List a single line at a
time from top to bottom, so no backing framebuffer is required at all.
DLOs are destroyed as they go out of scope during rasterization.
Although the memory required does scale with scene complexity in
terms of number of DLOs, it hardly scales at all with output
resolution, allowing modern 32-bpp rendering on very constrained
devices, if slowly.
## DLO capabilities
DLOs are quite capable
- no floats (`lws_fx` integer fixed-point)
- 16-bit signed coordinate space with off-surface clipping handled
- Internal 32-bpp RGBA colourspace (8-bit opacity)
- correct Z-order opacity resolution
- Supports arbitrary paletteization (down to 1bpp) and error diffusion
- DLO-private error diffusion for clean opaque overlaid objects
- Antialised bitmap text using compressed fonts (eg 7 font sizes 10-
32px in both regular and bold < ~100KB)
- Very lightweight stateful PNG and JPEG decode
All DLOs in a Display List are consumed as they are rasterized,
individual DLOs are destroyed as soon as they go out of scope during
top - bottom rendering, freeing any related resources as soon as possible.
## DLO PNGs
DLOs may point to a compressed PNG, which is decompressed on the fly
and the decompression context destroyed as the rasterization goes
beyond its bounding box. Using the lws stateful rewrite of upng, the
memory cost of 32-bpp PNG decode of any dimensions is 40K + 16 x width
bytes, including error diffusion line buffers. Decoding of the
compressed PNG data is done statefully on demand as needed to fill an
output line, so no memory is needed to hold excess decode production.
Multiple PNG DLOs including PNG-over-PNG (with alpha mixing) are
allowed. PNGs only take heap memory while the current rasterization
line intersects them, so any number of PNGs that don't intersect
vertically do not cost any more peak memory allocation than decoding one,
since the decoding contexts and DLOs of the earlier ones have been
destroyed before the next one's decoding context is allocated.
## DLO JPEGs
DLOs can also represent JPEGs using a stream parsing rewite of picojpeg.
No framebuffer is required to hold the output, it produces one line of
pixels at a time. JPEGs use either 8- or 16- line deep MCUs,
necessitating an 8 or 16 line RGB (or Y if grayscale) pixel buffer
during decode.
Heap requirements while a JPG is being rasterized is 2.5KB plus the
MCU buffer dependent on the chroma coding:
|Image type|Fixed alloc|MCU buffer|
|---|---|---|
|grayscale|2.5KB|image width x 8 bytes|
|YUV 4:4:4|2.5KB|image width x 24 bytes|
|YUV 4:4:2v|2.5KB|image width x 24 bytes|
|YUV 4:4:2h|2.5KB|image width x 48 bytes|
|YUV 4:4:0|2.5KB|image width x 48 bytes|
## DLO text
Text DLOs are predicated around unicode utf-8 and a stream parsing
rewrite of mcufont decoder.
mcufont includes a ttf renderer app which is ported into lws as well,
this allows production of antialised (16 alpha level) compressed
bitmaped fonts from any ttf font at a selected size and including
specified subsets of unicode code points.
Font glyphs are decompressed statefully as part of the DLO line
rasterization process, so there are no glyph buffers or caching.
The decompression is very fast and allows fitting over a dozen
font sizes and weights into 100KB.
Wrapping inside a bounding box is supported as is "run-on", where text
DLOs follow one another inline, used for example to use a bold font
in part of a text using a different DLO with a different font before
continuing with another DLO using the non-bold font cleanly. DLOs
are marked as running-on or not.
Centering and right-justification is possible by summing run-ons on
the current line by walking the display list backwards until a non-
run-on DLO is seen, and adjusting the affected DLOs x position.
## Display List lifecycle
### Create empty display list
Create the display state (the dynamic counterpart of the const, static
`lws_display` definition) and the empty display list.
```
lws_display_state_t lds;
lws_displaylist_t dl;
```
Instantiate the `lws_display` and bind the display list to it
```
lws_display_state_init(&lds, cx, 30000, 10000, lls, &disp.disp);
lws_display_dl_init(&dl, &lds);
### Create DLOs into the list
Eg, create a png from `data` / `len`, return NULL if failed.
```
if (!lws_display_dlo_png_new(&dl, &box, data, len)) {
```
Eg, create a white background rectange the size of the `lws_display`
```
lws_dlo_rect_t *dr;
lws_box_t box = { 0, 0, dl.ds->disp->ic.wh_px[0].whole,
dl.ds->disp->ic.wh_px[1].whole };
dr = lws_display_dlo_rect_new(&dl, &box, 0,
LWSDC_RGBA(255, 255, 255, 255));
if (!dr)
return 1;
```
### Rendering into an lws_display
```
lds->disp->blit(lds, (uint8_t *)&dl, &box);
```