GPU的诞生:从图形加速到通用计算
GPU的诞生:从图形加速到通用计算
计算机图形学的发展历程揭示了一个深刻的技术悖论:那些最初为满足人类视觉体验而诞生的专用硬件,最终却成为了突破计算能力边界的核心引擎。图形处理器(Graphics Processing Unit,GPU)的演进史,正是这一悖论的最佳诠释。当我们今天谈论人工智能革命的算力基础设施、讨论大语言模型训练所需的惊人计算资源时,很难想象这一切的起点,竟然是电子游戏中那些令人眼花缭乱的光影效果。
要理解GPU为何能够在通用计算领域掀起革命,我们必须首先回到它的技术原点,审视那些塑造了现代GPU架构的早期决定。1990年代初期,当个人电脑开始进入千家万户,图形用户界面成为人机交互的主流方式时,传统的CPU架构在处理日益复杂的图形渲染任务时显得力不从心。这种性能瓶颈催生了一个全新的硬件门类——专用图形加速芯片。从最初的简单帧缓冲区控制器,到具备几何变换能力的几何处理器,再到完全可编程的着色器流水线,GPU经历了数次重大的架构革命。每一次演进都不仅仅是性能的提升,更是对计算范式本质的重新定义。
理解这段历史,对于把握当代算力革命的技术脉络至关重要。英伟达在1999年推出GeForce 256时,首次正式使用"GPU"这一术语来描述这种新型处理器。这一命名绝非简单的营销噱头,而是对一种全新计算范式的正式宣告。在此之前,图形处理任务虽然也需要专用芯片,但这些芯片通常被视为CPU的附属组件,功能的定义和调用完全由主处理器控制。GeForce 256的出现改变了这一格局:它将几何变换、光照计算、像素处理等核心图形功能整合为一个独立可编程的处理器单元,从而在事实上创造了一种与CPU并行运作的专用计算架构。这种架构分离为后来的通用计算GPU(General Purpose GPU,GPGPU)革命奠定了物理基础。
本章将深入探索GPU从专用图形芯片到通用并行处理器的技术演进历程。我们将从图形渲染的基础原理出发,分析固定功能渲染架构如何逐步走向可编程化;探讨可编程着色器如何为通用计算打开大门;详细审视英伟达GeForce 256的技术创新及其历史意义;并最终揭示这场硬件革命如何为后续的通用计算转型埋下伏笔。通过这一历史脉络的梳理,我们将理解为何GPU的架构特征——大规模并行计算单元、高带宽内存访问、分支预测的简化——使其成为现代人工智能计算的不二之选。
图形渲染的技术基础与早期发展
计算机图形学的核心目标是将从三维几何描述转换为二维像素图像的过程自动化。这一过程在技术上被分解为一系列复杂的处理阶段,每个阶段都将前一个阶段的输出作为输入,逐步将抽象的场景描述转化为可在显示器上呈现的像素数据。理解这些处理阶段的具体内容和相互关系,是把握GPU架构演进的关键前提。
顶点处理与几何变换
三维场景的渲染始于顶点(Vertex)数据的处理。顶点是三维空间中的离散点,每个顶点除了包含位置坐标外,还关联着法向量、纹理坐标、颜色信息等多种属性。顶点处理阶段的核心任务是对这些顶点进行几何变换,包括模型变换(Model Transformation)、视图变换(View Transformation)和投影变换(Projection Transformation)。
模型变换将顶点从模型坐标系转换到世界坐标系。这一步骤定义了场景中各个物体的位置、朝向和缩放比例。假设一个三维模型定义在局部坐标系中,其顶点位置为 $\mathbf{v}_{local}$,模型变换矩阵为 $M$,则经过模型变换后的顶点位置为:
$$\mathbf{v}_{world} = M \cdot \mathbf{v}_{local}$$
视图变换将所有顶点从世界坐标系转换到观察者(摄像机)坐标系。这一变换的本质是建立一个以摄像机位置为原点、以视线方向为负Z轴的坐标系。通过视图变换,场景中的所有物体都被重新定位到以摄像机为中心的坐标系统中。设视图变换矩阵为 $V$,则视图空间中的顶点位置为:
$$\mathbf{v}_{view} = V \cdot \mathbf{v}_{world}$$
投影变换将三维顶点投影到二维平面上。这一步骤模拟了人眼或相机将三维场景投影到视网膜或胶片上的物理过程。投影变换分为正交投影(Orthographic Projection)和透视投影(Perspective Projection)两种。透视投影更接近真实世界的成像规律,因为它能够正确表现远近物体的大小比例关系——远处的物体会显得更小。透视投影矩阵 $P$ 将顶点从观察空间转换到剪裁空间:
$$\mathbf{v}_{clip} = P \cdot \mathbf{v}_{view}$$
在剪裁空间中,超过可视范围(视锥体)的图元将被裁剪,而那些跨越可视边界的图元则会被分割。最终,投影后的顶点坐标被归一化为屏幕坐标,用于后续的栅格化过程。
光照计算与材质处理
几何变换确定了顶点在屏幕上的位置,而光照计算则决定了这些顶点的颜色和明暗程度。光照模型是计算机图形学中一个历史悠久的研究领域,从简单的朗伯反射模型(Lambertian Reflectance)到复杂的基于物理的渲染(Physically Based Rendering,PBR)模型,研究者们提出了众多各具特色的光照计算方法。
朗伯反射模型是最基础的光照模型,它假设理想漫反射表面的亮度与光源方向和表面法线之间夹角的余弦成正比。对于表面上的一点 $p$,其漫反射光照强度可以计算为:
$$L_{diffuse} = k_d \cdot I \cdot \max(0, \mathbf{N} \cdot \mathbf{L})$$
其中 $k_d$ 是漫反射系数,$I$ 是入射光强度,$\mathbf{N}$ 是表面法线,$\mathbf{L}$ 是从表面指向光源的方向向量。$\max$ 函数确保了当光源位于表面背面时不会产生负的光照强度。
除了漫反射,真实世界的表面还会表现出镜面反射特性。冯氏镜面反射模型(Phong Specular Model)在朗伯漫反射的基础上增加了一个镜面反射分量:
$$L_{specular} = k_s \cdot I \cdot \max(0, \mathbf{R} \cdot \mathbf{V})^n$$
其中 $k_s$ 是镜面反射系数,$\mathbf{R}$ 是光线的反射方向,$\mathbf{V}$ 是观察方向,$n$ 是光泽度指数,用于控制镜面高光的锐利程度。光泽度越高,高光越集中,表面看起来越光滑。
这些光照计算需要在每个顶点或每个像素上执行,涉及大量的向量运算和超越函数(三角函数、幂函数等)计算。在没有专用硬件的年代,这些计算完全由CPU执行,严重制约了场景复杂度和渲染帧率的提升。正是在这一背景下,专用图形加速芯片应运而生,其首要目标就是将顶点处理从CPU上卸载下来。
光栅化与片段处理
经过顶点处理的图元(点、线、三角形)被投影到二维屏幕上,光栅化(Rasterization)阶段的任务是将这些连续的几何图元转换为离散的像素(或片段,Fragment)集合。光栅化过程涉及大量的内部测试,包括裁剪测试(判断片段是否在视锥体内)、背面剔除(判断三角形是否为朝向观察者的正面)、深度测试(判断片段是否被之前渲染的几何体遮挡)等。
片段处理是渲染流水线的最后阶段,负责为每个片段计算最终的颜色值。这一阶段通常包括纹理采样、颜色混合、环境光照等操作。纹理采样是片段处理中最耗费计算资源的操作之一,因为它需要根据片段的纹理坐标从纹理贴图中读取对应的颜色值。纹理采样涉及坐标变换、滤波计算和内存访问等多个子步骤。
早期图形芯片将光栅化和片段处理视为一个相对简单的阶段,主要处理固定功能的操作,如简单的纹理混合和雾效计算。然而,随着纹理映射技术的普及和人们对视觉效果要求的提高,片段处理逐渐成为渲染管线中最耗时的瓶颈。这一趋势最终推动了可编程着色器的诞生,允许开发者用自定义程序替代固定的片段处理逻辑。
固定功能渲染架构的演进
GPU的早期发展可以追溯到1990年代初期,当时个人电脑图形市场刚刚起步,3D游戏开始进入主流消费领域。在这一背景下,多家芯片厂商开始研发专用图形加速芯片,这些芯片最初只能处理特定的图形操作,但随着技术进步,其功能逐渐扩展,形成了所谓的“固定功能渲染架构”(Fixed-Function Rendering Pipeline)。
3dfx Voodoo:3D加速的先驱
1996年,3dfx Interactive公司推出了Voodoo Graphics,这是一款专门用于3D图形加速的子卡产品。Voodoo的诞生标志着消费级3D图形加速时代的开启,它将原本只能在高端工作站上才能实现的光照和纹理映射效果带入了普通家庭。
Voodoo Graphics的架构设计极具针对性:它专门负责处理3D渲染管线中最计算密集的部分,而将几何变换和顶点处理留给主CPU。这一设计决策反映了对当时技术条件的务实考量。1990年代中期的CPU虽然在通用计算方面已经相当强大,但在浮点运算能力方面还存在明显不足,难以高效执行大规模矩阵运算和超越函数计算。相比之下,专为图形处理设计的Voodoo芯片采用了高度流水线化的架构,能够以极高的吞吐率执行纹理采样和深度测试等操作。
Voodoo的技术规格在当时堪称惊艳:它支持高达640×480分辨率下的16位色渲染,最大填充率达到了每秒4500万个像素。在其帮助下,早期3D游戏如《雷神之锤》(Quake)和《古墓丽影》(Tomb Raider)首次在消费级硬件上实现了在当时看来相当逼真的3D视觉效果。玩家们第一次看到带纹理的地面、带光照的角落、带雾气效果的天空,这些如今看似平常的视觉效果在当时却带来了前所未有的沉浸感。
然而,Voodoo的专用化设计也带来了明显的局限性。作为一块子卡,Voodoo无法独立工作,必须搭配一块2D图形卡使用。更为重要的是,Voodoo完全无法编程——所有的渲染效果都通过芯片内置的固定功能电路实现。如果游戏开发者想要实现某种Voodoo硬件不支持的效果,比如复杂的阴影或环境映射,他们只能通过各种技巧来模拟,往往以牺牲性能为代价。
NVIDIA RIVA:集成化与可编程的萌芽
1997年,英伟达(NVIDIA)推出了RIVA 128,这是该公司进入图形芯片市场的首批产品之一。与Voodoo不同,RIVA 128是一款集成化的图形解决方案,它将2D显示和3D加速功能整合在同一块芯片上,简化了系统架构,降低了整机成本。RIVA 128还引入了对AGP(Accelerated Graphics Port)总线的支持,使其能够以更高的带宽访问系统内存中的纹理数据,突破了早期PCI总线对图形性能的制约。
更重要的是,RIVA 128开始引入一定程度的可配置性。它支持可设置的光照模式,允许开发者选择使用单光源还是多光源配置。虽然这种可配置性仍然非常有限,但它代表了图形硬件从纯固定功能向可编程方向演进的第一步。
1998年,英伟达推出了RIVA TNT,这是RIVA系列的第二代产品。TNT(TwiN Texel)这个名字来源于其创新的双像素管线架构:芯片内部集成两个并行的像素处理单元,能够在一个时钟周期内完成两个像素的着色处理。这种并行化设计是现代GPU架构的核心理念,尽管当时的并行度还非常有限。RIVA TNT还将最大分辨率提升到了1600×1200,支持32位色深渲染和双线性过滤纹理采样。
TNT的可配置性相比RIVA 128有了显著提升。开发者可以通过设置各种寄存器来控制雾效、透明度混合、深度缓冲等效果的行为模式。虽然这些控制仍然是通过预定义的参数实现的,而非真正的程序执行,但它们为开发者提供了更多的调优空间。
S3 Savage3D与Matrox G400:竞争格局的形成
在3dfx和英伟达激烈竞争的同时,其他厂商也在努力抢占图形芯片市场份额。S3 Graphics推出了Savage3D芯片,这是业界首款支持单周期三线性过滤的消费级图形处理器。三线性过滤是一种高级纹理滤波技术,能够在不同的MIP贴图级别之间平滑过渡,消除纹理锯齿和闪烁现象。Savage3D还引入了S3TC纹理压缩算法的硬件支持,这种压缩算法能够将纹理数据压缩到原始大小的六分之一,同时保持可接受的质量水平。
Matrox公司的G400是另一款值得关注的产品。G400在1999年推出,它引入了环境映射(Environment Mapping)硬件加速功能,这是实现金属和玻璃等材质真实感效果的关键技术。环境映射通过预计算的纹理来模拟表面反射,G400能够以硬件方式执行这种映射计算,大大降低了这类效果的实现难度。
从这些早期产品的特性可以看出,1990年代末期的图形芯片市场呈现出一个明显的趋势:各家厂商在提升性能的同时,也在不断扩展可配置性和可编程性的边界。固定功能架构虽然仍然占据主导,但已经触及了其扩展能力的极限。开发者们越来越频繁地遇到这样的困境:他们想要实现的视觉效果,在现有硬件上要么根本无法实现,要么只能以极低的帧率运行。这种局限性最终催生了可编程着色器架构的诞生。
可编程着色器的革命
真正意义上改变图形硬件发展方向的关键技术创新,是可编程着色器(Programmable Shader)的引入。着色器本质上是运行在图形处理器上的小程序,它们定义了顶点处理、几何处理或片段处理的具体逻辑。与固定功能硬件只能按照预定义方式处理图形数据不同,可编程着色器允许开发者完全控制这些处理阶段的每一个细节。
着色器模型的出现
1999年,NVIDIA在推出GeForce 256的同时,引入了开创性的"Transform and Lighting"(T&L,几何变换与光照)引擎。虽然从严格意义上讲,T&L引擎还不是完全可编程的——它仍然基于固定的算法执行几何变换和光照计算——但它首次将这些原本由CPU执行的计算密集型任务转移到了专用硬件上,大幅提升了图形渲染的效率。
真正的可编程性突破来自于着色器模型(Shader Model)的演进。2001年,NVIDIA推出了GeForce 3,这是首款支持可编程顶点着色器(Vertex Shader)的消费级图形处理器。GeForce 3的顶点着色器允许开发者使用一套类汇编语言的指令集来编写处理顶点的程序,这些程序可以完全替代硬件内置的几何处理功能。
顶点着色器的指令集相对简洁,主要包括向量运算指令(如加法、乘法、点积、叉积)、矩阵运算指令、超越函数指令(正弦、余弦、指数、对数等)以及纹理采样指令。开发者可以使用这些指令组合出任意复杂的顶点处理逻辑,从简单的顶点混合动画,到复杂的程序化地形生成,都可以在顶点着色器中实现。
2002年,NVIDIA在GeForce 4 Ti系列中引入了可编程片段着色器(Fragment Shader),当时称为"Pixel Shader"。片段着色器的灵活性比顶点着色器更进一步,因为它允许开发者直接控制最终像素的颜色计算。通过片段着色器,开发者可以自定义纹理过滤算法、创建复杂的材质效果、实现非真实感渲染(Non-Photorealistic Rendering)等多种视觉风格。
汇编着色器到高级语言的演进
早期着色器的编程方式与现代开发者熟悉的模式有显著差异。最初的着色器程序必须使用类汇编语言编写,这种编程方式不仅效率低下,而且极容易出错。开发者需要手动管理寄存器分配、优化指令序列、理解底层硬件的执行模型,这些要求将大量潜在的图形开发者挡在了可编程图形硬件的门外。
为了解决这一问题,各大图形API提供商开始开发着色器高级语言。2002年,NVIDIA推出了Cg(C for Graphics)语言,这是一种类似C语言的着色器编程语言。Cg提供了丰富的数据类型、流程控制结构和标准库函数,大大降低了着色器编程的门槛。开发者可以使用更直观的语法表达复杂的图形算法,而编译器则负责将这些高级代码转换为底层硬件指令。
微软也不甘落后,在DirectX 9中引入了High-Level Shading Language(HLSL),这是DirectX API的原生着色器语言。HLSL与Cg在语法上非常相似,两者实际上共享了很大一部分设计理念。这种相似性并非巧合——NVIDIA和微软在Cg语言的开发过程中进行了密切合作,试图建立一套统一的着色器编程标准。
OpenGL ARB(架构审查委员会)则推出了OpenGL Shading Language(GLSL),这是一种作为OpenGL扩展发布的着色器语言,后来成为OpenGL 2.0的核心组成部分。GLSL的语法与C语言有显著的差异,采用了更接近数学表达式的风格,这使得它在图形编程社区中获得了广泛的支持。
这些高级着色器语言的出现标志着图形编程民主化的开始。现在,普通的游戏开发者无需深入了解底层硬件架构,就可以编写复杂的视觉效果。着色器程序通过编译器转换,可以在不同的GPU架构上高效运行,这为图形技术的快速发展奠定了基础。
统一可编程流水线的诞生
尽管可编程着色器带来了前所未有的灵活性,但早期GPU的架构仍然存在一个根本性的限制:顶点着色器和片段着色器运行在完全独立的硬件单元上,它们的资源和处理能力是固定分配的。这意味着当场景中顶点处理任务繁重而片段处理任务较轻时,片段处理硬件会处于空闲状态;反之亦然。这种资源分配的不灵活性在某些工作负载下会导致严重的性能瓶颈。
2006年,AMD(当时的ATI)推出了Radeon X1800 GPU,这是首款采用统一渲染架构(Unified Shader Architecture)的消费级图形处理器。在统一架构中,所有的着色器单元都是相同的,它们可以根据工作负载动态地在顶点处理、几何处理和片段处理之间切换。不再存在专门的顶点着色器硬件或片段着色器硬件,只有一组可编程的流处理器(Stream Processor),它们在任何时刻都在执行最需要执行的任务。
统一渲染架构的另一个重要优势是它为通用计算提供了天然的编程模型。当所有处理单元都是同构的时候,为图形渲染编写的并行代码原则上也可以用于执行其他类型的并行计算。这一洞察最终导向了GPGPU(General Purpose GPU,通用GPU计算)革命的到来。
2007年,NVIDIA推出了采用统一架构的GeForce 8系列GPU,正式将这种架构命名为CUDA(Compute Unified Device Architecture)架构。GeForce 8将128个流处理器组织成16组,每组8个单元,每组共享一个指令控制单元但拥有独立的寄存器文件。这种架构在保持灵活性的同时,也实现了显著的性能提升。更为重要的是,NVIDIA为CUDA架构提供了完整的软件开发工具包,使得开发者可以使用C语言为GPU编写程序,而无需了解底层的图形API。
GeForce 256:GPU概念的正式确立
在GPU发展史上,1999年是一个具有里程碑意义的年份。这一年,NVIDIA推出了GeForce 256