-
Notifications
You must be signed in to change notification settings - Fork 1
Photon
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.mdin the main repo — vision, decisions (D1–D12), workstreams (W1–W8), milestones (M0–M5) and a dated status log. This page is the overview.
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.
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)
-
Sdf.csis 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
DrawCommandrecords (Clear / FillRRect / StrokeRRect, solid or two-stop linear gradient paints, baked 2D transforms).
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.
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).
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.
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.