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

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

プロジェクトが巨大な場合メモリ不足で起動できないことがあります。
Android のブラウザではロード中のまま止まってしまうので、
読み込みが遅いだけなのかエラーなのかわからない場合があります。
原因を調べるにはリモートデバッガが便利です。

MDN Android 版 Firefox のリモートデバッグ

(1) Android Firefox
・Menu → 設定 → デベロッパーツール → リモートデバッグ を ON

(2) HOST PC
・adb で接続したあと下記のコマンドを実行

adb forward tcp:6000 tcp:6000

(3) HOST PC Firefox
・Menu → 開発ツール → 開発ツールを表示 → 開発ツールパネルの左上の歯車アイコン → 「リモートデバッガを有効」にチェックを入れる (2014/05/26 追加)
・Menu → 開発ツール → 接続 → [接続] ボタン

(4) Android
・接続許可を求めるダイアログが出るので [OK]

(5) HOST PC Firefox
・どのタブに接続するか選択

↓エラーの例 (Android Firefox)

Successfully compiled asm.js code (total compilation time 3120ms; stored in cache) flview_jsr.js
uncaught exception: out of memory

● Library 化

bc file は merge できるので library として利用できます。

emcc src1.cpp -o src1.bc
emcc src2.cpp -o src2.bc
emcc src1.bc src1.bc -o libfile.bc

Lib 利用時

emcc file.cpp libfile.bc -o file.html

拡張子の対応付

PC          Emscripten
---------------------------------
.exe        .js/.html    実行可能
.obj/.o     .bc          object
.lib/.a     .bc          library

コマンドの対応付け

PC           Emscripten
---------------------------------
cl/clang     emcc -o *.bc
link/ld      emcc -o *.js/*.html
lib/ar       emcc -o *.bc

Emscripten はリンク時に未定義シンボルがあっても実行できます。
未定義の関数を呼び出さない限り動作に支障はないようです。

● データ型とサイズ

32bit, ILP32 です。

bool=1/1       char=1/1      short=2/2    int=4/4     long=4/4
long long=8/8  float=4/4     double=8/8
void*=4/4      intptr_t=4/4  size_t=4/4   off_t=4/4   wchar_t=4/4

(byte size / alignment size)

● EGL と OpenGL ES 2.0

3D の描画は EGL + OpenGL ES 2.0 の組み合わせを用います。
他にも初期化手順を省いてくれる便利なライブラリがいろいろあるようです。
とりあえずできるだけ低レベルと思われる手順を使っています。

enum {
    WINDOW_DEFAULT_WIDTH   =  960,
    WINDOW_DEFAULT_HEIGHT  =  640,
};
emscripten_set_canvas_size( WINDOW_DEFAULT_WIDTH, WINDOW_DEFAULT_HEIGHT );

Canvas サイズを指定したら、あとは EGL の初期化を行うだけ。

EGLDisplay  egl_display= eglGetDisplay( EGL_DEFAULT_DISPLAY );
EGLint	ver0, ver1;
eglInitialize( egl_display, &ver0, &ver1 );
eglBindAPI( EGL_OPENGL_ES_API );
~

● X11

Sample コードを見ていると Xlib の API も使えることがわかります。

XSetWindowAttributes  swa;
Display*  disp= XOpenDisplay( NULL );
Window  root= DefaultRootWindow( disp );
Window  win= XCreateWindow(
    disp, root, 0,0,
    WINDOW_DEFAULT_WIDTH, WINDOW_DEFAULT_HEIGHT, 0,
    CopyFromParent, InputOutput, CopyFromParent, 0, &swa );

内部コードを確認すると、XCreateWindow() で canvas size の設定を行っているだけのようです。
それ以外のコードは特に意味はありませんでした。
emscripten_set_canvas_size() を指定しているなら必要無いでしょう。

● 入力イベント

Xlib の Event API は実装されていないようなので、
Emscripten の callback を利用しています。

#include 
#include 


static EM_BOOL KeyCallback( int event_type, const EmscriptenKeyboardEvent* event, void* user_data )
{
    AppModule*  _This= reinterpret_cast(user_data);
    switch( event_type ){
    case EMSCRIPTEN_EVENT_KEYDOWN:
        _This->SendKeyEvent( event->keyCode, event::ACTION_DOWN );
        break;
    case EMSCRIPTEN_EVENT_KEYUP:
        _This->SendKeyEvent( event->keyCode, event::ACTION_UP );
        break;
    }
    return  TRUE;
}


static EM_BOOL MouseCallback( int event_type, const EmscriptenMouseEvent* event, void* user_data )
{
    AppModule*  _This= reinterpret_cast(user_data);
    int mouse_pos_x= event->canvasX;
    int mouse_pos_y= event->canvasY;
    ~
    return  TRUE;
}

void AppModule::Initialize()
{
    emscripten_set_mousedown_callback( NULL, this, TRUE, MouseCallback );
    emscripten_set_mouseup_callback(   NULL, this, TRUE, MouseCallback );
    emscripten_set_mousemove_callback( NULL, this, TRUE, MouseCallback );
    emscripten_set_wheel_callback(  NULL, this, TRUE, WheelCallback );

    emscripten_set_keydown_callback( NULL, this, TRUE, KeyCallback );
    emscripten_set_keyup_callback(   NULL, this, TRUE, KeyCallback );

    emscripten_set_touchstart_callback(  NULL, this, TRUE, TouchCallback );
    emscripten_set_touchend_callback(    NULL, this, TRUE, TouchCallback );
    emscripten_set_touchmove_callback(   NULL, this, TRUE, TouchCallback );

    emscripten_set_gamepadconnected_callback( this, TRUE, GamepadCallback );
    emscripten_set_gamepaddisconnected_callback( this, TRUE, GamepadCallback );
}

Mouse, Wheel, Keyboard, Gamepad は PC 上で確認。
Android のブラウザ上では Touch Event が有効でした。

Firefox の場合は EmscriptenMouseEvent の buttons に押されているボタンの
状態が入るので、MouseMove でも buttons を見るだけで判断できます。
Chrome では buttons が常に 0 だったので、ボタンが押されているかどうかは
MouseDown/MouseUp 時に自分で保持しておく必要があります。

● 残っている問題等

pthread が動作していないため、それに関連する Module をポーリングなど
他の手段に置き換える必要が生じています。
スレッドを使用していないため Atomic 系のコードも未実装です。

サウンド API は OpenAL が利用できるので、
OSX/iOS や Linux とコードを共通化できそうです。
ビルドは通っているのですがスレッドの関係もありまだテストできていません。
Socket API も実験中です。

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

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

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

前回 Cortex-A15 の動作だけ極端に低速で少々疑問が残る結果となりました。
RAM 1MB の端末でも動くようになったのでさらに調べてみました。

Tegra4 Cortex-A15   Firefox     60fps 以上  (Tegra Note 7)
Tegra3 Cortex-A9    Firefox     20~47fps   (Nexus 7 2012)

今回の結果を見る限り、Cortex-A15 でも Krait 並に高速に動作していることがわかります。
また Cortex-A9 も予想よりも速い印象です。

上の両機種とも画面解像度が低く 1280×800 dot です。
前回速度が出なかった Nexus 10 は 2560×1600 と非常に解像度が高いので、
ブラウザが何らかの解像度に応じた CPU 転送を行っている可能性もあります。
なお内部のレンダリング解像度は 960×640 固定です。

以下詳細データ

1. 960x640 63万Tri+Animation

Tegra4 Cortex-A15   Firefox     60fps 以上   (Tegra Note 7)
Tegra3 Cortex-A9    Firefox     20fps 前後   (Nexus 7 2012)

2. 960x640 63万Triangles

Tegra4 Cortex-A15   Firefox     60fps 以上   (Tegra Note 7)
Tegra3 Cortex-A9    Firefox     25fps 前後   (Nexus 7 2012)

3. 960x640 6万Triangles

Tegra4 Cortex-A15   Firefox     60fps 以上   (Tegra Note 7)
Tegra4 Cortex-A15   Chrome      12fps 以上   (Tegra Note 7)
Tegra3 Cortex-A9    Firefox     47fps 前後   (Nexus 7 2012)
Tegra3 Cortex-A9    Chrome       8fps 前後   (Nexus 7 2012)
K3V2   Cortex-A9    Firefox       描画崩れ   (dtab)
K3V2   Cortex-A9    Chrome        動作せず   (dtab)

・fps が大きい方が高速

Tegra3 は JavaScript の動作にはまだ余裕があるものの、
明らかに GPU 性能が足りずに速度が落ちているようです。

K3V2 は Vivante GC4000 による描画が崩れて正しく表示されませんでした。
ログを見る限りアプリケーション自体は動いているようです。

● Emscripten のビルド

Emscripten のビルドは gcc/clang の代わりに emcc コマンドを用います。
obj (.o) の代わりが .bc (bitcode) です。

emcc file1.cpp -o file1.bc

実際に実行できるよう JavaScript に変換 (ld/link) するには下記のようにします。

emcc file1.bc -o file1.js

または

emcc file1.bc -o file1.html

実行形式は js だけの場合と、html 含めたブラウザ向けの 2種類あります。

ローカルで実行する場合は node コマンド (Node.js) を使うことが可能で、
この場合は js だけで OK です。
WebGL の描画や preload 指定した追加ファイルを読み込む場合は html で出力し、
Web サーバー経由でブラウザから読み込みます。

実行形式   実行環境   バンドル
-----------------------------------------------------
 .js       node       --embed-file
 .html     Browser    --emded-file or --preload-file

● 実行手順の例

ローカルで実行する場合 (node)

emcc file1.cpp -o file1.bc
emcc file2.cpp -o file2.bc
emcc file1.bc file2.bc -o file.js

node file.js

ローカルサーバーを経由する場合 (Browser)

emcc file1.cpp -o file1.bc
emcc file2.cpp -o file2.bc
emcc file1.bc file2.bc -o file.html

python -m SimpleHTTPServer 8888

ブラウザで http://localhost:8888/file.html を開く

● ファイルシステム

Emscripten の実行環境は仮想 FileSystem を持っており、
内部的に Unix FileSystem をエミュレートします。
実行時に読み込むファイル群は、一旦この仮想 FileSystem 内に読み込んでおく必要があります。

必要なファイルを実行ファイルに埋め込む方法は下記 2種類あります。

--preload-file    外部ファイル(*.data)にアーカイブし起動時に読み込む
--embed-file      js に埋め込む

–embed-file の例

emcc file1.cpp -o file1.bc
emcc file2.cpp -o file2.bc
emcc file1.bc file2.bc -o file.js --embed-file root/shaders

↑この場合 root/shaders フォルダ以下のファイルをすべて js の中に埋め込みます。
仮想 FileSystem 内のパスも /root/shaders/* とみなします。

もし実際のデータ置き場と、仮想 FileSystem 内のパスが異なる場合は
‘@’ マークを使います。

emcc file1.cpp -o file1.bc
emcc file2.cpp -o file2.bc
emcc file1.bc file2.bc -o file.js --embed-file root/shaders@/data/shaders

↑ ‘@’ 以降が内部の仮想パスの指定になります。
実際のデータは root/shaders 以下に存在しており、
実行時は /data/shaders にあるとみなされます。

–embed-file は間違いが少なく node でも利用できて便利なのですが、
ファイル数が増えるとビルドが極端に遅くなる問題があります。
バンドルが 200MB くらいあるプロジェクトではコマンドが返ってきませんでした。

–preload-file の場合はデータを外部ファイルにまとめるため、
データ容量が増えても比較的時間がかからずにビルドできます。

emcc file1.cpp -o file1.bc
emcc file2.cpp -o file2.bc
emcc file1.bc file2.bc -o file.html --embed-file root/shaders@/data/shaders

python -m SimpleHTTPServer 8888

ブラウザで http://localhost:8888/file.html を開く

どちらにせよ、これらの方法はブラウザを開いたあと長いロードが入るので
その間何もできなくなります。
現実的には、動的な逐次読み込みを実現する必要があるでしょう。

またメモリ上の仮想 FileSystem はデータの保存ができません。
必要ならば Indexed Databased を FileSystem に mount して
利用することができるようです。

● Inline JavaScript

仮想マシンが JavaScript となる Emscripten では、Inline Assembler ではなく
Inline JavaScript を利用することができます。

#include 
~

int main()
{
    EM_ASM(
       ~
       JavaScript code
    );

    return  0;
}

EM_ASM() の中に JavaScript code を記述します。
仮想ファイルシステムへの動的な読み込みなど色々コードを埋め込むことができるようです。

● Main Loop

Emscripten では callback を使って Game の Main Loop の代わりにします。
例えば AppModule::Render() を毎フレーム呼び出したい場合は下記のような使い方になります。

#include 

class AppModule {
public:
   void Render();
};

// 毎フレーム呼ばれる
static void ems_loop( void* arg )
{
   AppModule*  iApp= reinterpret_cast( arg );
   iApp->Render();
}

int main()
{
    AppModule* iApp= new AppModule();

    // callback の登録
    emscripten_set_main_loop_arg( ems_loop, iApp, 0, TRUE );

    delete iApp;
    return  0;
}

● HeapSize

実行環境のメモリが足りずに、アプリケーションを起動できないことがあります。
下記のようにアプリケーションが使用する HEAP SIZE を指定することができます。

emcc  file.cpp -o file.bc
emcc  file.bc -o file.html  -s TOTAL_MEMORY=134217728

あまり大きな値を指定し過ぎると、今度はブラウザ側のメモリが足りず
Out of Memory でロードが止まってしまうことがあるようです。

● まとめ

・Android Cortex-A15/A9 + Firefox は遅くなかった
・Emscripten のビルドと実行手順
・仮想ファイルシステムとバンドル
・MainLoop と HeapSize

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

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

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 のアプリケーションをブラウザで動かす 一覧

BayTrail vs Kabini (Celeron J1900 vs Athlon 5350)

低消費電力の Desktop PC 向け CPU として Intel からは BeyTrail-D、
AMD からは Kabini が登場しています。
BayTrail-D Celeron J1900 と Kabini Athlon 5350 は、
どちらも 4 core CPU + マザーボードでちょうど 1万円。
価格帯もスペックも良く似ているので比べてみました。

                    BayTrail-D              Kabini
                    Celeron J1900         Athlon 5350
-----------------------------------------------------
CPU core             Silvermont             Jaguar
CPU cores                4                    4
CPU clock            2.0-2.41GHz           2.05GHz
RAM                DDR3-1333 dual         DDR3-1600
MEM BW                21.3GB/s             12.8GB/s
L2                      2MB                  2MB
SSE                    SSE4.2               SSE4.2
AVX                      --                  AVX
AES                      --                 AES-NI
CPU SP              24 fop/clock         32 fop/clock
CPU SP FLOPS        57.81 GFLOPS          65.6 GFLOPS
CPU DP               6 fop/clock         12 fop/clock
CPU DP FLOPS        14.46 GFLOPS          24.6 GFLOPS
GPU core         Intel HD Graphics 3G    RADEON R3 (GCN)
GPU clock            688-854MHz             600MHz
GPU SP              64 fop/clock         256 fop/clock
GPU SP FLOPS         54.7 GFLOPS         153.6 GFLOPS
OpenGL Windows       OpenGL 4.0           OpenGL 4.3
OpenGL Linux         OpenGL 3.3           OpenGL 4.3
TDP                     10W                  25W

Intel Celeron Processor J1900
AMD Athlon

浮動小数点演算能力

VFP Benchmark     Celeron J1900    Athlon 5350
-------------------------------------------------
SingleT SP max:   14.477 GFLOPS    15.943 GFLOPS
SingleT DP max:    3.619 GFLOPS     6.127 GFLOPS
MultiT  SP max:   57.902 GFLOPS    63.737 GFLOPS
MultiT  DP max:   14.471 GFLOPS    24.504 GFLOPS

・値が大きいほうが高速

前前回の予想通り浮動小数点演算能力は Jaguar (Kabini/Athlon) の方が高くなっています。
J1900 (BayTrail) は動作クロックの高さで補っている形です。

演算能力/clock    Single FP   Double FP
-----------------------------------------------
Celeron J1900         6          1.5
Athlon 5350           8            3

再測定して気が付きましたが、以前のエントリで J1900 の倍精度演算の
性能評価が間違っていました。下記訂正しましたので申し訳ありませんでした。
Atom Bay Trail の浮動小数点演算能力

前回のコンパイル速度比較を Kabini でも試してみました。
驚くほど拮抗しています。

flatlib3 Linux       clock  core  RAM   OS   arch compiler    time sec
-------------------------------------------------------------------------
Kabini Athlon 5350  2.05GHz  x4   8GB  14.04  x64  clang-3.5    54.8
BayTrail-D J1900    2.41GHz  x4   8GB  14.04  x64  clang-3.5    54.6

・time が小さい方が速い

テストした環境は下記の通り。

Test 環境
Celeron J1900 (Q1900B-ITX DDR3-1333 dual   8GB  21.3GB/s)
Athlon 5350   (AM1l       DDR3-1333 single 8GB  10.7GB/s)

Kabini は DDR3-1600 が使えますが、テスト環境では手持ちの DDR3-1333 を使用しています。
本来の能力よりもスコアが低くなっていると考えられますので予めご了承ください。

AES 変換テスト

AES CTR 599MByte  Celeron J1900    Athlon 5350
-------------------------------------------------
Table1               18.708          18.964
Table2               15.409          14.600
Table3               14.902          12.374
AES-NI                   --           4.238

・単位は秒、値が小さい方が速い, Single Thread

AES-NI が使えるため Jaguar (Athlon/Kabini) の方が高速です。
同じアルゴリズム同士でもわずかに Jaguar の方が速いようです。
メモリ速度、CPU の動作クロックともに J1900 (BayTrail) の方が上なので、
Jaguar (Athlon/Kabini) は Core 性能そのものが高いのだと思われます。

簡単なシーンのレンダリング速度の比較

Ubuntu 14.04   GPU                    API            fps
----------------------------------------------------------
Celeron J1900  Intel HD Graphics 3G   OpenGL 3.3     17fps
Athlon 5350    RADEON R3              OpenGL 4.3     89fps

・fps が大きい方が速い

比べるまでもなく内蔵 GPU の性能では圧倒的な差があります。
RADEON は OpenGL で新しい API が使える点もポイントが高いです。
J1900 の GPU は使用していて少々性能不足を感じます。

CPU core の基本性能は Jaguar (Athlon/Kabini) の方が上。
メモリ速度や動作クロックを加味すると両者かなり近い性能になっています。

GPU は当然 RADEON (Athlon/Kabini) の方が速く、
性能差には数倍の開きがあります。

● BayTrail-D (Celeron J1900/Silvermont)
・消費電力が低くファンレス
・メモリ帯域が広い

● Kabini (Athlon 5350/Jaguar)
・浮動小数点演算能力が高い
・AVX/AES 命令に対応している
・GPU 性能が非常に高い

関連エントリ
コンパイル時間の比較 BayTrail
Atom Bay Trail の浮動小数点演算能力

コンパイル時間の比較 BayTrail

BayTrail-D Celeron J1900 の PC でコンパイル時間を比べてみました。

flatlib3 Linux       clock  core  RAM   OS   arch compiler   time sec
-------------------------------------------------------------------------
Raspberry Pi ARM11   0.7GHz  x1 0.5GB wheezy arm6 gcc-4.7    2276.8 (38m)
Atom Z540            1.9GHz  x1   2GB 14.04  x86  clang-3.5   446.9  (7m)
Atom Z540            1.9GHz  x1   2GB 14.04  x86  gcc-4.8     369.4  (6m)
Tegra3 Cortex-A9     1.2GHz  x4   1GB 13.04  arm7 gcc-4.8     247.4  (4m)
BayTrail-D J1900     2.0GHz  x4   8GB 14.04  x64  gcc-4.8      72.1
BayTrail-D J1900     2.0GHz  x4   8GB 14.04  x64  clang-3.5    53.2
Core i7-2720QM Sandy 2.2GHz  x4  16GB 14.04  x64  gcc-4.8      26.6
Core i7-2720QM Sandy 2.2GHz  x4  16GB 14.04  x64  clang-3.5    20.2

・time が少ない方が高速

Linux 向け build は ARM 上でも走ります。
4core BayTrail で 1分弱。
Mobile 向け i7 で 20秒なので速度差は 2.6倍ほど。
Desktop PC だと 3倍以上差がつくと思われます。
i7 と ARM11 との差は 100倍以上。

下記は Android NDK を使った build 時間です。
armeabi, armeab-v7a, mips, x86 の 4種類、さらに OpenGL ES2/ES3 の
2種類生成しているため、上の Linux build よりも数倍時間がかかっています。

flatlib3 AndroidNDK  clock  core  RAM  OS           arch   time sec
-------------------------------------------------------------------------
Core 2 Duo P7350     2.0GHz  x2   8GB  MacOSX 10.9   x64   482.1  (8m2s)
BayTrail-D J1900     2.0GHz  x4   8GB  Windows 7     x64   424.1  (7m4s)
BayTrail-D J1900     2.0GHz  x4   8GB  Ubuntu 14.04  x64   277.2  (4m37s)
Core i5-3210M Ivy    2.5GHz  x2   8GB  MacOSX 10.9   x64   219.0  (3m39s)
Core i7-2720QM Sandy 2.2GHz  x4  16GB  Windows 8.1   x64   157.7  (2m37s)
Core i7-3615QM Ivy   2.3GHz  x4  16GB  Windows 8.1   x64   146.5  (2m26s)
Core i7-2720QM Sandy 2.2GHz  x4  16GB  MacOSX 10.9   x64   142.7  (2m22s)
Core i7-3615QM Ivy   2.3GHz  x4  16GB  MacOSX 10.9   x64   114.1  (1m54s)
Core i7-2720QM Sandy 2.2GHz  x4  16GB  Ubuntu 14.04  x64   102.9  (1m42s)

・time が少ない方が高速
・Android NDK (r9d) gcc 4.8
・armeabi, armeabi-v7a, mips, x86

↑こちらは ARM 上で走らない代わりに OS に依存せず比較できる利点があります。
ただ OS 環境による差が予想以上に大きいので
プロセッサの性能を見るならば同一 OS 上で比較した方がよさそうです。
Cygwin を経由せず直接 gcc を呼び出しているのですが、
それでも Windows 上のコンパイルは低速でした。

下記は OSX target での比較。

flatlib3 Mac OSX     clock  core  RAM   OS   arch compiler    time sec
-----------------------------------------------------------------------
Core 2 Duo P7350     2.0GHz  x2    8GB  10.9 x64  clang-3.4    69.0
Core i5-3210M Ivy    2.5GHz  x2    8GB  10.9 x64  clang-3.4    38.8
Core i7-2720QM Sandy 2.2GHz  x4   16GB  10.9 x64  clang-3.4    26.1
Core i7-3615QM Ivy   2.3GHz  x4   16GB  10.9 x64  clang-3.4    21.8

・time が少ない方が高速
・x86_64 のみ

i7-2720QM と Core 2 Duo との時間差は、OSX 向けで 2.64倍、
OSX 上の Android build で 3.37倍 になっています。
Ubuntu 上 Android build で比べると i7-2720QM と BayTrail は 2.2倍。
よって Coe 2 Duo よりも BayTrail 4core の方が速いと言えます。

下記は Windows target の比較です。
Windows 向けは x86/x64 両バイナリを生成していることと、
OS によってコードの量が異なるのでより時間がかかっています。

flatlib3 Windows     clock  core RAM   OS    arch  compiler    time sec
------------------------------------------------------------------------
BayTrail-D J1900     2.0GHz  x4   8GB  Win7   x64  VS2013TCP    402.1
Core i7-2720QM Sandy 2.2GHz  x4  16GB  Win8.1 x64  VS2013TCP    137.3
Core i7-3615QM Ivy   2.3GHz  x4  16GB  Win8.1 x64  VS2013TCP    113.4

・time が少ない方が高速
・x86, x64

↑こちらのデータを見ると 2.9倍と差が開いており、
比率としては Core 2 Duo との差が少なくなっています。

最後はデータとしては意味が無いけど念のため iOS 向け build です。
5種類分の Fat Binary を生成するため時間がかかっています。
OSX と比べるとほぼ 5倍なので計算通りです。

flatlib3 iOS         clock  core  RAM   OS   arch compiler    time sec
---------------------------------------------------------------------------
Core 2 Duo P7350     2.0GHz  x2    8GB  10.9 x64  clang-3.4   350.6  (5m51s)
Core i5-3210M Ivy    2.5GHz  x2    8GB  10.9 x64  clang-3.4   189.1  (3m9s)
Core i7-2720QM Sandy 2.2GHz  x4   16GB  10.9 x64  clang-3.4   128.5  (2m8s)
Core i7-3615QM Ivy   2.3GHz  x4   16GB  10.9 x64  clang-3.4   107.6  (1m48s)

・time が少ない方が高速
・armv7, armv7s, arm64, x86, x86_64

Desktop PC として使っているとさすがに遅さを感じますが、
CPU core 数が多いためそれなりにパフォーマンスが出ている印象です。

8inch クラスの軽量な Tablet PC として携帯しつつ、コンパイル時間が
ノート PC の数倍の範囲に収まるなら十分使えそうだと感じました。
ただし実際の Tablet では動作クロックも搭載 RAM 容量も大きく減るので
その点は検証が必要かと思います。

関連エントリ
Atom Bay Trail の浮動小数点演算能力