The Witcher 3 5.0 on Proton/Linux: re-enable DLSS, DLSS-G and ray tracing (wine_get_version check patch)

The Witcher 3 5.0 on Proton: re-enable DLSS, DLSS-G (and ray tracing)

What this is: an unofficial workaround until CD PROJEKT RED or Valve fix this properly.

Supports only: bin/x64_dx12/witcher3.exe 5.0.0.1041720 (the 2026-09-29 "Remastered" update, Steam build 25575366, sha256 c272b2c2…c7e25). The script refuses any other file.

Why DLSS is missing under Proton

The 5.0 executable asks ntdll for wine_get_version. When it finds it (Wine/Proton), the game does three things:

  • Skips NVIDIA Streamline entirely. It never calls slInit, so DLSS Super Resolution, Ray Reconstruction, DLSS Frame Generation and Reflex are all reported as unsupported.
  • Sets a cached "Wine or Steam hardware" flag. That flag forces DLSS-G unsupported, zeroes the ray tracing capability (all RT and path tracing options greyed out), skips the path-tracing shaders, disables FSR frame generation, and changes buffer alignment.
  • Nothing else. It is not the NVAPI IDs or the D3DKMTQueryAdapterInfo type 31 queries seen in the logs.

Root-cause details: ValveSoftware/Proton#607. RT hang details: HansKristian-Work/vkd3d-proton#3226.

Usage

Close the game first. Python 3, no dependencies.

python3 w3_proton_patch.py                # DLSS SR/RR, Reflex, DLSS-G   (default Steam path)
python3 w3_proton_patch.py /path/to/witcher3.exe
python3 w3_proton_patch.py --dry-run      # show the state, change nothing
python3 w3_proton_patch.py --restore      # undo everything
  • A copy of the original is saved once as witcher3.exe.orig-5.0.0.1041720.
  • Steam's "Verify integrity of game files" also restores the original.
  • A game update replaces the exe and the offsets change. Run the script again only if it says the build is supported.

Then choose DLSS and Frame Generation in Options → Graphics.

Ray tracing / path tracing (--rt) — read this first

python3 w3_proton_patch.py --rt

This clears the Wine flag, so RT and path tracing become selectable. On NVIDIA drivers 590 and newer, RT then hangs the GPU within about a minute (Xid 109 / VK_ERROR_DEVICE_LOST). This is vkd3d-proton#3226 and is not fixed upstream.

What was stable here (RTX 4090, driver 615.71.09, GE-Proton11-7, 20+ minutes with RT, path tracing, DLSS and DLSS-G):

  1. A vkd3d-proton built with vkd3d-rtas-prebuild-x8.patch (in this gist). It multiplies the acceleration-structure prebuild sizes by 8; VKD3D_RTAS_SIZE_MULT= overrides the factor at runtime. Build vkd3d-proton at the commit your Proton ships (GE-Proton11-7: af89350c) and drop the x64 d3d12.dll / d3d12core.dll into a copy of your Proton under files/lib/wine/vkd3d-proton/x86_64-windows/.
  2. --rt also raises the game's RT scratch buffer from 32 MiB to 256 MiB. ×8 alone still hung once; ×8 plus the 256 MiB buffer did not.

--rt also keeps the buffer alignment behaviour Wine gets. Clearing the flag alone makes the game request tight-aligned 256-byte buffers, which vkd3d-proton rejects, and the game then crashes within seconds. This part is only needed on vkd3d-proton builds older than #3308 (merged 2026-09-21), such as the one in GE-Proton11-7. On newer builds the request works, and keeping the patch is harmless.

Patches (file offsets)

Offset Original → new Effect
0x1B709CB 75 42 → 90 90 Creates the Streamline manager under Wine (DLSS SR/RR, Reflex)
0x1B759A0 74 → EB DLSS-G support comes from Streamline instead of the Wine flag
0x1EE2A53 75 0B → 90 90 --rt: the Wine flag no longer set (RT, path tracing, FSR FG)
0x1EE09F7 75 → EB --rt: keep Wine's buffer alignment (needed only on vkd3d-proton older than #3308)
0x106E0D 20 00 00 00 → 00 01 00 00 --rt: RT BLAS scratch default 32 → 256 MiB

Notes

  • Tested on Linux with an RTX 4090. DLSS-G needs an RTX 40 or newer.
  • Modifying the executable may be against the game's EULA. It does not touch any DRM, only the platform check, and it is fully reversible.
diff --git a/libs/vkd3d/device.c b/libs/vkd3d/device.c
index 44685730..3b531c9d 100644
--- a/libs/vkd3d/device.c
+++ b/libs/vkd3d/device.c
@@ -7946,6 +7946,25 @@ static void STDMETHODCALLTYPE d3d12_device_GetRaytracingAccelerationStructurePre
info->UpdateScratchDataSizeInBytes = size_info.updateScratchSize;
}
+ /* LOCAL WORKAROUND (vkd3d-proton #3226): Witcher 3 RT hangs on NVIDIA 590+ unless the RTAS result and
+ * scratch sizes reported to the application are inflated. x8 by default;
+ * VKD3D_RTAS_SIZE_MULT= overrides it at runtime (1 = stock behaviour). */
+ {
+ static uint32_t rtas_size_mult;
+ uint32_t mult = vkd3d_atomic_uint32_load_explicit(&rtas_size_mult, vkd3d_memory_order_relaxed);
+
+ if (!mult)
+ {
+ mult = max(1u, vkd3d_env_var_as_uint("VKD3D_RTAS_SIZE_MULT", 8));
+ vkd3d_atomic_uint32_store_explicit(&rtas_size_mult, mult, vkd3d_memory_order_relaxed);
+ INFO("RTAS prebuild sizes are multiplied by %u (local workaround).\n", mult);
+ }
+
+ info->ResultDataMaxSizeInBytes *= mult;
+ info->ScratchDataSizeInBytes *= mult;
+ info->UpdateScratchDataSizeInBytes *= mult;
+ }
+
TRACE("ResultDataMaxSizeInBytes: %"PRIu64".\n", info->ResultDataMaxSizeInBytes);
TRACE("ScratchDatSizeInBytes: %"PRIu64".\n", info->ScratchDataSizeInBytes);
TRACE("UpdateScratchDataSizeInBytes: %"PRIu64".\n", info->UpdateScratchDataSizeInBytes);
#!/usr/bin/env python3
"""Re-enable DLSS / DLSS-G (and optionally ray tracing) in The Witcher 3 5.0 under Proton/Wine.
The Witcher 3 5.0.0.1041720 ("Remastered", DX12, Steam build 25575366) detects Wine through
GetProcAddress(ntdll, "wine_get_version") and then deliberately skips NVIDIA Streamline (so DLSS SR/RR,
DLSS Frame Generation and Reflex are unavailable) and forces ray tracing / path tracing off.
This script flips those checks in bin/x64_dx12/witcher3.exe. It only accepts that exact build.
python3 w3_proton_patch.py [path/to/witcher3.exe] DLSS SR/RR, Reflex and DLSS-G
python3 w3_proton_patch.py --rt [path/to/witcher3.exe] also RT and path tracing (read the README first:
needs a vkd3d-proton with the #3226 workaround,
or the GPU hangs within a minute)
python3 w3_proton_patch.py --restore [path/to/witcher3.exe] undo every patch (Steam "Verify integrity" also does)
add --dry-run to only report the current state.
Unofficial; use at your own risk. Close the game before running it.
"""
import argparse
import hashlib
import os
import shutil
import sys
ORIGINAL_SHA256 = "c272b2c2e61f84c758e28fab69ab2915944dd1e539dbb435fae9fc67494c7e25"
ORIGINAL_SIZE = 90832336
DEFAULT_PATH = os.path.expanduser(
"~/.local/share/Steam/steamapps/common/The Witcher 3/bin/x64_dx12/witcher3.exe")
# (file offset, original bytes, patched bytes, description)
BASE = [
(0x1B709CB, b"\x75\x42", b"\x90\x90", "create the Streamline manager (slInit) under Wine: DLSS SR/RR, Reflex"),
(0x1B759A0, b"\x74", b"\xEB", "do not force DLSS-G 'unsupported' on the Wine flag"),
]
RT = [
(0x1EE2A53, b"\x75\x0B", b"\x90\x90", "clear the cached Wine flag: RT, path tracing, FSR FG"),
(0x1EE09F7, b"\x75", b"\xEB", "keep buffer alignment as under Wine (vkd3d-proton rejects the tight-aligned 256 B buffers)"),
(0x106E0D, b"\x20\x00\x00\x00", b"\x00\x01\x00\x00", "RT BLAS scratch buffer default 32 MiB -> 256 MiB"),
]
ALL = BASE + RT
def state_of(data, patch):
off, orig, new, _ = patch
cur = data[off:off + len(orig)]
return "original" if cur == orig else "patched" if cur == new else "unknown"
def main():
ap = argparse.ArgumentParser(
description="Re-enable DLSS / DLSS-G (and optionally RT) in The Witcher 3 5.0 under Proton/Wine.")
ap.add_argument("exe", nargs="?", default=DEFAULT_PATH)
ap.add_argument("--rt", action="store_true", help="also enable ray tracing and path tracing")
ap.add_argument("--restore", action="store_true", help="revert every patch")
ap.add_argument("--dry-run", action="store_true", help="report only, change nothing")
args = ap.parse_args()
path = args.exe
if not os.path.isfile(path):
sys.exit(f"not found: {path}")
data = bytearray(open(path, "rb").read())
if len(data) != ORIGINAL_SIZE:
sys.exit(f"unexpected size {len(data)}: this script only supports witcher3.exe 5.0.0.1041720 (DX12)")
states = [state_of(data, p) for p in ALL]
if "unknown" in states:
sys.exit("unexpected bytes at a patch site: different build or modified exe; nothing changed")
# Rebuild the original image in memory and check it is exactly the supported build.
orig = bytearray(data)
for off, o, _, _ in ALL:
orig[off:off + len(o)] = o
if hashlib.sha256(orig).hexdigest() != ORIGINAL_SHA256:
sys.exit("sha256 mismatch: not witcher3.exe 5.0.0.1041720 (DX12); nothing changed")
for p, s in zip(ALL, states):
print(f" 0x{p[0]:07X} {s:8} {p[3]}")
if args.restore:
target = bytes(orig)
else:
target = bytearray(data)
for off, _, new, _ in (ALL if args.rt else BASE):
target[off:off + len(new)] = new
target = bytes(target)
if target == bytes(data):
print("nothing to do")
return
if args.dry_run:
print("dry run: would write changes")
return
backup = path + ".orig-5.0.0.1041720"
if not os.path.exists(backup):
with open(backup, "wb") as f:
f.write(bytes(orig))
print(f"backup of the original: {backup}")
tmp = path + ".tmp-patch"
with open(tmp, "wb") as f:
f.write(target)
shutil.copymode(path, tmp)
os.replace(tmp, path)
print("restored the original" if args.restore else
"patched: DLSS/DLSS-G" + (" + RT/path tracing" if args.rt else ""))
if args.rt and not args.restore:
print("WARNING: RT under Proton needs a vkd3d-proton with the RTAS prebuild-size workaround "
"(HansKristian-Work/vkd3d-proton#3226); without it the GPU hangs (Xid 109). See README.")
if __name__ == "__main__":
main()
添加评论
点赞收藏
点踩分享查看原文
评论
?
参与讨论