Confirm real PinMAME ROM-driven emulation actually running
Tested pinball.loadRom() against a correctly-matched ROM zip for a real community table (Heavy Metal Meltdown, Bally 1987): PinMAME loads the ROM, and its own video/audio subsystems come up and run with no errors (osd_create_display: 60.00 fps; real INT16/44100Hz audio format), not just Controller object creation succeeding as before. Updates the README to move this from "not yet validated" to confirmed, narrowing the remaining gap to on-screen DMD/backglass output and hands-on switch/solenoid/scoring behavior during actual play, which nobody has watched yet. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SoSarxLgY33Kax5UNXcafZ
This commit is contained in:
@@ -21,16 +21,16 @@ Getting here required finding and fixing four real, previously-unknown bugs in t
|
||||
3. The window's OpenGL back buffer was created with the window's *logical* (CSS) pixel size instead of its *device* pixel size — on any browser tab with `devicePixelRatio != 1` (essentially all HiDPI displays), the GL viewport only covered a fraction of the canvas's actual backing buffer, rendering anchored to one corner (GL's viewport origin) instead of filling the canvas.
|
||||
4. `Window::OnResized()` (called on every SDL resize event, including entering/leaving browser fullscreen) updated the window's own tracked pixel size but never propagated it to the window's back buffer render target — so toggling fullscreen resized the canvas but rendering stayed pinned to the pre-resize viewport size.
|
||||
|
||||
## Status: real PinMAME (`VPinMAME.Controller`) integration — cooperative scheduling confirmed, gameplay unconfirmed (no ROM to test with)
|
||||
## Status: real PinMAME (`VPinMAME.Controller`) integration — real ROM-driven emulation confirmed running
|
||||
|
||||
Real-hardware ("SS"/ROM-based) tables `CreateObject("VPinMAME.Controller")` against the actual PinMAME emulation core (`libpinmame`, from the real [vpinball/pinmame](https://github.com/vpinball/pinmame) project — not a stub, not a mock), compiled to wasm32 and statically linked in. Confirmed by hands-on testing against a real community ROM-based table: the Controller correctly identifies the requested game from PinMAME's actual ~2,900-entry built-in driver database (`PinMAME::Controller::SetGameName` → `Game found: name=hvymetal, description=Heavy Metal Meltdown, manufacturer=Bally, year=1987`), and a missing/invalid ROM now fails cleanly (a logged error, the game just doesn't start) instead of crashing the page.
|
||||
Real-hardware ("SS"/ROM-based) tables `CreateObject("VPinMAME.Controller")` against the actual PinMAME emulation core (`libpinmame`, from the real [vpinball/pinmame](https://github.com/vpinball/pinmame) project — not a stub, not a mock), compiled to wasm32 and statically linked in. Confirmed by hands-on testing against a real community ROM-based table with its real, correctly-matched ROM zip supplied via `pinball.loadRom()`: the Controller identifies the requested game from PinMAME's actual ~2,900-entry built-in driver database (`PinMAME::Controller::SetGameName` → `Game found: name=hvymetal, description=Heavy Metal Meltdown, manufacturer=Bally, year=1987`), loads the ROM successfully, and PinMAME's own video and audio subsystems come up and run with no errors (`osd_create_display: 60.00 fps`; `OnAudioAvailable: format=INT16, channels=1, sampleRate=44100.00, framesPerSecond=60.00`) — this is real emulation actually executing, not just object creation succeeding. A missing/invalid ROM (verified separately, with two different non-matching ROM zips) fails cleanly instead — a logged error, the game just doesn't start, no page crash.
|
||||
|
||||
Getting a real OS-thread-based emulator core running inside a single-threaded WASM build required the same class of fix as the vsync/game-loop bugs above, just one level deeper — this time inside PinMAME's own CPU-execution loop, not vpinball's:
|
||||
1. `PinmameRun()` spawned PinMAME's actual emulation main loop (`run_game()` → `run_machine()` → `run_machine_core()` → `cpu_run()`, MAME's real CPU-cycle scheduler) on a real `std::thread` — the same hard-abort-under-Emscripten bug as `RenderDevice::WaitForVSync()` above, just for an entire emulation session instead of one vsync wait. Fixed by splitting that whole call chain into a one-shot init, a step bounded to roughly one host video frame of emulated time (`timer_get_time()`-bounded, called once per frame from `Player::EmscriptenStepFrame()` itself), and a one-shot teardown — see `patches/pinmame/0004-emscripten-cooperative-scheduling.patch`.
|
||||
2. Two small wasm32 portability bugs in libpinmame itself, unrelated to threading: an x86-only compiler intrinsic (`__rolq`/`__rorq`) reached by a portability guard that didn't exclude wasm32, and a bundled-zlib include path only wired up for the Windows build — see `patches/pinmame/0001-*` and `0003-*`.
|
||||
3. An optional external-clock-sync feature (`time_fence`, mirrored by `Controller.TimeFence` in table scripts) used POSIX semaphores unavailable in this build; it now reports itself as unsupported instead, the same way every other optional sync/timing feature becomes a no-op under this build's single-threaded model — see `patches/pinmame/0002-*`.
|
||||
|
||||
A ROM zip can be supplied via `pinball.loadRom(gameName, romZipBytes)`, written to `/tables/pinmame/roms/<gameName>.zip` — the same table-relative convention vpinball's own PinMAME plugin already checks before any global settings path, so no extra configuration is needed. **Not yet validated: actual gameplay** (real switch/solenoid state, sound, scoring) against a real ROM — none was available to test against, and ROM files are copyrighted, so none was sought out. Table script compatibility for tables that don't need real ROM emulation — most tables, including the bundled default — is unaffected either way.
|
||||
A ROM zip can be supplied via `pinball.loadRom(gameName, romZipBytes)`, written to `/tables/pinmame/roms/<gameName>.zip` — the same table-relative convention vpinball's own PinMAME plugin already checks before any global settings path, so no extra configuration is needed. **Still not visually/interactively confirmed:** actual on-screen DMD/backglass output and hands-on switch/solenoid/scoring behavior during play — video/audio subsystem startup is confirmed (see above), but no one has yet watched a full game played against this integration. Table script compatibility for tables that don't need real ROM emulation — most tables, including the bundled default — is unaffected either way.
|
||||
|
||||
## Why a source-level port, not a reimplementation
|
||||
|
||||
@@ -81,9 +81,10 @@ Full research and two isolated feasibility spikes (proving real VBScript executi
|
||||
- **A full loading → play flow in a real page** (`examples/basic/index.html`): a byte-level download progress bar, a user-gesture "Start" button (required for both audio autoplay and fullscreen to work), a working fullscreen button, and responsive canvas sizing that fills its container correctly.
|
||||
- **Browser file-loading for self-contained tables**: picking a `.vpx` file, mounting it via `FS.writeFile`, and starting the engine against it — verified end-to-end (`PinTable::LoadGameFromFilename /tables/uploaded.vpx` in the boot log, followed by a normal render).
|
||||
- A JS-callable `evalScript()` debug/utility hook (`pinball.evalScript(script)`) that runs arbitrary VBScript against the live table via the same entry point the interpreter's own debug console uses.
|
||||
- **Real PinMAME (`VPinMAME.Controller`) ROM-driven emulation actually running**, not just object creation — see Status above for the exact confirmation (real video/audio subsystem startup against a real, correctly-matched ROM zip supplied via `pinball.loadRom()`).
|
||||
|
||||
**Not yet validated (should work, per code review and by analogy to already-proven mechanisms, but unconfirmed end-to-end):**
|
||||
- **PinMAME (`VPinMAME.Controller`) real gameplay** — Controller creation, game identification, and graceful missing-ROM handling are confirmed (see Status above), but actual ROM-driven switch/solenoid/sound/scoring behavior is unconfirmed end-to-end, since no ROM file was available to test against (and none was sought out — they're copyrighted).
|
||||
- **PinMAME on-screen DMD/backglass output and hands-on gameplay** — the emulation session itself is confirmed running (see Status above), but no one has yet watched real DMD frames render or played a full game against it to confirm switch/solenoid/scoring behavior end-to-end.
|
||||
- Gamepad/joystick input during real gameplay (keyboard input uses the identical `InputManager` pipeline and is confirmed working; gamepad support is code-complete but untested on real hardware).
|
||||
- Touch-control overlay (`attachTouchControls`) actually flipping a flipper on a real touch device — implemented and included in the example (synthesizes the real default keyboard scancodes on `window`), not yet confirmed on physical touch hardware.
|
||||
- DMD rendering via a script-driven `Flasher`/`ScriptGlobalTable::put_DMDPixels`. This is native, core-engine functionality requiring no new code (`src/core/ScriptGlobalTable.cpp:886-937`, `src/parts/flasher.cpp:1312-1341`), and rides the exact same `ScriptInterpreter::Evaluate()` VBScript-dispatch path already confirmed working by the flipper test above — but the bundled default table has no DMD-configured `Flasher`, so a full *visual* confirmation needs a real DMD-equipped table (uploadable via the file picker) or authoring one, neither done yet.
|
||||
@@ -152,7 +153,7 @@ See `examples/basic/index.html` for a complete working page (loading progress, f
|
||||
## Known limitations
|
||||
|
||||
- Single-threaded only (no pthreads/SharedArrayBuffer) — a deliberate tradeoff, not a gap; see Roadmap.
|
||||
- Real PinMAME (`VPinMAME.Controller`) integration for ROM-based tables — Controller creation, game identification, and graceful missing-ROM handling confirmed, but actual ROM-driven gameplay unconfirmed without a real ROM (copyrighted, none sought out) — see Status and Roadmap. The rest of the plugin ecosystem (DOF/FlexDMD/etc., and the modern `plugins/b2s` backglass plugin) remains unwired — see Roadmap.
|
||||
- Real PinMAME (`VPinMAME.Controller`) integration for ROM-based tables — confirmed actually running real ROM-driven emulation (video/audio subsystem startup against a real ROM), but on-screen DMD/backglass output and hands-on switch/solenoid/scoring behavior during play are not yet confirmed — see Status and Roadmap. The rest of the plugin ecosystem (DOF/FlexDMD/etc., and the modern `plugins/b2s` backglass plugin) remains unwired — see Roadmap.
|
||||
- No raw hardware input (real cabinet nudge/plunger boards) — permanent, no browser equivalent.
|
||||
- Keyboard input, audio, and VBScript-driven gameplay are confirmed working end-to-end by hands-on manual testing (not just code review). Gamepad input and the touch-control overlay are code-complete and use the identical input pipeline, but are not yet confirmed on real gamepad/touch hardware — see Roadmap.
|
||||
- DMD rendering is native, code-complete functionality riding the same proven VBScript-dispatch path, but not yet visually confirmed since the bundled default table has no DMD-configured `Flasher` — see Roadmap.
|
||||
|
||||
Reference in New Issue
Block a user