Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compatibility Rework with DLSS handling #16

Open
wants to merge 7 commits into
base: compatibility-rework-2
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 88 additions & 4 deletions src/XIVLauncher.Common.Unix/Compatibility/CompatibilityTools.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ public class CompatibilityTools

private DirectoryInfo dxvkDirectory;

private DirectoryInfo GamePath;

private StreamWriter logWriter;

public bool IsToolReady { get; private set; }
Expand All @@ -36,7 +38,7 @@ public class CompatibilityTools

private Dictionary<string, string> extraEnvironmentVars;

public CompatibilityTools(WineSettings wineSettings, DxvkSettings dxvkSettings, bool? gamemodeOn, DirectoryInfo toolsFolder, bool isFlatpak, Dictionary<string, string> extraEnvVars = null)
public CompatibilityTools(WineSettings wineSettings, DxvkSettings dxvkSettings, bool? gamemodeOn, DirectoryInfo toolsFolder, DirectoryInfo gamePath, bool isFlatpak, Dictionary<string, string> extraEnvVars = null)
{
this.Settings = wineSettings;
this.DxvkSettings = dxvkSettings;
Expand All @@ -49,6 +51,8 @@ public CompatibilityTools(WineSettings wineSettings, DxvkSettings dxvkSettings,
this.wineDirectory = new DirectoryInfo(Path.Combine(toolsFolder.FullName, "wine"));
this.dxvkDirectory = new DirectoryInfo(Path.Combine(toolsFolder.FullName, "dxvk"));

this.GamePath = gamePath;

this.logWriter = new StreamWriter(wineSettings.LogFile.FullName);

if (!this.wineDirectory.Exists)
Expand All @@ -73,6 +77,9 @@ public async Task EnsureTool(DirectoryInfo tempPath)
if (DxvkSettings.Enabled)
await InstallDxvk().ConfigureAwait(false);

if (DxvkSettings.NvapiEnabled)
await InstallNvapi().ConfigureAwait(false);

IsToolReady = true;
}

Expand All @@ -93,7 +100,7 @@ private async Task InstallDxvk()
File.Copy(fileName, Path.Combine(system32, Path.GetFileName(fileName)), true);
}

// 32-bit files for Directx9.
// 32-bit files for Directx9. Only needed for external programs.
var dxvkPath32 = Path.Combine(dxvkDirectory.FullName, DxvkSettings.FolderName, "x32");
var syswow64 = Path.Combine(Settings.Prefix.FullName, "drive_c", "windows", "syswow64");

Expand All @@ -105,7 +112,83 @@ private async Task InstallDxvk()
{
File.Copy(fileName, Path.Combine(syswow64, Path.GetFileName(fileName)), true);
}
}
}
}

private async Task InstallNvapi()
{
var dxvkPath = Path.Combine(dxvkDirectory.FullName, DxvkSettings.NvapiFolderName, "x64");
if (!Directory.Exists(dxvkPath))
{
Log.Information($"DXVK Nvapi does not exist, downloading {DxvkSettings.NvapiDownloadUrl}");
var nvapiFolder = new DirectoryInfo(Path.Combine(dxvkDirectory.FullName, DxvkSettings.NvapiFolderName));
nvapiFolder.Create();
await DownloadTool(nvapiFolder, DxvkSettings.NvapiDownloadUrl).ConfigureAwait(false);
}

var system32 = Path.Combine(Settings.Prefix.FullName, "drive_c", "windows", "system32");
var files = Directory.GetFiles(dxvkPath);

foreach (string fileName in files)
{
File.Copy(fileName, Path.Combine(system32, Path.GetFileName(fileName)), true);
}

// Create symlinks to nvngx.dll and _nvngx.dll in the GamePath/game folder. For some reason it doesn't work if you put them in system32.
// If NvngxOverride is set, assume the files/symlinks are already there. For Nix compatibility, mostly.
if (!string.IsNullOrEmpty(DxvkSettings.NvngxFolder) && Directory.Exists(DxvkSettings.NvngxFolder) && !DxvkSettings.NvngxOverride)
{
string[] targets = { "nvngx.dll", "_nvngx.dll"};
foreach (var target in targets)
{
var source = new FileInfo(Path.Combine(DxvkSettings.NvngxFolder, target));
var destination = new FileInfo(Path.Combine(GamePath.FullName, "game", target));
if (source.Exists)
{
if (!destination.Exists) // No file, create link.
{
destination.CreateAsSymbolicLink(source.FullName);
Log.Verbose($"Making symbolic link at {destination.FullName} to {source.FullName}");
}
else if (destination.ResolveLinkTarget(false) is null) // File exists, is not a symlink. Delete and create link.
{
destination.Delete();
destination.CreateAsSymbolicLink(source.FullName);
Log.Verbose($"Replacing file at {destination.FullName} with symbolic link to {source.FullName}");
}
else if (destination.ResolveLinkTarget(true).FullName != source.FullName) // Link exists, but does not point to source. Replace.
{
destination.Delete();
destination.CreateAsSymbolicLink(source.FullName);
Log.Verbose($"Symbolic link at {destination.FullName} incorrectly links to {destination.ResolveLinkTarget(true).FullName}. Replacing with link to {source.FullName}");
}
else
Log.Verbose($"Symbolic link at {destination.FullName} to {source.FullName} is correct.");
}
else
Log.Error($"Missing Nvidia dll! DLSS may not work. {target} not found in {DxvkSettings.NvngxFolder}");
}
}

// 32-bit files for Directx9. Only needed for external programs.
var dxvkPath32 = Path.Combine(dxvkDirectory.FullName, DxvkSettings.NvapiFolderName, "x32");
var syswow64 = Path.Combine(Settings.Prefix.FullName, "drive_c", "windows", "syswow64");

if (Directory.Exists(dxvkPath32))
{
files = Directory.GetFiles(dxvkPath32);

foreach (string fileName in files)
{
File.Copy(fileName, Path.Combine(syswow64, Path.GetFileName(fileName)), true);
}
}
}

private void UninstallNvngx()
{
File.Delete(Path.Combine(GamePath.FullName, "game", "nvngx.dll"));
File.Delete(Path.Combine(GamePath.FullName, "game", "_nvngx.dll"));
}

private async Task DownloadTool(DirectoryInfo installDirectory, string downloadUrl)
Expand Down Expand Up @@ -201,7 +284,8 @@ private Process RunInPrefix(ProcessStartInfo psi, string workingDirectory, IDict

var wineEnvironmentVariables = new Dictionary<string, string>();
wineEnvironmentVariables.Add("WINEPREFIX", Settings.Prefix.FullName);
wineEnvironmentVariables.Add("WINEDLLOVERRIDES", $"msquic=,mscoree=n,b;d3d9,d3d11,d3d10core,dxgi={(wineD3D ? "b" : "n,b")}");
wineEnvironmentVariables.Add("WINEDLLOVERRIDES", $"msquic=,mscoree=n,b;d3d9,d3d11,d3d10core,dxgi={(wineD3D ? "b" : "n,b")};{Settings.ExtraWineDLLOverrides}");
Console.WriteLine("WINEDLLOVERRIDES=\"" + wineEnvironmentVariables["WINEDLLOVERRIDES"] + "\"");

if (!string.IsNullOrEmpty(Settings.DebugVars))
{
Expand Down
30 changes: 29 additions & 1 deletion src/XIVLauncher.Common.Unix/Compatibility/DxvkSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,30 @@ public class DxvkSettings

public string DownloadUrl { get; }

public string NvapiFolderName { get; }

public string NvapiDownloadUrl { get; }

public string NvngxFolder { get; }

public bool NvapiEnabled { get; }

public bool NvngxOverride { get; }

public Dictionary<string, string> Environment { get; }

public DxvkSettings(string folder, string url, string storageFolder, bool async, int maxFrameRate, bool dxvkHudEnabled, string dxvkHudString, bool mangoHudEnabled = false, bool mangoHudCustomIsFile = false, string customMangoHud = "", bool enabled = true)
public DxvkSettings(string folder, string url, string storageFolder, bool async, int maxFrameRate, bool dxvkHudEnabled, string dxvkHudString, bool mangoHudEnabled = false, bool mangoHudCustomIsFile = false, string customMangoHud = "", bool enabled = true, string nvapiFolder = "", string nvapiUrl = "", string nvngxFolder = "")
{
FolderName = folder;
DownloadUrl = url;
NvapiFolderName = nvapiFolder;
NvapiDownloadUrl = nvapiUrl;
NvngxFolder = nvngxFolder;
Enabled = enabled;
NvngxOverride = !string.IsNullOrEmpty(NvapiFolderName) && string.IsNullOrEmpty(NvngxFolder);

// Disable Nvapi if the NvapiFolderName is empty, if Dxvk is not enabled, or if the dxvk version is dxvk-1.x or dxvk-async-1.x
NvapiEnabled = (!string.IsNullOrEmpty(NvapiFolderName) && DxvkAllowsNvapi(FolderName) && Enabled);

var dxvkConfigPath = new DirectoryInfo(Path.Combine(storageFolder, "compatibilitytool", "dxvk"));
Environment = new Dictionary<string, string>
Expand Down Expand Up @@ -57,6 +74,11 @@ public DxvkSettings(string folder, string url, string storageFolder, bool async,
Environment.Add("MANGOHUD_CONFIG", customMangoHud);
}
}

if (NvapiEnabled)
{
Environment.Add("DXVK_ENABLE_NVAPI", "1");
}
}

public static bool DxvkHudStringIsValid(string customHud)
Expand All @@ -74,6 +96,12 @@ public static bool DxvkHudStringIsValid(string customHud)
return hudvars.All(hudvar => Regex.IsMatch(hudvar, ALLOWED_WORDS));
}

public static bool DxvkAllowsNvapi(string dxvkVersion)
{
var pattern = @"^dxvk-(async-)?1\.\d{1,2}(\.\d)?$";
return !Regex.IsMatch(dxvkVersion, pattern);
}

public static bool MangoHudIsInstalled()
{
var usrLib = Path.Combine("/", "usr", "lib", "mangohud", "libMangoHud.so"); // fedora uses this
Expand Down
20 changes: 19 additions & 1 deletion src/XIVLauncher.Common.Unix/Compatibility/WineSettings.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
using System.IO;
using System.Text.RegularExpressions;
using System.Linq;


namespace XIVLauncher.Common.Unix.Compatibility;

Expand All @@ -16,6 +19,8 @@ public class WineSettings

public string DownloadUrl;

public string ExtraWineDLLOverrides;

public string EsyncOn { get; private set; }

public string FsyncOn { get; private set; }
Expand All @@ -26,18 +31,31 @@ public class WineSettings

public DirectoryInfo Prefix { get; private set; }

public WineSettings(bool isManaged, string customBinPath, string managedFolder, string managedUrl, DirectoryInfo storageFolder, string debugVars, FileInfo logFile, DirectoryInfo prefix, bool? esyncOn, bool? fsyncOn)
public WineSettings(bool isManaged, string customBinPath, string managedFolder, string managedUrl, string extraDLLOverrides, DirectoryInfo storageFolder, string debugVars, FileInfo logFile, DirectoryInfo prefix, bool? esyncOn, bool? fsyncOn)
{
// storageFolder is the path to .xlcore folder. managedFolder is the foldername inside the tarball that will be downloaded from managedUrl.
IsManaged = isManaged;
FolderName = managedFolder;
DownloadUrl = managedUrl;
BinPath = (isManaged) ? Path.Combine(storageFolder.FullName, "compatibilitytool", "wine", managedFolder, "bin") : customBinPath;
ExtraWineDLLOverrides = WineDLLOverrideIsValid(extraDLLOverrides) ? extraDLLOverrides ?? "" : "";

this.EsyncOn = (esyncOn ?? false) ? "1" : "0";
this.FsyncOn = (fsyncOn ?? false) ? "1" : "0";
this.DebugVars = debugVars;
this.LogFile = logFile;
this.Prefix = prefix;
}

public static bool WineDLLOverrideIsValid(string dlls)
{
string[] invalid = { "msquic", "mscoree", "d3d9", "d3d11", "d3d10core", "dxgi" };
var format = @"^(?:(?:[a-zA-Z0-9_\-\.]+,?)+=(?:n,b|b,n|n|b|d|,|);?)+$";

if (string.IsNullOrEmpty(dlls)) return true;
if (invalid.Any(s => dlls.Contains(s))) return false;
if (Regex.IsMatch(dlls, format)) return true;

return false;
}
}