Skip to content
Go back

The Devil is in the Details: idTech 666

· Updated:

slides web

拙訳

初期の必須条件(Initial Requirements)

  • パフォーマンス: 60Hz @ 1080p
  • アートワークフローの高速化
  • マルチプラットフォームのスケーラビリティ
  • KISS
    • ミニマリスト的なコード
    • シェーダ順列が狂ったような数ではない: ~100シェーダ、~350パイプラインステート
  • 次世代ビジュアル
    • HDR、PBR
    • 動的で一様なライティング、シャドウ、反射
    • 良好なアンチエイリアシングとVFX

フレームの解剖(Anatomy of a Frame)

  • シャドウキャッシング: ~3.0ms
  • Pre-Z: ~0.5ms
  • 不透明フォワードパス: ~6.5ms
    • クラスタデータの準備
    • テクスチャコンポジット、ライティング計算
    • 出力: Lバッファ、薄いGバッファ、フィードバックUAV
  • ディファードパス: ~2.0ms
    • 反射、AO、フォグ、最終コンポジット
  • 透明: ~1.5ms
    • パーティクルライトキャッシング、パーティクル/VFX、草
  • ポストプロセス(非同期): ~2.5ms

ライティング&シェーディングのためのデータ構造(Data Structure for Lighting & Shading)

  • 以下からの派生
  • Just works™ - 透明な表面 - 追加のパスも処理も必要なし - 深度バッファから独立 - 深度の非連続性にわたって偽陽性なし - 次のスライドでよりJust Works™する

クラスタ構造の準備(Preparing Clustered Structure)

  • 錐台型のボクセル化/ラスタライゼーション処理
    • 深度スライスあたり1つのCPUジョブで行われる
  • 対数関数的な深度分布
    • 拡張されたニア面とファー面
    • ZSlice=Nearz(FarzNearz)slicenumslicesZSlice = Near_z \cdot \left( \frac{Far_z}{Near_z} \right)^{\frac{slice}{num slices}}
  • 各アイテムをボクセル化する
    • アイテムは以下があり得る: ライト、環境プロブ、デカール
    • アイテムの形状は: OBB、錐台(プロジェクター)
    • スクリーン空間のminxymin_{xy}maxxymax_{xy}、深度境界で括ったboundedラスタライゼーション
  • refinementはクリップ空間で行われる
    • クリップ空間でのセルはAABBである
    • N個の平面 VS セルのAABB
    • OBBは平面が6つ、錐台は平面が5つ
    • すべてのボリュームに対して同じコード
    • SIMD
for (y = MinY; y < MaxY; ++y) {
    for (x = MinX; x < MaxX; ++x) {
        intersects = N個の平面 vs セルのAABB
        if (intersects) {
            アイテムを登録する
        }
    }
}
  • 構造
    • オフセットリスト:
      • 64ビット x グリッドの大きさX x グリッドの大きさY x グリッドの大きさZ
    • アイテムリスト:
      • 32ビット x 256 x ワーストケース(グリッドの大きさX x グリッドの大きさY x グリッドの大きさZ)
  • オフセットリスト、要素ごと
    • アイテムリストへのオフセット、ライト/デカール/プロブの数
  • アイテムリスト、要素ごと
    • 12ビット: ライトリストへのインデックス
    • 12ビット: デカールリストへのインデックス
    • 8ビット: プロブリストへのインデックス
  • グリッドの解像度はかなり低解像度: 16 x 8 x 24
    • フォールスポジティブ: 早期脱出early outが軽減+アイテムリストの読み込みが一様(GCN)

ホットスポット: ~300個の光源、~1.2kのデカール

世界の描き込み(Detailing the World)

  • バーチャルテクスチャ[van Waveren 2009van Waveren, J.M.P. 2009. id Tech 5 Challenges. ACM SIGGRAPH. https://mrl.cs.vsb.cz/people/gaura/agu/05-JP_id_Tech_5_Challenges.pdf.]の更新
  • アルベド、スペキュラ、スムーズネス、法線、HDRライトマップ
  • フィードバックバッファUAVは最終解像度に直接出力する
  • 非同期コンピュートのトランスコーディング
    • コストはほぼ無関係mostly irrelevant
  • 設計上の欠陥が未だに存在する
    • 例えば、リアクティブテクスチャストリーミング = テクスチャポッピング
  • ジオメトリラスタライゼーションに組み込まれたデカール
  • メガテクスチャの”スタンピング”へのリアルタイム交換
    • 高速なワークフロー/低ディスク容量
  • Just Works™
    • 法線マップブレンディング
    • すべてのチャンネルで線形補正ブレンディング
    • ミップマッピング/異方性
    • 透明
    • ソート
    • 0個のドローコール
  • 8K x 8Kのデカールアトラス
    • BC7
  • ボックス投影
    • e0e_0e1e_1e2e_2はOBBの正規化された大きさextentppは位置
MdecalProj=MscaleMdecal1M_{decalProj} = M_{scale} \cdot M_{decal}^{-1}M_{scale} = \left| \begin{array} \\ \frac{0.5}{sizeX} & 0 & 0 & 0.5 \\ 0 & \frac{0.5}{sizeY} & 0 & 0.5 \\ 0 & 0 & \frac{0.5}{sizeZ} & 0.5 \\ 0 & 0 & 0 & 1 \end{array} \right|M_{decal} = \left| \begin{array} \\ e_{0_x} & e_{1_x} & e_{2_x} & p_x \\ e_{0_y} & e_{1_y} & e_{2_y} & p_y \\ e_{0_z} & e_{1_z} & e_{2_z} & p_z \\ 0 & 0 & 0 & 1 \end{array} \right|
  • デカールアトラスへのインデックス付け
    • デカールごと: 例えば、パラメータをスケール&バイアスする
const float4 albedo = tex2Dgrad(decalsAtlas, uv.xy * scaleBias.xy + scaleBias.zw, uvDDX, uvDDY);
  • アーティストにより手動で配置される
    • ブレンディングのセットアップを含む
    • “ブレンドレイヤー”の一般化
  • 視錐台ごとに4Kに制限される
    • 一般に1K以下で可視
  • LOD
    • アートが最大ビュー距離をセットアップする
    • プレイヤーの品質設定は同様にビュー距離に影響を与える
  • 動的な非変形ジオメトリで動作する
    • デカールにオブジェクトの変換を適用する

ライティング(Lighting)

  • 単一の/統一されたライティングコードパス
    • 不透明パス、ディファード、透明、分離したパーティクルライティング用(スライド23-27)
  • シェーダ順列が狂ったような数ではない
    • 静的/一貫性のある分岐はこんにちではかなり良い --- 使おう!
    • すべての静的ジオメトリで同じシェーダ
    • より少ないコンテキストスイッチ
  • 構成要素
    • ディフューズ間接ライティング: 静的ジオメトリにはライトマップ、動的ジオメトリには放射照度ボリューム
    • スペキュラ間接ライティング: 反射(環境プロブ、SSR、スペキュラオクルージョン)
    • 動的: ライト&シャドウ
// 擬似コード

ComputeLighting(inputs, outputs) {
    ベースのテクスチャを読み込む&パックする
    for each セル内デカール {
        早期脱出のフラグメント確認
        テクスチャを読み込む
        結果をブレンドする
    }

    for each セル内ライト {
        早期脱出のフラグメント確認
        BRDFを計算する/シャドウを適用する
        ライティングを累積する
    }
}
  • シャドウはアトラスにキャッシュ/パックされる
    • PC: 8K x 8Kのアトラス(高スペック)、32ビット
    • コンソール: 8K x 4K、16ビット
  • 距離に応じた可変解像度
  • 距離に応じたタイムスライシング
  • 静的ジオメトリに対する最適化されたメッシュ
  • ライトは移動しない?
    • 静的ジオメトリのシャドウマップをキャッシュする
    • 錐台の内側での更新なし?Ship it
    • 更新する?キャッシュされた結果で動的ジオメトリを合成する
    • 依然としてアニメーションできる(例えば、フリッカー)
  • アートセットアップ/クオリティ設定が上記すべてに影響を与える
  • シャドウ錐台投影行列へのインデックス
  • すべてのライトタイプで同じPCFルックアップコード
    • より少ないVGPRプレッシャー
  • これはディレクショナルライトのカスケードを含む
    • カスケード間で使われるディザー
    • 単一のカスケードルックアップ
  • VSMや派生型を試みた
    • すべていくらかのアーティファクトあり
    • 概念的にはフォワードで良好な将来性を持つ
      • 例えば、ラスタライゼーションからフィルタリング頻度を分離する
  • 一人称武器のセルフシャドウ
    • 専用のアトラスの一部。アトラス空間を節約するためにコンソールでは無効化される
  • VGPRプレッシャーに目を配る
    • 長い寿命を持つデータをパックする。例えば、HDR色ではfloat4⇔uint、RGBEエンコード
    • レジスタ寿命を最小化する
    • ネストされたループ/ワーストケースパスを最小化する
    • 分岐を最小化する
    • コンソール(PS4)で56個のVGPR
      • コンパイラの非効率さのためPCではもっと高い☹️ (AMDのコンパイラチームへ、ほんと直してください --- パフォーマンスの計算が狂っちゃうので)
  • 将来的に: half精度のサポートが役に立つだろう
  • NVIDIA: UBO/定数バッファを使う(分割バッファが必要 = 更なる/醜いコード)
  • AMD: SSBO/UAVのほうが良い

透明(Transparents)

  • 粗いガラスの近似
    • トップのMIPはハーフ解像度で、トータルで4つ
    • ガウシアンカーネル(おおよそGGXローブ)
    • 表面のスムーズネスに応じてMIPをブレンドする
    • 屈折の転送はパフォーマンスのためにフレームごと2つに制限される。
  • 表面のパラメータ化/デカール経由のバリエーション

パーティクルライティング(Particle Lighting)

分離したパーティクルライティング(Decoupled Particle Lighting)

  • 観察
    • パーティクルは一般に低周波/低解像度
    • 多分パーティクルあたりクアッド1つをレンダリングして、ライティング結果をキャッシュする?
  • スクリーン解像度からライティング周波数を分離する=利益
    • ライティングパフォーマンスがスクリーン解像度から独立
    • スクリーン/距離に依存する適応的解像度ヒューリスティック
      • 例、32x32、16x16、8x8
  • 厳密に同じライティングコードパス
  • 最終的なパーティクルは依然としてフル解像度である
    • バイキュービックカーネルでライティング結果を読み込む
// 擬似コード - パーティクルシェーディングはこのようなモノになる

Particles(inputs, outputs) {
    ...
    const float3 lighting = tex2D(particleAtlas, inputs.texcoord);
    result = lighting * inputs.albedo;
    ...
}
  • 4K x 4Kのパーティクルライトアトラス
    • サイズはプラットフォームごと/クオリティ設定で変化する
    • R11G11B10_FLOAT
  • パーティクル解像度ごとに専用アトラス領域
    • いくつか無駄になる、が申し分なく動作する --- Ship it
  • かなりパフォーマンスが良い: ~0.1ms
    • ワーストケースで最大1msくらい
    • それでも2、30倍couple orders magnitudeくらい高速
    • 非同期コンピュートに対する良い候補

ポストプロセス(Post-Process)

データフェッチの最適化(GCN)(Optimizing Data Fitching)

  • divergent1でない処理に対するGCNスカラユニット
  • データフェッチの高速化で素晴らしい
    • いくつかのVGPRを節約する
    • 一貫性のある分岐
    • より少ない命令数(SMEM: 64バイト、VMEM: 16バイト)
  • クラスタードシェーディングのユースケース
    • 各ピクセルはその属するセルからライト/デカールをフェッチする
    • 生まれつきdivergentだが、解析する価値がある

クラスタードライティングのアクセスパターン(Clustered Lighting Access Patterns)

Analyzing the Data(データの解析)

  • ほとんどのWavefrontはひとつのセルのみにアクセスする
  • 近くのセルはそのコンテンツのほとんどを共有する
  • スレッドはほぼ同じデータをフェッチする
  • スレッドごとのセルデータフェッチは最適ではない
    • このデータ集中性convergenceを活用していない
  • マージしたセルのコンテンツにわたるスカライテレーションの可能性
    • すべてのスレッドがまったく同じデータを独立してフェッチさせない

アクセスパターンの活用(Leveraging Access Patterns)

  • データ: ソートされたアイテム(ライト/デカール)IDの配列
    • ライトやデカール処理と同じ構造
    • 各スレッドは異なるノードにアクセスする可能性がある
    • 各スレッドはこれらの配列で独立してイテレートする
  • スカラの読み込み: イテレーションをシリアライズする
    • すべてのスレッドに渡るアイテムIDの最小値を計算する
      • ds_swizzle_b32/minInvocationsNonUneformAMD
    • 選択されたインデックスが一致するスレッドでアイテムを処理する
      • 一様なインデックス -> スカラ命令
      • 合致するスレッドは次のインデックスに移動する

特殊なパス(Special Paths)

  • ひとつのセルのみに触る場合にはファストパス[Fuller 2015Fuller, M. 2015. GPU Best Practices (Part 2). Xfest.]
    • GCN1と2では安価ではない、アイテムIDの最小値の計算を避ける
    • いくつかの追加の(マイナーな)スカラのフェッチと処理
  • シリアライズはスレッド間の局所性を仮定する
    • 触るセルが多すぎる場合、かなり遅くなる可能性がある
    • パーティクルライティングアトラス生成では無効化される
  • 不透明レンダリングパス、PS4 @ 1080p
    • デフォルト: 8.9ms
    • シリアライズされたイテレーションのみ: 6.7ms
    • 単一セルのファストパスのみ: 7.2ms
    • シリアライズされたイテレーション+ファストパス: 6.2ms

動的解像度スケーリング(Dynamic Resolution Scaling)

  • GPU負荷に基づいて解像度を適応させる
    • PS4ではほぼ100%、Xboxではより積極的なスケーリング
  • 同じターゲットにレンダリングして、ビューポートサイズを調整する
    • 直観的に: 追加のシェーダコードを必要とする
    • OpnGLでの選択肢のみ
  • 将来的に: 複数のレンダターゲットをエイリアスする
    • コンソールやVulkanで可能性がある
  • TAAは様々な解像度からサンプルを累積できる
  • 非同期コンピュートでアップサンプリングする

非同期ポストプロセッシング(Async Post Processing)

  • シャドウ&深度パスはコンピュートユニットをほぼ使わない
    • 固定グラフィクスパイプライン・ヘビー
  • 不透明パスは100%ビジーでもない
  • それらをポストプロセッシングとオーバーラップする
    • GFXキューで乗算済みアルファバッファにGUIをレンダリングする
    • コンピュートキューでのポストプロセス/AA/アップサンプル/UI合成
    • N+1フレームのシャドウ/深度/不透明とオーバーラップする
    • 使えるならコンピュートキューからpresentする
      • 潜在的に低レイテンシー

GCNのWaveの限界のチューニング(GCN Wave Limits Tuning)

  • パスごとに異なる限界をセットアップする
    • 高いピクセル/トライアングル比に対する遅延アロケーションを無効化する
  • 非同期コンピュートのアロケーションを制限する
    • すべてのコンピュートユニットを盗むのを回避する
    • cache thrashing2を和らげる
  • 出荷前に細かな調整を行う価値がある
    • DOOMでの幾つかのシーンでは最大1.5msを節約した!

GCNのレジスタの使い方(GCN Register Usage)

  • レジスタとLDS割り当てについて大局的に考える
    • 除数を256に常にしようとしない
    • 並行な頂点/非同期コンピュートシェーダを覚えておく
  • スイートスポットを見つけるための細かな調整
  • 例: DOOMの不透明パス
    • GFXキュー: PSでは56VGPR、VSでは24VGPR
    • コンピュートキュー: アップサンプリングCSでは32VGPR
    • 4PS+1CS/VS か 3PS+2CS+1VS
    • 64VGPRバージョンと比較して0.7msを節約する

次は?(What’s next?)

  • コストの頻度を分離する=利点
  • 改善
    • テクスチャクオリティ
    • 大域照明
    • 全体のディテール
    • ワークフロー
    • など

おまけのスライド(Bonus Slides)

ライティング(Lighting)

  • ライトタイプ
    • ポイント、プロジェクター、ディレクショナル(明示的な太陽ではない)、エリア(クアッド、ディスク、スフィア)
    • IBL(環境プロブ)
  • ライト形状
    • ほとんどのライトはOBB: アートがライトリークを軽減するのに役立つ暗黙的な”クリップボリューム”を務める
    • プロジェクターはピラミッド
  • 減衰/プロジェクター
    • 現時点ではアート駆動テクスチャを用いる
    • アトラスに格納され、デカールに似たインデクシング
    • アートは時々偽のシャドウを用いる
    • BC4
  • 環境プロブ
    • キューブマップの配列、プロブID経由でインデックスする
    • 固定の解像度、128x128
    • BC6H

ディファードパス(Deferred Passes)

  • 動的でパフォーマンスの高いAO&反射を求めた
  • フォワード不透明パス中の2つの追加ターゲット
    • スペキュラ&スムーズネス: RGBA8
    • 法線: R16B16F
  • プロブをリアルタイム反射と合成できるようにする
  • 最終合成
    • SSR、環境プロブ、AO/スペキュラオクルージョン、フォグ

Footnotes

  1. 訳注:Branch divergenceとは、GPUがデータ依存の分岐処理を扱う方法。GPUでは、スレッドは32/64個ごとにWarpにまとめられ、Warp単位で歩調を合わせて命令を実行するため、Warp内でスレッドごとに分岐先が異なる場合、先に分岐先の計算をすべて行ってしまい、その結果をスレッドが取捨選択することで実現する。一般に計算量が増えるのでパフォーマンスが低下する。参考: http://www.irisa.fr/alf/downloads/collange/cours/gpuprog_ufmg_2015/gpu_ufmg_2015_5.pdf

  2. 訳注:特定のアクセスパターンにより、キャッシュミスが過度に発生する状態。