2009/05/11
Direct3D DXGI とマルチ GPU (アダプタ)
PC を入れ替えて複数のビデオカードを同時に使えるようになりました。
対応マザーとそれなりの電源が必要です。
いろいろ試しています。
マルチ GPU といっても SLI や CrossFire のことではなく、
それぞれ独立した GPU として使います。
例えば GeForce と RADEON の 2枚差しで、それぞれにモニタをつないで
マルチモニタのように使用することができます。
・GeForce GTX260 → モニタ1
・RADEON HD4670 → モニタ2
GeForce は モニタ1 の描画を行い、RADEON は モニタ2 へ出力を行っています。
Windows から使っている分には 1枚のビデオカードに複数モニタをつないだ状態と
何も変わりません。
広いデスクトップとして使用可能で双方にまたがったウィンドウも配置できます。
ここまでは理解できますが Direct3D を使った場合はどうなるでしょうか。
D3D10CreateDevice / D3D11CreateDevice 時に PC につながっている任意のアダプタ
(GPU)を与えることが可能です。
どちらの GPU でも同じように使えるし、どちらのモニタにも描画することができました。
行き来もできるし中間に配置しても動いています。
このあたりをコントロールするのが DXGI で、非常に柔軟な使い方が可能となっています。
・IDXGIAdapter = GPU
・IDXGIOutput = モニタ
現在利用可能なアダプタとモニタは
IDXGIFactory::EnumAdapters()
IDXGIAdapter::EnumOutputs()
で列挙可能です。モニタに接続されていないアダプタも描画に使うことができます。
DXGI1.1 ではこれにさらに Command Remoting が加わります。
リモートデスクトップでアクセスしている場合に、ホストとクライアントどちらの
アダプタでレンダリングするか選択できるわけです。
●サンプルで確認
DirectX SDK 付属の Direct3D 11 のサンプルプログラムを起動するとウィンドウに
アダプタ名 (GPU名) が表示されています。
モニタ間 (アダプタ間) を行き来するとアダプタ名が切り替わるので違いがよくわかります。
プログラム的にはわざわざアダプタを切り替える必要は無いのですが、
DXUT では敢えてこのような仕様になっているようです。(理由は後述)
●プログラムで確認
実際にプログラムを書いて任意のアダプタで動かしてみました。
・RADEON HD4850 → モニタ1
・RADEON HD4670 → モニタ2
IDXGIFactory::EnumAdapters() でアダプタを列挙して、任意のアダプタを使って
デバイスを作成します。
アダプタは IDXGIFactory::EnumAdapters() で列挙したハードウエアアダプタ、
もしくは IDXGIFactory::CreateSoftwareAdapter() で作成したソフトウエアアダプタです。
すでに TYPE を特定できるので、DriverType には D3D_DRIVER_TYPE_UNKNOWN を
与えなければなりません。(最初ここではまりました)
結果
HD4850 ではモニタ1 の方が高速、HD4670 ではモニタ2 の方が高速です。
アダプタから直接出力した方が速く、予想通りの結果といえます。
同時にたとえ直結されていなくても、モニタ2 の描画も HD4850 が行った方が速いこともわかります。
DirectX SDK 付属サンプルの DXUT がウィンドウの位置を監視して、モニタに応じて
デバイスを作り直しているのは少しでも高速に動作するためだと考えられます。
昔はビデオカードを何度も何度も差し直して開発していました。
GeForce と RADEON の挙動を同時に確認できるなんて、大変便利になったものです。
上のテストの最中、途中で GeForce GTX260(192sp) から HD4850 に差し直したのは
本日非常に暑かったからです。
関連エントリ
・Windows7 リモートデスクトップと Direct3D
対応マザーとそれなりの電源が必要です。
いろいろ試しています。
マルチ GPU といっても SLI や CrossFire のことではなく、
それぞれ独立した GPU として使います。
例えば GeForce と RADEON の 2枚差しで、それぞれにモニタをつないで
マルチモニタのように使用することができます。
・GeForce GTX260 → モニタ1
・RADEON HD4670 → モニタ2
GeForce は モニタ1 の描画を行い、RADEON は モニタ2 へ出力を行っています。
Windows から使っている分には 1枚のビデオカードに複数モニタをつないだ状態と
何も変わりません。
広いデスクトップとして使用可能で双方にまたがったウィンドウも配置できます。
ここまでは理解できますが Direct3D を使った場合はどうなるでしょうか。
D3D10CreateDevice / D3D11CreateDevice 時に PC につながっている任意のアダプタ
(GPU)を与えることが可能です。
どちらの GPU でも同じように使えるし、どちらのモニタにも描画することができました。
行き来もできるし中間に配置しても動いています。
このあたりをコントロールするのが DXGI で、非常に柔軟な使い方が可能となっています。
・IDXGIAdapter = GPU
・IDXGIOutput = モニタ
現在利用可能なアダプタとモニタは
IDXGIFactory::EnumAdapters()
IDXGIAdapter::EnumOutputs()
で列挙可能です。モニタに接続されていないアダプタも描画に使うことができます。
DXGI1.1 ではこれにさらに Command Remoting が加わります。
リモートデスクトップでアクセスしている場合に、ホストとクライアントどちらの
アダプタでレンダリングするか選択できるわけです。
●サンプルで確認
DirectX SDK 付属の Direct3D 11 のサンプルプログラムを起動するとウィンドウに
アダプタ名 (GPU名) が表示されています。
モニタ間 (アダプタ間) を行き来するとアダプタ名が切り替わるので違いがよくわかります。
プログラム的にはわざわざアダプタを切り替える必要は無いのですが、
DXUT では敢えてこのような仕様になっているようです。(理由は後述)
●プログラムで確認
実際にプログラムを書いて任意のアダプタで動かしてみました。
・RADEON HD4850 → モニタ1
・RADEON HD4670 → モニタ2
IDXGIFactory::EnumAdapters() でアダプタを列挙して、任意のアダプタを使って
デバイスを作成します。
// 列挙 IDXGIAdapter1* iAdapter= NULL; IDXGIFactory1* iFactory= NULL; CreateDXGIFactory1( __uuidof(IDXGIFactory1), reinterpret_cast( &iFactory ) ); for( unsigned int index= 0 ;; index++ ){ HRESULT ret= iFactory->EnumAdapters1( index, &iAdapter ); if( ret == DXGI_ERROR_NOT_FOUND ){ break; } // ~ アダプタの選択 // iAdapter->Release(); } iFactory->Release(); // 作成 HRESULT hr= D3D11CreateDeviceAndSwapChain( iAdapter, iAdapter ? D3D_DRIVER_TYPE_UNKNOWN : DriverType, NULL, // software D3D11_CREATE_DEVICE_DEBUG,// flags NULL, // featurelevels 0, // featurelevels D3D11_SDK_VERSION, &SwapChainDesc, &iSwapChain, &iDevice, &FeatureLevel, &iContext );
アダプタは IDXGIFactory::EnumAdapters() で列挙したハードウエアアダプタ、
もしくは IDXGIFactory::CreateSoftwareAdapter() で作成したソフトウエアアダプタです。
すでに TYPE を特定できるので、DriverType には D3D_DRIVER_TYPE_UNKNOWN を
与えなければなりません。(最初ここではまりました)
結果
RADEON HD4850 → モニタ1 : 257fps RADEON HD4850 → モニタ2 : 205fps RADEON HD4670 → モニタ1 : 140fps RADEON HD4670 → モニタ2 : 164fps
HD4850 ではモニタ1 の方が高速、HD4670 ではモニタ2 の方が高速です。
アダプタから直接出力した方が速く、予想通りの結果といえます。
同時にたとえ直結されていなくても、モニタ2 の描画も HD4850 が行った方が速いこともわかります。
DirectX SDK 付属サンプルの DXUT がウィンドウの位置を監視して、モニタに応じて
デバイスを作り直しているのは少しでも高速に動作するためだと考えられます。
昔はビデオカードを何度も何度も差し直して開発していました。
GeForce と RADEON の挙動を同時に確認できるなんて、大変便利になったものです。
上のテストの最中、途中で GeForce GTX260(192sp) から HD4850 に差し直したのは
本日非常に暑かったからです。
関連エントリ
・Windows7 リモートデスクトップと Direct3D
Windows7 RC と同時に WindowsSDK の RC 版も出ています。
・Microsoft Windows SDK for Windows 7 and .NET Framework 3.5 SP1: RC
・Microsoft Windows SDK for Windows 7 and .NET Framework 3.5 SP1: RC (ISO)
BETA 時点からタッチ周りの API など変更されているところがあるので要注意です。
たとえば WM_TOUCHDOWN, WM_TOUCHUP, WM_TOUCHMOVE 等は無くなり
WM_TOUCH に統一されているようです。
マニュアルも更新されています。
以前 User Interface の下にあった Touch 関連が Windows Touch
という新項目にまとめられています。このあたり力が入ってます。
・MSDN Windows Touch
Direct3D11 関連も DirectX SDK March 2009 より新しいものが含まれていました。
ただし d3d11.lib などの lib 名に _beta がついていないので include の順番に
注意した方が良さそうです。
Vista で使う場合は DXSDK の方を。
関連エントリ
・Windows7 Multitouch API その(2) WM_GESTURE 系
・Windows7 Multitouch API
・DirectX SDK March 2009
・Microsoft Windows SDK for Windows 7 and .NET Framework 3.5 SP1: RC
・Microsoft Windows SDK for Windows 7 and .NET Framework 3.5 SP1: RC (ISO)
BETA 時点からタッチ周りの API など変更されているところがあるので要注意です。
たとえば WM_TOUCHDOWN, WM_TOUCHUP, WM_TOUCHMOVE 等は無くなり
WM_TOUCH に統一されているようです。
マニュアルも更新されています。
以前 User Interface の下にあった Touch 関連が Windows Touch
という新項目にまとめられています。このあたり力が入ってます。
・MSDN Windows Touch
Direct3D11 関連も DirectX SDK March 2009 より新しいものが含まれていました。
ただし d3d11.lib などの lib 名に _beta がついていないので include の順番に
注意した方が良さそうです。
Vista で使う場合は DXSDK の方を。
関連エントリ
・Windows7 Multitouch API その(2) WM_GESTURE 系
・Windows7 Multitouch API
・DirectX SDK March 2009