DirectX一覧

VisualStudio 2012とDirectX SDK

どうやらVisualStudio2012を使う状況においては、DirectXSDKにも注意が必要のようです。
VisualStudio2010を使う際にもDirectXSDKの諸注意がありましたが、2012においても同様に注意が必要のようです。

まず結論からいうと、うまく動作するDirectX SDK にはある範囲があるようです。
手元にインストールしてあったSDKを調べてみるとこんな感じです。

  • DirectX SDK 2008 Nov NG
  • DirectX SDK 2009 Aug OK
  • DirectX SDK 2010 June OK

以下、失敗したときの参考事例と言うことでメモっておきます。

よく言われているのがDXSDK_DIRのインクルードを設定する部分です。
プロジェクトのプロパティで”C/C++” / “追加のインクルードディレクトリ” に $(DXSDK_DIR)Include を追加すると下記のようにエラーが出ます(一部抜粋)。

これについては、プロジェクトのプロパティから、
“VC++ディレクトリ”/”インクルードディレクトリ”の末尾に、$(DXSDK_DIR)include を追加してあげることでエラーが消えます。

しかし、先ほど言ったようにこれだけでは不完全でした。
XAudio2.hをインクルードするソースコードだとこの対策をしても下記のようなエラーが環境によっては出てしまうことがあります。

これは、_WIN32_WINNT がどこかで定義されていることが原因です。
それがVisualStudio2012が標準で参照するWindowsSDKDirの中にあるXaudio2.hでエラーとなっています。このヘッダでは_WIN32_WINNTはWindows8の値がくることを想定しているようです。

よって、このままではWindows8以外を想定したビルドは通りません。
WindowsXP~7等で動作するアプリケーションのためにはDirectX SDKに含まれているXAudio2のヘッダを使う必要がありそうです。

このためには、DirectXのヘッダを読み込む優先順をあげる必要があります。
それは先ほどの$(DXSDK_DIR)Includeを設定した部分にあります。
優先順をあげて、VisualStudio2012の標準ヘッダ群より先にするために、”C/C++”/”追加のインクルードディレクトリ”のほうに設定します。ただし、2008Novのバージョンではエラーとなったことを上記の方で既に体験しています・・・・。

そこで、DirectX SDKのバージョンを上げてみます。2009Augではどうだろうか、と。
試してみたところ、うまくビルドが通りました。
インクルードの順序を確認してみましたが、DirectXSDKのほうのヘッダを参照していることも確認できました。

同様に2010Juneでも確認してみましたが、同様に成功しました。

まとめると、DirectXSDKを正しく使用するためには以下の手順となります。

  1. DirectX SDKは2009Aug以降を使用すること。できれば公式にVisualStudio2010対応してるとされていた2010Juneがよいと思います。
  2. DirectXSDKのインクルードパスの設定は、プロジェクトのプロパティのVC++ディレクトリに対して行わず、”C/C++”の”追加のインクルードディレクトリ”にて行うこと。

この2点が大切です。
これを守らないと変なインクルードの順序となり、予期せぬ不都合が起こるかもしれません。

チェック環境

  • Windows7 Pro SP1 (x64)
  • VisualStudio 2012 RTM
  • DirectX SDK  2008Nov, 2009Aug, 2010Jun

現在はもっと新しい記事があります。
VisualStudio 2012とDirectX SDK 再び


remoteFX環境下で試してみた

ちょっとだけ調べてみました。
動作環境ではRADEON5450を搭載しています。

Fetch4は使えるのか?

使えないです。

DepthTextureは使える?

使えるようです。

まとめ

やはりGPUを抽象化した別のデバイスとしてみえるため、
ベンダ拡張の機能がまだ強い物は扱えないようです。
Fetch4もダメとなるとNVIDIAのTransparency Antialiasもダメだろうなぁ。

ついでに、デバイスが別物なのでCUDA,(GPU側の)OpenCLもダメかなと思います。


DirectX11とDirectX9比較

DirectX11(D3D11)はDirectX9ハードウェア上でも動きます。
そういう場合に、DirectX11とDirectX9ではどちらを選択すべきだろうか、と思ってちょっと比較をしてみようかと思います。

チェック環境

  • RADEON HD 5450(DX11対応ハード)
  • Geforce9600GT
  • Geforce6800GT

サンプルプログラムとしてBasicHLSL11というSDK付属の物を使います。
これを実行してFPSの計測を行います。

チェックしてみる項目は以下の通り

  • D3D11デバイスでD3D_FEATURE_LEVEL_11_0
  • D3D11デバイスでD3D_FEATURE_LEVEL_10_0
  • D3D11デバイスでD3D_FEATURE_LEVEL_9_3
  • D3D9デバイス

結果

それぞれの場合でFPSを計測すると以下のようになりました。
(解像度は800×600)

条件 FPS値(5450) FPS値(9800GT) FPS値(GF6800)
D3D11+D3D_FEATURE_LEVEL_11_0 1170
D3D11+D3D_FEATURE_LEVEL_10_0 3625
D3D11+D3D_FEATURE_LEVEL_9_3 1220 4183 1604
D3D9 965 1367 1201

D3D9 vs D3D11では、圧倒的にD3D11の方が高速に動作しているようです。
そして貧弱なハードウェアだからか、レベルを落とした方が若干高速でした。
この結果を見ると、DX9とDX11(9_3レベル)を悩むならDX11のほうがよいと言えます。


ハードウェアシャドウマップをやってみる -エラー編-

うまく行きそうで失敗

AMD RADEON 5450の環境でもハードウェアシャドウマップが使える*1というので
ちょっと試してみました。
しかしながら、DirectXのデバッグランタイムを使用すると
エラーメッセージが表示される結果となってしまい現在調査中。

同プログラムはNVIDIA製グラフィックボード使ったときには正常だったのですが。

表示されるエラーメッセージは以下のようなものです。

ちなみに、デプステクスチャは、D24S8で作成していましたが、D24X8でも同様。
D16にすると上記のメッセージは出なくなるのですが、出来ることなら24bit精度使いたいと思いますし、
いったい何が悪いのかをしばらく調査しようかと思います。

デプステクスチャ
512×512 D24S8, D24X8 エラーメッセージが出る
512×512 D16 正常

動作環境としては、Windows7(x64), Catalyst 10.7、DXSDK2009Aug を使用しています。
なお、NVIDIA環境では260.99ドライバで9800GTを用いています。

ちなみにメッセージは表示されますが、画面の描画結果は正常だったりします。エラーのメッセージさえ見られなければ、どうということは無いのかもしれません(笑

*1 : Advanced DX9 Capabilities for ATI Radeon Cards.pdfを参照してサポートの状況を確認しています。

動作チェック予定

現在の症状から、以下の変更を行ってみて症状が改善するかを試みる方針です。

  • DXSDKの更新
    • 2010Juneあたりでやってみるといいのかも
  • ドライバの更新
    • Catalyst 10.11などは安定しているという噂も(ミドルレンジはという制約ありで)
  • 動作OSの変更
    • 32bit版Win7
    • Vista, XP
    • これらの環境ではどうなのだろうか

D3DPOOLについて考える

今回はDirectX9でのD3DPOOLについて考えてみました。
最近はDX10の話だったので、ちょっと流れをぶち切ってしまいました。
以下の話は、すべてWindowsXP DirectX9での話となります。
Vista以降のDirectX9Exの話はまた異なるため、そのうちにでも。

説明

http://msdn.microsoft.com/ja-jp/library/ee418784%28v=VS.85%29.aspx
このページを見てしまってから思い悩むことになってしまいました。
今までは、以下の方針でリソース作成を行っておけばいいと思っていたのですが。

  • 途中で更新するデータである
    • → D3DPOOL_DEFAULT + DYNAMIC付き
  • 上記以外
    • → D3DPOOL_MANAGED

この背景には、D3DPOOL_MANAGEDであればデバイスロスト時の処理が楽になる点と、
実際にはVRAMへ転送済みであるということを想定していたからでした。

しかし、この理解は若干間違っているというのが、図によって分かりました。

  • D3DPOOL_DEFAULT
    • VRAM上かAGPメモリに配置される
    • DYNAMICリソースであればAGPメモリに配置される
  • D3DPOOL_MANAGED
    • VRAM上かAGPメモリ上、それとシステムメモリにバッキングストアとして配置される

このようになっていることが図から読み取れます。

理解が間違っていたのはD3DPOOL_DEFAULTは常にVRAMと思っていた点でした。

まとめ

さて、これらの点からどのようにリソースを配置していくべきかを考えてみました。

PC用と想定すれば、実際に動かされる環境はまちまちなので、ドライバに任せる部分は任せて、
多少の動作速度改善に向けた配置を心がけるのが良さそうです。

  • 途中で更新するデータ
    • 頂点orインデックスバッファなら D3DPOOL_DEFAULT + DYNAMIC付き
    • テクスチャなら D3DPOOL_DEFAULT + D3DPOOL_SYSTEMMEMの2重持ち
      • SYSTEMMEMに更新したいデータを埋めて、あとで転送する方式にします
  • データは最初から終わりまで不変
    • D3DPOOL_MANAGEDで配置。
    • D3DPOOL_MANAGEDはドライバによって実際に配置される場所が決定される。
    • この配置決定には、パフォーマンスや使用状況も考慮されるためお勧めの模様。

注意点としては、上記の動的なデータというのは限りなく少なくしておくべきという点でしょうか。
今回ドキュメントを読んで知ったのですが、MANAGEDとDEFAULTの混在はビデオメモリの断片化を招き、よろしくないとのことです。
DEFAULTを先に作成し終えてから、MANAGEDリソースを作るのが良いとのことです。

もしも対象としている動作環境が VRAM 256MB必須 としてしまい、それ以下の搭載メモリの状況では動作を保証しないというのであれば、
D3DPOOL_MANAGEDを使用する代わりにDEFAULTでもいいのかなと思います。
デバイスロストのときには、データを再度読み込むか、あるいは、SYSTEMMEMで最初から持っておくとかそういうようにして準備する必要はあると思います。
実際にDEFAULT+SYSTEMMEMの両方持っているという状況はOpenGLでは(実装の上では)このようにやっているように見えます。
(メモリの使用状況を見ていると、倍くらい使用メモリが多いので)。


HW ShadowMapのために。

HW ShadowMapのために最近の状況をしらべてみました。

  • NVIDIA
    • Geforce7x00くらいのころから搭載*1
    • テクスチャとしてUSAGE_DEPTHSTENCIL付きでD24S8フォーマットで作成可能
    • これをサンプリングするときに4近傍からの平均がとれてしまう。
  • AMD
    • fetch4
      • X1800以外のX1xxxシリーズで使用可能
      • このとき、DF24というフォーマットでテクスチャを作れる
      • このサンプリング時にfetch4機能で4サンプルとって、シェーダー内で平均算出
    • 通常のD24S8テクスチャ
      • RADEON 2000以上で使用可能になっているよう
      • サンプリング時に4近傍からの平均が求まってしまう。

このような相違があります。

では多くの環境でHWシャドウマップ技術を使うには、という点を考えてみます。

*1 : 6×00系ですでに使えたかも

多くの環境でHWシャドウマップ技術を適用するには

まず、環境がNVIDIAかAMDかで振り分けます。

NVIDIA時

D24S8形式のテクスチャ(USAGE_DEPTHSTENCIL付き)が使えるかを調べます。

もし使えないようならば、完全ソフトウェアのシャドウマップを使うしかありません。

AMD時

  1. D24S8形式のテクスチャが使えるかを調べます。
    1. これが使えるのはRADEON 2000以上です。PCFが有効でデプス値はサンプリングだけから求まります。
    2. 使えるならこれを使用します。使えない場合に以下に続きます。
  2. 続いてfetch4機能が使えるかを調べます。
    1. 使えるのは、RADEON X1x00以降です(1800を除く)。PCFはかからないので、自前で平均を計算します
    2. 使えるならこれを使用します。使えない場合に以下に続きます。
  3. 完全ソフトウェアのシャドウマップを使用します

このような感じで適用すべき機能が振り分けられると思います。
ここでいう完全ソフトウェアのシャドウマップとは、
D3DFMT_R32Fなどの単一要素のカラーとしてレンダーテクスチャを作成し、カラー値としてデプスを書き込む感じになります。

まとめ

これらの方針で一度実装してみようかと思います。
現在の多くの環境では、完全ソフトウェアのシャドウマップをやらなきゃいけないということはないと思われます。
DX10対応しているハードであれば、HWシャドウマップは使えるはずですし。
そうでないにしても、fetch4くらいは使える環境が多いのではないでしょうか。

個人的には、この記事を元に、マルペケつくろ~のIKDさんがサンプルおよび、ここよりわかりやすい解説に発展させてくれないかなと、密かに期待しております。


低レベルなDirectX9

ドライバーの内部エラーについて、ここに記載がちょっとありました。http://msdn.microsoft.com/ja-jp/library/ee417865%28VS.85%29.aspx

こんな仕組みになっているけど、デバイスの破棄および再生成で処理を復帰っていうことが、
果たしてどのくらい可能なんだろうか。ちょっと疑問に思います。

でも、IDirect3DDevice9::ValidateDevice というメソッドを DrawPrimitive系の直前に挿入して、
デバイス状態を確認するという手法はなかなか良さそうに思いました。
デバッグビルドとかフラグでそんなコードになるように、元々のコードに準備をしておくのは役立つかもしれません。

コマンドバッファな話

Direct3D API 呼び出しの正確なプロファイリング (Direct3D 9)と題して、MSDNに記載を発見。
以前はどこかのWeb記事でDirectXのコマンドバッファの話を読んだ気がしていましたが。
このドキュメントの本来の意味は、タイトル通りプロファイリングの話です。
しかし、アプリケーションから実デバイスまでに設定データ類がどのように伝達するか、というのが使用されている図と、プロファイリングの注意点より読み取ることが出来ます。

ドキュメントの後方にある構成の図はなかなかわかりやすいです。
結局デバイスに到達するときには、各設定はコマンドバッファというバッファに単純なコマンドとして記録された状態になっています。
GPUはそのバッファを順番に解釈し、実行しているだけに過ぎません。

もちろん、このやりとりにはデバイス制御があるため、
カーネルモードに遷移したりするのですが、この部分まできちんと説明があるため、
このドキュメントはよく出来ていると思いました。


Collada+DirectX

海外のサイトで、COLLADAとDirectXの話が書いてありました。
さらりと見てみましたが、COLLADA DOMとその中身にどうアクセスするか、
各種メッシュ(静的メッシュ、スキニングのような骨の親子構造を持つもの、モーフィング)の扱い方
これらについて丁寧に書いてありました。
ただし、英語で、ですが。ここに。→ http://thecansin.com/2010/10/collada-loading-for-directx/

ソースコードも同時に公開されているのでかなり参考にできそうです。

書籍を購入しました

ちょうどタイミングを同じくして、「MESH GURU」という書籍を購入しました。
まだざっくりとしか読めてないですが、その内容と今回の海外でのサイト情報とがほぼ一致してるような気がして、
急いで中身を見てみましたが、全く一緒と言うことはありませんでした。
用語が一緒で、ドキッとしたくらいですね。

.xやFBX,COLLADAとフォーマットをまたいでの知識であれば書籍を、
COLLADA特化なら上記の海外サイト情報がお勧めできそうです。

各種モデラーからデータを出す場合には、最近はCOLLADAがいいのですかねぇ・・・?
FBXも捨てがたいとは思うのですが。悩みどころのような気がします。


D3DPOOL_MANAGEDのデータ保存先について

D3DPOOL_MANAGEDについて。
どうやら生成元となったバイナリデータ列はユーザー空間に置かれる模様。そんな挙動のため、結局のところは使用メモリがどんどん増えていくように見える。
仮に256MBほどテクスチャがあったとすると、このフラグ付きで送った場合には結局メインメモリにも同じ容量だけメモリを使われていることになってしまう。

また先日作業用のメモリとって、必要に応じてUpdateTextureで転送すればいいと書いたけど、これも結局のところD3DPOOL_MANAGED相当を自前でやっているだけに過ぎない…。

意外といけてなかった。
もっとよりよい方法を考えてみることにします。


テクスチャとサンプラーステートの関係

テクスチャとひとことで言った場合、この中には2つの要素が含まれていると思います。
1つは、ポリゴン表面に貼りたい画像のデータ。
そしてもう1つは、その画像に適用するフィルタ設定やUV設定といったの各設定情報。このうち後者はテクスチャフィルタやラッピングモード(アドレッシングモード)とも言われるため
テクスチャの情報としてまとめられてしまうことが多いと感じます。
特に昔からのOpenGLではテクスチャオブジェクト内にラップモードとフィルタ設定を行っておき、
テクスチャの使用時にはその設定が有効になるという挙動を示します。

DirectX9においては後者の設定はテクスチャの処理するステージに対して設定するものとなっています。
SetSamplerStateメソッドのヘルプを見てみても、サンプラー番号といわれる部分はサンプラステージインデックスと表記されています。
HLSLシェーダ内にレジスタ指定できますが、そのときの register(s0);という”s”の部分については、おそらくステージの意味合いなのではと思います。

しかし近年、DirectX10(D3D10)以降これらの関係がAPIの上から変わりました。
前述の各設定情報がサンプラーオブジェクトとして分離されました。
ハードウェアの面から考えると、画像が置いてある部分の内容と、そこから読み出すときのフィルタ設定は確かに分離でき
こちらのほうが自然な印象を受けます。
この時代においても、レジスタ指定の部分では従来どおり register(s0); ですが、
このときの”s”の意味合いは、サンプラーの意味を持つ”s”へと変わっていると思います。

また、OpenGLのほうでもテクスチャの設定関連が見直され、
新しいOpenGL*1では、テクスチャとサンプラーとそれぞれ別のオブジェクトとして使うことが可能になってきました。
これらにおいては、glGenSamplers, glBindSamplerといった生成、割り当ての関数が追加されています*2

新しいものだけを見れば、DirectXもOpenGLも同じ流れになっていてすっきりしました。
しかし、気になる点も1点あります。
それはこのサンプラーの設定はサンプラーの番号に対して設定するという方法しかないという点です。
HLSLのエフェクト(.fx)を使う上では、サンプラーステートと参照するテクスチャを結びつけて記述が出来ますが、
それぞれのシェーダーを別々に設定するような機構では、この設定は出来ないようです。
まだ見つけられてないだけかも知れませんが、OpenGL(GLSL)ではそういった機構すらないように思えます。

これらの点から、テクスチャの割り当てとサンプラの割り当ての番号は一致するように実装しておくのがいいのかなと思いました。
テクスチャの割り当ての番号自体は、シェーダーリフレクションを使えば求められます。
DirectX9については、そもそも同一のステージ番号に閉じ込められていますし、
旧OpenGLではテクスチャオブジェクト内にまとまってしまっています。
全てにおいて統一の取れたものにするには、この方法しかないのでは?と考えています。

*1 : OpenGL3.2以降だと思われる

*2 : GL_sampler_objects