fenster icon indicating copy to clipboard operation
fenster copied to clipboard

Added emscripten support

Open wernsey opened this issue 1 year ago • 3 comments

Hi, thank you for fenster. It is really nice to just drop the file into a directory and have a demo ready to go.

I spent some time adding support for emscripten in my fork because I wanted my demo to be runnable in a web browser as well.

I've modified the makefile in the drawing-c example to demonstrate how to build it once your emscripten environment is set up. It will create an output directory web/ that contains all the HTML, JavaScript and wasm files. There is also a serve target in the Makefile that will use Python3's http module to serve the application on http://localhost:9000/ for testing purposes .

wernsey avatar Oct 15 '24 10:10 wernsey

SDL seems inappropriate for Fenster.

vaguinerg avatar Oct 15 '24 14:10 vaguinerg

@CardealRusso it's a bit of a trick, since this is only using SDL from emscripten, which is a shim around canvas. You can do this stuff other ways, but it's not as terrible as it might seem (it's not like re-making fenster on top of SDL, it's more like building on the SDL2 shim-functions that operate on canvas, only on emscripten.) The alternative is that you end up hand-implementing the same stuff they did in the SDL-shim yourself, for no reason, with less eyes on it for testing, missing some tricks they already worked out. Then you have to expose host-functions to give your special functions access to the canvas.

I often don't use emscripten for WASM that doesn't need it (like native plugins or whatever) but it does have a place (like here, where you can use the much simpler SDL API to mess with canvas, and lose nothing.) it's important to note that any interaction with canvas requires host-level functions, like it's not built into wasm or something, no matter how you make your wasm. You can either expose these yourself, or use WASI for file-like objects, or just use what emscripten provides, but they all work the same.

Here are a couple examples of not doing it the "emscripten way":

  • I made web-zen-dev to be able to use WASI with a file-like framebuffer devices
  • I am making a game engine that runs the same wasm on native and web. I expose WASI and functions that are used for drawing, and emscripten is not available in native (host is written in C, and is not a browser)

In both these places it makes sense to not use the emscripten wrappers, because the host doesn't run JS (so no emscripten) or fit neatly in WASI file-access (like piping to /dev/fb0, where you still need an interceptor function in the host to handle that.)

I also made the web-target for pntr_app where we use Module.ctx.putImageData(Module.screen, 0, 0); (and also setup Module.ctx in init) but that ends up not that much different from using the SDL shim, in terms of performance or code-size.

I think the real test is to make an alternative non-SDL emscripten canvas version, and compare them, but it's a lot of work to verify what I have already found: it's a little smaller, more of a PITA to maintain, and not really better, in terms of performance or anything else.

konsumer avatar Feb 16 '25 05:02 konsumer

I dunno, to be fair, and make sure I was correct in my assertions, I did just end up implementing it.

Seems not too bad actually (fenster has a nice & simple API) but because of sync-time-stuff assumptions (things that work in C native, but not web) it requires you to add ASYNCIFY to build, which adds a ton of js, behind the scenes (more than SDL does, by itself.) I still think I agree with you, though, since there is no SDL code, and it is maybe a lil simpler. I am probly missing some tricks the SDL people did, but maybe that is ok.

It would be better if there was a "do a loop until you should not" method that wraps around the loop-function. As it is, I use async in fenster_loop to pause a bit, so it doesn't max-out and freeze the main-loop.

I will clean it up, and add a PR.

konsumer avatar Feb 16 '25 06:02 konsumer