docs/RUST.md: the emulator crash loop was the missing GLES fallback, with the panic-hook note

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
irisandClaude Fable 5.1 committed 2026-09-07 21:50:06 -04:00
1 parent 85869d02f8
commit 50e69995b6
1 file changed
+60 -5
+60 -5
View File
@@ -716,11 +716,66 @@ closes it.
devlog agent shrank the label type 18 -> 13 to make room (UI_RULES: devlog agent shrank the label type 18 -> 13 to make room (UI_RULES:
never shrink text to fit). Put the controls in two rows or make the never shrink text to fit). Put the controls in two rows or make the
header wrap; restore the size. Sonnet. header wrap; restore the size. Sonnet.
- [ ] Bench app crash-loops on this checkout's emulator once - [x] **Bench app crash-loops on this checkout's emulator (done
backgrounded (seen by the devlog agent, pre-existing; the phone's 2026-09-07).** Not the surface lifecycle at all, and not "once
resume works since ba2afba). Reproduce on the emulator's GLES path, backgrounded" -- a build with the **default features** (no
read the crash from the devlog/`adb logcat`, fix. Opus if it is in `force-gles`) never got a first frame. `AndroidRenderer::new`
the surface lifecycle. (`iris/src/android/render.rs`) asked wgpu for `Backends::PRIMARY`,
which does not contain `GL`, and this emulator advertises a Vulkan ICD
with no adapter behind it: `RequestAdapterError::NotFound {
active_backends: VULKAN, no_adapter_backends: VULKAN,
supported_backends: VULKAN | GL }`, `.expect`ed, so SIGABRT, so the
launcher restarts it -- the loop. A `force-gles` build was never
affected, which is why the crash looked like it belonged to whatever
else was going on. **Root cause: iris refused a device whose only
usable adapter is a GLES one.**
**Fix, two halves.** (1) `AndroidRenderer::new` now probes for a
`PRIMARY` adapter with an instance that never touches the window and
rebuilds the instance on `Backends::GL` when there is none. The probe
is surface-free deliberately: **an Android window can be connected to
one graphics API only**, so a single instance carrying both backends
fails differently and worse -- Vulkan's
`vkCreateAndroidSurfaceKHR` claims the window in `create_surface` and
the GLES surface built from the same window then reports `In
Surface::configure / Invalid surface`, aborting one frame later in
`Surface::get_current_texture_view` ("Surface is not configured for
presentation"). That was measured here on the way to the fix, not
reasoned about. Vulkan still wins wherever it has an adapter, so
nothing changes on the phone. (2) The surface, adapter and device
requests all report through the `Result<Self, String>` this function
already returns, instead of two of the three panicking -- one rule for
the set, and `surface_changed` already puts that string on screen and
in the log ring.
**Evidence**, this checkout's emulator (API 36, x86_64, debug):
before, default features aborted on first launch with `Abort message:
'Could not get adapter!: NotFound {...}'`; after, `iris renderer: no
Backends(VULKAN | METAL | DX12 | BROWSER_WEBGPU) adapter on this
device, falling back to GLES` then `new renderer built (Gl)` and
frames. Then the cases the fix had no reason to touch, clean on both
the default build and a `force-gles` one: two background/return
cycles, rotate to landscape and back (`already_live=true`, the reuse
branch), a background/return after the rotation, and cold starts.
**Vulkan could not be exercised here** -- the probe's own answer is
that this emulator has no Vulkan adapter, which is the whole defect;
Vulkan remains only testable on Iris's phone.
**Also landed with it, and worth more than the fix**: a panic hook in
`iris/android-app/src/app_log.rs`. Checked first, rather than assumed:
under `panic = "abort"` a panic's message reaches the tombstone's
`Abort message` and **nothing else** -- not `log`, so not the ring, so
not Dev Updater's Runtime tab, which is the only surface Iris has on a
phone with no `adb`. The hook writes the message and its location at
`error` level, and -- because the ring is memory only and the process
is about to die -- also to `last-panic.txt` in the app's private
directory, which `set_crash_dir` (called from `nativeSetFilesDir`)
replays into the ring at `error` level on the next start and deletes.
So a crash loop now explains itself in the Runtime tab of the run
that is still up. Verified on the emulator by building the *unfixed*
renderer with the hook: `iris panic at .../render.rs:140:14: Could not
get adapter!: NotFound {...}` in the ring on the run that died, and
`iris app log: the previous run died -- ...` on the next one.
- [ ] Masks with a shape -- docs/LAYOUT.md "Masks with a shape (decided - [ ] Masks with a shape -- docs/LAYOUT.md "Masks with a shape (decided
2026-09-07)". A mask references a primitive already drawn 2026-09-07)". A mask references a primitive already drawn
(rect SDF, texture or glyph alpha), chained and multiplied; `.masked()` (rect SDF, texture or glyph alpha), chained and multiplied; `.masked()`