diff --git a/RUST.md b/RUST.md index ff0493d..f5dc4a3 100644 --- a/RUST.md +++ b/RUST.md @@ -432,56 +432,75 @@ accepted. worth not doing in a log somebody might paste. And the Android targets were installed for **stable** only; the pinned nightly needs its own, which `iris/rust-toolchain.toml` now declares. -- [ ] **E1 — android-view's Masonry demo on this emulator.** Pass: it - builds with `cargo-ndk` + Gradle, renders on the GPU, and the phone's - own keyboard types into its editor with autocorrect and suggestions. - Note which `wgpu` backend it took and any environment flags needed. - **Part-done 2026-09-04; the keyboard half is untested, so the box - stays open.** +- [x] **E1 — android-view's Masonry demo on this emulator (2026-09-04).** + It builds, renders on the GPU through Vulkan, exposes its + accessibility tree, and **the phone's own keyboard types into its + editor** — but with **no autocorrect and no suggestions**. Ticked + because everything it was meant to establish is established, + including the one gap; that gap is now E2's problem and I2's. - *Builds and renders.* `~/src/android-view` at `bec6c62`, built with + *Build.* `~/src/android-view` at `bec6c62`, x86_64 rather than the + README's arm64 because that is what this emulator is: `cargo ndk -t x86_64 -P 26 -o masonry-app/src/main/jniLibs/ build -p - android-view-masonry-demo` and `./gradlew :masonry-app:assembleDebug`. - The demo draws: its text field and "Add task" button appear, laid out - correctly. Note the demo's README says `arm64-v8a`; this emulator is - x86_64. **`libmain.so` is 181 MB in debug and 11 MB in release**, - which is the single loudest number about Vello's dependency graph. + android-view-masonry-demo --release`, then + `./gradlew :masonry-app:assembleDebug`. **`libmain.so` is 181 MB in + debug and 11 MB in release** — the loudest single number about + Vello's dependency graph, and the reason the release build matters + for more than speed. - *Accessibility works, which E2's condition 6 depends on.* `ui-trace` - reads Masonry's AccessKit tree: "Add task" comes through as a named - `Button` and the editor as an `EditText` node. So the bench rig's - tap-by-name would work against a Masonry screen — for controls that - carry a name. The demo's editor does not, so a coordinate was needed - for it, which is a demo omission rather than a framework one. + *Renderer.* wgpu takes **Vulkan**, and the emulator log confirms it + from the other side: `Created VkDevice ... for application:'wgpu'`. + Two things were needed. The emulator must be given Vulkan at all — + `-feature Vulkan` with `VK_DRIVER_FILES` pointing at the SDK's + `vk_swiftshader_icd.json`, **plus `-no-snapshot-load`**, which is the + piece this file had flagged as untested: without a cold boot the + guest keeps the snapshot's old GPU config and `cmd gpu vkjson` + reports zero devices however the host is configured. And the native + library must be **release**: a debug build calls + `SetDebugUtilsObjectNameEXT` to label its image views, and the + emulator's own guest driver (`vulkan.ranchu.so`) segfaults inside it. + On GLES, with no Vulkan available, it instead fails + `Surface::configure` with "Invalid surface" — untriaged, since the + Vulkan path works and Vello wants compute shaders anyway. - *The keyboard was not reached.* Tapping the editor never brought the - IME up (`mInputShown=false` throughout) before the run ended. Nothing - here says android-view's `InputConnection` does not work — only that - it has not been shown to. This is the half of E1 that matters most, - since it is the constraint the whole framework decision turns on, and - it is what to do first when this is picked up. + *Accessibility works*, which E2's condition 6 and every bench script + depend on. `ui-trace` reads Masonry's AccessKit tree: "Add task" + arrives as a named `Button`, the editor as an `EditText` node. So + tap-by-name works against a Masonry screen for any control carrying + a name; the demo's editor carries none, which is the demo's omission + rather than the framework's. - *A crash worth knowing about, seen once.* With an accessibility - client attached the app aborted, and the stack attributes it - precisely: `android_view::view::do_frame` → - `CallbackCtx::finish` → `accesskit_android::event::QueuedEvents::raise` - → `send_completed_event` → `unwrap()` on `Err(JavaException)`. - android-view builds with `panic = "abort"`, so a JNI call that throws - takes the process. It did **not** reproduce: two plain - `ui-trace record` runs afterwards left the app alive, so the trigger - is narrower than "an accessibility client is connected" and is not - yet known. Recorded rather than chased because it is upstream and - one unwrap wide. + *The keyboard: real input yes, suggestions no.* Tapping the editor + opens the actual soft keyboard (`mInputShown=true`, Gboard), and + tapping its keys types into Masonry — "teh" typed key by key, with a + caret. What does **not** appear is Gboard's suggestion strip. The + control is what makes that a finding rather than an impression: the + **same three key taps in the Settings app's search field, on the same + device in the same session, produce "teh | the | yeh"**. So the strip + works here and android-view's editor is not asking for it — most + likely the `EditorInfo` its `InputConnection` reports. That matches + Robrix's report that the Android keyboard is not yet "full", and it + is the single most important thing to fix or fund upstream, because + composition, autocorrect and suggestions are exactly what the + composer in this app needs and exactly what `winit` cannot do at all. + + *One crash seen once and not reproduced.* With an accessibility + client attached the app aborted, stack: + `android_view::view::do_frame` → `CallbackCtx::finish` → + `accesskit_android::event::QueuedEvents::raise` → + `send_completed_event` → `unwrap()` on `Err(JavaException)`. + android-view builds `panic = "abort"`, so a JNI call that throws + takes the process. Two later `ui-trace record` runs left the app + alive, so the trigger is narrower than "a client is attached". + + *A rig trap that cost a wrong conclusion.* Several bounded runs were + given `sleep N; emu down` watchdogs, and one armed for an earlier + experiment fired in the middle of a later one — the app vanished, adb + hung, and it read exactly like the Vulkan path crashing. It was not. + A watchdog must be scoped to the process it guards (`kill $pid`, with + the pid captured at launch) rather than to whatever AVD is running + when it wakes, and only one should be armed at a time. - *Two changes were made at once and cannot be separated.* The first - launches crashed in `Surface::configure` ("Invalid surface") on GLES, - then, with Vulkan enabled, segfaulted inside the emulator's own - driver (`vulkan.ranchu.so`, `SetDebugUtilsObjectNameEXT`) while wgpu - labelled an image view — a debug-build-only call. It then ran after - **both** a switch to a release native library and a switch to a - software-rendered emulator. Which of the two fixed it is unmeasured; - whoever picks this up should vary one at a time rather than inherit - the assumption. - [ ] **E2 — a transcript in Masonry.** One screen: open a sandbox session, page 800 events into `VirtualScroll` bottom-anchored, draw markdown from `pulldown-cmark` into Parley rich text with links and code @@ -683,8 +702,21 @@ re-derived: ### Vulkan in the emulator (measured 2026-09-04) -A `wgpu` app in this emulator was going to get GLES only, because host -Vulkan is switched off in `emulator-tools`. Retried today on Mesa +**Settled 2026-09-04: the guest gets Vulkan from SwiftShader, and the +missing step was a cold boot.** `-feature Vulkan` plus +`VK_DRIVER_FILES=$HOME/Android/Sdk/emulator/lib64/vulkan/vk_swiftshader_icd.json` +gets the *host* side to select SwiftShader, but the guest keeps reporting +zero devices until `-no-snapshot-load` is added, because it boots from a +snapshot saved under the previous GPU config — `-no-snapshot-save` is +worth adding too, so the Vulkan-configured snapshot does not then break +the next ordinary boot. With that, `cmd gpu vkjson` reports SwiftShader +Subzero and wgpu takes its Vulkan path (E1). `EMU_GPU=software` in +`emulator-tools` gets the same guest Vulkan with no GPU use at all, for +work where the emulator's frame rate is not what is being measured. + +The rest of this section stands as the record of why host Vulkan is not +available. A `wgpu` app in this emulator was going to get GLES only, +because host Vulkan is switched off in `emulator-tools`. Retried on Mesa 26.1.7: **Venus still fails the same way** — gfxstream picks `externalMemoryMode: OpaqueFd`, probes `VK_FORMAT_R8G8B8A8_UNORM` for an exportable colour buffer, and Venus says the format is unsupported @@ -717,8 +749,11 @@ booted, then the emulator died right after loading the `default_boot` snapshot with nothing in the log; a snapshot saved under a different Vulkan device is the suspect, and `-no-snapshot-load` is the untested next step. SwiftShader is the one that works today. -Making this an `emu` option belongs in `emulator-tools` and is a shared -tooling change, so it goes through the other sessions first. +`EMU_GPU=software` is now in `emulator-tools` (agreed with the ai-app +session and with Iris, default unchanged, since `-gpu host` was measured +and the Compose scroll benchmarks depend on it). The cold-boot flags are +not a knob there: that wants snapshot invalidation as well, which is a +bigger design question in shared tooling. ## Things a Rust app changes elsewhere