NVIDIA 很高興介紹下一代 GPU 中可用的新功能,稱為著色器執行重新排序( SER )。 SER 是一種性能優化,可以釋放光線跟蹤著色器中更好的光線和內存一致性的潛力,從而提高著色效率。
背景和概述
著色發散是光線跟蹤中的一個長期問題。隨著渲染器實現的日益復雜,越來越多的工作負載受到著色器執行而不是光線跟蹤的限制。緩解此問題的一種方法是在執行著色器代碼時減少影響 GPU 的發散。
SER 有助于緩解兩種類型的分歧:執行分歧和數據分歧。當不同的線程在一個著色器中執行不同的著色器或分支時,會發生 Execution divergence 。當不同的線程以難以緩存的模式訪問內存資源時,會發生 Data divergence 。
SER 通過動態地重新排序 GPU 上的線程來緩解分歧,以便它們能夠以更高的一致性繼續執行。它還支持光線相交和著色的解耦。
有關 SER 的更全面概述,請參閱 Shader Execution Reordering 白皮書。
使用 NVIDIA API 集成
先決條件
要訪問 SER 提供的功能集和優化,您需要以下各項:
- GPU 支持 DXR 1.0 或更高版本
- 支持 SER 、 R520 和更新版本的驅動程序
- HLSL 擴展頭,可在最新的 NVIDIA API 中找到
- 針對 nvapi64.lib 的鏈接,包含在包含上述標題的包中
- DXC / dx 編譯器的最新版本。支持模板的 dll (可選)。如果要從 Visual Studio 編譯著色器,請確保將項目配置為使用此版本的編譯器可執行文件。
Get started with SER and NVIDIA API .
初始化 NVAPI 并啟用 SER API
首先,使用以下調用初始化/取消初始化 NVAPI :
NvAPI_Initialize();
NvAPI_Unload();
接下來,使用以下調用驗證 SER API 是否受支持:
bool supported = false; NvAPI_D3D12_IsNvShaderExtnOpCodeSupported(pDevice, NV_EXTN_OP_HIT_OBJECT_REORDER_THREAD, &supported); if (!supported) { /* Don't use SER */ }
主機端集成
在創建光線跟蹤狀態對象之前,設置一個假 UAV 插槽并注冊它:
#define NV_SHADER_EXTN_SLOT 999999 // pick an arbitrary unused slot #define NV_SHADER_EXTN_REGISTER_SPACE 999999 // pick an arbitrary unused space NvAPI_D3D12_SetNvShaderExtnSlotSpace(pDevice, NV_SHADER_EXTN_SLOT, NV_SHADER_EXTN_REGISTER_SPACE);
如果需要線程本地變量,請使用相關函數:NvAPI_D3D12_SetNvShaderExtnSlotSpaceLocalThread
。
接下來,將偽 UAV 插槽添加到用于編譯光線跟蹤管道的全局根簽名中。您不需要為此分配和/或綁定資源。下面是一個用粗體表示的假 UAV 插槽擴充 D3D12 示例代碼的示例。應用程序中的根簽名創建看起來可能會有很大不同。
// Global Root Signature // This is a root signature that is shared across all raytracing shaders invoked during a DispatchRays() call. { CD3DX12_DESCRIPTOR_RANGE ranges[5]; // Perfomance TIP: Order from most frequent to least frequent. ranges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_UAV, 1, 0); // output texture ranges[1].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 2, 0, 1); // static index buffers ranges[2].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 2, 0, 2); // static vertex buffers ranges[3].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0, 3); // static vertex buffers // fake UAV for shader execution reordering ranges[4].Init(D3D12_DESCRIPTOR_RANGE_TYPE_UAV, 1, NV_SHADER_EXTN_SLOT, NV_SHADER_EXTN_REGISTER_SPACE); CD3DX12_ROOT_PARAMETER rootParameters[GlobalRootSignatureParams::Count]; rootParameters[GlobalRootSignatureParams::OutputViewSlot].InitAsDescriptorTable(1, &ranges[0]); rootParameters[GlobalRootSignatureParams::AccelerationStructureSlot].InitAsShaderResourceView(0); rootParameters[GlobalRootSignatureParams::SceneConstantSlot].InitAsConstantBufferView(0); rootParameters[GlobalRootSignatureParams::VertexBuffersSlot].InitAsDescriptorTable(3, &ranges[1]); rootParameters[GlobalRootSignatureParams::SerUavSlot].InitAsDescriptorTable(1, &ranges[4]); CD3DX12_ROOT_SIGNATURE_DESC globalRootSignatureDesc(ARRAYSIZE(rootParameters), rootParameters); SerializeAndCreateRaytracingRootSignature(globalRootSignatureDesc, &m_raytracingGlobalRootSignature); }
在著色器代碼中使用 API
在著色器代碼中,使用相同的值定義假 UAV 插槽并再次注冊:
#define NV_SHADER_EXTN_SLOT u999999 // matches slot number in NvAPI_D3D12_SetNvShaderExtnSlotSpace #define NV_SHADER_EXTN_REGISTER_SPACE space999999 // matches space number in NvAPI_D3D12_SetNvShaderExtnSlotSpace #include "SER/nvHLSLExtns.h"
現在, SER API 可用于光線生成著色器:
NvHitObject hitObject = NvTraceRayHitObject(TLAS, RAY_FLAG_NONE, 0xff, 0, 1, 0, ray, payload); NvReorderThread(hitObject, 0, 0); NvInvokeHitObject(TLAS, hitObject, payload);
將 HLSL 編譯為 DXIL 時,請執行以下操作之一:
1 ) 通過指定命令行參數-HV 2021
,確保在 DXC 中啟用模板
或
2 ) 使用不需要模板的 API 宏版本。可以通過在#包括nvHLSLExtns.h
之前#定義NV_HITOBJECT_USE_MACRO_API
來啟用宏版本。這適用于難以切換到 HLSL 2021 的傳統代碼庫。如果代碼庫可以支持,建議使用模板。
Unreal Engine 5 Nv RTX 的集成
虛幻引擎開發人員可以利用虛幻引擎( NvRTX ) NVIDIA 分支中的 SER 。以下部分介紹 SER 如何在光線跟蹤操作中提供性能提升,并提供針對特定用例的優化提示。
NVIDIA Unreal Engine 5 Nv RTX 5.0.3 版本將采用 SER 集成,以支持優化其許多光線跟蹤路徑。有了 SER , Nv RTX 開發人員將在 40 系列卡上看到額外的幀速率優化,光線跟蹤操作速度提高 40% ,對質量或內容創作的影響為零。這提高了復雜光線跟蹤計算的效率,并將在充分利用光線跟蹤功能的場景中提供更大的增益。
SER 在 Unreal Engine 5 中的優勢
Unreal Engine 5 ( UE5 )中的 SER 可以實現更好的脫機路徑跟蹤,可以說是 UE5 中最復雜的跟蹤操作。同樣,硬件光線跟蹤反射和半透明(與材質和照明有復雜的交互作用)也將受益。
啟用硬件光線跟蹤時, SER 還可以提高流明性能。在某些情況下,實現這一點所需的更改(與初始系統復雜性無關)是微不足道的。在其他情況下,它增加了實質性的復雜性。下面將更詳細地探討三個不同的示例。
簡單案例:路徑跟蹤
路徑跟蹤提供了一個高度分散的工作流,使其成為應用 SER 的一個很好的候選者。

應用 SER 可以減少路徑跟蹤器在材料評估中的分歧,而不僅僅是反彈次數。通過以下代碼更改,性能提高了 20-50% :
#if !PATH_TRACER_USE_REORDERING // Trace the ray, including evaluation of hit data TraceRay( TLAS, RayFlags, RAY_TRACING_MASK_ALL, RAY_TRACING_SHADER_SLOT_MATERIAL, RAY_TRACING_NUM_SHADER_SLOTS, MissShaderIndex, PathState.Ray, PackedPayload); #else { NvHitObject Hit; // Trace ray to produce hit object NvTraceRayHitObject(TLAS, RayFlags, RAY_TRACING_MASK_ALL, RAY_TRACING_SHADER_SLOT_MATERIAL, RAY_TRACING_NUM_SHADER_SLOTS, MissShaderIndex, PathState.Ray, PackedPayload, Hit); // Reorder threads to have coherent hit evaluation NvReorderThread(Hit); // Evaluate hit data in the now coherent environment NvInvokeHitObject(TLAS, Hit, PackedPayload); } #endif
可以通過將 DXR TraceRay
函數替換為等效的NvTraceRayHitObject
、NvReorderThread
和[EZX29]集來實現此改進。一個關鍵的方面是,優化只是選擇性地應用。此更改僅適用于 UE5 路徑跟蹤代碼中的TraceTransparentRay
函數,因為這是大多數實質性評估分歧的根源。其他射線的操作成本較低,重新訂購的重要性較低,因此它們可能不值得嘗試重新訂購的額外成本。
當談到路徑跟蹤代碼的潛力時,這個例子只是冰山一角。更仔細的分析幾乎肯定會帶來額外的收益,包括可能消除使用多次通過壓縮更長光線的需要。
不同尋常的情況:流明全局照明中的工作壓縮
通常,人們會考慮重新排序,以處理點擊著色所經歷的執行分歧。雖然流明全局照明中使用的光線跟蹤過程不會運行發散命中著色器,但它們仍然受益于 SER 提供的機制。
對于大型場景,如 UE5 City Sample ,軌跡被分割到近場和遠場,作為單獨的跟蹤過程運行,并在其間進行壓縮。多次傳遞和壓縮可以由單個NVReorderThread
調用代替。這避免了 GPU 上的閑置氣泡,這些氣泡用于壓縮近場跟蹤結果,然后發射遠場射線。

消除存儲、壓縮和重新啟動工作的額外開銷通常值得節省 20% 。由于原始代碼中的假設(使用宏而不是參數排列行為的函數),著色器更改可能會更加密集。然而,邏輯更改相當于添加了兩個重新排序調用,用一個布爾表達式表示跟蹤是否命中。
復雜情況:流明反射
流明是 UE5 中包含的一個系統,用于實現全局照明和反射。它具有高度的復雜性,對它的深入討論遠遠超出了本文的范圍。下面的描述經過了嚴格的提煉,重點介紹了一種特定的配置:啟用硬件光線跟蹤( HWRT )命中照明的流明反射。請注意, Lumen 還可以通過帶符號的距離場利用軟件光線跟蹤,這將在這里不再討論。
要渲染反射, Lumen HWRT 命中照明路徑使用多個過程:
- 近場追蹤 – 提取材料 ID
- 緊湊型光線
- 遠場跟蹤(可選) – 提取材料 ID
- 緊湊型光線
- 附加遠場射線(可選)
- 按材質對光線排序
- 使用命中照明重新跟蹤
此外,以下關于流明工作原理的重要細節有助于解釋 SER 和非 SER 方法的差異。
- 內腔中的近場和遠場分別對應于 TLAS 中靠近相機的物體和遠離相機的物體的不同部分。近場和遠場都包含在同一 TLAS 中。
- 在上述過程中使用了兩條不同的光線跟蹤管道。近場和遠場都使用簡化的(快速)跟蹤路徑,而命中照明具有完全的材質支持。這就是使用命中照明單獨重新跟蹤路徑的原因。
有關這些焊道的更多技術細節,請參見 Lumen Technical Details 。啟用 SER 后,可以組合傳遞,因為不再需要單獨的壓縮和排序階段。該過程大致成為軌跡近場,如果不是命中軌跡遠場,如果其中一個命中,則使用命中對象評估材質并執行照明。由于跟蹤和著色的解耦,這是可能的。
著色器的相關部分如下所示:
NvHitObject SERHitObject; // Near field NvTraceRayHitObject(..., SERHitObject); NvReorderThread(SERHitObject); Result.bIsHit = SERHitObject.IsHit(); // Far field if (!Result.bIsHit) { // Transform ray into far field space of TLAS ... NvTraceRayHitObject(..., SERHitObject); NvReorderThread(SERHitObject); Result.bIsHit = SERHitObject.IsHit(); } // Compute result if (Result.bIsHit) { NvInvokeHitObject(Context.TLAS, SERHitObject, Payload); Result.Radiance = CalculateRayTracedLighting(); } // Handle miss
這是 SER 可用性的一個例子,它對渲染體系結構產生了更高層次的影響,而不僅僅是用相應的 NVAPI 等效物替換 TraceRay 。上述實施導致 GPU 上流明反射速度增加 20-30% ,這是在 UE5 城市樣本中分析典型工作負載時測得的。
結論
在同時考慮數據和執行時,著色差異可能會帶來性能問題。 Shader Execution Reordering API 為開發人員提供了一個功能強大的工具來減輕這些懲罰,只需相對較少的工作即可開始。上面討論的優化只是將 SER 提供的可能性引入大型代碼庫(如 Unreal Engine 5 )的初始階段。我們期待看到 SER 隨著使用的發展發揮出更多的潛力。
其他資源
Read the Shader Execution Reordering whitepaper
Access the NVIDIA RTX Branch of Unreal Engine
Ask a question on the NVIDIA Developer Forum
?