版权声明
- 本文为“优梦创客”原创文章,您可以自由转载,但必须加入完整的版权声明
- 文章内容不得删减、修改、演绎
- 本文视频版本:见文末
引言
大家好,我是老雷,今天我想从GPU硬件原理出发,给大家分享在图形渲染流水线中,光栅化步骤的硬件原理,从而帮助大家更好的理解图形学的底层原理以及渲染优化的底层逻辑。
好,废话不多说,我们先来整体看一下渲染流水线,以及光栅化在渲染流水线中的位置和作用。
图形渲染流水线
光栅化,英文Rasterization,是图形渲染流水线中非常重要的一个步骤,它位于顶点计算之后,像素着色之前,目的就是把顶点构成的三角形映射到屏幕的一个个像素点上。
但是在一个游戏场景中,光栅化的压力是很大的。
我们知道,游戏场景是由很多游戏元素构成,例如:玩家、怪物、宠物、道具、地形、植被、树木、房子等等,这些模型少则几十、几百个三角面,多则几千、上万个三角面,每个三角面在经过光栅化以后,又会被填充到多个屏幕像素上,
因此光栅化的开销很大!
但是不用怕,我们的GPU就是为大规模计算而生的,那么GPU是如何做到快速的光栅化计算的呢?
这就需要掌握一些GPU底层的知识了。下面我将带着你一步一步揭开光栅化的底层面纱~
GPU架构
先看这幅图:这是我们的GPU,它由显存和许多计算单元组成。
显存(Global Memory)主要指的是在GPU主板上的DRAM,类似于CPU的内存,特点是容量大但是速度慢,CPU和GPU都可以访问。
计算单元通常是指SM(Stream Multiprocessor,流多处理器),这些SM在不同的显卡上组织方式还不太一样。作为执行计算的单元,其内部还有自己的控制模块、寄存器、缓存、指令流水线等部件。
GPC
GPU包含若干个GPC(它是Graphics Processing Cluster,图形处理簇的缩写)
不同架构的GPU包含的GPC数量不一样。以Maxwell架构为例,它是由4个GPC组成
SM
Maxwell的1个GPC有4个SM
不过这不是我们本次分享的重点,大家要重点关注的是GPC里连接各个SM计算单元的光栅化引擎(Raster Engine)。另外,连接每个GPC靠的是Crossbar,例如某一个GPC计算完的数据需要另外GPC来处理,这个分配就是靠的Crossbar。
光栅化跟GPU硬件的关系
再回到我们的问题:那么光栅化跟上面的硬件有什么具体关系呢?
首先,为了平衡光栅化的负载压力,Crossbar会根据一定策略,将屏幕划分成多个区域块,并重新分配给每一个GPC。这是Crossbar为屏幕划分区域块的示意图。
这里GPC接收到分配的区域后,就交给光栅化引擎来负责这些三角形像素信息的生成。同时还会处理其他的一些渲染流水线步骤,包括:三角形裁剪、背面剔除以及Early-Z(相关知识可以参考我的TA全栈项目)。
GPU架构和渲染管线
接下来光栅化引擎将将Vertex Shader计算后存放在L1和L2缓存里面的数据加载出来
将插值好的数据转交给PolyMorph Engine的Attribute Setup模块
经过插值的数据填充到Pixel Shader的寄存器里,供SM的运算核心做像素计算的时候使用
上面提到Crossbar会根据一定策略划分区域块,实际上的划分可能比上图更加复杂,我们来看一个实验
实验:渲染SM_ID
那么问题来了:
如果给每个SM分配一个[0,SM_COUNT-1]的WARP_ID
并将每个像素根据SM_ID渲染为不同亮度的红色:SM_ID / (SM_COUNT-1),
你认为会得到什么渲染结果呢?(图中的绿色暂时忽略)
这里我们以Geforce1080为例,它有20个SM,如果我们用不同亮度的红色表示不同的线程ID,并且渲染由两个三角形构成的四边形面片,就会得到这样的像素块效果。
在这里有几点值得注意:
第一,图中有20个亮度色阶,说明有20个不同编号的SM
第二,像素颜色不是连续变化的,说明SM的划分并不是按编号顺序简单地依次划分,而是由Crossbar重组后被光栅化器调度执行的
第三,同一个色块内的像素如果分属不同三角形,就会分给不同的SM进行处理。如果三角形越细碎,分配SM的次数就会越多,调度开销越大。
第四,这里一个色块是8×8,也就说明一个SM里运行了256个线程束
那么,什么是线程束呢?
什么是线程束
线程束英文WARP,为了和线程数加以区分,在容易产生歧义的地方,我们统一用英文WARP,而不用中文术语(线程束)
那么光栅化以后的像素是如何被并行计算(也就是逐像素渲染)的呢?
在逻辑上,一个线程执行一个Pixel Shader的核心函数,也就是一个线程处理一个像素。
GPU将屏幕分成一个一个的2×2的像素块,因为逻辑上一个Warp包含了32个线程,也就是说一个Warp处理的是8个像素块,这就解释了为什么上面我们看到的色块是8*8的。
思考:如果渲染WARP_ID…
同理,我们再以WARP_ID渲染为例,你认为如果将每个像素根据SM_ID渲染为不同亮度的红色,会得到什么结果?
大家可以思考一下
思考题答案以及代码片段请在三连截图,并私信回复“光栅化”
我是优梦创客的老雷,一个14年经验的游戏公司主程和引擎架构师,同时也是一位爱分享的游戏开发技术UP主
我会保持更新每月不少于2集、每年不少于26小时的干货视频
如果你觉得不错,请一键三连支持我们
也欢迎你保持关注,以获取我的最新更新
当然,我也准备了几百个小时的技术美术教程分享,欢迎私信了解
小结
最后,我们对今天的分享做一个小结。今天我们:
- 了解了光栅化在图形渲染流水线中的地位和作用
- 知道了GPU、GPC、SM的关系
- 也知道了SM、Warp、Thread的关系
- 并且通过实践理解了光栅化在GPU中是如何被调度的
进阶
这里还有一些可以进阶学习的知识点,在这里列出,供同学们参考:
GPU如何处理像素运算?
在输出到渲染目标前,GPU还会做哪些事情?
移动平台的GPU跟桌面端有哪些不同?
如何针对移动端GPU做优化?
CPU和GPU在计算上有什么本质区别?
如何编写高效能Shader代码?
参考
完整视频请点击本链接观看:https://www.bilibili.com/video/BV1gUWDe2ECU
技术交流请加v:alice17173