diff --git a/notes/dev/browser-boxedwine.md b/notes/dev/browser-boxedwine.md new file mode 100644 index 0000000..905e0fd --- /dev/null +++ b/notes/dev/browser-boxedwine.md @@ -0,0 +1,101 @@ +# Browser feasibility: Boxedwine (2026-11-07) + +Question: can *The Emperor's New Groove* (groove.exe, D3D7/DirectDraw, DirectInput, DirectSound) run in a +web browser through [Boxedwine](https://github.com/danoon2/Boxedwine) (Wine + x86 emulator, also built to WebAssembly)? + +## Verdict + +**Not with today's Boxedwine web build: Direct3D is missing in the browser.** +- **Web (Emscripten) build 26R1:** the game starts and shows Wine dialogs, then stops with the game's own + message *"Direct Draw kann nicht gestartet werden."* ("Direct Draw cannot be started"). The web build has no + OpenGL bridge: the Emscripten makefile defines none of the `BOXEDWINE_OPENGL_*` switches, the stripped file + system has no `libGL.so.1` (Wine logs `Failed to load libGL … OpenGL support is disabled`), and the release + readme says *"OpenGL and Direct3D are not supported in the Web/Emscripten build because they can not currently be + converted to WebGL."* Without OpenGL, wined3d has no D3D device, so groove.exe finds no 3D device. +- **Native Linux build (same emulator, x86 JIT), Wine 11 file system:** **works.** After three small Boxedwine + fixes (see below) it reaches the intro, the main menu, the save slot screen, the map and in-game + Village chapter 1 at ~30 fps (llvmpipe on Xvfb, load average ~15). Keyboard input works. One visible problem: + in-game the camera seems to sit at Kuzco's position (the llama is not visible, the view pitches up/down + with Up/Down); in the attract-mode demo Kuzco is drawn normally. Not investigated. + With the Wine 6 file system it hangs on the loading screen (emulator livelock, see below). +- **Software renderer (plan B) does not help:** no own rasterizer found in groove.exe. `FUN_0040ffd0` + chooses a DirectDraw device + Direct3D device by name (`DisplayDevice`/`D3DDevice`). The "software" flag + (`SoftwareScreenBPP/W/H`, device record +0x10) is derived from the enumerated **D3D** device description + (`FUN_00412a10`: `(desc+0xf4 >> 3) & 1`), most likely D3D's own software device (RGB/MMX emulation) – in any case a device the game gets from Direct3D enumeration, not an own rasterizer (no other draw path was found by grep). In Wine that + device is wined3d too, which needs OpenGL (or Vulkan). Wine has no GL-free D3D rasterizer, so the software + path also needs a GL bridge in the browser. +- **Path in Boxedwine:** yes, D3D7 → Wine `ddraw` → `wined3d` → OpenGL. Natively, Boxedwine passes the + emulated GL calls to the host GL through SDL (`source/opengl/sdl`). In the browser that bridge would have + to become WebGL (GL ES 2/3), which Boxedwine does not do. The source has an unused ES path + (`source/opengl/es`: glshim/esopengl) that is not part of the Emscripten build. + +### What it would take to ship +1. A GL → WebGL bridge for the Emscripten build (upstream work in Boxedwine: wined3d needs desktop GL 2.1+ + features; a translation layer like gl4es/glshim or a WebGL2 backend for the marshalled GL calls). This is + the blocker, weeks of emulator work at least, not something LlamaMod can patch around. +2. Speed: the web build has no JIT (wasm interpreter, `TOTAL_MEMORY` 512 MB). Native JIT gives ~30 fps with + 1.2 cores; the interpreter is typically several times slower, so even with WebGL the 3D game would likely + be far below playable on average hardware. Unmeasured. +3. Distribution page: a static page where the user drops their own ISO/folder; JS builds the app zip in + memory (game folder + CD data, ~400 MB without movies) plus a root zip with the registry values, never + uploaded anywhere. Never host game data. Needs COOP/COEP headers for the multi-threaded build. +4. Sound and movies: DirectSound opened 17 SDL audio streams natively (silent dummy driver here, audibility + not checked). Intro movies (`movies/*.dat`) do not play in Wine 11 under Boxedwine (quartz: `Failed to + create filter … hr 0x8007000e`); the game skips them. + +Alternatives that do not need a GL bridge are out of scope here (e.g. a native port, or a WebGL renderer +re-implementation of the engine's D3D7 calls). + +## Versions + +| Item | Version / source | +|---|---| +| Boxedwine | 26R1.0 (2026-04-22). GitHub releases have Windows, Mac and Web builds, **no Linux build** → built from the source tarball | +| Linux build | GCC 11.4 (Mint 21.3). Official requirement is GCC 12; one fix needed (below). `libminizip-dev` missing → linked against the installed `libminizip.so.1` via a local symlink (no system packages installed) | +| File systems | from Boxedwine's own list `http://www.boxedwine.org/v2/26R1/filesV2.xml`: `TinyCore15Wine6.0.zip`, `TinyCore15Wine11.0.zip`; web: `boxedwine.zip` (stripped Wine 6) from `Boxedwine26R1Web.zip` | +| Browser | Chromium (`/usr/bin/chromium`, own profile) on Xvfb :26, page served by a local Python server with COOP/COEP headers on 127.0.0.1, MultiThreaded web build | +| Game | German CD via `tools/apptest.py setup boxedwine`; LlamaMod's patched `game/groove.exe` (HKCU registry) | + +## Procedure (native) + +``` +Xvfb :26 -screen 0 1920x1080x24 -nolisten tcp +extension GLX +# prefix: copy user.reg out of the file-system zip into /home/username/.wine/, append +# [Software\\Disney Interactive\\Emperors New Groove\\1.0] CDPath="Z:\\mnt\\lama\\cd-active\\" HDPath=".\\" +# ScreenW=dword:280 ScreenH=dword:1e0 +# and write "disable" into .update-timestamp (otherwise wineboot updates the prefix: >15 min and it hung) +SDL_AUDIODRIVER=dummy DISPLAY=:26 boxedwine -root -zip TinyCore15Wine11.0.zip \ + -env WINEDLLOVERRIDES=mscoree,mshtml= -mount /data /mnt/lama -w /mnt/lama/game /bin/wine groove.exe +``` +Keys via `xdotool keydown/keyup` with the pointer over the window (X focus follows the pointer, no WM). +The game renders 640x480 into the top-left of the 800x600 Boxedwine window. + +Boxedwine fixes needed (patch: `$CLAUDE_JOB_DIR/tmp/boxedwine/results/boxedwine-26R1-linux-xvfb.patch`, not upstreamed): +1. `readIcons.cpp`: `std::make_shared` → `std::shared_ptr(new U8[n]())` (GCC 11). +2. `platform/linux/platformOpenGL.cpp`: skip GLX fbconfigs with `GLX_SLOW_CONFIG` caveat and without + `GLX_WINDOW_BIT`. Under Xvfb/llvmpipe, Wine otherwise picks an accum-buffer config (SDL refuses it as + "accelerated") or a non-window config (`set_pixel_format … not compatible for window rendering`) and wined3d + reports `Failed to get a GL context`. Probably Xvfb-specific; real GPUs may not need it. +3. `KMemory::mapNativeMemory`: when no free pages are left above 0xD0000000, reserve in the user area + instead. Without it the first `glMapBufferRange` of wined3d (Wine 6) fails → `Failed to map bo` → page fault. + Not checked whether Wine 11 still needs it. + +Wine 6 file system with these fixes: loading screen drawn through D3D7, ~10–25 presents/s for ~30 s, then +every emulated thread waits for the JIT memory mutex (`JitCodeGen::doJIT`) while one thread spins — the game +never leaves the loading screen. Not investigated further; Wine 11 does not show it. + +## Procedure (web) + +Web page = release `MultiThreaded/` folder plus `lamaroot.zip` (= `boxedwine.zip` with the user.reg above, CDPath +`C:\\files\\lama\\cd\\`) and `lama.zip` (`lama/` = game folder + `lama/cd/` = CD data without movies, stored, +415 MB). URL: `boxedwine.html?root=lamaroot&app=lama&p=groove.exe&sound=false`. +The `overlay=` parameter did **not** override `user.reg` of the root zip (game asked for the CD), a modified +root zip did. Loading 415 MB into the page took a few seconds locally. + +## Screenshots + +- `../img/dev/boxedwine-native-menu.jpg` – main menu (native Boxedwine, Wine 11) +- `../img/dev/boxedwine-native-demo.jpg` – attract-mode demo in 3D (the right/bottom strips are a stale frame + outside the 640x480 game area) +- `../img/dev/boxedwine-native-village.jpg` – Village chapter 1 in game (Kuzco not visible, see above) +- `../img/dev/boxedwine-web-ddraw-error.jpg` – web build in Chromium: "Direct Draw kann nicht gestartet werden." diff --git a/notes/img/dev/boxedwine-native-demo.jpg b/notes/img/dev/boxedwine-native-demo.jpg new file mode 100644 index 0000000..1e5223d Binary files /dev/null and b/notes/img/dev/boxedwine-native-demo.jpg differ diff --git a/notes/img/dev/boxedwine-native-menu.jpg b/notes/img/dev/boxedwine-native-menu.jpg new file mode 100644 index 0000000..5bf645c Binary files /dev/null and b/notes/img/dev/boxedwine-native-menu.jpg differ diff --git a/notes/img/dev/boxedwine-native-village.jpg b/notes/img/dev/boxedwine-native-village.jpg new file mode 100644 index 0000000..02bcf2b Binary files /dev/null and b/notes/img/dev/boxedwine-native-village.jpg differ diff --git a/notes/img/dev/boxedwine-web-ddraw-error.jpg b/notes/img/dev/boxedwine-web-ddraw-error.jpg new file mode 100644 index 0000000..c4b55ca Binary files /dev/null and b/notes/img/dev/boxedwine-web-ddraw-error.jpg differ