UE_GPU Driven Pipeline & Mesh Shader(meshlet)

学习UE源码过程中,涉及到好多未知新概念(可能以前实现过,但不知),本系列将针对UE源码学习过程中所有遇到的知识点进行总结归纳。

一、GPU Driven Pipeline

相关文章:GPU-Driven Rendering Pipelines:http://advances.realtimerendering.com/s2015/aaltonenhaar_siggraph2015_combined_final_footer_220dpi.pdf

Optimizing the Graphics Pipeline with Compute: https://frostbite-wp-prd.s3.amazonaws.com/wp-content/uploads/2016/03/29204330/GDC_2016_Compute.pdf

GPU Driven Rendering Pipeline的产生和发展得益于图形API和硬件的发展(DX12 & Vulkan),具体来说,有两个至关重要特性:

  • Compute Shader: CS允许我们在GPU上方便地执行各类和渲染无关的GPGPU运算,并且将计算结果以Buffer或者Texture的形式存储在VRAM上。
  • **ExecuteIndirect:**间接绘制允许我们以GPU Buffer的形式直接构建Draw Command List。

这两者结合起来,就表示我们能够在Compute Shader里构造Draw Command List用于绘制,整个过程无需CPU参与

传统的GPU Driven Pipeline,剔除依赖CS,剔除的数据通过VRAM向顶点处理管线传递,如下图所示:

在这里插入图片描述

先抛开具体实现细节,回到我们最初引入剔除的初衷:我们希望GPU知道哪些物体是不需要被渲染的(视锥之外,被完全遮挡),这个信息仅供GPU使用;此外,剔除算法的并行性很好,计算过程又相对简单,没有太多的分支和跳转,非常适合GPU去做。为此,我们只需要将场景的所有渲染资源(包括几何信息,材质信息,变换信息,包围盒信息)以一定规则打包存储在Buffer中,然后提供摄像机(视锥)信息和遮挡体绘制的Z-Buffer(类似于Software Rasterization的Z-Buffer),通过Compute Shader去执行视锥剔除和遮挡剔除,并将通过剔除的模型经由ExecuteIndirect提交渲染。

具体执行的时候,得益于GPU强大的浮点数计算能力,我们可以做比模型更细粒度的剔除:将Mesh切分成Cluster,每个Cluster有64个顶点,并且重排IndexedBuffer(Cluster大小的选取以及重排IB主要是为了提高Vertex Fetch时缓存的命中率,进而提高Vertex Fetch的速度),基于Cluster计算包围盒,利用Cluster Bouding Box去做视锥剔除。

Mesh Cluster Rendering如下:
在这里插入图片描述
GPU使用cluster bounds来cull 如下:

在这里插入图片描述

对于遮挡剔除,在构造用于剔除的hierarchy Z-buffer的时候,也能够利用比software rasterization更快的hardware rasterization在GPU端去做:

  • 构造Hi-Z的过程,首先基于美术指定的大遮挡体和地形去渲染一个Z-Buffer,然后down sample到低分辨率,混合上一帧Z-Buffer经过reprojection的结果,最后做一系列down sample得到一个层次Z-Buffer的结构

不同于Software Rasterization的方法,Hi-Z意味着我们可以从最粗粒度的Z-Buffer开始进行遮挡查询和剔除,相较于全分辨率的遮挡查询,这样的查询效率更高。

除了常用的Frustum Culling和Occlusion Culling,我们还可以在Compute Shader里去做Backface Culling和Small Primitive Culling,把背面的三角形和面积很小的三角形剔除掉

在剔除工作完成后,通常会启动一个Compaction的Compute Shader,这个Shader会把通过culling的所有triangle复制到一个更紧凑的Buffer里面,并且执行一些基于材质Batch的合并策略。最后调用ExecuteIndirect来渲染最终场景:
在这里插入图片描述

GPU Driven Rendering Pipeline的核心思路是减少CPU和GPU之间的通信,尽量将所有渲染相关的事务(包括提交)都放在GPU端(自己的事情自己做),解放CPU的算力用于构造物理和AI的规则。同时,利用GPU的算力能够更精细粒度地去控制渲染命令队列内的生成和合并。在实际渲染时,除了我们这里提到的基于Compute Shader的Culling和Batching,还需要辅以Virtual Texturing,Mega Texture等技术并对渲染管线做配套改造,对原本的渲染引擎架构改动也较大,想要把这一技术植入引擎中并不容易。

总的看来,GPU driven pipeline是有两个部分:

  • 剔除:GPU执行剔除操作

  • 提交:目标是使用一个drawcall,多个indirectdrawcall执行完成

在这里插入图片描述
具体见:Vulkan_基于GPU的视锥体剔除和LODVulkan_间接绘制(vkCmdDrawIndexedIndirect)

二、Mesh Shader(meshlet)

相关文章如下:

Mesh Shading: Towards Greater Efficiency of Geometry Processing :http://advances.realtimerendering.com/s2019/Mesh_shading_SIG2019.pptx

Introduction to Turing Mesh Shaders:https://developer.nvidia.com/blog/introduction-turing-mesh-shaders/

网格着色器(Mesh Shader)是NVIDIA Turing GPU引入的功能。网格着色管线取代了常规的VTG管线(VTG =V顶点/T细分/G几何)。
下图展示了网格着色管线与常规的VTG管线的对比:

在这里插入图片描述
具体实现可以参照文章:Quick Introduction to Mesh Shaders (OpenGL and Vulkan)

复杂场景绘制的瓶颈通常有两个:

(1)每次Draw Call带来的CPU端验证及CPU-GPU之间的通信开销;
(2)由于剔除不够精确导致的overdraw和由此带来的GPU计算资源的浪费;

近年来渲染技术优化往往也都是围绕这两个难题,并形成了一些业内的技术共识:

针对CPU端验证、状态切换带来的开销,我们有了新一代的图形API(Vulkan,DX12,Metal),旨在让驱动在CPU端做更少的验证工作;将不同任务通过不同的queue派发给GPU(Compute/Graphics/DMA Queue);要求开发者自行处理CPU和GPU之间的同步;充分利用多核CPU的优势多线程向GPU提交命令。得益于这些优化,新一代图形API的draw call数量相较于上一代图形API(DX11,OpenGL)提高了一个数量级。

另一个优化方向是减少CPU和GPU之间的数据通讯,以及更加精确的剔除对最终画面没有贡献的三角形。基于这个思路,诞生了GPU Driven Pipeline(上一节内容)。得益于GPU Driven Pipeline在游戏中越来越广泛的应用,把模型的顶点数据进一步切分为更细粒度的Cluster(或者叫做Meshlet),让每个Cluster的粒度能够更好地适应Vertex Processing阶段的Cache大小,并以Cluster为单位进行各类剔除(Frustum Culling,Occulsion Culling,Backface Culling)已经逐渐成为了复杂场景优化的最佳实践,GPU厂商也逐渐认可了这一新的顶点处理流程。但传统的GPU Driven Pipeline依赖Compute Shader剔除,剔除后的数据需要存储在GPU Buffer内,经由Execute Indirect这类API,把剔除后的Vertex/Index Buffer重新喂给GPU的Graphics Pipeline,无形中增加了一读一写的开销;此外顶点数据也会被重复读取(Compute Shader在剔除前读取以及Graphics Pipeline在绘制时通过Vertex Attribute Fetch读取)。

基于以上的原因,为了进一步提高顶点处理的灵活度,NVidia最先引入了Mesh Shader的概念:希望能够逐步去掉传统顶点处理阶段的一些固定单元(VAF,PD一类的硬件单元),并把这些事交由开发者通过可编程管线(Task Shader/Mesh Shader)处理

Cluster示意图如下:

在这里插入图片描述

基于Mesh Shader的Pipeline,Cluster剔除成为了顶点处理阶段的一部分,减少没必要的Vertex Buffer Load/Store,如下图:

在这里插入图片描述
Mesh Shader重点有三个:

  1. 合并GS、VS、曲面细分这些操作。之前为了兼容性,GS和曲面细分都是像补丁一样被引入的,现在融合在一起能减少开销。
  2. 优化线程模型。一方面因为GS/曲面细分等的要求,需要看到多个“顶点”,另一方面和Compute Shader一样提供更丰富的底层特性(SIMT/Shared Memory)以便优化算法/性能。
  3. 延迟实际的VS阶段。传统来说VS是渲染的第一阶段,现在MS不一定是,而且可以把实际的顶点着色推迟,从而让遮挡剔除等操作更好地发挥作用。(降低压力,尤其内存压力)。

详细中文教程可参照知乎相关文章【Vulkan/MeshShader】其中详细讲述了实现细节

  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值