第八章 导入导出与 Python 脚本扩展
.rdc 文件导入与导出格式
RenderDoc 的抓帧文件(.rdc)是一种不透明的二进制格式,包含重建和回放帧所需的全部 API 对象和调用数据。这些内部数据被称为 structured data(结构化数据),可在捕获文件打开时在内存中访问,也可导出为外部文件格式,反之亦可从外部文件格式导入。
内置导出格式
RenderDoc 提供多种内置导出格式,但并非所有格式都包含完整数据,因此不一定支持回导(re-import):
| 格式 | 说明 | 支持回导 |
|---|---|---|
| XML only | 仅导出结构化数据,速度快 | 否 |
| XML + ZIP | 导出结构化数据及全部二进制缓冲(纹理、顶点缓冲等),速度慢 | 是 |
XML + ZIP 是唯一包含完整数据的格式,可被 RenderDoc 重新加载为捕获文件。其 XML 部分记录了每次函数调用对应的 chunk,示例如下(Vulkan vkCmdBeginRenderPass):
<chunk id="1045" name="vkCmdBeginRenderPass" length="69" threadID="17140"
timestamp="865021" duration="6">
<ResourceId name="commandBuffer" typename="VkCommandBuffer" width="8"
string="ResourceId::146">146</ResourceId>
<struct name="RenderPassBegin" typename="VkRenderPassBeginInfo">
<enum name="sType" typename="VkStructureType"
string="VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO">43</enum>
<null name="pNext" typename="VkGenericStruct" />
<ResourceId name="renderPass" typename="VkRenderPass" width="8"
string="ResourceId::158">158</ResourceId>
<ResourceId name="framebuffer" typename="VkFramebuffer" width="8"
string="ResourceId::130">130</ResourceId>
<struct name="renderArea" typename="VkRect2D">
<struct name="offset" typename="VkOffset2D">
<int name="x" typename="int32_t" width="4">0</int>
<int name="y" typename="int32_t" width="4">0</int>
</struct>
<struct name="extent" typename="VkExtent2D">
<uint name="width" typename="uint32_t" width="4">1280</uint>
<uint name="height" typename="uint32_t" width="4">720</uint>
</struct>
</struct>
<uint name="clearValueCount" typename="uint32_t" width="4">0</uint>
<array name="pClearValues" typename="VkClearValue" />
</struct>
<enum name="contents" typename="VkSubpassContents"
string="VK_SUBPASS_CONTENTS_INLINE">0</enum>
<array name="DebugMessages" typename="DebugMessage" hidden="true" />
</chunk>每个 chunk 对应一次函数调用或一个逻辑工作单元,参数以结构化树形式完整描述,可从中读取 ResourceId、struct 成员、数组及基本类型。
导入方式
将 XML + ZIP 文件导入时,RenderDoc 会将其作为普通抓帧文件加载,与原生 .rdc 文件使用体验一致。
Python API 基础用法
pyrenderdoc 模块
RenderDoc 内置完整的 Python API,核心入口对象为 pyrenderdoc,即 CaptureContext 句柄,在 Python Shell 以及扩展的 register 函数中均可直接使用。
Python Shell 位于 Tools 菜单下,可实时交互式操作当前打开的捕获文件。
访问结构化数据
通过 pyrenderdoc 可以访问抓帧的结构化数据。以检查某个函数调用为例:
# 获取 action 111 最后一个 APIEvent,找到对应的 chunk 索引
event = pyrenderdoc.GetAction(111).events[-1]
print("event %d is at chunk %d" % (event.eventId, event.chunkIndex))
# 输出: event 111 is at chunk 223
# 取得对应 chunk 并遍历参数
chunk = pyrenderdoc.GetStructuredFile().chunks[event.chunkIndex]
print("We have chunk '%s'" % chunk.name)
for child in chunk.data.children:
print("Parameter %s" % child.name)
# 输出:
# Parameter commandBuffer
# Parameter RenderPassBegin
# Parameter contents
# Parameter DebugMessages从 chunk 的 data.children 出发,可以继续向下递归遍历 struct 成员、数组,直至基本类型。
Python 扩展(Extensions)
扩展是放置在 RenderDoc 配置目录下的 Python 模块,并附带 extension.json 清单文件:
- Windows:
%APPDATA%\qrenderdoc\extensions\<扩展名>\ - Linux:
~/.local/share/qrenderdoc/extensions/<扩展名>\
extension.json 模板:
{
"extension_api": 1,
"name": "Extension name for users",
"version": "1.0",
"minimum_renderdoc": "1.2",
"description": "A longer description of your extension.\n\nIt can contain multiple lines",
"author": "Your name <your@email.com>",
"url": "url/to/repository"
}extension_api 当前固定为 1;minimum_renderdoc 用于限制兼容的 RenderDoc 最低版本。
扩展入口函数:
def register(version, pyrenderdoc):
# version: RenderDoc Major.Minor 版本字符串,如 "1.2"
# pyrenderdoc: CaptureContext 句柄,与 Python Shell 中的全局对象相同
pass
def unregister():
# 扩展被重新加载时调用,用于清理持久状态(可选)
pass启用方式: 打开 Tools -> Manage Extensions,选中扩展后点击 Load,勾选 Always Load 可设为随 UI 启动自动加载。已加载的扩展可点击 Reload 热重载代码(若遇到问题建议重启程序完整重载)。
自动化脚本示例
批量导出纹理
利用 pyrenderdoc 遍历所有资源并导出纹理:
import renderdoc as rd
# 获取所有纹理资源
textures = pyrenderdoc.GetTextures()
controller = pyrenderdoc.GetReplayController()
for tex in textures:
# 设置保存配置
save_data = rd.TextureSave()
save_data.resourceId = tex.resourceId
save_data.destType = rd.FileType.PNG
save_data.mip = 0
save_data.slice.sliceIndex = 0
filename = "/tmp/textures/%s_%d.png" % (tex.name, tex.resourceId)
controller.SaveTexture(save_data, filename)
print("Saved: %s" % filename)遍历 DrawCall
遍历所有 action(DrawCall)并打印基本信息:
def walk_actions(action):
if action is None:
return
# 过滤出真正的绘制调用
if action.flags & renderdoc.ActionFlags.Drawcall:
print("Draw eventId=%d name='%s' numIndices=%d" % (
action.eventId, action.customName, action.numIndices))
for child in action.children:
walk_actions(child)
# 从根 action 开始遍历
for top_action in pyrenderdoc.GetActions():
walk_actions(top_action)遍历结构化数据中的 chunk
sf = pyrenderdoc.GetStructuredFile()
for i, chunk in enumerate(sf.chunks):
print("[%d] chunk name=%s" % (i, chunk.name))
for param in chunk.data.children:
print(" param: %s" % param.name)自定义 Pass 可视化(Custom Visualisation)
Custom Visualisation 允许用户在 Texture Viewer 中使用自定义着色器对纹理进行解码、解包或复杂变换,超出默认控件的处理能力。
着色器语言支持
| API | 支持语言 |
|---|---|
| D3D11 / D3D12 | HLSL(唯一选项) |
| OpenGL | GLSL |
| Vulkan | GLSL 或 HLSL(需要编译器支持) |
由于 .glsl 同时用于 Vulkan 和 OpenGL,可通过预定义宏 VULKAN 区分。
着色器文件放置位置
将 .hlsl 或 .glsl 文件放置于应用数据目录:
- Windows:
%APPDATA%/qrenderdoc/ - Linux:
~/.local/share/qrenderdoc/
RenderDoc 在加载捕获文件时自动加载这些着色器,并监视文件变化,外部修改后自动热重载。
着色器入口点要求
Pixel Shader 必须定义 main() 函数,返回 float4,表示最终输出颜色。Texture Viewer 的范围调整(Range Adaption)和通道选择控件仍对自定义着色器的输出生效。
预定义输入
UV 坐标
/* HLSL */
float4 main(float4 pos : SV_Position, float4 uv : TEXCOORD0) : SV_Target0
{
// uv.xy 范围 0~1,覆盖纹理全尺寸
return float4(uv.xy, 0, 1);
}/* GLSL */
layout (location = 0) in vec2 uv;
void main() { /* uv 范围 0~1 */ }常量辅助函数
uint4 RD_TexDim(); // x=width, y=height, z=depth/arraySize, w=mipLevels
uint RD_SelectedMip(); // 当前选中的 mip 层级
uint RD_SelectedSliceFace(); // 当前选中的 array slice 或 cubemap face
int RD_SelectedSample(); // 当前选中的 MSAA sample(负值表示 average)
float2 RD_SelectedRange(); // Texture Viewer 范围选择器的 (min, max)
uint RD_TextureType(); // 当前纹理类型,配合 RD_TextureType_2D 等宏使用Sampler 绑定
/* HLSL */
SamplerState pointSampler : register(RD_POINT_SAMPLER_BINDING);
SamplerState linearSampler : register(RD_LINEAR_SAMPLER_BINDING);/* GLSL - Vulkan only */
#ifdef VULKAN
layout(binding = RD_POINT_SAMPLER_BINDING) uniform sampler pointSampler;
layout(binding = RD_LINEAR_SAMPLER_BINDING) uniform sampler linearSampler;
#endif纹理资源绑定(以 HLSL 为例)
Texture2DArray<float4> texDisplayTex2DArray : register(RD_FLOAT_2D_ARRAY_BINDING);
Texture3D<float4> texDisplayTex3D : register(RD_FLOAT_3D_BINDING);
// 整数格式
Texture2DArray<int4> texDisplayIntTex2DArray : register(RD_INT_2D_ARRAY_BINDING);
Texture2DArray<uint4> texDisplayUIntTex2DArray : register(RD_UINT_2D_ARRAY_BINDING);每次只有与当前纹理类型匹配的绑定槽有效,其余绑定槽为空。通过 RD_TextureType() 返回值配合 API 对应的 RD_TextureType_* 宏判断应采样哪个资源。
完整示例模板可参考社区仓库:https://github.com/baldurk/renderdoc-contrib/tree/main/baldurk/custom-shader-templates
RGP(Radeon GPU Profiler)集成与使用
RenderDoc 内置了与 AMD Radeon GPU Profiler(RGP)的集成,支持从 RenderDoc 捕获文件直接生成 RGP profile,并在两个工具之间同步事件视图。
启用 RGP 集成
默认情况下 RGP 集成处于关闭状态。启用步骤:
- 打开
Settings窗口 - 在
Core区域勾选Enable Radeon GPU Profiler integration
生成 RGP Profile
- 打开
Tools菜单,选择Create new RGP Profile- 若此菜单项不可见,说明未安装最新的 AMD 驱动程序
- 点击后弹出小窗口,RenderDoc 花几秒时间生成 profile
- 生成完成后,RGP 工具自动打开
- 若未配置 RGP 工具路径,会在此处提示配置
注意: RGP profile 数据会嵌入到 .rdc 文件中,与抓帧数据一起保存。
打开已有的 RGP Profile
已嵌入 .rdc 的 RGP profile 无需重新生成,可在任何机器(无需 AMD 驱动或 AMD 硬件)上打开:
- 打开
Tools菜单 - 选择
Open RGP Profile
RGP 工具将以与新生成时相同的方式打开。
RenderDoc 与 RGP 的事件关联
当 RGP 版本 >= 1.2 时,两个工具具备同步视图能力:
- 在 RGP 中选中一个事件 → 右键 →
Select RenderDoc Event:RenderDoc 切换到前台并选中对应事件 - 在 RenderDoc 的 Event Browser 中右键某事件 →
Select RGP Event:RGP 执行反向同步
注意: RGP 和 RenderDoc 的事件编号不同,因为两个工具对帧的视角、范围和用途各不相同,数字无法直接对应,需通过上述关联操作在两工具之间跳转。