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

PlayStation Suite と対応ハードの性能比較

PlayStation Suite Developer Program より対応ハード一覧。
2012/04/19 現在。

device         SoC      CPU core             GPU core           RAM     display
-------------------------------------------------------------------------------
Xperia PLAY    MSM8255  Scorpion  1.0GHz     Adreno 205         512MB   854x480
Xperia arc     MSM8255  Scorpion  1.0GHz     Adreno 205         512MB   854x480
Xperia acro    MSM8255  Scorpion  1.0GHz     Adreno 205         512MB   854x480
Sony Tablet P  Tegra250 Cortex-A9 1.0GHz x2  ULP GeForce(8)     1GB    1024x960
Sony Tablet S  Tegra250 Cortex-A9 1.0GHz x2  ULP GeForce(8)     1GB    1280x800
Xperia acro HD MSM8260  Scorpion  1.5GHz x2  Adreno 220         1GB    1280x720
Xperia S       MSM8260  Scorpion  1.5GHz x2  Adreno 220         1GB    1280x720
Xperia ion     MSM8260  Scorpion  1.5GHz x2  Adreno 220         1GB    1280x720
PS Vita                 Cortex-A9   ?GHz x4  PowerVR SGX543MP4+ 640MB   960x544

すべて ARMv7A + OpenGL ES 2.0 世代。
機能的には Tegra2, 速度的には single core 1.0GHz + Adreno205 が
最低スペックとなるようです。

素の Android で同等の開発を行う場合 Java + OpenGL ES 2.0 となりますが、
PC 上で同作する Emulator が安定しなかったり、最近になってやっと
GPU や OpenGL ES 2.0 がサポートされたりと、
端末や OS 互換性の問題だけでなく開発環境そのものにも制約が多かったのも事実。

PSS は簡単に導入できて Emulator まであっさり起動するので
Android の苦労が嘘のようです。

上の表はこちらにもまとめています。

PlayStation Suite 対応ハード

iPad 3 PowerVR SGX543MP4 の速度

更新しました。

Mobile GPU bench mark

間違いなく PowerVR SGX543MP4 は最強です。
これまでのハイエンドグループのスコアの 2倍程度出ています。
でもそれをもってしても 2048×1536 の解像度は一筋縄では
いかないようです。
速度優先ならレンダリング解像度を下げる必要がありそうです。

またこれだけハイレゾになるとピクセルに負担をかけるのは現実的で
ないので、多くの処理を頂点で行い 3D モデルを適度に
ハイポリ化した方が良いと思われます。
2D も 3D もベクタ化を考えた方が良さそうです。

関連エントリ
頂点性能の比較 その2 (OpenGL ES 2.0 Mobile GPU)
A5 PowerVR SGX543MP2 は iOS 5 だと速い
さらに OpenGL ES 2.0 Mobile GPU の速度比較
OpenGL ES 2.0 Mobile GPU の速度比較 (dual core世代) 更新

OpenGL ES 2.0 GLSL precision 宣言と GPU 毎の演算精度を調べる

OpenGL ES 2.0 の GLSL では highp, mediump, lowp と 3種類の
演算精度の宣言ができます。
C言語の float と double のようなもので、浮動小数点演算の場合
highp が 24~32bit、mediump が 16bit (half)、lowp はそれ
以下となります。
実際に用いられる演算精度は実装に依存しており GPU によって異なります。

一般的に演算精度を下げることによってレジスタの消費量を抑える
ことができ、並列実行可能なスレッド数の低下を防ぐことができます。
また純粋に ALU の演算能力不足を補うために低精度宣言が効果的な
GPU もあります。
逆にこれらの宣言が全く意味を持っていない GPU もあります。
現在の Mobile 向け GPU はどれも設計思想が異なっており
その特性は千差万別です。

最適化するためにはどこまで演算できるか限界をある程度把握して
おく必要があります。
OpenGL ES の命令 glGetShaderPrecisionFormat() を使うと
演算精度のより詳しい情報が得られます。
各 GPU 毎に調べた値を下記のページに加えました。

Mobile GPU の Extension

// 例 PowerVR SGX
Precision
 0: [1 1] 8
 1: [14 14] 10
 2: [126 126] 23
 3: [8 8] 0
 4: [11 11] 0
 5: [24 24] 0
 6: [1 1] 8
 7: [14 14] 10
 8: [126 126] 23
 9: [8 8] 0
10: [11 11] 0
11: [24 24] 0

[range-min range-max] precision
上から順に vertex float lowp~highp, int lowp~highp,
fragment float lowp~highp, int lowp~highp

この情報をもとにまとめたのが下記ページの表です。

GPU Precision まとめ

以下は FLOAT 部分のみの抜粋です。

                        Vertex Shader        Fragment Shader
FLOAT                   high medium low      high medium low
--------------------------------------------------------------
Adreno 200系 unified    fp32  fp32  fp32     fp32  fp32  fp32
GC860        unified    fp32  fp32  fp32     fp32  fp32  fp32
PowerVR SGX  unified    fp32  fp16  fix10    fp32  fp16  fix10
Mali-400MP   discrete   fp32  fp32  fp32     ----  fp16  fp16
Tegra2/3     discrete   fp32  fp32  fp32     ----  fp20? fix10

まず大きく分けて Unified タイプと Discrete の GPU があります。
Unified は Vertex と Fragment の演算機能が同一です。
また Discrete タイプの Fragment Shader はどれも highp 未対応です。

Unified : Adreno/GC800/PowerVR  Vertex Fragment同一
Discrete: Mali-400/Tegra2/3     Fragment に highp無し

常に精度一定な GPU と precision 系(lowp等)の宣言が有効な GPU があります。

無効: Adreno 200系/GC860/Mali-400?
有効: PowerVR SGX/Tegra2/3

また Vertex Shader の場合、PowerVR SGX 以外はどれも fp32 固定で
highp だけが用いられているように見えます。
ですが、実際にシェーダーを走らせて演算範囲を検証すると、上記の
結果と異なっていることがわかりました。

例えば Vertex Shader で下記のようにわざと演算精度を落とすような
演算を加えてみます。

// Vertex Shader
vec2  uv= TEXCOORD0.xy * 0.01;
uv+= 1.0;
~
vTexcoord.xy= uv * 100.0 - 100.0;

Tegra では明らかに mediump, lowp 宣言の影響を受けます。
また Mali-400MP もわずかに違いが見られます。

わかりやすくするためカラーを用いました。
Fragment Shader なら下記のようにして SCALE の値がどの範囲まで
正しく描画できるか調べます。

// Fragment Shader (Pixel Shader)
precision mediump float;
#define SCALE  100.0
#define PREC   lowp
varying mediump vec2 vTexcoord;
varying PREC vec4 vColor;   // == vec4(1.0)
uniform lowp sampler2D ColorMap;
void main()
{
    PREC vec4  color= texture2D( ColorMap, vTexcoord );
    color*= vColor.x * SCALE;         // -- (A)
    color*= vColor.y * (1.0/SCALE);   // -- (B)
    gl_FragColor= color;
}

例えば PowerVR や Tegra の lowp なら SCALE が 2 を超えると
色が暗くなり、大きく範囲を外れると color が 0 になります。
上限 2.0 で clamp されていることがわかります。

反対に highp 固定の Adreno/GC860 の場合は lowp と書いてあっても
1.0e37 まで正しい色で描画できます。

(A) と (B) を入れ替えたり SCALE を負数にしても試します。
Vertex Shader でも頂点カラーを使い同様に調べられます。
値の範囲から実際の演算精度を予想し、highp, mediump, lowp 毎に
まとめ直したのが下記の表です。

                           Vertex Shader        Fragment Shader
                           high medium low      high medium low
------------------------------------------------------------------
PVR SGX535/540  unified    fp32  fp16  fix10    fp32  fp16  fix10
PVR SGX543MP    unified    fp32  fp16  fix10    fp32  fp16  fix16?
Tegra2          discrete   fp32  fp16  fix10?   ----  fp16  fix10
Mali-400MP      discrete   fp32  fp32  fp32     ----  fp16  fp16
Adreno 200系    unified    fp32  fp32  fp32     fp32  fp32  fp32
GC860           unified    fp32  fp32  fp32     fp32  fp32  fp32

exp 範囲から推測しているので間違っている可能性があります。

●PowerVR SGX

ほぼ仕様通りで Vertex/Fragment 共に 3段階、明確な違いがあります。
lowp は -2.0~2.0 の範囲のみとなります。
ただ GPU によって Fragment mediump の範囲にばらつきが生じます。
543MP は Fragment lowp で mediump 相当の値を示していますが、
計測に問題があった可能性があります。

●Tegra2

Vertex Shader は PowerVR SGX 同様 3段階の違いがはっきり現れます。
ただし Vertex lowp は -2.0~2048 の範囲が有効だったので、計測に
間違いがなければ正の方向にオフセットが加えられているようです。
より精度が高い可能性があります。
Fragment mediump は普通の fp16 でした。

●Mali-400MP

Vertex Shader の演算範囲は mediump/lowp の影響を受けず
fp32 固定でした。
ただし precision で default 宣言を行うと mediump で描画に差が生じます。
レジスタと ALU が fp32 固定でも uniform / varying が fp16 に
切り替わっている可能性があります。lowp はありません。
Fragment は fp16 固定でした。

●Adreno 200/205/220 / Vivante GC860

すべて fp32 固定でした。
mediump / lowp の影響を受けません。

これらの実際に計測した結果も下記のページにまとめています。
整数は調べていません。

GPU Precision まとめ

(2012/03/03 修正: fix8 を fix10 に訂正させて頂きます。コメントによる指摘ありがとうございました。)

関連エントリ
OpenGL ES 2.0 shader の演算精度

OpenGL ES 2.0 Adreno 205 と discard 命令の問題

GPU Adreno 205 は Fragment Shader で discard 命令を使うと
フリーズし、OS ごと再起動することがあるようです。
コメントchototsu さんより情報を頂きました。
ありがとうございました。

試したらあっさり再現してしまいました。
ドライバレベルで停止しているらしく発生すると何もできなくなります。
デバッガで強制的にプロセスを削除すると OS ごと再起動します。
またはシェーダー実行直後に何もしなくても OS がリブートします。

試した機種
Xperia Ray SO-03C Android 2.3.3
Qualcomm MSM8255 1.0GHz Adreno 205

Adreno 200/220 では発生しません。205 だけです。
ただ 205 でもフリーズしないケースもあったので、条件を変えて
症状を調べてみました。

結論としては
FragmentShader で Texture を使用している場合に、
discard 命令より後で Texture フェッチが発生すると固まります。

Alpha Test や Clip Plane 等で discard を使う場合は
十分注意した方がよさそうです。

以下検証した結果

●Texture を使っていないシェーダーの場合

(1) 無条件 discard は固まらない
(2) varying 依存 discard も固まらない

// (1)  問題なし
precision mediump float;
void main()
{
    discard;
}
// (2)  問題なし
precision mediump float;
varying vec2 vTexcoord;
void main()
{
    if( vTexcoord.x < 0.5 ){
        discard;
    }
    gl_FragColor= vec4(1.0, 1.0, 0.0, 1.0);
}

●Texture を使っているシェーダーの場合

(3) 無条件 discard はどこに挿入しても固まる。
(4) texture 依存 discard は shader の一番最後なら固まらない。
  ・すべての texture 読み込み命令のあとなら固まらない。
(5) varying 依存 discard も (4) と同じだが、texture フェッチの
  前でも固まらない場合があった。

// (3)  freeze
precision mediump float;
varying vec2 vTexcoord;
uniform lowp sampler2D ColorMap;
void main()
{
    // discard; ここでも同じ
    gl_FragColor= texture2D( ColorMap, vTexcoord );
    discard;
}
// (4) - A  問題なし
precision mediump float;
varying vec2 vTexcoord;
uniform lowp sampler2D ColorMap;
void main()
{
    lowp vec4  color= texture2D( ColorMap, vTexcoord );
    if( color.w < 0.7 ){
        discard;
    }
    gl_FragColor= color;
}
// (4) - B  freeze
precision mediump float;
varying vec2 vTexcoord;
uniform lowp sampler2D ColorMap;
void main()
{
    lowp vec4  color= texture2D( ColorMap, vTexcoord );
    if( color.w < 0.7 ){
        discard;
    }
    color+= texture2D( ColorMap, vTexcoord + vec2(0.1,0.1) );
    gl_FragColor= color;
}
// (4) - C  問題なし
precision mediump float;
varying vec2 vTexcoord;
uniform lowp sampler2D ColorMap;
void main()
{
    lowp vec4  color= texture2D( ColorMap, vTexcoord );
    color+= texture2D( ColorMap, vTexcoord + vec2(0.1,0.1) );
    if( color.w < 0.7 ){
        discard;
    }
    gl_FragColor= color;
}
// (5) - A  freeze
precision mediump float;
varying vec2 vTexcoord;
uniform lowp sampler2D ColorMap;
void main()
{
    if( vTexcoord.x < 0.5 ){
        discard;
    }
    gl_FragColor= texture2D( ColorMap, vTexcoord );
}
// (5) - B  問題なし
precision mediump float;
varying vec2 vTexcoord;
uniform lowp sampler2D ColorMap;
void main()
{
    gl_FragColor= texture2D( ColorMap, vTexcoord );
    if( vTexcoord.x < 0.5 ){
        discard;
    }
}

テクスチャ命令との順番が関係しています。(3),(5) に関しては
例外もありますが discard が Texture と依存関係が無いので、
コンパイラによって命令の実行順が変更されたためだと考えられます。

対策としては discard を使わないか、すべてのテクスチャ命令のあと
出来るだけ最後に記述するようにします。

ただ幸いなことに、discard は半透明と同じように TBDR の PowerVR
と大変相性が悪い命令です。さまざまな GPU への対応を考えると、
おそらくテクスチャを多数読み込むような複雑なシェーダーでは、
discard があまり積極的に用いられていないのではないかと思います。
(Adreno でもあまり推奨されていません。)

また discard の用途は多くが Alpha Test だと思うので、この場合
必ず Texture 命令のあとに用いられます。
上と同じ理由でテクスチャ一枚きりの単純なものが多く、今まで
あまり問題になっていなかったのではないかと考えられます。

関連エントリ
さらに OpenGL ES 2.0 Mobile GPU の速度比較