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 @@
-
-
-
-
-