[GDC16] Optimizing the Graphics Pipeline with Compute

Optimizing the Graphics Pipeline with Compute算法


DX12虽然带来了CPU的low overhead,可是依然GPU会卡在tiny draw上。主要是GBuffer的后面半段dp会由于Hi-Z cull掉不少pixel(从近到远draw),并且远处的物体会有大量细节物体。微信

能够看到后半段,大部分只有vs,没有ps invoked闭包

乐观点假设rasterizer每一个cycle能处理2个triangles,实际上xb1是0.9个。由于从VGT->PA使用FIFO队列,因此在4096个cycle中处理完vs填满FIFO队列,才不会使得rasterizer饥饿(怎么算出来的)。在shadow pass的表现最差,由于有部分特别大的triangles,coarse rasterizer对于1个tile只用一个cycle就完成了,因此对于大于32*32像素的三角形须要多个cycle架构

大部分引擎在CPU作coarse culling,再在GPU上refine,由于CPU和GPU之间的延迟,不少优化没法达成。为此会作一些GPU上的culling,包括Depth-aware culling,late-latch culling以及本篇讲的cluster/triangle culling并发

CS处理mesh带来了一系列好处,最主要的思想就是把drawcall看作data,这些GPU生成的数据能够pre-built,cached以及reused异步

Overview 以前Ubi的GPU-Driven差很少,略过ide

相互交叉vb的各个attribute会带来更好的性能。对于compute cull,不用关心其余数据(uv,tbn等),这样stride就是一个固定值没有任何状态切换。对于vertex数据的cache也更加友好,以前cacheline须要保存很大一块数据,如今用完相应的数据能够直接invalid cacheline。另外一方面,对于CPU的数据也由SoA变为了AoS,更加适合SSE。并且能区分容易改变的和固定的数据,好比pos+uv(画shadow),skin data等。分开的好处还有一个就是能够自由重建indexbuffer,对于depth only pass,只须要pos数据,能够re-use更多的顶点(正常绘制的时候,pos同样可是uv和normal可能不同 )性能

Cluster Culling。事先使用贪心算法把mesh分红256个triangle一组的clusters,对于每一个cluster预烘焙一个bounding cone,作法是对这256个法线投到球上,作一个最小闭包的椎体。4个8bit channel的SNorm的精度足够了,只须要判断视线和cone normal的夹角是否小于cone的张角。为了不false reject张角能够大一些,还能够对normal进行GBuffer经常使用的encode测试

Occlusion用的是bounding sphere vs bounding box(HiZ),注意在透视投影中sphere会变成ellipsoid优化

在133us开始,由于index为空因此遇到了empty draw,151us连续10us空闲,实际由于流水打断须要从新填满,因此性能损失超过10us。从中能够看出compact index的重要性

DX12新潮作法

通用作法,在cs中作parallel reduction,在GCN架构中还有其余奇技淫巧

Parallel prefix sum

Ballot 64bit表明每一个thread的状态

利用这个

MBCNT计算以前几个thread的bit累加

两个结合起来,获得了prefix sum

看代码好懂

每一个thread处理一个triangle,经过的culling的会使用刚才的技巧来得到当前triangle的compact index。对于wavefront之间若是想作半透排序等,须要使用ds_ordered_count来保证wavefront之间的输出顺序。

对于if branch编译器会作优化来进行divergence execute,实际上没什么必要,只有在须要rw的时候才进行branch,好比Hi-Z cull

理论上50%的triangle会被back-face culling,因此须要用效率最高的算法

Tessellation patch back face cull略,没接触过

越小的triangle对于raster来讲效率越低,由于卡在primitive setup上,raster一直饥饿

这个挺有用的,对于raster的效率能够写段可视化代码测试,对于每个triangle会对应一个wavefront来处理其raster以后的pixel,那么输出每一个wavefront中真正有效pixel的thread占比,就能够看出是否有太多的琐碎triangle,另外也能够测试LOD的设置是否合理

Small primitive cull的几种状况

Frustum culling,只作4个plane保守cull

一种方法是若是当前triangle或者cluster的bb彻底在tile内,那么判断是否reject,不然保守保留

在作16*16的depth reduction,各类优化41us,对于其余的好比light tile也使用一样的代码

另一种方法,也是frostbite用的就是hierarchical Z pyramid,根据triangle的bb去选择mipLevel,直接对比depth

AMD HTILE主要就是能够8*8的depth只用32bit,一个test能够reject64个pixel。由于是console spec的,后面略

可使用CPU的软光栅化ZBuffer

使用固定大小的buffer,每次生成大概3MB的indexbuffer,错开dispatch&draw,更好利用异步来并发流水

起步并非太好

能够作一些其余计算

44w面->9w面

GPU 性能提高15%-30%

Tessellation提高更多40-80%

More:【微信公众号】 u3dnotes 

本文分享自微信公众号 - Unity3D游戏开发精华教程干货(u3dnotes)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。

相关文章
相关标签/搜索