WinNative

Embedded Dolphin (Route B2) — WinNative-driven GC/Wii

Packaging note (current): the emucore and its runtime data are no longer committed here. They are built in the WinNative-Emu fork and shipped in the Retro-Consoles bundle the app downloads at runtime. The build/patch details below describe how that fork produces the binary and remain accurate for the fork.

Decision (2026-07-22): replace the dolphin-libretro GLES path for GameCube/Wii with an embedded standalone Dolphin core, mirroring the ARMSX2/PS2 pattern. WinNative drives everything — Dolphin’s own menus/UI are stripped; every setting, driver and toggle is fed from WinNative’s surfaces (Shortcut Settings, Settings > Retro, in-game drawer).

Why: dolphin-libretro can only render GLES via libretrodroid, and the system Adreno GLES driver SIGSEGVs on new silicon (see DOLPHIN_VULKAN.md). Standalone Dolphin brings its own Vulkan backend + native adrenotools/Turnip loading, RetroAchievements, netplay, and save infrastructure.

Module: dolphin/

Phases

Status 2026-07-22: Phases 1–5 done and verified on-device (CPH2749): TP GC boots on Vulkan crash-free, input proven via chained input-only transitions, settings bridge verified both directions (stretch applied / auto restored), and Turnip verified on Adreno 840 — WN-Turnip-1.06 staged via wn.gc.driver → GpuDrivers/Extracted, libvulkan_freedreno.so confirmed mapped in-process, clean rendering. GPU Driver pickers live on both GC/Wii settings surfaces.

Phases 6–7 (2026-07-22, verified on-device): DolphinGameOverlay attaches the shared WinNative RetroInputView (GC/Wii themes) + drawer menu via the DolphinHost hook (Ps2GameOverlay pattern; PluviaApp installs in every process, :gc gets light init). Verified: overlay renders over the game, drawer opens, save state wrote GZ2E01.s01, Exit → StopEmulation → clean finish. Routing: GC/Wii launches go to embedded Dolphin in both launch paths behind wn.gc.embedded (default true; off = libretro fallback). Settings parity pass (2026-07-22, compile-verified; device was disconnected):

Start/teardown lifecycle (2026-07-22, compile-verified): the Dolphin core cannot reliably boot twice in one process, so :gc follows the ARMSX2 model — fresh process per session. teardown() (idempotent; Exit button, back press, Run() returning, and onDestroy-when-finishing all funnel into it) does StopEmulation → join the Run thread (≤15s, so memcards/saves flush) → delete .running_rom marker → finish() → kill the :gc process. onPause/onResume skip pausing while stopping (no pause-during-shutdown races). Launch side: the game activity now JOINS the Library task (NEW_TASK only from non-activity contexts) so exiting lands back on the Library; prepareLaunch kills a lingering :gc before starting UNLESS the .running_rom marker matches the requested ROM (tapping Play on the running game resumes instead of restarting).

Drawer parity + shared-source pass (2026-07-22, compile-verified):

Settings surfaces + persistence pass 2 (compile-verified):

Open items: overlay polish (FrameRating-style HUD, touch-IR for Wii ir_mode, controller-connected hiding, playtime/cloud hooks), RetroAchievements for the embedded path, defaults tuning (dual core ON), retiring the libretro dolphin core after parity sign-off. On-device retest checklist when phone reconnects: drawer tabs render + live-apply (aspect change visible), audio mute, HUD OSD, VBI toggle, touch-controls hide, edit-layout back handling, Play-button routing end-to-end.

  1. Scaffold (done): module, build script, manifest, stub activity, app wiring.
  2. Emucore + JNI surface: build libmain.so; vendor the minimal Java classes Dolphin’s IDCache/JNI_OnLoad requires (NativeLibrary, NativeConfig, GpuDriverHelper, model classes); patch IDCache to drop upstream-UI-only classes.
  3. DolphinEmulationActivity: SurfaceView → NativeLibrary.SurfaceChanged, Run(rom), pause/resume, input forwarding, clean shutdown.
  4. Settings bridge: generate User/Config/Dolphin.ini + GFX.ini from WinNative prefs pre-boot (renderer=Vulkan, IR scale, aspect, dual core, JIT, skip BIOS, widescreen, sensor bar, IR mode, cheats); live updates via NativeConfig where safe. Same keys/surfaces as the current GC/Wii settings (RetroCoreOptions ids map 1:1 onto Dolphin ini keys).
  5. GPU driver: reuse CustomDriver Turnip packs through Dolphin’s GpuDriverHelper; per-console wn.gc.driver pref; default system Vulkan.
  6. Overlay: DolphinGameOverlay (Ps2GameOverlay analogue) — RetroInputView touch overlay, WinNative drawer (save states via NativeLibrary.SaveState/LoadState, live settings, HUD, cheats), playtime stats, exit cloud backup.
  7. Routing: RetroShortcuts.launch sends gc/wii to the embedded activity (toggle first, libretro fallback until parity); settings surfaces switch to the Dolphin sections; decide native RetroAchievements vs RetroAchievementsManager.

Phase 2 analysis (done)

Authoritative JNI-required Java surface (every FindClass under Source/Android/jni/), 30 classes — all model/util, no upstream UI:

Naive transitive closure is 92 files because a few bridge classes import the UI web. Patch these cut points (in patches/), then the closure collapses to ~50 UI-free files:

  1. NativeLibrary.kt — replace EmulationActivity/AlertMessage references with a WnHost callback interface our activity registers (alerts, exit, orientation, title changes). This IS the B2 design: UI callbacks go to WinNative.
  2. utils/Analytics.kt — strip the FragmentActivity dialog method (analytics is compiled out with -DENABLE_ANALYTICS=OFF).
  3. NetplaySession.kt — sever imports of netplay UI (NetplaySetupActivity, viewmodels) if present; keep the session/Player model.
  4. Settings.kt/NativeConfig chain — sever SettingsActivity/MenuTag imports.
  5. Drop DolphinApplication (not JNI-required); our module provides directory init via DirectoryInitialization directly.
  6. Skylander/Infinity ui/ adapters fall out once EmulationActivity is cut.

Vendoring mechanism: gradle Copy task from emucore-src/.../java (post-patch) into build/generated/dolphinJava, added as a srcDir — no duplicated sources in-repo.

MMJR2 fork review (2026-07-22)

Reviewed Medard22/Dolphin-MMJR2-VBI, nachoverdon/Dolphin-MMJR2, Mato00KAN/Dolphin-MMJR2 for patches worth adopting:

Notes

Cloud-save bucket fix (2026-07-22): the real reason Save History was blank for ALL retro consoles — auto-upload used cloudGameId (“retro_gc_") but the History UI and manual backup query under customGameId (":.desktop") = two different Google buckets, so nothing ever appeared. Worse, backupSaveToGoogle resolves the save DIR from the gameId (getCustomSaveSources → findShortcut → retroSaveDir); a cloudGameId resolves no shortcut, so it found no files and silently uploaded nothing. Fix: everything now uploads/restores under customGameId (same as the working PS2 path). retroSaveDir extended to return the full per-game set: PS2=memcards, GC/Wii=DolphinCloudSync staging (states+GC memcards), other libretro=RetroSaveStates.gameDir (states+sram). Internal staging dir stays keyed by cloudGameId (a stable path token) while the Google bucket uses customGameId — the two IDs have distinct roles. findCustomShortcutByContainerAndFile resolves retro shortcuts via loadShortcuts() (retroContainer id 0), confirmed.