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/.
91 lines
3.9 KiB
Bash
Executable File
91 lines
3.9 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Build the gallery Android APK (and optionally install it).
|
|
#
|
|
# ./scripts/build.sh # release x86_64 (emulator) + install
|
|
# ./scripts/build.sh aarch64 # release aarch64 (real device) + install
|
|
# ./scripts/build.sh debug # debug x86_64 + install (faster builds)
|
|
# ./scripts/build.sh <arch> no-install
|
|
#
|
|
# framelog (FR frame-gap lines for tools/fr_capture.py):
|
|
# ./scripts/build.sh aarch64 framelog # or append `framelog`
|
|
set -euo pipefail
|
|
cd "$(dirname "$0")/.."
|
|
|
|
export ANDROID_HOME=$HOME/android-sdk
|
|
export ANDROID_NDK_ROOT=$HOME/android-sdk/ndk/27.0.12077973
|
|
# ~/.local/bin: nasm (host build of libjpeg-turbo SIMD; aarch64 needs no nasm).
|
|
export PATH="$HOME/.local/bin:$HOME/.cargo/bin:$ANDROID_HOME/platform-tools:$PATH"
|
|
|
|
# turbojpeg (M2): build the vendored libjpeg-turbo with CMake, statically
|
|
# linked into the app (no extra .so in the APK). The NDK CMake toolchain +
|
|
# ANDROID_* vars are picked up by the `cmake` crate.
|
|
if [ -n "$ANDROID_NDK_ROOT" ]; then
|
|
export CMAKE_TOOLCHAIN_FILE=$ANDROID_NDK_ROOT/build/cmake/android.toolchain.cmake
|
|
export ANDROID_PLATFORM=android-26
|
|
export ANDROID_STL=c++_static
|
|
export TURBOJPEG_STATIC=1
|
|
fi
|
|
|
|
# C/C++ cross-compilers for bundled native deps (libsqlite3-sys via
|
|
# rusqlite, libjpeg-turbo via turbojpeg). The `cc`/`cmake` crates pick
|
|
# these up per target triple (min sdk 26).
|
|
NDK_BIN=$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin
|
|
# CMake target ABI (x86_64 default; overridden below for aarch64).
|
|
export ANDROID_ABI=x86_64
|
|
# The cc crate picks these up per target triple (min sdk 26).
|
|
export CC_x86_64_linux_android=$NDK_BIN/x86_64-linux-android26-clang
|
|
export CXX_x86_64_linux_android=$NDK_BIN/x86_64-linux-android26-clang++
|
|
export AR_x86_64_linux_android=$NDK_BIN/llvm-ar
|
|
export CC_aarch64_linux_android=$NDK_BIN/aarch64-linux-android26-clang
|
|
export CXX_aarch64_linux_android=$NDK_BIN/aarch64-linux-android26-clang++
|
|
export AR_aarch64_linux_android=$NDK_BIN/llvm-ar
|
|
# The cmake crate (turbojpeg-sys → libjpeg-turbo) only honors the plain
|
|
# CC/CXX: NDK 27's CMake toolchain defaults to `x86_64-linux-android-clang`
|
|
# (no API suffix), which does not exist, so the compiler must be given.
|
|
# Set AFTER the target is known (below).
|
|
# Debug-keystore signing is fine for personal use / Play internal testing.
|
|
export CARGO_APK_RELEASE_KEYSTORE=$HOME/.android/debug.keystore
|
|
export CARGO_APK_RELEASE_KEYSTORE_PASSWORD=android
|
|
|
|
arg1=${1:-x86_64}
|
|
arg2=${2:-install}
|
|
|
|
profile=--release
|
|
features=""
|
|
case $arg1 in
|
|
debug) target=x86_64-linux-android; profile="" ;;
|
|
debug-aarch64) target=aarch64-linux-android; profile=""; export ANDROID_ABI=arm64-v8a ;;
|
|
x86_64) target=x86_64-linux-android ;;
|
|
aarch64) target=aarch64-linux-android; export ANDROID_ABI=arm64-v8a ;;
|
|
*) echo "unknown arch: $arg1" >&2; exit 1 ;;
|
|
esac
|
|
|
|
# `framelog` as the second arg: FR lines for tools/fr_capture.py.
|
|
if [ "$arg2" = framelog ]; then
|
|
features="framelog"
|
|
arg2=install
|
|
fi
|
|
|
|
# Plain CC/CXX for the cmake crate (full NDK compiler for this target).
|
|
export CC=$NDK_BIN/${target}-android26-clang
|
|
export CXX=$NDK_BIN/${target}-android26-clang++
|
|
|
|
profile_dir=release; [ -z "$profile" ] && profile_dir=debug
|
|
|
|
# Optional: ADB_SERIAL picks the device when several are attached (see AGENTS.md).
|
|
adb=(); [ -n "${ADB_SERIAL:-}" ] && adb=(adb -s "$ADB_SERIAL")
|
|
|
|
# 16 KB page kernel (Pixel 9 Pro): keep the .so's program-header page
|
|
# size at 4096 or it refuses to load. (The linker itself is set by
|
|
# cargo-apk2: CARGO_TARGET_*_LINKER = the NDK clang.)
|
|
export RUSTFLAGS="-C link-arg=-Wl,-z,max-page-size=4096"
|
|
|
|
cargo apk2 build $profile --target "$target" --lib ${features:+--features $features}
|
|
apk=target/$profile_dir/apk/gallery.apk
|
|
echo "APK: $apk ($(du -h "$apk" | cut -f1))"
|
|
|
|
if [ "$arg2" = install ] && command -v adb >/dev/null; then
|
|
"${adb[@]}" install -r "$apk"
|
|
"${adb[@]}" shell am start -n wow.gmp.gallery/android.app.NativeActivity || true
|
|
fi
|