読者です 読者をやめる 読者になる 読者になる

syghの新フラグメント置き場

プログラミングTipsやコード断片の保管場所です。お絵描きもときどき載せます。

Windows SDKと旧DirectX SDK

DirectX SDKはJune 2010がリリースされた後、まったく新しいバージョンが出ない時期が続いたんですが、Visual Studio 2012にバンドルされているWindows SDK 8.0において、DirectX SDKWindows SDKと統合されました。

昔(DirectX 9や10.xの時代)はかなり頻繁に、それこそ2、3ヶ月おきぐらいにDirectX SDKが更新されていたんですが、今後はDirectX APIの更新はWindows SDKの更新と同程度の頻度になるようです(つまりWindowsのバージョンアップと同時期にDirectXもアップデートされる)。また、旧DirectX SDKにはDXUTフレームワークとともに大量のハイレベルかつ有用なサンプルコードが付属していたんですが、DXUTやD3DXの一部はCodePlexに移管され、またサンプルコードはVisual Studio 2012向けに移植された一部のサンプルがDeveloper Center (Developer Network) で個別に公開されています。

ちなみに旧サンプルのうち、AMDの開発者が実装に関わったと思われるものに関しては、AMD Radeon SDK (ATI Radeon SDK) に移管されているそうです*1

Visual Studio 2012付属のWindows SDK 8.0で使用可能なDirectXコンポーネントは下記です(太字は新規)。

  • Direct3D 9, 9Ex
  • DXGI 1.0, 1.1, 1.2
  • Direct3D 10.0, 10.1
  • Direct3D 11.0, 11.1
  • Direct2D 1.0, 1.1
  • DirectWrite 1.0, 1.1
  • DirectSound
  • XAudio2 (v2.8)
  • X3DAudio
  • DirectInput
  • XInput (v9.1.0, v1.4) *2
  • DirectShow
  • DirectDraw

Windows 8標準搭載のDirect2D 1.1では、シェーダーで実装された定義済みエフェクトを使用できるほか、プログラマーが頂点シェーダー、ピクセル シェーダー、コンピュート シェーダーにアクセスできるようになっています。
また、ブレンドモード(Composite Mode)を制御することで、加算合成などを容易に実現できるようになっています。
APIDirect3D 11.1上に再構築され、Windows Vista/7向けのDirect2D 1.0(Direct3D 10.1ベース)と比べてDirect3D APIへのアクセスや連携が簡単になっています。

Visual Studio 2013付属のWindows SDK 8.1で使用可能なDirectXコンポーネントは下記です(太字は新規)。

  • Direct3D 9, 9Ex
  • DXGI 1.0, 1.1, 1.2, 1.3
  • Direct3D 10.0, 10.1
  • Direct3D 11.0, 11.1, 11.2
  • Direct2D 1.0, 1.1, 1.2
  • DirectWrite 1.0, 1.1, 1.2
  • DirectSound
  • XAudio2 (v2.8)
  • X3DAudio
  • DirectInput
  • XInput (v9.1.0, v1.4)
  • DirectShow
  • DirectDraw

デスクトップ アプリでは当然すべてのDirectXコンポーネントを使用できますが、Windowsストア アプリ開発に使用できるDirectXコンポーネントは、Direct3D 11/Direct2D/DirectWrite、XAudio2/X3DAudio、XInputなど、列挙した中の一部のみとなります。

なお、これは予想ですが、2015年にリリースされる予定のVisual Studio 14正式版では、3月のGDC 2014にて発表されたDirectX 12 (Direct3D 12) と、9月のNVIDIA Editor's Dayにて先日発表されたDirectX 11.3 (Direct3D 11.3) が使えるようになるものと思われます。デスクトップアプリではもちろん11.3も12も両方使えるはずですが、ストアアプリではどうなるんでしょうか……
本記事の執筆時点ではDirectX Early Access Programに参加しているユーザーのみが、DirectX 12ベータをテストすることができます。

D3DX/DXUTの廃止

Windows SDK 8.0に統合された新しいDirectX SDKでは、D3DXやDXUTが廃止されています。D3DXは非常に便利な公式ライブラリで、DirectX 9全盛期にD3DXを使ったことがないという個人開発者はおそらくいないのではないでしょうか。Crysisのように有名なAAAタイトルのPCゲームでもD3DXが使われていました。

下記にD3DXからのポーティングに関して比較一覧があるようです。

DirectXMath

D3DXのうち、算術ライブラリに関しては代替として、Windows SDKにDirectXMathという算術ライブラリが標準で用意されるようになります。

DirectXMathは、もともとWindows/Xbox両対応のクロスプラットフォームな算術ライブラリとして開発されていたXNA Mathの後継ライブラリです*3。内部的にはXNA Math 3.xの扱いになっています。ただし完全なスーパーセットというわけではなく、ARM対応などもあって一部互換性がないのですが、ほとんど同じ要領で使えます。

とりあえず、今D3DX Mathを使っているけどDirectXMathが使える環境ではないという人は、早めに単独の最終バージョンであるXNA Math 2.05を試すなりして慣れておいたほうが良いでしょう。

DirectXTK, DirectXTex, DirectXMesh

D3DXのうち、スプライト、フォント、メッシュ、エフェクト、テクスチャなどのユーティリティ系は、DirectX Tool Kit (DirectXTK, DXTK), DirectX Texture Processing Library (DirectXTex), DirectXMesh geometry processing library (DirectXMesh) というオープンソースのライブラリにそれぞれ分割・移行されました。

CodePlex:

Direct3D 11で手軽に使えるスプライトやフォントのライブラリができるのはいいことだと思うんですが、DXTKのフォントライブラリはデフォルトで日本語などの非ASCII文字には対応していません。また、フォントテクスチャ画像はGDI+.NETを利用して事前作成する仕組みなので、DirectWriteを使う場合と比べて描画品質が劣ります。もし単にDirect3D 11.1以降の環境で文字列描画を行ないたいだけであり、また限界性能を追及しないのであれば、Direct2D/DirectWriteを使うのが無難です。
なお、DXTKのエフェクトは、フレームワークとしては非常に貧弱です。.fxファイルを扱うこともできません。
メッシュは3Dプログラミングに慣れている人であればすでにDirect3D 9/10/11およびOpenGL両対応のライブラリなりを自作していると思いますが、DirectXTK, DirectXTex, DirectXMeshはいずれもオープンソースなので、パワーユーザーであっても参考になるコードがあるかもしれません。ちなみにDirectXMeshはかつてD3DXに実装されていたようなメッシュ最適化機能を備えているようです。

DXUT, Effects

DXUTフレームワーク、およびEffects 11フレームワークは、前述のようにCodePlexに移管されていますが、互換性のために一応残っているというレベルなので、特にEffects 11に関しては今後積極的に使うべきではないと思います。
Visual Studio 2012/2013には、WindowsストアアプリのDirect3D/Direct2Dプロジェクト テンプレートは存在するんですが、Desktopアプリ用のDirect3D/Direct2Dプロジェクト テンプレートはありません。技術論文の検証プログラムや、NVIDIAIntelAMDが公開してるサンプルは結構DXUTを使っているものが多いのですが、今後(特にDirectX 12以後)はどうなるんでしょうか。DXUTはWin32/MFC/WinForms/WPFと違ってフルスクリーンモードでもUI部品が使える(部品は単なるテクスチャなので、Direct3Dレンダリングバッファにそのまま合成できるし、IMEにも対応している)のが強みで、Windowsおよびコンソールにおけるクロスプラットフォームなゲーム用ユーザーインターフェイス実装の良いサンプルという役目も果たしていました。Windows 8.x以降やXbox One限定であればWindowsストアアプリというサンドボックスが代わりになる……かもしれません。

D3DCSX

D3DXのうち、DirectCompute(Compute Shader)のユーティリティであるD3DCSXだけはWindows SDK 8.0以降にも残っています。ですがD3DCSXライブラリはWindowsストアアプリでは使えないので注意しましょう。
もしWindowsストアアプリでGPGPUをやりたいだけであれば、C++ AMPを利用するという手もあります。

D3DX MathからXNA Math(DirectX Math)への移行

今後はD3DXが廃止されてDirectXMath, DirectXTK, DirectXTex, DirectXMeshなどに移管されますが、XNA Math/DirectXMathはかなりローレベルのAPIです。雰囲気的にはSSEのintrinsicと大差ありません。
D3DXの便利な機能(特にD3DXVECTOR2/D3DXVECTOR3/D3DXVECTOR4/D3DXMATRIXの演算子オーバーロード)がXNA Math/DirectXMathには存在しないどころか、多くの算術演算関数はXMVECTOR型(メンバーにアクセスすることは許されない、不透明な構造体。SSEを有効にすると、_m128型になる。主に中間計算の一時変数用途)やXMMATRIX型を引数にとるようになっているので、簡単にD3DX型とD3DX関数だけを置き換えるというわけにはいきません。XMFLOAT2/XMFLOA3/XMFLOAT4/XMFLOAT4X4をストレージ(クラスのメンバー変数など)に使う場合、

XMVectorGet~()
XMVectorSet~()
XMLoad~()
XMStore~()

を使ってXMVECTORから成分取得、あるいはXMVECTORへ成分設定してやる(相互変換してやる)必要があります。つまりSSEの知識(アライメントされたデータを専用レジスターへロード/ストアーする処理)がある程度必要になります。
こりゃD3DXのほうが圧倒的に楽だな……と思うかもしれませんが、XMLoad~(), XMStore~()を内部で使って、D3DXとほぼ同じ仕様のI/Fを持つラッパー関数を書けばいいだけなので、移行自体はそんなに大変ではないと思います。

例えばD3DXの、

D3DXMatrixTranspose(&outMatrix, D3DXMatrixLookAtRH(&outMatrix, &vEye, &vAt, &vUp));

に相当するXNA Math/DirectXMath実装は以下のような感じ。

inline void CreateTrMatrixLookAtRH(XMFLOAT4X4* pOut, const XMFLOAT3* pCameraEye, const XMFLOAT3* pCameraAt, const XMFLOAT3* pCameraUp)
{
    const XMVECTOR vCameraEye = XMLoadFloat3(pCameraEye);
    const XMVECTOR vCameraAt = XMLoadFloat3(pCameraAt);
    const XMVECTOR vCameraUp = XMLoadFloat3(pCameraUp);
    const XMMATRIX mView = XMMatrixLookAtRH(vCameraEye, vCameraAt, vCameraUp);
    XMStoreFloat4x4(pOut, XMMatrixTranspose(mView));
}

ぱっと見D3DXバージョンよりも呼び出す関数の数が増えて遅くなるんじゃないかと思えますが、XNA Mathの関数はいずれもインライン実装されてるし、Load/Store系は_m128型変数への転送を行なっているだけなので、リリースビルドでは多分ほとんど変わらないかXNA Mathのほうが高速になる可能性もあります。ベンチマークは取ってませんが。

なお、上記サンプルコードではconst XMVECTORとかconst XMMATRIXとかいう風に、XNA Math関数の戻り値をローカル変数に一時的に格納する際に型を明示してますが、ここでC++11の型推論(auto)を使ってしまうと、リリースビルドではVisual C++コンパイラーが不正な最適化を行なってランタイムエラーになることがあるみたいなので注意。また、XMVECTORやXMMATRIXは16バイト境界でアライメントされたメモリーブロックを必要とするため、基本的にヒープ上に作成してはダメで、通常はスタック変数として確保する必要があります(つまり基本的にはローカル変数や関数パラメータとしてのみ確保する)。newなどでヒープされる可能性がある構造体・クラスのメンバーにこれらの型は使わないほうがよいです。どうしてもヒープする必要がある場合はアライメント対応の専用ヒープ関数を使う必要がありますが、面倒なのでまずやらないほうがいいでしょう。普段のデータ保持目的や、定数バッファ経由でGPUに渡す際に使うのは、扱いやすいXMFLOAT2/XMFLOAT3/XMFLOAT4/XMFLOAT4X4にしておきましょう。

また、DirectXTKには、D3DXのD3DXVECTOR2/D3DXVECTOR3/D3DXVECTOR4/D3DXMATRIXのように演算子オーバーロードが定義されたC++向けのユーティリティクラス群を含むSimpleMathが用意されています。こちらを利用するとD3DX Mathから移行しやすいでしょう。

ちなみにXNA Math/DirectXMathでも相変わらず倍精度浮動小数(double)のサポートはないです。仕事で倍精度対応のD3DXライク算術ライブラリを書いたことがありますが、結構面倒です。GPGPUで倍精度演算を今後使うことがある人は、GLM (OpenGL Mathematics) のdvecを使うといいかもしれません。Intel AVX命令が使える場合はdvec4もdvec2並に高速化されると思います。

なお、DirectXTKやDirectXTexは既定でDirectXMathを要求するのですが、DirectXTexに限っては USE_XNAMATH というシンボルを定義することで、DirectXMathの代わりにXNA Math 2.05を使うことができるようになるらしいです。ただ、DirectXTKもDirectXTexも(一部を除いて)Direct3D 11.xにしか対応していないので、Direct2DやDirectWriteと組み合わせるならばVisual Studio 2012+Windows 8あるいはVisual Studio 2013+Windows 8.1の環境がベストかと。

その他の非推奨コンポーネント

DirectMusicやXACT (XACT3) などは、旧DirectX SDKの特定バージョンを最後に、ヘッダーやライブラリが収録されなくなっています。Windows OS自体は、互換性維持のためにまだこれらの機能(コンポーネント)を搭載しており、例えばWindows 8.1でも一応使うことはできますが、新しいSDKでは開発がサポートされていない非推奨のAPIになっています。中には64bitネイティブコンポーネントすら用意されていないものもあります*4Windows SDK 8.xに収録されていないということは、当然Windowsストアアプリ開発には使えません。このあたりの経緯や詳細に関しては下記のMSDN公式ブログが詳しいです。

ちなみに過去の頻繁なSDKアップデートでどういった機能が追加されていたのか、詳細を知りたい場合は下記が参考になります。

*1:なぜかAMD Radeon SDKのほうはリンク切れになっていて、旧ATI Radeon SDKのほうがアーカイブされています。

*2:XInput Versions (Windows)

*3:XNA Math自体は、XNA Game Studio/XNA Frameworkとは直接の関係はありません。

*4:ゲーム開発者のための 64 ビット プログラミング