[Siggraph15] GPU-Driven Rendering Pipelines

[Siggraph15] GPU-Driven Rendering Pipelines

GPU-Driven Rendering Pipelines


GPU来掌控哪些实际渲染的物体

-切换viewport/frustum

-GPU更细粒度的Visibility

-不需要CPU/GPU的来回传递数据

动机:

RedLynx

User generated content(UGC)

-内容服务器下载,需要精简尺寸

-没法预烘焙

-非常细小的module组合

-超远视距

-shadowmap造成dp膨胀

-物理模拟/脚本系统CPU开销大

Assassin’s Creed Unity

-超多几何物体

-内部建筑无缝读图

-大量人群

-模块化半自动生成内容(大量dp)

Mesh Cluster Rendering

-Fixed topology (64 vertex strip,64 thread per wavefront)

-重整所有mesh来适应cluster(包括degenerated triangle)

-从vs中读取shared buffer来获取顶点(不需要setVB/IB)

-DrawInstancedIndirect(节省大量CPU time)

-GPU culling输出cluster list以及drawcall参数

-一个dp任意多的模型

-GPU使用cluster bounds来cull

-cluster可以做depth sorting来避免overdraw

Cons:

-Memory increase due to degenerate triangles

-Non-deterministic cluster order(会造成z-fighting)

Overview

1. CPU使用coarse quad tree culling

2.CPU update GPU数据

-instance data:

*比如transform/LOD factor/…

*每个instance使用8 offsets去索引数据,比如vb location/extents/transform

*对于static mesh,这些数据是永久的

-对于非instance data建立hash

*比如material/renderstate/…

-使用这些hash来merge drawcall

*merge之前,会sort by distance drawcall

3. Batch Drawcall

4. Instance culling

-instance stream包含了GPU-buffer per instance的数据,比如transform/instance bounds等(ExecuteIndirect)

-GPU做frustum和occlusion,对于通过的instance生成cluster chunk

5. Cluster chunk expansion

-使用中间数据chunk的原因是,每个instance展开的cluster数量方差太大(1-1000),直接展开会造成wavefront计算资源不平均,每个chunk可以展开64个clusters

6. Cluster culling

这一步使用instance的transform和每个cluster的bounds去做frustum和occlusion culling。对于每个cluster,会在之前预烘焙cluster的view-dependent的朝向mask做backface culling。通过culling的cluster会导出index compact job,其中包含triangle mask和r/w offsets,这些offset根据关联的instance primitive使用atmoic操作生成

7.Index compaction

Index buffer之前在cpu上create的,所以每个mesh的ib都是full unculled。因为compact ib比较小(8MB),所以一次场景渲染可能没法完全存进一个buffer。所以index compaction(ExcuteIndirect)和multi-draw(DrawIndexInstancedIndirect)是交替进行的

每个wavefront处理一个cluster,每个线程处理一个三角形,它们之间是相互独立的。根据之前cluster culling传递的triangle mask和i/o offsets,每个线程计算输出正确的写入位置。这步通常占用5-10%的geometry rendering(G-Buffer pass)

8.Multi-Draw

最后每个batch一个multi-draw,渲染数据

Occlusion Depth Generation

-Pre-Depth pass(~300 best occluders,使用bounds和美术设置的标记作为occluder,选择其中最近的300个occluder)

-Full-res HiZ & EarlyZ

-使用downsample的Z(512*256)

-混合上一帧的depth

*reproject会补充occluder的空洞,但是当镜头移动时,可能还是会出现空洞;如果有太大的快速移动物体时,可能会出现false occlusion,reject镜头附近的occluder来避免这种情况

-HiZ for GPU Culling

Shadow Occlusion Depth Generation

-camera depth reprojection(64*64)

-和上一帧shadowmap混合

*有太大的快速移动物体时也会有问题,但是基本上没有

-Hi-Z for GPU Culling

Camera depth reprojection

-会遮挡掉大部分view中被遮住的caster

Results

-CPU

*节省了1-2个数量级的drawcall

*75%的时间开销,~10倍数量的物体

-GPU

*20-40%的三角形culled

*整体只有<10%的性能提升

*30-80% shadow三角形culled

Virtual Texturing

-256’000*256’000

-128*128 texel

-8k*8k page cache

*5 texture array:
albedo,specular,roughness,normal,etc.

*BC5/BC3

GPU-Driven Rendering with VT

-所有的texture数据一次性全部准备好,只用一次texture binding

-不在需要根据texture来batch

Single Draw Call Rendering

-GPU-driven pipeline可以一次性取得所有mesh data,vt可以取得所有texture,意味着整个场景只需要一次drawcall

-Dynamic branching for different vertex animation types

-可以在cluster的细粒度来sort场景,这样在geometry pass就相当于pre-depth

-cheap OIT using inverse sort

-复杂的材质blend和decal可以直接保存在VT中

-VT自带cache,节省了大量的带宽(可以让关卡设计师随意放置decal,任意使用大量材质,不用关心贴图尺寸数量)

-对UGC特别友好(假设用户没有technical knowledge)

Virtual Deferred Texturing

-下次再说

Two-Phase Occlusion Culling

-跟精确的pixel级别culling

-不用渲染一遍occluder

-只用上一帧的full-res depth

Benchmark

-250’000物体

-1GB mesh数据

-只用两个DrawInstancedIndirect

XB1上的数据,性能好的令人咋舌。。。

PS:15年Ubi刚出GPU-Driven的产品,结果Unity被称为Bug最多的一款AC。。。不过Ubi在游戏技术创新和开拓的精神真的令人 十分敬佩,当年Ubi China是可是中国游戏的黄埔军校啊。16年SIG上Frostbite更进一步,进行了triangle级别的culling以及index compact。NVidia有一篇类似 tech report,CPU的性能优化提升了百倍数量级,随着DX12的到来,CPU的 计算力 算是得到了 更好的解放,不过在GPGPU方面的探索和进步还是有很多值得学习研究的地方。

发布于 2018-02-19

文章被以下专栏收录