This repository was created to see how feasible it is to use wazero to drive a small game engine (using Ebitengine). It simply sets up Ebitengine and exports a small api for wasm to import.
If you're trying to do something similar, hopefully this provides a decent starting point.
- Install the toolchain for the language you want to compile (zig, rust, odin, tinygo, assemblyscript)
cd
into their[lang]-game
directory- run
./build.sh
(this will create agame.wasm
file in the root directory) - run
go run .
in the root directory to start the game
Below are a few grain-of-salt metrics I've gathered for each bunnymark-styled demo. This isn't intended to be a direct comparison of performance, more to see how much overhead there is when calling between wazero/wasm and go.
Note: these were ran on a 2022 M2 MacBook Air (8GB)
Language 60 Fps Max 60 Tps Max (Avg. Fps)
asc 22,000 71,000 (14)
odin 23,000 88,000 (15)
zig 24,000 83,000 (15)
go 25,000 94,000 (15)
rust 25,000 94,000 (15)
Below compares this approach to other ways I've tested:
Runtime 60 Fps Max 60 Tps Max (Avg. Fps)
go/goja 2,000 3,000 (18)
go/gopher-lua 13,000 22,000 (19)
go/browser[1] 13,000 49,000 (14)
go/wazero[2] 53,000 184,000 (15)
go/native[3] 55,000 192,000 (15)
go/native[4] 64,000 230,000 (14)
- 60 Fps Max: number of entities before consistent fps is below 60
- 60 Tps Max: number of entities before consistent tps is below 60
- Avg. Fps: average fps when tps is passed tps max
- Ebitengine Sprites Example
- BrutEngine (my custom wasm engine)
- Ebitengine Bunnymark
- Gophermark
From my tests, embedding wasm/wazero within a native go application performs better than embedding lua/js or running wasm in the browser. However, as expected, both still perform significantly worse than native compilation.
Keep in mind that "bunnymark" isn't a definitive benchmark and your mileage may vary.
Public Domain