VS之后,是光栅化阶段。这个阶段属于固定功能(不可编程)阶段,通常被认为是执行效率很高的,所以往往会被忽视。
其实就我所观察到的情况来言,这部分成为瓶颈的情况,并不罕见。比如《原神》在开发过程当中,就出现过这样的情况。
《原神》当时的情况是,游戏当中当人物爬树的时候,为了避免树冠遮挡人物,会有一个将树冠变成半透明的效果。普通的半透明渲染是已知的性能杀手,所以这里开发商采用了用stencil抠掉一些像素,也就是所谓的dither(抖动)的方法。如果不了解这种方法,可以想象一下报纸上的那些图片,都是一些点状的图案组成的。
按理说,这种镂空会减少需要渲染的像素,也就是PS的工作量。但是开发组发现,最终结果是不降反升。也就是渲染时间反而增加了。而且更加不可思议的是,通过对比开关此效果的GPU跟踪文件,可以观测到PS工作量的确是明显减少,但是渲染时间并没有变化甚至是略微变长了。
其实原因就在于光栅化。VS输出的三角形,在光栅化模块进行光栅化之后,形成PS工作量。在光栅化之前,会进行根据三角形级别的背面/正面剔除、视锥剔除/裁剪,以及零面积/小三角形剔除。但是,基于stencil测试级别的排除,并不是发生在三角形级别,而是发生在光栅化之后的fragment级别。也就是说,dither虽然减少了进入PS阶段的fragment数量,但是并不影响光栅化的工作量。
但是如果仅仅是如此,那么dither开启之后,应该还是快些。因为光栅化工作量一样,但是PS工作量减少,应该是变快的。但是实测是变慢,这又是为什么呢?
这是因为在当代的桌面GPU当中,引入了tile-based rasterization。注意这并不是移动平台的TB(D)R,因为它只限rasterization阶段。
具体来说,GPU并非是一次性将三角形按照渲染分辨率拆解成为fragment,而是以更低的分辨率,比如1/8目标分辨率,进行光栅化。比如,如果我们的画面最终是1920x1080,则GPU首先是以240x145这个分辨率进行光栅化,然后再对每个光栅化结果(8x8像素)进行进一步光栅化。(具体做法及尺寸不同GPU型号可能有显著差异)
这种做法有一个好处,就是可以大幅提高pre Z以及pre Stencil的效率。如果低分辨的一个单位(tile)整体上在pre Z测试或者pre Stencil测试当中被拒绝,那么就没有必要再对其进行更加精细的光栅化。
而在我们这个案例当中的情况是,其使用的Stencil模板,也就是“镂空”的模板,其中洞洞的图案并没有对齐这个tile。也就是说,当以tile为单位去做pre Stencil的时候,永远是无法拒绝(因为tile当中蒙版数值不一样,部分通过部分拒绝)。相比较不开dither的情况,等于是白白多了一个stencil测试但是光栅化的工作量一点儿都没有减少,反而是在光栅化过程当中多了一个查询stencil的步骤。所以光栅化效率反而变低了。
来源:oschina
链接:https://my.oschina.net/u/4255780/blog/4707896