第一章:GPU架构演进史——从固定功能管线到统一着色器架构

大家好,我是你们的老朋友。今天咱们聊聊GPU的进化史。

说实话,我入行那会儿,GPU还是个“傻大个”。它只会干一件事——画图。你给它一堆三角形,它老老实实给你渲染出来。别的?别指望了。

但你看现在,GPU成了并行计算的巨兽。训练大模型、跑科学计算、挖矿……什么都能干。这中间到底发生了什么?

嗯,咱们从头捋一捋。

1.1 固定功能管线时代:GPU的“石器时代”

90年代末,GPU还是个纯粹的图形加速器。它的工作流程是固定的,就像一条流水线,每个环节干固定的活。

这条流水线长这样:

顶点输入 → 顶点变换 → 图元装配 → 光栅化 → 片段着色 → 输出合并

每个环节都是硬件写死的。你没法改,也没法跳过去。

我印象最深的是,那时候做游戏特效,想实现一个“水面波纹”的效果。程序员只能在CPU端算好顶点位置,再传给GPU。每帧都要算,CPU累得半死,GPU却闲得发慌。

为什么会这样?因为GPU太“死板”了。它只认固定的指令集,你没法让它干点“出格”的事。

固定功能管线的核心特点:

  • 每个阶段功能固定,不可编程
  • 数据流单向,不可回读
  • 开发者只能通过参数调节,无法自定义算法

说白了,那时候的GPU就是个“高级画图卡”。你给它什么,它画什么。你想让它算点别的?门儿都没有。

1.2 可编程管线的萌芽:GPU开始“开窍”了

2001年左右,NVIDIA和ATI(后来被AMD收购)开始琢磨:能不能让GPU干点更灵活的事?

于是,顶点着色器片段着色器诞生了。

这两个东西,说白了就是给GPU装上了“小脑袋”。开发者可以写一小段程序,告诉GPU怎么处理顶点、怎么计算颜色。

我记得当时NVIDIA的GeForce 3是第一块支持可编程着色器的消费级GPU。我拿到开发板那天,兴奋得一夜没睡。终于可以自己定义光照算法了!

但问题也来了:

  • 顶点着色器和片段着色器是分开的硬件单元
  • 它们的指令集不通用
  • 资源分配不灵活——顶点多的场景,顶点着色器忙死,片段着色器闲死;反之亦然

你想想看,一个游戏场景里,如果模型很复杂(顶点多),但特效简单(片段少),那顶点着色器就累趴了,片段着色器却在旁边看戏。反过来也一样。

这种“旱的旱死,涝的涝死”的局面,让硬件利用率大打折扣。

避坑指南:我曾经在一个项目中,为了平衡顶点和片段的负载,不得不把一些计算从顶点着色器挪到片段着色器。结果发现,不同GPU的负载特性完全不一样。有的GPU顶点单元强,有的片段单元强。没有万能的优化方案,必须针对具体硬件调优。

1.3 统一着色器架构:GPU的“觉醒时刻”

2006年,NVIDIA发布了GeForce 8800 GTX。这块卡,改变了游戏规则。

它采用了统一着色器架构(Unified Shader Architecture)。

什么意思呢?就是把顶点着色器和片段着色器合并成一种通用的计算单元——流处理器(Stream Processor)。

这些流处理器长得一模一样,能干所有活。顶点计算、片段计算、几何计算……全都能干。

这样一来,负载均衡的问题就解决了。顶点多的时候,所有流处理器都去算顶点;片段多的时候,所有流处理器都去算片段。再也没有“闲人”了。

特性 固定功能管线 分离式可编程管线 统一着色器架构
计算单元 专用硬件 顶点/片段分离 通用流处理器
编程灵活性 几乎为零 有限
负载均衡 固定
代表产品 GeForce 2 GeForce 3/4/5/6/7 GeForce 8800 GTX

我个人习惯把统一着色器架构比作“瑞士军刀”。以前你需要带三把刀——切水果的、削木头的、开瓶盖的。现在一把刀全搞定,而且随时可以切换功能。

1.4 从图形到通用计算:GPU的“跨界之旅”

统一着色器架构带来的另一个革命性变化是:GPU终于可以用来做通用计算了

因为流处理器是通用的,你完全可以写一段程序,让它去算矩阵乘法、做物理模拟、甚至破解密码。

2007年,NVIDIA推出了CUDA(Compute Unified Device Architecture)。这玩意儿,说白了就是给GPU装上了“编程语言”。开发者可以用C语言直接写GPU程序,不用再伪装成图形渲染了。

我记得第一次用CUDA做并行归约(Parallel Reduction)的时候,看到GPU把CPU甩开几十倍的速度,整个人都傻了。原来计算可以这么快!

但这里有个坑:

注意:GPU不是万能的。它擅长的是“数据并行”——同样的操作,对大量数据同时执行。如果你要处理的是“任务并行”——不同的操作,对少量数据执行——那GPU反而可能比CPU慢。因为GPU的单个线程很弱,它靠的是“人多力量大”。

1.5 架构演进的关键里程碑

咱们用时间线捋一下关键节点:

  1. 1999年:GeForce 256,首款“GPU”命名,固定功能管线
  2. 2001年:GeForce 3,引入可编程顶点/片段着色器
  3. 2006年:GeForce 8800 GTX,统一着色器架构,流处理器诞生
  4. 2007年:CUDA发布,GPU通用计算时代开启
  5. 2010年:Fermi架构,引入L1/L2缓存,更适合计算
  6. 2017年:Volta架构,引入Tensor Core,专为AI计算优化

你看,从固定功能到统一着色器,GPU走了将近10年。但这10年的积累,让GPU从一个“画图卡”变成了“计算巨兽”。

1.6 对开发者的启示

说了这么多历史,对我们写代码有什么启发?

我觉得有三点:

  • 理解硬件才能写出好代码:你知道GPU是统一着色器架构,就知道为什么“分支”是性能杀手——因为所有流处理器执行同样的指令,遇到分支就得串行化。
  • 负载均衡是永恒的主题:不管是图形渲染还是通用计算,让所有计算单元都忙起来,才是性能最大化的关键。
  • 架构决定上限:你代码写得再漂亮,如果硬件架构不支持,那也是白搭。所以,了解GPU的演进史,就是了解性能优化的“天花板”在哪里。

嗯,第一章就聊到这儿。下一章咱们深入GPU的指令流水线,看看一条指令从发射到完成,到底经历了什么。

到时候见。