Files

13 KiB
Raw Permalink Blame History

Wpyw DLSS — Minecraft Java 1.20.1 (Fabric)

在 Minecraft Java 版里接入 NVIDIA DLSS 超分(Super Resolution) 与 帧生成(Frame Generation / 插帧)。

工程名 wpywdlss / MinecraftDLSS 是临时名,随你改。


一、先讲清楚三个硬事实(省掉走弯路的成本)

1. DLSS 5 不是超分,也不是插帧

超分 插帧 本质
DLSS 4 ✅ Super Resolution ✅ Multi Frame Generation(最高 6X) 你要的就是这两个
DLSS 5 ❌ ❌ 3D 引导神经渲染:重建材质 / 光照 / 皮肤 / 阴影 / 反射

DLSS 5 于 2026-09-03 上线,官方仅 RTX 50 系,目前只有 NBA 2K27 一款游戏,集成走 UE5 插件路径。 在 Streamline SDK 2.14.1 的 include/ 与 bin/x64/ 里不存在任何 dlssnr / 神经渲染的头文件或插件—— 即通用 Streamline 层根本没有 DLSS 5 的集成接口。

2. Minecraft Java 是 OpenGL,而 NGX 不支持 OpenGL

NGX / Streamline 只支持 D3D11 / D3D12 / Vulkan。所以 DLSS 进 MC Java 的唯一办法是: 游戏继续用 OpenGL 渲染,模组内部再起一个 Vulkan 设备,用外部内存/信号量把纹理零拷贝共享过去, 在 Vulkan 侧跑 NGX。

3. 真正的工程量在「运动矢量」

DLSS 超分必须吃 运动矢量 + 深度 + 抖动投影矩阵,而 Minecraft 的 OpenGL 管线一个都不生产。 这是本项目 80% 的工作量。在 Iris + 光影包环境下更难:Iris 接管整条管线、自己控制投影矩阵与 G-buffer, 且还有 Distant Horizons / Voxy 的 LOD 几何要算速度。


二、架构

┌─ Minecraft 1.20.1 (Java, OpenGL / LWJGL) ──────────────────────────┐
│  Fabric 模组 (本仓库 src/main/java)                                 │
│   • Mixin 投影矩阵亚像素抖动 (jitter)                               │
│   • Mixin 渲染分辨率 → 低分渲染 world framebuffer                   │
│   • 导出 depth / motion vector 纹理                                 │
│   • 在 present 点调用原生桥接                                        │
└────────────────────────┬──────────────────────────────────────────┘
                         │ JNI
┌────────────────────────▼──────────────────────────────────────────┐
│  自研原生桥接 DLL (C++ / MSVC)   ← native/  本项目核心               │
│   • 建 Vulkan 1.2+ 设备(同一块 GPU)                                │
│   • GL↔VK 外部内存互操作                                             │
│     GL_EXT_memory_object_win32 ↔ VK_KHR_external_memory_win32       │
│     GL_EXT_semaphore_win32      ↔ VK_KHR_external_semaphore_win32   │
│   • slInit / slSetVulkanDevice / slSetConstants                     │
│   • slDLSSSetOptions + slEvaluateFeature   (超分)                  │
│   • slDLSSGSetOptions                      (帧生成)                │
└────────────────────────┬──────────────────────────────────────────┘
                         │
             ┌───────────▼────────────┐
             │  sl.interposer.dll     │   ← 用户自备,不随模组分发
             │   ├─ sl.dlss.dll       │ → nvngx_dlss.dll   超分
             │   ├─ sl.dlss_g.dll     │ → nvngx_dlssg.dll  插帧
             │   └─ NvLowLatencyVk.dll│ → Reflex(Vulkan)
             └────────────────────────┘

三、NVIDIA 运行时:绝不打包进模组

nvngx_dlss.dll / nvngx_dlssg.dll / sl.*.dll 均为 NVIDIA 专有二进制,不允许随模组再分发。 本模组只提供加载逻辑,二进制由用户自行放置。

运行时查找顺序:

  1. JVM 参数 -Dwpywdlss.runtimeDir=<路径>
  2. <gameDir>/ngx/
  3. <gameDir>/config/ngx/

需要的文件(全部来自 Streamline SDK 2.14.1 的 bin/x64/):

文件 大小 用途
sl.interposer.dll 652,928 Streamline 核心
sl.common.dll 843,392 公共层
sl.dlss.dll 422,016 超分插件
sl.dlss_g.dll 636,032 帧生成插件
nvngx_dlss.dll 58,956,912 DLSS 超分模型 (310.9.1.0)
nvngx_dlssg.dll 7,460,976 DLSS 帧生成模型 (310.9.1.0)
NvLowLatencyVk.dll 57,840 Vulkan Reflex(可选)

若 NGX 因缺少 applicationId 拒绝加载,可改用 bin/x64/development/ 下的开发版 DLL 做实验。


四、构建

Java 侧(Fabric 模组)

$env:JAVA_HOME = 'C:\Program Files\Java\jdk-21.0.10'
.\gradlew.bat build

产物:build/libs/wpywdlss-0.1.0.jar

版本组合(对齐 Fabric 官方 1.20.1 分支): minecraft 1.20.1 · loader 0.19.5 · loom 1.17-SNAPSHOT · fabric-api 0.92.12+1.20.1 · Mojang 官方映射

原生侧(C++ 桥接 DLL)

见 native/。使用 MSVC(VS2022 BuildTools 14.44.35207)+ CMake。

不需要 Vulkan SDK:Khronos 头文件取自 DLSS demo 自带的 DLSS_Sample_App/donut/thirdparty/glfw/deps/vulkan/,导入库由 dumpbin /exports C:\Windows\System32\vulkan-1.dll + lib /def: 自造。


五、路线图

阶段 目标 验证方式
P0 地基 Fabric 工程可编译;原生桥接 DLL 可编译;JNI 打通;Vulkan 设备创建成功;GL↔VK 互操作往返 游戏内一张纹理经 GL→VK→GL 往返后画面一致
P1 数据源 深度纹理 + 抖动投影 + 运动矢量。先在纯净版 / Sodium 下做 运动矢量可视化输出正确
P2 DLSS 超分 接 sl.dlss,出画面。applicationId 风险在此暴露 1080p→4K 提升且画质可接受
P3 HUD 原生分辨率 世界低分渲染、HUD/UI 保持原生清晰 HUD 文字不糊
P4 帧生成 接 sl.dlss_g。最难一步(需接管 present 路径) 输出帧率提升,伪影可接受
P5 Iris 兼容 在光影包环境下算运动矢量 主流光影包下不崩不糊

六、P0 实测结果(已跑通,非推演)

环境:RTX 5070 / 驱动 616.92 / Vulkan loader 1.4.341 / Win11 26100 方式:tools/ProbeRunner.java 独立加载桥接 DLL 调用 nativeProbe(),不启动游戏 结论:nativeIsReady() = true,exit code 0

检查项 实测结果
Vulkan 实例 ✅ VK_SUCCESS,loader 1.4.341
物理设备 2 个:RTX 5070(0x10de, DISCRETE, api 1.4.351)+ AMD 核显(0x1002, INTEGRATED, 1.4.315);自动选中 NVIDIA
设备扩展(291 可用) ✅ VK_KHR_external_memory_win32 / VK_KHR_external_semaphore_win32 / VK_KHR_timeline_semaphore / dedicated_allocation / image_format_list / synchronization2 全部可用
设备创建 ✅ VK_SUCCESS(queue family 0,已启用 timeline semaphore)
互操作函数指针 ✅ vkGetMemoryWin32HandleKHR / vkGetSemaphoreWin32HandleKHR / vkImportSemaphoreWin32HandleKHR 经 vkGetDeviceProcAddr 全部取到
镜像导出(go/no-go) ✅ OPAQUE_WIN32: exportable=YES, importable=YES, dedicatedOnly=no
信号量 ✅ OPAQUE_WIN32: exportable=YES, importable=YES
显存 11,943 MiB device-local

两个必须记住的实测细节

  1. D3D12_HEAP / D3D11_TEXTURE 只能导入、不能导出(exportable=no)。 这直接影响你那个 rtx_vsr_host.dll(只有 NVSDK_NGX_D3D12_* 接口): 它无法接收"OpenGL/Vulkan 分配、D3D12 导入"的纹理,只能反过来由 D3D12 侧分配再共享出来。 所以 VSR 超分和 DLSS 超分不能复用同一条互操作管线,这是两套东西。
  2. dedicatedOnly=no:不强制专用分配,意味着我们可以在同一块 VkDeviceMemory 里规划输入/输出镜像,省一次分配和一次拷贝。

常用命令

# 编原生桥接(自动处理 vulkan-1.lib)
.\native\tools\build_native.cmd

# 只重造 vulkan-1.lib
.\native\tools\make_vulkan_lib.cmd

# 跑 P0 探测(不需要启动游戏)
$env:JAVA_HOME='C:\Program Files\Java\jdk-21.0.10'
java -cp "build\classes\java\main" `
     -Dwpywdlss.bridgePath=native\build\wpywdlss_bridge.dll `
     tools\ProbeRunner.java

七、OpenGL 互操作实测结果(2026-09-16,已跑通)

为什么这一个探测决定所有路线的生死:OpenGL 只能导入、不能导出内存和信号量。 所以分配方必须是 Vulkan/D3D12,GL 只负责导入对方给过来的 Win32 HANDLE。 GL_EXT_external_objects* 是导入 Vulkan 对象的另一条路,走 OPAQUE_WIN32 时不需要它 —— 把它当必需项会得出假阴性(我第一版就写错了,已修正)。

nativeProbeOpenGL() 创建一个隐藏 WGL 上下文实测:

检查 结果
GL_RENDERER NVIDIA GeForce RTX 5070/PCIe/SSE2
GL_VERSION 4.6.0 NVIDIA 616.92
GL 扩展总数 405
GL_EXT_memory_object ✅
GL_EXT_memory_object_win32 ✅
GL_EXT_semaphore ✅
GL_EXT_semaphore_win32 ✅
glCreateMemoryObjectsEXT ✅
glImportMemoryWin32HandleEXT ✅
glTextureStorageMem2DEXT ✅
glImportSemaphoreWin32HandleEXT ✅
glDeleteMemoryObjectsEXT / glDeleteSemaphoresEXT ✅
GL_EXT_external_objects* ❌(不需要,走 OPAQUE_WIN32 时用不到)
glCreateSemaphoresEXT ❌(不需要,GL 只导入不导出)

判定:VERDICT: the OpenGL transport is AVAILABLE on this machine.

两侧合起来的完整链路(能力层面已验证):

Vulkan/D3D12 分配镜像
      │ vkGetMemoryWin32HandleKHR / D3D12 CreateSharedHandle
      ▼  (Win32 HANDLE)
OpenGL  glCreateMemoryObjectsEXT → glImportMemoryWin32HandleEXT
        → glTextureStorageMem2DEXT   (得到可渲染/可采样的 GL 纹理)
      ▲  (Win32 信号量 HANDLE)
        glImportSemaphoreWin32HandleEXT

八、路线 C(ReShade 路线)落地清单

先明确 C 在 OpenGL 下的天花板(引自 DLSS5-Feeder 官方 Limitations):

DLAA contract, optional reduced work extent on D3D11 — render resolution still equals DLAA output resolution... D3D12, Vulkan and OpenGL paths remain at 100%. This is not jittered DLSS Super Resolution, and a Quality/Balanced/Performance mode cannot be added.

即:OpenGL 下是纯 DLAA + DLSS 5 神经渲染观感,内部渲染分辨率不降 → 零帧率收益,拿不到超分,也没有插帧。 另外官方承认 "the UI is processed with the scene" —— Minecraft 的物品栏/聊天/F3 会被一起处理而拖影。

需要的组件

组件 来源 状态
ReShade 6.8+(需 add-on 支持),装成 opengl32.dll,API 选 OpenGL reshade.me 需你下载
Generic Depth add-on 启用并认到 Minecraft 的场景深度 ReShade 自带 ⚠️ 最大风险点,见下
神经消费者:Deep Fried Chicken(推荐)或 Krish 的 renodx-dlss5.addon64 各自 Discord 需你获取(Discord 门禁,我拿不到)
nvngx_dlssnr.dll 已有 ✅ GUI-DLSS5 包里
nvngx_dlss.dll(放在游戏目录旁) 已有 ✅ Streamline SDK 里
运动矢量提供者:LumeniteFX Kernel(=3,推荐) github.com/umar-afzaal/LumeniteFX 需下载
dlss5-feed.addon64 + DLSS5_Feed.fx DLSS5-Feeder release 需下载

Minecraft 特有的四个坑(我预判,待实测确认)

  1. 深度缓冲:ReShade 的 Generic Depth 必须正确识别 Minecraft 的场景深度。 Iris/光影会自建 FBO,Sodium 改了区块渲染 —— 识别很可能失败。
  2. GPU 选择:这条路要求渲染真的在 NVIDIA GPU 上。你有 RTX 5070 + AMD 核显, 必须在 Windows「设置 ▸ 显示 ▸ 图形」里把 Java 强制到 NVIDIA,否则 DLSS 无从谈起。
  3. HUD 拖影:官方明说 UI 与场景一起处理。要么忍受,要么自己加 UI 遮罩。
  4. 驱动版本:他们实测的坏组合是驱动 616.56 / 616.64(nvngx_dlssnr.dll 内部 fault)。 你是 616.92,比他们测过的都新,未知。 先跑他们的自检 host64\dlss5-feed-host64.exe --test(300/300 evaluates succeeded 才算 OK)。

九、许可与合规

  • 本模组代码:MIT
  • NVIDIA 专有二进制一律不再分发,仅由用户自备(同 Salt's Anti-Aliasing 等既有项目的做法)
  • 参考但不复制任何现有模组代码;Super Resolution(GPL-3.0)与 Salt's Anti-Aliasing(MIT) 仅作为「这条路走得通」的存在性证据
  • NGX applicationId 需向 NVIDIA 申请;在获批前 NVIDIA 目前为宽容放行(会打警告日志)