D3D Shader/OpenGL」カテゴリーアーカイブ

Android の新しい GPU BayTrail-T Intel HD Graphics

Bay Trail-T 搭載の Android 端末が発売されたので軽く調べてみました。
Android 端末に使われている GPU の種類に Intel HD Graphics が
新たに加わったことになります。

Qualcomm     Adreno
Imagination  PowerVR
NVIDIA       Tegra
ARM          Mali
Vivante      GC
Intel        HD Graphics   ← NEW

ASUS MeMO Pad 7 ME176

Adreno 320/330, Mali-T604, PowerVR G6430 (iOS) に続いて
入手可能な OpenGL ES 3.0 対応端末となっています。

対応している Extension は下記の通り。

// ASUS MeMO Pad 7 ME176 Android 4.4
// Atom Z3745 x86 RAM 1GB

GL_VENDOR: Intel
GL_RENDERER: Intel(R) HD Graphics for BayTrail
GL_VERSION: OpenGL ES 3.0 - Build eng.yunweiz.20140425.225700

GL_EXT_blend_minmax
GL_EXT_multi_draw_arrys
GL_SUN_multi_draw_arrys
GL_EXT_texture_filter_anisotropic
GL_EXT_texture_compression_s3tc
GL_EXT_texture_lod_bias
GL_EXT_color_buffer_float
GL_EXT_packed_float
GL_EXT_texture_rg
GL_INTEL_performance_queries
GL_EXT_texture_storage
GL_OES_EGL_image
GL_OES_framebuffer_object
GL_OES_depth24
GL_OES_stencil8
GL_OES_packed_depth_stencil
GL_OES_rgb8_rgba8
GL_ARM_rgba8
GL_OES_depth_texture
GL_EXT_color_buffer_half_float
GL_OES_vertex_half_float
GL_EXT_shadow_samplers
GL_OES_point_sprite
GL_OES_blend_subtract
GL_OES_blend_func_separate
GL_OES_blend_qeuation_separate
GL_OES_standard_derivatives
GL_OES_read_format
GL_OES_mapbuffer
GL_EXT_discard_framebuffer
GL_EXT_texture_format_BGRA8888
GL_OES_compressed_paletted_texture
GL_OES_ELG_image_external
GL_OES_compressed_ETC1_RGB8_texture
GL_OES_fixed_point
GL_OES_vertex_array_object
GL_OES_get_program_binary
GL_OES_texture_3D
GL_OES_texture_cube_map
GL_OES_fbo_render_mipmap
GL_OES_texture_float
GL_OES_texture_float_linear
GL_OES_texture_half_float
GL_OES_texture_half_float_linear
GL_OES_stencil_wrap
GL_OES_element_index_uint
GL_OES_texture_npot
GL_OES_texture_mirrored_repeat
GL_EXT_sRGB
GL_EXT_frag_depth
GL_APPLE_texture_max_level
GL_EXT_occlusion_query_boolean
GL_INTEL_timer_query
GL_ANGLE_texture_compression_dxt1
GL_ANGLE_texture_compression_dxt3
GL_ANGLE_texture_compression_dxt5
GL_EXT_texture_compression_dxt1
GL_OES_required_internalformat
GL_EXT_separate_shader_objects
GL_OES_surfaceless_context
GL_OES_EGL_sync
GL_EXT_robustness
GL_EXT_shader_texture_lod
GL_EXT_unpack_subimage
GL_EXT_read_format_bgra
GL_EXT_debug_marker
GL_KHR_blend_equation_advanced
GL_EXT_shader_integer_mix

対応している圧縮テクスチャフォーマットは ETC2/EAC, ETC1, DXT(S3TC) 。
DirectX11 世代の GPU なので機能面での心配はおそらく不要でしょう。

Android 向けには、BayTrail の他にも新 Atom (Silvermont core) SoC として
Z3400/Z3500 (Moorefield) が発表されています。
搭載 GPU は PowerVR G6400 となっており Intel HD Graphics ではありません。

Impress: Intel、22nmのスマートフォン向けAtom Z3400/3500を発表

実際に 2014/5/8 に au から Z3580 を搭載した MeMO Pad 8 が発表されています。
発売自体は 8月とまだ先です。

Impress: LTE対応の8インチタブレット「ASUS MeMO Pad 8」

Tablet            SoC   core clock   display    GPU
---------------------------------------------------------------------
MeMO Pad 7 ME176  Z3745  4  1.86GHz  1280x800   Intel HD Graphics 4EU
MeMO Pad 8 ME181  Z3745  4  1.86GHz  1280x800   Intel HD Graphics 4EU
MeMO Pad 8 (au)   Z3580  4  2.33GHz  1920x1200  PowerVR G6430

Full HD モデルに使われているのは PowerVR G6430 の方です。
多くの Windows Tablet 同様に ME176/ME181 の画面サイズは 1280×800 なので、
純粋な GPU 性能では Intel HD Graphics (4EU) よりも PowerVR G6430 の方が
高いのではないかと思われます。

SoC core CPU-clock  GPU                   GPU-clock  fop   GFLOPS
-----------------------------------------------------------------
Z3745  4  1.86GHz   Intel HD Graphics 4EU   778MHz    64     49.8
Z3580  4  2.33GHz   PowerVR G6430           533MHz   256    136.4

Wikipedia Atom (system on chip)
Intel Atom Processor Z3745 (2M Cache, up to 1.86GHz)

Android でも x86 端末は珍しくなくなりました。
CPU 自体は x64 にも対応しています。

おそらく今後 Android も 64bit に対応すると思われますが、
既存の端末に対して 64bit 版が提供されるかどうかは不明です。
ここしばらくは、購入するタイミングが判断しづらく悩ましい状態となりそうです。

関連エントリ
BayTrail vs Kabini (Celeron J1900 vs Athlon 5350)
コンパイル時間の比較 BayTrail
Atom Bay Trail の浮動小数点演算能力

Chromecast で C++ アプリを走らせる。Emscripten のゲームを動かす

Chromecast 上でも Emscripten のプログラムが動きました。

chromecast_chiraks.jpg

少々ややこしいのですが、PC のブラウザで走らせた結果を、
Tab のミラーリング機能で TV に表示しているわけではないです。

Emscripten で作った JavaScript コードを、Custom Receiver として登録することで
Chromecast 上で走らせています。

速度は 10~15fps 前後。
Android 端末よりも遅いので、
Chromecast の CPU はあまり動作クロックが高くないようです。

● Chromecast とは

ほぼストリーム専用に特化したメディアプレイヤーです。

 ・Google Chromecast

端末の画面を TV にミラーリング表示するような、リモートモニタアダプタとは異なっています。

インターネットへの接続機能を持っており、基本的には Chromecast は
メディアプレイヤーとして単独で動作します。
ただし本体にリモコンやコントローラを繋ぐことはできず、UI を持っていません。
必ず PC や Android/iOS 等の他の端末経由で操作を行うことになります。

一般のメディアプレイヤー BOX / スティック との違いは下記の通り

・ストリーム向けなのでストレージを必要としない。SD カードスロットもない
・リモコンを持たない。USB/Bluetooth/IR 等の周辺機器をつなぐことができない

ストレージ含めて周辺機器も不要にしたことでハードウエアはシンプルです。
UI もいらないため Android を搭載したメディアプレイヤーよりも性能を必要とせず
コストダウンを可能にしているようです。

● ハードウエア

 ・iFixit Chromecast Teardown
 ・ARM Marvell SoCs

分解記事より Marvell 88DE3005-A1、↑ARM Marvell SoCs より Cortex-A9。
↓Amazon の Fire TV の比較表でも Single core の RAM 512MB と記載されています。

 ・Amazon Fire TV

動作クロックや GPU は不明。
同様のコンセプトだった Nexus Q と比べてもかなり控えめなスペックとなっています。

● Chromecast のアプリケーション

Chromecast は Web Browser (Chrome) が内蔵されており、
Web Application を走らせるプラットフォームとして機能しています。
ただし自由に Web page を表示させることはできず、
登録した Web Application (Receiver App) しか開けないように制限されています。

また Chromecast 本体だけでは何も操作できないので、
PC/Android/iOS 側にも操作用のアプリケーションが必要になります。

(1) Receiver Apps : Chromecast 上で走る Web Application (HTML+JS)
(2) Sender Apps : 外部から操作するためのアプリ (PC Chrome/Android/iOS Apps)

基本的には (1) と (2) の組み合わせで出来ています。
他にも Web Application として (1) を設置するための Web サーバーが要ります。

● PC の Tab ミラーリング

PC の Chrome ブラウザに拡張機能を追加すると、ブラウザの表示内容を
Chromecast に送信できるようになります。
アイコンから「このタブをキャスト」ボタンを選択。

CPU 負荷が一定分増加することからも、動画として Web Page の内容を送信しているようです。
PC がストリームサーバーを兼ねていることになります。

任意の Web を制限なく表示できますが、Chromecast が直接ネットにアクセスして
レンダリングを行っているわけではありません。

● リモコンだけのアプリ (Default Receiver)

メディアプレイヤーなどのよく使われる Receiver (1) は、デフォルトのものが用意されています。
そのためアプリケーションによっては、(2) のリモコン側を作るだけで機能を実現することができます。
この場合登録は不要。

● Chromecast の上で動くアプリ (Custom Receiver)

Chromecast 上で走る (1) の Receiver アプリを作るには登録が必要になります。

 1. Receiver / Sender アプリを作成
 2. Receiver を Web サーバーに転送する
 3. Developer Console で 2. の URL を登録して ID を受け取る
 4. 開発に使う Chromecast のシリアルを登録して Developer mode にする
   (Remote Debug できるようになる)

以下テスト実行までの手順

◎ Receiver アプリ URL の登録

1. Developer Console に登録&ログイン (5ドル必要)
 ・Google Cast SDK Developer Console
2. [ADD NEW APPLICATION] で Custom Receiver を選択
3. 名前と Receiver App を設置した URL の登録
   例 http://~/receiver_chiraks.html
4. Application ID が発行されるので、リモコン側 (2) のアプリケーションに ID を書き込む

◎ Chromecast Device の登録

1. Developer Console の [ADD NEW DEVICE] でシリアルナンバーを登録する。
 ・本体の裏面上部の文字列、または箱のシールにある SN の文字列
2. Device 登録には時間がかかるので 15分待つ。
3. “Ready For Testing” になったら完了

◎ Developer mode の確認

1. Chromecast の電源を一旦落とす。
2. Chromecast を再び起動して PC 上の Chrome ブラウザから下記 URL を開く
  http://ChromecastのIPアドレス:9222
3. もし開けない場合は、再び電源を落として時間をおいてからやりなおす。

“Inspectable WebContents” と表示されたら成功で、
Console の log を確認したり Remote Debug できるようになります。

◎ アプリの実行

Sender を起動して登録した Chromecast Device に接続

とりあえず Chromecast のようなデバイスでも
Emscripten でプログラムを作れることがわかりました。

関連エントリ
Emscripten C++/OpenGL ES 2.0 (9) C関数呼び出しと FileSystem
Emscripten C++ のアプリをブラウザで動かす (8) iOS でも動く
Emscripten C++/OpenGL ES 2.0 (7) Emscripten の OpenGL API と WebGL
Emscripten C++/OpenGL ES 2.0 (6) Chrome の速度と IE11/Safari
Emscripten C++/OpenGL ES 2.0 のアプリケーションをブラウザで動かす (5)
Emscripten C++/OpenGL ES 2.0 のアプリケーションをブラウザで動かす (4)
Emscripten C++/OpenGL ES 2.0 のアプリケーションをブラウザで動かす (3)
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 (9) C関数呼び出しと FileSystem

● JavaScript から C関数を呼び出す

ccall() を使います。
(C/C++言語から JavaScript Lib を呼び出す方法は こちら)

#include  
#include  

extern "C" void myfunc01()
{
    printf( "MYFUNC01\n" );
}

int main()
{
    EM_ASM(
        // C言語関数の呼び出し
        ccall( 'myfunc01', 'v' );
    );
    return  0;
}

C/C++側から参照がない関数はオプティマイザが削除してしまうので
そのままだと上のプログラムはエラーになります。
コンパイル時に下記のオプションが必要です。

-s EXPORTED_FUNCTIONS="['_main','_malloc','_myfunc01','_myfunc02']

EXPORTED_FUNCTIONS で個別に関数名を指定するか、または

-s EXPORT_ALL=1

を指定します。

C言語の symbol なので内部表現では先頭に ‘_’ が付きます。
C++ 内で定義する場合は extern “C” が必要な点に注意。

● 引数の指定と cwrap

ccall 2番目の引数 ‘v’ は戻り値の型を意味しています。
例えば文字列を返す関数の場合 ‘string’ を与えます。

#include  
#include  

extern "C" const char* myfunc01()
{
    return  "MYFUNC_01";
}

int main()
{
    EM_ASM(
        // C言語関数の呼び出し
	console.log( ccall( 'myfunc01', 'string' ) );
    );
    return  0;
}

‘string’ は自動的にオブジェクトに変換されます。

引数を渡す場合も型の情報が必要です。

#include  
#include  

extern "C" const char* myfunc02( int a, float b, const char* c )
{
    printf( "%d %f %s\n", a, b, c );
    return  "MYFUNC_02";
}

int main()
{
    EM_ASM(
        // C言語関数の呼び出し
	console.log( ccall( 'myfunc02', 'string', ['number','number','string'], 12, 34.5, 'abcdefg' ) );
    );
    return  0;
}

文字列引数はポインタに変換するために、一旦内部の仮想メモリ空間に
展開する必要があります。
JavaScript から呼び出した場合、この領域として stack が用いられています。

戻り値   引数        C言語
---------------------------------------------
string   string      const char*
number   number      int/float 他 (int64以外)
v        --          void

頻繁に呼び出す場合は cwrap() で関数に変換できます。

var myfunc02= cwrap( 'myfunc02', 'string', ['number','number','string'] );

var ret_str= myfunc02( 345, 67.8, 'hijklmn' );

● IDBFS ファイルシステム

ブラウザのローカルストレージに保存可能なファイルシステムです。
任意の場所に mount 可能で、path + filename がそのまま key になります。
通常は仮想 FS に対して読み書きを行うので IDB との同期が必要です。

FS.syncfs( true, callback );     読み込み IDB → Virtual FS
FS.syncfs( false, callback );    書き込み Virtual FS → IDB
void save_func()
{
    FILE*  fp= fopen( "/save/data.txt", "w" );
    fputs( "ABCDEFG", fp );
    fclose( fp );
    EM_ASM(
	// 書き込み (false は省略できる)
        FS.syncfs( false, function(err){ } );
    );
}

// EXPORTED_FUNCTIONS に '_load_func' を加える必要あり
extern "C" void load_func()
{
    // 読み込みが完了したらアクセスできる
    EM_ASM(
        var  text= FS.readFile( '/save/data.txt', {flags:'r',encoding:'utf8'} );
        console.log( text );
    );
}

static void ems_loop()
{
    static int  count= 0;
    if( ++count == 60 * 3 ){
        save_func();
    }
}

int main()
{
    EM_ASM(
        FS.mkdir( '/save' );
        FS.mount( IDBFS, [], '/save' );

        // 読み込み
        FS.syncfs( true, function(err){
            ccall( 'load_func', 'v' );
        });
    );

    emscripten_set_main_loop( ems_loop, 60, true );
    return  0;
}

callback を使うので mail_loop が必要です。
いろいろ試していますが通常の C関数での読み込みがうまく行っていません。
JavaScript からは可能でした。

● NODEFS

ブラウザのように制限が無いため、node command の場合は NODEFS を
使って直接ローカルファイルにアクセスできます。

EM_ASM(
        FS.mkdir( '/save' );
        FS.mount( NODEFS, {root:'.'}, '/save' );
    );

mount 時の root option が実際の File System の Path 指定になります。
syncfs は不要。

● SOCKFS

read, write, open, close 等の標準 API で socket にアクセスできるようにするため、
Socket API は FileSystem の一種として実装されているようです。
実装上の内部的なものであって特に使用する必要はありません。

● 独自ファイルシステムを作る

MountType は FileSystem Object なので、
自分で FileSystem を作ることも可能です。

// chafs.js
mergeInto( LibraryManager.library, {
    chafs_init: function(){
        Module.CHAFS= {
            createNode: function( parent, name ){
                var node= FS.createNode( parent, name, 511 ); // 0777
                node.node_ops= {
                    lookup: function( parent, name ){
                        return  Module.CHAFS.createNode( parent, name );
                    },
                };
                node.stream_ops= {
                    open: function( stream ){
                    },
                    close: function( stream ){
                    },
                    read: function( stream, buffer, offset, length, position ){
                        // buffer を 'A' で埋めるだけ
                        for( var i= 0 ; i< length ; i++ ){
                            buffer[offset + i]= 65;
                        }
                        return  length;
                    },
                };
                return  node;
            },
            mount: function( mount ){
                return  Module.CHAFS.createNode( null, '/' );
            },
        };
    },
});

chafs_init() で FileSystem を作成しています。

// main.cpp
#include  
#include  

extern "C" void chafs_init();

static void load_func()
{
    FILE*   fp= fopen( "/save/data.txt", "r" );
    char    buf[128];
    size_t  size= fread( buf, 1, 10, fp );
    buf[size]= '\0';
    fclose( fp );
    printf( "%s\n", buf );
}

int main()
{
    chafs_init();  // 作成

    EM_ASM(
        FS.mkdir( '/save' );
        FS.mount( Module.CHAFS, [], '/save' );
    );
    load_func();
    return  0;
}

この例では CHAFS をマウントした '/save' 以下どのファイルを読み出しても、
すべて 'A' で埋められています。
ただし getattr を定義していないのでファイルサイズを取ることはできません。

関連エントリ
Emscripten C++ のアプリをブラウザで動かす (8) iOS でも動く
Emscripten C++/OpenGL ES 2.0 (7) Emscripten の OpenGL API と WebGL
Emscripten C++/OpenGL ES 2.0 (6) Chrome の速度と IE11/Safari
Emscripten C++/OpenGL ES 2.0 のアプリケーションをブラウザで動かす (5)
Emscripten C++/OpenGL ES 2.0 のアプリケーションをブラウザで動かす (4)
Emscripten C++/OpenGL ES 2.0 のアプリケーションをブラウザで動かす (3)
Emscripten C++/OpenGL ES 2.0 のアプリケーションをブラウザで動かす (2)
Emscripten C++/OpenGL ES 2.0 のアプリケーションをブラウザで動かす (1)
Emscripten C++/OpenGL ES 2.0 のアプリケーションをブラウザで動かす 一覧

Emscripten C++ のアプリをブラウザで動かす (8) iOS でも動く

実際に C/C++ で書かれたゲームを Emscripten で移植してみました。
プラグインなしにブラウザだけ動きます。

↓Windows Firefox
Windows Firefox の画面

ChiRaKS (Emscripten) ここから直接実行できます

● お勧めブラウザと端末

PC      : Chrome / Firefox / IE11 / Safari どれでも OK
Android : Chrome / Firefox どちらか (Krait , Cortex-A9 以降推奨)
iOS     : Safari (iOS7以降: iPhone 5s, iPad Air, iPad mini retina,
                  iOS8以降: iPhone5/5c, iPad4)

未確認ですがおそらく iPad Air, iPad mini retina でも動作します。
(2014/05/30 追記: 動作確認取れました)
(2014/09/19 追記: iOS8 で対応機種が増えました)

● CPU レンダリング

このゲームは CPU だけですべて描画しています。
つまり JavaScript で 3D 演算やライティング、ポリゴンのラスタライズも行っており、
それなりに演算負荷が高いアプリケーションとなっています。

PC 上では Chrome/Firefox/IE11/Safari いずれもフレームレート上限となり
高速に動作しておりレスポンスも十分。

Android 端末でも、最近のハイエンドな機種ではブラウザと思えないほど
快適にプレイできています。

● iOS でも動く

WebGL を使用していないので、これまで動かなかった OS やブラウザでも
走らせられるようになりました。

特に iPhone 5s の Safari はかなり高速に動作しています。
WebGL が使えないものの、Emscripten による iOS アプリの作成も
可能なことがわかりました。

↓iPhone 5s Safari
iOS 7.1 iPhone 5s

なお手持ちの iPad4/iPad3/iPhone5 では動かなかったので注意が必要です。
今のところ iOS で正しく動作するのは 64bit CPU (Apple A7) 搭載端末だけかもしれません。
よって iPad Air, iPad mini retina では動作するのではないかと思われます。
iPad Air / iPad mini retina でも動作することを確認しました。

● 動作テスト

下記は動作テストした環境一覧です。より詳しい表はこちら。

【おすすめ】         Chrome   Firefox   IE11    Safari    独自
----------------------------------------------------------------
Deskttop Windows8     30fps     30fps  30fps       --       --
Deskttop Ubuntu14     30fps     30fps     --       --       --
iPhone 5s iOS7.1       4fps        --     --    30fps       -- 
Kindle HDX 7          30fps     30fps     --       --    30fps (silk)
Tegra Note 7          30fps     30fps     --       --       --
Nexus 10              29fps     29fps     --       --       --
Nexus 7 (2013)        29fps     29fps     --       --       --
HTC J Butterfly     B 29fps   B 29fps     --       --       --
Nexus 7 (2012)      B 29fps   B 29fps     --       --       --
dtab 01             B 29fps   画面乱れ    --       --       --


【非推奨】           Chrome   Firefox   IE11    Safari    独自
----------------------------------------------------------------
HTC EVO 3D          D 10fps   C 20fps     --       --       --
Xperia acro              --   E  8fps     --       --    動作しない
iPad 4              E 1.8fps       --     --   動作しない   --
iPhone 5            E 1.7fps       --     --   動作しない   --
iPad 3              E 1.0fps       --     --   動作しない   --
PS Vita                  --        --     --       --   E 0.1fps

・fps値が大きい方が高速、ただし 30fps が上限
・B = 若干 FPS 値の変動あり。ほぼ 30fps で動作。
・C~D = 変動が大きく安定しない
・E = 低速で動作に支障あり

ページを読み込んだあと、速度が安定するまで多少時間がかかる場合があります。
おそらく JIT Compiler か GC と思われます。

ほぼ 100% CPU 性能に依存するため、
GPU が非力な Tegra 3 (Nexus 7 2012) でも結構良いスコアになっています。

● PlayStation Vita でも一応動く

PS Vita の内蔵ブラウザでも一応動くことがわかりました。
ただし非常に低速で 0.1fps。 ほぼ止まっているに等しい状態です。

↓PS Vita 内蔵ブラウザ
PS Vita

iOS 版 Chrome でも動きますが低速です。
PS Vita ブラウザ や iOS 版 Chrome が極端に遅いのは、
Native コンパイラが組み込まれていないためだと考えられます。

● Native アプリ

ブラウザではあまり速度が出ていない古い Android 端末でも、
こちらの Android Native アプリ版 では十分高速に動作していました。

アプリの方は画面サイズに応じてレンダリング解像度を
160×160 ~ 540×540 まで可変する構造になっているので、
画面が小さい機種ほど正確な比較にならないかもしれません。

速度差は生じているものの、常に 512×512 固定でレンダリングしている
Emscripten 版は、予想以上に頑張っているといえます。

● プログラムについて

ゲーム本体はすべて C/C++ で書かれており、ライブラリを抜いて 100 file ほど。
コンパイル後の js は約 900KB で、Data 込でも合計 1MB 弱です。

スコアの保存は Emscripten の IDBFS を使用しています。
IDBFS の読み書き (FS.syncfs) とレンダリング結果の画面転送だけ
JavaScript で記述しています。

ゲーム中は描画エリア (Canvas) の外部もタッチエリアとして使うことができます。
ゲームの状態を見てタッチイベントの動作を変えています。

ChiRaKS (Emscripten) 解説ページ

● まとめ

WebGL 無しなら iOS でも高速に動作する (iPhone 5s のみ) iOS8 以降は iOS も WebGL に対応しており iPhone 5s 以外でも動きます
・C/C++ で書かれた資産を活用可能
・PC, Android, iOS 全てに対応したアプリ開発へ応用可能

関連エントリ
Emscripten C++/OpenGL ES 2.0 (7) Emscripten の OpenGL API と WebGL
Emscripten C++/OpenGL ES 2.0 (6) Chrome の速度と IE11/Safari
Emscripten C++/OpenGL ES 2.0 のアプリケーションをブラウザで動かす (5)
Emscripten C++/OpenGL ES 2.0 のアプリケーションをブラウザで動かす (4)
Emscripten C++/OpenGL ES 2.0 のアプリケーションをブラウザで動かす (3)
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 (7) Emscripten の OpenGL API と WebGL

Emscripten の OpenGL API には 3 つの動作モードがあります。

(1) defaut (WebGL-friendly subset of OpenGL)
(2) -s FULL_ES2=1 (OpenGL ES 2.0 emulation)
(3) -s LEGACY_GL_EMULATION=1 (OpenGL emulation of older desktop and mobile versions)

(1) は WebGL 命令をほぼそのまま OpenGL ES 2.0 API にコンバートしたものです。

(2) は (1) に加えて OpenGL ES 2.0 の足りない機能を補っています。
WebGL は VertexBuffer を経由しない描画をサポートしていないためです。

(3) は WebGL 上で OpenGL 1.x の固定パイプラインをエミュレートしています。
各種レンダーステートにより、動的にシェーダーの生成も行っているようです。

通常は (1) のままで十分ですが、もし正しく描画されない要素がある場合は
(2) を試すことが可能です。
具体的には glVertexAttribPointer() や glDrawElements() の最後の引数に、
直接データのポインタを渡している場合が相当します。
もともと GPU Hardware 的にも望ましくない機能であること、
また Emscripten でのエミュレーションもオーバーヘッドが生じるため
Client Side Arrays は出来る限り使わないことが推奨されています。

● GPU/Browser 毎の Extension

前回のデータを Android 端末含めてさらに集めてみました。
詳細は下記ページへ

WebGL Extensions (Emscripten)

テクスチャ

                                   TS RTS CTex Depth ANI Float Half
W8  Intel HD G 4000   Firefox 29   8K  8K  DXT   Y    Y   Y-L   Y
W8  Intel HD G 4000   Chrome 35    8K  8K  DXT   Y    Y   Y-L   Y-L
W8  Intel HD G 4000   IE 11       16K 16K  DXT   N    Y   Y-L   N
W8  RADEON HD 6750M   Firefox 29  16K 16K  DXT   Y    Y   Y-L   Y
W8  RADEON HD 6750M   Chrome 35   16K 16K  DXT   Y    Y   Y-L   Y-L
W8  RADEON HD 6750M   IE 11       16K 16K  DXT   N    N   Y-L   N
W7  GeForce GTX650    Firefox 29  16K 16K  DXT   Y    Y   Y-L   Y
W7  GeForce GTX650    Chrome 35   16K 16K  DXT   Y    Y   Y-L   Y-L
W7  GeForce GTX650    IE 11       16K 16K  DXT   N    N   Y-L   N
OSX RADEON HD 6750M   Firefox 29  16K 16K  DXT   Y    Y   Y-L   Y
OSX RADEON HD 6750M   Chrome 35    4K 16K  DXT   Y    Y   Y-L   Y-L
OSX RADEON HD 6750M   Safari 7    16K 16K  DXT   Y    Y   Y     N
OSX Intel HD G 4000   Firefox 29   4K  4K  DXT   Y    Y   Y-L   Y
OSX Intel HD G 4000   Chrome 35    4K 16K  DXT   Y    Y   Y-L   Y-L
OSX Intel HD G 4000   Safari 7    16K 16K  DXT   Y    Y   Y     N
U14 RADEON HD 6750M   Firefox 29  16K 16K  DXT   Y    Y   Y-L   Y
U14 RADEON HD 6750M   Chrome 35   16K 16K  DXT   Y    Y   Y-L   Y-L
U14 RADEON R3         Firefox 29  16K 16K  DXT   Y    Y   Y-L   Y
U14 RADEON R3         Chrome 35   16K 16K  DXT   Y    Y   Y-L   Y-L
U14 Intel HD G        Firefox 29   8K  8K  DXT   Y    Y   Y-L   Y

                                   TS RTS CTex Depth ANI Float Half
A42 S80 Adreno 330    Firefox 29   4K  4K  ATC   Y    Y   Y     Y
A42 S80 Adreno 330    Chrome 35    4K  4K  ---   N    Y   Y     Y-L
A44 S4P Adreno 320    Firefox 29   4K  4K  ATC   Y    Y   Y     Y
A44 S4P Adreno 320    Chrome 35    4K  4K  ---   N    Y   Y     Y-L
A44 T4  ULP GeForce72 Firefox 29   4K  4K  DXT   N    Y   N     Y
A44 T4  ULP GeForce72 Chrome 35    4K  4K  DXT   N    Y   N     Y-L
A44 E5  Mali-T604     Firefox 29   8K  8K  ---   Y    N   Y-L   Y
A41 K3  VivanteGC4000 Firefox 29   8K  8K  ---   Y    Y   Y     Y
A44 T3  ULP GeForce12 Firefox 29   2K  2K  DXT   N    Y   N     Y
A44 T3  ULP GeForce12 Chrome 35    2K  2K  DXT   N    Y   N     Y
A42 OM4 PVR SGX540    Firefox 29   2K  2K  PVR   Y    N   Y     Y
A41 R66 Mali-400MP4   Firefox 29   4K  4K  ---   Y    N   N     N
A40 S3  Adreno 220    Firefox 29   4K  4K  ATC   Y    Y   Y     Y
A23 S2  Adreno 205    Firefox 29   4K  4K  ATC   Y    Y   Y     Y

TS   = GL_MAX_TEXTURE_SIZE
RTS  = GL_MAX_RENDERBUFFER_SIZE
CTex = 対応している圧縮テクスチャフォーマット
Depth= WEBGL_depth_texture
ANI  = EXT_texture_filter_anisotropic
Float= OES_texture_float (Y-L は OES_texture_float_linear)
Half = OES_texture_half_float (Y-L は OES_texture_half_float_linear)

W8=Windows8.1, W7=Windows7, OSX=10.9, U14=Ubuntu14.04, A44= Android 4.4

圧縮テクスチャは、Desktop では 100% DXT1~DXT5 (S3TC) が利用可能となっています。
Android は通常の OpenGL ES 2.0 と同じく GPU によって DXT/ATC/PVR とばらばら。
Android が共通でサポートしているはずの ETC1 が列挙されていませんが、
本当に使えないのかどうかは未確認。

DXT に対応しているはずの Vivante GC4000 が未対応となっているのは、
ブラウザの WebGL Layer が GL_COMPRESSED_TEXTURE_FORMSTS ではなく、
GL_EXTENSIONS だけチェックしているからではないかと思われます。

テクスチャ以外

                                   Uniform  In/Out EInt VAO Ins DB sRGB
W8  Intel HD G 4000   Firefox 29   254/ 221 16/10   Y    N   N   N   N
W8  Intel HD G 4000   Chrome 35    254/ 221 16/10   Y    Y   Y   N   N
W8  Intel HD G 4000   IE 11        512/ 512 16/14   N    N   N   N   N
W8  RADEON HD 6750M   Firefox 29   254/ 221 16/10   Y    N   N   N   N
W8  RADEON HD 6750M   Chrome 35    254/ 221 16/10   Y    Y   Y   N   N
W8  RADEON HD 6750M   IE 11        512/ 512 16/14   N    N   N   N   N
W7  GeForce GTX650    Firefox 29   254/ 221 16/10   Y    N   N   N   N
W7  GeForce GTX650    Chrome 35    254/ 221 16/10   Y    Y   Y   N   N
W7  GeForce GTX650    IE 11        512/ 512 16/14   N    N   N   N   N
OSX RADEON HD 6750M   Firefox 29   768/ 768 16/16   Y    Y   N   Y   Y
OSX RADEON HD 6750M   Chrome 35    768/ 768 16/32   Y    Y   Y   Y   N
OSX RADEON HD 6750M   Safari 7     768/ 768 16/32   Y    Y   N   N   N
OSX Intel HD G 4000   Firefox 29  1024/1024 16/16   Y    Y   Y   Y   Y
OSX Intel HD G 4000   Chrome 35   1024/1024 16/15   Y    Y   Y   Y   N
OSX Intel HD G 4000   Safari 7    1024/1024 16/15   Y    Y   N   N   N
U14 RADEON HD 6750M   Firefox 29  4096/4096 29/32   Y    Y   Y   Y   Y
U14 RADEON HD 6750M   Chrome 35   4096/4096 29/32   Y    Y   Y   Y   N
U14 RADEON R3         Firefox 29   256/ 256 29/32   Y    Y   Y   Y   Y
U14 RADEON R3         Chrome 35    256/ 256 29/32   Y    Y   Y   Y   N
U14 Intel HD Graphics Firefox 29  4096/4096 16/32   Y    Y   Y   Y   Y

                                   Uniform  In/Out EInt VAO Ins DB sRGB
A42 S80 Adreno 330    Firefox 29   256/ 224 16/16   Y    Y   N   N   N
A42 S80 Adreno 330    Chrome 35    256/ 224 16/16   Y    Y   N   N   N
A44 S4P Adreno 320    Firefox 29   256/ 224 16/16   Y    Y   Y   Y   N
A44 S4P Adreno 320    Chrome 35    256/ 224 16/16   Y    Y   N   N   N
A44 T4  ULP GeForce72 Firefox 29   280/1024 16/15   N    Y   N   N   N
A44 T4  ULP GeForce72 Chrome 35    280/1024 16/15   N    Y   N   N   N
A44 E5  Mali-T604     Firefox 29  1024/1024 16/15   Y    Y   Y   Y   N
A41 K3  VivanteGC4000 Firefox 29   568/ 568 16/12   Y    N   N   N   N
A44 T3  ULP GeForce12 Firefox 29   256/1024 16/15   N    N   N   N   N
A44 T3  ULP GeForce12 Chrome 35    256/1024 16/15   N    Y   N   N   N
A42 OM4 PVR SGX540    Firefox 29   128/  64  8/ 8   Y    Y   N   N   N
A41 R66 Mali-400MP4   Firefox 29   256/ 256 16/12   N    N   N   N   N
A40 S3  Adreno 220    Firefox 29   251/ 221 16/ 8   Y    Y   N   N   N
A23 S2  Adreno 205    Firefox 29   251/ 222 16  8   Y    N   N   N   N

Uniform = Vsh/Fsh
In/Out  = Attribute/Varying
EInt    = OES_element_index_uint (32bit index)
VAO     = OES_vertex_array_object
Ins     = ANGLE_instanced_array
DB      = WEBGL_draw_buffers
sRGB    = EXT_sRGB

基本的には GPU に依存しますが、さらにブラウザごとにフィルタがかかっている印象です。
Desktop Native では対応してるはずの機能もブラウザによっては無効となっています。
Mobile GPU はもともとこんな感じだったので、それほど驚きはないでしょう。

対応度のばらつきが大きく、最適化以外ではあまり積極的に利用しない方が良いことがわかります。
OpenGL ES 2.0 の要求レベルが低いためで、WebGL 2.0 が OpenGL ES 3.x
ベースになるならもう少し統一されるのではないでしょうか。

動作は遅いものの Firefox + WebGL は Android 2.3 時代の端末でも動作しました。

関連エントリ
Emscripten C++/OpenGL ES 2.0 (6) Chrome の速度と IE11/Safari
Emscripten C++/OpenGL ES 2.0 のアプリケーションをブラウザで動かす (5)
Emscripten C++/OpenGL ES 2.0 のアプリケーションをブラウザで動かす (4)
Emscripten C++/OpenGL ES 2.0 のアプリケーションをブラウザで動かす (3)
Emscripten C++/OpenGL ES 2.0 のアプリケーションをブラウザで動かす (2)
Emscripten C++/OpenGL ES 2.0 のアプリケーションをブラウザで動かす (1)
Emscripten C++/OpenGL ES 2.0 のアプリケーションをブラウザで動かす 一覧