现代 GPU:它们有多“智能”?

lxg*_*xgr 11 graphics gpu

有许多关于 3D 编程(OpenGL 或 DirectX)和相应图形管道的资源可用,但我想知道它们在现代 GPU 上实现的级别。

到目前为止,我已经能够发现已经从实现图形管道各个阶段的非常专业的电路转向了更通用的方法。这种转换已部分反映在可编程着色器形式的 3D API 上。大多数晶体管似乎专用于执行实际着色器指令的大规模并行 SIMD 单元。

但是图形管道的其余部分呢?这仍然在硬件中实现吗?

现代 GPU(想想 Nvidia Fermi)基本上是一组“愚蠢的”SIMD 阵列,这些阵列从 CPU 和各种缓存中获取指令和数据,所有将图形管道映射到这些指令的实际逻辑都发生在图形驱动程序中?

或者在 GPU 的某处是否有一些控制单元将传入的高级指令和数据流(编译的着色器程序、顶点数据和属性以及纹理)转换为实际的 SIMD 指令并负责同步、内存分配等?

我怀疑现实介于这两个极端之间,答案会相当冗长,而且基于大量猜测(某些 GPU 供应商拒绝发布有关其产品的任何文档,更不用说驱动程序了,这肯定是有原因的)源代码...),但任何有关正确方向和有用资源的提示都将不胜感激。

到目前为止,我发现了一系列博客文章,这些文章对于更多地了解现代 GPU 非常有用,但是我缺少关于整体架构的某种更高层次的概述 - 我可以理解大部分提到的概念,但是不太明白它们是如何组合在一起的。

all*_*tic 8

到目前为止,我已经能够发现已经从实现图形管道各个阶段的非常专业的电路转向了更通用的方法。这种转换已部分反映在可编程着色器形式的 3D API 上。大多数晶体管似乎专用于执行实际着色器指令的大规模并行 SIMD 单元。

正确的。基本上,由于旧 GPU 上的特征尺寸相对较大,因此有效实现基本照明、抗锯齿、纹理映射、几何等功能的唯一方法是使用“固定功能”管道。他们为了性能而牺牲了灵活性,因为他们没有足够的芯片密度来使用更通用的大规模并行 SIMD 架构(如当前的 GPU)来实现它。

现代 GPU(想想 Nvidia Fermi)基本上是一组“愚蠢的”SIMD 阵列,这些阵列从 CPU 和各种缓存中获取指令和数据,所有将图形管道映射到这些指令的实际逻辑都发生在图形驱动程序中?

某些事情仍然在硬件中完成;其他人不是。例如,在最后阶段仍然使用ROP将像素数据推送到 VGA 芯片组。注意我在这里使用“VGA 芯片组”作为通用术语来指代将视频信号传输到您的显示器的机制,而不管它在任何方面是否真正是“VGA”。

的确,目前的 GPU 架构,例如 Nvidia Fermi 和 AMD Southern Islands,在大多数情况下是大规模并行 CPU,它们具有自定义指令集,并且每个单独的“核心”都非常弱,但也有一整个许多核心(有时几千个)。但是那里仍然有特定于图形的硬件:

  • 硬件视频解码通常在很大程度上使用固定功能的芯片来完成。当涉及 DRM(数字限制管理)时尤其如此。有时,“硬件”视频解码实际上是指一组固件引导的指令,这些指令仅作为 SIMD 内核的常规旧任务提供。这真的取决于。

  • 除了极少数特定于计算的 Nvidia 板 (Tesla) 外,几乎所有“通用 SIMD”显卡都有专用于视频输出的完整硬件阵列。视频输出与渲染不同;固定功能输出元素包括 LVDS/TMDS/HDMI/DisplayPort 编解码器、HDCP,甚至音频处理(基本上是一个小 DSP),因为 HDMI 支持音频。

  • “图形内存”仍然与 GPU 一起存储在板载上,因此它们不必遍历冗长且延迟相对较高的 PCIe 总线来访问系统 RAM,与更昂贵的相比,它本身更慢,响应时间更长,质量更高、速度更快的图形内存(例如 GDDR5),与系统内存相比,容量更小但速度更快。在图形内存中存储内容并将其从那里检索到 GPU 或 CPU 的过程仍然几乎是一个固定的功能操作。一些 GPU 有自己的“IOMMU”,但这个内存管理单元与 CPU 不同(独立)。然而,对于最近集成到其处理器(Sandy 和 Ivy Bridge)中的英特尔 GPU 而言,情况并非如此,其中内存架构几乎完全“一致” 系统内存)和从图形内存中读取对于 CPU 和 GPU 来说一样便宜。

或者在 GPU 的某处是否有一些控制单元将传入的高级指令和数据流(编译的着色器程序、顶点数据和属性以及纹理)转换为实际的 SIMD 指令并负责同步、内存分配等?

SIMD 的“原生”语言几乎总是由驱动程序在软件中生成,而不是由 GPU 自己的固件生成。对于 DirectX 9 / OpenGL 2.x 级别功能尤其如此。以 HLSL、GLSL 或 OpenGL ARB 着色器汇编器等高级语言编写的着色器最终由驱动程序通过敲击某些寄存器并执行所需的 PCIe 环来转换为 GPU 指令,以便发送计算和/或渲染的批处理缓冲区命令。

一些东西,比如硬件镶嵌(DirectX 11 / OpenGL 4.0)再次以固定功能的方式被推入硬件,类似于过去他们用来做几乎所有事情的方式。这是因为,再一次,性能限制要求进行这些计算的最有效方法是为其配备专用电路,而不是让固件或驱动程序“编程”SIMD 来执行此操作。

我怀疑现实介于这两个极端之间,答案会相当冗长,而且基于大量猜测(某些 GPU 供应商拒绝发布有关其产品的任何文档,更不用说驱动程序了,这肯定是有原因的)源代码...),但任何有关正确方向和有用资源的提示都将不胜感激。

AMD 和 Intel 公开了关于他们最近的 GPU 的非常强大的文档,以及用于 Linux 的完全可用的开源图形驱动程序(请参阅 Mesa 和 Direct Rendering Manager 项目)。如果您查看这些驱动程序中的一些代码,您会发笑,因为图形驱动程序编写者实际上必须在“软件”中实现诸如绘制各种形状或图案之类的几何图形(但使用硬件命令来提交真实的对硬件进行处理),因为 GPU 固件和固定功能的东西都不再存在以在硬件中完全处理它:) 他们必须做些什么来支持新的 OpenGL 1.x / 2.x硬件。

进化是这样的:

  • 很久以前(在实时 3d 渲染被认为可能之前):CPU 上的光线追踪对于非实时渲染来说是正常的。对于您在早期版本的 Windows 中看到的简单图形,CPU 的速度足以在没有固定功能硬件的情况下绘制简单的形状(矩形、字体字符、阴影图案等),但无法绘制太复杂的东西。
  • 很久以前(OpenGL 1.x):几乎所有东西都由固态硬件实现;“电动”固定功能即使对于基本操作也是常态
  • 不久前(OpenGL 2.x):向使 GPU 更具可编程性的转变已经开始。5 年前硬件上的“片段着色器”(又名像素着色器)几乎可以像 CPU 一样执行任意计算,但它受到架构的限制,架构仍然非常面向图形。因此,OpenCL / DirectCompute 在此硬件上不可用。
  • 最近(OpenGL 3.x):向通用 GPU 的过渡大部分已经完成,但它们当然针对涉及批量提交的大型数据矩阵(想想线性代数)的工作负载进行了优化,而不是可以高效运行的 CPU非常小的数据的长序列(依次为 1+1、2*4、5*6 等)通用计算可通过 OpenCL、CUDA 等进行,但硬件仍然不是全功能的“SIMD 协处理器”因为 (a) 您仍然需要敲击特定于硬件的寄存器才能使用 GPU 功能;(b) 由于 PCIe 总线开销,从 GPU VRAM 读取非常慢(从 GPU 读取在当前架构上不是很优化);(c) 内存和缓存架构与 CPU 不一致;许多传统的固定功能硬件仍然存在。
  • 现在(OpenGL 4.x):摆脱了很多遗留的固定功能硬件。稍微改善了 GPU 读取延迟。IOMMU允许在 VRAM 和系统内存之间进行(转换的)硬件辅助映射。还引入了硬件镶嵌,带回了固定功能的元素。
  • 未来 ( HSA):GPU 基本上是一个协处理器。它几乎与 CPU 完全集成,GPU 和 CPU 之间的阻抗非常小(用于读/写),即使对于 PCIe 总线上的专用 GPU 也是如此。完全一致的内存架构——“mi memoria es su memoria”(我的记忆就是你的记忆)。用户空间程序可以从“VRAM”中读取数据,就像从系统内存中读取数据一样,无需驱动程序垫片,硬件会负责它。你有 CPU 用于“串行”处理(做这个,然后做那个,然后做这个,然后做那个),用于适度数量的数据,还有 GPU 用于“并行”处理(在这个巨大的数据集上执行这个操作并将其划分)看你怎么看合适)。GPU 所在的板子可能仍然有 ROP、HDMI 编解码器等,但这些东西对于显示输出来说是必需的,