Three root causes, all fixed and verified on the Pixel 9 Pro: 1. Present phase (backend + renderer): VSYNC_LOCKED_RENDER defers the render to the vsync wake; RENDER_AHEAD presents the previous frame at the start of render() (phase = wake + ~1.1 ms) and holds the new frame one slot. Crash fix: a held wgpu frame must be PRESENTED, never merely dropped, before the next acquire (AlreadyAcquired panic at launch otherwise); discard_pending_frame presents too. 2. Full-res prefetch churn (src/lib.rs): the 8-slot full cache cycled through a ~20-cell viewport forever (137 decodes/20 s) and each eviction free()'d a 50 MB Vec on the UI thread (20-52 ms CPU spikes, ~7/s = the residual SLOWEV NonMain jank). Fix: 60 s tombstone cooldown on evicted paths (idle prefetch skips, urgent tap bypasses) + off-thread reaper for the freed blobs (insert: 21 ms -> 4 us). 3. (earlier) Skia final flush + Mailbox present mode (vendor, M3). Instrumentation (all behind --features perf): OTHR/INVK/INVK_TAG/FLCK lines for cross-thread closure timing and push-site tagging. Warm measured swipe, 8580-file grid: cadence median 8.33 ms (exact 120 Hz), p99 15.5 ms, 5/552 gaps >16.7 ms (0.9%, max 28.3 ms, zero >33 ms); PRES phase median ~994 us, zero late frames. Docs updated (docs/BUGS/scroll-jank-120hz.md, full scorecard + line reference). Also: vendored i-slint-core + wgpu-hal (vkshim interposition patch), vkshim profiling tooling, backend made a non-optional dep, debuggable flag for simpleperf (REMOVE before shipping).
56 lines
2.1 KiB
Bash
Executable File
56 lines
2.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Inject the Vulkan interposer (shim/vkshim.c, built to shim/out/libvulkan.so)
|
|
# into a gallery APK as lib/<abi>/libvulkan.so, so the app's linker namespace
|
|
# serves it to wgpu-hal's dlopen("libvulkan.so") INSTEAD of /system/lib64.
|
|
#
|
|
# scripts/inject_vkshim.sh <abi> <in.apk> <out.apk>
|
|
# abi: arm64-v8a | x86_64
|
|
#
|
|
# Steps: python adds the .so as an UNCOMPRESSED (STORED) zip entry (required
|
|
# for extractNativeLibs=false), zipalign page-aligns it, apksigner re-signs
|
|
# (the plain zip write invalidates the old signature).
|
|
set -euo pipefail
|
|
cd "$(dirname "$0")/.."
|
|
|
|
ABI=${1:?usage: inject_vkshim.sh <abi> <in.apk> <out.apk>}
|
|
IN=${2:?missing in.apk}
|
|
OUT=${3:?missing out.apk}
|
|
|
|
case $ABI in
|
|
arm64-v8a) SHIM=shim/out/libvulkan.so ;;
|
|
x86_64)
|
|
NDK=$HOME/android-sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/bin
|
|
$NDK/x86_64-linux-android26-clang -shared -fPIC -O2 shim/vkshim.c -o shim/out/libvulkan.so.x86_64 -lunwind
|
|
SHIM=shim/out/libvulkan.so.x86_64 ;;
|
|
*) echo "bad abi: $ABI" >&2; exit 1 ;;
|
|
esac
|
|
|
|
SDK=$HOME/android-sdk
|
|
BT=$SDK/build-tools/35.0.0
|
|
[ -x "$BT/zipalign" ] || { echo "build-tools zipalign missing: $BT" >&2; exit 1; }
|
|
|
|
python3 - "$IN" "$OUT" "$ABI" "$SHIM" <<'EOF'
|
|
import sys, zipfile, shutil, os
|
|
src, dst, abi, shim = sys.argv[1:5]
|
|
# Copy the APK, replacing/adding our entry, forcing STORED for the shim.
|
|
with zipfile.ZipFile(src) as zin, zipfile.ZipFile(dst, "w") as zout:
|
|
for item in zin.infolist():
|
|
if item.filename == f"lib/{abi}/libvulkan.so":
|
|
continue # replaced by ours
|
|
zout.writestr(item, zin.read(item.filename))
|
|
with open(shim, "rb") as f:
|
|
data = f.read()
|
|
info = zipfile.ZipInfo(f"lib/{abi}/libvulkan.so")
|
|
info.compress_type = zipfile.ZIP_STORED
|
|
info.external_attr = 0o755 << 16
|
|
zout.writestr(info, data)
|
|
EOF
|
|
|
|
"$BT/zipalign" -f 4 "$OUT" "${OUT%.apk}_aligned.apk"
|
|
mv -f "${OUT%.apk}_aligned.apk" "$OUT"
|
|
"$BT/apksigner" sign --ks "$HOME/.android/debug.keystore" --ks-pass pass:android \
|
|
--out "${OUT%.apk}_signed.apk" "$OUT"
|
|
mv -f "${OUT%.apk}_signed.apk" "$OUT"
|
|
"$BT/apksigner" verify --print-certs "$OUT" | head -2
|
|
echo "OK: $OUT ($(du -h "$OUT" | cut -f1))"
|