一、导言
二、GPU概述
三、GPU物理架构
四、GPU运行机制
4.1 GPU渲染总览
4.2 GPU逻辑管线
4.3 GPU技术要点
4.4 GPU资源机制
4.4.1 内存架构
4.4.2 GPU Context和延迟
4.4.3 CPU-GPU异构系统
4.4.4 GPU资源管理模型
4.4.5 CPU-GPU数据流
4.4.6 显像机制
4.5 Shader运行机制
4.6 利用扩展例证
五、总结
参考文献
四、GPU运行机制
4.1 GPU渲染总览
由上一章可得知,现代GPU有着相似的结构,有很多相同的部件,在运行机制上,也有很多共同点。下面是Fermi架构的运行机制总览图:从Fermi开始NVIDIA使用类似的原理架构,使用一个Giga Thread Engine来管理所有正在进行的工作,GPU被划分成多个GPCs(Graphics Processing Cluster),每个GPC拥有多个SM(SMX、SMM)和一个光栅化引擎(Raster Engine),它们其中有很多的连接,最显著的是Crossbar,它可以连接GPCs和其它功能性模块(例如ROP或其他子系统)。程序员编写的shader是在SM上完成的。每个SM包含许多为线程执行数学运算的Core(核心)。例如,一个线程可以是顶点或像素着色器调用。这些Core和其它单元由Warp Scheduler驱动,Warp Scheduler管理一组32个线程作为Warp(线程束)并将要执行的指令移交给Dispatch Units。GPU中实际有多少这些单元(每个GPC有多少个SM,多少个GPC ......)取决于芯片配置本身。例如,GM204有4个GPC,每个GPC有4个SM,但Tegra X1有1个GPC和2个SM,它们均采用Maxwell设计。SM设计本身(内核数量,指令单位,调度程序......)也随着时间的推移而发生变化,并帮助使芯片变得如此高效,可以从高端台式机扩展到笔记本电脑移动。如上图,对于某些GPU(如Fermi部分型号)的单个SM,包含:- 32个运算核心 (Core,也叫流处理器Stream Processor)
- 16个LD/ST(load/store)模块来加载和存储数据
- 4个SFU(Special function units)执行特殊数学运算(sin、cos、log等)
- PolyMorph Engine:多边形引擎负责属性装配(attribute Setup)、顶点拉取(VertexFetch)、曲面细分、栅格化(这个模块可以理解专门处理顶点相关的东西)。
- 2个Warp Schedulers:这个模块负责warp调度,一个warp由32个线程组成,warp调度器的指令通过Dispatch Units送到Core执行。
- 内部链接网络(Interconnect Network)
4.2 GPU逻辑管线
了解上一节的部件和概念之后,可以深入阐述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),然后发送给多个PGCs。这一步的理解就是提交上来n个三角形,分配给这几个PGC同时处理。4、在GPC中,每个SM中的Poly Morph Engine负责通过三角形索引(triangle indices)取出三角形的数据(vertex data),即图中的Vertex Fetch模块。5、在获取数据之后,在SM中以32个线程为一组的线程束(Warp)来调度,来开始处理顶点数据。Warp是典型的单指令多线程(SIMT,SIMD单指令多数据的升级)的实现,也就是32个线程同时执行的指令是一模一样的,只是线程数据不一样,这样的好处就是一个warp只需要一个套逻辑对指令进行解码和执行就可以了,芯片可以做的更小更快,之所以可以这么做是由于GPU需要处理的任务是天然并行的。6、SM的warp调度器会按照顺序分发指令给整个warp,单个warp中的线程会锁步(lock-step)执行各自的指令,如果线程碰到不激活执行的情况也会被遮掩(be masked out)。被遮掩的原因有很多,例如当前的指令是if(true)的分支,但是当前线程的数据的条件是false,或者循环的次数不一样(比如for循环次数n不是常量,或被break提前终止了但是别的还在走),因此在shader中的分支会显著增加时间消耗,在一个warp中的分支除非32个线程都走到if或者else里面,否则相当于所有的分支都走了一遍,线程不能独立执行指令而是以warp为单位,而这些warp之间才是独立的。7、warp中的指令可以被一次完成,也可能经过多次调度,例如通常SM中的LD/ST(加载存取)单元数量明显少于基础数学操作单元。8、由于某些指令比其他指令需要更长的时间才能完成,特别是内存加载,warp调度器可能会简单地切换到另一个没有内存等待的warp,这是GPU如何克服内存读取延迟的关键,只是简单地切换活动线程组。为了使这种切换非常快,调度器管理的所有warp在寄存器文件中都有自己的寄存器。这里就会有个矛盾产生,shader需要越多的寄存器,就会给warp留下越少的空间,就会产生越少的warp,这时候在碰到内存延迟的时候就会只是等待,而没有可以运行的warp可以切换。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)在它接收到的三角形上工作,来负责这些这些三角形的像素信息的生成(同时会处理裁剪Clipping、背面剔除和Early-Z剔除)。13、32个像素线程将被分成一组,或者说8个2x2的像素块,这是在像素着色器上面的最小工作单元,在这个像素线程内,如果没有被三角形覆盖就会被遮掩,SM中的warp调度器会管理像素着色器的任务。14、接下来的阶段就和vertex-shader中的逻辑步骤完全一样,但是变成了在像素着色器线程中执行。由于不耗费任何性能可以获取一个像素内的值,导致锁步执行非常便利,所有的线程可以保证所有的指令可以在同一点。15、最后一步,现在像素着色器已经完成了颜色的计算还有深度值的计算,在这个点上,我们必须考虑三角形的原始api顺序,然后才将数据移交给ROP(render output unit,渲染输入单元),一个ROP内部有很多ROP单元,在ROP单元中处理深度测试,和framebuffer的混合,深度和颜色的设置必须是原子操作,否则两个不同的三角形在同一个像素点就会有冲突和错误。4.3 GPU技术要点
由于上一节主要阐述GPU内部的工作流程和机制,为了简洁性,省略了很多知识点和过程,本节将对它们做进一步补充说明。4.3.1 SIMD和SIMT
SIMD(Single Instruction Multiple Data)是单指令多数据,在GPU的ALU单元内,一条指令可以处理多维向量(一般是4D)的数据。比如,有以下shader指令:float4 c = a + b; // a, b都是float4类型
对于没有SIMD的处理单元,需要4条指令将4个float数值相加,汇编伪代码如下:ADD c.x, a.x, b.x
ADD c.y, a.y, b.y
ADD c.z, a.z, b.z
ADD c.w, a.w, b.w
SIMT(Single Instruction Multiple Threads,单指令多线程)是SIMD的升级版,可对GPU中单个SM中的多个Core同时处理同一指令,并且每个Core存取的数据可以是不同的。上述指令会被同时送入在单个SM中被编组的所有Core中,同时执行运算,但a
、b
、c
的值可以不一样:4.3.2 co-issue
co-issue是为了解决SIMD运算单元无法充分利用的问题。例如下图,由于float数量的不同,ALU利用率从100%依次下降为75%、50%、25%。为了解决着色器在低维向量的利用率低的问题,可以通过合并1D与3D或2D与2D的指令。例如下图,DP3
指令用了3D数据,ADD
指令只有1D数据,co-issue会自动将它们合并,在同一个ALU只需一个指令周期即可执行完。但是,对于向量运算单元(Vector ALU),如果其中一个变量既是操作数又是存储数的情况,无法启用co-issue技术:于是标量指令着色器(Scalar Instruction Shader)应运而生,它可以有效地组合任何向量,开启co-issue技术,充分发挥SIMD的优势。4.3.3 if - else语句
如上图,SM中有8个ALU(Core),由于SIMD的特性,每个ALU的数据不一样,导致if-else
语句在某些ALU中执行的是true
分支(黄色),有些ALU执行的是false
分支(灰蓝色),这样导致很多ALU的执行周期被浪费掉了(即masked out),拉长了整个执行周期。最坏的情况,同一个SM中只有1/8(8是同一个SM的线程数,不同架构的GPU有所不同)的利用率。同样,for
循环也会导致类似的情形,例如以下shader代码:void func(int count, int breakNum)
{
for(int i=0; i {
if (i == breakNum)
break;
else
// do something
}
}
由于每个ALU的count
不一样,加上有break
分支,导致最快执行完shader的ALU可能是最慢的N分之一的时间,但由于SIMD的特性,最快的那个ALU依然要等待最慢的ALU执行完毕,才能接下一组指令的活!也就白白浪费了很多时间周期。4.3.4 Early-Z
早期GPU的渲染管线的深度测试是在像素着色器之后才执行(下图),这样会造成很多本不可见的像素执行了耗性能的像素着色器计算。后来,为了减少像素着色器的额外消耗,将深度测试提至像素着色器之前(下图),这就是Early-Z技术的由来。Early-Z技术可以将很多无效的像素提前剔除,避免它们进入耗时严重的像素着色器。Early-Z剔除的最小单位不是1像素,而是像素块(pixel quad,2x2个像素,详见[4.3.6 ](#4.3.6 像素块(pixel quad)))。- 开启Alpha Test:由于Alpha Test需要在像素着色器后面的Alpha Test阶段比较,所以无法在像素着色器之前就决定该像素是否被剔除。
- 开启Alpha Blend:启用了Alpha混合的像素很多需要与frame buffer做混合,无法执行深度测试,也就无法利用Early-Z技术。
- 开启Tex Kill:即在shader代码中有像素摒弃指令(DX的discard,OpenGL的clip)。
- 关闭深度测试。Early-Z是建立在深度测试看开启的条件下,如果关闭了深度测试,也就无法启用Early-Z技术。
- 开启Multi-Sampling:多采样会影响周边像素,而Early-Z阶段无法得知周边像素是否被裁剪,故无法提前剔除。
此外,Early-Z技术会导致一个问题:深度数据冲突(depth data hazard)。例子要结合上图,假设数值深度值5已经经过Early-Z即将写入Frame Buffer,而深度值10刚好处于Early-Z阶段,读取并对比当前缓存的深度值15,结果就是10通过了Early-Z测试,会覆盖掉比自己小的深度值5,最终frame buffer的深度值是错误的结果。避免深度数据冲突的方法之一是在写入深度值之前,再次与frame buffer的值进行对比:4.3.5 统一着色器架构(Unified shader Architecture)
在早期的GPU,顶点着色器和像素着色器的硬件结构是独立的,它们各有各的寄存器、运算单元等部件。这样很多时候,会造成顶点着色器与像素着色器之间任务的不平衡。对于顶点数量多的任务,像素着色器空闲状态多;对于像素多的任务,顶点着色器的空闲状态多(下图)。于是,为了解决VS和PS之间的不平衡,引入了统一着色器架构(Unified shader Architecture)。用了此架构的GPU,VS和PS用的都是相同的Core。也就是,同一个Core既可以是VS又可以是PS。这样就解决了不同类型着色器之间的不平衡问题,还可以减少GPU的硬件单元,压缩物理尺寸和耗电量。此外,VS、PS可还可以和其它着色器(几何、曲面、计算)统一为一体。4.3.6 像素块(Pixel Quad)
32个像素线程将被分成一组,或者说8个2x2的像素块,这是在像素着色器上面的最小工作单元,在这个像素线程内,如果没有被三角形覆盖就会被遮掩,SM中的warp调度器会管理像素着色器的任务。
也就是说,在像素着色器中,会将相邻的四个像素作为不可分隔的一组,送入同一个SM内4个不同的Core。4、无效像素虽然不会被存储结果,但可辅助有效像素求导函数。详见4.6 利用扩展例证。
这种设计虽然有其优势,但同时,也会激化过绘制(Over Draw)的情况,损耗额外的性能。比如下图中,白色的三角形只占用了3个像素(绿色),按我们普通的思维,只需要3个Core绘制3次就可以了。但是,由于上面的3个像素分别占据了不同的像素块(橙色分隔),实际上需要占用12个Core绘制12次(下图)。这就会额外消耗300%的硬件性能,导致了更加严重的过绘制情况。更多详情可以观看虚幻官方的视频教学:实时渲染深入探究。
作者:0向往0
博客地址:
https://www.cnblogs.com/timlly/p/11471507.html
- Real-Time Rendering Resources
- Life of a triangle - NVIDIA\\'s logical pipeline
- NVIDIA Pascal Architecture Whitepaper
- NVIDIA Turing Architecture Whitepaper
- Pomegranate: A Fully Scalable Graphics Architecture
- Performance Optimization Guidelines and the GPU Architecture behind them
- A trip through the Graphics Pipeline 2011
- Graphic Architecture introduction and analysis
- Exploring the GPU Architecture
- Introduction to GPU Architecture
- An Introduction to Modern GPU Architecture
- GPU TECHNOLOGY: PAST, PRESENT, FUTURE
- GPU Computing & Architectures
- GPU Architecture and Models
- Introduction to and History of GPU Algorithms
- GPU Architecture Overview
- GPU Programming Guide GeForce 8 and 9 Series
- Data Transfer Matters for GPU Computing
- Slang – A Shader Compilation System
- Graphics Shaders - Theory and Practice 2nd Edition
1、NVIDIA A100 Tensor Core GPU技术白皮书2、NVIDIA Kepler GK110-GK210架构白皮书3、NVIDIA Kepler GK110-GK210架构白皮书4、NVIDIA Kepler GK110架构白皮书6、NVIDIA Tesla V100 GPU架构白皮书《异构计算芯片(ASIC/FPGA等)技术合集(1)》《异构计算芯片(ASIC/FPGA等)技术合集(2)》3、Xilinx UltraScale业界首款ASIC级架构.pdf4、先进封装技术:核电子学ASIC技术研讨会.pdf本号资料全部上传至知识星球,更多内容请登录智能计算芯知识(知识星球)星球下载全部资料。
免责申明:本号聚焦相关技术分享,内容观点不代表本号立场,可追溯内容均注明来源,发布文章若存在版权等问题,请留言联系删除,谢谢。
电子书<服务器基础知识全解(终极版)>更新完毕,知识点深度讲解,提供182页完整版下载。
获取方式:点击“小程序链接”即可查看182页 PPT可编辑版本和PDF阅读版本详情。服务器基础知识全解PPT(终极版)
服务器基础知识全解PDF(终极版)
温馨提示:
请搜索“AI_Architect”或“扫码”关注公众号实时掌握深度技术分享,点击“阅读原文”获取更多原创技术干货。