发布网友 发布时间:2022-11-25 17:57
共1个回答
热心网友 时间:2023-10-09 15:13
以 nVidia MaxWell 为例,分析 GPU 的硬件架构
SP 是GPU 的最小运算单元,相当于一个微型 CPU,也叫 CudaCore。
PolyMorph Engine 是用来执行固定渲染步骤的硬件,一般包括这几个成部分
线程束(warp)是 GPU 进行任务调度的基本单位,一个 warp 包含 32 个线程,也就是说 GPU 的调度,是以32个线程为单位的,即使只处理3个顶点,也会调度 32 个线程,占用 32 个 SP 进行计算,其中 29 个将会被 mask 为不可用状态
(1) 图形 API (OpenGL/DirectX/Metal) 发出DrawCall 时,指令被推送到驱动程序,对指令进行合法性检查后,指令被推送到 GPU 可以读取的 pushbuffer 中。
(2) 一段时间或显式调用 flush 指令时,驱动程序将 pushbuffer 中的指令发送给 GPU,GPU 中的主机接口 (HostInterface) 接受命令,通过 FrontEnd 进行处理。
(3) 图元分配器(Primitive Distributor) 处理 indexbuffer 中的顶点数据,产生三角形的批次,发送给多个 GPC 处理
(4) 指令到达 GPC 后,每个 SM 中 Poly Morph Engine 中的 Vertex Fetch 模块负责通过三角形索引取出三角形数据。
(5) 获取数据后,SM中的 Warp Scheler 开始以 32 个线程为一组的线程束 warp 来调度,处理顶点数据。warp 是单指令多线程(SIMT, Single Intruction Multiple Thread) 的实现,32个线程同时执行同样的指令,但是各线程的数据不一样,比如 32 个顶点同时执行顶点着色器的指令。
(6) 单个 warp 中的线程会锁步(lock step)执行指令,没有分配到数据的线程将会被打上掩码,线程不能独立调度,必须以 warp 为单位,但不同 warp 之间是独立的。
(7) 指令执行时间长短不一样,特别是内存加载比较耗时,warp 调度器可能会直接切换到另外一个没有内存等待的 warp 执行,GPU 因此能够克服内存读取延迟。warp 在寄存器堆 RegisterFile 中都有属于自己的寄存器。
(8) 当 warp 执行完了顶点着色器的指令后,运算结果会传递给 Poly Morph Engine 中的 Viewport Transform 模块进行处理,通常顶点着色器输出的是裁剪空间的坐标,Viewport Transform 对顶点进行裁剪并进行 视口变换,也就是屏幕映射,将顶点坐标变换为屏幕坐标。
(9) 得到屏幕坐标后,就可以进行光栅化了,三角形被分割,分配给多个 GPC(通常按照屏幕分 Tile 进行分配),三角形的范围决定了将会被分配给哪一个 GPC 的 Raster Engine,每个 Raster Engine 覆盖了屏幕的若干 Tile。
(10) GPC 上的 Raster Engine 对三角形数据进行光栅化,得到每个三角形所覆盖的像素信息,这里通常会进行背面剔除和 early-z 剔除操作。
(11) 一个三角形的三个顶点,每一个顶点都会执行一次顶点着色器和 Viewport Transform,处理后的信息传递给 Raster Engine 进行光栅化,得到若干个片元,那么每个片元的数据(位置、颜色、法线等)是怎么得来的呢?SM 上的 Attribute Setup会根据顶点数据进行 插值得到片元数据,L1&L2 缓存用来存放这些数据以确保 片元着色器 能够进行处理。
(12) 8个 2x2 的片元块(共32个)将会被 SM 中的 Warp Scheler 分配到一个 warp 中执行片元着色器的指令。
(13) 片元着色器执行指令,完成片元颜色和深度计算,此时需要基于三角形的原始 API 提交顺序,将数据移交给渲染输出单元 ROP (Render Output Unit),一个 ROP 内部有很多 ROP 单元,ROP 单元中会处理逐片元操作如深度测试、与 FrameBuffer 中片元的混合等。
(14) ROP 拿到片元数据,通过访问 FrameBuffer 进行逐片元操作后,通过 Crossbar 将结果写入到 FrameBuffer,渲染流程结束。
GPU 中的内存分为若干类型,不同类型的内存读取速度相差比较大
Shader 中直接使用的寄存器内存速度很快,纹理和常常量内存以及全局内存的速度相对比较慢。
上述流程是 MaxWell 桌面 GPU 架构的渲染详细过程。然而移动端 GPU 的架构和桌面 GPU 是不同的。
移动端渲染流程是基于 Tile-Based 架构的,也叫 TBR(Tile-Based Render),针对一帧中的所有 DrawCall,先全部执行顶点着色器 VS,然后根据屏幕进行分块(Tile),基于 Tile 进行片元着色器(FS)的执行。
用一个例子来看。假如某一帧提交了两个DrawCall,每个DrawCall 包含了一个三角形,且两个三角形覆盖了全部屏幕。