月別アーカイブ: 2008年9月

WindowsMobile touchkeysip v1.07

バグ報告をいただいたので修正しました。
定数の値数で、-129 ~ -32768 の範囲の場合のみ符号が失われてしまいます。
値から一目瞭然ですが 1byte、2byte、4byte のそれぞれの範囲で定数の扱いを
区別しており、2byte の場合のみ符号が考慮されていなかったことが原因でした。

touchkeysip v1.07

Direct3D11 シェーダーの動的リンクやテクスチャ

●シェーダーの動的リンク

もともと Shader はマテリアルやライティング、アニメーションなど、組み合わせに
応じてすぐに数が増加する傾向があります。
加えて SM2.0~4.0 と徐々に固定機能が廃止され、有効な RenderState が減ると
さらに必要なシェーダー数が増えています。

シェーダー内の分岐もできますが、やはり大規模な並列実行でクリティカルな部分
なので、速度への影響が大きいマテリアルでは慎重になります。

もう1つ心配なのがコンパイル速度です。
シェーダーのコード量が増えるに従って、急激にコンパイルに時間がかかるように
なってきた印象があります。
シェーダーは CPU のコンパイラよりも比較的大胆な最適化が行われているので、
総当たりで比較しているのではないかとたまに思う時があります。

Direct3D11 ではこのような問題を解決するため、動的にシェーダーの Link が
できるようになるとのことです。
SetShader() 時に参照が解決されますが、HW native に変換されたコードで処理が
行われるため、リンクの操作も軽く、実行時の動作も速いそうです。
詳しい仕組みやパフォーマンスへの影響はまだわかりませんが、
分割コンパイルできるし組み合わせによる数の増加が抑えられるので、
管理はかなり便利になると思われます。

逆に、すでにシェーダー管理の仕組みを構築している場合は、D3D10→D3D11 への
移行時にいろいろと修正が必要になるかもしれません。
またいろいろ考えることが増えそうです。

●圧縮テクスチャ BC6/BC7

新しい圧縮テクスチャ BC6 は、HDR テクスチャの圧縮に使われるようです。
16 bpc RGB、つまり R16G16B16 相当を 1/6 = 1byte に圧縮するものと考えられます。

圧縮率 1/6 と書かれていますが、DXGI のフォーマットには 6byte = 48bit
の形式はないため、R16G16B16A16 との対比では alpha が無くなるものの
実質 1/8 のメモリ効率が得られそうです。

圧縮方法は従来の BC1~BC5 (DXT) によく似ています。
4×4 のブロックを単位にエンコードしますが、その手法はより複雑になっているようです。
格納するベースカラーに Alpha が無い代わりに HDR なこと、
ブロック毎にアルゴリズムを柔軟に変更できること、
エリアを分割して複数のパーティションとし、それぞれが異なるカラー補間テーブルを
参照できること、などなど。
これ以上の詳細はわからないので、DirectX11 SDK のリリースを待つ必要があるでしょう。

同じように BC7 は、HDR ではないカラー値の圧縮をより改良したものです。
BC6 同様にブロック毎にアルゴリズムを変更でき、RGB や RGBA の両方に対応できます。
RGB 比 1/3、RGBA で 1/4 とのことなので、やはり 1byte/texel となるようです。
これは BC2~3 (DXT3/DXT5) 等と同じです。

BC7 で完全に置き換えられるなら、BC2/3 は使われなくなるかもしれません。

テクスチャの最大サイズは 16384×16384 まで拡張されるようです。
16384×16384 32bit RGBA 相当で 1GByte
BC1(DXT1)/BC4 で 128MByte
BC2~3(DXT3/5),BC5~7 で 256MByte

関連エントリ
Direct3D11 マルチスレッドのための機能
Direct3D11 テセレータとシェーダー
Direct3D11 のパイプライン
Direct3D11 Compute Shader など
Gamefest2008 と Direct3D 11

Direct3D11 マルチスレッドのための機能

PC もマルチコア CPU が当たり前となり、マルチスレッド化がパフォーマンス向上の
鍵となっています。
Gamefest2008 の D3D11 関連のスライドによると、Direct3D11 ではようやく
本格的にマルチスレッドへの対応が行われるとのことです。

Gamefest 2008 Presentations

これまでは、原則としてレンダリング用の単一のスレッドがリソースアクセスや
描画を行う必要がありました。

D3D11 では非同期のリソース読み込みや複数スレッドからの描画が行えるようです。
またこれらに対応したため、個別に作成された Display List を使った描画も
実質的にできるようになっています。
ゲーム専用ハードでは当たり前のものですが、PC 側にフィードバックされる形と
なったようです。

概念としては現在の Device Interface (ID3D10Device) が、複数の Interface に
分割されます。

 (1) Device
 (2) Immediate Context
 (3) Deferred Context

リソースの作成は従来通り (1) の Device を通して行います。
Thread 対応となり、複数のスレッドで呼ばれても問題が起こりません。

(2) の Immediate Context は従来の ID3D10Device 等での描画に相当し、
レンダリング用スレッドで命令をすぐに発行できます。

(3) の Deferred Context は他のスレッドで描画命令を使用する場合に用いられます。
描画命令はバッファリングされます。いわば内部的に Display List が作られ、
最終的にレンダリングスレッドで Immediate Context と同じように描画命令を発行
できます。
API によっては DispalyList へ乗らないものもあるので、多少の制限は存在します。

基本的に各種ステートがそれぞれの Context 間で干渉することはないようです。
独立して管理し、Display List の描画を行ったあとにステートをリセットした方が
速いとのこと。
この辺の仕組みが具体的にどのような実装になっているのかまだわかりません。

D3D11 は上位互換性があり、D3D10 用の今の GPU でも動作することになっています。
現在の GPU ドライバはスレッド対応になっていないため、呼ばれた API を
バッファに記録して擬似的に Display List をエミュレートする形になるそうです。

リソースアクセスも、使用できるものの lock の粒度が荒くなるため効率は
それなりに落ちるとのこと。
将来的には Direct3D10 世代の GPU でも、ドライバの更新によってスレッド対応化が
行われてパフォーマンスが改善されるようです。

ちなみに現在の D3D9~10 でも、デバイス作成時のフラグで API 呼び出しを
Multi Thread 対応にすることが出来ました。
これは古いやり方で作られており効率悪いため、指定しない方がよいとのことです。

これまでは、使用する Direct3D SDK を次々と乗り換えてきたのは GPU の新しい
機能を使うためであって、GPU の都合によるものでした。

今回の更新は、今のマルチコア CPU を最大限活用するためにも必要となるかも
しれません。

関連エントリ
Direct3D11 テセレータとシェーダー
Direct3D11 のパイプライン
Direct3D11 Compute Shader など
Gamefest2008 と Direct3D 11

Direct3D11 テセレータとシェーダー

細かい使い方まではわかりませんが、様々な用例から構造が少しずつ見えてきています。
プログラマブルなシェーダー Hull Shader と Domain Shader に挟まれた形で
Tessellator が入ります。

このテセレータというのは、位置的にも機能的にもラスタライザに非常に近いもの
なのかもしれません。
そう思えば固定機能であることも納得できます。

DomainShader はラスタライズ後に走る Pixsel Shader に相当し、規模も走る
スレッド数も動的に変化します。

テクスチャによってエフェクトが入る点も似ています。
DomainShader は Displacement Map を読み込むので、Pixsel Shader に次いで
テクスチャアクセスを多用するシェーダーとなりそうです。

そもそも、動的にサイズが変化するユニットだからこそイメージマップを利用する
意味があるわけで、必然というか当たり前のことなのかもしれません。

単一のパイプライン中に Tessellator と Rasterizer の 2ヶ所でデータの増幅が
行われます。本当は Geometry Shader でも可能なので 3ヶ所です。

逆にポリゴン減らすのは、生成後のプリミティブ単位で実行される Geometry Shader
でしか出来ないと思われます。
もしマップによってメッシュに穴を開けたいなら、GeometryShader でもテクスチャを
サンプリングするか、Domain Shader からパラメータを渡すことになるのでしょう。

ピクセルを減らすこと自体は PiselShader でも clip (discard) で可能です。

Vertex 単位で走る VertexShader や、Pixel 単位で走る PixelShader を考えると、
GeometryShader は PrimitiveShader といった方が理解しやすいかもしれません。
となると HullShader は PatchShader です。

DomainShader は Post Vertex Shader といった位置づけで、Tessellation 後の
VertexShader に相当します。
本来の VertexShader は Pre Vertex Shader。

VS Vertex Shader   →  Pre Vertex Shader
HS Hull Shader     →  Patch Shader (Pre Primitive Shader)
TS [[Tessellator]]
DS Domain Shader   →  Post Vertex Shader
GS Geometry Shader →  Primitive Shader
RS [[Rasterizer]]
PS Pixel Shader

だいぶすっきりしました。
でも全部略称が PS になって区別できないからやっぱりだめです。

Tessellator や Displacement Map によって 3D データの作り方は今後変わっていく
と思われます。
3D だけでなく、ベクタフォントを GPU で直接描画するなど 2D 面でも応用できる
かもしれません。

関連エントリ
Direct3D11 のパイプライン
Direct3D11 Compute Shader など
Gamefest2008 と Direct3D 11

Direct3D11 のパイプライン

今日も Gamefest2008 の資料を参考に、D3D11 関連をいろいろ見てみます。
Gamefest 2008 Presentations

D3D11 ではテセレータと共に新しくシェーダーステージが追加されています。
Direct3D 11 の目玉機能の一つです。

新しく Patch プリミティブが導入されるようです。
Quad で指定可能で、かつ隣接する頂点情報を入力できます。

D3D10 GeometryShader の Triangle Adjacency に少々似てますが、
Triangle Adj は最大6頂点まででした。

Patch は最大 32 頂点まで入力できるようです。
たとえば単純で均等な Quad mesh なら、それぞれの隣接 Quad を1つ受け取ると
12頂点です。
これをコントロールポイントとして使います。

GeometryShader ではプリミティブ毎に 1つのシェーダーが走る形式でした。
HullShader は周囲の頂点情報を受け取りつつも、各入力頂点 (ControlPoint)
毎にシェーダー (Thread) を走らせることが可能となるようです。

頂点シェーダーと違うのは、それぞれのシェーダーが同じパッチ内のすべての
コントロールポイントにアクセス出来るということ。

また HullShader は、GS のようにパッチ毎に 1つだけ走らせることもできそうです。
おそらく、パッチ単位で走る HullShader 関数と、コントロールポイント毎に
走る HullShader 関数の両方を指定出来るのではないかと思われます。

HullShader はテセレータの前段階です。
テセレータの後に位置するのが DomainShader と呼ばれます。

DomainShader はテセレータで生成された頂点毎にシェーダーが走るようです。
この場合もパッチ単位で、入力されたコントロールポイントすべての情報を
受け取ることができます。

このように細切れで ShaderStage が増えているのは、入出力情報のグループ化に
よるものでしょうか。

とりあえずまとめてみました

VertexShader   頂点毎に走る。  入力情報はその1頂点のみ。
HullShader     パッチ毎。      パッチのコントロールポイントを全部参照できる。
HullShader     コントロールポイント毎。パッチのコントロールポイントを全部参照できる。
DomainShader   生成された頂点毎。 パッチの入力コントロールポイントを全部参照できる。
GeometryShader 生成されたプリミティブ毎 。プリミティブを構成する頂点を全部参照できる。
  テセレータがプリミティブとして Adjacency を生成できるかどうかは不明。
PixelShader    ラスタライズされたピクセル毎。GS or VS 出力から補間された値が入力となる。

関連エントリ
Direct3D11 Compute Shader など
Gamefest2008 と Direct3D 11