日別アーカイブ: 2014年5月19日

Emscripten C++/OpenGL ES 2.0 のアプリケーションをブラウザで動かす (1)

C++ で開発していた OpenGL/OpenGL ES の Project を Emscripten でビルドしてみました。
Native Code 向けのプログラムがそのままブラウザ内で動いています。

・Windows Firefox (29.0.1)

Emscripten Windows

・Android Firefox (29.0.1)

Emscripten AndroidEmscripten Android + animation

Chrome では 7 fps 程度なので asm.js (Firefox) の効果は絶大でした。
Android でも十分な速度で動いています。

追記 2014/05/24: その後 Chrome でも 60fps 以上出るようになりました。詳しくはこちら

Windows 8.1 Firefox 29    60fps 以上   (Core i7-3615QM)
FireOS 3.0  Firefox 29    60fps 以上   (Kindle Fire HDX7 MSM8974)
Android 4.4 Firefox 29    34fps 前後   (Nexus 7 2013 APQ8064)

Windows 8.1 Chrome 34      7fps 前後   (Core i7-3615QM)
FireOS 3.0  Silk           3fps 前後   (Kindle Fire HDX7 MSM8974)
Android 4.4 Chrome 34      3fps 前後   (Nexus 7 2013 APQ8064)

・fps の値が大きい方が高速
・FireOS 3.0 = Android 4.2.2 相当

もともと OpenGL ES 2.0 / EGL に対応していたこともあり、
修正箇所はごく僅かで済んでいます。
使えなかった API は pthread だけで、
追加したのは Mouse/Touch/Keyboard などの Event 周りです。
Network (socket系) とサウンドは未着手。
ソースコード数は 600 file, 26万行ほど。

Native を想定して書いたコードが、拍子抜けするほどあっさりと
ブラウザ内で動いています。

以前から何度か NativeClient (NaCl) への対応化にも取り組んでいたのですが、
あまり本質的でない部分で躓いていました。
同期型 FileIO や Thread 周りといった API 制限だけでなく、
gcc (4.4) が古くて C++11 のコードが通らなかったためです。
その後確認したところ、ARM や pnacl では比較的新しいコンパイラに
置き換わってるようです。

今回使用した Emscripten では何も問題はなく Native 向け API もそのままです。
詳しい説明は次回。

● Emscripten

emscripten wiki

Android では Java, iOS では Objective-C が使われているように、
プラットフォームによってアプリケーション記述言語はまちまちです。
ただ多くの場合 C/C++ も併用できることが多く、
C/C++ 言語 + OpenGL ES 2.0 の組み合わせは、
移植性の高い共通言語&API としての役割も担っています。
主にゲームで。

Web Browser も OpenGL ES 2.0 (WebGL) に対応しており、
NativeClient (NaCl) や Emscripten といった C/C++ のコードを
走らせる仕組みも登場しています。
C/C++ が使えるようになったことで、同じソースコードのまま
さらに多くの環境にアプリケーションを移植できるようになりました。

NaCl はコンパイルしたバイナリをブラウザ内で走らせますが、
Emscripten は仮想マシンとして JavaScript を利用しています。
ポインタを駆使した C Native なコードが JavaScript に変換されると聞いても
少々奇妙な印象を受けるかもしれません。
しかしながら JavaScript の性能向上は著しく、モバイル含めて
十分な速度で動いているこれらの結果にはやはり驚きを隠せません。

● 速度比較

1. 960×640 63万Tri/191万Vertices, 一部 Bone Animation あり

CPU                  GPU            OS           Browser      fps
------------------------------------------------------------------------
Ivy Core i7-3615QM   Intel HD 4000  Win8.1 x64   Win+OpenGL  100fps 前後
Ivy Core i7-3615QM   Intel HD 4000  Win8.1 x64   Firefox      60fps 以上*1
Ivy Core i7-3615QM   Intel HD 4000  Win8.1 x64   Chrome        7fps 前後
BayTrail-D J1900     Intel HD       Ubuntu14.04  X11+OpenGL    8fps 前後
BayTrail-D J1900     Intel HD       Ubuntu14.04  Firefox       5fps 前後
BayTrail-D J1900     Intel HD       Ubuntu14.04  Chrome         動作せず
Kabini Athlon5350    GeForce GTX650 Ubuntu14.04  X11+OpenGL  880fps 前後
Kabini Athlon5350    GeForce GTX650 Ubuntu14.04  Firefox      30fps 前後
Kabini Athlon5350    GeForce GTX650 Ubuntu14.04  Chrome        4fps 前後
APQ8064 Krait 1.5GHz Adreno 320     Android4.4   NDK+ES3.0    50fps 前後
APQ8064 Krait 1.5GHz Adreno 320     Android4.4   Firefox      34fps 前後
APQ8064 Krait 1.5GHz Adreno 320     Android4.4   Chrome        3fps 前後
Exynos5D Cortex-A15  Mali-T604      Android4.4   NDK+ES3.0    60fps 前後
Exynos5D Cortex-A15  Mali-T604      Android4.4   Firefox       8fps 前後
Exynos5D Cortex-A15  Mali-T604      Android4.4   Chrome         動作せず
MSM8974 Krait 400    Adreno 330     FireOS 3.0   Firefox      60fps 以上*1
MSM8974 Krait 400    Adreno 330     FireOS 3.0   Silk           fps 前後

・fps の値が大きい方が高速
・*1 : VSyncの上限
・Firefox 29, Chrome 34
・FireOS 3.0 = Android 4.2.2 相当
・APQ8064 = Nexus 7(2013), Exynos5D = Nexus 10, MSM8974 = Kindle Fire HDX7

2. 960×640 63万Tri/191万Vertices

CPU                  GPU            OS           Browser      fps
------------------------------------------------------------------------
Ivy Core i7-3615QM   Intel HD 4000  Win8.1 x64   Win+OpenGL  110fps 前後
Ivy Core i7-3615QM   Intel HD 4000  Win8.1 x64   Firefox      60fps 以上*1
Ivy Core i7-3615QM   Intel HD 4000  Win8.1 x64   Chrome       10fps 前後
BayTrail-D J1900     Intel HD       Ubuntu14.04  X11+OpenGL    8fps 前後
BayTrail-D J1900     Intel HD       Ubuntu14.04  Firefox       5fps 前後
BayTrail-D J1900     Intel HD       Ubuntu14.04  Chrome         動作せず
Kabini Athlon 5350   GeForce GTX650 Ubuntu14.04  X11+OpenGL  900fps 前後
Kabini Athlon 5350   GeForce GTX650 Ubuntu14.04  Firefox      30fps 前後
Kabini Athlon 5350   GeForce GTX650 Ubuntu14.04  Chrome        6fps 前後
APQ8064 Krait 1.5GHz Adreno 320     Android4.4   NDK+ES3.0    50fps 前後
APQ8064 Krait 1.5GHz Adreno 320     Android4.4   Firefox      30fps 前後
APQ8064 Krait 1.5GHz Adreno 320     Android4.4   Chrome        5fps 前後
Exynos5D Cortex-A15  Mali-T604      Android4.4   NDK+ES3.0    60fps 以上*1
Exynos5D Cortex-A15  Mali-T604      Android4.4   Firefox       8fps 前後
Exynos5D Cortex-A15  Mali-T604      Android4.4   Chrome         動作せず
MSM8974 Krait 400    Adreno 330     FireOS 3.0   Firefox      60fps 以上*1
MSM8974 Krait 400    Adreno 330     FireOS 3.0   Silk          5fps 前後

・fps の値が大きい方が高速

3. 960×640 6万Tri/19万Vertices

CPU                  GPU            OS           Browser      fps
------------------------------------------------------------------------
Ivy Core i7-3615QM   Intel HD 4000  Win8.1 x64   Win+OpenGL  520fps 前後
Ivy Core i7-3615QM   Intel HD 4000  Win8.1 x64   Firefox      60fps 以上*1
Ivy Core i7-3615QM   Intel HD 4000  Win8.1 x64   Chrome       15fps 前後
BayTrail-D J1900     Intel HD       Ubuntu14.04  X11+OpenGL   60fps 以上*1
BayTrail-D J1900     Intel HD       Ubuntu14.04  Firefox       5fps 前後
BayTrail-D J1900     Intel HD       Ubuntu14.04  Chrome         動作せず
Kabini Athlon 5350   GeForce GTX650 Ubuntu14.04  X11+OpenGL 1020fps 前後
Kabini Athlon 5350   GeForce GTX650 Ubuntu14.04  Firefox      38fps 前後
Kabini Athlon 5350   GeForce GTX650 Ubuntu14.04  Chrome        9fps 前後
APQ8064 Krait 1.5GHz Adreno 320     Android4.4   NDK+ES3.0    60fps 以上*1
APQ8064 Krait 1.5GHz Adreno 320     Android4.4   Firefox      60fps 以上*1
APQ8064 Krait 1.5GHz Adreno 320     Android4.4   Chrome        8fps 前後
Exynos5D Cortex-A15  Mali-T604      Android4.4   NDK+ES3.0    60fps 以上*1
Exynos5D Cortex-A15  Mali-T604      Android4.4   Firefox       9fps 前後
Exynos5D Cortex-A15  Mali-T604      Android4.4   Chrome         動作せず
MSM8974 Krait 400    Adreno 330     FireOS 3.0   Firefox      60fps 以上*1
MSM8974 Krait 400    Adreno 330     FireOS 3.0   Silk          8fps 前後

・fps の値が大きい方が高速

描画負荷を変えても速度が大きく変わらないものは CPU (JavaScript) 側の
限界と思われます。
Chrome, BayTrail-D, Kabini, Exynos 5D(Nexus10) が相当します。
また Native との差が少ないものは GPU 側も上限に近いことを意味しています。

Animation ありの場合骨の計算分 JS の負担が増えます。(頂点blendは GPU)
GPU に余裕があるのに 1. と 2. で大きく差が生じる場合は、
JavaScript の演算能力にも余裕がないことを示しています。

BayTrail-D は描画と CPU (JS) 両方共限界に達しているようです。
Native (X11+OpenGL) の 1./2. のテストでは、画面拡大時に速度が上がり、
オブジェクトが画面に全体が収まる場合は Firefox に近い速度まで下がります。
おそらく頂点性能が足りていないと思われます。

また同時に BayTraild の Firefox では拡大しても速度が上がらず一定なので、
JavaScript の動作速度も制限となっていることがわかります。
倍精度浮動小数点演算が苦手なことも影響しているかもしれません。

Kabini は外付けの GeForce がオーバースペック過ぎて CPU が追いついていません。
CPU (JS) 自体は BayTrail よりはかなり速いようです。

Android の Native (NDK+ES) は Fullscreen 動作となり、1920×1200, 2560×1600 で
レンダリングしているため他と条件が異なっています。

JavaScript の動作は Cortex-A15 よりも Krait/Krait 400 の方が高速でした。
Krait (APQ8064) は 3. のテストで制限がかかっていないため、
JavaScript 自体は余裕があるものの GPU で落ちているようです。
GPU の演算能力に余裕がある Krait 400 (MSM8974) はどのテストでも 60fps
超えています。

Desktop の Kabini よりも Krait/Krait 400 の方が JavaScript の
動作速度が速いこともわかります。

Cortex-A15 の速度が全然出ていませんが、VFP Benchmark の結果でも
倍精度演算は Krait の方が良い結果を出しています。
ただそれ以上に大きく差が開いているので、他にも何らかの要因があるのでは
ないかと思われます。

同じ Cortex-A15 のTegra Note 7 (Tegra4) でも試したかったのですが
RAM 容量が足りず動きませんでした。
今のところ Android + Firefox の組み合わせは RAM 2GB でぎりぎりです。
まだビルドを通したばかりでプロジェクトが巨大なせいもあります。

● まとめ

・Emscripten で C/C++ と OpenGL ES 2.0 のコードがブラウザ上でそのまま走る
・Firefox なら速度も速い (asm.js のおかげ)
・Android でも Firefox + Krait は高速動作 (Cortex-A15 が遅い原因は不明)

追記 (2014/05/20) : Tegra4 (Cortex-A15) では高速に動作することを確認しました

追記 (2014/05/24) : Chrome で速度が遅かった原因がわかりました。修正により 60fps 以上出ています。

続きます:「Emscripten C++/OpenGL ES 2.0 のアプリケーションをブラウザで動かす (2)」

関連エントリ
Emscripten C++/OpenGL ES 2.0 のアプリケーションをブラウザで動かす 一覧