基于 Unity SRP 的 Render Graph 来满足多个在研Unity项目多平台、高质量、多风格的渲染要求。

目录

简介&历史

WorldRender

Frame Graph

高级FrameGraph

lambdas

RenderMode

Transient resource system: The back-bone of FrameGraph


简介&历史

2007时是DICE的引擎,用于未来的battleField的产品,多平台DX9&10。10年后,2017年Frostbite成为EA的标准引擎,多平台DX12,在15款游戏以及未来的EA游戏中使用。

07年的rendering system

10年后,加了很多新特性,新平台,解决了很多新问题。

简化的rendering system。最底下是Platform Graphics API,上面是Render Contex作为API的抽象,在上面Shading system 07年介绍过,用于渲染整个世界,而且是根据美术在ShaderGraphs中的连线构造的Data-Driven Architecture。ShaderGraph定义了surface properties,对光照进行了解耦,来帮助我们创建一批shader可以用于deferred/forward;

shading system被渲染features驱动,比如地表渲染,mesh scattering,rigid geometry,一些渲染features会直接使用Render Contex,大部分是一些全屏处理,比如lightng,pp等,RC是code-driven的架构;最上层有一个庞然大物world render,来管理整个世界。

这是一个code-driven的架构,world render知道所有的渲染特性,views & passes,它分配出资源(RT,buffer),在不同的system中设置并调度它们。

BF4中使用的rendering pass(直接作用于Render Contex的features),很多产品项目组的程序美术会添加各种各样的new feature进来。

WorldRender

World Render的挑战:

  • 显式的立即的模式进行渲染;
  • 显式的资源管理,各个产品项目组都会定制、手工的管理ESRAM,对资源的统一性和merge造成了影响;
  • 和渲染框架耦合严重,因为显式的定制渲染和资源,所以很多模块都受到对方的影响;
  • 局限的扩展新;产品组必须fork来定制;10年间,从4k行代码涨到15k行,非常困难去维护、扩充、整合。

WorldRender的目标:

  • 想知道高层整帧的概况;
  • 更好的扩展性,解耦并组合渲染模块,自动化的资源管理,更好的可视化和分析工具。

为了达到目标,引入了两个新的架构组件:Frame Graph以及Transient Resource System

Frame Graph

Frame Graph用来高度抽象表示render pass和资源,它了解一帧之内所有的信息;Transient Resources来帮助FG分配资源,管理memory aliasing。

FG的目标:

  • 构建高层对整帧的了解,简化资源管理、简化渲染管线配置、简化async compute以及resource barriers;
  • 允许我们写独立的高性能渲染模块;
  • 可以可视化以及debug复杂的渲染管线。

这是一个Deferred Shading pipeline,橙色代表render passes,蓝色代表资源,箭头代表render pass之间的依赖关系,红色是write操作,绿色是read操作。

BF4的一帧,大概有几百个render passes和resources,一个可以线性分析的可视化工具,可以顺序的显示render passes和resources。

 最上面是render passes,包括graphic和async compute;当鼠标移到某个render pass上方时,可以看到那些resources是需要被当前rp读写的(绿色/红色);

当移动到resource上时,可以看到对它进行读写的render passes

最下方可以看到这些数据的物理内存分布,由transient resource system计算。

移除了立即模式的渲染,新的rendering代码可以分割为passes,rendering分为了3个阶段:

  1. setup设置使用哪些render passes,哪些resources(定义每个passes的inputs和outputs资源);
  2. compile负责resources的lifetime,并且给他们分配空间;
  3. execute就是执行每个render pass。

Render passes通过resources来建立互相的关系,这儿resources是handles并没有内存分配,rp必须定义所有用到的资源,包括读写和创建;有些永久资源直接通过API创建,它们会被导入到rp中一起进行管理,比如TAA的history buffer/backbuffer等。

在setup阶段,Flow类似于IM渲染,但在此阶段我们不会生成任何GPU命令。只是建立有关帧渲染操作的信息。在图形构建过程中,所有资源都是虚拟的。渲染过程的输入和输出是使用虚拟资源句柄声明的。

我们也可以读或者写之前创建的资源,这儿rp读一些资源并且写入一些资源;我们写入的资源之前老的handle会被invalidated,在写操作后我们会重命名这个资源,写入invalid handle的资源会造成runtime error,这会帮助我们找到一些之前老代码就存在的数据竞争与依赖。

高级FrameGraph

  • 延迟创建资源,很早的声明资源,直到使用时才创建,根据使用自动设置创建的desc;
  • 推导资源参数,可以根据input的格式/size来推导参数,比如在resolve pass需要一个downsample chain,简单的可以自动直接推导出创建资源。
  • 移动子资源,可以帮助我们直接在多个pass复用资源,自动的创建子资源或者资源别名。

有Deferred Shading,最终会输出2D RT;另外我们还有一个Reflection模块用来做一些convolution,他需要一些cubemap作为input,我们可以使用move操作把lighting buffer输出给cubemap的faces,所以lightbuffer会使用cubemap的subresource view来代替整个2D rtview,复用了lighting buffer的资源。这帮助我们解耦了各个模块,ds和refl模块之间不需要互相了解任何信息。

Compile阶段

这个阶段不会给program user暴露,自动运行。把没有引用的res和passes cull掉,这样在setup阶段可以草率一些,更容易解耦,简化了可选的passes以及debug rendering等;计算res的生命周期;根据生命周期和bind flag分配固定的GPU资源,对于async compute会延长其生命周期。

graph culling的重要性:DS会有一个debug模块,我们就一直加上他,不需要知道它是否开关,正常渲染时会被cull掉。

Culling algorithm
Simple graph flood-fill from unreferenced resources.
Compute initial resource and pass reference countsrenderPass.refCount++ for every resource writeresource.refCount++ for every resource read
Identify resources with refCount == 0 and push them on a stackWhile stack is non-emptyPop a resource and decrement ref count of its producerIf producer .refCount == 0, decrement ref counts of resources that it readsAdd them to the stack when their refCount == 0

执行阶段

执行每个rp的callback函数,里面的代码和没有FG之前的一样:包括使用RC、设置state等,dispatch和draw;唯一不同的是这儿需要根据handle去devirtualize真正的GPU资源。

异步计算

SSAO读取depth输出到raw AO上,filter把raw AO处理为AO,之后作为输入给Lighting pass,AO变为async compute,这样rawAO的声明周期就延长至lighting pass(main queue中第一次使用其output依赖的地方)

lambdas

重要的是在C++中怎么声明RP:可以对每个RP声明一个class,但是这样就会破坏code
flow(每个class分割了procedure的代码),需要一堆样板参数,对于现有代码难移植;使用了lambdas来解决,可以保证线性的代码流,最小化改变已有代码(把原有代码包进lambda中,加入资源的使用声明)

第一段包含rp使用的resources声明;接下来是setup phase的lambda,声明了resources如何使用;最后是execution phase的lambda,会在之后才执行,也许会被cull掉不执行;lambda能帮助我们自动捕获需要的变量,对于setup phase逻辑上应该可进行读写设置,捕捉引用&,对于execute phase逻辑上应该是延迟执行,捕捉使用值传递=。

addCallbackPass()是一个模板函数,它在后台创建一个由PassData和executelambda参数化的渲染过程类。Setuplambda是在addMyPass()中内联的,但executelambda是deferred的。Setuplambda可以通过引用捕获所有内容,但executelambda必须通过值捕获。

按值捕获数据有点危险,因为可能会意外捕获在执行阶段之前释放的指针。也有可能意外地capture huge structures by value。幸运的是,我们可以强制executelambda的大小在编译时低于一定的大小(我们确定了1KB的限制)。

RenderMode

Render modules:2种渲染模块:1)Free-standing stateless function

第二种是类似TAA的history buffer这种,生命周期大于一帧。WorldRenderer依然在高层协调整个渲染,但是它不会分配任何GPU资源,仅仅kick渲染模块,更加简单去扩展,代码量从15k行变为5k行。

之前渲染模块之间显式的通过参数和返回值传递数据,这种机制非常难以扩展因为需要改变函数声明或者结构定义。新的模块通过一种storage(hash table) component传递数据,key是typeid,这样的耦合是可控的。我们想让模块之间可以传递数据,但是又不行暴露给外界;举个例子:tonemap模块需要blur模块的数据,blur模块通过blackboard.add把相应数据加入hashtable,tonemap模块从blackboard中get出blur模块里的数据,这样blur模块不需要知道是否有tonemap的存在。

Transient resource system: The back-bone of FrameGraph

对于一帧之内临时的资源,我们希望最小化它们的生命周期。在真正使用时才分配资源,可以在渲染系统的叶子结点模块分配资源,尽快的回收,更容易的写独立包含的代码,不需要考虑其他模块/全局的资源传递创建等。它对于FG是非常重要的。

这是实际ps4中的memory map,x轴是时间,y轴是virtual address。Ps4中的trs首先会申请一大段virtual memory(例如几个G)但是没有物理内存的分配,在每帧的执行期间当我们需要一个新的rt时,用户申请数段chunks of memory并且真正分配物理空间,资源的handle会指向申请的内存,等待使用完毕我们可以复用它的virtual memory,可以在一帧开始计算需要多少GPU内存,事先分配好,在execute的时候使用。坏处是可能会造成内存碎片的浪费,因为使用greedy算法来分配回收内存,例如图示中的AO buffer回收后会造成不连续的碎片,但实际中不是太大的问题。

在DX12中有些不一样,GPU的分配会抽象为resource heap,分配之前需要找到满足条件的resource pool,使用placedResource(DX12 API)来创建heap中的资源,track heap中的资源来复用。这不仅会有ps4碎片的缺点,而且会带来更多per heap的细小内存碎片,但实际上使用了aliasing的管理还是比不使用任何内存管理效果好得多。

需要仔细考虑:必须小心,首先需要确定资源的metadata state(fastclear/discard/diable),其次要确定资源的生命周期,比想象中的要难很多,要考虑render和compute,保证在使用前已经分配了真正的物理内存页。

SUMMARY

知道每帧全局的信息有很多好处(复用内存,半自动化的async compute,简单的管线配置,可视化和debug工具);图表pipeline的表示非常吊,有非常直观的感受,类似cpu job graphs或者shader graphs,C++的新特性减少了重构的麻烦。

FrameGraph Extensible Rendering Architecture in Frostbite相关推荐

  1. 计算机网络相关论文翻译(1)A Brief Overview of the NEBULA Future Internet Architecture

    在计算机网络的学习中,由于网络近年来井喷式的发展,阅读一些论文是很有必要的,既有助于学习,也对网络能有更深的理解,后面,将会阅读一些计算机网络相关的论文,并将其翻译上传. 第一篇,选的是关于未来互联网 ...

  2. 《Real-Time Rendering 4th Edition》全文翻译 - 第2章 图形渲染管线(下)2.4 ~ 2.6(20200720翻新)

    ------分割线 2020.7.20------ 翻新了一遍译文,统一了名词,补充了漏译的部分. 实时渲染(第四版)Real-Time Rendering (Fourth Edition) 第2章  ...

  3. Image-based Lighting approaches and parallax-corrected cubemap

    Image-based Lighting approaches and parallax-corrected cubemap SEPTEMBER 29, 2012 25 COMMENTS Versio ...

  4. 计算机缩写术语完全介绍 By 001pc @ 1997.10.1-2004-6-12

    计算机缩写术语完全介绍By 001pc @ 1997.10.1-2004-6-12 在使用计算机的过程中,你可能会碰到各种各样的专业术语,特别是那些英文缩写常让我们不知所云,下面收集了各方面的词组,希 ...

  5. 计算机专用术语总结--转

    本文帮助一些新手在刚刚接触计算机技术方面而出现的对一些老鸟们说的一些#¥%---叫人看了也不能理解的术语的一个小小的总结.这个总结是需要大家来完善的,我希望这个帖子不要灌水. 1.CPU 3DNow! ...

  6. 计算机英文术语完全介绍

    计算机英文术语完全介绍 1.CPU 3DNow!(3D no waiting) ALU(Arithmetic Logic Unit,算术逻辑单元) AGU(Address Generation Uni ...

  7. Cubemaps相关

    使用 Cubmap 可以模拟出环境的反射,预先将环境渲染到 Cubmap 中,从而避免在游戏运行时对环境的实时反射产生的消耗,而且这样做表现效果也非常好.在一些户外环境尤其适用,比如说车身反射外部的环 ...

  8. 2 The Vuri FAQ - Vrui问答

    The Vrui FAQ - 有关Vrui工具包的问答 Tags:Vrui The Vrui FAQ 有关Vrui工具包的问答 General Questions 一般的问题 What is this ...

  9. chrome 硬件渲染(GPU Accelerated Compositing in Chrome)

    原文链接 http://www.chromium.org/developers/design-documents/gpu-accelerated-compositing-in-chrome chrom ...

最新文章

  1. 水晶报表设置FiledObject支持HTML格式的数据
  2. 服务器广播消息,c#-从服务器广播消息
  3. 【Device Tree】设备树(一)——GPIO
  4. pb65 xp 安装无反应_长春优质AFB型耐腐蚀泵安装
  5. 从github上下载单个文件
  6. 只想做程序员的钢铁侠埃隆·马斯克,是如何成为亿万富翁的?
  7. c++进阶(十八)stack容器和queue容器
  8. mysql系列之4.mysql字符集
  9. linux从哪里入侵电脑,linux入侵的基本命令网站安全 -电脑资料
  10. flash动画测试什么软件,flash测试(flash怎么测试动画)
  11. #includeiostream里的定义
  12. 北斗卫星的授时系统不输GPS授时系统并应用到各行各业
  13. Vue Echarts绘制世界地图
  14. 字符串右移n位,例如 “hello world“ 右移两位 后ldhello wor
  15. STM32F4单片机bootloader及在线升级IAP基本原理
  16. spring创建ProcessEngine抛空指针异常
  17. 验证码-kaptcha
  18. 吴恩达深度学习编程作业报错解决方法汇总
  19. 什么是泛域名?IIS里怎么设置泛域名?
  20. 湖北经济学院计算机专业全国排名,湖北经济学院世界排名、中国排名、专业排名...

热门文章

  1. react 渲染table数据
  2. android 角标框架,Android 实现桌面未读角标
  3. CSS3实现雪碧图动画
  4. hdlc协议解码的四种方法
  5. 关于 web service 参数传递的序列化反序列化问题
  6. LAMP编程之Linux(2)
  7. 国内三大制式3G网络简介及比较
  8. java 日期获取时间戳
  9. seata-tcc简单使用
  10. 若依ruoyi框架实现单点登录或者接入统一认证