← 所有文章

工程哲学:John Carmack,把性能当作一种道德手艺

John Carmack,程序员、id Software 联合创始人

核心要点

  • Carmack 把性能当作一个道德问题,而不是一道优化工序。代码与硬件物理极限之间的差距就是浪费,而浪费是你的一个选择。
  • 他的方法是做减法:把问题理解到根基,剥离到那个快速而简单的内核,并拒绝任何会拖慢这个内核的功能。
  • 当底层问题本身改变时,他会推倒重来。Quake 抛弃了让 id 成名的那套引擎,因为真正的 3D 是一个与“伪造 3D”截然不同的问题。
  • 他始终公开地工作——先是每天的 .plan 日志,后来是开源引擎——只因为一个信念:你打算公开的代码,是你会写得更诚实的代码。

核心理念

“光速糟透了。”——John Carmack1

这是一句玩笑,也是他的全部哲学。Carmack 是针对网络延迟说的这句话——一个数据包横跨整片大陆所需时间的硬性物理下限——但这种情绪贯穿了他写下的每一行代码。机器受物理规律支配,工程师的职责就是在问题允许的范围内,尽可能逼近物理极限。不是“足够接近”,而是物理所允许的极限。用户与光速之间的一切都是浪费,而浪费是你亲手做出的选择。

Carmack 把性能当作一个道德问题,而不是一道优化工序。大多数软件积攒迟缓的方式,就像房子积攒杂物一样——每次一个看似合理的决定,单看都站得住脚,加起来却无可辩护。Carmack 的纪律就是拒绝这种积攒:把问题理解到根基,剥离到那个快速而简单的内核,然后发布它。同样的信念也支撑着另一个论点——性能不是你添加的功能,而是一种你没能守住的属性:你无法把一个慢系统优化成快系统;你只能造出一个快的,然后守住它。

而且他公开了自己的全部过程。十多年来,Carmack 把他每天的工程日志——也就是 .plan 文件——发布到开放的互联网上,任何人只要有一个 finger 客户端就能读到。2 上世纪 90 年代最棘手的 3D 渲染难题,几乎是在近乎实时的状态下、当众被攻克的。公开工作不是为了营销。它与代码本身出自同一种本能:没有隐藏状态,没有任何你无法检视的东西。

背景

John D. Carmack 于 1970 年 8 月 21 日出生在堪萨斯州的肖尼米申(Shawnee Mission)。3 他在密苏里大学堪萨斯城分校读了两个学期,随后退学,靠写软件谋生。没有正规的学徒训练,也没有学位。他学图形编程的方式和 demoscene 那群人一样——啃硬件手册,测量芯片实际做了什么,写汇编,直到数字算对为止。

他落脚在 Softdisk,一家位于路易斯安那州什里夫波特(Shreveport)的软件兼磁盘杂志公司,参与一个名为 Gamer’s Edge 的游戏订阅项目。在那里,他结识了 John Romero、Tom Hall 和 Adrian Carmack(与他没有亲缘关系)。1990 年 9 月,Carmack 做出了一个本不该在 PC 上实现的演示:在 EGA 硬件上呈现出流畅的、主机级画质的横向卷轴。1990 年的 IBM PC 每一帧都要重绘整个屏幕——对卷轴游戏来说太慢了。Carmack 的技术,自适应图块刷新(adaptive tile refresh),利用了 EGA 硬件中一些冷僻的特性,把已经画好的画面整体平移,只重绘新露出来的边缘。4 团队把任天堂《超级马里奥兄弟 3》(Super Mario Bros. 3)的第一关重制成 PC 演示来证明这一点。任天堂拒绝了合作。团队留下了这套引擎。

1991 年 2 月,他们离开 Softdisk,创立了 id Software。模式已经定型:找到没人解决的问题,在硬件层面解决它,再在解决方案之上构建产品。Carmack 后来又用纹理映射的 3D 重演了一遍,再用真正的多边形 3D 重演一遍,又用虚拟现实重演一遍。围绕他的那种氛围——Michael Abrash 的《图形编程黑皮书》(Graphics Programming Black Book)、demoscene 那种计算时钟周期的文化——把处理器当作一个需要被精确理解、而非粗略估算的对象。是 Carmack 让这种文化广为人知。

John Romero(左)和 John Carmack 在 1990 年代初 id Software 办公室外与他们的法拉利合影,其中包括一辆 DOOM 涂装的赛车

作品

Commander Keen 与 Doom:快速内核(1990—1993)

DOOM(1993)封面,由 Don Ivan Punchatz 绘制——海军陆战队员立于一群恶魔之上

Commander Keen in Invasion of the Vorticons(1990 年 12 月)是第一款基于自适应图块刷新构建的商业游戏。它作为游戏的意义,远不如它作为一个证明的意义:对硬件的一次细致解读,能够弥合通用 PC 与专用主机之间的差距。那份流畅的卷轴并不是叠加在表层的图形小把戏。它本身就是引擎。

Doom(1993)是 Carmack 方法的经典范例。为了在 1993 年的 PC 上足够快地渲染场景,他采用了二叉空间分割(binary space partitioning)——也就是 BSP 树,源自一篇 1980 年的学术论文,由 Carmack 找到并加以改造——来预先计算墙面必须被绘制的顺序,使引擎绝不会去画一个稍后会被覆盖掉的像素。5 Doom 并非真正的 3D;它是一张 2D 地图,借助足够巧妙的手法渲染出有体积感的效果。这个区别正是关键所在。Carmack 没有去做那个最通用的系统。他做的是在当时已有的硬件上跑得快的系统,并拒绝任何会拖慢核心循环的功能。那个快速而简单的内核,被发布了出去。

Quake:软件实现的真正 3D(1996)

Quake(1996)的封面美术——深色石面上那枚锈迹斑斑、由钉子构成的 Q,宣告了 id 向真正 3D 的飞跃

Quake(1996)是那次推倒重来。Doom 是在伪造深度,而 Quake 则用软件渲染出真正的三维多边形世界——倾斜的表面、抬头与低头、真实的几何结构——而这一切发生在消费级 3D 加速卡尚未普及之前。6 这套引擎把预计算的 BSP 可见性、离线光照贴图(lightmaps)与手工调校的汇编结合在一起,做到了当时主流认知认为那个年代的 CPU 不可能做到的事。id 后来发布了 GLQuake,一个 OpenGL 渲染器,帮助消费级 3D 显卡确立了正当地位。

Quake 是那件能让人一眼看尽 Carmack 全部立场的作品:他抛弃了让公司成名的引擎,把新问题(真正的 3D)理解到根基,然后重建。不为复用而复用。先前的解决方案并不神圣;神圣的是问题本身。

开源的 id 引擎与 .plan 文件(1997—2011)

对于让自己致富的那些代码,Carmack 做了两件不同寻常的事。他发布了自己每天的工作日志——.plan 文件——让工程过程在发生的当下就清晰可读。2 然后,他把引擎送了出去。id 在 1997 年开源了 Doom 引擎,1999 年开源了 Quake,并在每一代 id Tech 的后继者发布之时,持续放出它的源代码,一直延续到 Doom 3 乃至更后。7 他的论点很朴素:放出旧代码能让更年轻的开发者真正学到这东西当初是怎么造出来的,而且“人们珍视的自由软件,为世界增添了财富”。8

这份意愿,正是大多数痴迷性能的工程师永远没能抵达的部分。Carmack 的手艺,是把私下的纪律公之于众。这份愿意被人阅读的意愿——愿意让任何人检视每天的日志,并最终检视源代码——本身就是一桩关于质量的交易。你打算公开的代码,是你会写得更诚实的代码。

Oculus VR:延迟的下限(2013—2019)

Oculus Rift CV1 虚拟现实头显,正是 Carmack 延迟攻关所针对的那款消费级设备

在 Oculus,Carmack 毕生的宿敌——延迟——成了整个问题本身。他写道:“从用户头部发生物理移动,到头戴显示器更新后的光子抵达其眼睛,这之间的延迟,是提供高质量体验最关键的因素之一”,而可被察觉的头部追踪延迟“也是引发模拟器眩晕症的主要原因之一”。9 他定下了一个预算——目标大致在 20 毫秒的“运动到光子”(motion-to-photon)量级——并把流水线的每一个环节都当作可以夺回几微秒的地方来对待。他的 timewarp(时间扭曲)技术,在画面送显前的最后一刻,对一帧已经渲染好的图像进行重投影,以吸收渲染过程中发生的头部运动。9 这又是一次自适应图块刷新,只不过晚了二十三年:不要重绘你能复用的东西,并以物理极限来衡量结果。

方法

这套方法在三十年间、跨越四个问题领域始终如一。

把问题理解到根基。 Carmack 啃硬件手册,测量实际行为,从第一性原理出发,而不是从惯例出发。BSP 树、光照贴图、timewarp,都不在任何现成的招式手册里;它们是从问题实际所要求的东西中推导出来的。

剥离到那个快速而简单的内核。 Doom 不是 3D,是因为在 1993 年的硬件上,不需要 3D 就能让人感到 3D。这种纪律是做减法:找出那个内层循环,把它做快,并拒绝那些会拖慢它的功能。

当问题改变时,推倒重来。 Quake 并没有去扩展 Doom 引擎。一旦底层问题发生了位移,Carmack 就把一个能正常工作的系统视为可抛弃之物。沉没成本不构成理由。

深度的、不被打断的专注。 Carmack 那些马拉松式的编码长跑,从来不是为了耐力本身。把整套引擎装在工作记忆里——数据布局、内层循环、各种边缘情况同时在脑中——需要数小时来“装载”,而一旦上下文切换便瞬间崩塌。他像守护渲染循环里的时钟周期那样守护这种状态:把它当作工作真正赖以运转的那种稀缺资源。

后期:C 语言里的函数式风格。 到了 Doom 3 的年代及其之后,即便是在 C 和 C++ 里,Carmack 也开始倾向于纯函数、把可变状态降到最低——不是赶时髦,而是因为没有隐藏状态的代码,其行为是可以预测的,这意味着更少的 bug。10 这与 .plan 文件出自同一种本能:没有任何你无法检视的东西。

影响链条

谁塑造了他

Michael Abrash 是这条谱系里最接近“导师”的人。Abrash 关于 x86 图形的文字——后来汇集成《图形编程黑皮书》——把那种计算时钟周期、凡事皆测量的文化系统化了,而这正是 Carmack 一直在践行的。两人后来在 id 共事,多年以后又在 Oculus 重聚,Abrash 在那里担任首席科学家。(直接影响)

1980 年代末的 demoscene 与汇编优化文化 教会了他那个根基性的信念:处理器是可以被精确认知的,而你的代码与硬件天花板之间的差距,是你的责任。(奠基性影响)

John Romero,他在 id 的搭档,扮演的是互补者而非教师的角色。Romero 的设计与关卡工作,赋予了 Carmack 的引擎一些值得运行的东西。这段合作提醒人们:一个快速的内核是必要的,但不是充分的——引擎之所以存在,是为了被玩。

他塑造了谁

整个游戏引擎行业。 BSP 可见性、光照贴图,以及成熟引擎的开源化,都成了基准实践。一代引擎程序员,正是通过阅读 Carmack 选择放出的 id Tech 源代码,学会了 3D 渲染。

消费级 3D 图形硬件。 Quake 的 OpenGL 渲染路径,是支持 3D 加速卡的一个早期商业论据,帮助把 GPU 推入主流 PC。

现代虚拟现实。 Timewarp 与那个不留情面的延迟预算,如今已是每一条 VR 流水线中的标准词汇。Carmack 当年追逐的 20 毫秒目标,正是今天的头显不会让人眩晕的原因。

贯穿始终的那条线

Andrej Karpathy 之所以从零重建神经网络,是因为理解无法被转交——你必须自己把它推导出来。Carmack 推导他的渲染器也是同样的方式:不是从某个框架,而是从硬件与问题本身出发。而当 Linus Torvalds 推崇“好品味”——那种把特例消融进通例的本事——时,Carmack 推崇的是那个做了物理所允许的最少工作量的内层循环。两者其实是同一个信念,只是穿着不同的衣裳:正确的结构不是叠加在问题之上的装饰;它就是问题本身,被正确地看见。(系列衔接)

我从中汲取了什么

我一直记着的那一课是:性能即诚实。一个慢系统,通常出自一个从未把问题理解得足够透彻、以至于找不到它快速内核的作者之手——他们堆砌抽象层,直到它能跑起来,而“能跑”就是他们停下的地方。Carmack 则停在物理极限上。这与质量是唯一的变量是同一套标准:问题从来不是“这够快可以发布了吗?”,而是“我究竟有没有真正理解它为什么会这么慢?”

在我如今所构建的世界里——智能体、工具循环、AI 系统——那种诱惑恰恰与 Carmack 的纪律相反:堆叠框架,用更多的模型调用去掩盖延迟,从不去读系统实际在做什么。Carmack 式的做法,是给那个循环做性能剖析,找出占主导的那一部分,把它理解到根基,再把其余的剥离掉。这个信念——品味是一套你可以度量的技术系统,而不是一种你随口断言的感觉——正是那条从 1990 年的 EGA 卷轴小把戏,一直贯穿到 2026 年某个智能体框架的线。

常见问题

John Carmack 的工程哲学是什么?

Carmack 把性能当作一个道德问题,而不是一件事后才想起的事。他的纪律是:把一个问题理解到根基,剥离到那个快速而简单的内核,拒绝那些会拖慢这个内核的功能,并在底层问题改变时推倒重来。与此相配的,是他公开地工作——发布每天的工程日志,开源成熟的引擎——其信念在于:你能检视的代码,是写得更诚实的代码。28

John Carmack 都做出了什么?

Carmack 于 1991 年联合创立 id Software,并担任以下作品的首席程序员:Commander Keen(1990,自适应图块刷新)、Wolfenstein 3D(1992)、Doom(1993,基于 BSP 的渲染)以及 Quake(1996,软件实现的真正 3D 渲染)。他在二十年间陆续开源了 id Tech 系列引擎,曾任 Oculus VR 的 CTO,在那里推动了“运动到光子”延迟方面的攻关,后来又创立了 AI 公司 Keen Technologies。5679

什么是自适应图块刷新?

这是 Carmack 在 1990 年想出的技术,用来在 IBM PC 的 EGA 硬件上实现流畅的横向卷轴——那套硬件本来因为每一帧都要重绘整个屏幕而太慢。自适应图块刷新利用 EGA 硬件特性把已经画好的画面整体平移,只重绘边缘新露出来的图块,从而大幅削减每帧的工作量。它让 Commander Keen 成为可能,也确立了 Carmack 的招牌做法:在硬件层面解决瓶颈。4

Carmack 为什么要发布他的 .plan 文件并开源他的引擎?

.plan 文件是一份每天更新的工程日志,最初通过 finger 协议即可读取,它几乎是在实时地记录着 id 的开发过程。2 Carmack 后来在每一代 id Tech 的后继者发布之后,便把它开源,他的论点是:放出旧代码能帮助更年轻的开发者学到游戏究竟是怎么造出来的,而有价值的自由软件“为世界增添了财富”。8 这两种做法都体现了与他代码相同的原则:没有隐藏状态,没有任何你无法检视的东西。


来源


  1. John D. Carmack, “The speed of light sucks.” Wikiquote,关于网络延迟。广泛引用自他 QuakeWorld 时期的网络编程工作;另见 Data Center Knowledge 的相关讨论。 

  2. Robbie, “The Carmack Plan,” Garbage Collected,2017 年 10 月——关于 .plan 文件、finger 协议以及公开地工作。oliverbenns/john-carmack-plan 中归档的日志横跨 1996 年至 2000 年代,记录了这一做法长达数年的持续运行。 

  3. “John Carmack.” DoomWiki。生于 1970 年 8 月 21 日,堪萨斯州肖尼米申;密苏里大学堪萨斯城分校;Softdisk;创立 id Software。 

  4. David Kushner, Masters of Doom: How Two Guys Created an Empire and Transformed Pop Culture(Random House,2003),第 3 章——将 Carmack 的流畅卷轴突破,以及那次通宵重制的《超级马里奥兄弟 3》,定在 1990 年 9 月于 Softdisk。Romero 的合作者 John Anderson 在 “The Saga of Dangerous Dave,” 中亦有佐证,其中将 “Dangerous Dave in Copyright Infringement” 定在 1990 年 9 月。技术细节:“Adaptive tile refresh,” Wikipedia,以及 Fabien Sanglard, “Commander Keen’s Adaptive Tile Refresh.” 

  5. “Doom rendering engine,” DoomWiki——BSP 树在 1993 年 5 月的 alpha 版与 10 月的 beta 版之间被采用;通过线段裁剪消除过度绘制。关于这项技术的起源:Sinclair Target, “How Much of a Genius-Level Move Was Using Binary Space Partitioning in Doom?,” Two-Bit History(2019)——将 BSP 树追溯到 Henry Fuchs、Zvi Kedem 与 Bruce Naylor 于 1980 年发表的论文 “On Visible Surface Generation by A Priori Tree Structures”(及其 1969 年美国空军飞行模拟器的前身),并记录了 Carmack 如何将其改造用于 Doom。 

  6. “Quake engine.” Wikipedia。软件实现的真正 3D 多边形渲染(1996),预计算可见性,光照贴图,以 C 和汇编写成,后期加入 OpenGL 渲染路径。 

  7. “id Tech,” Wikipedia——记录了各次源代码发布:Doom 引擎 1997 年(1999 年改用 GPL 重新授权)、Quake 引擎 1999 年、Quake II 2001 年、Quake III 2005 年,以及 Doom 3(id Tech 4)引擎 2011 年,那是最后一次 GPL 发布。概览:“A graphical history of id Tech,” PC Gamer。 

  8. Brad Cook,对 John Carmack 的采访,Apple.com(已归档),转引自 Wikiquote。”Sharing the code just seems like The Right Thing to Do… Free software that people value adds wealth to the world.” 另见:TechRadar, “id’s John Carmack sings praises of open source.” 

  9. John Carmack, “Latency Mitigation Strategies”(已归档;最初发布于 2013 年 2 月)。原文:”The latency between the physical movement of a user’s head and updated photons from a head mounted display reaching their eyes is one of the most critical factors in providing a high quality experience,” 以及 “Perceiving latency in the response to head motion is also one of the primary causes of simulator sickness.” 文中描述了 time-warp 重投影技术。VR 延迟目标的背景:PCGamesN, “John Carmack’s battle for 20 millisecond latency.” 

  10. John Carmack, “In-Depth: Functional Programming in C++,” Gamasutra/Game Developer,2012 年 4 月 30 日:”A large fraction of the flaws in software development are due to programmers not fully understanding all the possible states their code may execute in. Programming in a functional style makes the state presented to your code explicit.” 关于倾向于纯函数、把可变状态降到最低以减少 bug。 

相关文章

工程哲学:Thompson 与 Ritchie,把一件事做好

Thompson 与 Ritchie 用通过单一通用接口——文本流与管道——组合而成的小巧锋利的工具,构建了 Unix 与 C。简洁胜于功能堆砌。

3 分钟阅读

工程哲学:Leslie Lamport,先思考再写代码

Leslie Lamport 让分布式系统成为一门科学:时间不是全局的,真正实在的是因果,先写明设计规约,再动手写代码。

1 分钟阅读

The Shader Gallery That Lied: Debugging 216 WebGL Presets

A user said the shader playground looked broken. Pixel-readback testing found 30 dead presets, 11 that never compiled, a…

11 分钟阅读