HSR(Hidden Surface Removal)技术的概念和原理其实真的非常简单,没有多深奥。
介绍HSR之前先简述一下EarlyZ。EarlyZ优化已经是现代GPU的标准流程了,简单来说就是当不透明的图元从Rasterize阶段开始逐像素进行处理时,首先进行Depth Read & Test,通过后直接Write,后续再执行该像素上的PS程序,否则就可以停下来休息等待下一个要处理的像素了。后续又进一步对于那些在PS阶段会改变深度写入的图元(有discard/clip指令或有ZOffset)加入了 Depth Read & Test -> PS -> Depth Read & Test & Write 流程。总之简单一句话就是,绘制前先做深度检测,减少不必要的绘制。
这也是为什么我们在渲染不透明物体时要按从近到远的顺序去绘制,因为近处的物体先绘制好之后,其写入的深度会阻挡住后面物体的ZTest,也就避免了后面物体无意义的渲染开销。
基于EarlyZ是无法完全的避免Overdraw的。这是因为我们在真正对一个复杂场景去渲染的时候是不可能进行严格的由近到远的绘制的。一个面积很大的地块与远处的物体相比谁应该算“近”呢? 一个有凹面的物体,其上每个图元的的渲染顺序也会因视角不同而会出现先绘制远处三角面再绘制近处的情况。想把物体拆碎?那意味着drawcall增加。完全严格的前后物体排序?那很可能意味着Shader切换次数的增加。
基于硬件EarlyZ特性对渲染物体进行排序优化对于移动GPU也是同样适用的 —— 除了PowerVR,因为人家真正的TBDR渲染框架能做得更好。
这里HSR登场了,不需要在软件层面对物体进行排序,HSR在硬件上实现了零Overdraw的优化。原理也超简单,当一个像素通过了EarlyZ准备执行PS进行绘制前,先不画,只记录标记这个像素归哪个图元来画。等到这个Tile上所有的图元都处理完了,最后再真正的开始绘制每个图元中被标记上能绘制的像素点。这样每个像素上实际只执行了最后通过EarlyZ的那个PS,而且由于TBR的机制,Tile块中所有图元的相关信息都在片上,可以极小代价去获得。最终零Overdraw,毫无浪费,起飞。
最后说一下HSR是怎么处理AlphaTest和AlphaBlend的。HSR在设计原理上高到飞起,但前提是假定了前面的物体会挡住后面的物体,因此对于AlphaTest和AlphaBlend物体都是没有作用的(但他俩仍然可以被EarlyZ拦住)。不仅没作用,反而会被其中断Defer流程,导致渲染性能降低。(这里要加黑强调一下,所谓导致渲染性能降低只是与不透明物体相比较降低了,而不是说PowerVR在处理AlphaTest/Blend时比别的GPU慢。打个比方:原来大家都走路,PowerVR骑自行车,现在遇到AlphaTest,PowerVR会改成下来推车走)
如果在HSR处理不透明物体的过程中突然来了一个AlphaTest的图元,那么为了保证渲染结果正确,HSR就必须要终止当前的Defer,先把已标记好的像素都绘制出来,再进行后面的绘制。这显然严重影响了渲染的效率,也是为什么官方文档特意提到尽量避免AlphaTest的原因。相对应的AlphaBlend同样也要中断HSR的Defer,强制开始绘制,但是比AlphaTest好那么一点点的是他不影响后续图元并行地继续开始进行HSR处理,有兴趣可以参考下面的官方技术文档链接。
https://docs.imgtec.com/PowerVR_Architecture/topics/powervr_architecture_per_tile_rasterization__renderer.html
https://docs.imgtec.com/PowerVR_Architecture/topics/powervr_architecture_hidden_surface_removal_efficiency.html
最后总结下,在PowerVR上渲染,因为有HSR的存在我们只需要把所有不透明物体放到一起扔给GPU画就行了;在其他移动GPU上,同样也是要把所有不透明物体放到一起,但是还要先做个排序再交给GPU。
本文摘自:知乎 - Sparrowfc
原文链接:https://zhuanlan.zhihu.com/p/112120206
转载此文目的在于传递更多信息,版权归原作者所有。