小伙伴关心的问题:为什么要合并一本 *** (为什么要合并一本二本学校),本文通过数据整理汇集了为什么要合并一本 *** (为什么要合并一本二本学校)相关信息,下面一起看看。

为什么要合并一本 *** (为什么要合并一本二本学校)

由于本人并没有从事过图形API及驱动层的工作,关于这两部分的内容更多的是查阅各种资料,如果有说的不对的地方还请专业人士指出,以免误人子弟。

首先合并Draw Call这个说法并不准确,准确的说法应该叫合并Batch,Batch = Set Render State + Draw Call。

我们先来看一组测试数据,测试环境是只有Set Render State和Draw Call有性能消耗。

这是Nvidia在很久之前做的测试,虽然它很老,但是能说明问题。从上图中可以看到当triangles/batch小于130的时候,每秒处理的三角形数量随着triangles/batch的增加而增加,并且与显卡型号没有关系。简单理解就是GPU不背这个锅,是你CPU的问题。为什么过多的batch调用会耗费CPU的性能呢?

首先更多的函数调用肯定会消耗CPU端的性能,但是这不是主要原因,主要原因是Set Render State和Draw Call都是GPU需要的渲染指令,这些指令首先会存储在Command Buffer中,Command Buffer由图形API维护,它被分配在用户私有内存中,它不会被GPU直接访问,格式是由硬件供应商提供的。当一个Command Buffer被存满,或者发生以下事件时,Command Buffer会被提交到DMA buffer中:

调用Present调用FlushCommand Buffer中使用的某个资源被lock

DMA Buffer由驱动层维护,它被分配在操作系统内核管理的内存中,因此想要将Command Buffer拷贝到DMA Buffer需要将应用的权限提升到内核态,这是一个比较大的消耗。

在GPU读取DMA Buffer之前,驱动层需要先锁定DMA Buffer,然后映射给GPU。

另外GPU读取DMA Buffer之前,驱动层需要保证DMA Buffer中使用的资源已经上传到GPU中,如果调度程序发现某些资源没有在GPU中,需要先加载资源然后再读取DMA Buffer。这也是为什么单线程渲染中CPU会被GPU阻塞的原因之一。

了解了上面的流程,自然就知道为什么过多的batch会耗费CPU端的性能了。因为驱动层上传指令需要做很多工作,经过测试大部分的性能消耗是在驱动层,78% driver,14% D3D,6% Other32。

如果batch中的三角型数量过少,也会让GPU处于饥饿状态,因此合并Batch,不仅降低了CPU的性能消耗,也提高了GPU的使用率。

GPU都是按照Draw Call来执行渲染管线,如果Batch中的渲染状态发生了变化,那么下一个Draw Call就需要等待上一个Draw Call执行完毕后才能执行,这就会在渲染管线中产生气泡,降低GPU的使用率。现代GPU架构通常会将管线进行细分,尽量只刷新部分管线。所以我们在合并渲染状态的时候,要先合并影响管线最多的状态,通常是RT切换>shader切换>其他。如果GPU是性能瓶颈,那么合并渲染状态就是非常重要的优化手段。

性能优化有各种各样的手段,基本上可以分为以下几类:

合并Batch,尽量保证Batch的一致性,这样既可以提升CPU的性能又可以提升GPU的性能。

保持平衡,渲染管线中任何一个环节出现瓶颈都会影响整个管线,如果CPU是瓶颈,就将CPU的功能往GPU中移,反之如果GPU是瓶颈就往CPU中移。GPU渲染管线也是一样,如果一个阶段成为瓶颈,想办法用其他阶段来平衡。

Latency hiding,隐藏延迟,GPU是高延迟,高吞吐的硬件,我们需要尽量隐藏延迟,这里的隐藏延迟通常是指使用计算来填补内存读取的延迟。举个例子如果shader中使用更少的寄存器,那么就可以有更多的寄存器来存储线程数据,也就可以启动更多的线程来隐藏内存的读写。

不做无用功,使用各种剔除技术,减少overdraw。

以少替多,各种LOD技术,比如先将特效渲染到低分辨率的贴图中,然后再合并到屏幕中。

给shader编译器更多的提示,比如DX12指定资源使用的阶段,splite resource barriers。

更多为什么要合并一本 *** (为什么要合并一本二本学校)相关信息请关注本站,本文仅仅做为展示!