Webassembly & Fallout2
How it went
It begun with fallout2-ce project
Webassembly
Webassembly.Memory ~ ArrayBuffer
JavaScript
Webassembly
js_func1()
wa_func2()
js_func3()
Emscripten
LLVM code
Emscripten output
JS
WASM
HTML
libc / SDL / etc
JS event loop
JS
Webassembly
requestAnimationFrame()
call_me_on_each_frame()
Real-life example
more than 2 loops = “many”
First try: thread
PROXY_TO_PTHREAD || --proxy-to-worker == did not work with SDL & opengl
Main thread
Game thread
<waits in Atomics>
postMessage
Another try: post ImageBuffer
Very slow
Main thread
Game thread
postMessage with ImageBuffer
OffscreenCanvas?
WebGL commits on event loop
Main thread
Game thread
Canvas
OffscreenCanvas
Asyncify
Unwinds / rewinds call stack
“Pause and Resume WebAssembly with Asyncify, Alon Zakai”
Binaryen & JS
js_run_main()
wa_main()
main_loop()
render_frame()
get_time()
SDL_sleep()
sleep()
js_sleep()
return Date.now()
GLOBAL STATE = normal | unwinding | rewinding
char asyncify_stack[1000];
move_enemies()
It works!
Asyncfetchfs
Usual way is to preload everything
With Asyncify we can have async filesystem
Emscripten
JS
Asyncfetchfs
JS
__syscall_openat
WASM
stdlib
open()
WASM
fallout2-ce
fopen()
Issue with random freezing
___syscall_openat creates new stream everytime it runs
Emscripten
JS
WASM
Asyncfetchfs
JS
__syscall_openat
Here is side effect
open()
fd_read
In theory possible too
Emscripten
JS
WASM
wasi fd_read
Asyncfetchfs
JS
read()
Final FS layout
/ = MEMFS with no preloaded files
/app = asyncfetchfs
/app/data/SAVEGAME = IDBFS
/app/<temp1> = MEMFS
/app/<temp2> = MEMFS
Mostly no changes to original code
Spinwait for sound
while (! is_sound_buf_empty()) {
SDL_Sleep(1); // Add this line!
}
WebAudio scriptProcessorNode
read_data_from_SDL_buf()
Javascript code
Thanks!
Questions?