外网有很多关于GPU开发的优质博客,中文互联网关于这方面的资源甚少,决定做个搬运工,用中文在此记录。今天翻译的文章来自偶然发现的Understanding Modern GPUs,写于2011年。尽管过去了11年,GPU技术已经有了长足的发展,但问渠哪得清如此,这些资料依然值得学习借鉴。

序言

“GPU是如何工作的?”这是个我经常被别人问到的话题。这个问题十分广泛,有很多回答会去解释GPU如何使用顶点(vertices),矩阵(matrices),纹理(textures )等等去绘制图元(primitives)。但我更喜欢写博客介绍我所了解的计算机图形学的底层知识,介绍图形API(DirectX,OpenGL等)如何与硬件交互,以及数据如何在计算怪兽(computing monsters,作者指代GPUs)之间被传递。我特地强调了computing,现在GPUs能够计算海量的向量数据,这使得它们尤其适合高性能计算,而不只是用来绘制你现在的XXX标题。
BTW,我在这里找到了另一个解释类似内容的博客(好像已经打不开了2333)。这篇文章里的某些解释是带有猜测性质的,可能不是完全正确或完全错误的。GPU制造商不想暴露他们的架构,但仍可以通过阅读他们的API,文档和第三方研究来学习很多东西。OpenCL是一个良好的开端,因为API引入的许多概念似乎都直接映射到硬件如何实现这些操作。您可能希望在Intel,AMD和NVIDIA的网站上查看相关文档。我建议阅读以下论文,以获取有关GPU的更深入的信息:

3D图形管线介绍

首先,我想对一个常见的3D图形管道做一个简单的介绍,稍后我将对OpenCL/HPC进行简短的介绍。如果您需要更多信息,本节中介绍的概念可以帮助您更轻松地将问题提交给Google(2333)。
在当前高度可编程的GPU时代之前,各个API的管线都是固定的。这些管道的某些阶段仍然以某种方式存在于当前的3D引擎中,但实现/移植这些功能或完全忽略它们的决定权在使用者手中。下图中可以找到现代图形管线的一组常见阶段(非常简化):

pipeline.png

让我们从一组顶点和着色器(shaders)开始。着色器是在 GPU 内部运行并对顶点进行变换的小程序(例如通过空间变换和投影来获得它们在屏幕空间中的位置)。这已经非常简化了,现代API在可编程顶点处理器之后添加了更多阶段,这使我们可以给定新的顶点或图元,但让它们都落在屏幕之外。使用顶点流,管线会构建一些图元(点、线和顶点),并进入光栅化阶段(rasterization )。在此阶段,我们可以为每个片段定义运行所需的片段着色器。这些片段可能会在经过z-test和一些最终处理后被写入图像缓冲区。因为使用了不同的着色器,此逻辑是高度可编程的。

shader_full.jpeg

这一切背后的要点是,GPU架构如何利用输入输出数据流中的数据相互独立这一前提,实现了数据级别的并行。对我们来说,这些数据包是顶点和像素。如果你在设计中利用了这一点,就可以并行操作数百个顶点和像素。

OPENCL简介

这种从顺序处理到并行SIMD处理的范式转换,除了可以用来执行顶点变换和计算像素值之外,还被用于执行任何类型的重复计算。OpenCL就是这样一个API,它把GPU作为计算设备,在上面运行处理数据的小程序(kernel)。OpenCL的想法是,在问题域中的一个点上运行kernel,只要每个点都与其他点高度隔离,就可以实现并行处理(就像前面图形管线介绍的顶点和像素一样)。该 API 定义了一个执行模型和一个内存模型,该模型映射到 GPU 建立的限制中。在域中的某个点上运行的程序称为working-item(就像一个thread)。你必须定义一个N维的working-item并将它们分成working-groups。这些working-groups可以共享该working-groups专用的公共内存区域。下面是OpenCL的memory model。

openclmem.png

为了最大限度地提高吞吐量,我们会希望在 GPU 内部加载所有流处理器,并充分利用芯片的其他区域,例如纹理单元/内存提取器,因为它们与 ALU 并行工作。此外,与host memory的往返速度很慢,必须最小化。我们将在以后的帖子中更详细地看到这一点。

可以在这里找到OpenCL的一个很好的介绍:http://www.amd.com/us/products/technologies/stream-technology/opencl/pages/opencl-intro.aspx

在下一篇文章中,我们将讨论更多底层的东西:API如何与驱动程序和硬件通信,以及如何协调GPU以与CPU并行运行。