120 lines
9.2 KiB
Markdown
120 lines
9.2 KiB
Markdown
# 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 <root>/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 <root> -zip TinyCore15Wine11.0.zip \
|
||
-env WINEDLLOVERRIDES=mscoree,mshtml= -mount <apptest>/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<U8[]>` → `std::shared_ptr<U8[]>(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."
|
||
|
||
## Running it locally
|
||
|
||
A durable native setup lives in `~/opt/boxedwine-26R1/` (rebuilt 2026-11-07 from the procedure above):
|
||
|
||
| Path | Content |
|
||
|---|---|
|
||
| `bin/boxedwine` | Boxedwine 26R1.0 built from `dl-src/` (GitHub tag tarball) with `boxedwine-26R1-linux-xvfb.patch`, GCC 11.4. The sources are CRLF: convert the five patched files to LF (`sed -i 's/\r$//'`) before `patch -p1`; `project/linux/linux_build/lib/libminizip.so` → system `libminizip.so.1` |
|
||
| `dl-fs/TinyCore15Wine11.0.zip` | Wine 11 file system (+ `filesV2.xml`) |
|
||
| `root/home/username/.wine/` | `user.reg` from the zip + the game's HKCU key, `.update-timestamp` = `disable` |
|
||
| `apptest/lama/data/` | `APPTEST_ROOT=~/opt/boxedwine-26R1/apptest tools/apptest.py setup lama`: `game/` (patched groove.exe), `cd-active/`; mounted as `/mnt/lama` |
|
||
|
||
Start: `lama-boxedwine` (`~/.local/bin`, bash) on the current `$DISPLAY`, normal sound
|
||
(`SDL_AUDIODRIVER=dummy lama-boxedwine` for silence). Log: `~/opt/boxedwine-26R1/last-run.log`;
|
||
PID file `~/opt/boxedwine-26R1/boxedwine.pid` blocks a second instance. Known issues: in-game camera at
|
||
Kuzco's position, no intro movies (see above).
|
||
|
||
**Real screen (AMD RX 480, Mesa radeonsi):** the window stayed black and the game hung after the movie attempts; with `LIBGL_ALWAYS_SOFTWARE=1` (llvmpipe) it shows the title and runs. `lama-boxedwine` therefore defaults to the software renderer (`LAMA_BW_GPU=1` to try the GPU).
|