iris: a device change re-uploads its textures, and a mark is one texture per shape
The bench APK panicked on frame 1 on the emulator:
iris panic at iris/core/src/render/texture.rs:461:22:
texture slot 89 is not a live standalone image: None
widget::mark called Textures::add per widget, so a folded card per tool
call meant a standalone image, a bind group and a draw call each --
hundreds of copies of three pictures. Textures::reset, which the Android
surface-rebuild path calls for a genuinely new renderer, then threw the
slot numbering away with the pixels, leaving every one of those live
handles naming a slot nothing recognised. Its doc had said the only
standalone image in the workspace was tabs-ui's, "confirmed by grep" --
true when written, false the moment mark existed.
Textures::reupload replaces reset: queue every slot for upload again in
slot order, empty slots included, so the new device gets the same slot
numbering and a handle a widget has been holding still names its own
texture. The glyph atlas is no longer cleared on that path either, so an
app switch stops re-rasterising every glyph on screen.
Textures::shared(key, make) is one texture per description, keyed by a
SharedTextureKey the caller packs exactly rather than hashes. mark keys on
direction and colour: three mark textures for the screen, not one a card.
And the devlog can finally show a panic. After a crash, Dev Updater's
query starts the app process for the provider alone, so no activity ran,
so set_crash_dir never replayed the panic hook's file -- the Runtime tab
held one line, the provider announcing itself. DevLogProvider.nativeReady
takes the files directory and does the replay from onCreate; the hook also
saves the dying run's last 80 lines beside the panic, read through a new
non-blocking LogRing::try_tail_text so a panic holding the ring's lock
cannot deadlock the hook.
Verified on this checkout's emulator: opens clean, survives 33 full-screen
scrolls back through the fixture, image_bind_group_creates_prev=1; a real
panic replays into the next launch, and a hand-written last-panic.txt
replays in a process started by a provider query with no activity.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
c8785b6091
commit
341b7a5922
9 files changed
+550
-57
No files matched your search
@@ -8064,3 +8064,95 @@ states the refresh it ran at.
|
||||
**Not yet confirmed on the phone** -- that needs a build in her hands,
|
||||
and the emulator cannot answer it (it is a 60Hz GLES rig, so the defect
|
||||
is invisible there by construction).
|
||||
|
||||
## Iris's phone report, 2026-09-08 evening: "crashes as soon as I scroll up" and a devlog that showed one line
|
||||
|
||||
Her two sentences: the bench crashes shortly after she scrolls back from
|
||||
where it opens, and Dev Updater's Runtime tab held only `iris devlog:
|
||||
serving this app's log at content://dev.iris.android.demo.bench.devlog`.
|
||||
|
||||
### The devlog could only ever show the run that was still up
|
||||
|
||||
**Fixed.** After a crash, Dev Updater's query starts the app process **for
|
||||
the provider alone**: no activity runs, so
|
||||
`MainActivity.nativeSetFilesDir` never fired, so `app_log::set_crash_dir`
|
||||
never replayed the line the panic hook had written to
|
||||
`files/last-panic.txt`. The one line she saw is the provider announcing
|
||||
itself in a process that had just been started to answer her.
|
||||
|
||||
`DevLogProvider.nativeReady` takes the files directory now and calls
|
||||
`set_crash_dir` from `onCreate`; whichever of the provider and the
|
||||
activity runs first does the replay, and the file is deleted before it is
|
||||
replayed, so a replay that itself panicked cannot make a loop. The hook
|
||||
also saves the dying run's last 80 log lines beside the panic (a new
|
||||
non-blocking `LogRing::try_tail_text`, so a panic raised while the ring's
|
||||
lock was held cannot deadlock the hook), replayed into the new ring ahead
|
||||
of the panic line under the target `previous_run`.
|
||||
|
||||
Verified on this checkout's emulator both ways: a real panic replayed into
|
||||
the next launch, and a hand-written `files/last-panic.txt` replayed by a
|
||||
process started by `content query` alone with **no activity** (the query
|
||||
is refused for the `shell` uid, which does not hold
|
||||
`dev.updater.permission.READ_DEVLOG` -- the provider's `onCreate` still
|
||||
runs, which is the half under test).
|
||||
|
||||
### The crash: one texture per mark, and a device change that forgot them
|
||||
|
||||
The bench APK **panicked on frame 1** on this checkout's emulator, which
|
||||
is where this was found rather than by reasoning from her report:
|
||||
|
||||
iris panic at iris/core/src/render/texture.rs:461:22:
|
||||
texture slot 89 is not a live standalone image: None
|
||||
|
||||
`widget::mark` (added the same day) called `Textures::add` **per widget**,
|
||||
so a folded card per tool call meant a standalone image, a bind group and
|
||||
a draw call each -- slot 89 was one of hundreds of copies of three
|
||||
pictures. `Textures::reset`, which the Android surface-rebuild path calls
|
||||
when it builds a genuinely new renderer, then threw the slot *numbering*
|
||||
away along with the pixels, leaving every one of those live handles naming
|
||||
a slot nothing recognised. Its own doc had said the only standalone image
|
||||
in the workspace was `tabs-ui`'s, "confirmed by grep" -- true when it was
|
||||
written, false the moment `mark` existed. **A rule stated on one member of
|
||||
a set** (CODE_RULES): the grep was the invariant, and nothing re-ran it.
|
||||
|
||||
Two fixes, both in `iris-core`:
|
||||
|
||||
- **`Textures::reupload` replaces `reset`**: queue every slot for upload
|
||||
again in slot order, empty slots included (they cross as `PushFree`, so
|
||||
the indices after a hole still land where they were). This side holds
|
||||
the images, so the new device gets the same slot numbering and every
|
||||
handle a widget is holding still names its own texture. The glyph atlas
|
||||
is no longer cleared on that path either -- its pages are slots here, so
|
||||
they come back with everything else, and an app switch stops costing a
|
||||
re-rasterisation of every glyph on screen.
|
||||
- **`Textures::shared(key, make)`**: one texture per description. `mark`
|
||||
keys on direction and colour, packed exactly into a
|
||||
`SharedTextureKey { owner, id }` rather than hashed, so the screen has
|
||||
three mark textures rather than one per card and the rasterising is paid
|
||||
once. The map holds its own reference, so a shared slot is never freed
|
||||
and never recycled under a widget still drawing it.
|
||||
|
||||
After the fix the emulator opens clean and survives 33 full-screen scroll
|
||||
gestures back through the fixture, with
|
||||
`image_bind_group_creates_prev=1`.
|
||||
|
||||
**Whether this is the crash on *her* phone is not yet confirmed** -- her
|
||||
build is release, its startup does not take the GLES fallback that made
|
||||
the emulator rebuild its renderer, and the panic she saw was never
|
||||
recorded anywhere. It is the crash this code had; the devlog fix above is
|
||||
what will say whether it was hers. Ask for the Runtime tab after the next
|
||||
bench APK.
|
||||
|
||||
### Open: why `mark` exists at all (Iris asked, 2026-09-08)
|
||||
|
||||
Her question, mid-fix: "why does mark exist? The font should be working if
|
||||
it's working for compose and nerd fonts are bundled." The Compose app
|
||||
draws its chevron from **its own committed Nerd Fonts subset**
|
||||
(`app/build-icon-font.sh`, `NerdIcons.kt`); iris bundles no font at all
|
||||
since 2026-09-07, and `tool.rs` was using bare geometric codepoints
|
||||
(U+25B8/25BE/25B4) out of whatever system face resolved -- which her phone
|
||||
had none for. So the two apps were never doing the same thing, and the
|
||||
2026-09-07 note that "iris had no equivalent icon font to keep" is what
|
||||
left the gap. The alternative to `mark` is to bundle the same ~100-glyph
|
||||
subset in iris and take icons from it, which would serve every future icon
|
||||
rather than one triangle. Not done: it is hers to choose.
|
||||
Reference in new issue
Block a user