From 73406d1f3aae4bb220a1c53bd9975dd3cded0a4e Mon Sep 17 00:00:00 2001 From: Aaron Robinson Date: Wed, 19 Nov 2025 21:46:10 -0600 Subject: [PATCH] Move Tipc commands and fix remaining warnings --- .gitignore | 3 + Directory.Build.props | 3 - Directory.Build.targets | 6 ++ .../Ryujinx.BuildValidationTasks.csproj | 2 + .../Formatters/DynamicObjectFormatter.cs | 2 + .../IpcCommandGenerator.cs | 54 +++++++------ .../ServiceNotImplementedException.cs | 2 +- src/Ryujinx.HLE/HOS/Services/IpcService.cs | 81 +++++++------------ .../HOS/Services/Nv/INvDrvServices.cs | 33 ++++---- src/Ryujinx/Ryujinx.csproj | 13 --- src/Ryujinx/TrimmerRoots.xml | 5 -- 11 files changed, 86 insertions(+), 118 deletions(-) create mode 100644 Directory.Build.targets delete mode 100644 src/Ryujinx/TrimmerRoots.xml diff --git a/.gitignore b/.gitignore index 6f887e638..17df1588e 100644 --- a/.gitignore +++ b/.gitignore @@ -185,3 +185,6 @@ PublishProfiles/ # Ignore distribution build files distribution/macos/temp/ distribution/macos/output/ + +# MSBuild logs +*.binlog diff --git a/Directory.Build.props b/Directory.Build.props index d20dcd0eb..a4df830a3 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -2,8 +2,5 @@ net10.0 preview - true - true - true diff --git a/Directory.Build.targets b/Directory.Build.targets new file mode 100644 index 000000000..9ef091149 --- /dev/null +++ b/Directory.Build.targets @@ -0,0 +1,6 @@ + + + true + true + + diff --git a/src/Ryujinx.BuildValidationTasks/Ryujinx.BuildValidationTasks.csproj b/src/Ryujinx.BuildValidationTasks/Ryujinx.BuildValidationTasks.csproj index 31181bc55..eff20a215 100644 --- a/src/Ryujinx.BuildValidationTasks/Ryujinx.BuildValidationTasks.csproj +++ b/src/Ryujinx.BuildValidationTasks/Ryujinx.BuildValidationTasks.csproj @@ -2,6 +2,8 @@ Exe + false + false diff --git a/src/Ryujinx.Common/Logging/Formatters/DynamicObjectFormatter.cs b/src/Ryujinx.Common/Logging/Formatters/DynamicObjectFormatter.cs index a7b4da40f..7533bf6fb 100644 --- a/src/Ryujinx.Common/Logging/Formatters/DynamicObjectFormatter.cs +++ b/src/Ryujinx.Common/Logging/Formatters/DynamicObjectFormatter.cs @@ -37,7 +37,9 @@ namespace Ryujinx.Common.Logging.Formatters return; } +#pragma warning disable IL2075 // GetProperties is *probably* fine here, it only really matters what exists anyway PropertyInfo[] props = dynamicObject.GetType().GetProperties(); +#pragma warning restore IL2075 sb.Append('{'); diff --git a/src/Ryujinx.HLE.Generators/IpcCommandGenerator.cs b/src/Ryujinx.HLE.Generators/IpcCommandGenerator.cs index f96195f84..47918c5cf 100644 --- a/src/Ryujinx.HLE.Generators/IpcCommandGenerator.cs +++ b/src/Ryujinx.HLE.Generators/IpcCommandGenerator.cs @@ -83,35 +83,41 @@ namespace Ryujinx.HLE.Generators generator.EnterScope($"namespace {data.Namespace}"); generator.EnterScope($"partial class {data.TypeName}"); - generator.EnterScope("protected override RC InvokeCmifMethod(int id, ServiceCtx context)"); - generator.EnterScope("switch (id)"); - foreach (var command in data.CmifCommands) - { - generator.AppendLine($"case {string.Join(" or ", command.CommandIds)}:"); - generator.IncreaseIndentation(); - generator.AppendLine($"LogInvoke(\"{command.MethodName}\");"); - generator.AppendLine($"return (RC){command.MethodName}(context);"); - generator.DecreaseIndentation(); - } - generator.AppendLine("default: return base.InvokeCmifMethod(id, context);"); - generator.LeaveScope(); - generator.LeaveScope(); - - generator.EnterScope("public override int CmifCommandIdByMethodName(string name)"); - generator.EnterScope("return name switch"); - foreach (var command in data.CmifCommands) - { - // just return the first command with this name - generator.AppendLine($"\"{command.MethodName}\" => {command.CommandIds[0]},"); - } - generator.AppendLine("_ => base.CmifCommandIdByMethodName(name),"); - generator.LeaveScope(";"); - generator.LeaveScope(); + GenerateCommandMethod("Cmif", data.CmifCommands); + GenerateCommandMethod("Tipc", data.TipcCommands); generator.LeaveScope(); generator.LeaveScope(); ctx.AddSource($"{data.Namespace}.{data.TypeName}.g.cs", generator.ToString()); + + void GenerateCommandMethod(string commandType, ImmutableArray commands) + { + generator.EnterScope($"protected override RC Invoke{commandType}Method(int id, ServiceCtx context)"); + generator.EnterScope("switch (id)"); + foreach (var command in commands) + { + generator.AppendLine($"case {string.Join(" or ", command.CommandIds)}:"); + generator.IncreaseIndentation(); + generator.AppendLine($"LogInvoke(\"{command.MethodName}\");"); + generator.AppendLine($"return (RC){command.MethodName}(context);"); + generator.DecreaseIndentation(); + } + generator.AppendLine($"default: return base.Invoke{commandType}Method(id, context);"); + generator.LeaveScope(); + generator.LeaveScope(); + + generator.EnterScope($"public override int {commandType}CommandIdByMethodName(string name)"); + generator.EnterScope("return name switch"); + foreach (var command in commands) + { + // just return the first command with this name + generator.AppendLine($"\"{command.MethodName}\" => {command.CommandIds[0]},"); + } + generator.AppendLine($"_ => base.{commandType}CommandIdByMethodName(name),"); + generator.LeaveScope(";"); + generator.LeaveScope(); + } }); } } diff --git a/src/Ryujinx.HLE/Exceptions/ServiceNotImplementedException.cs b/src/Ryujinx.HLE/Exceptions/ServiceNotImplementedException.cs index f1d453172..038eed023 100644 --- a/src/Ryujinx.HLE/Exceptions/ServiceNotImplementedException.cs +++ b/src/Ryujinx.HLE/Exceptions/ServiceNotImplementedException.cs @@ -49,7 +49,7 @@ namespace Ryujinx.HLE.Exceptions StringBuilder sb = new(); var commandId = Request.Type > IpcMessageType.TipcCloseSession - ? -1 // TODO: tipc name + ? Service.TipcCommandIdByMethodName(MethodName) : Service.CmifCommandIdByMethodName(MethodName); sb.AppendLine($"Service Command: {Service.GetType().FullName}: {commandId} ({MethodName})"); diff --git a/src/Ryujinx.HLE/HOS/Services/IpcService.cs b/src/Ryujinx.HLE/HOS/Services/IpcService.cs index 31420f485..780b68f79 100644 --- a/src/Ryujinx.HLE/HOS/Services/IpcService.cs +++ b/src/Ryujinx.HLE/HOS/Services/IpcService.cs @@ -11,10 +11,8 @@ using System.Reflection; namespace Ryujinx.HLE.HOS.Services { - abstract partial class IpcService + abstract class IpcService { - public IReadOnlyDictionary TipcCommands { get; } - public ServerBase Server { get; private set; } private IpcService _parent; @@ -24,25 +22,6 @@ namespace Ryujinx.HLE.HOS.Services public IpcService(ServerBase server = null) { - if (true) - { - var sw = Stopwatch.StartNew(); - - TipcCommands = GetType() - .GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public) - .SelectMany(methodInfo => methodInfo.GetCustomAttributes() - .Select(command => (command.Id, methodInfo))) - .ToDictionary(command => command.Id, command => command.methodInfo); - - sw.Stop(); - - Logger.Debug?.Print( - LogClass.Emulation, - $"{TipcCommands.Count} Tipc commands loaded in {sw.ElapsedTicks} ticks ({Stopwatch.Frequency} tps).", - GetType().AsPrettyString() - ); - } - Server = server; _parent = this; @@ -85,11 +64,31 @@ namespace Ryujinx.HLE.HOS.Services return ResultCode.Success; } + public virtual int CmifCommandIdByMethodName(string name) => -1; + + protected virtual ResultCode InvokeTipcMethod(int id, ServiceCtx context) + { + if (!context.Device.Configuration.IgnoreMissingServices) + { + string dbgMessage = $"{this.GetType().FullName}: {id}"; + + throw new ServiceNotImplementedException(this, context, dbgMessage); + } + + string serviceName = (this is not DummyService dummyService) + ? this.GetType().FullName + : dummyService.ServiceName; + + Logger.Warning?.Print(LogClass.KernelIpc, $"Missing service {serviceName}: {id} ignored"); + + return ResultCode.Success; + } + + public virtual int TipcCommandIdByMethodName(string name) => -1; + protected void LogInvoke(string name) => Logger.Trace?.Print(LogClass.KernelIpc, $"{this.GetType().Name}: {name}"); - public virtual int CmifCommandIdByMethodName(string name) => -1; - public void CallCmifMethod(ServiceCtx context) { IpcService service = this; @@ -166,39 +165,13 @@ namespace Ryujinx.HLE.HOS.Services { int commandId = (int)context.Request.Type - 0x10; - bool serviceExists = TipcCommands.TryGetValue(commandId, out MethodInfo processRequest); + context.ResponseData.BaseStream.Seek(0x4, SeekOrigin.Begin); - if (context.Device.Configuration.IgnoreMissingServices || serviceExists) - { - ResultCode result = ResultCode.Success; + ResultCode result = InvokeTipcMethod(commandId, context); - context.ResponseData.BaseStream.Seek(0x4, SeekOrigin.Begin); + context.ResponseData.BaseStream.Seek(0, SeekOrigin.Begin); - if (serviceExists) - { - Logger.Debug?.Print(LogClass.KernelIpc, $"{GetType().Name}: {processRequest.Name}"); - - result = (ResultCode)processRequest.Invoke(this, [context]); - } - else - { - string serviceName; - - serviceName = (this is not DummyService dummyService) ? GetType().FullName : dummyService.ServiceName; - - Logger.Warning?.Print(LogClass.KernelIpc, $"Missing service {serviceName}: {commandId} ignored"); - } - - context.ResponseData.BaseStream.Seek(0, SeekOrigin.Begin); - - context.ResponseData.Write((uint)result); - } - else - { - string dbgMessage = $"{GetType().FullName}: {commandId}"; - - throw new ServiceNotImplementedException(this, context, dbgMessage); - } + context.ResponseData.Write((uint)result); } protected void MakeObject(ServiceCtx context, IpcService obj) diff --git a/src/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs b/src/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs index d7e420383..50e041766 100644 --- a/src/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs +++ b/src/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs @@ -32,20 +32,20 @@ namespace Ryujinx.HLE.HOS.Services.Nv "/dev/nvhost-prof-gpu" ]; - private static readonly Dictionary _deviceFileRegistry = new() + private static readonly Dictionary> _deviceFileRegistry = new() { - { "/dev/nvmap", typeof(NvMapDeviceFile) }, - { "/dev/nvhost-ctrl", typeof(NvHostCtrlDeviceFile) }, - { "/dev/nvhost-ctrl-gpu", typeof(NvHostCtrlGpuDeviceFile) }, - { "/dev/nvhost-as-gpu", typeof(NvHostAsGpuDeviceFile) }, - { "/dev/nvhost-gpu", typeof(NvHostGpuDeviceFile) }, - //{ "/dev/nvhost-msenc", typeof(NvHostChannelDeviceFile) }, - { "/dev/nvhost-nvdec", typeof(NvHostChannelDeviceFile) }, - //{ "/dev/nvhost-nvjpg", typeof(NvHostChannelDeviceFile) }, - { "/dev/nvhost-vic", typeof(NvHostChannelDeviceFile) }, - //{ "/dev/nvhost-display", typeof(NvHostChannelDeviceFile) }, - { "/dev/nvhost-dbg-gpu", typeof(NvHostDbgGpuDeviceFile) }, - { "/dev/nvhost-prof-gpu", typeof(NvHostProfGpuDeviceFile) }, + { "/dev/nvmap", (ctx, mem, owner) => new NvMapDeviceFile(ctx, mem, owner) }, + { "/dev/nvhost-ctrl", (ctx, mem, owner) => new NvHostCtrlDeviceFile(ctx, mem, owner) }, + { "/dev/nvhost-ctrl-gpu", (ctx, mem, owner) => new NvHostCtrlGpuDeviceFile(ctx, mem, owner) }, + { "/dev/nvhost-as-gpu", (ctx, mem, owner) => new NvHostAsGpuDeviceFile(ctx, mem, owner) }, + { "/dev/nvhost-gpu", (ctx, mem, owner) => new NvHostGpuDeviceFile(ctx, mem, owner) }, + //{ "/dev/nvhost-msenc", (ctx, mem, owner) => new NvHostChannelDeviceFile(ctx, mem, owner) }, + { "/dev/nvhost-nvdec", (ctx, mem, owner) => new NvHostChannelDeviceFile(ctx, mem, owner) }, + //{ "/dev/nvhost-nvjpg", (ctx, mem, owner) => new NvHostChannelDeviceFile(ctx, mem, owner) }, + { "/dev/nvhost-vic", (ctx, mem, owner) => new NvHostChannelDeviceFile(ctx, mem, owner) }, + //{ "/dev/nvhost-display", (ctx, mem, owner) => new NvHostChannelDeviceFile(ctx, mem, owner) }, + { "/dev/nvhost-dbg-gpu", (ctx, mem, owner) => new NvHostDbgGpuDeviceFile(ctx, mem, owner) }, + { "/dev/nvhost-prof-gpu", (ctx, mem, owner) => new NvHostProfGpuDeviceFile(ctx, mem, owner) }, }; private static readonly ArrayPool _byteArrayPool = ArrayPool.Create(); @@ -78,12 +78,9 @@ namespace Ryujinx.HLE.HOS.Services.Nv return NvResult.NotSupported; } - if (_deviceFileRegistry.TryGetValue(path, out Type deviceFileClass)) + if (_deviceFileRegistry.TryGetValue(path, out Func deviceFileFactory)) { - ConstructorInfo constructor = deviceFileClass.GetConstructor([typeof(ServiceCtx), typeof(IVirtualMemoryManager), typeof(ulong) - ]); - - NvDeviceFile deviceFile = (NvDeviceFile)constructor.Invoke([context, _clientMemory, _owner]); + NvDeviceFile deviceFile = deviceFileFactory(context, _clientMemory, _owner); deviceFile.Path = path; diff --git a/src/Ryujinx/Ryujinx.csproj b/src/Ryujinx/Ryujinx.csproj index fd17db406..b67bb054b 100644 --- a/src/Ryujinx/Ryujinx.csproj +++ b/src/Ryujinx/Ryujinx.csproj @@ -28,21 +28,12 @@ true - - true - false - - - - - true - @@ -179,8 +170,4 @@ - - - - diff --git a/src/Ryujinx/TrimmerRoots.xml b/src/Ryujinx/TrimmerRoots.xml deleted file mode 100644 index 1db3915e7..000000000 --- a/src/Ryujinx/TrimmerRoots.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - -