proton: Copy DLLs provided by the NVIDIA driver into prefix
The upcoming NVIDIA 470 driver series will introduce a DLL (nvngx.dll) for the support of NVIDIA DLSS in Proton. This change adds logic for discovering the location of DLL files provided by the NVIDIA driver, and copies them to C:\Windows\System32\ Reviewed-by: Adam Moss <amoss@nvidia.com>
This commit is contained in:
parent
1630811474
commit
0afcb19416
1 changed files with 106 additions and 1 deletions
107
proton
107
proton
|
@ -15,6 +15,15 @@ import subprocess
|
||||||
import sys
|
import sys
|
||||||
import tarfile
|
import tarfile
|
||||||
|
|
||||||
|
from ctypes import CDLL
|
||||||
|
from ctypes import POINTER
|
||||||
|
from ctypes import Structure
|
||||||
|
from ctypes import addressof
|
||||||
|
from ctypes import cast
|
||||||
|
from ctypes import c_int
|
||||||
|
from ctypes import c_char_p
|
||||||
|
from ctypes import c_void_p
|
||||||
|
|
||||||
from filelock import FileLock
|
from filelock import FileLock
|
||||||
from random import randrange
|
from random import randrange
|
||||||
|
|
||||||
|
@ -99,7 +108,7 @@ def merge_user_dir(src, dst):
|
||||||
else:
|
else:
|
||||||
extant_dirs += dst_dir
|
extant_dirs += dst_dir
|
||||||
|
|
||||||
def try_copy(src, dst, add_write_perm=True, copy_metadata=True):
|
def try_copy(src, dst, add_write_perm=True, copy_metadata=True, optional=False):
|
||||||
try:
|
try:
|
||||||
if os.path.isdir(dst):
|
if os.path.isdir(dst):
|
||||||
dstfile = dst + "/" + os.path.basename(src)
|
dstfile = dst + "/" + os.path.basename(src)
|
||||||
|
@ -119,6 +128,12 @@ def try_copy(src, dst, add_write_perm=True, copy_metadata=True):
|
||||||
new_mode = os.lstat(dstfile).st_mode | stat.S_IWUSR | stat.S_IWGRP
|
new_mode = os.lstat(dstfile).st_mode | stat.S_IWUSR | stat.S_IWGRP
|
||||||
os.chmod(dstfile, new_mode)
|
os.chmod(dstfile, new_mode)
|
||||||
|
|
||||||
|
except FileNotFoundError as e:
|
||||||
|
if optional:
|
||||||
|
log('Error while copying to \"' + dst + '\": ' + e.strerror)
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
|
||||||
except PermissionError as e:
|
except PermissionError as e:
|
||||||
if e.errno == errno.EPERM:
|
if e.errno == errno.EPERM:
|
||||||
#be forgiving about permissions errors; if it's a real problem, things will explode later anyway
|
#be forgiving about permissions errors; if it's a real problem, things will explode later anyway
|
||||||
|
@ -162,6 +177,87 @@ def try_get_game_library_dir():
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
# Function to find the installed location of DLL files for use by Wine/Proton
|
||||||
|
# from the NVIDIA Linux driver
|
||||||
|
#
|
||||||
|
# See https://gitlab.steamos.cloud/steamrt/steam-runtime-tools/-/issues/71 for
|
||||||
|
# background on the chosen method of DLL discovery.
|
||||||
|
#
|
||||||
|
# On success, returns a str() of the absolute-path to the directory at which DLL
|
||||||
|
# files are stored
|
||||||
|
#
|
||||||
|
# On failure, returns None
|
||||||
|
def find_nvidia_wine_dll_dir():
|
||||||
|
try:
|
||||||
|
libdl = CDLL("libdl.so.2")
|
||||||
|
except (OSError):
|
||||||
|
return None
|
||||||
|
|
||||||
|
try:
|
||||||
|
libglx_nvidia = CDLL("libGLX_nvidia.so.0")
|
||||||
|
except OSError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# from dlinfo(3)
|
||||||
|
#
|
||||||
|
# struct link_map {
|
||||||
|
# ElfW(Addr) l_addr; /* Difference between the
|
||||||
|
# address in the ELF file and
|
||||||
|
# the address in memory */
|
||||||
|
# char *l_name; /* Absolute pathname where
|
||||||
|
# object was found */
|
||||||
|
# ElfW(Dyn) *l_ld; /* Dynamic section of the
|
||||||
|
# shared object */
|
||||||
|
# struct link_map *l_next, *l_prev;
|
||||||
|
# /* Chain of loaded objects */
|
||||||
|
#
|
||||||
|
# /* Plus additional fields private to the
|
||||||
|
# implementation */
|
||||||
|
# };
|
||||||
|
RTLD_DI_LINKMAP = 2
|
||||||
|
class link_map(Structure):
|
||||||
|
_fields_ = [("l_addr", c_void_p), ("l_name", c_char_p), ("l_ld", c_void_p)]
|
||||||
|
|
||||||
|
# from dlinfo(3)
|
||||||
|
#
|
||||||
|
# int dlinfo (void *restrict handle, int request, void *restrict info)
|
||||||
|
dlinfo_func = libdl.dlinfo
|
||||||
|
dlinfo_func.argtypes = c_void_p, c_int, c_void_p
|
||||||
|
dlinfo_func.restype = c_int
|
||||||
|
|
||||||
|
# Allocate a link_map object
|
||||||
|
glx_nvidia_info_ptr = POINTER(link_map)()
|
||||||
|
|
||||||
|
# Run dlinfo(3) on the handle to libGLX_nvidia.so.0, storing results at the
|
||||||
|
# address represented by glx_nvidia_info_ptr
|
||||||
|
if dlinfo_func(libglx_nvidia._handle,
|
||||||
|
RTLD_DI_LINKMAP,
|
||||||
|
addressof(glx_nvidia_info_ptr)) != 0:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Grab the contents our of our pointer
|
||||||
|
glx_nvidia_info = cast(glx_nvidia_info_ptr, POINTER(link_map)).contents
|
||||||
|
|
||||||
|
# Decode the path to our library to a str()
|
||||||
|
if glx_nvidia_info.l_name is None:
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
libglx_nvidia_path = os.fsdecode(glx_nvidia_info.l_name)
|
||||||
|
except UnicodeDecodeError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Follow any symlinks to the actual file
|
||||||
|
libglx_nvidia_realpath = os.path.realpath(libglx_nvidia_path)
|
||||||
|
|
||||||
|
# Go to the relative path ./nvidia/wine from our library
|
||||||
|
nvidia_wine_dir = os.path.join(os.path.dirname(libglx_nvidia_realpath), "nvidia", "wine")
|
||||||
|
|
||||||
|
# Check that nvngx.dll exists here, or fail
|
||||||
|
if os.path.exists(os.path.join(nvidia_wine_dir, "nvngx.dll")):
|
||||||
|
return nvidia_wine_dir
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
EXT2_IOC_GETFLAGS = 0x80086601
|
EXT2_IOC_GETFLAGS = 0x80086601
|
||||||
EXT2_IOC_SETFLAGS = 0x40086602
|
EXT2_IOC_SETFLAGS = 0x40086602
|
||||||
|
|
||||||
|
@ -705,6 +801,15 @@ class CompatData:
|
||||||
if os.path.exists(nvapi32_dll):
|
if os.path.exists(nvapi32_dll):
|
||||||
os.unlink(nvapi32_dll)
|
os.unlink(nvapi32_dll)
|
||||||
|
|
||||||
|
# Try to detect known DLLs that ship with the NVIDIA Linux Driver
|
||||||
|
# and add them into the prefix
|
||||||
|
nvidia_wine_dll_dir = find_nvidia_wine_dll_dir()
|
||||||
|
if nvidia_wine_dll_dir:
|
||||||
|
for dll in ["_nvngx.dll", "nvngx.dll"]:
|
||||||
|
try_copy(nvidia_wine_dll_dir + "/" + dll,
|
||||||
|
self.prefix_dir + "drive_c/windows/system32/" + dll,
|
||||||
|
optional=True)
|
||||||
|
|
||||||
try_copy(g_proton.lib64_dir + "wine/vkd3d-proton/d3d12.dll",
|
try_copy(g_proton.lib64_dir + "wine/vkd3d-proton/d3d12.dll",
|
||||||
self.prefix_dir + "drive_c/windows/system32/d3d12.dll")
|
self.prefix_dir + "drive_c/windows/system32/d3d12.dll")
|
||||||
try_copy(g_proton.lib_dir + "wine/vkd3d-proton/d3d12.dll",
|
try_copy(g_proton.lib_dir + "wine/vkd3d-proton/d3d12.dll",
|
||||||
|
|
Loading…
Reference in a new issue