找回密码
 立即注册
查看: 322|回复: 0

4.GPU

[复制链接]
发表于 2022-3-12 19:35 | 显示全部楼层 |阅读模式
0.前言

    本笔记主要参考了May佬百人计划和Games,RTR3提炼总结等
    仅为本菜鸡自己学习记录分享,如有错误还请各位大佬指出。
整个笔记如下(不定期更新):
1.渲染流水线
2.MVP矩阵运算
3.纹理
4.GPU
5.色彩
6.测试与混合
<hr/>1.PC端GPU

GPU全称是Graphics Processing Unit,图形处理单元。GPU最初功能与名字一致,但如今加入了许多其他功能。GPU是显卡最核心的部件,除此外显卡还有散热器,通讯元件等。
(1)GPU一些概念与部件

a.部件部分概念一览

  • GPC(图形处理簇)
  • TPC(纹理处理簇)
  • Thread(线程)
  • SM、SMX、SMM(Stream Multiprocessor,流多处理器)
  • Warp线程束、Warp Scheduler(Warp编排器)
  • SP(Streaming Processor,流处理器)
  • Core(执行数学运算的核心)
  • ALU(逻辑运算单元)
  • FPU(浮点数单元)
  • SFU(特殊函数单元)
  • ROP(render output unit,渲染输入单元)
  • Load/Store Unit(加载存储单元)
  • L1 Cache(L1缓存)
  • L2 Cache(L2缓存)
  • Shared Memory(共享内存)
  • Register File(寄存器)
b.核心组件结构
包含关系:GPC->TPC->SM->CORE
其中SM中包含PolyMorphEngine(多边形引擎),L1Cache,Shared Memory,Core等
CORE中包含ALU、FPU、Execution Context(执行上下文),(Detch)、解码(Decode)等


(2)GPU微观物理结构


  • 2008-Tesla:Tesla最初是给计算处理单元使用,应用于早起的CUDA系列芯片,并不是真正意义上普通图形处理芯片
☆2010-Fermi:是第一个完整的GPU计算架构,首款可支持与共享储存结合纯chache的GPU架构,支持ECC的GPU架构

  • 2012-Kepler:相比Fermi更快,效率更高,性能更好。
☆2014-MaxWell:其全新的例题像素全局光照(VXGI)技术首次让游戏GPU能够提供实时动态全局光照。基于此架构的GTX980和970GPU采用了包含多帧采样抗锯齿MFAA,哦动态超级分辨率DSR,VR Direct以及超节能实际在内的一系列新技术

  • 2016-Pascal:此架构将处理器和数据集成在同一个程序包内,以实现更高计算效率。1080和1060系列基于Pascal
  • 2017-Volta:配备了640个Tensor核心,每秒可提供超100兆次浮点运算(TFLOPS)的深度学习效能,比前一代Pascal快5倍以上
☆2018-Turning:配备了名为RT Core的专用光追处理器,能够以每秒高达10 Giga Rays的速度对广夏安和声音在3D空间传播进行加速计算。将光线追踪运算加速至上一代Pascal架构的25倍,并能以高出CPU30多倍的速度进行电影效果的最终帧渲染,2060 2080系列也屙屎跳过了Volta直接选择了Turning架构
a. Tesla架构
含有7组TPC,每个TPC又两组SM,
每个SM又包含8个SP,2个SFU,L1缓存,MTissue,C-cahce,共享内存等
除此外还有与显存,CPU,系统内存交互的部件。


b. Fermi架构
拥有16个SM         2个WarpScheduler(线程束)        两组共32个Core
16组加载储存单元(LD/ST) 4个特殊函数但阿远(SFU) 分发单元(Dispatch Unit)


每个Core有1个FPU和1个ALU
c. Maxwell架构
拥有4个GPC,每个GPC有4个SM


d. Turing架构
含有6个GPC ,36个TPC 72个SM 每个GPC有6个TPC,每个TPC又2个SM
共4608CUDA核 72RT核 576Tensor核 288纹理单元 12x32GDDR6内存控制器
Turing中每个SM含有64个CUDA(统一计算架构) 8Tensor 256k寄存器文件


(3)GPU渲染过程

Fermi架构运行机制总览图


Shader是在SM上完成的,每个SM包含了许多为线程执行数学运算的Core。
a.GPU逻辑管线
以Fermi的SM为例
<1>程序通过图形API(DX、GL、WEBGL)发出drawcall指令,指令会被推送到驱动程序,驱动会检查指令的合法性,然后会把指令放到GPU可以读取的Pushbuffer中。
<2>经过一段时间或者显式调用flush指令后,驱动程序把Pushbuffer的内容发送给GPU,GPU通过主机接口(Host Interface)接受这些命令,并通过前端(Front End)处理这些命令。
<3>在图元分配器(Primitive Distributor)中开始工作分配,处理indexbuffer中的顶点产生三角形分成批次(batches),然后发送给多个GPCs。这一步的理解就是提交上来n个三角形,分配给这几个GPC同时处理。


<4>在GPC中,每个SM中的Poly Morph Engine负责通过三角形索引(triangle indices)取出三角形的数据(vertex data),即图中的Vertex Fetch模块。
<5>在获取数据之后,在SM中以32个线程为一组的线程束(Warp)来调度,来开始处理顶点数
<6> SM的warp调度器会按照顺序分发指令给整个warp,单个warp中的线程会锁步(lock-step)执行各自的指令,如果线程碰到不激活执行的情况也会被遮掩(be masked out)
<7> warp中的指令可以被一次完成,也可能经过多次调度,例如通常SM中的LD/ST(加载存取)单元数量明显少于基础数学操作单元。
<8>由于某些指令比其他指令需要更长的时间才能完成,特别是内存加载,warp调度器可能会简单地切换到另一个没有内存等待的warp,这是GPU如何克服内存读取延迟的关键,只是简单地切换活动线程组



<9>一旦warp完成了vertex-shader的所有指令,运算结果会被Viewport Transform模块处理,三角形会被裁剪然后准备栅格化,GPU会使用L1和L2缓存来进行vertex-shader和pixel-shader的数据通信。
<10>接下来这些三角形将被分割,再分配给多个GPC,三角形的范围决定着它将被分配到哪个光栅引擎(raster engines),每个raster engines覆盖了多个屏幕上的tile,这等于把三角形的渲染分配到多个tile上面。也就是像素阶段就把按三角形划分变成了按显示的像素划分了。




<11> SM上的Attribute Setup保证了从vertex-shader来的数据经过插值后是pixel-shade是可读的。
<12> GPC上的光栅引擎(raster engines)在它接收到的三角形上工作,来负责这些三角形的像素信息的生成(同时会处理背面剔除和Early-Z剔除)。
<13> 32个像素线程将被分成一组,或者说8个2x2的像素块,这是在像素着色器上面的最小工作单元,在这个像素线程内,如果没有被三角形覆盖就会被遮掩,SM中的warp调度器会管理像素着色器的任务。
<14>接下来的阶段就和vertex-shader中的逻辑步骤完全一样,但是变成了在像素着色器线程中执行。 由于不耗费任何性能可以获取一个像素内的值,导致锁步执行非常便利,所有的线程可以保证所有的指令可以在同一点。




<15>最后一步,现在像素着色器已经完成了颜色的计算还有深度值的计算,在这个点上,我们必须考虑三角形的原始api顺序,然后才将数据移交给ROP(render output unit,渲染输入单元),一个ROP内部有很多ROP单元,在ROP单元中处理深度测试,和framebuffer的混合,深度和颜色的设置必须是原子操作,否则两个不同的三角形在同一个像素点就会有冲突和错误。


(4)GPU资源机制

a.内存架构
GPU与CPU类似,有多级缓存结构:寄存器,L1缓存,L2缓存,GPU显存,系统显存。读取速度依此变慢
因此,shader直接访问寄存器和L1,L2较快,但访问无能力,常量缓存和全局内存非常慢,造成高延迟       




b.GPU内存
GPU内存分布在RAM储存芯片或者GPU芯片上,
物理上所处的位置决定了速度,大小和访问规则。
<1>全局内存(Global memory)
位于片外存储体中。容量大、访问延迟高、传输速度较慢,使用二级缓存(L2 cache)做缓冲
<2>本地内存(Local memory)
一般位于片内存储体中,变量、数组、结构体等都存放在此处,但是有大数组、大结构体以至于寄存器区放不下他们,编译器在编译阶段就会将他们放到片外的DDR芯片中(最好的情况也会被扔到L2 Cache中),且将他们标记为“Local”型
<3>共享内存(Shared memory)
位于每个流处理器组中(SM)中,其访问速度仅次于寄存器
<4>寄存器内存(Register memory)
位于每个流处理器组中(SM)中,访问速度最快的存储体,用于存放线程执行时所需要的变量。
<5>常量内存(Constant memory)
位于每个流处理器(SM)中和片外的RAM存储器中
<6>纹理内存(Texture memory)
位于每个流处理器(SM)中和片外的RAM存储器中


(5)CPU-GPU

a. CPU-GPU异构系统
根据CPU和GPU是否共享内存,可以分为两种CPU-GPU架构
<1>分离式架构


CPU和GPU各自有独立的缓存和内存,两者共享一套虚拟地址空间,必要时会进行内存拷贝,它们通过PCI-e等总线通讯。这种结构的缺点在于 PCI-e 相对于两者具有低带宽和高延迟,数据的传输成了其中的性能瓶颈。目前使用非常广泛,如PC等。
<2>耦合式架构


CPU 和 GPU 共享内存和缓存,由 MMU 进行存储管理。AMD 的 APU 采用的就是这种结构,目前主要使用在游戏主机中,如 PS4、智能手机。
b. CPU-GPU数据流
<1>将主存的处理数据复制到显存中。
<2>CPU指令驱动GPU。
<3>GPU中的每个运算单元并行处理。此步会从显存存取数据。
<4>GPU将显存结果传回主存。


c.Shader运行机制


首先由高级语言编译为汇编语言再转义为二进制命令
在执行阶段,CPU端将shader二进制指令经由PCI-e推送到GPU端,GPU在执行代码时,会用Context将指令分成若干Channel推送到各个Core的存储空间。
在这样一个假象的Core:一个 GPU Core 包含 8 个 ALU,4 组执行环境(Execution context),每组有 8 个Ctx。这样,一个 Core 可以并发(Concurrent but interleaved)执行 4 条指令流(Instruction Streams),32 个并发程序片元(Fragment)。


在执行阶段,汇编代码会被GPU推送到执行上下文(Execution Context),然后ALU会逐条获取(Detch)、解码(Decode)汇编指令为二进制指令,并执行它们。


(6)其他

a.EarlyZ
早期GPU的渲染管线的深度测试是在像素着色器之后才执行,这样会造成很多本不可见的像素执行了耗性能的像素着色器计算。后来,为了减少像素着色器的额外消耗,将深度测试提至像素着色器之前,这就是Early-Z技术的由来。
(详解见另一篇)
b.SIMD
SIMD(Single Instruction Multiple Data)是单指令多数据,在GPU的ALU单元内,一条指令可以处理多维向量。
如果没有SIMD 相加的话就要把向量各个部分相加,
但有了SIMD可以一条指令完成
c.SIMT
SIMT(Single Instruction Multiple Threads,单指令多线程)是SIMD的升级版,可对GPU中单个SM中的多个Core同时处理同一指令,并且每个Core存取的数据可以是不同的。
对于SIMT架构的GPU 汇编指令有所不同,变成了SIMT特定的指令代码,并且Context以Core为单位组成共享的结构,同一个Core的多个ALU共享一组Context
如果有多个Core,就会有更多的ALU同时参与shader计算,每个Core执行的数据是不一样的。




这个技术导致SM中很多Core并不是独立,当其中有需要访问恩到纹理或全局内存等时,就会导致非常大的卡顿。


d.Co-issue


co-issue是为了解决SIMD运算单元无法充分利用的问题。例如下图,由于float数量的不同,ALU利用率从100%依次下降为75%、50%、25%。
为了解决这个问题可以通过合并1D和3D或2D与2D,
但是,对于向量运算单元(Vector ALU),如果其中一个变量既是操作数又是存储数的情况,无法启用co-issue技术。




e.Warp
Warp是SM的基本执行单元。一个Warp包含32个并行thread,这32个thread执行于SIMT模式。也就是说所有Thread执行同一条指令,并且每个Thread会使用各自的数据执行该指令。
f.小总结

  • 顶点着色器和像素着色都是在同一个单元中执行的(在原来的架构中vs和ps的确是分开的,后来nv把这个统一了)vs是按照三角形来并行处理的,ps是按照像素来并行处理的。
  • vs和ps中的数据是通过L1和L2缓存传递的。
  • warp和thread都是逻辑上的概念,sm和sp都是物理上的概念。线程数≠流处理器数。
g.优化建议
<1>尽量使用自己扩展的几何实例化代替unity提供的静态合批,动态合批,前者将合并mesh增加的vbo内存占用,后者会增加cpu端耗时开销
<2>尽量减少顶点数与三角面数,前者减少顶点着色器元,另外减少gpu中frameData内存储存,后者减少片元着色器消耗。
<3>避免每帧提交buffer数据,比如unity的cpu版本粒子系统,可以使用gpu版本的,讲过修改数据移动到gpu端,还有就是进来避免大片的透明粒子效果,会造成严重overdraw
<4>减少渲染状态的设置和获取,例如在Update中获取设置shader属性或者公共变量,因为cpu是通过mmio获取寄存器苏护具,会耗费更多时间周期
<5>3D物件应使用LOD减少处理的顶点与面数消耗,开始mipmap减少贴图缓存命中的丢失
<6>避免alphatest 会让earlyz失效
<7>避免三角面过小,家具过度绘制情况。如果一个三角形管只占用3个像素戴安,却用12个线程去计算像素值,然后遮蔽其余9个的计算结果
<8>在寄存器数量与变体中寻找平衡,用if变量达成静态分支取代变体,一方面可减少变体数量,另一方面也可使得URP中SRP Batch更高效合批
<9>避免动态的判断粉嫩之,也就是Shader中的if ture和false情况
<10>减少复杂函数调用,因为特殊处理单元远小于正常计算单元
2.移动端GPU

(1)现状与基础

a.占比与对比
<1>占比
CPU


高通占比49.2%,相比于其他厂商有较大的优势,其次是华为28.6%,联发科21%,三星1.1%,
        GPU


                Aderno和Mail在GPU市场分别占比49.2%和48.2%,PowerVR-GPU占比仅有2.6%
<2>功耗对比
                ·桌面级主流性能平台,功耗一般为300W
                ·游戏主机150-200W
                ·入门和旗舰游戏本功耗100W
                ·主流笔记本为50-60W 超级本15-25W
                ·旗舰平板8-15W
                ·旗舰手机5-8W
                ·主流手机3-5W
<3>带宽对比


b.名次解释
<1>Soc
Soc(System on Chip)是把CPU GPU 内存,通信基带,GPS模块等等整合在一起的芯片的称呼,常见有A系Soc(苹果),骁龙Soc(高通),麒麟Soc(华为),
联发科Soc,猎户座Soc(三星)。苹果推出的M系Soc暂用于Mac,但说明手机,笔记本PC通用芯片已经出现
<2>物理内存
Soc中GPU和CPU公用一块片内LPDDR物理内存,就是我们常说的手机内存,也叫System Memory,大概几个G。除此之外CPU和GPU还分贝尔有自己的高速SRAM的Cache缓存,也叫On-chip Memory 一般几百k~几M。不同距离内存访问存在不同时间消耗。读取System内存时间大概是On-chip Memory的几倍到几十倍
<3>On-chip Buffer
在TB(D)R框架下会储存Tile的颜色,深度,模板缓冲。读写修改都非常快。如果Load/Store指令中缓冲需要被Preserve,将会被写入一份到System Memory中。
<4>Stall
当一个GPU核心的两次计算结果之间有依赖关系而必须串行时,等待的过程便是Stall。
<5>FillRate
像素填充率 = ROP运行的时钟频率 x ROP的个数 x 每个时钟ROP可以处理的像素个数
(2)TB(D)R渲染框架

a. IMR与TB(D)R
TB(D)R全称Tile-Based(Deferred)Rendering是目前主流的移动GPU渲染框架,
简单来说就是屏幕被分块(16*16或32*32)渲染


TBR:VS-Defer-RS-PS
TBDR:VS-Defer-RS-Defer-PS
Defer就死“阻塞+批处理”GPU一帧的多个数据一起处理
对应一般PC上GPU渲染框架则是IMR(Immediate Mode Rendering)。
IMR过程中是直接和内存进行交互


而TBDR与其不同点是会把电竞形成的各种数据刷到系统内存上,且最后是先刷到片上内存,再刷到系统内存


TBR与IMR简单对比示意图



实际中GPU硬件为乱序执行


b. TBR的优点缺点目标
        TBR的核心目的是降低抵款,减少功耗,但渲染帧率上并不比IMR快
<1>优点
· TBR给消除Overdraw提供了机会,PowerVR用了HSR技术,Mali用了Forward Pixel Killing技术,目标一样,就是要最大限度减少被遮挡pixel的texturing和shading。
· TBR主要是 cached friendly, 在cache里头的速度要比全局内存的速度快的多,以及有可能降低render rate的代价,降低带宽,省电
<2>缺点
·Binning过程是在vertex阶段之后,将输出的几何数据写入都DDR,然后才能被fragment shader读取。几何数据过多管线容易此处瓶颈
· 如果某些三角形叠加在数个tile上,需要绘制数次,渲染时间高于即时渲染模式
c.Defer
<1>Binning过程 第一个Defer
它确定了有哪些块元来渲染,类似四叉树
当Binning过程所占时间太久,就要考虑几何数据是否过多


<2>不同GPU的Eearly-DT 第二个Defer
·Android
Qualcomm Adreno采用外置模块LRZ,在正常渲染管线前,先多执行一次VS生成低精度depth texture 提前剔除不可见的triangles。就是直接用硬件走occlusion culling,功能类似光栅剔除遮挡
·Arm Mali
采用Forward pixel kill技术


·ISO
使用powervr的HSR(Hidden suface removal)隐形面剔除技术
对每个被投影光束交接的对象进行排序处理,只有最近的不透明饿最近的透明对象需要被渲染,余下的片元被剔除


HSR前后对比




d.TBR优化
<1>        不使用Frame buffer时记得清理或discard
主要是清空积存在tile buff上的 frame Data,所以在unity里面对render texture的使用也特别说明了一下,当不再使用这个rt之前,调用一次Discard。在OpenGL ES上善用glClear,gllnvalidateFrameBuffer避免不必要的Resolve(刷system memory)行为
<2>不要在一帧里面频繁的切换framebuffer的绑定, 本质上就是减少tile buffer 和system memory之间的 的stall 操作
<3>对于移动平台,建议你使用 Alpha 混合,而非 Alpha 测试。在实际使用中,你应该分析并比较 Alpha 测试和 Alpha 混合的表现,因为这取决于具体内容,因此需要测量,通常在移动平台上应避免使用 Alpha 混合来实现透明。需要进行 Alpha 混合时,尝试缩小混合区域的覆盖范围
<4>手机上必须要做Alpha Test时,先做一遍Depth prepass,参考参考目录的 [Alpha Test的双pass 优化思路]
<5>图片尽量压缩 例如:ASTC  ETC2
<6>图片尽量走 mipmap
<7>尽量使用从Vertex Shader传来的Varying变量UV值采样贴图(连续的),不 要在FragmentShader里动态计算贴图的UV值(非连续的),否则CacheMiss                <8>在延迟渲染尽量利用Tile Buffer 存储数据
<9>如果你在Unity 里面调整 ProjectSetting/Quality/Rendering/Texture Quality 不同的设置,或者不同的分辨率下,帧率有很多的变化,那么十有八九是带宽出问题啦
<10> MSAA(增加对framebuffer读取的次数)其实在TBDR上反而是非常快速的。
<11>少在FS 中使用 discard 函数,调用gl_FragDepth从而打断Early-DT( HLSL中为Clip,GLSL中为discard )
<12>尽可能的在Shader里使用Half Float,如果Shader中仅有少量FP16的运算,且FP16需和FP32混合计算,则统一使用Float,好处:
(1)带宽用量减少(2)GPU中使用的周期数减少,因为着色器编译器可以优化你的代码以提高并行化程度。(3)要求的统一变量寄存器数量减少,这反过来又降低了寄存器数量溢出风险。具体有哪些数据类型适合用half或者float 或者fix,请查看参考目录的[熊大的优化建议]
<13>在移动端的TB(D)R架构中,顶点处理部分,容易成为瓶颈,避免使用曲面细分shader,置换贴图等负操作,提倡使用模型LOD,本质上减少FrameData的压力
3.图形API简述

定义:是一个图形库,用于渲染2D3D矢量吐信的跨语言快平台的应用程序接口,针对GPU
(1)DirectX

由微软定义,被 Windows 系统支持。
(2)OpenGL

由 Khronos 定义,被 Windows、Linux、Mac(Unix)系统支持。
(3)OpenGL ES

OpenGL ES1.x锡类为固定功能管线,2.0和3.0都是可编程图形管线。开发者可以自己编写图形管线中
OpenGL ES3.0是向后兼容2.0的,像一些基于GPU的例子动画,几何形状实例化,纹理压缩的伽马矫正等技术都是3.0才引入。
3.0移除了Alpha测试和逻辑操作(LogicOp)因为Alphatest可在片段着色器中dicard,另一个逻辑操作是因为很少使用。
a. OpenGL ES 3.0新特性
太多了就省略,可查看参考资料中百人计划图形API
b.GPU版本与API支持
从 Adreno 302 开始,支持 OpenGL ES 3.0。
从 Adreno 405 开始,支持 OpenGL ES 3.1。


从 Adreno 420 开始,支持 OpenGL ES 3.2。
参考资料

https://learnopengl-cn.github.io/
https://www.bilibili.com/video/BV1q5411w7E8?p=2
https://www.bilibili.com/video/BV1Bb4y167zU?spm_id_from=333.999.0.0
https://www.bilibili.com/video/BV1aM4y1g75f?spm_id_from=333.999.0.0
https://zhuanlan.zhihu.com/p/357112957
https://zhuanlan.zhihu.com/p/39923057
https://zhuanlan.zhihu.com/p/259760974
https://zhuanlan.zhihu.com/p/58017068
http://www.xionggf.com/post/unity3d/shader/u3d_shader_optimization/
https://zhuanlan.zhihu.com/p/360661324

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-5-19 20:34 , Processed in 0.100644 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表