godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.11k stars 69 forks source link

Add WASM (WASI) host support (including, but not limited to, the HTML5 target) #147

Open Type1J opened 4 years ago

Type1J commented 4 years ago

Describe the project you are working on: I am working on an app that needs updates often due to new features.

Describe the problem or limitation you are having in your project: Replacing a GDNative dll is how we currently need to distribute new updates. Each platform needs it's own dll. The dlls are written in Rust. GDScript isn't an option due to the CPU intensive tasks in other threads that we are performing.

Describe how this feature / enhancement will help you overcome this problem or limitation: Only 1 .dll (.wasm) file will need to be produced, and it will work on all platforms

Show a mock up screenshots/video or a flow diagram explaining how your proposal will work:

Current: Windows -> .dll Linux -> .so macOS -> .dylib HTML5 -> Currently not supported, but desired Android -> .so iOS -> Currently not supported, but desired (for our project)

After proposal: Windows, Linux, macOS, HTML5, Android, and iOS (potentially more) -> .wasm

Describe implementation detail for your proposal (in code), if possible: The .wasm dynamic library would basically implement the same API as GDNative dynamic libraries currently do. See wasmer and WASI (https://wasi.dev/) for an example host native application.

If this enhancement will not be used often, can it be worked around with a few lines of script?: No. Currently, this is a build system and distribution problem. The feature is the only option for a GDNative library for HTML5, and it can be used to prevent the need for other proposals to go into the core.

Is there a reason why this should be core and not an add-on in the asset library?: It enables asset libraries to make "native"-ish extensions that can be used on multiple platforms. They may not be as fast as true native, but they are faster than GDScript by far, and enable legacy code in the same way that GDNative does, but WASI also provides sandboxing support that GDNative does not have, which reduces the security audit required in some cases with asset library GDNative dynamic libraries.

Bugsquad edit (keywords for easier searching): WebAssembly

Calinou commented 4 years ago

See also https://github.com/godotengine/godot/issues/28303.

Frontrider commented 4 years ago

You could try using this: https://wasmtime.dev/ This is a standalone webassembly vm, with a lot of embedding options including C, WASI included.

This one also means that Godot would supports a huge number of languages without any specific runtimes. Debugging is a real question tough, as I don't know if webassembly has any way to map the bytecode back to whatever it was compiled from.

robbiespeed commented 4 years ago

As a stepping stone why not keep the existing structure of compiled per platform libraries, but add wasm to the list for the web platform. Later it could be tested weather allowing wasm to be used for all platform builds via some wasm runtime should be added as an option, by testing the performance impact that would introduce.

Type1J commented 4 years ago

We are already using a Rust GDNative plugin that includes wasmer-runtime and loads a .wasm library that is switched out. We still don't support HTML5, but we've worked around this issue for now. I believe that it should be resolved before we expand to HTML5 and iOS.

Frontrider commented 4 years ago

@robbiespeed Things that are designed for the web are always fast. That's one of the main business targets. Faster execution means that your customer gets to your products sooner. Overly optimized javascript is not that much slower than native code (the parsing is the part where it has a small slowdown, yes I was surprised), and webassembly is even faster than that. https://takahirox.github.io/WebAssembly-benchmark/

robbiespeed commented 4 years ago

@Frontrider yes wasm is faster than javascript (in some workloads), and we have come a long way in performance on the web, but it is still slower than native compiled code.

Here's a fairly in depth paper on wasm vs native performance https://arxiv.org/pdf/1901.09056.pdf

In that paper it describes that on average in their tests wasm performed roughly 1.5x slower than native.

Frontrider commented 4 years ago

@robbiespeed I know that it's slower. Nothing is faster than native at this point. I personally don't think speed is going to be an issue for now (it's already faster than whatever runtime this small-ish team could produce on their own), and the plan is to compile gdscript to webassembly and that would be a big speedup on it's own. (I'm personally fond of gdscript, even tough I do not like python's syntax) The benefits of not needing to write any specific compatibility layers for a large chunk of languages/tools is also big one.

And yes I agree, GDnative should remain and be improved, because there is a clear usecase for it.

Calinou commented 4 years ago

and the plan is to compile gdscript to webassembly and that would be a big speedup on it's own.

I don't think that's currently planned.

robbiespeed commented 4 years ago

@Frontrider this proposal if I interpreted it correctly is about introducing wasm as a build target for gdnative projects, and replacing existing gdnative generated platform specific libraries with wasm, so that you only need to have one build target.

I am very much looking forward to the first part, because we need that in order to have web as a supported build target for gdnative projects. I don't think the second part is a good idea though unless it were optional, even then I don't see much benifit.

TheRawMeatball commented 4 years ago

This seems like the place where HTML5 support for gdnative is tracked, is this feature (primarily the first part) on the roadmap?

Calinou commented 4 years ago

@TheRawMeatball Support for GDNative in HTML5 may happen in the future, but there's no target version.

follower commented 4 years ago

A way to call WebAssembly functions from Godot desktop apps today

I started on a project last year to integrate the Wasmtime WebAssembly runtime with Godot for desktop (Linux, Mac & Windows).

Over past couple of days I finally did a public release of the project "WASM Engine for Godot" (MIT License) in its current WIP stage if you're interested in checking it out: https://gitlab.com/RancidBacon/godot-wasm-engine

Current implementation details

The add-on is implemented on top of Foreigner--a wrapper for the libffi Foreign Function Interface library--along with some additions for buffer/struct support. (And is in part a demonstration of why I think FFI/ctypes-style support in the core would enable more functionality to be added (& added more easily) to Godot.)

The use of Foreigner means that the libwasmtime wrapper is written entirely in GDScript and further functionality from Wasmtime can be exposed without writing or compiling any C/C++: https://gitlab.com/RancidBacon/godot-wasm-engine/-/blob/main/src/addons/wasm-engine/WasmEngine.gd

The current wrapper was handwritten (in part because I was still figuring out how to embed libwasmtime as the C API was pretty under-documented when I started) but after gaining further experience with wrapping another complex library I'd probably look at doing more scripted generation of the binding moving forward.

Demonstration projects

There are two demonstration projects built on Godot which have binaries available for download for Linux, Mac & Windows:

So, even in the add-on's current WIP state (which requires functions called must have no parameters and either return a 32-bit integer or nothing; and, a module must not require any external imports) it's still possible to do interesting things.

Interested to have people try out the project & to see what WASM execution functionality can enable for Godot with some concrete examples. Thanks!

sunnystormy commented 4 years ago

Hello! I'm another proponent of adding this feature to Godot by default. As someone who does hardware development with OpenSource ISAs (RISC-V, OpenPOWER) it would be useful to have a platform-agnostic binary that could be used to demonstrate graphical applications. Thank you!

kirawi commented 4 years ago

I'm interested too, but I have a feeling it won't be added for a while. In the big scheme of things, most people aren't using GDNative for their games.

Frontrider commented 4 years ago

I'm interested too, but I have a feeling it won't be added for a while. In the big scheme of things, most people aren't using GDNative for their games.

Don't get me wrong, but if something is this tedious to set up, with this amount of extra steps (compared to alternatives it is like that) then of course it won't be widely used. Convenience is a big strength.

Webassemby at least has a merit of being fully integrateable to the editor as is, because you should be able to read the library in a more convenient way. It's not out of bounds to have a dropdown where you can just pick methods from the exported webassembly file, like "map my _ready function to the exported function unit_ready", because at worse (terrible solution) you can regex out the exported names from the textual representation unlike with other binary formats. The textual may even be enough for Godot, as we can build the binary as we package the game.

fire commented 3 years ago

If we wanted to build wasm into godot engine, here's another approach:

Advantages:

Disadvantages:

GeorgeS2019 commented 3 years ago

To all, I still not having the overview yet for Godot and WASM. Is it possible to export Godot WASM with JavaScript callable methods and callback that allows the exported Godot WASM embedded in HTML5 as a Web Component serving as 3D Viewer?

If this can be done based on discussions in this thread, what will be the practical way to do that? This functionality serving as plugin? How to make that a plugin module. The plugin module essentially serve to broadcast events in godot 3D to outside world as callbacks and expose methods that allow outside JavaScript to access Godot internal Node properties and functions.

I value your feedback and suggestion.

Calinou commented 3 years ago

Is it possible to export Godot WASM with JavaScript callable methods

Calling JavaScript code from GDScript is possible, but calling GDScript from JavaScript isn't (see https://github.com/godotengine/godot-proposals/issues/286).

callback that allows the exported Godot WASM embedded in HTML5 as a Web Component serving as 3D Viewer?

Godot's HTML5 export is designed to be on its own page. While you can customize the export template, it's not a Web Component you can place on arbitrary pages and expect it to work.

GeorgeS2019 commented 3 years ago

@Calinou During initialization, it is possible for OUTSIDE to pass in a series of string argument through engine.start() By using GDScript call JavaScript, perhaps a way to redirect events and messages from within Godot to OUTSIDE.

Perhaps potentially, having a WASM as plugin that serve as the BRIDGE server between INSIDE and OUTSIDE. During Engine Init, the intended URL for the bridge server is being passed as argument for engine.Start().

I hope to use Godot as a sophisticated 3D viewer.

I do not yet have the overview, looking forwards for any other ideas.

Calinou commented 3 years ago

@GeorgeS2019 Please use other community channels to ask support questions. This place is meant to discuss feature proposals; please don't derail them.

fire commented 3 years ago

@follower Were you able to match the entire GDNative api? Was curious about your https://gitlab.com/RancidBacon/godot-wasm-engine implementation.

Last night we got WASM defined functions with arguments returning to Godot Engine. We're using https://github.com/bytecodealliance/wasm-micro-runtime.

Zireael07 commented 3 years ago

@fire: Got a demo anywhere?

MMMaellon commented 3 years ago

Demo of the WASM stuff fire was talking about: https://drive.google.com/file/d/1CYvogO4F9URhvFvZIDsxyVQWVupymLcv/view?usp=sharing

Use the godot exe to open the project that's in the folder next to it and then hit run. WARNING: I never got around to fixing an issue with one of the particle systems. It's playing all the time and causes overdraw and lag. In the editor, zooming out all the way or disabling the particle system will fix this. In game, just keep moving so that the particles don't draw on top of each other. Sorry for the mess.

The source code for this demo is here: https://github.com/V-Sekai/WasGo/tree/main/demo

kisg commented 2 years ago

With the implementation of the new GDExtension API it should be possible to integrate WASM into Godot quite well:

blockspacer commented 2 years ago

@kisg Awesome news! Where can i find some usage examples or docs about WASI usage within godot engine? Thank you in advance.

kisg commented 2 years ago

@blockspacer AFAIK this suggestion with the GDExtension API (and the related #3370) is not implemented yet, my goal was to check if there is interest / objections from the core developer's side. An equally important proposal is in my opinion #3369, which would simplify the engine considerably, but unfortunately it did not get much interest until now.

hansondr commented 1 year ago

Apologies for a bit of necromancy but as another option Wasmtime recently reached 1.0

Frontrider commented 1 year ago

Not just simplify the engine, but as a side effect also remove the "tear" that the engine currently has along c# and GDScript. Typed GDScript is even a good target for webassembly, as it does not need garbage collection.

fire commented 1 year ago

I've been sketching how to do wasm based gdscript and other extensions based on c++ wasm3.

kisg commented 1 year ago

Good to hear @fire. Do you intend to use the CodeGenerator interface in the GDScript runtime to emit WASM bytecode instead of GDScript bytecode? Would love to hear more. :)

fire commented 1 year ago

You can check the repo here https://github.com/Geequlim/ECMAScript

Frontrider commented 1 year ago

Thinking about it, could it also allow Godot to focus more on GDScript's syntax and usability? Wasm is quite fast on it's own already. You can also try to integrate existing wasm optimizers instead of trying to develop an in-house solution.

Compilation speeds matter, but not as much as execution speed.

Calinou commented 1 year ago

Thinking about it, could it also allow Godot to focus more on GDScript's syntax and usability? Wasm is quite fast on it's own already. You can also try to integrate existing wasm optimizers instead of trying to develop an in-house solution.

I don't think GDScript should depend on a WebAssembly runtime being available. There are likely cases where WebAssembly is not usable or only available in limited form (e.g. on consoles). Moreover, building the WebAssembly runtime from source is probably not easy, especially if you don't have a Rust toolchain installed. We want Godot to remain fast and easy to build from source after all :slightly_smiling_face:

kisg commented 1 year ago

@Calinou To be clear, I am not saying that the new GDScript interpreter should be thrown out.

But the concerns that you raise are not really an issue for a WASM-based runtime:

So I think that a WASM-based alternative runtime for GDScript would have a lot of benefits, and with the WASI standard already widely implemented, it would be straightforward to provide bindings to the rest of Godot inside the WASM runtime. Now that the GDScript Runtime has a nice abstraction for bytecode generation, it should be easier to create this alternative runtime.

aunyks commented 1 year ago

Hoping to keep this open. I compile the core simulation of my game to a WASM binary for portability and would love to use Godot as an interface for the sim (right now I use the web, Bevy, and raylib as interfaces that use the .wasm file).

ManicMarrc commented 1 year ago

Is there any news about this proposal?

fire commented 1 year ago

https://github.com/ashtonmeuser/godot-wasm is an attempt in the area.

fire commented 7 months ago

I was able to run blender on a wasi host with https://github.com/ktock/container2wasm.

This sample takes a blender container from New York Time's engineers and compiles it to a 1.5 gigabyte wasm file which is then loaded and executed. This is unoptimized, but shows how a WASI host can be used to load arbitrary amd64 and also riscv docker containers.

The blender command creates a monkey mesh primitive that is then saved as fbx.

In theory, Godot Engine containers should run too.

Although networking was described as working, I was only able to mount host to wasm directories and use stdio for the shell.

container2wasm gives a new promising use for WASI hosts.

.\c2w  -build-arg VM_MEMORY_SIZE_MB=1024 nytimes/blender:3.3.1-cpu-ubuntu18.04  blender.wasm
wasmtime --dir ../out::OUT -- blender.wasm blender -b --python-expr "import bpy; bpy.context.scene.render.fps = 30;bpy.ops.object.select_all(action='SELECT'); bpy.ops.object.delete(); bpy.ops.mesh.primitive_monkey_add(); bpy.ops.export_scene.fbx(filepath='/OUT/monkey.fbx')"

Here's an image of blender counting vertices.

image

Frontrider commented 7 months ago

As someone who wants this, I think I drop one thing in on why it should NOT be officially supported yet.

Godot will NEED to support the web assembly component model, but it is not in a production ready phase yet. https://component-model.bytecodealliance.org/

This is a must, because this lets Godot use all the existing (or ones that will exist) compiler infrastructure. Even if it would be restricted to one language for some reason, there is no real need to maintain the compilers specifically for this one engine.

And I still think that it is an amazing idea, as now it can let any "native extensions" to be running on any platform, because the maintenance cost for any given platform goes from "compiler for each language for each target" to "compile standard web assembly to the target's native code as needed".