> ## Documentation Index
> Fetch the complete documentation index at: https://devdocs.xbox.com/llms.txt
> Use this file to discover all available pages before exploring further.

# XDXRStandaloneTraverse

> XDXRStandaloneTraverse

XDXR 目前不支援 DXR 1.1 中所述的 `RayQuery` 物件。不過，我們提供單一標頭的周遊實作 (具有數個變體)，它與我們的 DXR 1.0 周遊邏輯共用大部分程式碼，並將其包裝在與 `RayQuery` 物件 API 大致相同的 API 中。此標頭可用於任何允許使用者配置 LDS 的著色器階段，包括計算著色器與像素著色器。

此系統應能讓依賴 DXR 1.1 `RayQuery` 的 PC 轉譯程式碼進行簡單 (幾乎 1:1) 的轉換。此外，在光線追蹤著色器 (AnyHit/ClosestHit 等) 數量不多的情況下，由於額外負荷較低，此系統在 XBOX 上通常明顯比 DXR 1.0 風格的光線追蹤更快。強烈建議陰影或環境光遮蔽等轉譯功能使用此內嵌標頭系統。

請注意，XDXR 目前不會針對 DXR 1.0 內嵌小型著色器繫結資料表。因此，部分 PC IHV 可能會有不同的建議。建議您獨立於 PC 驅動程式之外，分析 XBOX 光線追蹤的取捨。

## 使用方式

### 標頭

為取代 DXR 1.1 的 `RayQuery` 物件，我們在 GDK 安裝目錄 `GDK_Install_Path\GDK_Version\GXDK\gameKit\Include\Scarlett` 中提供數個版本的 XDXRStandaloneTraverse\*\*\*.hlsli 標頭檔。

這些標頭以原始程式碼形式提供，但開發人員必須負責確保其標頭檔版本與建置 BVH 所使用的 GDK 相容。較新的 GDK 不支援舊版標頭，而對標頭所做的修改必須與較新 GDK 中的任何變更合併。

目前的版本如下：

* XDXRStandaloneTraverseShortStack.hlsli
  * 此周遊版本與 XDXR 中目前用於 DXR 1.0 支援的預設周遊演算法相同。建議用於所有可能具有發散性的光線追蹤，例如 AO 或光澤反射。
* XDXRStandaloneTraverseHT.hlsli
  * 此周遊版本實作「一致性」(coherent) 周遊演算法，對於陰影光線或鏡面反射等高度一致的內容，可能比其他演算法更快。這等同於在 DXR 1.0 `TraceRay()` 光線旗標中指定 `XBOX_RAY_FLAG_COHERENT_RAYS_HINT`。
* XDXRStandaloneTraverseShortStackNoMultibox.hlsli
  * 此周遊版本不支援離線建置的 BVH，但如果只執行執行階段 BVH 建置，可能會稍微快一些。
* XDXRStandaloneTraverseLongStack.hlsli
  * 此周遊版本的堆疊大小上限為 32 個節點，在某些內容上可能更快，但可能導致遺漏光線命中。

### 整合

XDXRStandaloneTraverse 標頭提供與 DXR 1.1 `RayQuery` 物件相對應的 `XboxRayQuery` 物件。除了命名之外，API 應與 DXR 1.1 相同，但有下列差異：

* 只有在 2024 年 3 月 GDK 或更新版本中以 HLSL 2021 編譯時，才支援 `XboxRayQuery<RAY_FLAG_FORCE_OPAQUE | RAY_FLAG_SKIP_PROCEDURAL_PRIMITIVES>` 之類的範本旗標。
* 在 HLSL 2021 與 2024 年 3 月 GDK 之前，使用者應以下列其中一種方式取代 `RayQuery<RAY_FLAG_XXX | RAY_FLAG_YYY>`：
  * 將所有旗標放在 TraceRayInline() 的 rayFlags 參數中。旗標建議使用編譯時期常值，而非常數緩衝區值，以產生更好的程式碼。如果您想切換旗標，請考慮以分支方式呼叫不同的 TraceRayInline()。
  * 使用 `XboxRayQuery.TraceRayInlineNoAHS()` 取代 `RayQuery<RAY_FLAG_FORCE_OPAQUE>`；同樣地，使用 `XboxRayQuery.TraceRayInlineNoIS()` 或 `XboxRayQuery.TraceRayInlineNoAHSNoIS()` 停用交集著色器處理。
    * 同樣地，`XboxRayQuery` 物件上也有 `disableAHS` 與 `disableIS` 布林成員，可在呼叫 `TraceRayInline` 之後、第一次呼叫 `Proceed()` 之前設定為常值。
* `XboxRayQuery` 會維護全域狀態，一個 `XboxRayQuery` 物件的所有使用都必須在建立或使用第二個物件之前完成。這包括查詢最終命中狀態或資訊。
* XDXR (以及 `XboxRayQuery`) 目前不支援 `RAY_FLAG_SKIP_TRIANGLES` 或 `RAY_FLAG_SKIP_PROCEDURAL_PRIMITIVES`。如果需要分離，請考慮使用批次建置器 API 平行建置多個 TLAS。
  * 例外的是，HLSL2021 支援 `XboxRayQuery<RAY_FLAG_SKIP_PROCEDURAL_PRIMITIVES>`，其等同於 `XboxRayQuery.TraceRayInlineNoIS()`。此旗標僅支援作為範本參數。
* 由於一致性演算法的結構，`XDXRStandaloneTraverseHT.hlsli` 要求所有 `Proceed()` 處理常式程式碼在 AnyHit 或交集著色器邏輯之前加入 `if (query.CandidateType() == CANDIDATE_NON_OPAQUE_TRIANGLE || query.CandidateType() == CANDIDATE_PROCEDURAL_PRIMITIVE)`，以檢查確實回報了有效的命中。雖然在一般 DXR 1.1 中允許這樣做，但如果已知 BVH 只包含一種基本型別，通常會省略此檢查。這會導致 `XDXRStandaloneTraverseHT.hlsli` 實作中出現瑕疵。
* `XDXRStandaloneTraverseHT.hlsli` 周遊實作要求光線旗標與 TLAS 指標必須一致 (uniform)。
* XDXR 獨立周遊包含數個 DXR 1.1 中沒有的延伸功能，將於下一節中討論。

### CurrentNumIterations() 與 SetMaxNumIterations()

XDXR 獨立周遊新增了兩個與查詢及限制周遊反覆運算次數相關的簡單延伸功能。請注意，這些延伸功能都可能造成額外的 VGPR 壓力或 ALU 負擔。除非使用者打算設定夠低的反覆運算限制以抵銷額外成本，否則不應使用/啟用這些功能。

* `XboxRayQuery.CurrentNumIterations()` 會傳回到目前為止已執行的周遊邏輯反覆運算次數。可以在周遊之後呼叫此函式以繪製熱度圖，或在 AHS 邏輯或類似邏輯中呼叫以做出決策。著色器中對此函式的任何參考都會為周遊增加些許成本，即使位於執行階段旗標之後也是如此。建議將任何「熱度圖」模式放在 `#ifdef` 旗標之後，以確保發行模式不受影響。
* `XboxRayQuery.SetMaxNumIterations(uint maxNumIterations)` 可設定反覆運算次數上限，超過此上限後周遊將提早結束，結果將包含最近一次認可的命中 (若尚未找到則為無)。
  * 若要使用此功能，必須在包含周遊標頭之前設定 `#define XDXR_ENABLE_ITERATION_LIMIT 1`。
  * 將 `XboxRayQuery.SetMaxNumIterations(YOUR_ITERATION_LIMIT)` 呼叫放在 `XboxRayQuery.TraceRayInline()` 呼叫之後、`XboxRayQuery.Proceed()` 呼叫之前。
  * 若要測試周遊是否提早結束，請檢查是否 `XboxRayQuery.CurrentNumIterations() >= YOUR_ITERATION_LIMIT`。請注意，反覆運算次數可能高於限制，特別是在 `XDXRStandaloneTraverseHT.hlsli` 的情況下，因為周遊的某些階段無法在不產生大量成本的情況下提早結束。

### InlineAHS 與 InlineIS

XDXR 獨立周遊提供兩個延伸功能，可在需要簡單的 AnyHit 或交集著色器邏輯時提升周遊速度。

根據預設，DXR 1.1 RayQuery 周遊必須跳出 BVH 周遊迴圈，才能將控制權交給使用者，以在 `while(query.Proceed())` 迴圈中處理 AnyHit 或交集著色器邏輯。這可能導致複雜的流程控制以及次佳的效能。

XDXR 獨立周遊提供 InlineAHS 與 InlineIS 機制，允許將 AHS 或 IS 邏輯內嵌於周遊迴圈中，以提升效能。

自 2024 年 3 月 GDK 起，`XDXR_USE_INLINE_AHS_FUNCTION` 與 `XDXR_USE_INLINE_IS_FUNCTION` 定義已被取代。InlineAHS 與 InlineIS 功能現在可透過以 HLSL 2021 範本為基礎的 API 使用，並具有數項優點。以下是 HLSL 2021 版本的說明，舊版的說明則位於下方的章節。

#### HLSL 2021 InlineAHS 與 InlineIS

* 根據您需要 AnyHit (AHS) 邏輯、程序式交集 (IS) 邏輯或兩者，建立一個延伸 `InlineAHSBaseLambda`、`InlineISBaseLambda` 或 `InlineAHSAndISBaseLambda` 其中之一的 HLSL 結構。
* 在結構中建立簽章與名稱為 `void InlineAHS(inout XboxRayQueryProxy rqp)` 和/或 `void InlineIS(inout XboxRayQueryProxy rqp)` 的函式。
* 將 `while(query.Proceed()) {ISLogic(); AHSLogic()}` 迴圈中的所有 AHS 與 IS 邏輯剪下/貼上到 `InlineAHS` 或 `InlineIS` 函式中。
* `XboxRayQueryProxy` 物件支援與一般 `XboxRayQuery` 完全相同的功能，但 `XboxRayQuery.CandidateType()` getter 除外。請在 `InlineAHS()` 中處理 `CANDIDATE_NON_OPAQUE_TRIANGLE` 邏輯，並在 `InlineIS()` 中處理 `CANDIDATE_PROCEDURAL_PRIMITIVE` 邏輯 (包括 Alpha 測試)。
* `XboxRayQueryProxy` 可用來以與一般 `RayQuery` 物件完全相同的方式查詢周遊資訊，並透過 `rayQueryProxy.CommitNonOpaqueTriangleHit()` 或 `rayQueryProxy.Abort()` 函式處理命中。
  * 可在 `InlineIS()` 中查詢 `rayQueryProxy.CandidateProceduralPrimitiveNonOpaque()`，以判斷是否應針對程序式基本型別執行 AHS 邏輯。這與標準 DXR 1.1 內嵌光線追蹤相同。
* 使用 `InlineAHS` 或 `InlineIS` (或兩者) 時，不需要將 `rayQuery.Proceed()` 呼叫放在 while 迴圈中，因為在周遊完成之前，控制權不會交還給使用者。所有 AHS 或 IS 邏輯都會使用提供的函式內嵌。

```cpp theme={null}
#ifdef COMPILE_FLAG_INLINE_TRAVERSAL_HYBRID 
    #include "XDXRStandaloneTraverseHT.hlsli"
#else
    #include "XDXRStandaloneTraverseShortStack.hlsli"
#endif

// Extend one of: InlineAHSBaseLambda, InlineISBaseLambda, InlineAHSAndISBaseLambda.
// Implement one or both of: void InlineAHS(inout XboxRayQueryProxy rqp), void InlineIS(inout XboxRayQueryProxy rqp).
struct MyAHSLambda : InlineAHSBaseLambda
{
    // Optional: lambda structs can contain whatever state is required for your use-case.
    bool statefulVariable;

    void InlineAHS(inout XboxRayQueryProxy rqp)
    {
        if (MyAnyHitShaderImpl(...))
        {
            // rqp is inout, use the Commit functions as you would in DXR 1.1.
            rqp.CommitNonOpaqueTriangleHit();
        }

        if (statefulVariable)
        {
            ...
        }
    
        // Default is to ignore hits, to exit traversal completely use rqp.Abort().
    }
};

// Requires HLSL 2021.
[RootSignature(GlobalRootSignature)]
[numthreads(8, 4, 1)]
void MyRaygenShaderWith2021Lambda(uint3 DTid : SV_DispatchThreadID)
{
    RayDesc myRay = { ... };

    // RAY_FLAG_SKIP_PROCEDURAL_PRIMITIVES is used here to avoid costs associated with procedural primitive handling.
    // MyAHSLambda's InlineAHS will be inlined into the traversal loop.
    XboxRayQuery<RAY_FLAG_SKIP_PROCEDURAL_PRIMITIVES, MyAHSLambda> xrq;

    xrq.TraceRayInline(
        Scene,
        RAY_FLAG_NONE,
        0xff,
        myRay);

    MyAHSLambda myStatefulLambda;
    myStatefulLambda.statefulVariable = bool(DTid.x < 10);

    // Looping over this call is not required if the InlineAHS mechanism is used.
    // If your lambda struct has state members, it must be instantiated and provided as an argument to Proceed().
    // If your lambda struct does not have state members, this parameter can be omitted.
    xrq.Proceed(/*optional*/ myStatefulLambda);

    if (xrq.CommittedStatus() == COMMITTED_TRIANGLE_HIT)
    {
        ...
    }
}

// Requires HLSL 2021.
[RootSignature(GlobalRootSignature)]
[numthreads(8, 4, 1)]
void MyRaygenShaderWith2021Flags(uint3 DTid : SV_DispatchThreadID)
{
    RayDesc myRay = { ... };

    // RAY_FLAG_SKIP_PROCEDURAL_PRIMITIVES is used here to avoid costs associated with procedural primitive handling.
    XboxRayQuery<RAY_FLAG_SKIP_PROCEDURAL_PRIMITIVES> xrq;

    xrq.TraceRayInline(
        Scene,
        RAY_FLAG_NONE,
        0xff,
        myRay);

    // We have to loop over hit-candidates here. Normal DXR 1.1 Inline Raytracing style.
    while (xrq.Proceed())
    {
        // This if-statement is required for XDXRStandaloneTraverseHT even if the BVH is known to only contain triangles. Otherwise lanes without hits may remain active in this loop.
        if (xrq.CandidateType() == CANDIDATE_NON_OPAQUE_TRIANGLE)
        {
            if (MyAnyHitShaderImpl(alphaTexture, shaderRecord.alphaIsMask, xrq.CandidateTriangleBarycentrics(), u1, u2, u3))
            {
                xrq.CommitNonOpaqueTriangleHit();
            }               
        }
    }

    if (xrq.CommittedStatus() == COMMITTED_TRIANGLE_HIT)
    {
        ...
    }
}

// Works in HLSL 2018.
[RootSignature(GlobalRootSignature)]
[numthreads(8, 4, 1)]
void MyRaygenShaderWith2018Flags(uint3 DTid : SV_DispatchThreadID)
{
    RayDesc myRay = { ... };

    // No template flags in HLSL 2018.
    XboxRayQuery xrq;

    // TraceRayInlineNoIS is used here to avoid costs associated with procedural primitive handling.
    // Equivalent to XboxRayQuery<RAY_FLAG_SKIP_PROCEDURAL_PRIMITIVES> in HLSL 2021 versions.
    xrq.TraceRayInlineNoIS(
        Scene,
        RAY_FLAG_NONE,
        0xff,
        myRay);

    while (xrq.Proceed())
    {
        // This if-statement is required for XDXRStandaloneTraverseHT even if the BVH is known to only contain triangles. Otherwise lanes without hits may remain active in this loop.
        if (xrq.CandidateType() == CANDIDATE_NON_OPAQUE_TRIANGLE)
        {
            if (MyAnyHitShaderImpl(alphaTexture, shaderRecord.alphaIsMask, xrq.CandidateTriangleBarycentrics(), u1, u2, u3))
            {
                xrq.CommitNonOpaqueTriangleHit();
            }               
        }
    }

    if (xrq.CommittedStatus() == COMMITTED_TRIANGLE_HIT)
    {
        ...
    }
}
```

#### HLSL 2018 InlineAHS 與 InlineIS (已淘汰)

* 在 `#include "XDXRStandaloneTraverse****.hlsli"` 之前指定 `#define XDXR_USE_INLINE_AHS_FUNCTION 1` 和/或 `#define XDXR_USE_INLINE_IS_FUNCTION 1`。請注意，如果同時存在 AHS 與 IS 邏輯，兩者都必須使用內嵌系統，不能與一般 DXR 1.1 處理常式混用。
* 建立簽章與名稱為 `void InlineAHS(inout XboxRayQueryProxy rqp)` 和/或 `void InlineIS(inout XboxRayQueryProxy rqp)` 的全域函式
* 依照上述 HLSL 2021 版本的說明操作，並將結構成員 InlineAHS 與 InlineIS 函式取代為全域定義的 InlineAHS 與 InlineIS 函式。

## 記憶體

XDXR 驅動程式會為 DXR 1.0 `TraceRay()` 風格的周遊配置後備記憶體。如果您的遊戲只使用內嵌光線追蹤，您可能會想回收這些記憶體。截至 2022 年 6 月，此記憶體在 XBOX Series S 上為 12MB，在 XBOX Series X 上為 32MB。若要停用此記憶體，遊戲應在 [D3D12XBOX\_CREATE\_DEVICE\_PARAMETERS](/zh-TW/reference/graphics/d3d12_xs/structs/d3d12xbox_create_device_parameters_xs) 中為 `pDXRStackBuffer` 指定 `D3D12_GPU_VIRTUAL_ADDRESS_UNKNOWN`，並為 `DXRStackBufferOverrideSizeBytes` 指定大小 `0`。

## PIX 整合

如需在使用獨立周遊時於 PIX 中啟用光線路徑與熱度圖顯示的說明，請參閱 [PIX BVH 檢視器](/zh-TW/tools/tools-console/pix/gpu/pix-bvh-viewer) 文件中的「Draw Rays」一節。

## 另請參閱

[PIX BVH 檢視器](/zh-TW/tools/tools-console/pix/gpu/pix-bvh-viewer) [光線追蹤 (與 DXR) 概觀](/zh-TW/build/core-features/graphics/newfeatures/raytracing/rt-overview)


## Related topics

- [NDA 主題目錄 - Microsoft Learn 線上連結](/zh-TW/nda/nda-topic-directory.md)
- [獨立 SDK 概觀](/zh-TW/services/playfab/sdks/sdk-overview.md)
- [hamcrest 授權](/zh-TW/services/playfab/sdks/java/Licenses/hamcrest-license.md)
- [junit 授權](/zh-TW/services/playfab/sdks/java/Licenses/junit-license.md)
- [Java SDK](/zh-TW/services/playfab/sdks/java/index.md)
