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 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 random import randrange
|
||||
|
||||
|
@ -99,7 +108,7 @@ def merge_user_dir(src, dst):
|
|||
else:
|
||||
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:
|
||||
if os.path.isdir(dst):
|
||||
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
|
||||
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:
|
||||
if e.errno == errno.EPERM:
|
||||
#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
|
||||
|
||||
# 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_SETFLAGS = 0x40086602
|
||||
|
||||
|
@ -705,6 +801,15 @@ class CompatData:
|
|||
if os.path.exists(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",
|
||||
self.prefix_dir + "drive_c/windows/system32/d3d12.dll")
|
||||
try_copy(g_proton.lib_dir + "wine/vkd3d-proton/d3d12.dll",
|
||||
|
|
Loading…
Reference in a new issue