Open4

WebGL-Native: 脱Node.jsの準備

okuokuokuoku

prev: https://zenn.dev/okuoku/scraps/1128673fdb2a15
next: https://zenn.dev/okuoku/scraps/1d00a240007452

Node.js依存から脱却する

... Node.jsから脱却といっても幾つかのポイントがある:

  1. Node.jsのライブラリに依存しないようにするfs とか、 process とか。
  2. npm でインストールするライブラリに依存しないようにするffi-napi
  3. 最近のECMAScriptの機能に依存しないようにする 。アロー構文とか。

最後のはBabelでも何でも通せば良いので、依存ライブラリの処理がもっとも重要と言える。雑に grep したところ、

  • Node.js標準ライブラリ: fs path crypto (のrandomBytes) ws perf_fooks (のperformance)
  • npmのモジュール: ffi-napi ref-napi weak-napi

に依存しているようなので、それらをやっつける事を考える。

okuokuokuoku

作戦

よく見てみると npm の依存は全てFFI関連なので、これを置き換えるのが最初のステップとしては妥当だろう。

  • ffi-napi : NCCC に置き換える
  • ref-napi : 今使用しているのは Buffer のポインタを得る場所だけっぽいので、 1) メモリ確保をネイティブ側に移す 2) ネイティブ側のポインタを指すような ArrayBuffer を生成できる仕組みを考える。
  • weak-napi : ... ちょっと良いアイデアが無い(Node.js以外の処理系でも共通して使えるようなweak pointerの仕組みを考える必要がある)

最初の作業でいきなりUnityをターゲット してかなり後悔したので、まずは 前回まともな速度で動くようになった DOSboxをターゲットに、使用しているネイティブ関数をNCCC化することを考える。

DOSboxはレンダリングに直接はWebGLを使用せず、 こちらで用意した適当なCanvasエミュレーション を使っている。よって、必要なWebGL APIもそこまで多くはない。

okuokuokuoku

wrap対象のAPIを分離

とりあえず最初のwrap対象になるAPIを分離しておいた。

https://github.com/okuoku/cwgl-proto/commit/94abc89b43b60d475e19c17a6990c55741131f15

で、

YFRM_API cwgl_ctx_t*
yfrm_cwgl_ctx_create(int32_t width, int32_t height, 
                     int32_t reserved, int32_t flags);

のようなAPIを、↓ のようなある種のDSLで表現することにして、

nccc_api(yfrm_cwgl_ctx_create
    IN u32 u32 u32 u32
    OUT ptr)

そして、この記述を以下のようなCヘッダに出力するCMakeスクリプトをこれから書く。

#define FORWARD_STUB_EXPAND(x) \
    x(arg,void,yfrm_init) \
    x(void,void,yfrm_terminate) \
    x(arg,ret,yfrm_cwgl_ctx_create) \

#define SYM_yfrm_cwgl_ctx_create_NAME "yfrm_cwgl_ctx_create"
#define SYM_yfrm_cwgl_ctx_create_IDX 4
#define SYM_yfrm_cwgl_ctx_create_STUB_TYPE forward_0
#define SYM_yfrm_cwgl_ctx_create_ARG_COUNT 4
#define SYM_yfrm_cwgl_ctx_create_RET_COUNT 1
#define SYM_yfrm_cwgl_ctx_create_ARG_EXPAND(x) \
    x(0,arg,u32) \
    x(1,arg,u32) \
    x(2,arg,u32) \
    x(3,term,u32) \
#define SYM_yfrm_cwgl_ctx_create_RET_EXPAND(x) \
    x(0,term,ptr) \

... これは wasm2c の出力をDLL化したとき と非常によく似たやりかたではあるが、共通点をくくり出すのが面倒なのでもう一度書きなおすことにした。

WebAssemblyの場合は↑に書いたような内容はバイナリ中のexport/import情報として埋め込まれているのでそれを抽出すれば良かったが、今回のようにCで書いたAPIの場合は手書きするか適当なスキャナで抽出してやる必要がある。

機械的にやれば良いじゃんというのはそれはそれで正しいけど、エクスポートしたいかそうでないかをアノテートしてやる必要もあるので。。既存のAPIをスキャンしてAPI定義を抽出するものとしては、最近だと win32metadata のようなプロジェクトがあるが無限の金があるMSをもってしてプロジェクトのリリースは年末を予告している。真面目にやろうとするとそれくらい難しい。

okuokuokuoku

バインディングできた

https://github.com/okuoku/cwgl-proto/commit/7d230f8411225c9610fce4ceec8bf1a6f52fa9b6#diff-7fc3da5e106081f036cc7df89bd3679c6bff2aa5d9e6b555eb3d06e8152f1ec7R1

... 手書き。。DOSboxで使っているぶんだけにしようと最初は思ってたけど、ちょっとポインタの扱いを真面目に考えないとダメそうなのでとりあえず全アプリが動く状況をキープしながら作業することにした。

  1. 文字列をポインタ渡しするには変換する必要がある
  2. ArrayBufferのアドレスを得るAPIが別途必要
  3. Weakポインタの存在を忘れてた

現状では文字列をNCCC関数に渡せないので動かない(シェーダがコンパイルできない)。