Skip to content

fix/ios camera memory - #284

Merged
Monster0506 merged 2 commits into
mainfrom
fix/ios-camera-memory
Sep 20, 2026
Merged

Monster0506 merged 2 commits into
mainfrom
fix/ios-camera-memory

Conversation

@AndrewRoddy

Copy link
Copy Markdown
Collaborator
  • Cut the segmentation memory peak so iOS stops killing the tab
  • Say why the camera is unavailable, and how to get it back

Tapping an item on an iPhone reloaded the page. Nothing was caught and
nothing was logged, because nothing threw: iOS gives a tab a few hundred
megabytes and kills it outright when it goes over. The tap is where the
encoder runs, so the tap is where the budget ran out.

Four things were spending it before the model ever did any work:

- The ORT bundle was ort.all, which carries WebGPU, WebGL, WebNN and the
  training runtime, and loads the 23 MB JSEP WebAssembly binary whether
  or not the device has a GPU. The plain WASM build is 12 MB. Pick the
  bundle from navigator.gpu, and skip the doomed WebGPU session attempt
  where the runtime was never loaded.

- numThreads was set to min(4, cores) unconditionally. Threaded WASM runs
  on SharedArrayBuffer, which needs COOP/COEP headers this app does not
  send, so those threads could never exist. Ask for one.

- Both models were loaded and instantiated in parallel, holding two ONNX
  buffers and the runtime's copy of each at once. Sequential, releasing
  each buffer before reaching for the next, halves that high water mark.
  The download is the slow part and it is cached after the first run.

- Caching a downloaded model sliced it first, so a 40 MB encoder existed
  three times over: ours, the slice, and the Response body. Response
  copies what it is handed, so the slice bought nothing.

The scratch canvas in prepareTensor is also given back explicitly now
rather than waiting for a collection Safari is in no hurry to run.
Two failures looked identical from the viewfinder: a plain http:// origin,
where Safari withholds navigator.mediaDevices entirely and there is no
prompt to show, and a refusal, which Safari remembers per site and then
repeats without ever prompting again. Both left the same inactive stage
and a button that did nothing, and tapping it again could not help in
either case.

The browser is now asked what it supports before anything is offered, so
an insecure origin says so instead of presenting a dead button. And
openCamera reports its outcome rather than throwing it, because interop
flattens a thrown error down to its message and the DOMException name is
the part that separates a refusal the person can undo from a device that
simply has no camera. A refusal now carries the steps back through
Safari's own settings.

Flipping the camera tears the old stream down before asking for the new
one, so it reports the same way - a refusal there used to leave a blank
stage with nothing said.
@Monster0506
Monster0506 merged commit 017db07 into main Sep 20, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants