SlideShare a Scribd company logo
Unreal Engineが5日でasm.js
化出来たと聞いて
2014/03/25 KLab ALM 余興LT
@muo_jp
 なかざわ けい   @muo_jp
プログラミング19年目 29歳
(BASIC→C→PHP→Ruby→Python→C#2.0→C#3.0→C#4.0)
社会人 10年目(20歳∼)、経営学修士(IT業界の経営戦略論)
KLab 4年目(Kラボラトリー所属 C#充)
PlaygroundというゲームエンジンのOSSメンテナ
どんな話?
!
100,000行のC++コードを
JavaScriptに変換する話
前日譚: C++/CLIで
PSVita/PSMへ移植
しようとして失敗
(2013年ゴールデンウィーク)
前回までのあらすじ
Webの未来 ∼ PNaClとasm.jsでカワルミライ - いま、
モバイルWebの先端で起こっていること
http://www.slideshare.net/KeiNakazawa/web-
pnaclasmjs-web
2013/11/22前後に調べてた諸々をまとめたもの
前回の結論
遠くない未来に、一定以上のコンテンツがWebへ回
帰するはず
現状で見えている、C/C++で書かれたゲームエンジン
移植の有力選択肢はPNaClとasm.js
この先は一度やってみたほうが見えてくるはず
Playgroundのアーキテクチャ
http://www.klab.com/jp/press/130926.html
asm.js化する部分
100,000行超のC++コード
まず10時間やってみよう
8時間ほどコードを削り倒す
当然一筋縄ではいかない
(`ェ´)ピャー
abort() at Error
at stackTrace (/.../playground/Engine/porting/emscripten/p.js:1032:15)
at abort (/.../playground/Engine/porting/emscripten/p.js:289649:25)
at nullFunc_viiiiii (/.../playground/Engine/porting/emscripten/p.js:8235:1574)
at Array.b978 [as 0] (/playground/Engine/porting/emscripten/p.js:287407:99)
at Object._main (/.../playground/Engine/porting/emscripten/p.js:11640:43)
at Object.callMain (/.../playground/Engine/porting/emscripten/p.js:289544:30)
at doRun (/.../playground/Engine/porting/emscripten/p.js:289597:25)
at run (/.../playground/Engine/porting/emscripten/p.js:289612:5)
at Object.<anonymous> (/.../playground/Engine/porting/emscripten/p.js:289669:1)
at Module._compile (module.js:456:26)
心折れました(3月上旬)
このへんをcodelunch.fm
というpodcastで喋って
きました
12時間ほどおかわり
足りないライブラリのソース
を拾ってきたりプラットフォー
ム依存部分を直したり
気合で読む
15945 $1 = 0;
15946 $2 = $argc;
15947 $3 = $argv;
15948 $width = 800;
15949 $height = 480;
15950 _emscripten_asm_const(((1168)|0));
15951 $6 = (__Znwj(32)|0);
15952 $7 = $6;
15953 __THREW__ = 0;
15954 invoke_viiiiii(6,($7|0),((1264)|0),((1272)|0),((1280)|0),((1288)|0),((1296)|0));
15955 $8 = __THREW__; __THREW__ = 0;
15956 $9 = $8&1;
15957 if (!($9)) {
15958 $pRequest = $7;
15959 $10 = (__ZN12CPFInterface11getInstanceEv()|0);
15960 $pfif = $10;
15961 $11 = $pRequest;
15962 __ZN15CAndroidRequest4initEv($11);
15963 $12 = $pRequest;
15964 __ZN15CAndroidRequest11setHomePathEPKc($12,(1312));
15965 $vararg_ptr = ($vararg_buffer);
15966 HEAP32[$vararg_ptr>>2] = (1320);
15967 _emscripten_log(1,($vararg_buffer|0));
15968 $13 = $pfif;
15969 $14 = $pRequest;
15970 $15 = $14;
15971 __ZN12CPFInterface18setPlatformRequestEP16IPlatformRequest($13,$15);
15972 (__ZN18KLBPlatformMetrics11getInstanceEv()|0);
asm.jsを読む
ifのelse側を冗長化して埋め込むケースもある。

アセンブリ読んでるとよくあること。
多分MSILを日常的に
読んでるC#勢からし
たら朝食パンケーキ
みたいなもの
※sourcemapはちょい用途が違うので、

やっぱアセンブリを読む
で、出来た結果は…
結果
Luaスクリプトの

実行まで成功
glClearColorとか動く
テクスチャ描画はまだ
元版(iOS Simulator)
Chrome 33
Firefox 27
asm.js化できた部分
先は100時間+かかりそうだけど、
できそうな見立ては立った
以下asm.js読書感想文
ここがイケてるemscripten:
ファイルシステムの扱い
非常に簡単にファイル群を取り込める
!
!
!
!
ちなみにWebブラウザ上で生成したデータを
IndexedDB経由で永続化できる仕組みを提供してる
$ emcc -s ASSERTIONS=2 -s LEGACY_GL_EMULATION=1
--embed-file simple_item/@/install/ -O0 ./*.o -o p.html
16 Module['FS_createPath']('/', 'install', true, true);
17 Module['FS_createDataFile']('/install', 'itemimage.png.imag', [76, 73, 78, 75, 0, 0, 0,
18 Module['FS_createDataFile']('/install', 'SimpleItem.lua', [102, 117, 110, 99, 116, 105,
19 Module['FS_createDataFile']('/install', 'start.lua', [102, 117, 110, 99, 116, 105, 111,
20 Module['FS_createDataFile']('/install', 'textureBoat.texb', [84, 69, 88, 66, 0, 1, 146,
ここがイケてるemscripten:
EM_ASM();
インラインアセンブリ的なインラインJavaScript
うわっと思うけど、無いより100倍マシ。良い選択
一応、この中で同スコープのポインタ触れる
501 int main(int argc, char* argv[])
502 {
503 int width = 800;
504 int height = 480;
505 EM_ASM(
506 Browser.createContext(Module.canvas, true, true, {});
507 Browser.setCanvasSize(800, 480, true);
508 );
509
510 CAndroidRequest * pRequest = new CAndroidRequest("model", "brand", "boar
511 CPFInterface& pfif = CPFInterface::getInstance();
OpenGL ES 1.1用コールは
冷遇の姿勢
お、おう(PlaygroundはOpenGL ES 1.1+ターゲット)
4280 var glTexEnvi = (typeof(_glTexEnvi) != 'undefined') ? _glTexEnvi : function(){};
4281 _glTexEnvi = _emscripten_glTexEnvi = function _glTexEnvi(target, pname, param) {
4282 GLImmediate.TexEnvJIT.hook_texEnvi(target, pname, param);
4283 // Don't call old func, since we are the implementor.
4284 //glTexEnvi(target, pname, param);
4285 };
emscripten/1.13.0/src/library_gl.js あたりを読む
地道デバッグ
一部を変更してem++でコンパイル、emccでJSファ
イルを吐き出してリロードあたりまでは10秒ぐらい
でいける。かなりインタラクション速い
ただし: ChromeのJSコンソールで15万行越えのあた
りにブレークポイントを止めようとすると30秒ぐら
いかかる
リビルド最速を目指して
-O0コンパイル

-O0リンク(8.8MiB・速い)
-O0コンパイル

-O2リンク(2.7MiB・遅い)
-O2コンパイル

-O2リンク(2.8MiB・遅い)
WonderSwan:emscripten keinakazawa$ ls -l p.*
-rw-r--r-- 1 keinakazawa staff 101607 Mar 25 18:57 p.html
-rw-r--r-- 1 keinakazawa staff 67 Mar 25 18:57 p.html.map
-rw-r--r-- 1 keinakazawa staff 8967061 Mar 25 18:57 p.js
-rw-r--r-- 1 keinakazawa staff 65 Mar 25 12:11 p.js.map
WonderSwan:emscripten keinakazawa$ ls -l p.*
-rw-r--r-- 1 keinakazawa staff 101607 Mar 25 18:59 p.html
-rw-r--r-- 1 keinakazawa staff 67 Mar 25 18:57 p.html.map
-rw-r--r-- 1 keinakazawa staff 2831435 Mar 25 18:59 p.js
-rw-r--r-- 1 keinakazawa staff 65 Mar 25 12:11 p.js.map
WonderSwan:emscripten keinakazawa$ ls -l p.*
-rw-r--r-- 1 keinakazawa staff 101607 Mar 25 19:02 p.html
-rw-r--r-- 1 keinakazawa staff 67 Mar 25 18:57 p.html.map
-rw-r--r-- 1 keinakazawa staff 2941528 Mar 25 19:02 p.js
-rw-r--r-- 1 keinakazawa staff 65 Mar 25 12:11 p.js.map
試行錯誤中はO0でビルド、実行成功まで
持っていくのが吉(ビルド時間が3倍ぐらい違う)
24時間付き合った印象
emscripten(asm.js)は、

JSとC++で変わってくる部分をうまく吸収しつつ、時
に美しく時に泥臭く(=最強)進行してるプロジェクト
残るJSのつらみ: メモリ空間共有できる
マルチスレッド機構がない
とpodcastで喋ってたら コメント頂いた
!
!
!
!
!
\( 'ω')/ウオオオオオアアアアアァァァーーッッッ!!
https://bugzilla.mozilla.org/show_bug.cgi?id=933001
所感
今のところは、携帯端末での動作よりもWindows/Mac上での動作
に絞ったほうが良い結果になる(SDLと似た立ち位置)

Luaのスクリプトを変更して3秒で動作確認できる(小規模なら)
開発中、どんどんリソースを書き換えていくのに良い
データサイズはやっぱり問題。けど、バックグラウンドロードをう
まく実装すれば、少なくとも社内でのテスト用途には割といける?
もう少し進むと、従来WebView+…でやってたものの形が逆転する
今後に向けた手持ち課題
Makefileをいい感じに整備
asm.js化するプロジェクトによって性質が異なるので、ちゃんと考える
差分ビルドをやりやすいように
emscripten固有部分をなるべく少ない箇所に閉じ込める
実行時にエラーとなりうる箇所をmake testなどで事前に掴めるように
これについては、非ブラウザ実行時(node.js実行時)にOpenGL系のコー
ルを一切発行しないようにするなど、何かしらの手を入れる必要がある

More Related Content

UnrealEngineが5日間でasm.js化できたと聞いた俺たちは…