WinQuake 存在的原因及其工作原理
摘要
深入探讨创建 WinQuake(Quake 的 Windows 原生版本)的历史原因,以及它如何在 Windows 95 和 NT 上实现接近 DOS 版本的性能。
暂无内容
查看缓存全文
缓存时间: 2026/05/16 03:34
# WinQuake 存在的原因及其工作原理
来源:https://fabiensanglard.net/winquake/index.html
2025 年 12 月 3 日
WinQuake 存在的原因及其工作原理
---
当我回顾 Quake 二进制文件的历史时,它们对我来说都合情合理。`quake.exe` 是原始版本,能够在 DOS 和 Windows 95 上运行。接着出现了 `vquake.exe`,用于支持硬件加速芯片 Vérité 1000。后来,`glquake.exe` 将硬件加速推广到任何提供 OpenGL 驱动程序的厂商。为了革新互联网死亡竞赛,id Software 发布了 QuakeWorld 服务器和客户端(`qwsv.exe` 和 `qwcl.exe`)。
然而,我一直想不通 `winquake.exe` 存在的意义。直到现在。以下是我理解的内容,并稍微深入探讨了它的工作原理。
## Quake.exe 的性能
---
`quake.exe` 可以在 DOS 和 Windows 95 上运行,但性能表现如何呢?在我的 Pentium MMX 233MHz、Matrox Mystique 电脑(320x200,屏幕尺寸 101,开启音效)上快速基准测试显示如下数据:
| 配置 | 帧率 |
|------|------|
| 从 DOS 启动 `quake.exe` | **48 fps** |
| 从 Windows 95 启动 `quake.exe` | **38 fps** |
所以“帧率”是证明 WinQuake 存在理由的开端。从 *Windows 95* 运行的 `quake.exe` 大约比从 DOS 启动的同一二进制文件慢 25%。这也是意料之中的。*Windows 95* 在虚拟机(“DOS BOX”)中运行 DOS 应用程序,其中内存访问、中断和信号都被虚拟化,这会产生开销。
另一个原因来自于 [Quake 通道](https://fabiensanglard.net/quake_chunnel)。`quake.exe` 可以访问 Windows 95 的 TCP/IP 栈,但只能通过 Mpath 的一种复杂技术来桥接“DOS BOX”与 Win32 DLL。通过创建一个纯 Win32 应用程序,id Software 保证了对 `winsock.dll` 的直接访问。
最后但同样重要的是,id Software 非常希望 Quake 能在 Windows NT 上运行。尽管付出了最大努力,DJGPP 的人依然无法让 `quake.exe` 中的 DPMI 客户端与 NT 虚拟 DOS 机器(NTVDM)兼容。
> 近指针在 NT 下无法工作——这令 id 非常失望,并引发了几次与微软的电话会议。
> — Charles Sandmann[\[1\]](https://fabiensanglard.net/winquake/index.html#footnote_1)
## winquake.exe 的工作原理
---
一个有趣的探索起点是首先阅读 [WQREADME.TXT](https://fabiensanglard.net/winquake/WQREADME.TXT),然后查看 `winquake.exe` 中可用的所有模式。它们通过脚本 [wq.bat](https://fabiensanglard.net/winquake/WQ.BAT) 进行配置。
```
Options for running WinQuake:
wq max: all features on, but doesn't work on all systems
wq fast: maximum speed, but doesn't work on all systems
wq fastvid: maximum video speed, but safer, probably slower sound
wq fastsnd: maximum sound speed, but safer, probably slower video
wq safe: very likely to run, but may be slower
wq verysafe: almost sure to run, but probably slower, and no sound
```
以下是我在同一台 Pentium MMX 233MHz 机器和相同配置下测试每种模式得到的数据:
| 配置 | 帧率 |
|------|------|
| `wq max` | 42.4 fps |
| `wq fast` | 41.8 fps |
| `wq fastvid` | **45.0 fps** |
| `wq fastsnd` | 41.8 fps |
| `wq safe` | **45.0 fps** |
| `wq verysafe` | **40.0 fps\*** |
令人印象深刻。`winquake.exe` 成功将帧率提升至与 DOS 下运行的 `quake.exe` 相差 6% 以内。任务完成。但它是如何做到的呢?
## winQuake.exe 后端
---
每种“模式”通过命令行参数配置。这部分揭示了输入控制、音频和视频有三种后端类型。
```
max winquake -dinput
fast winquake
fastvid winquake -wavonly
fastsnd winquake -nodirectdraw -nowindirect
safe winquake -wavonly -nodirectdraw -nowindirect
verysafe winquake -dibonly -nosound -nojoy
```
有趣的是,提供最高帧率的模式 `fastvid` 保留了所有默认设置,但禁用了音频后端!
“fastvid” 也是一个用于修复 Pentium Pro 在芯片组上极其糟糕的视频写入速度的 [工具](https://fabiensanglard.net/winquake/fastvid.txt) 的名称,该芯片组带有有缺陷的“Write Posting”。`qw.bat` 中的选项与此无关。
## 音频后端
---
WinQuake 可以使用两个音频后端发送音效(音乐来自 CD 音轨)(使用 `-nosound` 可完全禁用音效)。
这两个后端是 *DirectSound*(来自 DirectX 的 `dsound.h`)和 id 所谓的 *wave sound*,实际上是 `winmm.h`,即 Windows 多媒体音频 API,可追溯到 Windows 3.1。
如果 DirectSound 可用,WinQuake 会使用它以提供最低延迟。然而,此后端对 CPU 的影响较大,导致帧率降低 10%。使用 `-wavonly`,用户可以强制使用 `WinMM`,这会导致更高的延迟但更高的帧率。
## 输入控制后端
---
为了读取用户输入,WinQuake 使用 *DirectInput*(来自 DirectX 的 `dinput.h`)或传统的 Windows API `winuser.h`。默认情况下,WinQuake 使用 `winuser.h`,但可以通过 `-dinput` 请求使用 DirectInput,以获得更平滑的运动和对快速旋转动作的响应。我怀疑默认未启用是因为有些系统未安装 DirectX,或者担心驱动程序问题。
摇杆输入通过 `joystickapi.h` 处理。同样,驱动程序可能不稳定,因此 id 提供了 `-nojoy` 选项来禁用它。
## 视频后端
---
最令我感兴趣的部分是视频后端。WinQuake 可以使用五种模式运行:GDI、VGA、VESA、加速 VESA 或 DirectDraw。
### DIB 视频后端
---
图形设备接口(GDI)(`wingdi.h`)是在 Windows 95 桌面上渲染任何内容的基础。应用程序通常不直接使用它,而是调用 `winuser.h`(后者又使用底层的 `wingdi.h`)。
WinQuake 可以渲染到设备无关位图(DIB),这是一种表面,通过 GDI 向窗口进行位块传输。表面可以是任意尺寸,因此这里不需要检测“显示模式”,WinQuake 将其 DIB 模式硬编码为方形像素分辨率:320x240、640x480 和 800x600。
由于它按照 Windows 的“标准方式”运行,DIB 模式是最安全且应该始终有效的模式。它也是渲染到屏幕最慢的方式,因为 WinQuake 首先渲染到 DIB,然后发送给 GDI,再发送到显卡。
虽然较慢,但它并非完全缺乏硬件加速。许多希望在 Windows 95 上表现良好的显卡都实现了关键功能的硬件加速,例如 `bitBlt`。
最后,DIB 模式是唯一能够以“窗口模式”渲染的模式。其他所有模式都以“全屏模式”渲染。请注意,如果使用 `dibonly` 启动 WinQuake,DIB 也可以渲染为伪全屏,但这实际上是通过覆盖整个屏幕的无边框窗口“伪造”的。
### SciTech 的多平台图形库(MGL)
---
对于所有非 DIB 的情况,WinQuake 使用 SciTech 的 *MegaGraph Graphics Library*。这是一个相当昂贵的库(1997 年售价 499 美元,2025 年约为 1000 美元)[\[2\]](https://fabiensanglard.net/winquake/index.html#footnote_2),但物有所值,因为它为 1997 年视频系统世界的混乱局面带来了秩序,尤其是当游戏在 GDI 之外运行时。
WinQuake 可能需要处理以下类型的视频系统:
```
1. VBEAF : VESA Accelerator Function
2. VBE2 : VESA Linear Frame Buffer for direct to VRAM write/read.
3. DirectDraw : Only available if DirectX is installed.
4. StandardVGA : That good ol' VGA video mode.
```
启动时,WinQuake 注册希望 MGL 加载的驱动程序(参见 `registerAllDispDrivers`)。然后 MGL 列出所有支持的分辨率,并选择性能最高的驱动程序来访问每个分辨率(按以上列表顺序)。
```
void registerAllDispDrivers(void) {
/* Even though these driver require WinDirect, we register
* them so that they will still be available even if DirectDraw
* is present and the user has disabled the high performance
* WinDirect modes.
*/
MGL_registerDriver(MGL_VGA8NAME,VGA8_driver);
if (useWinDirect){
MGL_registerDriver(MGL_LINEAR8NAME,LINEAR8_driver);
if (!COM_CheckParm ("-novbeaf"))
MGL_registerDriver(MGL_ACCEL8NAME,ACCEL8_driver);
}
if (useDirectDraw) {
MGL_registerDriver(MGL_DDRAW8NAME,DDRAW8_driver);
}
}
```
模式列表以及 MGL 选择的驱动程序可通过 Quake 控制台中的命令 `vid_describemodes` 查看。下面的屏幕截图中,我们几乎可以看到全部驱动程序:`VGA8.DRV`、`DDRAW.DRV`、`LINEAR8.DRV` 以及窗口 DIB 模式。
*Quake fast mode.* | *Quake dibonly mode.* | *Quake nowindirect mode.* | *Quake nodirectdraw mode.*
--- | --- | --- | ---
[](https://fabiensanglard.net/winquake/quake_fast.png) | [](https://fabiensanglard.net/winquake/quake_verysafe.png) | [](https://fabiensanglard.net/winquake/quake_nodwindirect.png) | [](https://fabiensanglard.net/winquake/quake_nodirectdraw.png)
在阅读 MGL 源代码之前,我从未听说过 VBE/AF。据我所知,它从未获得广泛应用,很少有厂商编写驱动程序支持它。
许多游戏使用了 MGL:WinQuake、Hexen II、Grand Theft Auto、Maui Mallard in Cold Shadow、Total Mayhem、Balls of Steel。
### DirectDraw 视频系统
---
微软非常清楚 GDI 适用于应用程序,但对于视频游戏来说不够。早在 Windows 3.1 中,他们就发布了一个名为 WinG 的游戏开发者 SDK,以提供更直接的全屏屏幕访问。第二个版本的 WinG 被重命名为 DirectX,并包含了他们称之为 DirectDraw 的 2D 全屏 API。
> 尽管更安全、更可靠,但 Microsoft Windows 对应用程序施加了许多限制。这种情况的一个结果是,游戏和其他高性能图形应用程序无法再直接访问硬件资源以最大化性能和扩展功能。多年来,游戏程序员继续在 DOS 中磨练技艺,Windows 用户必须切换到 DOS 模式才能运行游戏、模拟和其他图形程序。这种情况带来了一个重大矛盾:一个图形操作系统,其中图形应用程序却以边缘性能执行。
> 第一个努力的方向是一个名为 WinG 的产品,即 Windows for Games 的缩写。WinG 最初于 1994 年提供,需要 Windows 3.1 中的 Win32。其主要特点是 WinG 使得游戏程序员能够快速将位图从系统内存传输到视频内存。这使得创建以更好性能运行的 Windows 游戏成为可能。微软将新版本的 Game SDK 重命名为 DirectX 2。之后发布的版本有 DirectX 3、DirectX 5、DirectX 6 以及目前的 DirectX 7。
> — Feng Yuan, "Windows Graphics Programming Win32 GDI and DirectDraw"
在性能方面,DirectDraw 比 GDI 有所提升,但由于驱动程序错误或用户未安装 DirectX,它并不能保证一定有效。可以使用 `nodirectdraw` 禁用它。
### WinDirect 视频系统
---
读者可能注意到前面有些说法明显错误:Win32 应用程序被禁止直接访问硬件。那么 MGL 如何能够绕过 GDI/DirectDraw 直接使用 VBEAF、VBE 和 VGA 呢?
这要归功于 *SciTech* 的秘密技术,称为 WinDirect。其工作原理在 [SciTech MGL Reference Guide v4.pdf](https://fabiensanglard.net/winquake/SciTech%20MGL%20Reference%20Guide%20v4.pdf) 中有解释。
> **什么是 WinDirect?**
> WinDirect 是 SciTech MGL 的一个关键组件,是一个运行时包,适用于 DOS 和 Windows 95,为 16 位和 32 位应用程序提供对显示硬件的直接访问。传统上,Windows 应用程序必须使用标准图形设备接口(GDI)执行所有图形输出。虽然 GDI 非常广泛且强大,但对于交互式视频游戏等实时应用程序所需的图形类型来说,它并不特别快。WinDirect 打破了这一障碍,它允许高性能应用程序关闭正常的 GDI 接口,并完全接管整个图形显示硬件,就像通常在 DOS 下所做的那样。一旦 GDI 关闭,交互式图形应用程序可以重新编程显示控制器并直接写入视频内存。WinDirect 应用程序可以编程任何标准 VGA 图形模式,如 320x200x256,可以重新编程控制器并运行标准 VGA ModeX 风格图形,或者可以调用标准 VESA BIOS 服务来运行高分辨率 SuperVGA 图形。
> — MGL v4 程序员指南[\[3\]](https://fabiensanglard.net/winquake/index.html#footnote_3)
MGL v4 [程序员指南](https://fabiensanglard.net/winquake/mgl_v4_programmer_guide.pdf) 是一个信息宝库。如果你像我一样好奇 WinQuake 附带的 `WDIR32.DLL` 和 `WDIR16.DLL` 库是什么,文档中提到了它们(**W**in**DIR**ect)。同样,文档将 `PMPRO16.DLL` 和 `PMPRO32.DLL` 描述为“用于保护模式服务的独立于 DOS 扩展器的 API”。里面还提到了 Michael Abrash 的 Zen Timer :)
WinQuake 源代码不包含 MGL。只提供了头文件和预编译的 32 位 `MGLLT.LIB`(MGL Lite)以允许编译。SciTech 最终在 2000 年发布了源代码[\[4\]](https://fabiensanglard.net/winquake/index.html#footnote_4),但现在已经 [不再可用](http://www.scitechsoft.com/dp_mgl.html)。上传到 GitHub[\[5\]](https://fabiensanglard.net/winquake/index.html#footnote_5) 的是 v5 版本,那时已经发生了巨大变化(例如,WinDirect 已被移除)。
幸运的是,有好心人镜像了 [MGL v4](http://ftp.lanet.lv/ftp/mirror/x2ftp/msdos/programming/scitech/00index.html)。如果你想自己研究,请安装 mglb405.exe 和 mgls405.exe。或者直接下载我的安装文件 [src.rar](https://fabiensanglard.net/winquake/src.rar)。
## 总结
---
总的来说,`winquake.exe` 通常能够找到快速的渲染路径,要么通过 DirectDraw,要么通过 WinDirect。回退到 DIB 模式虽然不理想,但与 `quake.exe` 相比仍然是一个胜利。再加上可以选择音频后端来优化帧率或音频延迟,结果是一种非常好的体验,完全证明了这一努力的价值。
30 多年后的今天,你仍然可以在 Windows 11 上运行 `winquake.exe`。全屏模式不支持宽屏,但窗口模式仍然完美运行。尽管微软最近的行为令人质疑,但他们对向后兼容性的承诺令人印象深刻。
## 参考文献
---
[\[1\]](https://fabiensanglard.net/winquake/index.html#back_1) 为什么 id 为 Quake 选择 DJGPP? (https://groups.google.com/g/comp.os.msdos.djgpp/c/VD-mIK56h74/m/P5zE_uabjnEJ)
[\[2\]](https://fabiensanglard.net/winquake/index.html#back_2) SciTech 的 MGL 价格 (https://www.gamespot.com/articles/scitech-releases-mgl-40-opengl-source-code/1100-2467345/)
[\[3\]](https://fabiensanglard.net/winquake/index.html#back_3) MGL v4 程序员指南 (https://fabiensanglard.net/winquake/mgl_v4_programmer_guide.pdf)
[\[4\]](https://fabiensanglard.net/winquake/index.html#back_4) SciTech 发布 MGL 4.0 OpenGL 源代码 (https://www.gamespot.com/articles/scitech-releases-mgl-40-opengl-source-code/1100-2467345/)
[\[5\]](https://fabiensanglard.net/winquake/index.html#back_5) SciTech 多平台图形库 (https://github.com/kendallb/scitech-mgl/)
---
相似文章
像1997年那样编译Quake!
一份详细的指南,介绍如何重现使用Windows NT 4和Visual C++ 6等老式工具编译Quake的win32二进制文件的过程(就像1997年所做的那样)。
打造一台1997年雷神之锤PC:雷神之锤基准测试
针对各种1990年代CPU和配置下雷神之锤性能的详细技术分析,比较英特尔、Cyrix、AMD芯片以及DOS和Windows 95下的内存类型。
quake.exe 如何获得其 TCP/IP 协议栈
本文详细介绍了 id Software 如何利用 Windows 95 DPMI 服务器和 TCP/IP 协议栈,使 Quake 的可执行文件能够在 DOS 和 Windows 95 上运行,从而实现更好的多人联网游戏体验。
打造一台1997年玩《雷神之锤》的PC:VQuake性能基准测试
一篇详细的回顾文章,讲述如何组装一台1997年时代的《雷神之锤》PC,并对硬件加速版VQuake进行基准测试,重点介绍Rendition Verite 1000显卡及其独特功能,包括双线性过滤和全亮度支持。
打造一台1997年的Quake PC:对GLquake进行基准测试
一位开发者讲述了他组装一台配备3dfx Voodoo显卡的复古PC,并对GLQuake进行基准测试的过程,同时讨论了硬件的小问题和性能印象。