Commit Graph

5 Commits

Author SHA1 Message Date
84c6a4170d Fix activity-recreation crash: render-thread GPU uploads + per-world lifecycle
The swipe-up-dismiss + relaunch bug (process survives, activity
re-creates) crashed or left a sparse grid. Root cause chain, fully
documented in docs/BUGS/recreation-stale-textures.md:

- Each android_main (per activity instance) is a fresh Slint world with
  a fresh wgpu device (i-slint-core context is thread-local); the old
  world zombie-parks (Slint 1.18 android backend never delivers
  TerminateWindow/Destroy to it).
- Worker-side GPU uploads + a process-global loader let textures cross
  world/device boundaries: a texture destroyed with its device left a
  stale handle in the registry (wgpu-core assert in transition_resources
  on the render thread) — either killing the process, or, with the
  interim catch_unwind band-aid, keeping a poisoned world alive and
  corrupting the VISIBLE world's imports (the sparse grid). A/B against
  pristine Slint confirmed the mechanism (pristine: 1 self-killing panic
  per recreation + full grid).

Fix:
- gputex rewrite: workers deliver plain RGBA8; the UI drain tick
  uploads to the device captured from the rendering notifier
  (Slint's borrowed-resource contract). Staleness impossible by
  construction. Keepalive thread removed.
- Per-world lifecycle: CURRENT_WORLD gate silences zombie ticks;
  re-init invalidates the dying device + swaps the engine; render
  notifier handles RenderingTeardown/RenderingSetup (in-place cell
  clear — never set_vec mid-render, which desyncs the for-loop).
- Vendor patch surface reduced to the single final-flush hunk
  (catch_unwind guard reverted to pristine).
2026-10-28 20:54:04 -04:00
9c0525e93f Jank fix: thread priorities — raise vsync waker, demote decoders
Slint's android-activity backend wakes the main loop from a dedicated
"slint vsync" Choreographer thread while any animation is active
(i-slint-backend-android-activity/vsync.rs). Android schedules that
thread at nice +10 (lowest on device), while our 4 turbojpeg workers
inherited the UI thread's nice -10. Under CPU bursts the +10 waker
starves and the main loop's next wakeup lands 3-4 frames late: 25-33 ms
of pure wake latency at 120 Hz, with zero cost in our tick (d=7-34 us) —
exactly the phone stall signature (measured: 28-39 ms gaps, catch-up
events).

- prio module: setpriority FFI (self + by-tid), raise_slint_vsync()
- thumb workers + dispatcher: nice +2 at spawn (ahead of background
  apps, behind the UI's -10)
- android_main: prio-fix thread raises "slint vsync" to nice 0 with a
  readback log
- verified on emulator: thumb-* hold nice 2, slint vsync holds 0 while
  foreground (Android re-nices backgrounded processes — expected)
- emulator scroll cadence unchanged (llvmpipe rasterization ceiling,
  not a priority issue) — phone is the acceptance target, A/B test
  planned for when it is back online

Also: drop unused android_logger dependency (nblog replaced it).
2026-10-28 00:53:30 -04:00
572409b702 M2: thumbnail engine — turbojpeg DCT-shrink decode, worker pool, disk cache
- images.rs: libjpeg-turbo 1/2..1/8 shrink decode (48MP @1/8 ~2.3MB peak),
  all 8 EXIF orientations, imageops::resize final fit, PNG via image crate,
  q85 re-encode for the disk cache
- thumb.rs: dispatcher + N=cores/2 workers (2..8), cache
  thumbs/{sha1(path|mtime|size|target)}.jpg (target in key: list 64px and
  grid 500px coexist), atomic rename, generation-based cancellation,
  per-worker sqlite set_thumb, 256-job cadence logs
- lib.rs: AppState OnceLock, 10Hz drain timer (leaked !Send Timer),
  scroll prefetch (50-row margin), do_prefetch gating for scan batches
- main.slint/db.rs: rows carry images; list_entries + set_thumb
- build.sh: NDK CMake toolchain env for turbojpeg-sys (ANDROID_JAR vs
  ANDROID_PLATFORM conflict), nasm on PATH, ADB_SERIAL, debug-aarch64
- HANDOFF: M2 done + acceptance data; HEIC deferred (0 HEIC on device);
  transient first-launch black screen parked as §10.7 (unreproducible)

Verified: 12 unit tests + 5k engine test; Pixel 9 Pro 8577 photos —
cold scan ~5s streaming, warm relaunch instant, thumbnails in every row,
~100% cache hits on relaunch; release aarch64 APK 9.8 MB.
2026-10-27 16:32:12 -04:00
e1982eade4 M1: metadata scan + sqlite DB + placeholder list
- scan.rs: recursive walk of Pictures/DCIM (GALLERY_SCAN_DIRS override),
  image-ext detection, mtime/size capture, no symlink-dir following
- db.rs: rusqlite(bundled) store; incremental apply (insert/update/delete)
  keyed on path with mtime/size change detection; derived columns reset on
  change; Android DB path in Android/data/<pkg>/files (EXTERNAL_DATA_DIR is
  unset in this NativeActivity setup)
- lib.rs: start_scan() background thread -> invoke_from_event_loop ->
  VecModel + status line; called from desktop and Android entry points
- main.slint: ListView of paths (M1), status line with scan stats
- main.rs: fix desktop bin for 1.18.1 (no slint::Result; ComponentHandle)
- build.sh: export NDK clang CC_/CXX_/AR_ per target (bundled sqlite)
- tests: 5k-file scan < 2s, incremental apply, roundtrip

Verified on emulator: 5002 files in 153-226 ms; relaunch 0+ 0~ 0-;
touch -> 1~, delete -> 1-.
2026-10-27 13:28:33 -04:00
4863e42bae M0: Slint gallery scaffold + development hand-off
- Slint 1.18.1 (backend-android-activity-06), cargo-apk2 packaging
- Manifest permissions: READ_MEDIA_IMAGES, READ_EXTERNAL_STORAGE (maxSdk 32),
  MANAGE_EXTERNAL_STORAGE
- android_main with permission-aware init_with_event_listener hook and
  AndroidApp clone stash for JNI (storage flow, later BLE/etc.)
- scripts/build.sh: release/debug x86_64 + aarch64, sign, adb install
- HANDOFF.md: full dev plan (architecture, thumbnail pipeline, milestones,
  gotchas, perf targets) from the Slint/eframe evaluation
- Verified: builds, installs, runs on pad_avd emulator (API 35)
2026-10-27 12:22:59 -04:00