[图形渲染]讲透RenderTarget 第十三章:调试与诊断
第十三章调试与诊断一句话概括当画面不对第一步就是逐张检查 RT——哪张出了问题效果就在哪步崩了。生活类比流水线质检——逐道工序检查半成品找到第一个出问题的环节。⏱ 30 秒概览RT 出问题 画面出问题。诊断核心流程抓帧 → 逐 Pass 检查每张 RT 的内容 → 定位第一张异常 RT → 问题在生成它的 Pass 中。工具箱RenderDoc通用首选、PIXDX12 深度分析、NsightNVIDIA 性能、Xcode GPU DebuggerMetal、Unity Frame Debugger / Unreal GPU Visualizer引擎内快速排查。五大常见异常① 全黑——绑定错误 / Clear 顺序 / Barrier 遗漏 / Viewport 为 0② 闪烁——双缓冲 RT 混用 / 帧间同步缺失 / TAA History 被回收③ 颜色错——sRGB vs Linear 搞混 / 通道顺序 RGBA↔BGRA / 精度不足 / 缺 ToneMapping④ 上下翻转——OpenGL vs DX 的 UV 原点差异⑤ 黑边拉伸——Viewport 与 RT 尺寸不匹配 / RTHandle Scale 未传入 Shader。通用方法论二分法定位 替换法隔离 单通道可视化。13.1 工具箱调试 RT 问题最有效的方式是抓帧——冻结 GPU 一帧的所有操作逐个 Draw Call 查看每张 RT 在每个时刻的内容。RenderDoc跨平台、开源、免费。最常用的帧调试工具。核心功能Texture Viewer查看任意一张 RT 在任意时刻的内容Pipeline State查看当前绑定的 RT 列表、格式、分辨率Resource Inspector查看 RT 的创建参数、显存占用Event Browser按时间线浏览所有 Draw Call 和 DispatchRT 诊断工作流1. 抓帧 2. 找到输出异常的最终 RT 3. 沿 Event Timeline 往前追溯 4. 逐步检查每个 Pass 的输入和输出 RT 5. 找到第一张不对的 RT → 问题就在生成这张 RT 的 Pass 中PIXWindows / Xbox微软官方工具对 DX12 支持最好。特色功能GPU Capture比 RenderDoc 更精确的性能数据Timing Capture每个 Pass 的 GPU 时间Resource Barrier 可视化直观看到 RT 状态转换流Occupancy 分析Shader 的 wave 利用率Xcode GPU DebuggermacOS / iOSApple 平台唯一选择。特色功能Metal Shader Profiler逐行 Shader 性能Memory Viewer精确的 RT 显存占用和压缩状态Dependency Graph自动生成 Pass 之间的 RT 依赖图Nsight GraphicsNVIDIANVIDIA 官方工具支持 DX11/12、OpenGL、Vulkan。特色功能Range Profiler对一组 Draw Call 做性能分析Shader Profiler热点 Shader 的逐行耗时Ray Tracing 调试可视化 BVH、RT 输出Android GPU InspectorAGIGoogle 官方的 GPU 调试工具支持 Vulkan 和 OpenGL ES。特色功能Frame Profiler类似 RenderDoc 的帧捕获和逐 Pass 检查System ProfilerGPU 频率、利用率、带宽的全局时间线Render Stage 分析查看每个 Render Pass 的 loadOp/storeOp 实际行为特别适合分析移动端 Tile-Based GPU 的 RT 带宽问题工具选择指南平台推荐工具通用OpenGL/VulkanRenderDocDX12Windows/XboxPIX RenderDocNVIDIA性能分析Nsight GraphicsAppleMetalXcode GPU DebuggerAndroid通用Android GPU Inspector (AGI)AndroidMaliRenderDoc Arm StreamlineAndroidAdrenoRenderDoc Snapdragon Profiler13.2 Unity Frame Debugger / Unreal GPU Visualizer引擎内置的调试工具不需要外部软件适合快速排查。Unity Frame DebuggerWindow → Analysis → Frame Debugger功能列出一帧中所有 Draw Call点击每个 Draw Call 可以看到当前 RT 的快照显示当前绑定的 RT 名称、格式、分辨率可以看到GetTemporaryRT/SetRenderTarget调用局限不能看 Shader 内部不能自定义通道查看比如只看 Alpha性能数据有限Unreal GPU Visualizer控制台命令ProfileGPU或快捷键CtrlShift,功能显示每个 Pass 的 GPU 时间可以看到 RDG 中每个 Pass 的名称和耗时输入vis TextureName可以在 Viewport 中可视化某张 RTUnreal 还有GPU Profilerstat gpu实时 GPU 时间统计RDG Insights可视化 Render Graph 的 RT 流转13.3 常见异常诊断手册异常一全黑画面或某张 RT 完全是黑色。可能原因检查方法RT 没有被绑定到输出RenderDoc → Pipeline State → 查看 Output Merger 的 RT 绑定Clear 颜色是黑色且没有渲染任何东西检查 Draw Call 列表中是否有渲染到这张 RT 的 Draw状态转换错误——RT 还是可写状态就被当纹理采样检查 Barrier 日志Vulkan Validation Layer 会报错RT 格式不匹配——Shader 输出 float4 但 RT 是 R8检查 Shader 输出语义和 RT 格式是否兼容Depth 测试挡住了一切暂时关掉 Depth Test 看看是否有输出Viewport 设置错误——渲染区域为 0检查 Viewport 和 Scissor Rect诊断流程全黑 → 这张 RT 有没有 Draw Call 写入 → 没有绑定问题检查 SetRenderTarget → 有Draw Call 有输出吗 → RenderDoc 中查看那个 Draw Call 后的 RT → 还是全黑 → 是Shader 问题Depth 挡住 / Shader 输出 0 / Viewport 为 0 → 不是后续某个 Pass 覆盖了检查后续的 RT 操作异常二闪烁每帧或每几帧画面变化可能原因检查方法Double Buffer / Triple Buffer 的 RT 混用检查 Swap Chain 配置确认不是在读两帧前的 Back Buffer帧间同步问题——读到了上一帧还没写完的 RT检查 Barrier / Fence 是否正确TAA 历史帧被意外覆盖确认 History RT 没有被 Pool 回收Ping-Pong 交换逻辑错误在每帧结束时打印 src/dst 索引确认交替正确异常三颜色错现象可能原因修复颜色过亮/过暗sRGB vs Linear 搞混确认 RT 格式是否带_SRGB后缀见第 7 章颜色偏粉/偏绿通道顺序错误RGBA vs BGRA检查 API 的 Swap Chain 格式颜色条纹/色阶精度不足R8 存 HDR 数据升级格式到 RGBA16F颜色断裂/阶梯Tone Mapping 前后格式切换确认 HDR → LDR 的路径格式正确全白/过曝HDR 值没有经过 Tone Mapping检查后处理链上 Tone Mapping Pass 是否执行sRGB / Linear 是最常见的颜色错误来源。诊断方法用 RenderDoc 查看 RT 的格式 → 写入侧的 RT 格式是否带 _SRGB → 读取侧的 Sampler 是否正确 → Shader 中是否手动做了 pow(2.2) 但 RT 又是 _SRGB导致双重 gamma异常四上下翻转原因常见场景OpenGL 的 UV 原点在左下角DX 在左上角从 OpenGL 项目移植到 DXFramebuffer Blit 的 src/dst 坐标系不一致使用glBlitFramebufferRT 作为纹理采样时 V 坐标需要翻转跨 API 设计修复在 Vertex Shader 或 Blit 时翻转 Y 坐标。// 翻转 UV.y uv.y 1.0 - uv.y;或者在投影矩阵中翻转Vulkan 推荐的做法// Vulkan 的 NDC Y 轴和 OpenGL 相反projMatrix[1][1]*-1;异常五黑边 / 拉伸 / 异常裁剪可能原因检查方法Viewport 大小与 RT 大小不匹配RenderDoc → Pipeline State → Viewport动态分辨率下 UV 缩放错误检查 RTHandle Scale 是否正确传入 ShaderScissor Rect 限制了渲染区域检查 Scissor 设置纵横比不一致RT 是 16:9 但 Viewport 设为 4:3通用诊断方法论二分法定位问题一帧有 30 个 Pass不知道问题出在哪用二分法1. 从最终输出开始往前追溯到第 15 个 Pass 2. 检查第 15 个 Pass 的输出 RT正常 → 正常问题在 Pass 16~30 → 不正常问题在 Pass 1~15 3. 继续二分直到找到第一个输出异常的 Pass替换法隔离问题把某张输入 RT 替换为一张已知正确的纯色纹理 → 输出正常问题在那张输入 RT 的生成 Pass → 输出仍异常问题在当前 Pass 自身Shader / 状态设置“可视化法”把每张 RT 的单个通道R/G/B/A/Depth映射为灰度图显示 → 检查数据范围是否合理0~10~100全 NaN → 检查是否有不该出现的区域如 Shadow Map 中有些区域深度为 0RenderDoc 的 Texture Viewer 自带这些可视化功能——可以选择查看单通道、调整范围、显示 NaN/Inf 像素。本章小结工具强项平台RenderDoc通用帧调试Windows/Linux/AndroidPIXDX12 深度分析Windows/XboxNsightNVIDIA GPU 性能WindowsXcode GPU DebuggerMetal 调试macOS/iOSUnity Frame DebuggerUnity 快速排查编辑器内Unreal GPU VisualizerUnreal 快速排查编辑器内诊断核心思路先定位哪张 RT 出了问题——逐 Pass 检查看输入还是看输出——输入对但输出错 → Shader / 状态问题输入就错 → 问题在更前面五大常见异常全黑绑定/Barrier、闪烁同步、颜色错sRGB/格式、翻转坐标系、黑边Viewport 思考题你遇到了一张 RT 在某些帧是正确的、某些帧全黑但不是每隔一帧那种规律。可能是什么原因怎么排查如果你发现 RenderDoc 中某张 RT 的内容看起来正确但最终画面上对应的区域颜色偏亮你会先检查什么提示第 7 章 sRGBVulkan Validation Layer 可以捕获哪些 RT 相关的错误它捕获不了哪些错误下一章展望 RT 技术的未来演进。Visibility Buffer 正在颠覆 G-Buffer 的胖 MRT 模型Mesh Shader 让 RT 拓扑重新洗牌NeRF/3DGS 更在问如果不再有三角形RT 还存在吗14 章走到最后一章是时候把视线从当下的最佳实践抬起来看看五到十年后 RT 的形态。