Upgrade to Pro — share decks privately, control downloads, hide ads and more …

EmscriptenでC/C++アプリをWASM化してブラウザで動かしてみた

 EmscriptenでC/C++アプリをWASM化してブラウザで動かしてみた

AGAWA Koji

June 12, 2024
Tweet

More Decks by AGAWA Koji

Other Decks in Programming

Transcript

  1. Compile your existing projects written in C or C++ —

    or any language that uses LLVM — to browsers.
  2. EM_ASM_JS / C → JS static int DrawStringWidth(lua_State *L) {

    int n = lua_gettop(L); assert(n >= 3); assert(lua_isnumber(L, 1)); assert(lua_isstring(L, 2)); assert(lua_isstring(L, 3)); int height = lua_tointeger(L, 1); int font = luaL_checkoption(L, 2, "FIXED", fontMap); const char *text = lua_tostring(L, 3); int width = EM_ASM_INT({ return Module.getStringWidth($0, $1, UTF8ToString($2)); }, height, font, text); lua_pushinteger(L, width); return 1; } EM_ASM_JSマクロでインラインで JSが書ける
  3. Asyncify EM_ASYNC_JS(int, paste, (), { var text = await Module.paste();

    var lengthBytes = lengthBytesUTF8(text) + 1; var stringOnWasmHeap = Module._malloc(lengthBytes); stringToUTF8(text, stringOnWasmHeap, lengthBytes); return stringOnWasmHeap; }); static int Paste(lua_State *L) { const char *text = (const char *)paste(); lua_pushlstring(L, text, strlen(text)); free((void *)text); return 1; } Cから同期的に JSの Promiseを解決できる
  4. cwrap / JS → C const onFrame = module.cwrap("on_frame", "number",

    [], { async: true }); onFrame(); EMSCRIPTEN_KEEPALIVE int on_frame() { lua_State *L = GL; draw_begin(); void *buffer; size_t size; draw_get_buffer(&buffer, &size); EM_ASM({ Module.drawCommit($0, $1); }, buffer, size); draw_end(); return 0; }
  5. WASMヒープ const wasmMemory = new WebAssembly.Memory(); const HEAPU8 = new

    Uint8Array(wasmMemory.buffer); WASMのヒープは JSから見ると単なる ArrayBuffer Emscriptenでは HEAPU8などの TypedArrayが公開されている JSで mallocして Cで freeなどもできる