Best performance way to draw graphics in wasm?

Hello everybody!

I want to create a little (but performance) online game (like diep.io). The question arose as to how best to draw the graphics for the game, there are several ways:

  1. Use stdweb, wasm-bindgen, e t c

like this

  1. draw all graphics in js and store struct in rust

like this (sandspiel)

  1. low level methods?

like this (a bit simular to sandspiel)

3 Likes

Coincidentally I'm seriously researching this topic so I cannot claim to have all the answers. Please correct me if I misunderstood part(s) of the ecosystem.
In short, the answer depends on the bigger picture of the project.

Personally I found it hard to actually understand the point and benefits of the RustxWebassembly ecosystem. It helps to keep in mind that your WASM code becomes a dynamic library. A self-contained "portable brain" that you plug into a platform.
So you have a plugin, but to make it dance you need platform interaction. Typically this interaction is glue code that knows about the platform capabilities and your WA interface.

I found my confusion stems from the fact that web-sys exists, which promises that you can call WebGL and other methods directly from within WASM. The crate is called web -sys, which is a non accepted, but common convention for wrapping system native APIs into safe rust. The crates stdweb, js-sys and web-sys import javascript functions from the browser platform, which is not exactly native but it depends on how you look at it.
Utilizing the WASM sys crates comes down to writing glue code in rust or in javascript.

Let's say you decide to write all code in Rust. This hasn't answered the actual question; how to structure the distinction between platform(/glue) code and app code. This post goes a bit into how to structure your code (with diagrams) and shortly describes the experience of each approach.

So, following the advice of the mentioned post, you could follow the first approach on your list; Use the WASM entry point to construct a canvas, WebGL context and register itself with window.requestAnimationFrame, without leaving Rust. This is possible through the bindings from web-sys.
Thankfully others have walked this path before; gate, raze rgx, which left lessons for us to learn.
Both gate and raze have a very elaborate and manual glue layer written in javascript. I think primarily because of the requirement on specific javascript packages (eg audio).

But all the previous links are about engines and implementations of single-player games. The networking code should be considered in our evaluation! This is the point where I'm uncertain about a good approach.
The browser already has an event loop, so it's logical that our platform glue code handles threading and I/O; The browser will call into WASM when it's time to draw a frame or when socket data was received.

On the other side, there is this "ideal"(?) case where you "just" give a single thread to the, completely self-contained, WASM code and let it sort out everything itself. I/O or blanks are, according to this model, interrupts which preemptive/non-preemptive wake/schedule a rust future to perform the requested task. This is a literal brain analogy where sensory neurons are the interrupts.
I have no idea how feasible this idea actually is; I haven't found anyone else with a public source who did it like this. The WASM spec is also evolving still, I'm not familiar enough with the platform or spec direction to say this approach is supposedly supported.

I'm waiting for a blog post mentioning WASM+Async I/O that will come out next week which will shed some light onto the possibility of executors and rust futures in WASM (I hope).
Note that there is already a crate that abstracts "JS Promise" <-> "Rust Future". My initial impression of this crate was that it promotes platform event loops instead of WASM event loops, but the WASM+Async interview will definitely contain information about the direction of the WASM-team and possibilities.

2 Likes

I have no idea really. I guess it all depends on what you want to do.

I just came to say how much I love Cliff L. Biffle's solution to drawing from Rust/WASM in the browser. So small, so simple, so easy to understand.

Of course if you want to make a game with that you might have an adventure learning how to draw lines, polygons, filled shapes etc. It would be like the good old days of creating games for the old 8 biters, the Amiga or the Atari ST!

For a 2D game written in Rust/WASM I'd be wanting an interface to ivank.js http://lib.ivank.net/?p=demos&d=graphics to get the speed of WebGL in a simple way.

I'm currently very happy with Rust/wasm32 + raw WebGL (it's also not clear to me how to do better.)

You get the full power of WebGL vertex/fragment shaders (as limited as they are.)

Together with ArrayBufferObjects, all compute heavy floating point manipulations are all done in either:
(1) fragment/vertex shaders
(2) rust/wasm32 code

The only time you pay the cost of the Rust/wasm32 <-> JS layer is when making glClear / updating ArrayBufferObject / glDraw calls ...

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.