このサイトは、只今WEB業界で活躍中のデザイナー、プログラマーの方々の情報を集めたweb統合情報サイトです。

Archives Details

Webassembly用いて、SDL 2.0をブラウザでレンダリング

C++

2020.08.10

この記事は最終更新日から1年以上が経過しています。

どもです。

お仕事で、ちょいとWebassembly扱う機会(前の話になりますが。。)ありましたのでメモ程度にと。

もろもろ調べていましたら、SDL 2.0もレンダリングできるとの事でしたので、早速テスト。

環境

macOS Mojave 10.14.5

Python 3.7.0

nodejs 12.18.1

Emscripten インストール

先ずは、ともあれ、Emscripten(エムスクリプトン)コンパイラが必要となって来ますので、インストールをして行きましょう。

Emscriptenとはなんぞやですが、Emscriptenは、C++ から生成される LLVM ビットコードを入力に、ウェブブラウザや Node.js などで動作する JavaScript を出力するコンパイラとなっております。

公式サイトとGitHubレポジトリは以下の通り。

Emscripten

http://emscripten.org

GitHub

https://github.com/emscripten-core/emscripten

こちらのダウンロード(インストール)方法に沿って実行していきます。

こちらのページより、各環境に沿ったインストール方法が記載されております。

https://emscripten.org/docs/getting_started/downloads.html

$ git clone https://github.com/emscripten-core/emsdk.git
$ cd emsdk

公式ドキュメントより

git pull

# Download and install the latest SDK tools.
./emsdk install latest

# Make the "latest" SDK "active" for the current user. (writes .emscripten file)
./emsdk activate latest

# Activate PATH and other environment variables in the current terminal
source ./emsdk_env.sh

と、会社のPCでは何も問題なかったのですが、自宅Macだと、

<urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:749)>

と、

SSL: CERTIFICATE_VERIFY_FAILEDのエラーが吐かれてしまった。。

何か足りないのか。必須となりそうな所は公式サイトでは、以下の通り。

Node.js (0.8 or above; 0.10.17 or above to run websocket-using servers in node):
Python 2.7.12 or above, or Python 3.5 or above (Python 2.7.0 or newer may also work, but is known to have SSL related issues, https://github.com/emscripten-core/emscripten/issues/6275)
Java (1.6.0_31 or later). Java is optional. It is required to use the Closure Compiler (in order to minify your code).
Git client. Git is required if building tools from source.
LLVM (LLVM, including clang and wasm-ld)
Binaryen (Binaryen, including wasm-opt, wasm-emscripten-finalize, etc.)
The Emscripten code, from GitHub

こちらから確認できます。

https://emscripten.org/docs/building_from_source/toolchain_what_is_needed.html#toolchain-what-you-need

エラーから見てみると、どうもpyhonの証明書のパスが通っていないぽい。。

pyenvを利用しているからかも。

どうやら、certifiパッケージあれば良いみたいなので、pipコマンドでインストール。

$ pip install --upgrade certifi

(デフォルトをpip3にしている)

インストール完了後、pythonインタプリタ実行。

$ python
>>> import certifi
>>> certifi.where()

上記のコマンドで、 certifi/cacert.pem のパスが表示します。

以下のコマンドでパスを通します。

$ export SSL_CERT_FILE=表示されたcertifi/cacert.pemパス

再び、Emscriptenのインストールを行う。

$ ./emsdk install latest

インストール後アクティベートコマンド実行。

$ ./emsdk activate latest

すると、以下のようなメッセージが表示しますので、

Setting the following tools as active:
node-12.18.1-64bit
python-3.7.4-64bit

Next steps:
- To conveniently access emsdk tools from the command line,
consider adding the following directories to your PATH:
....

以下のコマンドで、シェルを適応。

$ source ./emsdk_env.sh

すると、PATHとenvironmentが設定されます。

(…..は、各環境で異なります。)

Adding directories to PATH:
PATH += ...../emsdk
PATH += ...../emsdk/upstream/emscripten
PATH += ...../emsdk/node/12.18.1_64bit/bin
PATH += ...../emsdk/python/3.7.4_64bit/bin

Setting environment variables:
EMSDK = ...../emsdk
EM_CONFIG = ...../emsdk/.emscripten
EM_CACHE = ...../emsdk/upstream/emscripten/cache
EMSDK_NODE = ...../emsdk/node/12.18.1_64bit/bin/node
EMSDK_PYTHON = ...../emsdk/python/3.7.4_64bit/bin/python3

と、いう事で無事Emscriptenをインストール出来ました。

ここまで行って、後から気が付いたのですが、Macであれば homebrewで一発でインストール出来るっぽいです。。。(試していないです。)

$ brew install emscripten binaryen

SDL Canvas Wasm

それでは、SDL2.0を、wasm形式に出力し、ブラウザにレンダリングして行きましょう。

という事で、手っ取り早く試せるデモがこちらのレポジトリにありましたので試して行きます。

https://github.com/timhutton/sdl-canvas-wasm

こちらのレポジトリに書かれた手順で行って行きます。

Install Emscripten: http://emscripten.org

Clone this repo:git clone https://github.com/timhutton/sdl-canvas-wasm.gitcd sdl-canvas-wasm

Build index.js and index.wasm:emcc core.cpp -s WASM=1 -s USE_SDL=2 -O3 -o index.js

Open index.html in a web browser. You should see a moving blue square in a red square:

Chrome doesn't support file:// XHR requests, so you need to first start a webserver, e.g.:

with Python 2: python -m SimpleHTTPServer 8080

with Python 3: python -m http.server 8080

and then open this URL:

http://localhost:8080/

Emscripten コンパイラで、OpenGLやらSDLが、wasm形式ファイルとjsファイルとして出力されているのが確認できます。

HTMLのJS読み込み箇所は以下の通り。

グローバルオブジェクトの「Module」を使ってレンダリングするDOMを指定すれば良いみたいです。

<!-- Create the canvas that the C++ code will draw into -->
<canvas id="canvas" oncontextmenu="event.preventDefault()"></canvas>

<!-- Allow the C++ to access the canvas element -->
<script type='text/javascript'>
    var Module = {
        canvas: (function() { return document.getElementById('canvas'); })()
    };
</script>

<!-- Add the javascript glue code (index.js) as generated by Emscripten -->
<script src="index.js"></script>

SDLをインクルードしているC++ファイルを見てみると、

SDL 2.0 window使用ではなく、Emscripten loopを使う形ぽいで、そのままSDL 2.0のソースを利用できるってことではなく、

ちょっと置き換えが必要ぽい感じですね。

emscripten_set_main_loop_arg(mainloop, &ctx, fps, simulate_infinite_loop);

https://github.com/timhutton/sdl-canvas-wasm/blob/main/core.cpp#L49

Emscripten コマンド

先ほど、Emscriptenコマンドの emcc を用いてwasmのコンパイルを行ったのですが、コマンドのオプションも色々と用意されており、

オプションのよってビルド結果も異なって来ます。

#include <stdio.h>

int main(int argc, char ** argv) {
    printf("Hello World\n");
}

Emscriptenコマンド実行

$ emcc hello.c -s WASM=1 -o hello.html

上記のオプションは次のとおりです。

-s WASM=1 — 出力を wasm に指定。指定しない場合、Emscripten はデフォルトでは asm.js として出力されます。

-o hello.html — コードを実行するための HTML ページを指定。wasm モジュールとウェブ環境で使用できるようにコンパイル、インスタンス化するための JavaScriptコードも出力に含まれます。

上記のコマンドを行って、出力されるファイルは、以下の通りになります。

バイナリの wasm モジュールコード (hello.wasm)

ネイティブの C の関数と JavaScript/wasm の間で変換を行う JavaScript ファイル (hello.js)

wasm コードをロード、コンパイル、インスタンス化し、ブラウザに出力するための HTML ファイル (hello.html)

最後に

Webassemblyの特徴の一つとして、AOTコンパイラによる実行パフォーマンスの効率化が挙げられるでしょう。

JITコンパイラ(Just-in-Timeコンパイラ=実行時コンパイラ)ではなく、AOTコンパイラ(Ahead-of-Timeコンパイラ=事前コンパイラ)であり、これにより大幅なシンプル化とネイティブコード実行時のオーバーヘッドを実現できたとしています。

また、気を付けないといけない点は、Emscriptenでコンパイルする対象のCなどのソース側にはDOMを扱うAPIがないので、DOMのイベントなどを扱う場合はHTML5側でUIを作成し、DOMイベントを制御し、Cなどのソース側にイベントを送る必要があります。

図で書くと以下の通り。

つまり、処理とレンダリングは行えるけど、DOMAPIなど存在しないので UIはHTMLで作成となります。

Web側から、C/C++側の関数を直接呼び出すときは、Moduleのccall関数を使って呼び出す形となります。

以下のように、

Module.ccall('myFunction', // 関数名
'', // 戻り値の型
['string'], // 引数の型名の配列
['テスト']); // 引数の配列

C/C++側

int myFunction() {
    何かしらの処理
}

という風に呼び出すので、web側のDOMイベントにバインドさせ実行する形になるでしょう。

といった様に今回は、触りだけではありますが、Webassembly関連のお話でした。

今後もっと触っていければと思います。

ではではぁ。

Comment

Related Article

【Qt】Mac開発 ソートダイアログ (拡張するダイアログ)を作成

2021.04.01

【Qt】Macの、Qt Creatorで Dialog GUI作成

2020.12.29

【Qt】Macで、Qt Creatorをbrew installしてサクッと起動する。

2020.12.14

Macで、Qt5 開発 QPushButton、QSliderなどウィジェット作成

2020.12.13

Macで、Qt5をbrew installしてサクッと起動する。

2020.12.02

Webassembly用いて、SDL 2.0をブラウザでレンダリング

2020.08.10

MacOS Mojave (10.14.4)の Xcode に、過去のMacOSのSDKをインストール

2019.05.19

CMake インストール 使い方

2016.07.06

CATEGORY LIST

LATEST NEWS

Rust - Actix Web mongo ユーザー登録 JWT認証

Rust

2024.03.24

Rust - Actix Web JWT 認証認可 APIの作成

Rust

2024.02.25

Rust - Actix Web × JSON 静的ファイルをAPIで返却

Rust

2024.01.19

Rust - Actix Web × MongoDB環境をサクッと起動

Rust

2024.01.18

5分で学ぶ RustでWave Function Collapse (波動関数崩壊アルゴリズム)

Rust

2024.01.15

LLaMAモデル GGMLフォーマット(llama.cpp)をRustフレームワーク Leptosを用いて M1MacMiniでサクッと動かす。

Rust

2024.01.11

2024年 狙っているモバイルノートPC

tool

2024.01.07

MacOS XcodeにSDL2を追加

tool

2023.12.26

php 7.4にアップデート

PHP

2023.12.24

5分で覚える Flutter Flameで作る Wave Function Collapse - 波動関数崩壊アルゴリズム

AI・Bot・algorithm

2023.12.20

Flutter - Flameでゲーム作成 (キャラクターの移動)

Flutter

2023.07.23

Flutterで作る ChatGPT Prompt Manager

Flutter

2023.07.12

RANKING

Follow

SPONSOR

現在、掲載募集中です。



Links

About Us

WEBデザイナーの、WEBデザイナーによる、WEBデザイナーの為のサイト。「みんなで書こう!」と仲間を募ってみたが、結局書くのは自分だけとなってしまいました。日々のメモを綴っていきます。

Entry Profile

Graphical FrontEnd Engineer
- Daisuke Takayama

MAD CITY 北九州市で生まれ育つ。20代はバンド活動に明け暮れ、ふと「webデザイナーになりたい。」と思い、デジタルハリウッド福岡校入学。卒業後、数々の賞を受賞、web業界をざわつかせる。
現在、主に、ゲーム制作中心に港区六本木界隈で活動中。

FOLLOW US