type
Post
status
Published
date
Jan 8, 2025
slug
图形api与着色器
summary
玩游戏时看到「正在编译着色器」那个进度条,里面到底在干什么?这篇用人话讲讲着色器是什么、为什么要编译、为什么这么慢。
tags
开发
工具
游戏
category
技术分享
icon
password
synced
paired_with
3551d487-a2a1-81fc-ad17-d951139050a0
source_hash
ab3b53509a53d3d386878ad08a54a29f57e4385c86f4216931d241f548ac7ef7
translation_locked
translation_locked
玩游戏时是不是经常看到"正在编译着色器"的进度条?尤其是 Steam 上下完一个新游戏第一次启动,那个进度条能转好几分钟。这玩意儿到底在编译什么、为什么要编译、为什么不能"早就编好"?这篇尝试用人话讲清楚。
着色器是什么
游戏画面里你看到的每一个像素,都是显卡跑了一段叫"着色器" (shader) 的小程序算出来的。光照、阴影、水面反射、皮肤质感、粒子效果,全是着色器干的活。
着色器是写给显卡跑的程序。和给 CPU 写的 C 不一样,它是给 GPU 写的。最常见的两种是顶点着色器(决定每个顶点画在屏幕的哪里)和片段着色器(决定每个像素是什么颜色)。
为什么要"编译"
游戏开发者写的着色器是高级语言(HLSL、GLSL 这种),显卡看不懂。要让显卡执行,需要把它翻译成显卡能直接跑的"机器码"。这一步就是着色器编译。
但显卡的机器码不像 CPU 的 x86 是一个标准。NVIDIA 的卡、AMD 的卡、Intel 集显,每家的指令集都不一样。同一段着色器代码,在不同的卡上要编译成不同的机器码。
这就是为什么不能在游戏发布前就编好。开发者不知道你用的是哪张卡、哪个驱动版本。所以游戏只能带着源码(或者一种中间格式)发给你,第一次启动时让你的驱动现场翻译给你的显卡。
图形 API 简史
着色器编译这件事,背后是图形 API 的演化。简单梳理一下。
OpenGL (1992) 由 Silicon Graphics 开源,跨平台。曾经是 PC 游戏的事实标准,后来逐渐被替代。它的版本历程大致是
- 1992 年 OpenGL 1.0
- 2004 年 OpenGL 2.0,引入了着色器语言 GLSL
- 2010 年 OpenGL 4.0
- 2017 年 OpenGL 4.6,至今没大版本更新
DirectX 是微软的,绑定 Windows。Direct3D 12 把控制权下放到开发者手里,让你直接管 GPU 内存、自己排队渲染命令,性能上限更高(也更难写)。今天 PC 上 3A 游戏几乎都跑在 DX12 上。
Vulkan 算是 OpenGL 的接班人,由 Khronos 在 2016 年推出。设计思路和 DX12 类似,"显式控制、低开销"。跨平台、开源,《毁灭战士 永恒》《无人深空》这种重度游戏都用它。
Metal 是苹果家的,2014 年推出,Mac 和 iPhone 上唯一的图形 API。针对苹果自己的 GPU 做了优化,特别是 M 系列芯片上效率非常高。
为什么编译要那么久
顺着上面的思路就能理解。一个现代 3A 游戏可能有上千个不同的着色器组合(不同光源数量、不同材质、不同特效叠加),每一个组合都要在你的卡上编译一次。再叠上 DX12、Vulkan 这些"显式 API"对编译时机更严格的要求,第一次启动时就需要把以后会用到的着色器都先编一遍,免得游戏中途卡顿。
这就是你看到那个进度条的全部原因。它在一次性把后面会用到的所有着色器都翻译成你显卡的机器码,再缓存到本地。下次启动直接读缓存,就不用再编译了。
但缓存会失效。换显卡、升级驱动、游戏打补丁,缓存就作废,得重新编一遍。这就是为什么有时候你只是更新了一下显卡驱动,进游戏又看到那个进度条。
写在最后
下次你看到"正在编译着色器",别再以为游戏是在装 bug 卡你。它其实是在给你的显卡量身定做一份运行说明,编完一次以后玩起来就顺了。这反而是游戏在尽力照顾你的体验。
📎 参考文章
- 作者:LeoQin
- 链接:https://leoqin.com/article/%E5%9B%BE%E5%BD%A2api%E4%B8%8E%E7%9D%80%E8%89%B2%E5%99%A8
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。