【Unity】Shaderで使うfloat,half,fixed精度によるパフォーマンスの違い

2019/07/01DEVELOP, Unity

シェーダーを書いていて、特にモバイル端末でのパフォーマンスが気になることが多々あります。なんとかフレームレートを改善して快適な操作を保ちたい。そんな中、いくつかの最適化方法を試す中で恐らく試すであろう

「データ型の精度を調整する」

ことに関して検証してみようと思います。正直、実際問題どの程度の改善がみられるのかシンプルなベンチマークを取る機会が少なかったのでUnityを使って改めて計測してみようと思いました。

検証環境

  • Unityバージョン 2019.1.0f2
  • 端末 HTC 10

Cubeにテクスチャを貼り付けたものを5000体インスタンスを生成する。その際のフラグメントのコードは以下の通り

float4 frag (v2f i) : SV_Target
{
	float4 col = tex2D(_MainTex, i.uv);
	return col;
}

とにかくシンプルなものにしました。このfloatの部分をhalf、fixedと置き換えて計測します。

精度の違い

  • half: 16bit
  • fixed: 11bit
  • float: 32bit

パフォーマンス計測には以下のAssetを使用しました。
[Graphy] – Ultimate FPS Counter – Stats Monitor & Debugger – Asset Store

計測結果

  • float 25~27
  • half 30~31
  • fixed 29~31

float の結果は予想通りでしたが、シンプル過ぎたシェーダーのせいかhalfとfixedとでは、誤差の範囲での結果となりました。

もう少し計算量を増やしてみる

少し計算量を増やしてみます。

float4 frag (v2f i) : SV_Target
{
    float4 col = tex2D(_MainTex, i.uv);
    float4 col2 = tex2D(_MainTex, i.uv);
    float4 col3 = tex2D(_MainTex, i.uv);
    float4 col4 = tex2D(_MainTex, i.uv);
    return col * col2 * col3 * col4;
}
  • float 20~22
  • half 20~22
  • fixed 20~22

検証端末ではhalfとfixedの差は見受けられない結果となりました。少し不思議ですが、これはGPUの種類によって、サポートされているデータ型の精度が異なるための様です。

シェーダーのデータ型と精度 – Unity マニュアル

使い分け

どのデータ型を使うべきかは公式にも書いてありますが

高精度: float
float は最高精度の浮動小数点値で、通常のプログラミング言語の float と同じように一般な 32 ビットです。
フルfloat の精度は、一般に、ワールド空間位置、テクスチャ座標、または三角法やべき乗/べき乗などの複雑な関数を含むスカラー計算に使用されます。
中精度: half
half は中精度の浮動小数点値で、一般に 16 ビットです (–60000 から +60000 の範囲で、小数点以下約 3 桁)。
half は、ショートベクトル、方向、オブジェクト空間位置、HDR カラー に使用されます。
低精度: fixed
fixed は低精度で、固定小数点数です。一般的に 11 ビットで、–2.0 から +2.0 の範囲で、1/256 精度です。
fixed 精度は、標準カラー (一般的に標準テクスチャに保管されるので) とそれらの単純な制御に使用されます。

https://docs.unity3d.com/ja/current/Manual/SL-DataTypesAndPrecision.html

これで良いと思います。また、PC環境ではどれもfloatとして扱われるそうです。

結論

floatよりhalf・fixedに変更することでフレームレートの改善は見受けられるので試す価値はある。

Posted by kazupon