WebAssembly 应用程序如何将其原生 Window / OpenGL / Vulkan 调用映射到 DOM 中的 canvas 元素?

How a WebAssembly application maps its native Window / OpenGL / Vulkan calls to a canvas element in DOM?

我正在阅读有关 WebAssembly 的文章,我很好奇如何将 Vulkan 或 OpenGL 等图形编程移植到 canvas 元素。文档很长,我想我最终会解决这个问题,但我很好奇并且没有成功地当场寻找答案。

到目前为止,我知道它可以将函数导出到 JS,而 JS 将像往常一样完成操纵 DOM 的肮脏工作。

我可以直接编写 WebGL,但这不是我的意思。我看过移植到 WebAssembly 的游戏,我想知道它是如何工作的。如果 WebAssembly 不能直接访问 DOM,它如何渲染任何东西?通常,图形应用程序使用外部 Window 管理器(如 GLFW or SDL)来创建 Window 上下文来绘制您的东西。

如果我确实使用此类库编译了一个程序,这些库期望启动具有某些 Window 对象的环境,那么如果没有这样的概念,这些指令将如何映射到 canvas DOM?我需要以某种方式调整我的 C++ 程序吗?

好的,原来答案在 the same page I was reading 上,但还差一点。

答案是需要有一个 Javascript “胶水”代码来加载 .wasm 并将本机库调用转换为 DOM 上下文,但你不需要编写它手。人们使用 Emscripten,它包括文件系统模拟、移植到最流行的媒体库(如 SDL),并且它生成 .wasm 代码及其对应的 JS 胶水。

来自Mozilla WebAssembly page

The Emscripten tool is able to take just about any C/C++ source code and compile it into a .wasm module, plus the necessary JavaScript "glue" code for loading and running the module, and an HTML document to display the results of the code.

In a nutshell, the process works as follows:

  1. Emscripten first feeds the C/C++ into clang+LLVM — a mature open-source C/C++ compiler toolchain, shipped as part of XCode on OSX for example.
  2. Emscripten transforms the compiled result of clang+LLVM into a .wasm binary.
  3. By itself, WebAssembly cannot currently directly access the DOM; it can only call JavaScript, passing in integer and floating point primitive data types. Thus, to access any Web API, WebAssembly needs to call out to JavaScript, which then makes the Web API call. Emscripten therefore creates the HTML and JavaScript glue code needed to achieve this.

限制:

Emscripten 仅支持完全可移植 C 和C++ 代码,您需要根据它们Portability Guidelines.

启用一些优化

此外,您需要牢记 Web 平台和 JS 运行时的固有限制,因此您无法直接访问文件系统,也无法进行同步(阻塞)网络调用,详见 API Limitations页。

OpenGL 和 Vulkan:

对于 OpenGL,具体而言,由于代码最终将转换为沙盒 WebGL 上下文,因此您需要将自己限制在 WebGL 提供的内容(即 OpenGL ES 2.0)。根据 Optimizing WebGL 页面,Emscripten 默认会将您的代码转换为 WebGL 1,功能较少且语法不友好,但支持更多平台。但是,您也可以针对 WebGL 2,它提供了更好的 API 和一些硬件优化。

对于 Vulkan,目前没有原生支持,但 W3C 中正在进行关于发布 WebGPU specification. This is their Github page with up-to-date information and the current browser support 页面的讨论。

Mozilla 也有一个实验性的 WebGPU Rust implementation,因此我们已经可以瞥见未来。