Skip to content

Add scummvm to the ASYNCIFY-required cores list - #48

Draft
TRusselo wants to merge 4 commits into
EmulatorJS:v1.22.2from
TRusselo:add-scummvm-needsasync
Draft

TRusselo wants to merge 4 commits into
EmulatorJS:v1.22.2from
TRusselo:add-scummvm-needsasync

Conversation

@TRusselo

Copy link
Copy Markdown

ScummVM fetches its engine data over the network during game load. LibretroRemoteEngineData::fetch() is registered in the engine search path and calls emscripten_wget_data(), which is synchronous:

emscripten_wget_data(url.c_str(), &buffer, &numBytes, &error);

Engines pull fonts.dat, toon.dat and similar from there while retro_load_game() is running, so without ASYNCIFY that call blocks the main thread and the load never completes.

Same shape as bluemsx in ad2ca2a — a core doing synchronous I/O during load.

One line, no behaviour change for any other core.

AI assistance: written with Claude, reviewed and tested by me before opening.

state_data was a local array, so the char* this function returns pointed
at stack memory already invalid by the time the JS side (emulatorjs.js's
saveStateInfo cwrap, return type "string") read it via UTF8ToString().
JS never frees the buffer despite the comment claiming it does, so this
also isn't a heap-allocation-without-free situation -- making it `static`
is both correct and leak-free.

Symptom: every single save-state attempt (success or failure) logged
garbled, non-ASCII console output instead of the intended status message,
and the frontend reported "FAILED TO SAVE STATE" even once the
underlying core's retro_serialize()/retro_serialize_size() worked
correctly.

Assisted-by: Claude:claude-sonnet-5
platform_emscripten_get_canvas_size() returned early when either width
or height was non-zero, so a partially published canvas size returned
the zero one to the caller instead of falling back. Both dimensions are
written together in practice, so this has not been observed to bite; the
guard is simply wrong as written.

Unchanged at cold start: both values really are zero before the page
publishes them, so the fallback and its message still fire once there.

Same fix in both the emscripten and emulatorjs platform drivers.
…tent

platform_emscripten_update_canvas_dimensions_cb() stores width and height
as two separate atomic stores. Each is atomic; the pair is not. Under
HAVE_THREADS the reader runs on the emulator thread, so it can observe the
new width alongside a stale zero height.

platform_emscripten_get_canvas_size() then returned early -- its guard was
`width != 0 || height != 0` -- handing the caller a zero height, which is
used to compute geometry and produces a wrong aspect ratio. Intermittent by
nature, and not specific to any core.

Store height first and width last, making width the release point: a reader
that sees a non-zero width is guaranteed to see the matching height. The
reader already loads width first, which is the matching acquire order.

Also require both dimensions before skipping the fallback, so a zero can
never be returned even if the store order is broken again later.

Both platform drivers carry the same code and the same bug.
ScummVM fetches its engine data over the network during game load:
LibretroRemoteEngineData::fetch() sits in the engine search path and calls
emscripten_wget_data(), which is synchronous. Built without ASYNCIFY that
blocks the main thread and the load never completes.

Assisted-by: Claude:claude-opus-5
@TRusselo
TRusselo marked this pull request as draft September 21, 2026 01:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant