AMD Radeon™ GPU Analyzer
Radeon GPU Analyzer 是一款用于 DirectX®、Vulkan®、SPIR-V™、OpenGL® 和 OpenCL™ 的离线编译器和性能分析工具。
Radeon GPU Analyzer (RGA) 2.2 在其命令行工具的新模式 (-s dx12) 中增加了对 Direct3D 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] 属性
着色器模型 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 块作为输入
如果根签名已预编译到块中,则无需其他参数——RGA 将使用块中的根签名。否则,您应该使用 –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 许可证约束。