Skip to content
Go back

GPU Memory Pools in D3D12

· Updated:

web

拙訳

  • UMA:CPUとGPUが同じ物理メモリを共有するアーキテクチャ
    • CPUとGPUで同じ領域を直接読み書きできる
    • NUMAとくらべてメモリ帯域幅が一桁くらい狭い
      • DDRでは数十GB/sなのに対し、GDDRでは数百GB/s
  • NUMA:GPUが専用の物理メモリを持つアーキテクチャ
    • UMAとくらべてメモリ帯域幅が広い
    • 外とデータをやり取りするためのPCIeバスの帯域幅が狭い
      • PCIe 3.0では16GB/s、PCIe 4.0では32GB/s
    • CPUはBAR(ベース・アドレス・レジスタ)によりVRAMに直接書き込みできる
      • BARでは256MBまでに制限される
      • ReBAR(Resizable BAR)では全体にアクセスできる
  • write combining:
    • CPUキャッシュを介さずに連続した書き込みをまとめて行う機能
    • 「CPU書き込み・GPU読み取り」を行うときに有効
      • CPU読み取りを行わないので、キャッシュする必要がない

D3D12

  • ヒープタイプ:
    • DEFAULT:GPUでアクセス
    • UPLOAD:CPUからGPUへ
    • READBACK:GPUからCPUへ
    • CUSTOM
      • UMA
        • L0(SysRAM)
          • NOT_AVAILABLE:CPU読み書き不可
          • WRITE_COMBINE:キャッシュされないメモリアクセス
            • CPU書き込みが速く、CPU読み取りが非常に遅い
          • WRITE_BACK:キャッシュされるメモリアクセス
            • CPU読み取りが速い
            • CacheCoherentUMA == TRUEなら、書き込みも速い
            • CacheCoherentUMA == FALSEなら、WRITE_COMBINEのほうが速くなるかも
      • NUMA
        • L0(SysRAM):GPU読み取りはPCIeを介するため比較的遅い
          • NOT_AVAILABLE:CPU読み書き不可。不要
          • WRITE_COMBINE:キャッシュされないメモリアクセス
            • CPU書き込みが速く、CPU読み取りが非常に遅い
          • WRITE_BACK:キャッシュされるメモリアクセス
            • CPU読み書きが速い
              • CPU読み取りを行わないなら、キャッシュ汚染しないWRITE_COMBINEのほうが良い
        • L1(VRAM)
          • NOT_AVAILABLE
            • CPU読み書き不可
            • GPUのみで読み書きする場合に最適
          • WRITE_COMBINE:無効
          • WRITE_BACK:無効
  • CPUアクセス可能なVRAMはAPI上では公開されていない
    • メーカーの拡張APIを使うとできる場合もある
    • ドライバが自動でやってくれる場合もある
  • VRAMが足りなくなると、OSはリソースをVRAMからSysRAMへ移動させることができる
    • VRAMに残す優先順位を付けるためのAPIがある

テクスチャ

  • テクスチャはGPU固有のswizzleパターンで格納される
    • アプリはそのパターンを知らないので、非swizzleなデータをドライバ経由でコピーする必要がある
      • UPLOADバッファからDEFAULTテクスチャへコピーする
      • CPU書き込み可能なテクスチャへWriteToSubresourceで書き込む
        • テクスチャがSysRAMに配置される場合、NUMAでパフォーマンス上の問題になる可能性がある
        • UMAやBARでは選択肢としてありだが、コピー処理でCPU負荷が高くなるかもしれない

バッファ

  • 何度も再利用しない小さなデータなら、UPLOADバッファのパフォーマンス損失は無視できる
    • 逆に、DEFAULTにコピーすると、そのコピーの分だけロスになる可能性もある
    • UMAやReBARでは、常にUPLOADバッファを使うこともできるようになるかも

コピーキュー

  • NUMAでは専用のDMAユニットで処理される
    • 計算処理に対して非同期に行うことができる
  • UMAではDMAがないので、他のキューのコマンドと共に単一のハードウェアキューでフラット化される
    • UMAに最適化するなら、CPU書き込み可能なテクスチャを使用すると良い
  • NVIDIAやAMDのGPUでは、コピーキューを2つ持つことができる
    • 優先度の高い処理を別にすることで、DIRECTキューへの影響を小さくする
  • 設計の例:
    • リングバッファでステージングバッファを管理する、とか
    • レンダリングフレームと同期してコマンド記録する、とか
    • 独立したスレッドでコマンド記録する、とか

まとめ

  • NUMAの場合:
    • CPUからアクセスする必要ないリソースは必ずVRAMに置く
    • コピーキューを使って、VRAMに置いたリソースを非同期に初期化する
    • 大きなバッファはステージングバッファ経由でコピーキューを使って更新する
    • ストリーミング用のコピーキューとフレームリソース用のコピーキューを用意する
    • 可能であれば、大きなバッファはCPU書込み可能なVRAMを割り当てる
  • UMAの場合:
    • コピーキューを使わず、CPU書き込みできるバッファを使う
  • 共通:
    • キャッシュされないCPU読み取りは行わない
    • CPUからGPUへのメモリの更新では、memcpyのようなシーケンシャルな書き込みで行う