メインコンテンツへスキップ
Tech Playground
ゲーム開発

SER標準化でレイトレ性能90%向上の実装解説

DirectX 12 Agility SDK 1.619で正式リリースされたShader Execution Reorderingの仕組みとHLSL実装パターンを、実タイトルのベンチマークとともに解説する

約15分で読めます

2026年2月26日、MicrosoftはAgility SDK 1.619とDXC 1.9.2602.16を正式リリースし、Shader Model 6.9を製品版に昇格させた。目玉はDXR 1.2に含まれるShader Execution Reordering(SER)の標準化だ。NVIDIAがAda Lovelace世代で独自実装していたスレッド再配置技術が、DirectXの公式APIとして全ベンダーに開放された。Microsoftのデモではインテル Arc B-Seriesで最大90%、RTX 4090で約40%のフレームレート向上が確認されている。

本稿では、SERがなぜこれほどの性能差を生むのかをGPUのサブグループ実行モデルから解きほぐし、HLSL上の実装パターンと実ゲームタイトルでの効果を検証する。

レイトレーシングにおけるスレッド発散問題とSERの解決アプローチ

レイトレーシングの性能ボトルネックは、GPUの並列実行モデルとレイの「ランダム性」の相性の悪さにある。GPUは32スレッド(NVIDIA)または64スレッド(AMD)をサブグループ(Warp/Wave)として束ね、同一命令を一括実行する。しかしレイトレーシングでは、1つのサブグループ内の各スレッドが異なるマテリアル(金属、ガラス、拡散面、ミス)にヒットし、それぞれ別のClosestHitシェーダーを呼び出す。結果として32本のレイが32種類のシェーダーを逐次実行する最悪ケースが発生し、理論上の並列性能の数%しか活用できない。

SERはこの問題を「トラバーサルとシェーダー呼び出しの分離」で解決する。従来のTraceRay()は加速構造体のトラバーサルからClosestHit/Missシェーダーの実行までを一括で行っていた。SERでは以下の3ステップに分解する。

  1. HitObject::TraceRay() — 加速構造体をトラバースし、結果をHitObjectに格納(シェーダーは呼ばない)
  2. dx::MaybeReorderThread() — GPU上でスレッドを一時停止し、類似するシェーダーを実行するスレッド同士を同一サブグループに再配置
  3. hit.Invoke() — 再配置後の高いコヒーレンシーでClosestHit/Missシェーダーを実行

以下のダイアグラムは、SER適用前後のサブグループ内スレッド実行パターンの変化を示している。

flowchart LR
    subgraph before["SER適用前:サブグループ内の発散"]
        direction TB
        W1["Warp 0"]
        W1 --> T0["スレッド0: 金属"]
        W1 --> T1["スレッド1: ガラス"]
        W1 --> T2["スレッド2: ミス"]
        W1 --> T3["スレッド3: 拡散"]
        W1 --> T4["スレッド4: 金属"]
        W1 --> T5["スレッド5: ガラス"]
        T0 -.- note1["→ 6種のシェーダーを逐次実行"]
    end

    subgraph after["SER適用後:コヒーレントな再配置"]
        direction TB
        W2["Warp 0(再配置済)"]
        W2 --> R0["スレッド0: 金属"]
        W2 --> R1["スレッド1: 金属"]
        W2 --> R2["スレッド2: 金属"]
        W2 --> R3["スレッド3: 金属"]
        W2 --> R4["スレッド4: 金属"]
        W2 --> R5["スレッド5: 金属"]
        R0 -.- note2["→ 1種のシェーダーを並列実行"]
    end

    before --> after

SER適用前はサブグループ内で複数種類のシェーダーが混在し逐次実行されるが、適用後は同種のシェーダーがまとまり、GPU演算ユニットの稼働率が飛躍的に改善する。

HLSLによるSER実装パターンとコヒーレンスヒント設計

Shader Model 6.9で追加されたHitObject型とMaybeReorderThread組み込み関数を使った基本的な実装パターンは以下の通りだ。

[shader("raygeneration")]
void RayGen()
{
    RayDesc ray = GenerateCameraRay();
    MyPayload payload = (MyPayload)0;

    // Step 1: トラバーサルのみ実行、シェーダーは呼ばない
    HitObject hit = HitObject::TraceRay(
        Scene, RAY_FLAG_NONE, ~0, 0, 1, 0, ray, payload);

    // Step 2: コヒーレンスヒント付きでスレッドを再配置
    uint sortKey = hit.IsHit() ? hit.GetInstanceID() % 16 : 0;
    dx::MaybeReorderThread(sortKey, 4); // 4ビットのヒント

    // Step 3: 再配置後にシェーダーを実行
    hit.Invoke(payload);
}

MaybeReorderThreadの第2引数はソートキーのビット幅を指定する。GPUはまずシェーダー種別で大分類し、次にアプリケーション提供のヒントで細分類する。ヒント設計がSERの効果を大きく左右する。MicrosoftのSER仕様書では、マテリアルフラグ、テクスチャバインディングインデックス、早期終了条件のエンコードが推奨されている。

HitObjectはシェーダーを呼ばずにヒット情報にアクセスできる点も重要だ。シャドウレイやアンビエントオクルージョンのように「当たったかどうか」だけが必要なケースでは、hit.IsHit()で判定するだけでClosestHitシェーダーの呼び出し自体を省略できる。

以下のダイアグラムは、従来のTraceRayパイプラインとSER適用時のパイプラインを比較している。

sequenceDiagram
    participant App as RayGenシェーダー
    participant BVH as 加速構造体
    participant GPU as GPUスケジューラ
    participant CHS as ClosestHitシェーダー

    Note over App,CHS: 従来のTraceRay(一括実行)
    App->>BVH: TraceRay()
    BVH->>CHS: ヒット → 即座にシェーダー呼び出し
    CHS-->>App: 結果返却(発散したまま実行)

    Note over App,CHS: SER適用時(3ステップ分離)
    App->>BVH: HitObject::TraceRay()
    BVH-->>App: HitObject返却(シェーダー未実行)
    App->>GPU: MaybeReorderThread(hint)
    GPU-->>App: スレッド再配置完了
    App->>CHS: hit.Invoke()
    CHS-->>App: 結果返却(コヒーレント実行)

従来方式ではトラバーサル直後にシェーダーが呼ばれるためスレッド発散を制御できないが、SERではトラバーサルとシェーダー実行の間に再配置ポイントを挿入することで、GPU側がスレッドを最適に並べ替える余地を得る。

実タイトルでの効果:Indiana Jonesとベンダー別ベンチマーク

SERの実ゲームでの効果は、NVIDIAが公開したIndiana Jones and the Great Circleのパストレーシング最適化事例が最も詳細なデータを提供している。GeForce RTX 5080上でのTraceMainパス(メインのパストレーシング処理)を対象に、以下の結果が報告された。

SER適用によるアクティブスレッド率の変化:

  • SER適用前: Warpあたり38%のアクティブスレッド率
  • SER適用後: Warpあたり70%のアクティブスレッド率

初期のSER実装ではGPU時間が4.08ms → 3.63ms(11%削減)にとどまったが、NVIDIA Nsight GraphicsのRT Live Stateプロファイラで特定したスピルデータの最適化が鍵となった。primaryHitDesc構造体の動的ループを条件分岐に変換して72バイト削減、radianceAndAccumHitDistをfloat4からhalf4に精度降格して追加削減した結果、スピルされるRT Live Stateが222バイト → 84バイト(62%削減)に改善。最終的にSER ON/OFFの差は4.07ms → 3.08ms(24%削減)まで拡大した。

このLive State最適化は重要な教訓を含んでいる。SERはスレッドのローカル変数(Live State)を保存・復元して再配置を行うため、Live Stateが大きいほどオーバーヘッドが増加する。SERを導入する際は、RayGenシェーダー内の変数サイズを可能な限り圧縮することが性能改善の前提条件となる。

他の実タイトルでもSERの効果は確認されている。Khronosのブログによれば、Black Myth: WukongのReSTIR GIパスでは15.10ms → 4.08ms(3.7倍高速化)、コヒーレンスが20.5% → 69.9%に改善。Alan Wake 2ではOpacity Micromapとの併用でレイトレーシングコストが16.8ms → 10.2ms(約39%削減)に低下した。

ベンダー別のハードウェア対応状況:

GPUSER API対応実際のリオーダー実行Microsoftデモでの性能向上
NVIDIA RTX 40xx以降対応実行ありRTX 4090: 約40%向上
NVIDIA RTX 50xx対応実行ありRTX 5080: 約80%向上
Intel Arc B-Series対応実行あり最大90%向上
AMD RX 9000 (RDNA 4)対応実行なし限定的

AMDのRDNA 4はSERのAPIを「サポート」するが実際のリオーダーは行わない。D3D12_RAYTRACING_TIER_1_2への対応は表明しているものの、ハードウェアレベルでのスレッド再配置はRDNA 5/UDNA世代からの対応が見込まれる。開発者はデバイスクエリでリオーダー実行の有無を確認できるため、ハードウェア差を考慮した分岐処理が可能だ。

なお上記のベンチマーク数値はいずれもMicrosoftのデモ(D3D12RaytracingHelloShaderExecutionReordering)またはベンダーの技術デモによるもので、実ゲームタイトルでの効果はワークロード構成に依存して変動する。

DXR 1.2のもう一つの柱:Opacity MicromapとLong Vectors

Agility SDK 1.619ではSERと並んで、DXR 1.2のもう一つの主要機能であるOpacity Micromap(OMM)のHLSL部分も正式版に昇格した。OMMは半透明ジオメトリの処理を最適化する技術で、草木やフェンスなどアルファテスト付きジオメトリに対するAnyHitシェーダーの呼び出しコストを大幅に削減する。各マイクロトライアングルに「不透明」「透明」「不確定」のラベルを事前に付与し、不確定な場合にのみAnyHitシェーダーを呼び出す仕組みだ。NVIDIAの報告ではパストレーシング対応タイトルで最大2.3倍の性能向上が確認されている。ただしハードウェアアクセラレーションはNVIDIA RTX 4xxx以降に限定される。

Shader Model 6.9のもう一つの注目機能はLong Vectorサポートだ。従来HLSLのベクトル型は最大4要素(float4等)に制限されていたが、SM 6.9では最大1024要素のベクトルに対する要素単位演算が可能になった。これはニューラルネットワーク推論のシェーダー内実行を想定した機能で、重み行列の演算をGPUシェーダー内で直接処理できる。なお同機能の発展形として、SM 6.10ではCooperative Vectorを置き換える統一的な行列・ベクトル演算APIが予定されている。

VulkanでもSERに相当するVK_EXT_ray_tracing_invocation_reorderがベンダー横断の拡張として策定されており、reorderThreadEXT()とhitObjectTraceRayEXT()でDirectXと同等のパイプラインを構築できる。APIの抽象度はほぼ同一で、DirectXのMaybeReorderThread(hint, bits)がVulkanのreorderThreadEXT(hitObject, hint, bits)に対応する。クロスAPI開発において、SERロジックの移植コストは低い。

SERの標準化はレイトレーシングの性能特性を根本から変える。従来「GPUが勝手に最適化する領域」とされていたスレッドスケジューリングに、開発者がコヒーレンスヒントを通じて介入できるようになった。エンジン統合が進めば、パストレーシングのリアルタイム化がより多くのタイトルで現実的な選択肢になる。

参考リンク

#DirectX12 #Shader Execution Reordering #レイトレーシング #DXR 1.2 #Shader Model 6.9
シェア: