Shader 调试前提条件
Debug 信息要求
RenderDoc 的 Shader 调试依赖 Shader 反射信息(Reflection Info)和可选的源码级 Debug 信息。反射信息通常默认随 Shader 编译产物一同存在,除非在编译或打包流程中被显式裁剪掉。源码级 Debug 信息(变量名、局部变量映射、函数调用栈等)则通常不会默认内嵌,需要手动启用。
D3D11 / D3D12
- 编译时向
fxc传递/Zi标志,或向D3DCompile()传递D3DCOMPILE_DEBUG标志,可将 Debug 信息嵌入 Shader blob。 - 避免使用
/Qstrip_debug和/Qstrip_reflection,这两个选项会裁掉 Constant Buffer 变量名等对调试有用的反射信息。 - 建议同时使用
/Od(或D3DCOMPILE_SKIP_OPTIMIZATION)禁用优化,这样可自动启用 HLSL 源码级调试。 - D3D12 支持通过
/Fd将 Debug 信息分离到独立文件,RenderDoc 完整支持该方式;详见”Shader Debug Info 配置”章节。 - Callstack 和局部变量映射信息需要 Windows 8.0 及之后版本的
fxc(对应D3DCompiler_47.dll)。
Vulkan
- RenderDoc 通过
NonSemantic.Shader.DebugInfo.100扩展指令集实现源码级调试。 - 使用
glslang时加-gVS选项生成 Debug 信息;使用dxc时加-fspv-debug=vulkan-with-source。两者都会将必要的 Debug 信息嵌入 SPIR-V blob。
OpenGL
- OpenGL 不存在独立的 Debug 信息,RenderDoc 直接使用上传到 API 的 GLSL 源码。若源码已被裁剪或混淆,需在应用层自行处理。
API 支持情况
Shader 调试目前仅支持以下 API:
| API | 支持状态 |
|---|---|
| D3D11 | 支持 |
| D3D12 | 支持 |
| Vulkan | 支持 |
| OpenGL | 不支持调试,仅显示源码 |
| 其他 API | 不支持,相关选项隐藏或禁用 |
部分 Shader 即使在支持的 API 上也无法调试,例如使用了不受支持的 Vulkan 扩展时,相关调试选项同样会被禁用。
启动 Shader 调试器
从 Pipeline State 面板发起
在 Pipeline State 面板中找到需要调试的 Shader Stage(例如 Vertex Shader、Pixel Shader),点击该 Stage 旁边的调试入口,即可进入 Shader 调试器。
调试 Vertex Shader
- 打开 Mesh Viewer。
- 在 Vertex Input 的 Mesh 数据中选中目标顶点,该顶点及其所属图元会在 Mesh 显示中高亮(需处于 vertex input 模式)。
- 右键点击,选择 “Debug Vertex”。
- 调试器打开后,Vertex Shader 的输入数据已从 Mesh 数据自动填充。
注意:Geometry Shader 和 Tessellation Shader 暂不支持调试。
调试 Pixel Shader
- 在 Texture Viewer 中选中目标像素(详见像素检视文档)。
- 在像素上下文区域点击 History 按钮,打开 Pixel History 窗口,查看对该像素的所有修改记录。
- 在 Pixel History 窗口中选择要调试的图元,发起调试;Pixel Shader 的输入数据将自动填充。
- 若当前选中的 DrawCall 没有写入目标像素,Pixel History 窗口会自动打开供选择;若同一像素被多次绘制(overdraw),默认调试最后一个通过深度测试的 Fragment,可在 Pixel History 中指定特定的 Fragment。
调试 Compute Shader
在 Pipeline State 中的 Compute Shader 区域,输入目标线程的 Group ID 和 Thread ID,即可单独调试该线程。调试时该线程以完全隔离的方式运行,不与其他线程同步。
注意:此功能处于高度实验性阶段,仅对简单 Compute Shader 有效,不提供稳定性保证。
逐步调试操作
Step Into / Step Over
Shader 调试器提供基本的步进控制,界面顶部工具栏包含以下操作:
| 操作 | 快捷键 | 说明 |
|---|---|---|
| Run Forward | F5 | 从当前位置运行到程序末尾 |
| Run Backward | Shift+F5 | 从当前位置反向运行到程序起始 |
| Step Forward | F10 | 执行当前指令并跳到下一条,遵循流控制(跳转、循环等) |
| Step Backward | Shift+F10 | 跳回到产生当前指令的上一条指令(非简单上一行,可能是跳转源) |
| Run to Cursor | Ctrl+F10 | 运行到光标所在行后暂停,或运行到 Shader 结束 |
| Run to Sample | - | 运行到下一次纹理 load / gather / sample 操作 |
| Run to NaN/Inf | - | 运行到下一个产生 NaN 或 Infinity 的操作 |
当前高亮的指令表示下一条将要执行的指令,而非刚刚执行完的指令。
在 HLSL 源码调试模式下,步进操作可能一次跨越多条汇编指令。
断点
按 F9 可在当前行设置或删除断点。在 Run / Run to Cursor 等运行模式下,执行到断点时会自动暂停。
变量监视
调试器提供三种变量视图:
Constants 窗口
显示在整个 Shader 执行过程中不可变的寄存器,包括:
- 输入寄存器(Vertex 属性、插值输入等)
- Constant Buffer 寄存器
- 资源和采样器寄存器(含基本格式信息)
Registers 窗口
显示可变寄存器,包括:
- Temporary 寄存器(随执行步进而更新)
- Output 寄存器
寄存器默认以 float 解释,工具栏提供切换按钮可将其解释为 int。
Watch 窗口
支持自定义监视表达式,可输入涉及输入、Temporary 或 Output 寄存器的任意表达式,并配合 Swizzle 和类型转换:
- Swizzle 语法遵循 HLSL/GLSL 规则:
.[xyzw]或.[rgba]的任意组合与重复。 - 类型转换后缀:
,u(无符号整数)、,i(有符号整数)、,f(浮点)、,x(十六进制)、,o(八进制)、,b(二进制)、,c(颜色,显示 RGB 色块)。 - 存在 Debug 信息时,还可在 Watch 窗口中引用局部变量名。
将鼠标悬停在反汇编或视图窗口中的寄存器上,会弹出 Tooltip 显示多种格式的值解释。
HLSL Callstack 与 Locals
当 HLSL Debug 信息可用时,Callstack 窗口显示当前指令的函数调用栈,Locals 窗口显示当前作用域内所有局部变量的名称和值。
Shader 编辑与热替换(Edit Shader)
场景 Shader 热替换
RenderDoc 允许在不重新采集帧的情况下,直接编辑 Capture 中使用的 Shader 并实时查看效果。
操作步骤:
- 在 Pipeline State 面板中找到目标 Shader Stage。
- 点击该 Stage 旁边的编辑按钮(铅笔图标)。
- 若存在多个编辑选项,会弹出下拉菜单(由 Shader 处理工具决定,见下文)。
- 编辑窗口打开后,在编辑器中修改 Shader 源码。
- 点击工具栏中的 “Apply changes” 按钮或按
F5编译并应用修改。 - 编译警告和错误会显示在主编辑区下方的 Errors 面板中。
注意事项:
- 修改会影响所有使用该 Shader 的 DrawCall,不限于当前选中的 DrawCall。
- 修改在编辑窗口关闭之前一直生效。
- 若编译出错,Shader 自动回退到 Capture 中原始的 Shader,直到错误被修复。
Shader 处理工具(Shader Processing Tools)
各图形 API 有其原生 Shader 格式:
- D3D11 / D3D12:DXBC 字节码(D3D12 还支持 DXIL)
- Vulkan:SPIR-V 字节码
- OpenGL:GLSL 源码文本
字节码格式的 Shader 可能内嵌了原始源码的 Debug 信息。
编辑 Shader 时,RenderDoc 优先显示原始源码(如果可用),否则会尝试调用已配置的 Shader 处理工具(反编译器)将字节码转换为可编辑的形式。多个处理工具可在设置窗口中配置,RenderDoc 默认内置了若干 SPIR-V 处理工具。若无可用工具,RenderDoc 会生成存根代码或默认的反汇编作为起点。
每个处理工具的输入/输出格式明确定义,例如:编译器可接受 HLSL 并输出 DXBC,反编译器可接受 SPIR-V 并输出 HLSL。
自定义可视化 Shader
自定义可视化 Shader 存储为文件(Windows:%APPDATA%/qrenderdoc/,其他平台:~/.local/share/qrenderdoc)。在 RenderDoc 内点击编辑按钮会打开内置编辑器,保存后实时生效。也可用外部编辑器直接编辑文件,RenderDoc 会自动重新加载,但外部编辑时无法看到编译警告或错误。
Shader Debug Info 配置
嵌入式 Debug 信息
若 Debug 信息已内嵌在 Shader blob 中(未被裁剪),RenderDoc 会自动找到并使用,无需额外配置。若使用编译器提供的机制(如 D3D12 的 /Fd)生成了独立的 Debug 信息文件,只需在 RenderDoc 设置中指定搜索路径,同样无需手动关联。
分离式 Debug 信息搜索路径
当 Debug 信息被手动分离时,需在 RenderDoc 设置窗口的 Core 类别下配置搜索目录。RenderDoc 会按列表顺序搜索各目录。
路径匹配规则:
- 绝对路径:直接使用,每次均按该路径查找。
- 相对路径:在配置的搜索目录中逐一匹配。若全部目录均未命中,则移除路径的第一段子目录后重试,以支持绝对路径与搜索目录的尾部子路径匹配。
SPIR-V Debug 信息(Vulkan)
通过 NonSemantic.Shader.DebugInfo.100 扩展指令集将 Debug 信息嵌入 SPIR-V:
# glslang
glslang -gVS input.vert -o output.spv
# dxc
dxc -fspv-debug=vulkan-with-source input.hlsl -spirv -o output.spvDXBC / DXIL Debug 信息(D3D11 / D3D12)
嵌入方式(D3D11 / D3D12):
# fxc
fxc /Zi /Od shader.hlsl /T vs_5_0 /E main /Fo shader.dxbc
# dxc (D3D12 DXIL)
dxc -Zi -Od shader.hlsl -T vs_6_0 -E main -Fo shader.dxil分离方式(D3D12,使用 /Fd):
# 指定文件路径:绝对路径存入 blob
fxc /Zi /Fd path/to/debug.pdb shader.hlsl /T vs_5_0 /E main /Fo shader.dxbc
# 指定目录:以 hash 命名存入该目录,blob 中记录相对路径
fxc /Zi /Fd debug_dir\ shader.hlsl /T vs_5_0 /E main /Fo shader.dxbc运行时指定路径(D3D11 API):
std::string pathName = "path/to/saved/blob.dxbc"; // UTF-8 编码
ID3D11VertexShader *shader = ...;
GUID RENDERDOC_ShaderDebugMagicValue = RENDERDOC_ShaderDebugMagicValue_struct;
shader->SetPrivateData(RENDERDOC_ShaderDebugMagicValue,
(UINT)pathName.length(), pathName.c_str());运行时指定路径(Vulkan API):
std::string pathName = "path/to/saved/blob.spv"; // UTF-8 编码
VkShaderModule shaderModule = ...;
VkDebugUtilsObjectTagInfoEXT tagInfo = {VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_TAG_INFO_EXT};
tagInfo.objectType = VK_OBJECT_TYPE_SHADER_MODULE;
tagInfo.objectHandle = (uint64_t)shaderModule;
tagInfo.tagName = RENDERDOC_ShaderDebugMagicValue_truncated;
tagInfo.pTag = pathName.c_str();
tagInfo.tagSize = pathName.length();
vkSetDebugUtilsObjectTagEXT(device, &tagInfo);注意:分离式 Debug 信息不包含在 Capture 文件中,若文件被移动或删除,RenderDoc 将无法找到,Capture 只能展示无 Debug 信息时的有限内容。
SPIR-V 反汇编查看
在 Vulkan 管线中,RenderDoc 可直接显示 SPIR-V 的反汇编文本。在 Pipeline State 面板中选中 Shader Stage 后,若无源码级 Debug 信息可用,调试器和编辑器均会展示 SPIR-V 反汇编作为默认视图。
在调试器中切换汇编与源码视图
当 HLSL Debug 信息可用时,调试器工具栏会出现 “Debug in HLSL” 按钮;反之在源码调试模式下会出现 “Debug in Assembly” 按钮。也可以通过右键菜单选择 “Go to Disassembly” 或 “Go to Source” 在两种视图之间切换。
源码级调试与汇编级调试使用相同的控制操作(断点、单步、运行等)。
使用 Shader 处理工具反编译 SPIR-V
RenderDoc 默认内置了若干 SPIR-V 处理工具,可将 SPIR-V 字节码反编译为 GLSL 或 HLSL 等可读格式。这些工具在设置窗口中配置,编辑 Vulkan Shader 时 RenderDoc 会自动选择最合适的工具进行处理。
若没有可用工具,RenderDoc 会直接显示 SPIR-V 反汇编文本或生成存根代码作为编辑起点。