← Blog
0.7.0 · APPS · SRDX

SRDX Viewer Decode Path + HTTP Fetch — 0.7.0 T2

June 22, 2026 · sigil-apps ad28b7d · Sigil-Docs
srdx viewer browser networking http 0.7.0 milestone

sigil-apps ad28b7d closes two critical 0.7.0 loops. apps/srdx/viewer.sg (IS_SCENE) closes the SRDX 1.0 decode loop: the viewer now has an inline BGRA32 decoder that blits dirty-rect frames directly to the raw framebuffer layer and composites the Lumen chrome on top. This is the Apps-side receiver for srdx_relay.sg frames (OS, coming next) — no ABI change needed when the OS relay lands. apps/net/http_fetch.sg (arm-el0) closes the HTTP dark lane: it exercises the full HTTP/1.1 redirect chain (GET → 301 → GET → 200 → body) using the same inline request builder as the OS cc0 net stack, wiring to live Cap<NetConn> syscalls when the Kernel grants net caps.


viewer.sg — SRDX decode path (IS_SCENE)

The SRDX viewer was already in the App (Sessions Manager, srdx_negotiate_* wired in f6ef9a4). What was missing was the actual decode path — the pipeline that takes an incoming SRDX encoded frame, decodes it, and blits it to the display. ad28b7d wires this in.

srdx_decode_inline: scalar BGRA32 dirty-rect decoder. For each tile in the incoming SRDX frame:

  1. Check the tile's dirty bit in the frame header
  2. If dirty: decode the 64×64 tile payload (raw BGRA32, no compression in the loopback test path) into the raw fb layer
  3. Call poke32 per pixel into the framebuffer at the tile's (x,y) offset

After all tiles are decoded, the Lumen chrome is composited over the raw fb layer — nav bar, session status panel, and the SRDX stream canvas are all compositor layers drawn on top. The viewer is IS_SCENE in build.sh (appears in the demo reel and IS_SCENE build target).

The left panel surfaces live decode state:

Host address
sigil-pi:5900 — the connected host's ADV-discovered address and port.
SRDX cap
srdx capability chip shown held, not dimmed — confirms the viewer holds the SRDX transport cap.
STATE
live — updated each frame. Transitions: connectingnegotiatinglivestalled.
seq
Current frame sequence number from the most recently decoded SRDX frame header.
rect
The dirty rect bounding box of the most recently decoded frame (in tile coordinates).
dim
Decoded frame dimensions (w × h pixels).
decode-ok
Boolean — 1 if the last frame decoded without error. CRC or tile count mismatch sets this to 0.

Canvas position: item (164,0,440,300) = screen coordinates (187,63) with size 438×298. The fb blit aligns exactly to this canvas boundary — the dirty-rect decoder writes only inside this region.

ABI stability: srdx_relay.sg (OS, coming next) will feed frames directly into this viewer via the same SRDX frame wire format. No ABI change on the viewer side — the relay just becomes the frame source instead of a test fixture.

Build: ./build.sh srdx_viewer shot — runs the viewer demo scene and saves a screendump.

viewer.sg blit-order fix — SRDX decode live, Lumen chrome composited on top
viewer.sg blit-order fix (258d512): composite_scene first (Lumen chrome + window bg), srdx_decode_inline blit second (BGRA32 gradient fills 438×298 canvas region exactly, chrome composited on top). QEMU screendump confirms full frame path: srdx_decode_inline → fb blit → Lumen compose. srdx_relay.sg (OS, next) feeds frames directly — no ABI change.

http_fetch.sg — HTTP/1.1 redirect-follow + parse (arm-el0)

apps/net/http_fetch.sg is the arm-el0 (real hardware / EL0 cap ABI) counterpart to the OS cc0 http_fetch.sg that shipped in 0ecc2f6. It exercises the full HTTP/1.1 redirect chain — the "dark lane" that the OS net stack tests with loopback stubs, now tested with the real arm-el0 cap ABI.

GET / (initial)
Builds HTTP/1.1 GET request using wstr/wline inline helpers. Sends via Cap<NetConn> sys 109 (net_conn_connect) + sys 110 (net_conn_send).
301 Location:/new
Response parser finds status 301, extracts Location: header via find_location(). Closes the connection, opens a new one. HTTP_MAX_REDIRECTS=3 prevents infinite redirect loops.
GET /new (redirect)
Second GET to the Location path, following the redirect chain transparently.
200 headers+body
Final response. find_body() locates body start (after \r\n\r\n). print_headers() surfaces Content-Type, Content-Length. Body excerpt printed.
Live wire-in
Cap<NetConn> sys 109/110/111/112 (net_conn_connect/send/recv/close from OS 722353c) wires in when the Kernel grants CAP_NET. Currently runs against the loopback test server in the arm-el0 test harness.

Parser helpers, composed inline rather than as separate surface rows:

This covers the OS "dark HTTP lane" — the path where the app layer exercises HTTP without going through a JS runtime. When cc0/JS ships, JS fetch() calls go through http_fetch.sg via the Net process. The arm-el0 test validates the ABI independently.

apps/net/http_fetch.sg (arm-el0)
  GET /
    → Cap<NetConn> sys109 (connect) + sys110 (send)
    ← 301 Location:/new
      find_location() → /new
      sys112 (close)
  GET /new
    → sys109 (connect) + sys110 (send)
    ← 200 OK
      find_body() → body offset
      print_headers() → Content-Type, Content-Length
      body excerpt printed

What this closes

FileWhat shipsLoop closed
apps/srdx/viewer.sgIS_SCENE, inline BGRA32 decoder, dirty-rect fb blit, Lumen chrome compositeSRDX 1.0 decode loop (Apps side)
apps/net/http_fetch.sgarm-el0 HTTP/1.1 redirect chain, Cap<NetConn> sys 109–112 wire-inHTTP dark lane (arm-el0 ABI)
srdx_relay.sg (OS)coming nextSRDX 1.0 relay loop (OS side)

srdx_relay.sg on the OS side is the remaining 0.7.0 SRDX closure. When it lands, the relay becomes the frame source for the viewer — no ABI change, the wire format is already locked by ad28b7d.