OpenGL ES 2.0 Tegra2/3/4 の Fragment Shader と動的ループ

Desktop GPU で Vertex Shader と Pixel Shader の仕様が完全に
統一されたのは Direct3D 10 の ShaderModel 4.0 からです。
それまでは使える命令や Constant 領域、レジスタ数、プログラムサイズ、
テクスチャ命令など様々な違いが残っていました。

Hardware の Unified Shader 化は ATI の Xbox360 GPU が先行しています。
これが今の Qualcomm Adreno に繋がっていきます。
その後一般の Desktop PC 向けにも NVIDIA GeForce 8800 (G80) が登場し、
以後 Unified Shader model が当たり前となっています。

OpenGL ES 2.0 の Shader 世代は Direct3D 9 の Shader Model 3.0 に相当
するのですが、Mobile GPU の多くはすでに Unified Shader です。
そのためあまり Vertex と Fragment Shader の機能差を意識する必要が
ありませんでした。

そんな中、Tegra2/3/4 は G70 ベースの GPU であり、Unified Shader 化する前の
制限が残っている珍しいケースとなっています。

コメントで Tegra の Fragment Shader は動的ループが使えないとの
指摘を頂いたので試してみました。

// (1) 動的ループ
int loop= int( uniform_value );
for( int i= 0 ; i < loop ; i++ ){
   ...
}

↑ループ回数を動的に求めた場合、Vertex Shader は通りますが
Fragment Shader ではコンパイル時にエラーが発生します。

以前書いたように Uniform 配列の index アクセス ↓(2) も
Tegra の Fragment Shader ではエラーとなります。
どちらも Direct3D 9 世代の制限と考えられます。

// (2) Uniform 配列
uniform vec4 src_color[30];
~
int index= int(tex_color.x);
vec4 color= src_color[ index ]; // Tegra の Fragment Shader では Error

Tegra 4 でも同様なので、大幅に機能拡張されていても GPU のベースは
同じであることがわかります。
なお Tegra と同じように Discrete Type の Shader Unit を備える
Mai-400MP では動きました。

	     Vertex Shader            Fragment Shader
	     動的Loop  Uniform配列    動的Loop  Uniform配列
-----------------------------------------------------------
Unified      ◯         ◯              ◯         ◯
Mali-400MP   ◯         ◯              ◯         ◯
Tegra2/3/4   ◯         ◯              ERROR     ERROR

ただし Tegra でも動的分岐はできるので、実行時にループ回数が変動する
場合でも同等の処理を実現することは可能です。

// (3) Tegra向け 動的分岐によるループ
for( int i= 0 ; i< 100 ; i++ ){
    if( i >= Loop ){
        break;
    }
    ~ 動的ループ相当
}

以下まとめ (いずれも Fragment Shader の場合)

コンパイル時にループ回数が定まらない場合はエラー。

// (4) ループ回数不定  -- Tegra で ERROR
for( int i= start ; i< end ; i++ ){
    ~
}

ループの範囲が決まっていればコンパイル可能。

// (5) 上限が決まってる場合 -- Tegra でも OK
for( int i= 0 ; i< 100 ; i++ ){
    if( i >= start && i < end ){
        ~ 動的ループ相当
    }
}

おそらく下記のように展開されているものと考えられます。

i= 0;
if( i >= start && i < end ){
    ~
}
i= 1;
if( i >= start && i < end ){
    ~
}

~

i= 99;
if( i >= start && i < end ){
    ~
}

Tegra K1 以降は ShaderModel 5.0 世代の GPU core になるので
このようなハードウエア的な制限はなくなるでしょう。

GPU 互換性など気軽に相談してください。

関連エントリ
OpenGL ES 2.0 Adreno 330, Tegra 4 の GPU 速度
OpenGL ES 2.0 で迷路シェーダー
GLSL互換性

OpenGL ES 2.0 Tegra2/3/4 の Fragment Shader と動的ループ” に1件のフィードバックがあります

  1. かみやん

    詳細なレポートありがとうございます!
    大変勉強になりました。

コメントは停止中です。