ScummVM on Kandelo - SCUMM v0-8 games in the browser on the Wayland/DRI desktop stack - #1368
Draft
mho22 wants to merge 6 commits into
Draft
ScummVM on Kandelo - SCUMM v0-8 games in the browser on the Wayland/DRI desktop stack#1368mho22 wants to merge 6 commits into
mho22 wants to merge 6 commits into
Conversation
Gate 1 polled for WLC_LAYOUT, which the compositor prints before THEME and WALLPAPER, so the plain assertions that followed raced the rest of startup. Poll for WALLPAPER — the last startup marker — and plain-assert the earlier ones, which are already in the stream once it appears.
…ange event1 advertised REL_X/REL_Y alongside its ABS axes, and consumers classify on exactly those two bits: SDL2's evdev backend saw a relative mouse and discarded every EV_ABS record. The host bridge compensated by pegging the relative integrator to the origin with an oversized negative delta before each move, and the compositor carried a matching suppression for the peg frame. Drop the REL_X/Y bits, send true EV_ABS coordinates from sendPointerAbs, and delete the peg workaround on both ends. The advertised EVIOCGABS range must be right when the device is OPENED: libevdev caches absinfo at open, and wlcompositor runs setup_input() before its lazy first-present drmModeSetCrtc, so a range corrected at SETCRTC is a range libinput never sees. connectorModeSize() becomes the single mode derivation, and setKmsDisplaySize advertises it to the input device the moment the embedder reports the display — before the compositor spawns. The SETCRTC hook (onKmsScanoutFb) stays for late openers and mid-session modesets; SDL reads raw ABS values, so it survives either keying. The wldesktop liveness smoke drives the real bridge pattern now: EV_ABS + SYN injection with the range set via kmsSetDisplaySize, the Node-host regression gate for the open-time keying.
…m renders through ScummVM's OpenGL graphics manager needs more of GLES2 than the bridge carried: glDetachShader, glVertexAttrib4fv (the per-draw color when the attribute array is disabled), glDeleteFramebuffers, glGetShaderPrecisionFormat, glGetString/glGetIntegerv on the client side, glBufferSubData, glTexSubImage2D with GL_UNPACK_ALIGNMENT row strides, and chunked texture uploads: the TLV payload length is u16, so uploads past ~64 KB stream as row bands instead of being dropped. eglGetProcAddress answers with the statically linked gl* entry points, because GL loaders (ScummVM's glad through SDL_GL_GetProcAddress) fetch every function through it and read a NULL glGetString as "no GL". A canvas-backed session gains a durable present target: an offscreen FBO the guest renders into, blitted to the default framebuffer once per GLIO_PRESENT. The browser composites an OffscreenCanvas at the end of any worker task that touched it, so rendering straight at the canvas puts clears and half-drawn frames on screen — whole-screen flicker while a program redraws every frame. The target is re-ensured at present time because ScummVM recreates its EGL window surface when it leaves the launcher, and destroy_surface frees the target with the binding's redirect.
The final link names the wayland archives with -l flags, but no -L pointed at the resolver-staged libwayland prefix. Carry it on CMAKE_EXE_LINKER_FLAGS so the staged archives resolve.
Two demo-surface capabilities the KMS pane lacked: A guest that draws its own cursor (modeset, ScummVM, a compositor) must have the browser pointer hidden over the scanout, or two arrows stack and drift apart; a guest that draws no cursor (the sdl2 GLSL playground) leaves the user nothing to aim with. The image-declared presentation gains hostPointer for the second kind, default hidden, and the pane sets the canvas cursor from it. The pane also fits the canvas to the live scanout aspect instead of the 16:9 constant, which only remains the pre-first-frame fallback. The demo ingest control moves up from the framebuffer pane into a shared IngestControl with per-surface test ids, and the KMS pane mounts it: an upload lands while the guest keeps running, because a KMS program holds DRM master for the whole session and restarting it would cost the user their place. The toast styles rename from kframebuffer-* to kdemo-* to match their two consumers.
ScummVM 2026.3.0 (SCUMM engine with scumm-7-8) as a registry package on the Kandelo SDL2 stack: Wayland video under wlcompositor with the GLES2 OpenGL graphics manager through wayland-egl, OSS audio through SDL2's dsp backend, seat input from the compositor. Two patches: a wasm32posix host triple so the generic POSIX/SDL backend builds instead of the Emscripten port, and the OpenGL manager as default because Kandelo's SDL2 compiles SDL_Render out. The package declares [[runtime_files]] — the launcher's themes, icons and fonts — and the resolver mirrors the closure under programs/wasm32/scummvm/. The browser app restates the declaration in package-runtime-files.ts (it cannot run xtask), and browser-binary-dependencies.test.ts fails on drift against the manifest. The demo runs ScummVM alone on /dev/dri/card0 as DRM master. No game ships: the KMS pane's Load game data upload lands a zip that the demo's shell extracts into the directory the launcher browses. The config seeds into the demo user's scratch home, writable, with gui_scale at the device-pixel ratio so the GUI lays out in CSS pixels while rendering at physical ones. Gates: the browser spec proves the runtime files, the pointer ownership, and the upload-extract path through the demo's own shell; the Node smoke runs scummvm --version to a clean exit.
mho22
force-pushed
the
explore-dri-scummvm
branch
from
September 3, 2026 21:42
f385348 to
ad8ea9d
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #1354 (Quickshell on Kandelo — Qt 6.10 on wasm32), which carries the desktop stack this builds on: evdev devices, the Wayland compositor, and the Qt/Quickshell packages.
Why
The desktop stack from #1354 could run its own clients, but nothing the size of a real application had been ported onto it. ScummVM exercises the platform end to end — SDL2 over Wayland, the GLES2 OpenGL graphics manager, OSS audio, evdev pointer input, and package runtime data — and the user-visible result is
?demo=scummvm: SCUMM v0–8 games (Monkey Island 1–3, Day of the Tentacle, Full Throttle, The Dig) playable in the browser from a user-supplied game upload. Porting it surfaced two platform bugs that this PR fixes for every GL and pointer consumer, not just ScummVM.What changed
ScummVM 2026.3.0 joins the registry with the scumm engine and its scumm-7-8 sub-engine enabled, patched only for the host triple and to default to the OpenGL graphics manager. Its GUI themes and data files travel as
[[runtime_files]]staged into/usr/share/scummvm, so the engine boots with no game data embedded anywhere; games arrive through the demo's "Load game data" upload, which extracts into the directory the launcher browses.The GL bridge grows the ops ScummVM renders through (
glDetachShader,glVertexAttrib4fv,glDeleteFramebuffers,glGetShaderPrecisionFormat), andhost_gl_presentnow ensures a present target instead of testing for one: destroying an EGL window surface freed the target, but only the first canvas claim ever built one, so recreating a surface on the same context (leaving the launcher for a game) lost the bind-0 redirect and composited every half-drawn frame as a black flash./dev/input/event1becomes a real absolute pointer. It advertised REL_X/REL_Y alongside its ABS axes, so SDL classified it as a relative mouse and discarded every EV_ABS record; the host compensated by pegging the cursor to the origin before each move, and a click processed between the two frames registered at (0,0). The REL bitmap now carries only the wheel axes,sendPointerAbsstates the position as EV_ABS, and the advertised EVIOCGABS range is keyed to the connector mode atsetKmsDisplaySizetime — libinput caches absinfo when it opens the device, so a range corrected any later is one a running compositor never sees.A one-line quickshell build fix rides along: the CMake link line passes the staged libwayland prefix explicitly.
Validation
Host Vitest: 142 passed, 2 skipped across kandelo-session, browser-binary-dependencies, the ScummVM CLI smoke, the wldesktop liveness gate (now driving the EV_ABS pattern through
kmsSetDisplaySize), and sdl2. Playwright chromium: 10/10 across the wayland, hyprland, omarchy, modeset, scummvm, and doom-ingest specs; the scummvm spec also passes on firefox and webkit (4/4)../run.sh local-buildunder the source-only policy: all nodes succeeded, products 7/7.cargo test -p runtime-core input::: 16 passed. Monkey Island 2 was played end to end in the browser manually. The branch was later restacked into six commits with identical content apart from dropped npm lock churn and a relocated doc comment; on the restacked tree the Vitest selection (142 passed, 2 skipped), the chromium Playwright specs (10/10), and the cargo suites (wasm-posix-shared gl_tests 4 passed, runtime-core input 36 passed) were rerun green.