关于图形,我意识到我几乎不知道它们是什么。我要记住,如果我们按成本排序,则状态更改类似于:
着色器均匀更改。更改。
活动着色器程序更改。
活动帧缓冲区更改。数量级是多少。如果我们尝试放置单位,ns,时钟周期或指令数,那么我们在谈论多少?
#1 楼
我所看到的关于各种状态变化的相对代价的最多数据来自于卡斯·埃弗里特(Cass Everitt)和约翰·麦克唐纳(John McDonald)自2014年1月以来关于减少OpenGL API开销的演讲。他们的演讲包括这张幻灯片(31:55):这次演讲并没有提供有关他们如何衡量这一点的更多信息(甚至是他们正在衡量CPU或GPU成本,或两者都不计!)。但这至少与传统观点相吻合:渲染目标和着色器程序更改最昂贵,统一更新最少,中间有某个位置的顶点缓冲区和纹理更改。他们其余的演讲在减少状态更改开销方面也有很多有趣的智慧。
#2 楼
任何特定状态更改的实际成本因多种因素而变化,以至于几乎不可能回答。首先,每个状态更改都可能同时具有CPU端成本和GPU端成本。根据驱动程序和图形API的不同,CPU成本可以全部在主线程上支付,也可以部分在后台线程上支付。
其次,GPU成本可能取决于进行的工作量。现代GPU的流水线非常多,并且喜欢一次完成大量的工作,而最大的减慢就是停止流水线,以便当前飞行中的所有内容必须在状态改变之前退役。什么会导致管道停顿?好吧,这取决于您的GPU!
了解此处性能的实际需要知道的是:驱动程序和GPU需要做什么来处理状态变化?当然,这取决于您的GPU,还取决于ISV通常不公开共享的细节。但是,有一些通用原则。
GPU通常分为前端和后端。前端处理驱动程序生成的命令流,而后端则完成所有实际工作。就像我之前说过的那样,后端喜欢进行大量工作,但是它需要一些信息来存储有关该工作的信息(可能由前端填写)。如果您踢出足够多的小批量并用完所有硅片来跟踪工作,那么即使周围有许多未使用的马力,前端也将停顿。所以这里的原则是:状态变化(绘制次数少)越多,您越可能使GPU后端饿死。在实际处理绘制时,您基本上只是在运行着色器程序,这些程序正在进行内存访问以获取制服,顶点缓冲区数据,纹理以及告诉着色器单元顶点缓冲区所在位置的控制结构以及您的纹理是。 GPU在这些内存访问之前也具有缓存。因此,每当您在GPU上抛出新的制服或新的纹理/缓冲区绑定时,第一次读取它们时就可能会发生缓存丢失。另一个原则:大多数状态更改将导致GPU缓存未命中。 (这在您自己管理常量缓冲区时最有意义:如果在绘制之间保持常量缓冲区相同,则它们更有可能留在GPU的缓存中。)
很大一部分着色器资源的状态更改成本为CPU端。每当您设置新的常量缓冲区时,驱动程序很可能会将该常量缓冲区的内容复制到GPU的命令流中。如果您设置一个单一的制服,驱动程序很可能会将其变成背后的大常量缓冲区,因此它必须在常量缓冲区中查找该制服的偏移量,将值复制进去,然后标记常量缓冲区因为它很脏,所以可以在下一个绘制调用之前将其复制到命令流中。如果绑定新的纹理或顶点缓冲区,则驱动程序可能正在为该资源复制控件结构。另外,如果您在多任务操作系统上使用离散GPU,则驱动程序需要跟踪您使用的每个资源以及在您开始使用它时,以便内核的GPU内存管理器可以确保该资源的内存位于GPU的内存中。绘制时的VRAM。原理:状态更改使驱动程序随机移动内存以为GPU生成最小的命令流。
更改当前着色器时,可能会导致GPU缓存未命中(它们也具有指令缓存!)。原则上,CPU工作应仅限于在命令流中放置一个新命令,说“使用着色器”。但是,实际上,要处理的着色器杂乱无章。即使您提前创建了着色器,GPU驱动程序也经常会懒惰地编译着色器。但是,与该主题更相关的是,GPU硬件本身不支持某些状态,而是将其编译到着色器程序中。一个流行的例子是顶点格式:可以将它们编译到顶点着色器中,而不是在芯片上处于单独的状态。因此,如果使用以前未与特定的顶点着色器一起使用的顶点格式,则现在可能要花费大量CPU成本来修补着色器并将着色器程序复制到GPU。此外,驱动程序和着色器编译器可能合谋做各种事情来优化着色器程序的执行。这可能意味着优化统一和资源控制结构的内存布局,以便将它们很好地打包到相邻的内存或着色器寄存器中。因此,当您更改着色器时,它可能会使驱动程序查看已绑定到管道的所有内容,并将其重新打包为新着色器的完全不同的格式,然后将其复制到命令流中。原理:更改着色器会导致大量CPU内存拖移。
帧缓冲区的更改可能与实现最相关,但是在GPU上通常非常昂贵。您的GPU可能无法同时处理对不同渲染目标的多个绘制调用,因此可能需要暂停这两个绘制调用之间的管道。它可能需要刷新缓存,以便以后可以读取渲染目标。它可能需要解决图纸期间已推迟的工作。 (积累深度缓冲区,MSAA渲染目标等的单独数据结构是非常普遍的。当您离开该渲染目标时,可能需要最终确定。如果您使用的是基于图块的GPU就像许多移动GPU一样,当您离开帧缓冲区时,可能需要清除大量实际的着色工作。)原理:更改渲染目标在GPU上非常昂贵。确保所有这些都非常令人困惑,并且不幸的是,很难做到过于具体,因为细节通常不是公开的,但是我希望这是当您调用某些状态更改功能时实际上正在发生的某些事情的半透明的概述在您最喜欢的图形API中。
评论
$ \ begingroup $
我选择此答案是因为它给出了数量级,这是迄今为止我所问的最接近的数量级,即使上述来源并未给出太多解释。
$ \ endgroup $
–朱利安·盖尔特(Julien Guertault)
2015年8月9日在23:42