Skip to main content

Chapter 111: Compute-Driven Rendering

Compute-driven rendering 指把可见性判断、LOD 选择、实例筛选、粒子更新、间接绘制参数生成等工作放到 compute pass 中完成,再让 graphics pass 读取 GPU 端生成的结果执行光栅化。本章的目标是让读者能定位一个 frame 中哪些决策适合交给 compute,追踪 buffer、barrier、indirect command 与 raster pass 的关系,并判断这种改造带来的收益与成本。

贯穿本章的材料是一帧“大规模城市场景”:场景中有二十五万个可渲染对象,实际进入主相机视锥并通过距离筛选的对象约一万两千个。每个对象有包围盒、mesh id、material id、LOD 范围和 transform。CPU 驱动版本在主线程遍历对象、排序并提交 draw;Compute-driven 版本把对象状态上传为 GPU buffer,由 compute shader 生成 visible list、LOD 结果和 indirect draw buffer,再由 graphics pass 消耗这些结果。

本章的核心结论很直接:Compute-driven rendering 的收益来自“把高频变化的大量对象决策留在 GPU 端”,它适合对象数量高、可见性变化频繁、CPU submit 成本明显、数据已经常驻 GPU 的场景。它的成本集中在 compute dispatch、全局内存读写、compaction、barrier、indirect command 格式和调试复杂度上。稳定的小场景、draw 数少的 UI、材质状态极度碎片化的内容,通常会先受限于工程复杂度和状态组织成本。

把本章放在图形管线中看,compute pass 生成的是“后续 graphics pass 的输入合同”。这个合同由资源格式、写入范围、可见对象数量、间接命令布局、同步点和 fallback 路径组成。读者评估同类方案时,应先看数据是否已经在 GPU,接着看 CPU 是否在重复做筛选与提交,再看 compute 输出能否直接变成 draw、dispatch 或 meshlet 消费的输入。

111.1 Compute‑Driven Rendering 的思想与优势

Compute-driven rendering 的工作定义是:渲染决策由 compute shader 在 GPU 端产生,并通过 buffer、counter、indirect command 或 meshlet task 传递给后续渲染阶段。这里的“驱动”指命令数量、可见对象列表、LOD 选择、实例数量或粒子状态由 compute 结果决定;graphics pass 仍然负责顶点处理、光栅化、深度测试、着色和混合。

在城市场景中,CPU 驱动路径通常会按对象数组做视锥测试,按材质或 pipeline state 排序,然后为可见对象提交 draw。对象数量增大后,CPU 做了两类重复工作:一类是逐对象判断,另一类是把判断结果翻译成 API 命令。Compute-driven 路径把对象数据整理成 GPU 可顺序读取的结构,让 compute shader 以大量 work item 并行测试包围盒、选择 LOD,并把通过测试的对象写入 visible list 或 indirect command buffer。CPU 在这一帧中的职责收缩为更新相机、提交少量 dispatch、建立资源状态和触发间接绘制。

这种思想的第一个优势是减少 CPU 提交路径中的对象级开销。CPU 仍然创建 command buffer 或 command encoder,但每个对象的“是否绘制”和“绘制几何层级”由 GPU 批量决定。Direct3D 12 的 Indirect Drawing 文档 把 indirect drawing 描述为把部分 scene traversal 与 culling 移到 GPU 的机制;Vulkan 的 vkCmdDrawIndexedIndirectCount 参考页 也体现了 draw 参数和 draw count 可从 buffer 中读取的执行模型。工程上要抓住的点是:间接绘制让 GPU 端生成的结构成为命令输入,CPU 提交数量随对象数增长的斜率会降低。

第二个优势是 GPU 端数据复用。深度金字塔、上一帧可见性、粒子状态、meshlet bounds、instance transform、材质索引本来就在 GPU 端参与渲染。把可见性和 LOD 决策放到 compute pass,可以减少读回 CPU、再上传 GPU 的路径。对粒子、草、群集灯光、小物件海量实例这类内容,状态更新与渲染消费在同一个 GPU frame 内完成,数据路径更短。

第三个优势是把“对象级决策”变成“buffer 级合同”。传统路径中,draw call 是 CPU 逐条组织的结果;Compute-driven 路径中,visible list、counter、indirect argument buffer、material bin 和 meshlet list 成为可检查资源。工具捕获时,可以查看某个 buffer 在 compute pass 后的元素数量、命令 stride、counter 值和后续 draw 的输入状态。调试对象从“为什么这条 draw 没提交”变成“哪个 compute pass 没把对象写入可见列表”。

优势成立需要满足清晰前提。对象数量要足够高,CPU 遍历或提交要在帧耗时中占有可观察比例;对象数据要能被 GPU 顺序或合并读取;compute 输出要能被后续 pass 直接消费;资源同步成本要低于被替代的 CPU 工作。把这些前提合在一起,Compute-driven rendering 的判断句可以写成:当渲染帧中的对象筛选、LOD、实例数量和命令生成具有高并行度,并且结果能留在 GPU 端消费时,compute pass 可以从“辅助计算”上升为“渲染调度的核心阶段”。

判断维度CPU 驱动路径Compute-driven 路径观察证据
对象筛选CPU 遍历对象并提交可见 drawcompute 写 visible list 或 counterCPU submit time、visible count buffer
LOD 选择CPU 根据距离和屏幕误差选 meshcompute 写 LOD id 或 meshlet rangeLOD histogram、indirect record 分布
命令生成CPU 填 draw call 或 command bufferGPU 写 indirect argument bufferindirect buffer 内容、draw count
数据往返CPU 需要读回或重建部分状态GPU buffer 在 pass 间传递readback 次数、upload bytes
调试入口draw list 和 CPU 日志buffer、counter、barrier、draw eventframe capture 资源历史

111.2 实现通用计算与光栅渲染结合

通用计算与光栅渲染结合的关键在于资源合同。Compute pass 负责读取场景状态并写出渲染输入,raster pass 负责在固定功能和 shader stage 中消费这些输入。两者之间的交接对象通常是 buffer:visible object buffer 保存对象 id,LOD buffer 保存几何层级,indirect command buffer 保存 draw 参数,counter buffer 保存实际命令数量,material bin buffer 保存按材质或 pipeline state 分组后的范围。

下面的流程图描述本章城市场景的一帧路径。它覆盖主相机可见性、LOD、粒子更新、间接绘制和光栅 pass 的连接关系,边界是单 GPU、单主视角、主 graphics queue 提交;多队列并行会在 111.4 处理。

这条路径的核心变化是:CPU 上传相机、时间、全局参数后,场景对象的大量逐项决策留在 GPU。Compute culling 读取对象包围盒和 transform,输出通过测试的对象 id;LOD selection 根据屏幕空间误差或距离写入 LOD id;Compaction 把稀疏结果整理成连续数组;Indirect commands 根据 mesh、material 和实例数量写出绘制参数。Resource barrier 让后续 graphics pass 以正确状态读取这些 buffer。

通用计算与光栅阶段的结合需要先固定输入与输出格式。以下伪代码展示一条最小可理解的资源路径。它不是某个 API 的完整代码,只表达 buffer 之间的因果关系。

struct ObjectRecord {
uint meshId;
uint materialId;
uint transformIndex;
uint lodBase;
};

struct VisibilityRecord {
uint objectId;
uint lodId;
uint materialId;
uint meshId;
};

struct DrawIndexedIndirectRecord {
uint indexCount;
uint instanceCount;
uint firstIndex;
int vertexOffset;
uint firstInstance;
};

// compute pass output contract
RWStructuredBuffer<VisibilityRecord> visibleObjects;
RWStructuredBuffer<DrawIndexedIndirectRecord> indirectDraws;
RWByteAddressBuffer visibleCounter;

这段结构说明三个事实。第一,object record 是稳定场景输入,它的生命周期通常跨越多帧。第二,visibility record 是当前 frame 的中间结果,它把 culling 和 LOD 决策编码为后续 pass 可消费的数据。第三,draw indexed indirect record 必须匹配目标 API 的间接参数布局;Vulkan、Direct3D 12、Metal、WebGPU 对字段、对齐、count buffer 和功能支持有各自边界,跨 API 抽象层要把这些差异集中到 backend contract 中。

Compute culling 的输入应尽量保持顺序读取。每个 work item 读取一个对象包围盒、对象 transform、相机 frustum 和可选的深度金字塔。如果对象通过视锥测试与遮挡测试,shader 使用 atomic counter 或 prefix sum 写入 visible list。atomic append 实现简单,适合调试与中等规模;prefix sum 和 compaction 更适合高吞吐路径,因为输出顺序和内存写入更稳定。

LOD selection 可以直接跟在 culling 后,也可以合并到同一个 shader 中。选择依据通常来自距离、包围球半径、屏幕高度、目标像素误差和资源预算。输出结果需要足够具体:只写“可见”还不足以驱动渲染,后续 graphics pass 需要知道 mesh id、index range、instance range、material id 和可能的 shader variant。把这些字段写入 visible record,raster pass 就能用统一的 instance id 或 firstInstance 找回对象属性。

Particle update 与普通静态对象有差异。粒子状态每帧变化,compute pass 会更新 position、velocity、lifetime、sort key 或 alive flag。更新后的 alive particle list 可以变成 instanced draw 的实例输入,也可以变成点精灵、billboard 或 mesh particle 的 indirect count。这里的结合点仍然是 buffer:compute 写出可渲染粒子,graphics pass 按实例读取粒子状态并完成光栅化。

间接绘制是 compute 输出进入 raster pass 的常见入口。Direct3D 12 使用 command signature 描述间接参数格式和每条命令能修改的绑定;Vulkan 的 indirect count 机制让 draw count 从 GPU-visible buffer 读取。工程设计时,应把“命令格式”和“资源绑定策略”一起设计。只生成 draw 参数而没有稳定的 material、descriptor 或 bindless 索引,graphics pass 仍会退回大量 CPU state change。

111.3 构建 Compute‑Driven 渲染管线

构建 Compute-driven 渲染管线时,先确定一帧内哪些资源是持久输入、哪些资源是当前帧临时输出、哪些资源会被 graphics pass 读取。城市场景中,持久输入包括 object buffer、mesh metadata、material table、transform buffer 和 bounds buffer;当前帧临时输出包括 visible list、LOD list、indirect command buffer、draw count buffer 和 debug counter;graphics pass 读取 indirect commands、instance data、material table、vertex buffer、index buffer、texture descriptors。

第一步是建立 GPU scene data。对象数据要被 compute shader 高效读取,常见布局是结构数组拆分成多个 buffer,例如 bounds buffer、mesh id buffer、material id buffer 和 transform index buffer。拆分的收益在于 culling pass 只读取 bounds 与 transform,LOD pass 只读取 bounds 与 mesh metadata,draw generation 才读取 material 与 mesh draw range。这样每个 pass 的带宽更接近实际需要。

第二步是写 visibility buffer。本章中的 visibility buffer 指“可见对象或可见 meshlet 的 GPU 列表”,它和 deferred rendering 中把三角形 id 写入屏幕像素的 visibility buffer 技术处在不同语境。当前语境下,它解决的问题是把大量对象的布尔可见结果压缩成连续列表,让后续 pass 按有效对象数量工作。

第三步是 compaction。GPU culling 往往先产生稀疏结果:每个对象一个可见标记,或每个 work group 一个局部结果。Compaction 把这些结果压缩成连续数组,并产生有效元素数量。常见实现有 atomic append、prefix sum、workgroup-local scan 加全局 scan。选择方式取决于对象数量、输出顺序需求和调试便利性。atomic append 的代码路径短,counter contention 会随可见对象数量增长;prefix sum 的实现复杂度更高,吞吐和输出稳定性更好。

第四步是生成 indirect command buffer。生成命令时需要把 visible record 翻译成 API 可执行的 draw 参数:index count、instance count、first index、vertex offset、first instance。若引擎使用 bindless material 和 bindless texture,firstInstance 或实例索引可以让 vertex shader / fragment shader 读取对象级材质索引。若引擎依赖传统 descriptor 绑定,就需要在生成命令前按 material 或 pipeline state 分 bin,让 graphics pass 分批绑定少量状态后执行一段 indirect draw。

第五步是插入同步与资源状态转换。Compute pass 写入的 buffer 在 graphics pass 中读取时,必须建立写后读可见性和资源状态转换。Vulkan 中表现为 pipeline stage、access mask 和 buffer memory barrier 的组合;Direct3D 12 中表现为 resource barrier、UAV barrier 或 queue synchronization;Metal 中表现为 encoder 顺序、resource usage 和 fence/event 语义。跨 API 渲染层不应把 barrier 写成“通用刷新动作”,应记录写入 pass、读取 pass、资源 usage、队列归属和访问类型。

第六步是执行 GPU-driven draw。这个 draw 仍然需要合法的 pipeline state、descriptor、vertex/index buffer 和 render target。Compute-driven 只改变“draw 数量和参数由谁决定”,并不会自动解决材质排序、shader variant、透明排序或 render target 带宽。构建管线时要把可见性、命令生成、状态分组和着色成本同时纳入 frame graph。

下面是一条更接近 frame graph 的简化顺序。它展示每个 pass 的输入输出,而非 API 调用细节。

Pass UploadFrameConstants
writes CameraBuffer, FrameParams

Pass BuildDepthPyramid
reads PreviousDepth or PrepassDepth
writes DepthPyramid

Pass CullAndSelectLOD
reads ObjectBounds, TransformBuffer, CameraBuffer, DepthPyramid
writes VisibleFlags, LODResults

Pass CompactVisibleObjects
reads VisibleFlags, LODResults
writes VisibleObjects, VisibleCount

Pass BuildIndirectDraws
reads VisibleObjects, MeshMetadata, MaterialTable
writes IndirectDraws, DrawCount, MaterialBins

Pass MainRaster
reads IndirectDraws, DrawCount, VisibleObjects, VertexBuffer, IndexBuffer, MaterialTable
writes ColorTarget, DepthTarget

这段伪代码的检查重点是每条边。CullAndSelectLOD 写出的结果经过 CompactVisibleObjects 才能被 BuildIndirectDraws 稳定消费;BuildIndirectDraws 写出的 indirect buffer 要在 MainRaster 前完成写后读同步;MainRaster 的 draw 事件要能通过 firstInstance 或同等字段找到 VisibleObjects 中的对象信息。只要某条边没有明确格式、状态和使用范围,Compute-driven 管线就会在调试时变成黑盒。

调试路径应从 buffer 内容开始。先查看 visible count 是否符合相机位置预期,再查看 visible record 中的 object id、LOD id、material id 是否落在合法范围,接着查看 indirect command 的 index count 与 first index 是否对应 mesh metadata,最后在 draw event 中检查 descriptor、vertex buffer、index buffer 与 shader 读取路径。这个顺序能把问题限定在 culling、compaction、command generation、barrier 或 raster consume 中的某一段。

111.4 混合管线调度策略

混合管线调度要解决 Compute 与 Graphics 的执行顺序、资源依赖和队列选择。最稳妥的基础方案是同一 graphics queue 内顺序提交:depth prepass 或上一帧深度输入先准备好,compute culling 写出可见列表与 indirect commands,随后 barrier,最后 graphics pass 读取命令并渲染。这个方案同步简单,工具捕获也更容易解释,适合作为第一个可工作的版本。

当 compute 工作与 graphics 工作有重叠空间时,可以考虑 async compute。可重叠的前提是 compute pass 的输入已经准备好,输出不会马上被当前 graphics pass 读取,GPU 有独立调度资源,并且内存带宽没有被同时段 graphics pass 占满。粒子模拟、上一帧可见性预处理、light list 构建、部分后处理准备工作更容易形成重叠;当前帧主相机 culling 通常会被主 raster pass 立即消费,重叠空间较小。

同队列调度的典型顺序如下:CPU 更新 frame constants;graphics pass 生成 depth prepass 或复用上一帧 depth pyramid;compute pass 执行 culling、LOD 和 command generation;barrier 把 indirect buffer 和 visible list 转成 graphics read;graphics pass 执行 indirect draw;后处理继续读取 color/depth。这个顺序的优点是依赖清楚,缺点是 compute 阶段处在 raster 前的关键路径上。若 compute 变慢,主渲染会直接等待。

多队列调度需要把等待点显式化。假设 async compute queue 更新粒子并生成粒子 indirect draw,graphics queue 同时渲染静态不透明物体。粒子 pass 的输出在透明 pass 前被读取,因此两个队列只需要在透明 pass 前同步。这个设计能让粒子更新与不透明渲染重叠。若粒子更新同时读取不透明 pass 的 depth,则依赖方向变成 graphics 先写 depth、compute 后读 depth、graphics 再读粒子输出,队列切换和同步点会增加。

调度策略还要处理资源所有权。Vulkan 多队列可能涉及 queue family ownership transfer;Direct3D 12 多队列需要 fence 建立跨队列顺序;Metal 的不同 command buffer 或 encoder 需要通过事件、fence 或提交顺序表达依赖。抽象层应记录资源在哪个 pass 写入、在哪个 queue 写入、下一次在哪个 pass 读取。只记录“当前状态是 UAV”这类局部状态,无法解释跨队列等待。

混合管线中常见的稳定做法是把关键路径和可延迟路径分开。主相机静态几何 culling 与 indirect draw 属于关键路径,目标是控制最坏耗时和 barrier 数量;粒子模拟、草场动画、远景 impostor 更新、阴影级联中远级别 culling 属于可延迟路径,可以使用上一帧结果、分帧更新或 async compute。这样调度时不会把所有 compute 工作堆到主 raster pass 前。

fallback 路径也是调度策略的一部分。某些平台没有 indirect count、某些移动 GPU 对大量 UAV 写入和全局同步敏感、某些 Web 环境的功能子集受安全和实现约束影响。引擎应保留 CPU culling、固定最大 draw count、分批 indirect draw 或普通 instancing 路径。fallback 的目标是让功能在能力较弱的平台上保持正确输出,再按 profile 开启更激进的 GPU-driven 路径。

111.5 性能对比与评估方式

评估 Compute-driven rendering 时,先拆分收益来源,再拆分新增成本。收益来源包括 CPU traversal 减少、CPU draw submission 减少、GPU 端可见性复用、实例数据更新留在 GPU、远距离对象和小物体的绘制减少。新增成本包括 compute dispatch、bounds 读取、depth pyramid 读取、atomic 或 scan、indirect buffer 写入、barrier、额外 buffer 占用、工具调试成本和状态分组复杂度。

CPU culling、GPU culling、indirect draw、mesh shader 的比较要放在同一组对象上看。CPU culling 适合对象数量有限、可见性规则复杂且 CPU 已经拥有完整场景结构的场景;GPU culling 适合对象数量高、规则可并行、数据已常驻 GPU 的场景;indirect draw 适合 draw 数量随可见性变化明显且 API 支持稳定的场景;mesh shader 适合把 meshlet 级 culling、amplification 和几何生成合并到更靠近 GPU 前端的路径,但它受硬件、API 和工具支持边界约束。

评价顺序可以固定为五步。第一,看 CPU frame profile 中 scene traversal、render item build、command recording 和 API submit 的耗时。第二,看 GPU frame profile 中 compute culling、compaction、barrier、raster pass 的耗时。第三,看对象数量、可见数量、draw count、visible ratio 和 LOD 分布。第四,看内存指标,包括 bounds buffer 读取、indirect buffer 写入、depth pyramid 采样、render target bandwidth 和 cache hit。第五,看画面正确性,包括 pop、LOD 抖动、遮挡错误、粒子丢失和透明排序问题。

下表是一个示例预算,用来说明判断方法;它不是硬件测试数据。

路径CPU submit / buildGPU cullingBarrier 与间接读取主 raster适合结论
CPU culling + normal draw5.0 ms0 ms0 ms4.0 msCPU 已成瓶颈时收益空间大
GPU culling + indirect draw0.8 ms1.2 ms0.3 ms4.2 ms总帧耗时下降,适合继续优化
GPU culling + 状态未分组0.9 ms1.2 ms0.4 ms6.0 ms状态和材质分布抵消可见性收益
Mesh shader / meshlet path0.7 ms合入 mesh stage0.2 ms3.8 ms依赖硬件能力和 meshlet 资产管线

这个表的关键判断是总帧路径,而非单项指标。第二行中,CPU submit 从 5.0 ms 降到 0.8 ms,新增 GPU culling 和 barrier 共 1.5 ms,主 raster 变化很小,总体收益明确。第三行显示状态分组失败时,raster pass 因材质切换、descriptor 访问或 shader divergence 增长,吞掉了 culling 收益。第四行看起来更好,但它引入 meshlet 构建、硬件 feature detection、fallback、工具支持和资产验证成本。

对象数量和可见比例决定收益上限。若场景只有几百个对象,CPU 直接筛选与提交的成本可能低于 GPU culling 的 dispatch 与 barrier。若场景有几十万个对象但大多数可见,GPU culling 减少的 raster 工作有限,收益更多来自 CPU submit 减少。若场景有大量被遮挡小物体,depth pyramid culling、LOD 和 compaction 会产生更明显收益。这里的判断要用实际 frame capture 和 counter,而不是按对象总数下结论。

带宽是 Compute-driven 路径最容易被低估的成本。每个对象读取 bounds、transform、mesh metadata;每个可见对象写 visible record、LOD result、indirect command;后续 raster 又读取这些结果。数据布局分散、record 过大、随机访问材质表、counter 争用严重时,compute pass 会从并行筛选变成内存带宽瓶颈。优化顺序应先缩小 record、按 pass 拆 buffer、使用连续访问,再考虑更复杂的 scan 或 binning。

最终评估要形成可迁移决策:CPU 侧先确认 submit 与对象遍历成本,GPU 侧再确认 culling 与 barrier 成本,资源侧确认 buffer 格式与内存访问,画面侧确认可见性和 LOD 稳定,平台侧确认 indirect draw、indirect count、mesh shader 或 fallback 支持。只有这些证据同时支持,Compute-driven rendering 才是工程收益明确的管线升级。

最小自检任务

有一个场景包含二十万个静态小物体和三万粒子。CPU 驱动版本中,主线程每帧对象筛选与 draw 构建耗时 5.0 ms,graphics pass 光栅化耗时 4.0 ms。改成 GPU culling 后,CPU 提交下降到 0.8 ms,compute culling 与 LOD 耗时 1.2 ms,compaction 与 indirect command generation 耗时 0.6 ms,barrier 与间接读取耗时 0.3 ms,主 graphics pass 变为 4.2 ms。请判断这条 Compute-driven 管线是否值得保留,并写出你会检查的三个 GPU buffer 或 counter。

答案要点

这条管线值得保留。原路径中 CPU 对象筛选与 draw 构建为 5.0 ms;新路径把这部分降到 0.8 ms,同时新增 GPU compute、compaction 和 barrier 共 2.1 ms,主 graphics pass 只增加 0.2 ms。按这组数据估算,帧内关键路径减少约 2.7 ms,收益来自 CPU submit 下降和对象级决策留在 GPU。

需要检查的第一个对象是 visible count 或 draw count buffer。它回答“compute pass 实际生成多少可见对象和 draw”,并能发现 culling 过严、过松或 counter 未清零。第二个对象是 visible object / LOD buffer。它回答“每个可见对象对应哪个 object id、LOD id、material id 和 mesh id”,并能定位 LOD 抖动、对象丢失和材质索引错误。第三个对象是 indirect command buffer。它回答“raster pass 实际读取的 index count、instance count、first index、first instance 是否合法”,并能把问题分到 command generation 或 graphics consume。

必要边界是:这组数据只证明当前场景和当前平台收益明确。若切换到对象数量较少、可见比例接近百分之百、材质状态极度碎片化或 indirect count 支持较弱的平台,应重新比较 CPU submit、GPU culling、barrier、raster pass 和画面稳定性。

本章知识点总结

  • 核心定义:Compute-driven rendering 让 compute pass 在 GPU 端生成可见列表、LOD 结果、间接命令或实例数量。
  • 收益来源:收益主要来自 CPU 对象遍历和 draw 提交下降,以及 GPU 端数据在 pass 间直接复用。
  • 适用前提:对象数量高、决策可并行、数据常驻 GPU、compute 输出能被 raster pass 直接消费时,Compute-driven 路径更容易成立。
  • 资源合同:visible list、LOD buffer、indirect command buffer、counter buffer 和 material bin 是 compute 与 graphics 的交接合同。
  • 光栅结合:compute 负责筛选、压缩和命令生成,graphics pass 负责按合法 pipeline state 消耗这些结果并完成着色输出。
  • 管线构建:GPU scene data、visibility buffer、compaction、indirect command generation、barrier 和 GPU-driven draw 构成最小闭环。
  • 同步边界:compute 写出的 buffer 被 graphics 读取前,需要明确访问类型、资源状态、队列归属和写后读可见性。
  • 调度策略:同队列顺序提交适合建立稳定版本,async compute 适合输入已准备且输出稍后消费的任务。
  • 性能评估:评估顺序应覆盖 CPU submit、GPU compute、barrier、draw count、内存带宽、主 raster 和画面正确性。
  • 比较边界:CPU culling、GPU culling、indirect draw 和 mesh shader 要按对象数量、可见比例、平台能力和资产管线一起比较。
  • 调试入口:先查 visible count,再查 visible record,接着查 indirect command,最后检查 draw event 的资源绑定和 shader 读取。
  • 最终判断:Compute-driven rendering 是数据路径和命令生成方式的改变,只有证据显示总帧路径受益时才应进入正式管线。