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

OpenGL 4.3/GLES 3.0 次の圧縮テクスチャ ASTC

DXTC(S3TC)/PVRTC/ETC1/ETC2 など、4×4 block を 64bit 単位で
変換する圧縮テクスチャフォーマットが第一世代なら、
128bit 単位で処理する BC6H/BC7 (BPTC) は第二世代の新しい
圧縮テクスチャフォーマットと言えます。

64bit の枠を超えた余剰 bit を、モード分岐やパーティション分割等
画質を向上させるための様々な情報として用います。

ASTC も同様で、BC6H/BC7(BPTC) と同じように 128bit 単位で圧縮を
行います。その仕組はさらに複雑でより踏み込んだ内容でした。

 ・128bit 単位
 ・複雑なモード分岐
 ・Dual Plane 機能 (Index を 2セット持つ)
 ・Partition 分割 (カラーセット Endpoint を複数持つ)

これらの特徴は BC6H/BC7(BPTC) と共通のものです。
ASTC にはさらに独自の仕様が多数含まれています。

 ・可変 Block サイズ (4×4 ~ 12×12)
 ・最大 4分割 の Partition (BPTC は 3分割まで)
 ・2,3,5 の 3種類の基数選択
 ・1~4 component の自由なフォーマット (R,RG,RGB,RGBA)

Khronos の仕様では LDR モードのみ定義されていますが、
ARM のドキュメントでは 3D texture や HDR まで言及されており
より幅広い用途が想定されていたことがわかります。

KHR_texture_compression_astc_ldr
ARM Mali developer Center: ASTC Evaluation Codec

bit field は非常に自由で、モードと Endpoint (代表カラー値) が
下位 bit から、Index (Texel Weight) が上位 bit から必要個数並ぶという
可変フォーマットです。
そのため組み合わせ数は膨大で単純なモード数では表現できません。

また 2進数からくる制約が少ないのも大きな特徴の一つです。
例えば block サイズも 5×5 , 6×6 , 10×8 など中途半端なサイズを
選ぶことができます。
Index によるカラーの補間も、DXT 等では 2bit なので 4段階ですが、
ASTC では 3値や 5値等の任意の段階を選ぶことができます。

DXT では 2色の代表カラーを選んでも、4階調だとちょうど中間の値を
生成することができません。画像によっては都合が悪く、敢えて
DXT1 の 3色モード (Alpha 1bit) を用いることがありました。

ASTC は 3 と 5 の基数を用いることができます。
5つの 3階調値を 8bit (3^5 = 243) に格納し、同様に 3つの 5階調値を
7bit (5^3 = 125) に収めます。
これに任意ビット数のスケール値を掛けることで、2 の n 乗に制限されず
下記の値の範囲を格納することができます。

 3 (0-2) =  3  + 0bit
 4 (0-3) =       2bit
 5 (0-4) =  5  + 0bit
 6 (0-5) =  3  + 1bit = 3 * 2
 8 (0-7) =       3bit
10 (0-9) =  5  + 1bit = 5 * 2
12 (0-11)=  3  + 2bit = 3 * 4
 :

例えば 12 (0~11) 段階をエンコードするなら 5個単位で格納します。
それぞれが 2bit のスケールを持つので、8bit + 5*2bit = 18bit (5個分)
となります。

このようにより自由なエンコードアルゴリズムを用いつつ、かつハードウエアで
実装しやすいようさまざまな工夫が施されています。

関連エントリ
OpenGL 4.3/ES 3.0 ETC2 Texture 圧縮の仕組み (PVRTC2,ASTC)
Direct3D11/OpenGL 圧縮テクスチャ BPTC, BC6H/BC7 の詳細構造 (2)
Direct3D11/OpenGL 圧縮テクスチャ BPTC, BC6H/BC7 の詳細構造 (1)
OpenGL の圧縮テクスチャ (3) BPTC, BC6H/BC7
OpenGL の圧縮テクスチャ (2) 法線圧縮
Android OpenGL ES 2.0 の圧縮テクスチャ

OpenGL ES 3.0 / OpenGL 4.3 ETC2 テクスチャ圧縮の比較

比べてみました。

↓元 (4倍に拡大したものです)
orig_enc0z.png orig_enc1z.png

↓DXT1 (S3TC)
dxt1b_enc0z.png dxt1b_enc1z.png

↓ETC1 (RGB8)
etc1_enc0z.png etc1_enc1z.png

↓ETC2 (RGB8)
etc2_enc0z.png etc2_enc1z.png

結果はエンコーダーの能力にも依存します。
おそらくもっと良い圧縮ツールもあると思います。
特に DXT (S3TC) はツールが豊富なので、上の例よりも良い結果に
なるかもしれません。

ETC1 しか使えない Mali-400 等の GPU では、今までテクスチャの
圧縮方法が限られていました。

・RGB8 のみで Alpha がない
・4×2 単位で 1色しか選択できない

ひとつは Alpha が使えないなど機能的な問題ですが、もうひとつは
画質の問題です。上の例のように 4×2 の大きなブロックが生じ、
DXT1 よりも著しく劣化するケースがありました。

結果を見ても、ETC2 ではこの問題が解消されていることがわかります。

・Alpha や 1-2 component などバリエーションが豊富
・DXT のように 4×4 単位で 2色使える mode が追加された
・GPU 間で共通のフォーマットとして使える (ようになるはず、将来は)

(注意: 手元に手頃なサンプル画像がなかっただけで、決して法線圧縮に
利用しているわけではありません。)

関連エントリ
OpenGL 4.3/ES 3.0 ETC2 Texture 圧縮の仕組み (PVRTC2,ASTC)

OpenGL 4.3 / OpenGL ES 3.0 ETC2 のエンコード

ARM Mali Developer Center で ETC2 に対応した Texture Compression Tool
が公開されています。

Mali GPU Texture Compression Tool v4.0

ところが自分の環境 (Windows 7 x64) では画像変換時にエラーとなり
今まで正しく動いていませんでした。

GUI を使わずにコマンドラインで変換すれば動作することがわかりました。
Program Files の install フォルダ↓にパスを通しておきます。

「 ARM\Mali Developer Tools\Mali Texture Compression Tool v4.0.0\bin 」

etcpack.exe を直接実行します。

etcpack  INPUTFILE.tga  outputdir  -ktx -c etc2 -s slow

これで outputdir に ktx 形式でファイルが作られます。
ktx から ppm への逆変換もできます。

ktx 形式は OpenGL 版の dds のようなものです。
OpenGL の GLenum をそのまま用いるため、どんなフォーマットも格納できます。
詳しくは下記エントリ参照。

Android OpenGL ES 2.0 の圧縮テクスチャ

環境を整えたら実際の変換結果なども比べてみたいと思います。

関連エントリ
OpenGL 4.3/ES 3.0 ETC2 Texture 圧縮の仕組み (PVRTC2,ASTC)
Android OpenGL ES 2.0 の圧縮テクスチャ

OpenGL ES 3.0 と Shader Model の関係、まとめ wiki の更新

OpenGL ES 3.0 の API はおよそ 100 個増えています。
OpenGL ES 2.0 で 150 弱だった命令数が 250 個になりました。
シェーダーと世代の対応は下記の通り。

OpenGL         OpenGL ES        DirectX         ShaderModel
---------------------------------------------------------------
OpenGL 1.x     OpenGL ES 1.x    Direct3D 7      Fixed Pileline
OpenGL 2.x     OpenGL ES 2.0    Direct3D 9      Shader Model 3
OpenGL 3.x     OpenGL ES 3.0    Direct3D 10     Shader Model 4
OpenGL 4.x     --               Direct3D 11     Shader Model 5

OpenGL ES 3.0 は OpenGL 3.x 同様に DirectX10 世代、ShaderModel 4.0 に
相当します。

ハードウエアも API も順当に進化しています。
GPU 毎に機能差は生じますが、下記はそれぞれ最小値の比較です。

                            GLES 2.0   GLES 3.0  (DirectX)
-----------------------------------------------------------------
Vertex Uniform Vectors        128        256     (VSH Constant)
Fragment Uniform Vectors       16        224     (PSH Constant)
Vertex Attribs                  8         16     (VSH Input)
Vertex Output Vectors           8         16     (VSH Output)
Fragment Input Vectors          8         15     (PSH Input)
Draw Buffers                    1          4     (PSH Output,MRT)
Vertex Texture Image Units      0         16     (Vertex Texture)
Texture Image Units             8         16     (Pixel Texture)
Combined Texture Image Units    8         32

Uniform Block (D3D の ConstantBuffer) があるためこのあたりの制限は
さらにゆるくなるはずです。

このあたりを踏まえて wiki もいろいろ更新しました。

Mobile GPU 毎の機能比較表
OpenGL のバージョン表など
テクスチャフォーマットまとめ
Desktop 向け OpenGL ES 2.0 / OpenGL ES 3.0 実行環境

OpenGL ES 3.0 には GeometryShader がありませんが、これは OpenGL 3.0 も
同様でした。
GeometryShader が追加されたのは OpenGL 3.2 からなので、
同じように OpenGL ES にも今後 GeometryShader が追加拡張される
可能性が高いといえます。

関連ページ
OpenGL まとめトップ

OpenGL ES 3.0 と OpenGL ES 2.0 の互換性

OpenGL ES 3.0 は OpenGL ES 2.0 との上位互換性が保たれています。
まだ GL 4.3 の GL_ARB_ES3_compatibility と Mali/Adreno Emulator で
試しているだけですが、OpenGL ES 3.0 上で今までのソースコードも
シェーダーも 2.0 のまま変更なしに動いています。
OpenGL ES 3.0 は OpenGL ES 2.0 の実行環境の一つとして利用できそうです。

OpenGL ES 3.0 対応のため EGL の初期化は若干変更しています。
EGL_CONTEXT_CLIENT_VERSION に 3 を渡しています。
Mali のドキュメントでは EGL_OPENGL_ES3_BIT を使っていますが、
定義が見つからなかったため EGL_OPENGL_ES2_BIT のまま使用しました。

GLSL のシェーダーバージョン対応は下記のとおりです。

                 GLSL     shader 内の指定
-----------------------------------------------------------
OpenGL ES 2.0    1.0      #version 100
OpenGL 2.0       1.1      #version 110
OpenGL 2.1       1.2      #version 120

OpenGL 3.0       1.3      #version 130
OpenGL 3.1       1.4      #version 140
OpenGL 3.2       1.5      #version 150 [core/compatibility]
OpenGL ES 3.0    3.0      #version 300 es
OpenGL 3.3       3.3      #version 330 [core/compatibility]
OpenGL 4.0       4.0      #version 400 [core/compatibility]
OpenGL 4.1       4.1      #version 410 [core/compatibility]
OpenGL 4.2       4.2      #version 420 [core/compatibility]
OpenGL 4.3       4.3      #version 430 [core/compatibility/es]

番号が重なっていないためバージョンの数値だけでもすべて区別可能です。
shader の 1行目に #version が存在しない場合、OpenGL では 1.1 とみなします。
OpenGL ES では 1.0 とみなすことになっています。

バージョン番号の後に profile を指定できるようになったのは 1.5 からです。
OpenGL 4.3 では core, compatibility の他に es も加えられています。
実際に OpenGL 4.3 の context のまま “#version 300 es” を指定しても
コンパイルは通りました。

OpenGL 3.0 以後と以前でシェーダーの書き方が変わります。
OpenGL ES 3.0 も OpenGL 3.x 以降と同じ記述方法になりました。
共存させるために下記のようなヘッダを用いています。

// Vertex Shader
#ifdef GL_ES
# define LOWP       lowp
# define MEDIUMP    mediump
# define HIGHP      highp
precision HIGHP float;
#else
# define LOWP       
# define MEDIUMP    
# define HIGHP      
#endif

#if __VERSION__ < 130
# define IN         attribute
# define OUT        varying
#else
# define IN         in
# define OUT        out
#endif
// Vertex Shader
#ifdef GL_ES
# define LOWP       lowp
# define MEDIUMP    mediump
# define HIGHP      highp	
precision MEDIUMP float;
#else
# define LOWP
# define MEDIUMP
# define HIGHP
#endif

#if __VERSION__ < 130
# define IN     varying
# define        out_FragColor  gl_FragColor
#else
# define IN     in
out vec4        out_FragColor;
#endif

上記以外に texture のサンプリング命令も変わります。