项目实训记录1:项目初探
写在前面:这是一篇个人项目开发记录。团队 4 人合作完成 upscalerBridge——一个在游戏运行时实时替换超分辨率技术的中间件。我负责其中的资源管理与状态机模块。本系列博客会完整记录从技术调研到最终交付的全过程。
一、缘起
开始这个项目之前,我对实时渲染里的超分辨率技术只有一些零散的印象——知道 DLSS 能让游戏跑得更快,知道 FSR 是 AMD 的竞品方案,但对它们到底怎么运作的、差别在哪里,其实没什么概念。
真正让我坐下来系统看这块内容,是去年年底升级显卡那段时间。手头一张 A 卡一张 N 卡,跑同一款游戏,有的支持 DLSS 有的不支持,体验割裂得厉害。那时候就在想:凭啥游戏厂商选了哪家技术,玩家就得被绑在哪家的硬件上? 如果能做一层中间层,把不同厂商的方案串起来,是不是就没这事了?
这个想法搁了几个月,直到看到社区里有人做了类似的事情,才决定和同学一起动手。
二、项目目标
我们项目的目标用一句话说清楚:开发一个图形中间件,把 DLSS 和 FSR 的 API 调用拦截下来,翻译参数,然后交给用户指定的另一种后端去执行。
举个例子:一个游戏原生只调用了 DLSS 的接口,我们在这个调用到达驱动之前把它截住,提取出颜色缓冲、深度缓冲、运动矢量这些上采样需要的数据,转成 FSR 后端需要的格式,交给 FSR 处理完再返回给游戏。整个过程对游戏完全透明。
最终技术选型:经过团队讨论,我们决定基于 D3D12 + Proxy DLL + Detours Hook 的技术路线实现。为什么选 D3D12?因为 AMD FidelityFX SDK v2 对 D3D12 的支持最成熟,而我们的 FSR 后端正是基于这套 SDK 构建的。前期我在 Vulkan 方向做了一些预研,这个放到后面博客再细说。
测试目标:我们选定了 GTA 5 作为主测游戏。原因有三:一是它的渲染管线相对规范,便于定位注入点;二是社区对它的 mod 生态非常熟悉,出了问题容易对照;三是它原生支持 DLSS,可以验证"DLSS → FSR"这条替换路径是否通畅。
三、先搞清楚要操作的对象:DLSS vs FSR
在动手写代码之前,最紧迫的事是理解 DLSS 和 FSR 到底有什么区别。不搞清楚这个,后面的后端适配和参数翻译根本无从下手。
3.1 DLSS:NVIDIA 的"AI 脑补"
NVIDIA 在 RTX 20 系发布时一起推出来的技术。核心思路是把游戏画面用低分辨率渲染(比如 1080p),然后通过一个训练好的神经网络把这个低分画面"脑补"成高分画面(比如 4K)。
这事的难点在于"脑补"得准。DLSS 的训练不是凭空瞎猜的,它有一个高分辨率参考帧作为监督信号,网络学着从低分输入去逼近高分参考。再加上时间维度的信息——把前一帧的画面也喂进网络——纹理细节和边缘过渡就能处理得比较自然。
但代价也明显:必须用 NVIDIA 的 Tensor Core 做推理,只能用 RTX 卡。
3.2 FSR:AMD 的"算法流"
AMD 的方案,版本迭代很快,要分阶段看。
-
FSR 1.0 比较简单粗暴,纯空间域的放大加锐化,不依赖历史帧。运算量小,什么卡都能跑,但画质跟 DLSS 有明显差距。
-
FSR 2.0 是个转折点。引入了时间域信息——把多帧数据结合起来算,画质拉上来不少。同时它比 DLSS 的硬件门槛低很多,不要求特定的 AI 加速单元,通用计算单元就行。
-
FSR 3.0 进一步加了帧生成,在原始帧之间插帧,属于"花算力买流畅度"的思路。
我们项目实际使用的是 FSR 3.1(FidelityFX SDK v2 提供),支持超分 + 帧生成两条路径。
3.3 我们关注的核心差异
画完对比之后,我发现最有价值的不是"谁更强",而是理解它们各自的输入参数差异:
| 参数 | DLSS (NGX) | FSR (FFX) |
|---|---|---|
| 颜色缓冲 | InColor |
ColorBuffer |
| 深度缓冲 | InDepth (R32) |
DepthBuffer |
| 运动向量 | InMotionVectors (R16G16) |
MotionVectorBuffer |
| 抖动偏移 | InJitterOffsetX/Y |
JitterOffset |
| 曝光纹理 | InExposureTexture |
Exposure |
| 锐化强度 | Sharpness (0~1) |
Sharpness (0~1) |
看完这个表,一个想法越来越清晰:这两套东西的输入有大量重叠,区别主要在数据格式和参数编码上。如果能把这些差异在中间层消化掉,技术之间的替换就完全可行。
这个想法后来成了整个项目架构设计的出发点。
四、团队分工与我的职责
4 人团队的分工如下:
| 成员 | 负责模块 | 核心工作 |
|---|---|---|
| 付一鸣 | 注入与拦截模块 | DLL 代理、Detours Hook、API 拦截 |
| 我 | 资源管理与状态机 | GPU 资源追踪、状态管理、生命周期控制 |
| 刘昱晨 | API 适配模块 | 超分器后端实现(DLSS / FSR 适配) |
| 张垚 | 调试与配置模块 | ImGui 菜单、配置系统、日志 |
我负责的"资源管理与状态机"模块,处于整个系统的中间枢纽位置——往上对接 Hook 拦截层,往下对接 API 适配层。拦截层把 Present 调用截下来了,适配层等着往画面上写东西,但中间谁来告诉适配层"你要写的图是哪张、queue 是哪个、同步信号怎么串"?就是这个模块。
五、整体架构与我的模块定位
画了张很草的白板图之后,我把系统分成了下面几个大块:
游戏渲染调用
│
▼
┌─────────────────┐
│ 注入与拦截层 │ ← DLL代理 + Detours Hook,负责"截住"调用
└─────────────────┘
│
▼
┌─────────────────┐
│ 资源管理与状态机 │ ← 我负责!资源追踪、状态管理、生命周期控制
└─────────────────┘
│
▼
┌─────────────────┐
│ API 适配层 │ ← DLSS后端 / FSR后端
└─────────────────┘
│
▼
渲染结果返回游戏
三大层各司其职:
-
注入与拦截层:负责把自己塞进游戏进程,在正确的函数调用上挂上钩子
-
资源管理与状态机(我负责) :管理 GPU 渲染资源(纹理的追踪和校验),维护帧状态,把不同 API 的参数翻译成统一格式
-
API 适配层:负责对接各个厂商的 SDK,拿到统一格式的输入后调用具体算法
六、资源管理模块的初步思考
虽然第一篇博客还没到写代码的阶段,但我已经开始在脑子里搭这个模块的框架了。
核心问题:我们是一个"外人"——不参与游戏代码的编译链接,只能在运行时从旁路去"观察"和"记录"。每次 Present Hook 触发时,手里只有一个光秃秃的 swapchain 句柄和一个 imageIndex。至于这个 swapchain 到底对应哪些 image、哪个 queue 能提交命令、需不需要加 semaphore 等它渲染完成——全不知道。
设计原则:从注入点反推需要什么。Present 这个注入点需要的信息就三样:
-
知道 swapchain 对应哪些 images(才能用 imageIndex 找到目标图)
-
需要一个能提交命令的 queue + 对应的 command buffer(才能在 Present 前插入 GPU 操作)
-
需要把注入完成的事件塞进 Present 的等待链(才能避免闪烁)
这三个需求就是资源管理模块的边界。不是把所有 GPU 对象都管起来,而是只跟踪到能满足注入需求为止。
这部分的详细设计和实现,会在后续博客中展开。
七、AI 帮我做了什么
在学习阶段,AI 主要帮我做了两件事:
1. 快速查阅技术文档
读 FSR SDK 文档时,对 FfxResource 的结构体字段含义不确定。我让 AI 帮我查了 AMD FidelityFX SDK 的官方文档,它指出 FfxResource 的 state 字段需要和 D3D12 的资源状态对应,如果传入错误的状态值会导致 validation layer 报错。这个信息帮我提前规避了一个潜在的坑。
2. 理解参数映射关系
DLSS 的 InJitterOffsetX/Y 和 FSR 的 JitterOffset 在数值范围上是否有差异?我让 AI 帮我对比了两套 SDK 的规格说明,确认了它们的取值范围都是 [-0.5, 0.5],可以直接映射——如果范围不同,就需要在参数翻译层做额外的缩放处理。
这种"查规格"的工作如果完全靠翻 PDF 文档,效率很低。AI 帮我快速定位到了关键信息。
八、初期学习心得
这段时间主要花在理解技术背景和搭建知识框架上,还没到真正写核心代码的阶段。几点体会:
-
图形中间件的门槛在于广度。不是说某个算法有多难,而是你得同时懂多个厂商的 API、懂不同图形 API 的特性、懂 DLL 注入和 Hook 机制、懂渲染管线的资源生命周期——单一领域的深度都不缺,但把它们串起来才是挑战。
-
规格差异是最大的工作量。DLSS 和 FSR 输入输出的数据格式各有各的约定。比如运动矢量的缩放因子、深度缓冲的精度要求——这些细碎的差异,每一条到后面都是一行行适配代码。
-
资源管理是中间件稳定性的基石。在不拥有资源所有权的情况下,正确地追踪和释放 GPU 资源,是整个系统能不能稳定跑起来的关键。
九、后续计划
第一篇博客到这里差不多了。接下来几周的计划:
-
搭建项目骨架,把 DLL 注入模块的脚手架先跑通
-
深入研究 D3D12 下的资源生命周期,为写资源管理模块做准备
-
读 FSR 3.1 SDK 文档,理清输入参数的详细规格
-
在 GTA 5 上做初步的拦截测试
下一篇博客会记录具体的实践过程——搭建开发环境、编译调试项目、以及在 GTA 5 里测试拦截效果。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)