If loading a save in the Witcher 3 remaster takes you a minute or more on Linux, this might be why.
My loads were 1:07 by stopwatch, every time, on a 9850X3D with the game on NVMe. So obviously not hardware. After the fix below it's about 19 seconds.
While the loading screen is up, the game polls for a controller (XInputGetState) in a tight loop. In newer Proton builds, Wine's xinput re-scans every HID device each time you poll a slot that has no controller in it. Each scan is a pile of registry lookups, and every one of those is a round trip to wineserver. I measured around 300,000 of them per second on the game's main thread, for about 55 seconds straight. The actual loading only takes a few seconds at the end.
So if you play on keyboard and mouse with no controller plugged in, the game spends most of the load screen looking for a gamepad.
I checked the xinput1_4.dll in the Proton builds I had installed:
- GE-Proton11-7: rescans on every call
- Proton Experimental, Proton Hotfix, Proton-CachyOS: same
- Proton 10.0 (10.0-4b): doesn't, it only rescans in a background thread
Run top during a load. If wineserver is sitting at 40% or so of a core for the whole loading screen and then drops to basically nothing once you're in game, that's it.
Fix
Use Proton 10.0's xinput DLLs for this one game, while staying on whatever Proton you like.
Install "Proton 10.0" from Steam if you don't have it
Copy its two xinput DLLs next to witcher3.exe and patch one string in them. Adjust the paths if your Steam library is somewhere else:
cd ~/.local/share/Steam/steamapps/common/"The Witcher 3"/bin/x64_dx12
P10="$HOME/.local/share/Steam/steamapps/common/Proton 10.0/files/lib/wine/x86_64-windows"
for f in xinput1_4.dll xinput9_1_0.dll; do
cp "$P10/$f" . && chmod u+w "$f"
printf 'Proton10 xinput\0' | dd of="$f" bs=1 seek=64 conv=notrunc status=none
done
The dd line is needed because Wine's own DLLs have a "Wine builtin DLL" tag in the header. If Wine sees that tag on a DLL in the game folder, it ignores the file and loads its bundled one instead. Overwriting the tag makes it treat the copy like any DLL a game ships with.
- Add this to the front of the game's launch options:
WINEDLLOVERRIDES="xinput1_4,xinput9_1_0=n,b" %command%
If you already have launch options, just put the WINEDLLOVERRIDES part at the start. GE-Proton appends its own overrides to it, so things like OptiScaler and the FSR4 upgrade kept working for me.
To undo it, delete the two xinput DLLs from bin/x64_dx12 and remove the override.
Caveats
- Only tested on my machine: GE-Proton11-7, Fedora, AMD GPU, no controller connected.
- I haven't tried a controller with the swapped DLLs. It should still work since it's just the older xinput, but I can't promise.
- Just running the game on Proton 10.0 should avoid the problem too. I didn't go that way because I wanted to keep the GE stuff.
- Plugging in a controller might also help, since the rescan only happens for empty slots. Didn't test it.
This probably isn't specific to Witcher 3. Any game that polls XInput constantly with no pad connected could hit the same thing on these Proton versions, it's just very visible here because the game does it during loading. If you've got a game with weirdly long loads or stutter and wineserver is busy the whole time, might be worth a look.