diff --git a/src/SharpEmu.CLI/Program.cs b/src/SharpEmu.CLI/Program.cs index 197e9f3..577cdbb 100644 --- a/src/SharpEmu.CLI/Program.cs +++ b/src/SharpEmu.CLI/Program.cs @@ -50,6 +50,23 @@ internal static partial class Program if (args.Length > 0 && args[0] == SharpEmu.Core.Diagnostics.WindowsCrashCapture.HelperArgument) return SharpEmu.Core.Diagnostics.WindowsCrashCapture.RunHelper(args); + if (args.Length > 0 && args[0] == ShaderPrecompiler.WorkerFlag) + { + int workerExitCode; + try + { + workerExitCode = ShaderPrecompiler.RunWorker(args[1..]); + } + catch (Exception exception) + { + Console.Error.WriteLine($"[SHADER CACHE][ERROR] The precompile worker failed: {exception.Message}"); + workerExitCode = 1; + } + + Console.Out.Flush(); + Environment.Exit(workerExitCode); + } + RenderDocCapture.ApplyVulkanLoaderEnvironment(); SharpEmu.Libs.VideoOut.RenderDocCapture.Initialize(); @@ -243,6 +260,8 @@ internal static partial class Program return childExitCode; } + var precompileOnly = args.Any(static argument => string.Equals(argument, "--precompile-only", StringComparison.OrdinalIgnoreCase)); + args = args.Where(static argument => !string.Equals(argument, "--precompile-only", StringComparison.OrdinalIgnoreCase)).ToArray(); if (!TryParseArguments( args, out var ebootPath, @@ -279,6 +298,11 @@ internal static partial class Program return 2; } + if (precompileOnly) + { + return RunShaderPrecompileOnly(ebootPath); + } + if (!TryGetDebugServerOptions(args, out var debugServerEnabled, out var debugServerOptions, out var debugServerError)) { Log.Error($"Invalid --debug-server endpoint: {debugServerError}"); @@ -1008,9 +1032,36 @@ internal static partial class Program return builder.ToString(); } + private static int RunShaderPrecompileOnly(string ebootPath) + { + var app0Root = Path.GetDirectoryName(ebootPath)!; + var parent = Path.GetDirectoryName(app0Root); + if (string.Equals(Path.GetFileName(app0Root), "decrypted", StringComparison.OrdinalIgnoreCase) && + !string.IsNullOrWhiteSpace(parent) && Directory.Exists(Path.Combine(parent, "sce_sys"))) + { + app0Root = parent; + } + + var paramPath = Path.Combine(app0Root, "sce_sys", "param.json"); + var (title, titleId, version) = File.Exists(paramPath) + ? SharpEmu.Core.Loader.Ps5ParamJsonReader.TryReadPs5Param(File.ReadAllBytes(paramPath)) + : (null, null, null); + if (string.IsNullOrWhiteSpace(titleId)) + { + Log.Error($"The game title id could not be read from {paramPath}."); + return 2; + } + + VideoOutExports.ConfigureApplicationInfo(title, titleId, version); + Environment.SetEnvironmentVariable( + SharpEmu.Libs.Gpu.ShaderCache.ShaderCacheSettings.EnvironmentVariable, + SharpEmu.Libs.Gpu.ShaderCache.ShaderCacheSettings.Format(true)); + return ShaderPrecompiler.Run(app0Root, full: true); + } + private static void PrintUsage() { - Log.Info("Usage: SharpEmu.CLI [--strict] [--trace-imports[=N]] [--cpu-engine=] [--console=] [--console-language=] [--log-level=] [--log-file[=]] [--window-mode=] [--resolution=] [--display=] [--refresh-rate=] [--scaling=] [--vsync=] [--hdr=] [--overlay=] [--overlay-mode=] [--overlay-corner=] [--debug-server[=host:port]] "); + Log.Info("Usage: SharpEmu.CLI [--strict] [--trace-imports[=N]] [--cpu-engine=] [--console=] [--console-language=] [--log-level=] [--log-file[=]] [--window-mode=] [--resolution=] [--display=] [--refresh-rate=] [--scaling=] [--vsync=] [--hdr=] [--shader-cache=] [--shader-learn=] [--precompile-only] [--overlay=] [--overlay-mode=] [--overlay-corner=] [--debug-server[=host:port]] "); Log.Info(@"Example: SharpEmu.CLI --cpu-engine=native --trace-imports=64 --log-level=debug --log-file ""E:\Games\...\eboot.bin"""); Log.Info("Debug server: --debug-server starts a live debug listener (default 127.0.0.1:5714); connect with SharpEmu.DebugClient."); } @@ -1224,6 +1275,32 @@ internal static partial class Program hdrModeOverride = hdrMode; continue; } + if (TrySplitOption(argument, "--shader-learn", out var shaderLearnText)) + { + if (!SharpEmu.Libs.Gpu.ShaderCache.ShaderCacheSettings.TryParse(shaderLearnText, out var shaderLearnEnabled)) + { + ebootPath = string.Empty; + runtimeOptions = default; + return false; + } + Environment.SetEnvironmentVariable( + SharpEmu.Libs.Gpu.ShaderCache.ShaderCacheSettings.LearnEnvironmentVariable, + SharpEmu.Libs.Gpu.ShaderCache.ShaderCacheSettings.Format(shaderLearnEnabled)); + continue; + } + if (TrySplitOption(argument, "--shader-cache", out var shaderCacheText)) + { + if (!SharpEmu.Libs.Gpu.ShaderCache.ShaderCacheSettings.TryParse(shaderCacheText, out var shaderCacheEnabled)) + { + ebootPath = string.Empty; + runtimeOptions = default; + return false; + } + Environment.SetEnvironmentVariable( + SharpEmu.Libs.Gpu.ShaderCache.ShaderCacheSettings.EnvironmentVariable, + SharpEmu.Libs.Gpu.ShaderCache.ShaderCacheSettings.Format(shaderCacheEnabled)); + continue; + } if (string.Equals(argument, "--strict", StringComparison.OrdinalIgnoreCase)) { strictDynlibResolution = true;