工作总结10.31:VTK获取canvas画布的坑/WASM编译ES6/WASM给JS传送字符串

VTK 获取画布异常

无论使用 Vtk.js 还是将 VTK 编译成 WebAssembly 添加到 web 上,两种方式都要更新页面上 canvas 画布达到显示 3D 场景的效果。

但根据实测,这个 canvas 元素的获取方法并不是随意的:

首先是正确的方式:1

<canvas id="canvas"></canvas>;

document.getElementById("canvas");

(错误示例)但是对于 Vue 2/3

<template>
    <canvas ref="_canvas"></canvas>
</template>

<script setup>
    import { ref } from 'vue'
    const _canvas = ref()
</script>

这种方式以及各种获取方式 (总之 canvas 没有 id) 会产生如下报错:

registerOrRemoveHandler: the target element for event handler registration does not exist, when processing the following event handler registration:……

此时页面只渲染一帧,同时画面会上跳一部分并且显示很虚。


为什么说这个问题很坑呢,因为官方文档没有任何提示,示例代码仅仅提供了代码,并没有提到 canvas id 除了获取元素之外的作用。在 Vue 框架下获取 canvas 的语法直觉上就会用 ref 获取,所以用这个语法代替后报错并不能轻易想到是 id 的副作用。

WASM 编译 ES6

vue/webassembly/opengl https://www.philxu.cn/vue/webassembly-vue-opengl.html#emscripten-编译-es6-模块

  -s WASM=1 \
  -s ASSERTIONS=1  \
  -s EXPORT_ES6=1 \
  -s MODULARIZE=1 \
  -s USE_ES6_IMPORT_META=0 \
  -s TOTAL_MEMORY=134217728 \
  -s EXTRA_EXPORTED_RUNTIME_METHODS='["ccall", "cwrap"]'

WASM给JS传送字符串

有两种方式:wasm直接发送字符串给js,或转换成Uint8发送指针给js去访问共享内存。

下面的官方文档中的形式:

官方文档:Embind — Emscripten 3.1.48-git (dev) documentation

示例:

C++端:

std::string test(std::string buffer,std::string name){
    std::cout << buffer.length() << std::endl;
    return "helo world";
}

EMSCRIPTEN_BINDINGS(module){
    emscripten::function(name:"test", fn: &test)
}

JS端:

module.test() // "helo world"

类型化数组方式2: Wasm By Example

Unit8方式: javascript - Passing a JS ArrayBuffer or TypedArray to Emscripten w/o Copying - Stack Overflow

JS向wasm发送字符串

axios("***url",{
        responseType:"arraybuffer"
    }).then(({data})=>{
        const uint8Array = new Uint8Array(data);
        // 调用c malloc方法分配内存
        const ptr = malloc(uint8Array.length,"xxxx")
        Module.HEAPU8.set(uint8Array,ptr)
    })
int malloc(int length){
    void* ptr = malloc(length)
    return int(ptr);
}

这种方式下ptr指向的一块内存地址被C和js共用,C开数组JS写地址就完成了通信。

其他参考资料:

注意上面两篇文章中Pointer_stringify方法已经改名为UTF8ToString:出处

Footnotes

  1. 文档: Building using emscripten for WebAssembly - VTK documentation 示例代码: VTK / VTK · GitLab
  2. Wasm By Example