Skip to content

Android: setprop-tunable calibration knobs (face axes + UV flip)#17

Open
leaiss wants to merge 1 commit into
feat/android-cnsdk-dp-bundle-transitivefrom
feat/android-cnsdk-calibration-knobs
Open

Android: setprop-tunable calibration knobs (face axes + UV flip)#17
leaiss wants to merge 1 commit into
feat/android-cnsdk-dp-bundle-transitivefrom
feat/android-cnsdk-calibration-knobs

Conversation

@leaiss
Copy link
Copy Markdown
Collaborator

@leaiss leaiss commented May 27, 2026

Summary

Stacked on #14 (bundle-transitive). Wires the symptom→fix table in docs/cnsdk-android-calibration.md into runtime debug.dxr.leia.* system properties so post-Lume-Pad calibration iteration doesn't need a rebuild + reinstall + relaunch cycle — just `setprop` + `am force-stop` + restart.

Knobs

Property Default Effect
`debug.dxr.leia.flip_uv` 1 Pass false to leia_interlacer_set_flip_input_uv_vertical
`debug.dxr.leia.face_flip_x` 0 Negate out_x
`debug.dxr.leia.face_flip_y` 0 Negate out_y
`debug.dxr.leia.face_flip_z` 0 Negate out_z
`debug.dxr.leia.face_swap_xy` 0 Swap out_xout_y (before flips)

Tile-to-eye swap (B17) intentionally out of scope — the current atlas mode has no CNSDK-side swap parameter; that needs a runtime-side atlas blit change.

Implementation notes

  • Values cached at first plug-in call (std::atomic<bool> g_calib_loaded). Re-reading mid-session would race in-flight frames, and __system_property_get isn't free per-frame.
  • Logged once via U_LOG_W at first read so values land in logcat at every session start — visible even when CNSDK init never completes (e.g. emulator).
  • Hooked from leia_plugin_android_probe() (runs at xrCreateInstance time) via new C-callable leia_cnsdk_log_calibration_knobs(), so emulator validation can confirm the plumbing even though CNSDK init can't complete there.

Verification

Run `scripts/android-smoketest.sh` from the runtime repo (validated against the new plug-in build):

```

Defaults:

W monado.ensure_calibration_loaded: HW_DBG_CNSDK calibration: flip_uv=1 face_flip_xyz=000 face_swap_xy=0

After: adb shell setprop debug.dxr.leia.{flip_uv 0,face_flip_x 1,face_swap_xy 1}

+ adb shell am force-stop ...

+ adb shell am start ...

W monado.ensure_calibration_loaded: HW_DBG_CNSDK calibration: flip_uv=0 face_flip_xyz=100 face_swap_xy=1
```

Why

Without this, every calibration iteration on Lume Pad costs:

  1. Edit constant in `leia_cnsdk.cpp`
  2. Rebuild plug-in (~30s)
  3. `install-runtime-jnilibs` (~5s)
  4. Rebuild runtime APK (~2m)
  5. Adb install (~10s)
  6. Relaunch + test

≈ 3 minutes per flip. With 5 binary knobs there are 32 combinations to potentially test; this collapses to 5 seconds per knob via setprop.

Stacking

Based on plug-in #14. Rebase onto main once #14 lands.

🤖 Generated with Claude Code

@leaiss leaiss requested a review from dfattal as a code owner May 27, 2026 21:19
@leaiss leaiss force-pushed the feat/android-cnsdk-dp-bundle-transitive branch from 54a525f to e76cb87 Compare June 2, 2026 15:51
@leaiss leaiss force-pushed the feat/android-cnsdk-calibration-knobs branch from 8c883ca to fae05db Compare June 2, 2026 15:51
Wires the cnsdk-android-calibration.md symptom→fix table into runtime
`debug.dxr.leia.*` system properties so post-Lume-Pad calibration
iteration doesn't need rebuild + reinstall + relaunch — just setprop
+ am force-stop.

Knobs:
  debug.dxr.leia.flip_uv         (default 1) — UV flip pass-through
  debug.dxr.leia.face_flip_x     (default 0) — negate out_x
  debug.dxr.leia.face_flip_y     (default 0) — negate out_y
  debug.dxr.leia.face_flip_z     (default 0) — negate out_z
  debug.dxr.leia.face_swap_xy    (default 0) — swap x↔y before flips

Implementation:
  - Reads cached at first plug-in call to ensure_calibration_loaded()
    (under std::atomic<bool> g_calib_loaded). Re-reading mid-session
    would race in-flight frames, and __system_property_get isn't free
    per-frame.
  - Logged ONCE via U_LOG_W at first read so the values land in logcat
    at every session start — visible even when CNSDK init never runs
    (e.g. emulator hits VK_ERROR_EXTENSION_NOT_PRESENT before DP).
  - Hooked from leia_plugin_android_probe() (runs at xrCreateInstance
    time) via new C-callable leia_cnsdk_log_calibration_knobs() in
    leia_cnsdk.h, so emulator validation can confirm the knob plumbing
    even though CNSDK init can't complete there.

Tile-to-eye swap (B17) intentionally left out — current atlas mode
has no CNSDK-side swap parameter; would need a runtime-side atlas
blit change. Documented as a known limitation.

Verified on Android-36 emulator: defaults log
`flip_uv=1 face_flip_xyz=000 face_swap_xy=0`. After `setprop
debug.dxr.leia.{flip_uv 0,face_flip_x 1,face_swap_xy 1}` + force-stop
+ relaunch, logs flip to `flip_uv=0 face_flip_xyz=100 face_swap_xy=1`.
@leaiss leaiss force-pushed the feat/android-cnsdk-dp-bundle-transitive branch from e76cb87 to cfef49d Compare June 2, 2026 16:46
@leaiss leaiss force-pushed the feat/android-cnsdk-calibration-knobs branch from fae05db to 5635607 Compare June 2, 2026 16:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant