GPU 渲染管线和硬件架构浅谈

739次阅读  |  发布于2年以前

本文简述了 GPU 的渲染管线和硬件架构,对一些常见问题进行了讨论和分析。特此分享出来,与君共勉。当然,由于本人并未从事过硬件开发的工作,文中有错漏之处在所难免,欢迎批评指正。另外本文内容量很大,总结下来有以下几点核心内容:(1)移动平台渲染管线 TBDR 的介绍; (2)GPU 缓存体系的介绍;(3)Warp 的执行机制;(4)常见的如 AlphaTest 或者分支对性能的影响。

序言

一、GPU 渲染管线

1.1 渲染管线简述

所谓渲染管线,就是 CPU 传送给 GPU 一堆数据(顶点、纹理等),经过一系列处理,最后渲染得出来一副二维图像。有以下几个阶段。

1.1.1 应用程序阶段
1.1.2 顶点处理阶段
1.1.3 光栅化阶段
1.1.4 逐片元操作

1.2 IMR: Immediate Mode Rendering

上图展示了一个非常经典的 IMR 渲染管线,也是桌面端最常见的 GPU 架构。GPU 会在每个 drawcall 提交中,按照管线的顺序处理每个图元。

1.2.1 优势:
1.2.2 劣势:

1.3 TBR: Tile-based Rendering

1.3.1 为什么要使用 TBR 架构
1.3.2 TBR 架构的原理
1.3.3 优势
1.3.4 劣势

1.4 TBDR: Tile-Based Deferred Rendering

1.5 总结

二、GPU 硬件架构

2.1 GPU 和 CPU 的差异

这张图展示了 CPU 和 GPU 的硬件差异。

CPU 和 GPU 的差异可以描述在下面表格中:

2.2 CPU 的缓存体系和指令执行过程

虽然本文主要讲的是 GPU 架构,不过 CPU 和 GPU 有很多地方是相通的,同时又有一些设计方向是相反的。了解 CPU 可以帮助我们更好的理解 GPU 的执行过程。

2.2.1 内存的硬件类型
2.2.2 CPU 的缓存体系
2.2.3 CPU 指令的执行过程

2.3 GPU 渲染过程

具体渲染过程,其实就是经典的渲染管线的执行过程。可以跟上一部分的渲染管线流程图对照阅读。推荐阅读 Life of a triangle - NVIDIA's logical pipeline 一文。

2.4 桌面端 GPU 硬件架构

上图展示的是 NVIDIA Fermi 架构的示意图。不同的 GPU,架构差异较大,但是大体都包含下列核心组件:

2.5 Shader Core 的主要构成单元

2.6 GPU 的内存结构

2.6.1 UMA (Unified Memory Architeture)

2.6.2 GPU 缓存的分类
GPU 缓存结构

内存访问速度

内存的存取速度从寄存器到系统内存依次变慢:

存储类型 Register Shared Memory L1 Cache L2 Cache Texture/Const Memory System Memory
访问周期 1 1~32 1~32 32~64 400~600 400~600
NVIDIA 的内存分类

查资料的时候经常会看到这些概念,但是 NVIDIA 的内存分类是为 CUDA 开发服务的,与游戏开发或者移动 GPU 还是有一些差异的。所以这里只需要简单了解即可。

2.6.3 Cache line
2.6.4 Memory Bank 和 Bank Conflict

2.7 GPU 的运算系统

2.7.1 SIMD (Single Instruction Multiple Data) 和 SIMT (Single Instruction Multiple Thread)
2.7.2 Warp 线程束
2.7.3 Stall 和 Latency Hiding (延迟隐藏)
2.7.4 Warp Divergence

2.8 其他重要概念

2.8.1 Pixel quad
2.8.2 EarlyZS
2.8.3 Hierarchical-z 和 Tile-based Rasteration

这两个是硬件提供的优化。

2.8.4 Register Spilling 和 Active Warp
2.8.5 Mipmap
2.8.6 纹理采样和纹理过滤

2.9 从硬件角度理解 GPU 的执行逻辑

2.9.1 GPU 中的可编程元件和固定管线元件
2.9.2 从硬件角度看 EarlyZ
2.9.3 GPU 核心的乱序执行和保序

三、移动平台 GPU 架构

3.1 PowerVR 架构

3.1.1 PowerVR GPU 管线

3.1.2 PowerVR GPU 硬件架构

3.2 Mali 架构

3.2.1 Mali GPU 管线

3.2.2 Mali GPU 四代架构演变

Mali GPU 的架构演变非常直观的展示了移动 GPU 的进化过程。再加上 Mali 的开发资料比较多,所以这里分别介绍了 Mali 的四代架构。这里可以和上文介绍的 GPU 管线和硬件架构的理论形成参考和对照。

Utgard (2007)
Midgard (2012)

Bifrost (2016)

Valhall (2019)

3.2.3 Mali GPU 其他技术
Forward Pixel Kill
IDVS: Index-Driven Vertex Shading
AFBC: Arm Frame Buffer Compression

AFBC 是 FrameBuffer 的快速无损压缩。可以节省带宽,也可以降低显存占用。这个对开发者是无感知的。其他平台也都有类似的压缩技术。

Transaction Elimination

Transaction Elimination 也是一种很有效的降低带宽的方法。在有些情况下,只有部分 Tile 中的内容会变化(例如摄像机不动,一个 Tile 中只有静态物体)。此时通过比较该 Tile 前一次和本次的渲染结果的 CRC 值,可得到 Tile 是否变化,如果不变,那么就没有必要执行 Tile 到 System Memory 的写回操作了,有效地降低了带宽占用。

Hierarchical Tiling

根据图元的大小选择合适的 Hierarchy Level 的 Tile。降低 Tiling 阶段对主存的读取和写入开销。

Shared Memory

3.3 Adreno 架构

Flexable Render
Low Resolution Z

3.4 总结

四、常见问题的分析与讨论

4.1 DrawCall 对性能的影响

4.2 AlphaTest 和 AlphaBlend 对性能的影响

4.2.1 桌面平台
4.2.2 移动平台

4.3 不透明物体是否需要排序

4.4 PreZ pass/Depth prepass 是否有必要

4.5 Shader 中的分支对性能的影响

4.5.1 分支对性能的影响
4.5.2 编译器对 shader 的优化
4.5.3 分支的性能隐患
4.5.4 multi_compile 的副作用

如果不使用 if-else,那么另外一个选择就是 multi_compile。遗憾的是,使用 multi_compile 同样会有明显的副作用。

4.5.5 关于分支的建议

4.6 Load/Store Action 和 Memoryless

4.6.1 Load/Store Action
4.6.2 Memoryless
4.6.3 Render Target 切换

4.6.4 避免 CPU 回读 GPU 数据
4.6.5 Pixel local storage
4.6.6 移动平台延迟渲染优化

4.7 MSAA 对性能的影响

4.7.1 MSAA
Family 16x16 Tile 16x8 Tile 8x8 Tile
<= Bifrost Gen 1 128 bpp 256 bpp 512 bpp
>= Bifrost Gen 2 256 bpp 512 bpp 1024 bpp
4.7.2 Alpha to coverage

4.8 Shader 的优化建议

结语

参考资料

PowerVR (Imagination / Apple)

Mali (Arm)

Adreno (Qualcomm)

GPU 硬件架构及渲染管线

开源库

Copyright© 2013-2020

All Rights Reserved 京ICP备2023019179号-8