ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

把Blackwell内核移植到Ada:MFGAdaUnlock-RenoDx精确指纹校验与fatbin进程内重定向实现

把Blackwell内核移植到Ada:MFGAdaUnlock-RenoDx精确指纹校验与fatbin进程内重定向实现

【免费下载链接】MFGAdaUnlock-RenoDx

DLSS MFG on Ada — unlocks 3x/4x/6x frame generation on RTX 40-series cards and corrects the temporal midpoint. In-memory only.

项目地址:https://gitcode.com/gh_mirrors/mf/MFGAdaUnlock-RenoDx
点击查看免费下载

MFGAdaUnlock-RenoDx 是一个基于 ReShade/RenoDX 的开源插件,它的核心能力是把 NVIDIA 仅开放给 RTX 50 系(Blackwell)的 DLSS 多帧生成(3x/4x/6x)解锁到 RTX 40 系(Ada)显卡上。其中最有技术含量的部分,是精确指纹校验 + fatbin 进程内重定向这条"Blackwell 内核移植"路径——本文用尽量少的代码,讲清楚它背后的每一步设计。


背景:为什么要把 Blackwell 内核搬到 Ada?

DLSS 帧生成的插值内核是编译进驱动 DLL 里的。NVIDIA 在运行时通过架构检查(对比 NVAPI 架构 ID 是否为 Blackwell 的0x1b0)来决定是否开放多帧生成,于是 Ada 显卡只能拿到 2x。

仅解锁倍率还不够:Ada 的插值内核使用编译期写死的0.5混合权重,导致 4x 生成的三帧全部落在时间中点,画面"不前进"。早期方案是改写 PTX 中的混合系数(midpoint 修正),而 MFGAdaUnlock-RenoDx 更进一步的实验路径是:直接把为 Ada(sm_89)重编的 Blackwell 运动矢量、inpaint、inpaint 决策三个框架内核,替换回 provider 里原来的 Ada 内核槽位。

这条路径完全在已映射到进程内存的镜像中操作:不改磁盘上的任何 NVIDIA DLL(NGX 在加载时会验证 Authenticode 签名,磁盘改坏签名帧生成直接消失),插件卸载时全部字节原样恢复。

第一步:用 ELF 指纹给内核"验明正身"

NVIDIA provider 里嵌着 CUDA fatbin 容器(魔数0xBA55ED50),里面按架构存放多个 ELF cubin。插件先扫描非可执行节区,找出sm_89(Ada)且未压缩的 ELF 负载,然后对每个 ELF 提取三元组指纹:

指纹字段来源含义
text.text.*节区大小机器码字节数
shared.nv.shared节区大小静态共享内存(也是内核角色判据)
registers节区 header 的 info 高字节寄存器数量

shared大小同时充当内核角色识别器:7776 字节 = 运动矢量内核,3920 = inpaint,784 = inpaint 决策。这个映射在 blackwell.hpp#L303-L310 中定义,并由 blackwell_kernel_tests.cpp 的断言固化。

提取指纹的完整实现见FingerprintElf:blackwell.hpp#L255-L301。它先严格校验 ELF 头、节区表偏移和字符串表边界,任何越界都直接判为"不是有效 ELF",从解析层面杜绝越界读取。

第二步:指纹 + 槽位大小的双重精确匹配

拿到指纹后,插件在本地生成的替换表(kCubinPatches)中查找候选。匹配规则(MatchReplacement,blackwell.hpp#L313-L324)要求四个条件全部相等:

  1. text字节数一致;
  2. shared字节数一致;
  3. registers一致;
  4. 原始槽位大小orig_size精确等于当前 payload 大小。

此外还要求替换体大小不超过原槽位——因为默认路径是"原位覆盖",绝不写出槽位边界。

对于更细粒度的 thin-geometry 变体,MatchScatterVariant(blackwell.hpp#L327-L344)在此之上再追加一个FNV-1a64 整段负载哈希比对(source_fnv1a64),相当于把"结构指纹 + 字节内容"绑定起来。任何一项不符,该内核角色就保持原生状态,绝不做猜测式替换。

为什么如此苛刻?因为替换表是从本地安装的 NVIDIA provider 离线生成的,NVIDIA 每次更新 DLSS-G 都可能改变内核字节。"未知即不匹配"(fail-closed)保证了新 provider 出现时插件自动退守安全路径,而不是把旧内核塞进不匹配的上下文。

第三步:进程内原位替换——只写内存,不动磁盘

匹配成功后,Apply主流程(blackwell.hpp#L598-L630)先做歧义检查:运动矢量内核必须恰好 1 个,inpaint 与决策各至多 1 个,否则视为"ambiguous cubin set"直接放弃——宁可整个 Blackwell 路径不启用,也不替换到拿不准的目标上。

随后对每个槽位执行:

  1. VirtualProtect临时把该槽位改为可读写;
  2. 备份原始字节到Patch结构;
  3. memcpy写入新 cubin,剩余空间清零填充;
  4. 恢复原内存保护。

所有备份留在patches列表中。插件卸载时,Restore(blackwell.hpp#L573-L596)按逆序逐块还原,保证游戏进程里不留下任何半修补状态。

关键设计:fatbin 进程内重定向

原位覆盖有一个前提——替换体不能比原槽位大。但 Adaptive Quality V3 的研究性几何内核(ptxas 编译、零寄存器溢出)就是超过了原槽位尺寸,直接塞进去会覆盖相邻的元数据,破坏整个 fatbin。

解决方案是fatbin 进程内重定向(RedirectOversizedCubin,blackwell.hpp#L454-L564),思路类似"整块搬家 + 改门牌号":

  1. 有界复制:把整个 fatbin 复制到VirtualAlloc出来的受控内存块,总大小被硬性限制在 4 MiB 量级;
  2. 原位替换 payload:在新副本中仅替换目标 cubin 条目,更新该条目和 fatbin 外层的 size 字段,原条目之后的所有条目(其他架构 cubin、元数据)逐字节保留——这一点是 thin-geometry-release-candidate.md 中专门修订的安全项,早期版本会在该条目处截断容器,导致后续条目丢失;
  3. 重定向描述符引用:扫描 provider 镜像所有可读且非可执行节区,找出每一处恰好等于旧 fatbin 地址的 8 字节指针(即 CUDA 注册描述符),将其改写为新副本地址。引用数量必须在1 到 32 个之间,超出区间立即判失败——既防止漏改(残留旧指针),也防止误伤(大量巧合命中的 8 字节数据);
  4. 任何一步失败就整体回滚:已改的指针和槽位全部还原,回落到 fallback 路径。

还有一处值得注意的取舍(blackwell.hpp#L587-L595):如果任何一处描述符没能恢复成功,重定向的 fatbin 副本故意不释放。注释说得很直白——异常卸载时留一个有界内存泄漏,比让 CUDA 注册指针悬空要安全得多。

失败即回退:这条路径的安全网

整条 Blackwell 路径贯穿着 fail-closed 原则,汇总起来有六道关卡:

关卡失败行为
构建时没有本地生成的替换表直接报告无表,走 midpoint 修正
ELF 头/节区表解析失败视为非候选,跳过
指纹 + 槽位大小不匹配该内核保持原生
候选集合歧义(数量不符)整个 Blackwell 路径放弃
重定向引用计数超出 1..32回滚已打补丁,改用 fallback
槽位不可写 / 分配失败回滚并返回失败原因

最终 fallback 是 release-0.7 行为:解出受支持的 Ada 内核 PTX,把混合权重改写为使用时间参数,交给驱动 JIT 编译。面板会明确报告当前生效的是哪条路径,用户可以对照 blackwell.hpp 顶部的头注释理解每种状态的含义。

对应的配置项是ReShade.ini中[RenoDX.MFGUnlock]的BlackwellFrameworkKernels(默认开启),改动需要重启游戏生效;相关实验机制的默认值演进记录见 thin-geometry-release-candidate.md。

工具链:替换表从哪里来、如何审计

源仓库不存储任何生成的 cubin 表。替换表在发布准备阶段由本地安装的 NVIDIA provider 离线生成(沿用 Matias Lombo 的rebuild_cubins.py工作流),并通过 build_thin_geometry_variants.py 产出 thin-geometry 变体,生成的.generated.hpp属于私有构建输入,被排除在版本控制之外。

发布前用 inspect_generated_cubins.py 反查每个 cubin 的.text字节数、共享内存、寄存器占用,确认零溢出;blackwell_kernel_tests.cpp 则在编译期断言表结构完整性:每个替换体大小不超过原槽位(除非是授权的 V3 重定向变体)、机制名称白名单、kCubinsBuiltFor构建基线非空等。README 中nvdisasm的验证记录(如 Local cubin 无任何全局内存指令、Temporal 恰好 8 次全局加载)也属于这一验证链的一部分。

小结

把 Blackwell 内核移植到 Ada 的核心难题不是"改字节",而是"在不碰磁盘、不破坏容器、不引入悬空指针的前提下,确信自己改的是正确的字节"。MFGAdaUnlock-RenoDx 的答复是一套层层递进的校验体系:

  • ELF 三元组指纹确认内核身份,shared大小兼作角色判据;
  • 槽位大小精确匹配 + 可选 FNV-1a 内容哈希确认 provider 未被更新;
  • 原位覆盖 + 全量备份逆序还原保证可恢复性;
  • fatbin 重定向处理超大替换体,引用计数 1..32 的窗口同时防漏改与误伤;
  • fail-closed 回退确保任何不确定状态都退守经过验证的 midpoint 修正。

对普通用户来说,这些机制都封装在"面板显示哪条路径生效"这一行信息背后;对开发者来说,这套"精确指纹 + 有界重定向 + 全量可还原"的做法,是修改进程内嵌入式二进制负载时相当有参考价值的安全范式。

【免费下载链接】MFGAdaUnlock-RenoDx

DLSS MFG on Ada — unlocks 3x/4x/6x frame generation on RTX 40-series cards and corrects the temporal midpoint. In-memory only.

项目地址:https://gitcode.com/gh_mirrors/mf/MFGAdaUnlock-RenoDx
点击查看免费下载

相关推荐

上一篇:炉石传说HsMod插件:50+智能功能全面提升游戏体验的完整指南
下一篇:HsMod:炉石传说终极优化插件,50+功能全面解放你的游戏时间

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进