Skip to content
Edgar Mesquita edited this page Jul 5, 2026 · 12 revisions

Photon — The Native GPU Engine (Track N)

Photon is eQuantic.UI's proprietary GPU rendering engine for mobile (and eventually desktop): a from-scratch, Impeller-inspired renderer that draws the component tree pixel by pixel on the GPU — Metal on iOS/macOS, Vulkan on Android — with no Skia tier and no WebView. It is the second realization target of the write-once component architecture: the same C# components that lower to DOM+CSS on the web are rasterized by Photon natively.

The living plan is docs/NATIVE-GPU-ENGINE-PLAN.md in the main repo — vision, decisions (D1–D12), workstreams (W1–W8), milestones (M0–M5) and a dated status log. This page is the overview.

Why proprietary, why no Skia

The decision (2026-07): if the project was going to own a native tier at all, it would own the whole rendering stack — direct Metal/Vulkan backends with precompiled shaders, not a wrapper over Skia. That buys:

  • Predictable performance: fixed pipeline-state registry, zero shader compilation at runtime (the jank source Impeller was built to kill).
  • A tiny surface: UI rendering needs a handful of primitives, not a general 2D library.
  • One normative model: the same math, testable to the pixel, across CPU reference and every GPU backend.

Architecture at a glance

C# components (write-once, eQuantic.UI.Primitives vocabulary)
        │  Build(ComponentContext)          — pure, token-based, mode-free
        ▼
eQuantic.UI.Native.Framework                — C# flex layout engine (spec A2)
        ▼
eQuantic.UI.Native.Components               — PhotonRealizer: abstract tree → display list
        ▼
eQuantic.UI.Native.Engine                   — geometry, color model, Sdf.cs (NORMATIVE), DisplayList
        ▼
IRenderBackend
   ├── eQuantic.UI.Native.Engine.Reference  — scalar CPU rasterizer (golden ground truth, never shipped)
   ├── eQuantic.UI.Native.Engine.Metal      — Apple GPUs (offscreen spike landed)
   └── (Vulkan — planned)

The normative core

  • Sdf.cs is a spec, not a library: per-corner rounded-rect signed distance, centered stroke (|d| − w/2), 1-pixel anti-aliasing coverage ramp. Every rasterizer — the CPU reference and the GPU fragment shaders — implements exactly these formulas.
  • Color model: sRGB authoring → linear premultiplied blending → sRGB store, mirroring GPU hardware behavior with sRGB render targets.
  • Display lists: flat, heap-free DrawCommand records (Clear / FillRRect / StrokeRRect, solid or two-stop linear gradient paints, baked 2D transforms).

Golden-image harness

Every scene renders through a backend into a surface, reads back sRGB pixels, and compares against committed PNG goldens (dependency-free codec, EQ_UPDATE_GOLDENS=1 regeneration flow, ±2 tolerance, failure artifacts with amplified diffs). The scene catalog is shared: the Reference backend pins the goldens; GPU backends run the same catalog for parity.

Metal spike result (2026-07-04)

The first GPU frames validated the whole model: an offscreen Metal backend driven by ~100 lines of typed objc_msgSend P/Invoke (no binding framework, no C shims), one pipeline built at device init, runtime-compiled MSL that transliterates Sdf.cs. Measured against the CPU reference across all 14 golden scenes (fills, strokes, gradients, rotation/scale transforms, translucent blending, radius clamping):

Max channel difference: 1 (of 255). Zero pixels beyond ±2.

The GPU passes the golden harness's own tolerance — Sdf-as-spec and the color model hold end-to-end on hardware. Production shaders move to an offline Slang toolchain (single shader source → SPIR-V for Vulkan + metallib for Metal, embedded like the Bun binaries).

Component rendering today

The native realizer draws real component chrome (token-resolved fills, inside borders, per-corner radii) with documented placeholders where subsystems are pending:

Subsystem v1 state
Shapes, borders, gradients, transforms, blending ✅ Full, golden-tested
Layout (flex, stacks, truncation contract) ✅ C# engine, spec A1–A3
Text Placeholder line bars (30% alpha) until the HarfBuzz/FreeType atlas (W4)
Icons Tinted disc placeholder until the glyph atlas — path data already lives in the shared registry
Images SurfaceSubtle box until engine texture upload (M4)
Shadows (elevation) Border fallback until the analytic shadow primitive
Scrolling/clip Pending an engine clip primitive

Interaction is wired: PhotonHost holds a retained root, SetState invalidates, taps dispatch to ≥48dp hit regions (topmost wins, disabled swallows) — the native Counter runs tap → SetState → rebuild end-to-end in tests.

Status

M0 (walking skeleton) is effectively complete: engine core + Reference backend + golden harness + Metal parity + the write-once pipeline feeding it. Native suite: 150 tests, 25 goldens. Next on this track: engine clip primitive (unblocks ScrollView), Slang toolchain spike, RHI extraction from the Metal spike's shape, Vulkan backend.

Clone this wiki locally