Slint-on-Mali was conclusively janky at its base level (sltest: 0.33-0.83% slot drops on a scene with no app logic); egui on the same phone measured 3-7x cleaner (egtest: 0.12%, same referee/scene). Architecture (see HANDOFF §8.11-8.12): - winit 0.30 ApplicationHandler on android-activity 0.6, raw EGL (ES3), egui_glow::EguiGlow. winit 0.30 never delivers RedrawRequested on Android → the frame driver is app-owned: World::tick runs every loop iteration from about_to_wait (liveness), render when dirty or animating, park ~8 ms (one vblank) at rest. - Virtualized grid painter (3 cols, visible rows ±4), GPU-resident textures, turbojpeg worker pool decoding off-thread. - CRITICAL pixel-pipeline fix: RGB8→Vec<Color32> conversion happens on the WORKER (egui 0.31's from_rgba_unmultiplied is O(n) per-pixel, 8-60 ms/2 MB on the UI thread → 9.57% drops + phone OOM crash). UI thread only MOVES the vector into ColorImage. - Fling: per-event EMA velocity (frame-based dies at slow touch sampling), clamp 14000 px/s; decay exp(-7.42 dt). - Painter::image uv is NORMALIZED (0..1) — a screen-space uv made every cell a solid rectangle (the emulator's solid-color test images hid it). - Memory caps for a personal phone: full cache 6 entries / 16 MP. Verified on emulator: grid, scroll, fling, viewer, back-key. Phone deploy: thumbnails render, 8580 files. Pending: user finger test + fr_capture phone run (per-pixel fix expected to cut render cost 18.8 ms → <8.3 ms). Deletes: vendor/ (instrumented Slint tree), shim/, build.rs, gputex, vkshim, baseline60, main.slint — the Slint zero-jank campaign is concluded in docs/BUGS/.
107 lines
3.8 KiB
TOML
107 lines
3.8 KiB
TOML
[package]
|
|
name = "gallery"
|
|
version = "0.1.0"
|
|
edition = "2021"
|
|
|
|
# Android: cdylib so the NDK toolchain's -soname flag (libgallery.so) does
|
|
# not conflict with the lib crate's (libgallery.rlib). The NativeActivity
|
|
# loader finds the .so; android_main is the entry point (src/lib.rs).
|
|
[lib]
|
|
name = "gallery"
|
|
crate-type = ["cdylib", "lib"]
|
|
|
|
# The desktop entry (cargo run).
|
|
[[bin]]
|
|
name = "gallery"
|
|
path = "src/main.rs"
|
|
|
|
[dependencies]
|
|
# UI: egui + egui_glow (OpenGL ES 3.0 on Android via EGL) + egui-winit.
|
|
# egtest proved this stack at 120 Hz on the phone: 0.12% slot drops
|
|
# (vs 0.33-0.83% for every Slint variant, same referee, same scene).
|
|
# See docs/BUGS/scroll-jank-120hz.md §egui and harnesses/egtest.
|
|
egui = "0.31"
|
|
egui_glow = { version = "0.31", features = ["winit"] }
|
|
egui-winit = "0.31"
|
|
winit = { version = "0.30", features = ["android-native-activity"] }
|
|
android-activity = "0.6"
|
|
glow = "0.16"
|
|
libc = "0.2"
|
|
# EGL context + surface for egui_glow (Android: eglCreateWindowSurface over
|
|
# the native_window). egui_glow takes the API as a trait object — the
|
|
# context must live (in `World`) until the painter drops.
|
|
egl = "0.2"
|
|
|
|
# App layer (renderer-agnostic; carried over 1:1 from the Slint build):
|
|
# rusqlite with `bundled` (vendor libsqlite3.a — no system library).
|
|
# Build needs the NDK clang (cc crate); scripts/build.sh exports it.
|
|
rusqlite = { version = "0.41.0", features = ["bundled"] }
|
|
|
|
# M2: libjpeg-turbo for thumbnails + viewer. The crate compiles libjpeg-
|
|
# turbo from source (CMake) — needs the NDK CMake toolchain on Android,
|
|
# nasm on x86_64. See docs/THUMBS.md + HANDOFF.md §10.
|
|
turbojpeg = { version = "1.5.1", features = ["cmake"] }
|
|
# M2: EXIF orientation (JPGs) for decode-time rotation.
|
|
kamadak-exif = "0.6.1"
|
|
# M2 (PNGs only): the `image` crate's PNG decoder for non-JPG files.
|
|
image = { version = "0.25.10", default-features = false, features = ["png"] }
|
|
# M3: SHA1 of (path, mtime, size) as the thumbnail cache key.
|
|
sha1 = "0.11.0"
|
|
log = "0.4"
|
|
parking_lot = "0.12"
|
|
|
|
[profile.release]
|
|
# Thin LTO keeps builds minutes (not tens of minutes) while keeping release
|
|
# quality for the hot paths; the decode workers are C (libjpeg-turbo
|
|
# SIMD), so the Rust side is not the decode bottleneck.
|
|
lto = "thin"
|
|
codegen-units = 1
|
|
opt-level = 3
|
|
|
|
[profile.release.package."*"]
|
|
opt-level = 2
|
|
|
|
[features]
|
|
# FR frame-gap lines (docs/BUGS tooling): the fr_capture.py referee.
|
|
framelog = []
|
|
|
|
[package.metadata.android]
|
|
package = "wow.gmp.gallery"
|
|
build_targets = ["x86_64-linux-android", "aarch64-linux-android"]
|
|
|
|
[package.metadata.android.sdk]
|
|
min_sdk_version = 26
|
|
target_sdk_version = 35
|
|
|
|
[package.metadata.android.application]
|
|
label = "Gallery"
|
|
# Not debuggable: a debuggable app shows the system 16 KB compatibility
|
|
# dialog on EVERY cold launch — that dialog is its own activity, it pauses
|
|
# us, and its lifecycle was a source of lost surfaces / black windows.
|
|
debuggable = false
|
|
|
|
[[package.metadata.android.application.activity]]
|
|
name = "android.app.NativeActivity"
|
|
config_changes = "orientation|screenSize|screenLayout|smallestScreenSize|keyboard|keyboardHidden|navigation|uiMode|touchscreen"
|
|
|
|
[[package.metadata.android.application.activity.meta_data]]
|
|
name = "android.app.lib_name"
|
|
value = "gallery"
|
|
|
|
[[package.metadata.android.application.activity.intent_filter]]
|
|
actions = ["android.intent.action.MAIN"]
|
|
categories = ["android.intent.category.LAUNCHER"]
|
|
|
|
# --- Permissions (runtime flow: HANDOFF.md §7) ---
|
|
[[package.metadata.android.uses_permission]]
|
|
name = "android.permission.READ_MEDIA_IMAGES"
|
|
|
|
[[package.metadata.android.uses_permission]]
|
|
name = "android.permission.READ_EXTERNAL_STORAGE"
|
|
max_sdk_version = 32
|
|
|
|
# "All files access" — same special-access pattern as passgo; needed to
|
|
# browse arbitrary directories outside the media collection.
|
|
[[package.metadata.android.uses_permission]]
|
|
name = "android.permission.MANAGE_EXTERNAL_STORAGE"
|