D2DX架构全景:Glide API到DirectX 11转译引擎的设计哲学与核心组件
【免费下载链接】d2dxD2DX is a complete solution to make Diablo II run well on modern PCs, with high fps and better resolutions.项目地址: https://gitcode.com/gh_mirrors/d2/d2dx
D2DX 是让《暗黑破坏神2》在 modern PC 上流畅运行的完整解决方案——它模拟 3dfxGlide 图形 API,把游戏的全部绘制调用转译成DirectX 11指令,从而带来高帧率、宽屏与抗锯齿支持。本文将从架构视角拆解这个"Glide 到 DirectX 11 转译引擎"的三层设计与核心组件,帮助你理解它如何在 20 年前的老游戏与现代显卡之间架起桥梁。
一分钟看懂 D2DX:一个"假显卡驱动" 🎮
《暗黑破坏神2》当年使用 3dfx 的 Glide API 直接驱动显卡,而今天的显卡早已不再支持这套接口。D2DX 的做法是:向游戏提供一个名为glide3x.dll的假 Glide 驱动,骗过游戏;游戏以为自己在调用真正的 Glide,实际上每个调用都被转发进 D2DX 的转译引擎,最终以 DirectX 11 的形式渲染到窗口或全屏中。
游戏内效果则如右图所示:原始 640×480 的画面被高质量放大到现代 1080p 显示器上,细节依然锐利。
三层架构:一条清晰的调用链
D2DX 的源码位于 src/d2dx/,整体分为三层,职责泾渭分明:
游戏进程 (d2game.exe) │ 调用 grDrawVertexArray / grBufferSwap ... ▼ ① Glide 层 glide3x.cpp ────── 实现全部 Glide API 入口,纯转发 │ 通过 D2DXContextFactory 单例获取上下文 ▼ ② 转译层 D2DXContext ─────── 维护 Glide 状态机,把调用组装成"批次(Batch)" │ 同时处理 Win32 拦截与游戏内存探测 ▼ ③ 渲染层 RenderContext ───── DirectX 11 设备/交换链、着色器、缩放输出这种"入口层只做转发、逻辑集中在上下文"的设计,让每一层都可以独立测试(项目自带单元测试工程 d2dxtests/),也方便第三方 MOD 接入。
第一层:glide3x.dll —— Glide API 的"假驱动"
入口实现在 glide3x.cpp,它用 C 风格导出了一整套 Glide 函数:grSstWinOpen(开窗口/全屏)、grVertexLayout(定义顶点格式)、grDrawVertexArrayContiguous(批量提交顶点)、grBufferSwap(交换帧缓冲)等。
每个函数内部都遵循同一个套路——以 grDrawVertexArrayContiguous 为例:
- 用
_ReturnAddress()取回调用方返回地址,交给上层用于判断"这帧画的是游戏还是菜单"; - 转发给 D2DXContextFactory::GetInstance() 返回的单例上下文;
- 用
try/catch包裹一切异常,保证游戏进程绝不崩溃。
还有一些"聪明"的兼容细节:例如 grLfbLock 只为游戏真正会用到的 640×480 RGBA 写锁模式分配内存,其余调用一律返回"不支持",最大限度贴近原始驱动行为。
第二层:D2DXContext —— 状态机与批次组装
核心类 D2DXContext 实现了三个接口(见 ID2DXContext.h):
| 接口 | 职责 |
|---|---|
IGlide3x | 响应全部 Glide 调用(OnDraw*、OnTexSource、OnGammaCorrectionRGB…) |
IWin32InterceptionHandler | 拦截SetCursorPos、Sleep等 Win32 调用 |
ID2InterceptionHandler | 拦截游戏内部文字/图块绘制,服务运动预测 |
它的工作方式很像一个迷你状态机:
- 纹理内存模拟:维护一块虚拟 TMU 显存(
GlideState::tmuMemory),游戏的grTexDownloadMipMap把像素"下载"到这里,grTexSource指定纹理地址; - 批次(Batch)组装:每次
grDrawVertexArray*调用都会按当前混合/颜色模式归入 Batch,相同状态的顶点被合并提交,减少状态切换开销; - 帧循环:
OnBufferSwap触发整帧绘制,此时依次执行纹理哈希、运动预测修正、批次提交; - 能力协商:通过 Feature 标志位声明当前游戏版本支持哪些增强(单位/文字/天气运动预测),实现"特性降级"而非整体失效。
第三层:RenderContext —— DirectX 11 渲染管线
RenderContext 负责所有与显卡打交道的事:创建ID3D11Device与IDXGISwapChain(成员定义),并实现了多套策略化的同步与交换方式——AllowTearing(无垂直同步、最低延迟)、Interval0/1、以及基于ID3D11DeviceContext1::SetFrameLatencyWaitableObject的帧延迟控制,这就是它"低延迟全屏"的来源。
画面输出阶段由一组 HLSL 着色器完成(src/d2dx/ 下均为独立文件):
- DisplayIntegerScalePS.hlsl:整数倍缩放,保持像素锐利;
- DisplayNonintegerScalePS.hlsl:非整数缩放,采用"抗锯齿最近邻"采样避免糊化;
- DisplayCatmullRomScalePS.hlsl 与 DisplayBilinearScalePS.hlsl:偏柔和观感的可选滤镜;
- GammaPS.hlsl:实现正确 gamma 校正,保证暗部细节。
纹理缓存:FNV 哈希 + 位图 PMRU 淘汰
Glide 把纹理下载到"显存"再采样,而 D2DX 需要把它们变成 D3D11 纹理供着色器使用。TextureCache 用**固定尺寸的四张纹理图集(atlas)**存放所有游戏纹理:
- 内容键由 TextureHasher 基于FNV1a 哈希(第三方实现见 thirdparty/fnv/)计算,避免重复纹理占用空间;
- 淘汰策略不是简单的 LRU,而是自定义的 位图 PMRU(probabilistic MRU),对"反复使用的 UI 纹理"与"一次性场景纹理"都有更优的命中率;
- 图集满时自动按策略驱逐旧纹理,整帧开始还会调用
OnNewFrame刷新访问统计。
高帧率秘密:三套运动预测器 🚀
原版游戏锁定 25 FPS,直接解锁帧率只会得到"跳帧"。D2DX 的思路是在渲染层插值位置——既然游戏逻辑每 25ms 更新一次单位坐标,那在中间帧里按速度外推即可。对应三个组件:
- UnitMotionPredictor:追踪每个单位的
lastPos → velocity → predictedPos(见 UnitMotion 结构),实现人物、怪物、投射物、阴影的平滑移动; - TextMotionPredictor:跟随滚动的伤害数字等文字;
- WeatherMotionPredictor:雨雪天气粒子。
配合 GameHelper 对游戏内存的 FPS 补丁(TryApplyInGameFpsFix、TryApplyMenuFpsFix)和睡眠修复,菜单与游戏内都可以稳定跑在 60 FPS 以上。
Win32 拦截与内存探测:Detours 的功劳
D2DX 借助微软 Detours 库(封装在 Detours.cpp)挂钩两类入口:
- Win32 API:拦截
Sleep消除卡顿微停顿、拦截SetCursorPos把鼠标约束在窗口内(OnSetCursorPos); - 游戏内部函数:通过返回地址匹配(
IdentifyGameAddress)定位文字/图块绘制函数,为运动预测提供每帧真实坐标。
此外 CompatibilityModeDisabler 会主动阻止 Windows XP 兼容模式(它会导致画面花屏),体现了"现代环境跑老游戏"的设计立场。
与第三方 MOD 协作:ID2DXConfigurator 接口
D2DX 还暴露了一个类 COM 的公开接口 ID2DXConfigurator,供高分辨率 MOD 调用:
SetCustomResolution(w, h):告知 D2DX 使用自定义游戏分辨率,内置宽屏 MOD 自动让位;GetSuggestedCustomResolution():获取与显示器比例匹配的推荐分辨率。
这是典型的开闭设计:核心行为可被外部扩展覆盖而不需修改 D2DX 本身。分辨率 MOD 的底层则内嵌了 SGD2FreeRes(以 lzma 压缩打包,运行时经 pocketlzma 解压),由 BuiltinResMod 加载。
画质开关:FXAA 与宽屏选项
抗锯齿由 FXAA 实现(基于 Timothy Lottes 的公开实现),只作用于锯齿明显的边缘,不破坏像素风。对比效果如下:
全部行为都可通过配置文件 d2dx-defaults.cfg 定制(复制到游戏目录并改名为d2dx.cfg):
- 窗口区段:
scale=1-3整数缩放、position、frameless无边框窗口; - 游戏区段:自定义
size与filtering(锐利 / 双线性 / Catmull-Rom); - 关闭项区段:
nowide、noaa、nomotionprediction等可逐项回退到原版体验。
例如设置nowide=true后,标题画面会以约 4:3 的整数缩放模式呈现:
快速上手:获取与验证 📦
仓库为只读镜像,克隆后只需把编译产物glide3x.dll拷入《暗黑破坏神2》目录:
git clone https://gitcode.com/gh_mirrors/d2/d2dx启动游戏时加参数-3dfx(Game.exe -3dfx),之后 ALT-Enter 即可在窗口与全屏间无卡顿切换。
小结:这套架构最值得学习的地方 ✨
- 边界清晰:Glide 入口层零逻辑,状态机与渲染器分层解耦,单测工程可直接验证批次、SIMD 与缓存逻辑;
- 策略化而非硬编码:缩放滤镜、同步策略、纹理淘汰均可配置/可替换;
- 渐进式增强:
Feature标志 + 多版本适配(1.09d~1.14d),新特性默认开启又随时可关; - 生态友好:
ID2DXConfigurator让 D2DX 成为可被其他 MOD 编排的"渲染平台",而不只是一个独立的 MOD。
从 Glide 到 DirectX 11,D2DX 用不到两万行 C++ 证明了:理解旧 API 的每一处怪癖,就能让 25 年前的游戏在现代显卡上跑出它从未有过的流畅。
【免费下载链接】d2dxD2DX is a complete solution to make Diablo II run well on modern PCs, with high fps and better resolutions.项目地址: https://gitcode.com/gh_mirrors/d2/d2dx
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考