MENU

• 2026 年 10 月 20 日 • 已有 4 只咪围观过 • -学海无涯-

2026-10-20T07:35:40.jpg

参考文章:
链接内容
正确截取 Vulkan 模拟器特殊的Renderdoc版本
RenderDoc+MuMu12 截帧教程基础使用教学

之前都是用RenderDoc读Ue信息,第一次拆解安卓包。非常兴奋,充满了好奇hhh
仅用于自学和测试,无商业化行为!!!
(这个人自己还没打清楚包就开始拆别人的了)
实践以后增加了理解和思考,新的知识灌注中..

捕获原理:RenderDoc 截在模拟器的哪一侧?

1. Guest API、Host backend 与窗口合成

典型链路应拆成三段理解:

Android Guest
  application -> libvulkan.so -> guest Vulkan HAL / virtual GPU driver
                   |
                   | 私有命令/资源/同步传输通道
                   v
Windows Host renderer
  graphics bridge / worker -> vulkan-1.dll -> vendor ICD -> GPU work
                   |
                   | image、共享内存/句柄或内部传递
                   v
Host compositor / window
  compose / scale / color conversion -> swapchain -> present

Vulkan-to-Vulkan 桥接不等于 GPU PCIe passthrough。 Guest 与 Host 不共享可直接互用的 VkDevice、对象句柄和地址空间。bridge 通常需要映射对象、上传资源、重建命令及传递 fence/semaphore 完成状态。具体是否采用共享内存 ring、named pipe、socket,或者在何处重编码,由 MuMu 版本和 backend 决定,现有资料没有公开其协议。

MuMu 的“Vulkan 模式”选择模拟器图形 backend,不能单独证明 APK 实际使用 Vulkan:应用仍可能选择 GLES,bridge 也可能翻译 API。需要分别验证 Guest 实际 API 与 Host 实际 API。Host 图形进程加载 vulkan-1.dll/厂商 ICD、RenderDoc 报告 Vulkan,可以确认候选路径;捕获内容与目标应用匹配,才能确认捕获范围。

若 Host backend 是 D3D/OpenGL,RenderDoc 截到的是翻译后的工作流。它可以分析该边界上的资源和状态,但不能拿 D3D barrier、shader 或 pipeline 去解释 Guest 原始 Vulkan 调用。

2. 为什么容易只捕获最终 FrameBuffer

合成端拿到的 image 可能已经包含完整场景。它只需一次 copy/blit,或一个采样完整场景纹理的全屏 draw,就可以输出到窗口。RenderDoc 对合成端的捕获完全合法,回放也正确,但生成场景的几何、材质、深度与中间结果位于捕获范围之外。

资料 A 将问题概括为“同时存在多个渲染设备,应把运行中的设备都抓一遍”。工程上需要进一步区分:

拓扑常见表现对应动作
不同 PID 承载 renderer/compositorUI capture 只有合成,另一个 worker GPU 活跃识别真实 worker;在创建 Vulkan 对象前注入
同一 PID 内多个 Vulkan 上下文DLL 已注入、API=Vulkan,却总触发到外层输出检查 instance/device 与 capture trigger 的路由
跨进程/外部 image 共享image 有完整内容,本 capture 找不到生产者核对 external memory/semaphore 与另一 producer 的捕获范围
生产与消费跨帧当前帧采样 history/缓存 image检查前一帧或更早更新,不直接判为漏捕获

原文的“设备”并没有严格限定为 VkInstance、VkDevice 或 RenderDoc wrapper,不能将其直接等同于多 PID。Capture Child Processes 解决新生子进程注入,不解决同一 PID 内所有上下文的触发选择。 资料 A 的 fork 意在扩大运行中渲染设备的覆盖;其具体枚举、触发与文件输出方式须按所用 commit 的 diff 确认。

同时,Host present 不必等于 Guest 应用完整逻辑帧的边界。异步合成、多 queue 和跨进程图像传递,可能让一份 capture 只覆盖消费端。快照保存了输入 image 的初始内容,也不会包含生成这些像素的历史命令。

3. 注入链路的三个成功条件

  1. DLL 进入目标进程:模块表中有正确架构的 RenderDoc capture DLL。
  2. Vulkan 对象进入包装链:目标创建 instance/device 时经过 RenderDoc layer/dispatch wrapper。
  3. 捕获触发命中目标上下文:当前 frame trigger 落在真正生产目标画面的渲染上下文。

三者不互相替代。看到 renderdoc.dll 不能证明已有 Vulkan 对象被包装;看到 Vulkan overlay 不能证明 trigger 命中了真实 renderer;生成 .rdc 不能证明里面包含目标画面的生产命令。

Vulkan layer 通过 loader 的 dispatch chain 包装 vkGetInstanceProcAddr、vkGetDeviceProcAddr 及后续调用。RenderDoc 的标准安装通常注册 implicit layer,由启动/注入流程控制激活;explicit layer 则由应用或环境变量请求。

VK_INSTANCE_LAYERS=VK_LAYER_RENDERDOC_Capture 只是请求已存在的层名,不会安装 layer,也不改变 manifest 的 implicit/explicit 属性。VK_LAYER_PATH 主要影响 explicit layer 的搜索,不能代替 Windows implicit 注册。

# 诊断当前安装;32-bit 目标还要检查 /reg:32 和 HKCU 对应路径
reg.exe query 'HKLM\SOFTWARE\Khronos\Vulkan\ImplicitLayers' /reg:64
reg.exe query 'HKLM\SOFTWARE\Khronos\Vulkan\ExplicitLayers' /reg:64

$layerJson = 'C:\实际安装目录\renderdoc.json' # 替换成注册表指向的文件
if (Test-Path -LiteralPath $layerJson) {
  (Get-Content -Raw -Encoding UTF8 -LiteralPath $layerJson | ConvertFrom-Json).layer |
    Select-Object name,library_path,enable_environment,disable_environment
}

优先让 qrenderdoc Launch 管理环境。仅在排查 layer discovery 时,从将要启动 Host 进程的终端设置:

$env:VK_LOADER_DEBUG = 'error,warn,layer'
$env:VK_INSTANCE_LAYERS = 'VK_LAYER_RENDERDOC_Capture'
# 只有确认使用 explicit manifest 时才按需设置目录
# $env:VK_LAYER_PATH = Split-Path -Parent $layerJson

不要硬编码不存在的 RenderDoc\layers 目录,或将不同版本 DLL/manifest 混装。DLL 注入与 implicit layer 激活可以协同工作;不能仅凭启用了多种机制就认定“重复 hook”。以实际 loader chain、library_path 和加载模块为准。

4. Host capture 的可见性边界

Windows Host .rdc 记录 bridge 输出的 API 工作流,不会自动恢复:

  • Guest libvulkan.so 原始调用栈、Android CPU 调度和 driver 内部状态;
  • bridge 改写前的句柄、descriptor、shader 或纹理格式;
  • 未被捕获的进程、上下文和外部 producer 的历史命令;
  • 真实移动 GPU 的 tile memory、寄存器压力、occupancy、功耗和带宽成本。

ADB 可用于识别应用 API、启动场景和取日志,但 Android 环境变量/setprop 不会传到 Windows worker。Root 也不是 Host 注入的前置条件。Guest-side RenderDoc 是另一条捕获路径,须另行满足 ROM、应用调试与 layer 注入条件。

可复现工作流:从进程识别到有效捕获

1. 先保留启动现场,再重启注入

正常启动 MuMu 和应用一次,记录 PID/PPID、完整命令行、工作目录、实例目录、GPU engine 和加载模块。随后退出相关 worker,使用 RenderDoc 在 Vulkan 初始化前启动;晚期 Attach 不能追补未被包装的既有对象。

Get-CimInstance Win32_Process |
  Where-Object { $_.Name -match 'MuMu|Nemu' } |
  Select-Object ProcessId,ParentProcessId,Name,ExecutablePath,CommandLine

$targetPid = (Get-Process MuMuNxDevice -ErrorAction SilentlyContinue |
  Select-Object -First 1).Id
if ($targetPid) {
  Get-Process -Id $targetPid -Module | Where-Object {
    $_.ModuleName -match 'vulkan|renderdoc|nvoglv|amdvlk|igvk'
  } | Select-Object ModuleName,FileName
}

示例只用于枚举候选;多开实例时必须按真实路径和命令行选 PID。Process Explorer 的 GPU engine/模块可辅助筛选,但 GPU 活跃并不证明捕获到了正确上下文。

资料 B 的 v1.43 图使用:

Executable:  E:\mumu\MuMuPlayer\nx_device\12.0\shell\MuMuNxDevice.exe
Working Dir: E:\mumu\MuMuPlayer\nx_device\12.0\shell

其中 v1.33 图则使用 C:\Program Files\Netease\MuMu Player 12\shell\MuMuPlayer.exe。这些是版本相关入口;MuMuPlayerService.exe 通常属于守护/服务,不能按名字认定是 renderer。其他版本可能使用 MuMuVMMHeadless.exe 或 NemuHeadless 类命名。

直接启动 worker 若缺少实例参数、工作目录或服务上下文,可能无法正常工作。此时保留正常命令行,或从实际父启动器 Launch,并打开 Capture Child Processes。已有服务新建的 worker 不一定是被 hook 启动器的后代,要核对真实 PPID。

2. MuMu 与 RenderDoc 的复现基线

MuMu 选择资料 B 所示“Vulkan 模式(独家)”,将“强制使用独立显卡”置关。后者仅取消强制策略,不代表禁用独显,实际 adapter 必须从 capture/device properties 核对。

锁定 Android 显示尺寸、DPI、渲染分辨率策略与刷新率;先以 1280×720 验证链路,再升到目标尺寸。Host 窗口缩放不一定改变 Guest render extent,以实际 image extent 为准。截图中的 6 核/12 GB 不是捕获要求,过度分配反而会加重 Host 内存与调度压力。

RenderDoc 选项基线策略解释
Capture Child Processes开使新生子进程获得 hook;不能修复同 PID 多上下文选择
Allow Fullscreen / Allow VSync保持资料勾选状态不解决 layer discovery,不把 VSync 当通用 TDR 修复
Enable API Validation首次链路验证关,另做验证实验改变开销/时序;普通开关不等于 synchronization/GPU-assisted validation 全开
Ref All Resources关正常捕获已包含被引用资源;开启额外保存全部 live resources,不能补出未捕获的命令
Collect Callstacks / Only Action stacks关需要查 Host 调用点时再开;不恢复 Guest 栈
Verify Buffer Access关覆盖范围依当前 API/build,不能据此认定 Vulkan descriptor runtime 越界已检查
Capture all Cmd Lists不依赖它修复 Vulkan公共 API 对 Vulkan/D3D12 有忽略该选项的说明,应核对所用版本
Queue Capture / #Frames首轮单帧安排捕获帧,不是 Vulkan queue 同步开关

资料界面中没有可泛化的 RefCount Tracking、Queue Synchronization 开关。前者不能与 Ref All Resources 混用,后者不能与 Queue Capture 混用。若某 fork 提供额外生命周期/submit 序列化参数,应记录精确 option key、commit 和 A/B 结果,不能靠名称猜语义。

若启用 Tools -> Settings -> General 的 Enable process injection (restart required),重启 qrenderdoc 后生效。Allow global process hooking 只是开放该功能;实际启用应限定目标,捕获完成关闭。Global Hook 不能保证处理所有服务启动、权限或非标准 loader 路径。64-bit qrenderdoc 可借助 x86 helper 注入 32-bit 目标,但 DLL/helper 必须与目标架构匹配。

3. 稳定场景与 frame trigger

先完成 shader/pipeline warm-up、纹理 streaming 和场景切换,避免抓帧同时 resize、切后台或横竖屏。观察连续若干帧资源分配与 GPU 时间趋于稳定后,用 F12 或 target-control trigger;固定“两次 present”不是稳定性保证。

F12 面向 frame 边界,不会精确在某条 draw 自动停下。常规操作是捕获完整帧,再在 Event Browser 定位。若需要精确包围 Host 命令,必须修改实际 worker 并集成匹配版本的 RenderDoc API;在 Guest 应用调用 API 不会自动控制 Windows capture。

资料 B 的 overlay 显示 Capturing Vulkan、帧号和 capture 数量。它用于确认 API 接管,内容验收仍要在下一章完成。临时文件默认位置在资料中为 %LOCALAPPDATA%\Temp\RenderDoc\*.rdc;临时 capture 应在 qrenderdoc 中显式另存到证据目录。

按键后短暂卡顿可能来自资源快照/readback/等待。持续卡死、TDR 或 Device Lost 则要区分负载放大、同步停滞和真实 GPU 错误,不能统一归因于分辨率。首先单帧、低分辨率、关闭额外全资源/栈收集;TDR 阈值调整只作为隔离环境实验。

读 .rdc:从图像回溯到产生它的命令

1. 第一轮验收:这份 capture 值不值得继续分析

检查顺序是 输出匹配 -> 资源生产者 -> 目标 draw/dispatch -> 依赖闭环,而不是从第一条 API 顺序阅读。

验收层有效证据不能单独成立的证据
进程/注入目标 PID、模块、loader chain进程名、overlay
捕获路由目标窗口/上下文响应 triggerchild hook 已开启
画面内容输出对应当时场景与操作缩略图完整
生产过程draw/dispatch、相关资源和中间输出相互对应draw 数多、文件大
依赖目标输出可回溯到捕获内的生产命令一张初始内容已完整的输入 image

典型的 compositor-only 组合是:完整画面只存在于输入 image;本 capture 几乎只有 copy/blit/fullscreen composite;找不到该场景的生产命令;切换简单/复杂场景后,捕获工作结构基本不变。

但少 draw、全屏三角形、没有 marker 均不是单独定论。2D、视频层、compute renderer、静态缓存和 history 都可能如此。Usage 中没有本帧 writer,也可能只是静态上传或跨帧数据。先结合目标应用内容、资源更新规律与其他 PID/context 判断,不要用“必须几百个 draw”验收。

如果真正的生产命令在另一个进程/上下文,切换事件、打开 Ref All Resources 或放大 Texture Viewer 都不会把它补出来,应返回捕获阶段。

2. 固定阅读路径:最终 image -> writer -> inputs -> producer

与目标画面匹配的输出 image
  -> Resource Usage:本帧最后几次 write
  -> writer 的 Pipeline State / copy 参数
  -> 该事件的 sampled/storage image、buffer
  -> 输入资源的生产事件
  -> 几何 draw / compute dispatch / 外部或历史输入边界

第一步:确定正确输出。 在 Texture Viewer 检查 extent、format、mip、array layer、aspect、sample 和事件位置。最大 image 未必是最终画面:阴影图集、HDR 中间图、超分辨率输入都可能更大。最终 swapchain 也可能包含 MuMu 窗口合成,而应用颜色输出在更早的 image。

第二步:找改变目标内容的 writer。 在资源 Usage 中定位最后几次 write,跳到相应事件。区分 draw、dispatch、copy、blit、resolve;最后一次 writer 可能只做缩放或色彩转换。记录 writer 前后图像的差异,确认它改变的是目标区域。

第三步:继续追输入。 在该事件的 Pipeline State 查看绑定与 reflection 中的 image/buffer,再用 shader 索引、受支持的 descriptor-access 反馈/调试或受控实验确认实际读取项。descriptor array/bindless 中“已绑定”不等于本次 draw 一定访问。若采样的是一张已经完整的场景图,应继续追它的 writer。若 Usage 仅见消费事件、没有本帧 writer,再结合创建参数、外部句柄、日志和前序帧区分静态内容、history、初始快照与外部输入;Usage 本身不直接鉴定这些来源。

第四步:保存最小链。 每层保留“输入资源 -> EID/事件区间 -> 输出资源 -> 可观察变化”。例如:

输入事件/操作输出可观察变化
vertex/index、材质纹理EID A,indexed drawSceneImage首次出现目标物体
SceneImage、depthEID B,fullscreen/computeProcessedImage目标区域颜色/模糊发生变化
ProcessedImageEID C,blit/compositeWindowImage缩放、窗口合成或色彩转换

名称只作分析标注,不强行套某个引擎的 Pass 名。Resource Usage 是读写索引,不是同步正确性证明;存在 RAW 关系不代表 barrier、layout 或 ownership 一定正确。

3. 没有 marker,如何划分有效阶段

按 attachment 与依赖划分,而非把 command buffer、submit、VkRenderPass 当成业务阶段的一一映射:

结构特征优先验证
depth-only attachment + 几何深度生产/阴影候选;继续检查矩阵、extent 与使用者
同一组 color/depth 上多个几何 draw一段场景 raster 工作;检查 clear/load/store 与目标物体
多个 color attachment逐张检查编码和消费方式;MRT 本身不能证明 deferred
全屏工作读取前级 color后处理、合成、缩放或转码候选
尺寸逐级缩小/放大mip/downsample、bloom、重建等候选,须沿输入验证
dispatch 写 storage image,随后 graphics 采样compute producer 到 graphics consumer 的边界
完整画面 copy/blit 到 swapchain输出搬运,不应在这里停止追踪

同时检查 classic render pass/subpass 或 vkCmdBeginRendering 的 dynamic rendering 路径。一个阶段可能跨多个 submit,一个 render pass 也可能含多个逻辑阶段;subpass/input attachment 不保证 Host 桌面 GPU 上有移动端 tile-local 驻留。

Event Browser 记录的是捕获范围内可重建的图形事件,不是完整系统 API trace。某些创建参数要从 Resource/Pipeline Inspector 或 replay 接口读取;不要假定所有初始化调用都按原始时间顺序显示在帧事件列表里。

4. 黑图、错色、缺物体:先排除读图方式

黑图按顺序检查:事件位置 -> image -> mip/layer/aspect/sample -> 通道 -> 显示范围。常见误读包括查看未写入 mip、depth/stencil 选错 aspect、alpha 为零、HDR 超出 [0,1] 或 depth 集中在很窄数值范围。

先读目标像素的数值,再调 channel、range/exposure;区分原始线性数据与 sRGB 显示转换。若此前事件尚未写入,或内容按 load/store 语义未定义,查看器显示黑色不能证明 shader 输出为黑。

当 API、资源格式和 RenderDoc build 支持时,用 Pixel History 查目标像素,定位第一个偏离预期的事件:

  • 几何是否覆盖该像素;
  • fragment 是否被 depth/stencil 拒绝;
  • shader 输出是否已经错误;
  • shader 正确但 blend/color write mask 是否改变结果;
  • 后续阶段是否覆盖了正确结果。

Pixel History、Shader Debug 与某些 overlay 并非所有 Vulkan 路径可用。“工具无结果”不能解释为“没有写入”。缺支持时,退回事件前后 attachment 对比、实际 pipeline 状态和资源数据。

5. 锁定一条 draw 后,检查实际绑定状态

Pipeline State 应回答“这条事件实际使用了什么”,而不是展示一组 API 名词。按症状选择检查顺序:

症状检查链
物体消失/变形vertex/index buffer、offset/stride/index type、instance 数据 -> Mesh Viewer 输入与 VS 输出(支持时)-> NaN/clip -> viewport/scissor/cull/frontFace -> depth/stencil
贴图或材质错误descriptor set/binding/array element -> image view 的 format/mip/layer/aspect/swizzle -> sampler/filter/address/LOD -> buffer offset/range/dynamic offset -> shader 实际索引
颜色或透明异常fragment 输出 -> attachment format -> blend factor/op -> color write mask -> 后续 writer -> 显示转换
某效果来源不明输出 writer -> sampled/storage inputs -> input producers -> 对比进入/退出该阶段的图像变化

Texture List 中“看起来相同”的纹理不一定是该 draw 绑定的 image view。优先从事件的 descriptor 进入资源,记录 set/binding/数组元素和 subresource,再看内容。

几何分析不要脱离状态:深度方向要结合 depthCompareOp 与 clear value;输入位置正确不代表 VS 输出正确;VS 输出正确也可能被 scissor、cull、depth/stencil 或写掩码排除。Mesh Viewer 对某些 shader stage/特性不支持时,须注明证据缺口。

6. Shader/reflection:提取绑定契约,不假装恢复原源码

对目标 VS/FS/CS 查看 entry point、SPIR-V version、specialization constants、接口与资源 reflection。核心字段包括:

DescriptorSet / Binding / descriptor type / array count
InputAttachmentIndex
PushConstant offset / size / stage flags
buffer member offset / stride / matrix layout
shader input/output location / built-ins / execution mode

将 reflection 与真实 pipeline layout、descriptor、dynamic offset 和数据对齐核对。尤其检查动态偏移顺序、uniform/storage buffer 对齐、有效 range、descriptor 数量与 shader runtime index。普通 CPU-side Validation 不一定知道实际 shader 数组索引;GPU-assisted validation/插桩需另做受支持的实验。

反编译 GLSL/HLSL 只便于阅读,不能恢复原始材质节点、宏、业务变量语义或 Guest 调用栈;SPIR-V 也不是厂商 GPU ISA。导出原始 SPIR-V 后可离线检查:

$spirvEnv = 'vulkan1.1' # 示例,换成该模块真实目标环境
spirv-val --target-env $spirvEnv captured.spv
spirv-dis captured.spv -o captured.spvasm
spirv-cross captured.spv --reflect

spirv-val 通过只代表模块符合选定环境的静态规则。源码级调试还需要有效 debug information;有 shader module 不等于有 OpSource/OpLine 或 non-semantic debug instructions。

7. 纹理格式、队列与性能:哪些结论不能越界

ASTC/ETC2 要拆成三层格式。 APK/Guest 的原始格式、bridge 创建的 Host VkFormat、replay GPU 的支持范围可能不同。Guest 宣告 ASTC 支持,不代表 Host GPU 原生采样 ASTC;bridge 可以解压为 RGBA、转码为 BC 或使用其他实现。

Host ASTC LDR/ETC2 能力字段是 textureCompressionASTC_LDR、textureCompressionETC2;逐格式检查 vkGetPhysicalDeviceFormatProperties2 的 tiling features,完整 image 参数组合再查 vkGetPhysicalDeviceImageFormatProperties2。ASTC HDR 才涉及 VK_EXT_texture_compression_astc_hdr 等额外能力。

Texture Viewer 能显示压缩图,不证明 replay GPU 能采样该格式。缺支持时回放可能失败,只有确认当前 build 有对应 emulation 才能依赖 fallback。optimal-tiled image 的实际物理布局也不能从工具导出的 staging row pitch 推断。

资源链不等于同步链。 对关键 producer/consumer,继续核对 submit、semaphore wait/signal、fence、barrier stage/access、layout 和 queue-family ownership。external memory/semaphore 或跨进程 producer 可能超出单份 capture 的重建范围;“有图无 writer”先区分静态/历史内容与外部输入。

结构证据不等于真机性能。 Host replay 的 GPU duration、draw/dispatch 数、RT 理论字节数都受桌面 GPU、bridge、序列化和插桩影响。可用它提出“重复全屏工作”“大资源多次搬运”等可验证假设,再在原运行环境复测;不能直接宣布移动端带宽或功耗瓶颈。

跨 capture 对比时,EID、ResourceId 和 Vulkan handle 不作为稳定身份。结合 shader 内容/hash、资源描述、内容特征、事件结构与固定场景条件匹配。一个可交付的分析结论应能指出:异常首次出现的事件、资源、实际绑定状态,以及它与前后阶段的差异。

排查矩阵与分析记录

现象先取证优先排查
无法注入/无 APIPID/PPID、模块、loader chain、实际 Host APIUI/服务误选、GLES/D3D backend、注入晚于 instance 创建、架构/helper/权限
完整画面但无生产过程最终 image Usage、合成输入、其他 PID/context错 renderer、多上下文触发、跨进程 producer;Ref All Resources 不补命令
Overlay 有、F12 无文件active context/window、capture log、输出目录热键冲突、frame 边界/上下文不对、文件写入失败
VK_ERROR_LAYER_NOT_PRESENTmanifest、library_path、HKLM/HKCU 与位数视图过期注册项、发现规则错误、环境变量没有作用于 Host worker
.rdc 打开即失败文件完整性、capture/replay build、首条错误未写完、fork 序列化差异、工具版本不匹配;先解决文件解析再查 Vulkan
replay device 创建失败enabled 与 supported extensions/features/formatsGPU/驱动能力差异;通常先出现 extension/feature 不支持,不能统称 Device Lost
submit 后 Device Lost最后成功事件、第一条 VUID、queue/fence 进度、GPU resetdescriptor/地址越界、生命周期、同步停滞、长任务/TDR、驱动故障
回放黑图但事件存在event、subresource、通道/数值、writer、replay log读错图、未定义初值、外部资源、格式/resolve/色彩空间差异
pipeline/render-pass 断言shader/layout、format/sample/view mask、subpass/pNext参数不兼容或当前工具/驱动不支持的组合;classic/dynamic rendering 本身都合法
Validation 后终止首条 VUID、debug callback、break/abort 配置区分报告与主动 abort;关闭后能跑不代表 API 正确
捕获卡死/TDRwarm-up 状态、内存峰值、queue 进度、Windows reset快照放大、热加载竞态、死锁或非法 GPU 工作;单帧低分辨率仅用于区分负载敏感性
两份 capture 资源“对不上”shader/hash、资源属性/内容、场景条件不用 ResourceId/EID 跨文件认同一对象;先确认相同 backend/GPU/场景

VK_ERROR_DEVICE_LOST 的返回 API 不一定是故障发生点。GPU 异步执行,早前非法工作可能直到后续 submit、wait 或资源操作才报告。记录第一条可解释的错误与最后成功工作,比只截最后一条返回值更有用。

Guest validation、Host validation、replay validation 检查的是不同边界,不能互相替代。Validation 默认报告错误,不是统一拦截调用;首条 VUID 与实际 abort 组件应分开记录。

最小证据包与结论模板

保存 .rdc、目标画面截图、capture/replay log、进程树/完整命令行、模块路径、layer manifest、MuMu/应用版本、RenderDoc tag 或 fork commit、capture/replay GPU 与驱动。若分析某个现象,再保存目标 EID、资源链、subresource 和实际 pipeline 状态。

{
  "application": {"package": "com.example.app", "version": "填写"},
  "mumu": {"build": "填写", "instance": "填写", "backend": "Vulkan"},
  "target": {"pid": 1234, "ppid": 1000, "exe": "完整路径", "architecture": "x64"},
  "renderdoc": {"capture_build": "tag/commit", "replay_build": "tag/commit"},
  "capture_gpu_driver": "填写",
  "replay_gpu_driver": "填写",
  "scope_verdict": "real producer / compositor only / unresolved",
  "target_event": "本文件内 EID",
  "resource_chain": ["input -> event -> output"],
  "first_deviation": "首次出现异常的事件及状态",
  "evidence": ["writer 前后对比", "descriptor/view", "shader/state"],
  "unverified": ["尚未捕获的外部 producer", "未测原运行环境性能"]
}
返回文章列表 打赏
本页链接的二维码
打赏二维码