godotengine / godot-proposals

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

Build a tiny RISC virtual machine which can interpret and execute GDExtensions #10071

Open fire opened 1 week ago

fire commented 1 week ago

Describe the project you are working on

V-Sekai is a self-hostable MIT open source software stack built with Godot Engine 4. This project aims to provide a robust and flexible platform for game development.

Describe the problem or limitation you are having in your project

The main challenge we're facing is the inefficiency of compiling gdextension for multiple platform variants. Running a custom engine isn't feasible due to lack of adoption. We want more efficient and flexible ways to handle gdextension binaries. Additionally, we're interested in exploring the possibility of players distributing riscv binaries as user-generated scripts inside of godot scenes. As part of our future work, we plan to convert gdscript bytecode via string templating the bytecode as c and compile it with the TCC c compiler.

Describe the feature / enhancement and how it helps to overcome the problem or limitation

To address these issues, we propose building a tiny RISC virtual machine capable of interpreting and executing GDExtensions. The entire gdextension API would be wrapped and compiled as RISCV binaries. These binaries would function like shared libraries via librisc emulation, either as an interpreter or a register machine. An interpreter would allow us to maintain the fast developer iteration times that Godot Engine is known for, while an ahead-of-time compiled riscv binary would offer greater efficiency. We have already implemented instruction count limits.

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

Our approach involves using libriscv's vmcall to call into the riscv gdextension binary and exchange data. Here are some resources that will aid in this process:

  1. libriscv VM Call Documentation - Detailed documentation on making function calls into the VM guest.
  2. tcc
  3. Godot Orchestrator
  4. @shakesoda has provided an implementation of riscv processors in Godot Engine via zig language as a reference.

If this enhancement will not be used often, can it be worked around with a few lines of script?

The alternative to using compiled code is slower gdscript or utilizing the godot orchestrator. However, these options may not provide the same level of efficiency and flexibility that our proposed solution offers.

Is there a reason why this should be core and not an add-on in the asset library?

While this could potentially be developed as an addon, we are currently tracking the proposal in godot-proposals for better visibility and collaboration. More information can be found at godot-riscv.

fire commented 1 week ago

Thanks @fwsGonzo for assisting me with my questions.

octanejohn commented 1 week ago

1 doesnt web need wasm output anyway and most langs support wasm, gdscript could target it too instead building two paths

2 i know wasm doesnt work with how godot operates on non-web but with libgodot and hacking the wamr runtime separating scripting from inside godot it could work? example gdscript(any lang)>wamr<>libgodot>gd extention game instead of gdscript>godot game>wamr

3 is libriscv an ir like mlir llvm, what is its goal?

fire commented 1 week ago
  1. @octanejohn My conversation from my friend who worked on scripting for https://github.com/matrix-org/thirdroom mentioned they used a wasm quickjs to execute user scripts due to browser security.

If we've already got gdscript in wasm, we can already use it. Like there's no benefit.

If we can compile gdscript (feature doesn't exist) then we can also compile that to riscv (feature doesn't exist for basically the cost of a gcc compiler invoke).

  1. We spent years trying to get wasm wamr to work and it was too difficult.

  2. riscv is an instruction set standard like amd64 or arm64.

octanejohn commented 1 week ago

2 the wasm to godot i seen it wasnt with libgodot but if its easier and works with consoles no problem 3 so riscv isa is used like a low level intermediate representation, cool

fire commented 1 week ago

https://github.com/fwsGonzo/libriscv/pull/174

Adds support for embedded sandboxed code. This would allow platforms without support for dynamic linking to ship with full binary translation performance. Essentially, this means that the code can be executed directly without needing to be linked at runtime, which can improve performance.

This could potentially be beneficial for loading gdextension modules as it could speed up their execution.

fire commented 1 week ago

https://github.com/fwsGonzo/godot-riscv/issues/1

We discussed creating a proof-of-concept plan to validate the general idea.

  1. Implement shared object loading, verify able to fetch address of dynamically loaded functions
  2. Verify shared object works with binary translation
  3. Output embeddable C code for shared object
  4. Verify embeddable C code works. Eg. run it on Windows.

Edited:

So 3 and 4 relates to https://github.com/fwsGonzo/libriscv/pull/174

Edited:

1 and 2 are also completed.

Edited:

Shared executables are implemented, but not loading a specific symbol

Edited:

Shared libraries are implemented, but crashing on a jump to a garbage location.

octanejohn commented 1 week ago

it looks libriscv is simpler toolchain than what wasm is trying to do, very cool https://github.com/WebAssembly/wabt/tree/main/wasm2c https://github.com/dylibso/hermit https://github.com/bytecodealliance/wasm-micro-runtime/blob/main/doc/embed_wamr.md https://bytecodealliance.github.io/wamr.dev/blog/the-wasm-host-sharing-data-basics/ edit1 i forgot this link https://ziglang.org/news/goodbye-cpp/

fire commented 1 week ago

Since we can now load shared executables the next step is to load and execute a hello world function call with a shared object.

https://github.com/fwsGonzo/libriscv/issues/175#issuecomment-2198599790

JosephCatrambone commented 1 week ago

There may be a few folks who, like me, misread this ticket slightly. I was thinking initially, "This is adding RISCV as a compile target for Godot extensions. If that is the case, why not add WASM as a target VM?"

This proposal is not that.

This proposal is, "Let us build a very tiny RISC virtual machine which can interpret and execute GDExtensions not targeted for it." That's a much more interesting prospect in my mind, especially if it's safe and performant. I very much like the idea that it might eventually become a bytecode for GDScript, too.

fire commented 1 week ago

We're working in @fwsGonzo 's discord https://discord.gg/ExhqfFMCDz feel free to join or discuss building a tiny RISC virtual machine which can interpret and execute GDExtensions.

fire commented 1 day ago

In https://github.com/fwsGonzo/godot-riscv 2b9eb6f0fb66745fafae3311a97f56f932763131 we implemented a print function from the RISCV machine in RISCV emulator that calls the host gdextension's print method.