PoC of running Doom on top of GraalVM
At Stepstone, as part of our internal brown bag session, we talked about polyglot capabilities of GraalVM. We know, that GraalVM can run javascript, python, llvm and especially WebAssembly. But...
Can it run Doom? :suspect:
So, we took Doom port compiled to WebAssembly created by @diekmann and ran it on top of GraalVM. See Internals for implementation details.
This program was written on GraalVM 17+ v22.3. You must install wasm support by running gu install wasm
.
:warning: To run correctly, you must increase stack size with
-Xss4m
From IDE - just run com.stepstone.jc.demo.Doom
class
From the command line - compile with mvn package
and then run with:
java -Xss4m -jar doom-wasm-1.0-SNAPSHOT-jar-with-dependencies.jar
After this, you should see a Java Swing window and you can start killing monsters :godmode:
The process of porting Doom to WASM is described in the original repo.
GraalVM's support for WASM, for now, is very basic. One important missing feature is the ability to inject java object with bindings, which will be called by the wasm program.
Just running context.eval("wasm", doomWasmBytes)
will lead to unresolved dependency one env
and js
modules.
There is no direct equivalent of javascript's WebAssembly.instantiate accessible from standard GraalVM polyglot context. That's why we need to do some hacking. We use methods accessible by WebAssembly bindings to read and instantiate the WASM module, and to create an instance of WASM memory.
What we need to do:
js
and env
objects inside (com.stepstone.jc.demo.Bindings
)doom.wasm
module using com.stepstone.jc.demo.WASMModule.module_decode
com.stepstone.jc.demo.WASMModule.module_instantiate
main()
function to setup gamedoom_loop_step()
It is also possible to compile GraalVM-WASM-based Doom into the native image.
First, you need to run mvn package
and then run native-image
:
native-image --language:wasm --initialize-at-build-time=sun.awt.Toolkit -Djava.awt.headless=false -H:ConfigurationFileDirectories=native-config -H:DynamicProxyConfigurationFiles=native-config\dynamic-proxy.json --no-fallback -jar target\doom-wasm-1.0-SNAPSHOT-jar-with-dependencies.jar
This way you will have Doom compiled to LLVM, compiled to WASM, wrapped in the Java Swing app, and compiled to native code. Simple, right? ¯_(ツ)_/¯