Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ split** β€” in **[doc/diagrams/](doc/diagrams/)**. (They animate on GitHub.)

## Feature status

Every feature below is a `Capability<T>` β€” `Supported` (with a range) or
`NotSupported` (with a reason). `determineTier` turns the whole passport into a
control tier:

![capability passport β†’ tier](doc/diagrams/capability-passport-tier.svg)

### Architecture

| Feature | Status | Notes |
Expand All @@ -70,6 +76,12 @@ split** β€” in **[doc/diagrams/](doc/diagrams/)**. (They animate on GitHub.)

### Manual controls

Where a camera exposes no sensor controls (the macOS built-in camera, most
browsers), all six controls run through a digital pipeline β€” so the device
still reaches `CameraTier.full`:

![digital manual-control pipeline](doc/diagrams/digital-controls.svg)

| Feature | Status | Notes |
|---|---|---|
| ISO setter (`setIso`) | βœ… | Capability-guarded; throws `CameraFeatureNotSupportedError` if not supported |
Expand All @@ -86,6 +98,11 @@ split** β€” in **[doc/diagrams/](doc/diagrams/)**. (They animate on GitHub.)

### Visual aids

One preview frame is dispatched to the Metal GPU when available or the SIMD CPU
core otherwise β€” both produce byte-identical overlays:

![visual-aids pipeline](doc/diagrams/visual-aids-pipeline.svg)

| Feature | Status | Notes |
|---|---|---|
| Sobel focus peaking (C core) | βœ… | `camera_pro_compute_focus_peaking` |
Expand All @@ -103,6 +120,15 @@ split** β€” in **[doc/diagrams/](doc/diagrams/)**. (They animate on GitHub.)

### Capture

One frame, three encoders β€” PNG, a dependency-free linear-DNG writer (with
EXIF), and video:

![capture paths](doc/diagrams/capture-paths.svg)

Burst and exposure bracketing run through the same capture path:

![burst and EV bracket](doc/diagrams/burst-bracket.svg)

| Feature | Status | Notes |
|---|---|---|
| `capturePhoto()` API surface | βœ… | Method exists, capability-guarded, typed error on failure |
Expand Down Expand Up @@ -226,6 +252,11 @@ Future<void> main() async {

## Verified this build

`native.yml` runs on every push across macOS, Ubuntu, Windows, and web β€” every
βœ… in this README is one of those runs:

![CI matrix](doc/diagrams/ci-matrix.svg)

The following results were produced on macOS arm64 with Flutter 3.44.1 / Dart 3.12.1:

| Test suite | Result |
Expand All @@ -250,6 +281,11 @@ The following results were produced on macOS arm64 with Flutter 3.44.1 / Dart 3.

## Web

A single conditional export keeps `dart:ffi`/`dart:io` off the web build; the
browser gets a pure-Dart `WebCameraBackend` with the C kernels ported to Dart:

![web pure-Dart split](doc/diagrams/web-puredart-split.svg)

The package compiles for the browser: a conditional-import split keeps `dart:ffi`
and `dart:io` off the web tree, `WebCameraBackend` drives the camera via
`navigator.mediaDevices.getUserMedia`, and the visual-aid kernels
Expand Down Expand Up @@ -296,6 +332,17 @@ working exactly as on native.

## Measured performance

The histogram kernel runs on NEON, SSSE3, and scalar paths β€” all bit-exact,
with an honest surprise (clang's auto-vectorized scalar edges the hand-written
NEON on the M1):

![SIMD across architectures](doc/diagrams/simd-arch.svg)

Frames ride a lock-free, cache-aligned ring, so nothing per-frame hits the Dart
garbage collector on the hot path:

![lock-free buffer pool](doc/diagrams/buffer-pool-ring.svg)

`src/tests/bench.c`, 1920Γ—1080 RGBA, median of 31 runs, Apple M1 Pro, `-O2`:

| Kernel | ms/frame | fps |
Expand Down
Loading