Direct3D12のマルチGPU使用方法

Direct3D12ではマルチGPUの利用は二つの方法があるのですが,GDC 2016の”Culling at the Speed of Light in Tiled Shading and Explicit Multi GPU Programming with DirectX 12″あたりから使用方法について書いていきます.
Culling at the Speed of Light in Tiled Shading と Explicit Multi GPU Programming with DirectX 12
http://twvideo01.ubm-us.net/o1/vault/gdc2016/Presentations/Zhdan_Sjoholm_Light_culling_MGPU.pdf
※このスライドは2つの発表のスライドが1枚にマージされていて61枚目から”Explicit Multi GPU Programming with DirectX 12″がスタートします.”Culling at the Speed of Light in Tiled Shading”については今回話題にしません.
ちょうどこの話題をしてみようかと考えたのは,GeForce GTX 1080とRadeon RX 480のパフォーマンスの話で480をCrossfireすると1080を抜くという話とMicrosoftがLinked GPU SampleというマルチGPUのサンプル(D3DX12AffinityLayer ライブラリ)を公開したことがきっかけになります.
Linked GPU Sample
https://github.com/Microsoft/DirectX-Graphics-Samples/tree/master/Samples/Desktop/D3D12LinkedGpus
Direct3D12のマルチGPU利用の方法としては,Multi Adapterという方法がありましたが,これに関しては従来から下記にサンプルが公開されていました.ゲーミングノートPCなんかを利用している方にはIntel GPUとNVIDIA GPUを搭載したOptimus環境であれば下記のサンプルは動くと思います.
Heterogeneous Multiadapter Sample
https://github.com/Microsoft/DirectX-Graphics-Samples/tree/master/Samples/Desktop/D3D12HeterogeneousMultiadapter
今回は,Multi AdapterとLinked GPUの違いや利用のシナリオなどについて解説していきます.
最初のスライド”Explicit Multi GPU Programming with DirectX 12″の話題に戻りますが,まずMulti Adapterについて示した67枚目のスライドと66枚目のLinked GPUを見てみます.
gpu001
Multi Adapter
gpu002
Linked GPU
Multi Adapterでは,GPUごとにIDXGIAdapter(これはスライドでは省略)を作成したあとにID3D12Deviceを作成します.GPUごとにID3D12Deviceがあるのは管理は楽ではないですが,概念的にはわかりやすいと思います.
Direct3D12ではテクスチャやバッファなどのリソースの生成ID3D12Deviceで行いますが,生成に利用したID3D12DeviceのGPUのビデオメモリ上にテクスチャやバッファを作成しますので,複数のID3D12Deviceがあるプログラムではテクスチャやバッファはほかのデバイスから作成されたものと混ぜながら使うことができませんが,複数のGPUでデータをやり取りしたり分担しながら作業をさせるためにCross Adapter Resource Heapを使ってやり取りすることが書かれていますが,ドキュメントでいうと下記のShared Heapsですね.
Shared Heaps
https://msdn.microsoft.com/en-us/library/windows/desktop/mt186623(v=vs.85).aspx
一方で,Linked GPUの場合にはID3D12Deviceは1つでその中にNodeというものがあり,これがGPUを示します.ID3D12Deviceのメンバ関数のいくつかにはNodeを指定することができるものがあります.
例えば,ID3D12Device::CreateRootSignatureなんかにも第1引数に書かれてます.
ID3D12Device::CreateRootSignature
https://msdn.microsoft.com/ja-jp/library/windows/desktop/dn899182(v=vs.85).aspx
Nodeの指定はマスクで指定が可能で,下記のスライドのような感じです.GPUを1つ指定する以外にも複数指定などもできるわけですね.
gpu003
Linked GPUにはMulti Adapterに比べてさらにメリットがあるようでそれぞれのGPU上のリソースコピーに関してシステムメモリを経ずにダイレクトにGPU間のメモリコピーができるようです.
gpu004
「ダイレクトにGPU間のメモリコピー」はなんでできるのか考えてみると上図の右下のMulti GPU linkというのが目に入ります.これはSLIやCrossfireを行ったときにGPU間の接続に専用のブリッジケーブルを使ってることを指します.この直接接続が”Link”なんでしょうね.
SLIやCrossfireでは専用のブリッジケーブルを使うことでGPU間のメモリのやり取りなどできるわけですが,Direct3D12ではAPIでマルチGPU間の直接接続が考慮されてるわけですね.
NVIDIA環境なんかだと将来的にはNVLINKで接続されたマルチGPUなどもこのあたりをサポートしそうですね.
まとめ
そんなわけで,Direct3D12でマルチGPUを使用するMultiadapterとLinked GPUの2つの仕組みがどういうものかわかりました.サンプルプログラムはすでに両方とも用意されていますので,それをもとに実際に実装を学ぶことができますね.
それから”Explicit Multi GPU Programming with DirectX 12″の資料にはほかにもマルチGPU開発や注意点など書かれていますので,実際にマルチGPU環境を相手にする人は読み込んでおくとよいとは思います.