> ## 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.

# 著色器編譯器

> 著色器編譯器

DirectX 著色器編譯器 (DXCompiler 或 DXC) 是適用於 Windows 與 XBOX 的新著色器編譯器。

在 Windows 上，光線追蹤與其他新功能已經需要 DXC。今後，DXC 將是啟用許多其他新功能的受支援途徑，包括正在積極開發中之未來遊戲平台上提供的功能。我們將在未來的版本中新增更多 XBOX 內建函式、新的著色器模型支援，以及許多其他功能與效能改進。

較舊的 D3D 著色器編譯器 (D3DCompiler 或 FXC) 已淘汰且不再受支援。

## HLSL 2021

自 2023 年 10 月 GDK 起，DXC 預設使用 HLSL 2021 語言。HLSL 2021 新增了對各種 C++ 樣式功能的支援：

* 範本函式與結構
* 結構元素上的位元欄位
* 運算子多載
* C++ 樣式的函式多載
* 純量的邏輯運算短路

如需詳細資訊，請參閱 [HLSL 2021](https://github.com/microsoft/DirectXShaderCompiler/wiki/HLSL-2021) 與 [HLSL 2021 移轉指南](https://devblogs.microsoft.com/directx/hlsl-2021-migration-guide/)。

若要使用先前的預設語言 HLSL 2018，請將 `-HV 2018` 傳遞給編譯器。

GitHub 上目前的問題清單位於 [HLSL 2021 問題標籤](https://github.com/microsoft/DirectXShaderCompiler/issues?q=is:open+is:issue+label:hlsl2021)底下。

歡迎在 GitHub 上提出錯誤，或透過 [AskHLSL@microsoft.com](mailto:AskHLSL@microsoft.com) 與我們聯絡，提供意見反應與問題。

## 開發中

XBOX 的 DXC 目前正在積極開發中。我們將在未來的版本中新增簡化的編譯器 .dll 介面、更多 XBOX 內建函式、新的著色器模型支援，以及許多其他功能與效能改進。

您可以透過 [AskHLSL@microsoft.com](mailto:AskHLSL@microsoft.com) 與小組聯絡。

## 著色器編譯器說明

* [使用 DXC](/zh-TW/tools/tools-console/shadercompiler/dxc-usage)：如何使用編譯器命令列介面 (dxc) 與 .dll 介面 (dxcompiler\_x.dll)
* [FXC 至 DXC 移植指南](/zh-TW/tools/tools-console/shadercompiler/dxc-port-from-fxc)：將著色器移植至 DXC 時的一些秘訣與技巧

## XBOX 特有功能

XBOX 的 DXC 支援許多 Windows 上無法使用的特殊定義與內建函式。如需詳細資訊，請參閱下列內容：

* [XBOX 定義](/zh-TW/tools/tools-console/shadercompiler/dxc-xbox-defines)
* [XBOX 內建函式](/zh-TW/tools/tools-console/shadercompiler/dxc-xbox-intrinsics)
* [XBOX HLSL 延伸](/zh-TW/tools/tools-console/shadercompiler/dxc-xbox-extensions)
* [XBOX 支援的著色器模型功能](#shader-model-support)

### 預先編譯

在 XBOX 上，DXC 編譯器可以將 HLSL 一路編譯為 XBOX GPU 的最終指令集架構 (ISA) 指令。這可讓遊戲避免在執行階段從 DXIL 編譯為 ISA 指令的昂貴步驟。我們將此完整編譯步驟稱為「預先編譯」，因為它會離線 (在開發電腦上) 而非線上 (在 XBOX 主機上) 將著色器編譯為 ISA。

有[多種定義](/zh-TW/tools/tools-console/shadercompiler/dxc-xbox-defines)可用於控制預先編譯。在 XBOX 上，基本上有 3 種編譯著色器的方式。

A. 離線預先編譯並移除 DXIL (/D\_\_XBOX\_STRIP\_DXIL=1)

```text theme={null}
+--------------+
| DXC (offline)|
+--------------+

HLSL -> DXIL  -> ISA
  |           |
  |           +
  +------> RootSig

+---------------+
| XBOX (runtime)|
+---------------+

ISA  -> Use ISA if valid, otherwise error
     ^
     |
     +
  RootSig
```

B. 離線預先編譯但不移除 DXIL (/D\_\_XBOX\_STRIP\_DXIL=0)

```text theme={null}
+--------------+
| DXC (offline)|
+--------------+

HLSL ->  DXIL -> DXIL+ISA
  |           |
  |           +
  +------> RootSig

+---------------+
| XBOX (runtime)|
+---------------+

DXIL+ISA -> Use ISA if valid, otherwise recompile from DXIL
         |
         +
       RootSig
```

C. 離線且不預先編譯 (/D\_\_XBOX\_DISABLE\_PRECOMPILE)

```text theme={null}
+--------------+
| DXC (offline)|
+--------------+

HLSL -> DXIL

+---------------+
| XBOX (runtime)|
+---------------+

DXIL  -> compile to ISA
      |
      +
    RootSig
```

在 PC 上您只有選項 C，但在 XBOX 上我們偏好選項 A，因為沒有執行階段負擔。PC 著色器編譯器針對即時 (JIT) 模式執行進行最佳化，因此可以快速編譯 DXIL -> ISA。在 XBOX 上，我們有一個較重量級的編譯器，因為我們預期大部分時間都是離線執行，可以花更長的時間來最佳化程式碼。

## 外部文件

您可以在 GitHub 上查看完整的原始碼，甚至參與新前端編譯器的開發：[DirectXShaderCompiler](https://github.com/Microsoft/DirectXShaderCompiler)。

高階著色器語言 (HLSL) 的一般文件可在 Microsoft Docs 上找到：[HLSL 參考](https://learn.microsoft.com/windows/desktop/direct3dhlsl/dx-graphics-hlsl-reference)。

新編譯器與更進階著色器模型的文件現已位於 GitHub 上：[DirectXShaderCompiler wiki](https://github.com/Microsoft/DirectXShaderCompiler/wiki)。

## XBOX 上的 DXC 與 Windows 上的 DXC 之間的差異

在 Windows 上，著色器會編譯為 DXIL，然後傳送至 GPU 驅動程式進行最終編譯。在 XBOX 上，由於目標 GPU 硬體是固定的，著色器預設會預先編譯，這讓我們可以在執行階段略過編譯階段。

<Note>
  若要在 XBOX 上編譯著色器，必須指定根簽章，讓編譯器能夠預先編譯著色器。如果著色器在執行階段與另一個根簽章搭配使用，就會發生執行階段編譯，這通常是不理想的。請注意，對於測試著色器或工具，您可以使用 `__XBOX_DISABLE_PRECOMPILE` 定義完全略過預先編譯，但不建議在一般執行階段使用。
</Note>

## XBOX 著色器模型功能支援

<a id="shader-model-support" />

從著色器模型 6.0 開始，XBOX 對選用的著色器模型功能提供逐項支援。如果未使用任何不受支援的選用功能，您可以在 XBOX 上將著色器編譯為以任何著色器模型為目標。

著色器模型功能的詳細資訊可在 [GitHub 上](https://github.com/microsoft/DirectXShaderCompiler/wiki/Shader-Model)找到。下表詳細說明 XBOX 上的著色器模型功能支援。

| ShaderModel | 功能 | XBOX One 系列 | XBOX Series 主機 |
| - | - | - | - |
| 6.0 | Wave Intrinsics | 部分 [\[1\]](#SM-1) | 是 |
| 6.0 | 64-Bit Integers | 是 | 是 |
| | | | |
| 6.1 | SV\_ViewID | 否 | 否 |
| 6.1 | SV\_Barycentrics | 自訂 [\[2\]](#SM-2) | 是 |
| | | | |
| 6.2 | 16-Bit Scalar Types | 否 | 是 |
| 6.2 | Denorm Mode | 否 | 否 |
| | | | |
| 6.3 | DirectX12 Raytracing (DXR) | 否 | 是 |
| | | | |
| 6.4 | Packed Dot Product Intrinsics | 否 | 是 |
| 6.4 | Variable Rate Shading | 否 | 是 |
| 6.4 | Library Sub-objects | 否 | 是 |
| | | | |
| 6.5 | DXR 1.1 | 否 | 否 [\[3\]](#SM-3) |
| 6.5 | Sampler Feedback | 否 | 是 |
| 6.5 | Mesh Shader | 否 | 是 |
| 6.5 | Amplification Shader | 否 | 是 |
| 6.5 | WaveMatch Intrinsics | 否 | 否 |
| 6.5 | WaveMultiPrefix Intrinsics | 否 | 否 |
| | | | |
| 6.6 | New Atomic Operations | 是 | 是 |
| 6.6 | Dynamic Resources | 是 | 是 |
| 6.6 | IsHelperLane Intrinsic | 是 | 是 |
| 6.6 | Derivative Operations in CS, MS, AS | 否 | 否 |
| 6.6 | Pack and Unpack Intrinsics | 否 | 否 |
| 6.6 | WaveSize | 否 | 否 |
| 6.6 | Raytracing Payload Access Qualifiers | 否 | 否 [\[4\]](#SM-4) |
| | | | |
| 6.7 | GatherRaw | 否 | 否 |
| 6.7 | SampleCmpLevel | 否 | 否 |
| 6.7 | Programmable Texture Offsets | 否 | 否 [\[5\]](#SM-5) |
| 6.7 | Writable MSAA Textures | 否 | 否 [\[6\]](#SM-6) |
| 6.7 | QuadAny/QuadAll | 否 | 否 |
| 6.7 | WaveOpsIncludeHelperLanes | 否 | 否 [\[7\]](#SM-7) |

<a id="SM-1">\[1]</a> 如需支援的內建函式與類型清單，請參閱 XBOX [Wave 內建函式](/zh-TW/tools/tools-console/shadercompiler/dxc-xbox-intrinsics)。

<a id="SM-2">\[2]</a> 對於 XBOX One 系列，我們無法依規格所規定的觸發頂點順序旋轉頂點來存取它們，因此會以硬體提供的順序傳回。這與現有 XBOX [重心座標內建函式](/zh-TW/tools/tools-console/shadercompiler/dxc-xbox-intrinsics)的行為相符。

<a id="SM-3">\[3]</a> 我們不支援 DXR 1.1 RayQuery 物件。不過，我們支援一種稱為內嵌周遊的 XBOX 特有技術，可用來取代 RayQuery 物件。

<a id="SM-4">\[4]</a> 在 XBOX 上會忽略承載存取限定詞。

在 XBOX Series X|S 上，著色器編譯器支援原生 16 位元類型，您可以使用編譯旗標 -enable-16bit-types 並將著色器模型版本設為 6.2 或更高來啟用。在 XBOX Series X|S 上，強烈建議盡可能使用原生 16 位元類型，而非最低精確度類型。在未來的版本中，將不再需要使用 -enable-16bit-types，因為原生 16 位元類型將預設啟用。

<a id="SM-5">\[5]</a> 如果嘗試使用可程式化位移，會產生 ISA，但產生的程式碼不正確，且無法如預期運作。

<a id="SM-6">\[6]</a> 此功能可透過 XB\_Store HLSL 內建函式取得

<a id="SM-7">\[7]</a> \[WaveOpsIncludeHelperLanes] 屬性可以編譯，但 XBOX 編譯器目前會忽略它。

## 已知問題

* 如果您使用自訂配置器 (DxcCreateInstance2)，在卸載 dxcompiler .dll 之前，不得釋放自訂配置器。
* 如果著色器已序列化，且 .pdb 名稱與雜湊字串不相符，PIX 就無法自動找到 .pdb。未來我們將在 PIX 中新增一個選項，可在 PIX .pdb 搜尋路徑中的所有 .pdb 中搜尋相符的雜湊，而不論 .pdb 名稱為何。
* DXIL 大小平均比 DXBC 大小更大。我們正在積極處理 DXIL 大小問題。
* 反映資料的大小將在未來的版本中大幅縮減。
* 使用 DXC 建立之著色器的 PIX HLSL 偵錯工具有許多問題。我們正在積極改善品質。
* \_\_XBOX\_ENABLE\_SIGNATURE\_PACKING 目前僅適用於頂點著色器與像素著色器階段。
* 我們正在積極改善編譯時間效能與執行階段效能。如果您有特定著色器的編譯時間過長，或未符合您對執行階段效能的預期，請透過 [AskHLSL@microsoft.com](mailto:AskHLSL@microsoft.com) 寄送電子郵件給我們，或在 XBOX 論壇上與我們聯絡。

## 了解 GPU 編譯器階段與術語

GPU 編譯器由「前端」與「後端」組成：前端會將 HLSL 剖析為中繼語言，再由「後端」編譯器使用，後端編譯器會進行低階、機器特定的最佳化，並產生 GPU 機器碼。

```text theme={null}
Front end -> Intermediate Language -> Back end 
```

我們舊的前端編譯器 (稱為 D3DCompiler 或 FXC) 與舊的中繼語言 (DXBC) 都已被以開放 Clang 與 LLVM 標準為基礎的新前端編譯器 (DXCompiler 或 DXC) 與新中繼語言 (DXIL) 取代。此外，在 XBOX 上，Microsoft 已從 "SC" 後端程式碼基底轉移至同樣以 LLVM 為基礎、名為 "NB" 的更新程式碼基底。隨著 GPU 程式碼的複雜度增加，我們需要轉移至更進階且更具彈性的技術。

新的編譯器流程：

```text theme={null}
DXC -> DXIL -> NB
```

<a id="NGGDocumentation" />

## XBOX 編譯器上的 NGG 實作 (僅限 Scarlett)

NGG (Next Generation Geometry) 會略過 IA 硬體階段，可大幅提高基本圖形輸送量。

控制 NGG 程式碼產生的其他旗標：

| 欄 1 | 欄 2 |
| - | - |
| \_\_XBOX\_PRECOMPILE\_NGG | 此旗標會為已啟用的輸出階段啟用 NGG 著色器的預先編譯。目前 VS 是唯一支援自動 NGG 的階段。請注意，網格著色器會直接以 NGG 為目標。也必須在 CreatePSO 上使用 D3D12XBOX\_PIPELINE\_STATE\_FLAG\_VS\_NGG，才能在驅動程式中啟用 NGG 著色器。 |
| \_\_XBOX\_NGG\_PASSTHROUGH | 啟用 \_\_XBOX\_PRECOMPILE\_NGG 旗標會自動插入剔除程式碼。您可以啟用「傳遞」著色器產生，在保留 NGG 功能的同時明確停用自動剔除。這對於已知不會剔除太多 (或錯失太多以著色器為基礎之剔除機會) 的大量頂點工作負載可能有有限的用途。 |

若要利用自動剔除，遊戲必須

1. 從 VS 匯出寫入所有四個元件的 `SV_Position` 值。
2. 將 `D3D12_GRAPHICS_PIPELINE_STATE_DESC` 中的 `D3D12_RASTERIZER_DESC.CullMode` 設為 `D3D12_CULL_MODE_NONE` 以外的值。

`D3D12_RASTERIZER_DESC.FrontCounterClockwise` 的值會在執行階段讀取，以判斷頂點環繞順序。目前會執行下列類型的剔除：

1. 背面剔除
2. 零面積三角形剔除
3. 檢視範圍剔除

以下是自動剔除函式的 HLSL 實作。

```cpp theme={null}
    bool CullTriangle(
        float4 posH_0, float4 posH_1, float4 posH_2,
        bool cullBackFace, bool backFaceOrderCW )
    {
        // Test that all points are in front of the camera. W is usually a linear distance in the forward axis. Negative W
        // values are problematic because they invert all the following tests. It's better to cull now and assume positive values.
        float maxW = max(max(posH_0.w, posH_1.w), posH_2.w);
        bool negativeWCull = maxW <= 0.0f;
        if (negativeWCull)
            return true;
        
        // If some of the W values are negative, the triangle straddles the W=0 plane creating an inversion. Let the triangle
        // clipper sort it out. It's not worth the ALU.
        float minW = min(min(posH_0.w, posH_1.w), posH_2.w);
        bool nearPlaneClip = minW <= 0.0f;
        if (nearPlaneClip)
            return false;
    
        // To be correct, we need to fix the order of the vertices provided, know which direction should be culled (or not)
        // and adjust the sign of the test appropriately. A zero determinant should always cull because it has zero-area.
        float discriminant = determinant(float3x3(posH_0.xyw, posH_1.xyw, posH_2.xyw));
        discriminant = backFaceOrderCW ? +discriminant : -discriminant;
        bool isBackFaceOrZeroArea = discriminant <= 0.0f;
        if (cullBackFace && isBackFaceOrZeroArea)
            return true;
        
        bool cullLeft   = (posH_0.x < -posH_0.w) && (posH_1.x < -posH_1.w) && (posH_2.x < -posH_2.w);
        bool cullRight  = (posH_0.x > +posH_0.w) && (posH_1.x > +posH_1.w) && (posH_2.x > +posH_2.w);
        bool cullBottom = (posH_0.y < -posH_0.w) && (posH_1.y < -posH_1.w) && (posH_2.y < -posH_2.w);
        bool cullTop    = (posH_0.y > +posH_0.w) && (posH_1.y > +posH_1.w) && (posH_2.y > +posH_2.w);
        
        if (cullLeft || cullRight || cullBottom || cullTop)
            return true;
    
        return false;
    }
```

### 啟用 NGG 的效益

雖然最終目標是預設啟用 NGG 剔除，但目前只有在少數 (一或多個) 已知情況下才有效益。這些情況包括：

* 硬體的瓶頸在於基本圖形處理 (每個時脈 4 個基本圖形)
* 繪製具有蛇形網格的高頂點/基本圖形數量 (以產生長串的背面頂點)，使得長串的頂點被剔除。
* 大量只對屬性有貢獻的記憶體存取
* 大量的屬性匯出

這一切都基於一項假設：被剔除的基本圖形數量足夠多，足以觸及上述任一情境。全螢幕繪製、世界幾何以及引擎中既有的剔除，都會降低此功能的價值。如果工作負載的瓶頸已經在於像素速率，NGG 剔除也不會帶來好處。

### 未來的改進

這是初始版本，將隨著時間改進。計劃中的改進包括

1. 調整執行緒群組大小。NGG 剔除需要配置 LDS。較大的執行緒群組大小會因 LDS 配置限制而限制已編譯著色器的佔用率。
2. 在整個執行緒群組都被剔除時啟用提前結束。
3. 非內插屬性的每個基本圖形匯出。
4. 新增啟發學習法，在能以靜態方式判斷無效益時關閉剔除。範例：
   1. 剔除前與剔除後著色器區段中的重複指令 (由於位置與屬性匯出之間的共用)。
   2. Position.Z 為 0——可能不會被剔除的平面 (2D) 三角形。
   3. 小型子群組略過。
   4. 其他次要最佳化。

我們也在考慮新增對使用者定義剔除函式的支援，讓編譯器在為 NGG 編譯時可以呼叫這些函式。

請試用並提供意見反應。

## 另請參閱

[XBOX 主機遊戲開發 (環境與工具)](/zh-TW/tools/tools-console/gc-tools-console-toc)


## Related topics

- [適用於 XBOX GDK 的 HLSL 著色器編譯器 (DXC)](/zh-TW/tools/tools-console/shadercompiler/index.md)
- [XBOX GDK 主機開發的 NDA 主題索引](/zh-TW/nda/nda-overview.md)
- [適用於 XBOX 的主機型命令列工具](/zh-TW/tools/tools-console/console_commandlinetools/index.md)
- [D3D_SHADER_MODEL](/zh-TW/reference/graphics/d3d12/enums/d3d_shader_model_public.md)
- [命令列工具](/zh-TW/tools/tools-console/commandlinetools/index.md)
