AMD Radeon™ GPU Analyzer
Radeon GPU Analyzer 是一款用于 DirectX®、Vulkan®、SPIR-V™、OpenGL® 和 OpenCL™ 的离线编译器和性能分析工具。
Radeon™ GPU Analyzer (RGA) 2.2 在命令行工具的新模式 (-s dx12) 中引入了对 DirectX®12 计算着色器的支持。您可以使用这种新模式为计算着色器生成 GCN/RDNA ISA 反汇编,而无需考虑实际安装的 GPU。例如,您可以为 Navi 系列的 AMD Radeon™ RX 5700 目标 (gfx1010) 编译着色器,即使您的机器未安装 Navi 级显卡。此外,您还可以使用新模式获取计算着色器的硬件资源使用统计信息,例如 VGPR/SGPR 消耗和 LDS 使用量,并生成实时寄存器分析报告或控制流图。
与之前的 HLSL 模式(在 RGA 2.2 中已重命名为 –s dx11)相比,新模式的一个巨大优势在于它使用实时驱动程序来利用着色器在实际场景中经历的相同编译路径。这为您提供了最接近实际情况的结果,从而您可以做出更好的优化决策。
新模式需要最新的 AMD Adrenalin 驱动程序。
在开始使用示例之前,我们先了解一下 Direct3D® 12 的 RGA 如何工作。有两种用例:以 HLSL 作为输入,或以 DXIL/DXBC 块作为输入。在此模式下,为了为您提供最接近实际情况的结果,RGA 不会编译独立的计算着色器,而是编译计算管线。因此,您必须将有效的根签名与着色器一起传递,编译才能成功。让我们来分析这两种用例。
以 HLSL 作为输入
下图显示了 DX12 模式下 HLSL 文件的编译过程:
如果着色器模型为 5.1 或更高版本,RGA 会将 HLSL 代码通过 DXC 作为前端编译器进行传递,并在创建的管线中使用生成的 DXIL 二进制文件。如果着色器模型为 5.0 或更低版本,RGA 会使用运行时 (D3DCompiler*.dll) 将 HLSL 编译为 DXBC,并在管线中使用生成的 DXBC。当使用 HLSL 源代码作为输入时,您可以通过 3 种不同的方式将根签名提供给 RGA:
.hlsl 文件中的 [RootSignature] 属性
Shader Model 5.1 允许您在 HLSL 源代码的宏定义中定义根签名,并通过 [RootSignature] 属性从着色器中引用它。示例如下:
#define _RootSig \"RootFlags(0), " \"CBV(b0), " \"DescriptorTable(SRV(t0, numDescriptors = 2))," \"DescriptorTable(UAV(u0, numDescriptors = 2))"
[RootSignature(_RootSig)]void main(...)如果您使用此方法,RGA 可以自动检测根签名并将其与着色器一起编译。
相同 .hlsl 文件或包含文件中的宏定义(使用:–rs-macro)
另一种选择是在定义着色器的 .hlsl 文件(或单独的包含 .hlsl 文件)内的宏中定义根签名,而不使用 [RootSignature] 属性进行引用。例如,假设我们有与上面第一个要点相同的代码,但没有 [RootSignature(_RootSig)] 属性:
#define _RootSig \"RootFlags(0), " \"CBV(b0), " \"DescriptorTable(SRV(t0, numDescriptors = 2))," \"DescriptorTable(UAV(u0, numDescriptors = 2))"
void main(...)在这种情况下,您可以通过 **–rs-macro** 命令行选项将宏的名称传递给工具。然后,RGA 将执行两遍前端编译:首先编译根签名,然后编译着色器。
说明
预编译的二进制根签名(使用:–rs-bin)
如果您的根签名位于预编译的二进制文件中,请使用 **–rs-bin** 命令行开关,并将指向该二进制文件的完整路径作为参数。请注意,您可以使用 D3DGetBlobPart() 函数(传递 D3D_BLOB_ROOT_SIGNATURE 作为 blob 部分)从运行时编译的 blob 中提取根签名,或者使用 FXC 从编译的 DXBC blob 中提取根签名。
以 DXIL 或 DXBC 块作为输入
如果根签名已预编译到 blob 中,则不需要额外参数——RGA 将使用 blob 中的根签名。否则,您应使用 –rs-bin 提供已编译的根签名。
在接下来的示例中,我们将使用 Microsoft® DirectX Graphics Samples 中的 D3D12RaytracingMiniEngineSample 示例。假设我们要编译 FillLightGridCS_8.hlsl,并且为简化起见,该 .hlsl 文件和此示例的其余着色器位于我们系统上的 C:\sample 目录下。
以下命令将编译着色器并为最新支持的目标 GPU 生成反汇编
rga.exe -s dx12 —cs C:\sample\FillLightGridCS_8.hlsl —cs-entry main —cs-model cs_5_1 —isa C:\sample\disassembly.txt
让我们分解一下这个命令
请注意,我们没有明确提供根签名,但它仍然编译成功。这是因为该示例在 HLSL 代码中包含了一个根签名,并且为着色器提供了 [RootSignature()] 属性。
#define _RootSig \ "RootFlags(0), " \ "CBV(b0), " \ "DescriptorTable(SRV(t0, numDescriptors = 2))," \ "DescriptorTable(UAV(u0, numDescriptors = 2))"
[RootSignature(_RootSig)][numthreads(WORK_GROUP_SIZE_X, WORK_GROUP_SIZE_Y, WORK_GROUP_SIZE_Z)]void main(…)因此,这属于上面“用法”部分的 1.1 节,并且编译成功,生成以下构建日志:
Performing front-end compilation through DXC... front-end compilation success.Compiling compute pipeline...Extracting compute shader disassembly...Compute shader disassembly extracted successfully.Succeeded.请注意,我们使用的是 Shader Model 5.1,因此 DXC 用于执行前端编译,正如您在构建日志中看到的。如果我们已将 –cs-model 的参数从 cs_5_1 更改为 cs_5_0,您会观察到不再使用 DXC,而是使用运行时编译器(正如您在本篇文章开头图表中看到的)。
现在,我们来修改一下示例,并注释掉 [RootSignature(_RootSig)] 属性
//[RootSignature(_RootSig)][numthreads(WORK_GROUP_SIZE_X, WORK_GROUP_SIZE_Y, WORK_GROUP_SIZE_Z)]void main(...)这模拟了一个根签名定义在 HLSL 源代码中(或包含的 HLSL 文件中),但未使用 [RootSignature()] 属性引用的场景。在这种情况下,尝试使用相同命令编译修改后的着色器将会失败,因为编译器未被指示使用 _RootSig 宏作为我们着色器的根签名。要解决这个问题,我们会在命令中添加 **–rs-macro** 开关,并将 _RootSig 作为其参数
rga.exe -s dx12 —cs C:\sample\FillLightGridCS_8.hlsl —cs-entry main —cs-model cs_5_1 —rs-macro _RootSig —isa C:\sample\disassembly.txt
现在,我们属于上面 1.2 节的情况,RGA 执行两遍编译,先编译根签名,然后编译计算管线,编译成功。
最后,假设 _RootSig 宏也从文件中移除,并且根签名已预编译到一个名为 RootSig.rs.fxo 的二进制文件中(这在生产环境中是最常见的情况,因为从性能角度来看,预编译根签名是最佳实践)。要编译着色器,我们将修改命令,包含 **–rs-bin** 开关,并将 RootSig.rs.fxo 的完整路径作为参数
rga.exe -s dx12 —cs C:\sample\FillLightGridCS_8.hlsl —cs-entry main —cs-model cs_5_1 —rs-bin C:\Samples\RootSig.rs.fxo —isa C:\sample\disassembly.txt
现在,我们属于 1.3 节的情况,根签名取自预编译的文件,编译成功。
此处使用的代码样本来自 Microsoft® 的 DirectX Graphics Samples,版权归 Microsoft 2015 所有,并受 MIT 许可证约束。