From 644287faa6eebd0df4f31131bd15904dc25d7a9c Mon Sep 17 00:00:00 2001 From: LotP1 Date: Thu, 9 Jan 2025 01:53:01 +0100 Subject: [PATCH] Initial implementation --- src/Ryujinx.HLE/HLEConfiguration.cs | 7 +++++++ src/Ryujinx.HLE/HOS/Horizon.cs | 3 ++- src/Ryujinx.HLE/HOS/Kernel/KernelContext.cs | 4 +++- src/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs | 2 +- .../HOS/Kernel/Process/KProcessCapabilities.cs | 17 +++++++++++------ .../HOS/Kernel/Threading/KScheduler.cs | 18 +++++++++++++----- src/Ryujinx/AppHost.cs | 2 ++ src/Ryujinx/Headless/HeadlessRyujinx.Init.cs | 5 ++++- 8 files changed, 43 insertions(+), 15 deletions(-) diff --git a/src/Ryujinx.HLE/HLEConfiguration.cs b/src/Ryujinx.HLE/HLEConfiguration.cs index 8ac76508f..8e6ad570c 100644 --- a/src/Ryujinx.HLE/HLEConfiguration.cs +++ b/src/Ryujinx.HLE/HLEConfiguration.cs @@ -103,6 +103,11 @@ namespace Ryujinx.HLE /// internal readonly bool EnablePtc; + /// + /// The amount of cpu threads that should be used for emulation. + /// + internal readonly int CpuCoresCount; + /// /// Control if the guest application should be told that there is a Internet connection available. /// @@ -208,6 +213,7 @@ namespace Ryujinx.HLE VSyncMode vSyncMode, bool enableDockedMode, bool enablePtc, + int cpuCoresCount, bool enableInternetAccess, IntegrityCheckLevel fsIntegrityCheckLevel, int fsGlobalAccessLogMode, @@ -241,6 +247,7 @@ namespace Ryujinx.HLE CustomVSyncInterval = customVSyncInterval; EnableDockedMode = enableDockedMode; EnablePtc = enablePtc; + CpuCoresCount = cpuCoresCount; EnableInternetAccess = enableInternetAccess; FsIntegrityCheckLevel = fsIntegrityCheckLevel; FsGlobalAccessLogMode = fsGlobalAccessLogMode; diff --git a/src/Ryujinx.HLE/HOS/Horizon.cs b/src/Ryujinx.HLE/HOS/Horizon.cs index f9c5ddecf..b56e5cc1d 100644 --- a/src/Ryujinx.HLE/HOS/Horizon.cs +++ b/src/Ryujinx.HLE/HOS/Horizon.cs @@ -122,7 +122,8 @@ namespace Ryujinx.HLE.HOS device, device.Memory, device.Configuration.MemoryConfiguration.ToKernelMemorySize(), - device.Configuration.MemoryConfiguration.ToKernelMemoryArrange()); + device.Configuration.MemoryConfiguration.ToKernelMemoryArrange(), + device.Configuration.CpuCoresCount); Device = device; diff --git a/src/Ryujinx.HLE/HOS/Kernel/KernelContext.cs b/src/Ryujinx.HLE/HOS/Kernel/KernelContext.cs index 89d788c54..9b1dd0c3f 100644 --- a/src/Ryujinx.HLE/HOS/Kernel/KernelContext.cs +++ b/src/Ryujinx.HLE/HOS/Kernel/KernelContext.cs @@ -58,11 +58,13 @@ namespace Ryujinx.HLE.HOS.Kernel Switch device, MemoryBlock memory, MemorySize memorySize, - MemoryArrange memoryArrange) + MemoryArrange memoryArrange, + int cpuCoresCount) { TickSource = tickSource; Device = device; Memory = memory; + KScheduler.CpuCoresCount = cpuCoresCount; Running = true; diff --git a/src/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs b/src/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs index b4aa5ca5c..82c3d2e70 100644 --- a/src/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs +++ b/src/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs @@ -277,7 +277,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process return result; } - result = Capabilities.InitializeForUser(capabilities, MemoryManager); + result = Capabilities.InitializeForUser(capabilities, MemoryManager, IsApplication); if (result != Result.Success) { diff --git a/src/Ryujinx.HLE/HOS/Kernel/Process/KProcessCapabilities.cs b/src/Ryujinx.HLE/HOS/Kernel/Process/KProcessCapabilities.cs index ebab67bb8..63a21e930 100644 --- a/src/Ryujinx.HLE/HOS/Kernel/Process/KProcessCapabilities.cs +++ b/src/Ryujinx.HLE/HOS/Kernel/Process/KProcessCapabilities.cs @@ -35,15 +35,15 @@ namespace Ryujinx.HLE.HOS.Kernel.Process DebuggingFlags &= ~3u; KernelReleaseVersion = KProcess.KernelVersionPacked; - return Parse(capabilities, memoryManager); + return Parse(capabilities, memoryManager, false); } - public Result InitializeForUser(ReadOnlySpan capabilities, KPageTableBase memoryManager) + public Result InitializeForUser(ReadOnlySpan capabilities, KPageTableBase memoryManager, bool isApplication) { - return Parse(capabilities, memoryManager); + return Parse(capabilities, memoryManager, isApplication); } - private Result Parse(ReadOnlySpan capabilities, KPageTableBase memoryManager) + private Result Parse(ReadOnlySpan capabilities, KPageTableBase memoryManager, bool isApplication) { int mask0 = 0; int mask1 = 0; @@ -54,7 +54,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process if (cap.GetCapabilityType() != CapabilityType.MapRange) { - Result result = ParseCapability(cap, ref mask0, ref mask1, memoryManager); + Result result = ParseCapability(cap, ref mask0, ref mask1, memoryManager, isApplication); if (result != Result.Success) { @@ -120,7 +120,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process return Result.Success; } - private Result ParseCapability(uint cap, ref int mask0, ref int mask1, KPageTableBase memoryManager) + private Result ParseCapability(uint cap, ref int mask0, ref int mask1, KPageTableBase memoryManager, bool isApplication) { CapabilityType code = cap.GetCapabilityType(); @@ -176,6 +176,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Process AllowedCpuCoresMask = GetMaskFromMinMax(lowestCpuCore, highestCpuCore); AllowedThreadPriosMask = GetMaskFromMinMax(lowestThreadPrio, highestThreadPrio); + if (isApplication && lowestCpuCore == 0 && highestCpuCore != 2) + Ryujinx.Common.Logging.Logger.Error?.Print(Ryujinx.Common.Logging.LogClass.Application, $"Application requested cores with index range {lowestCpuCore} to {highestCpuCore}! Report this to @LotP on the Ryujinx/Ryubing discord server!"); + else if (isApplication) + Ryujinx.Common.Logging.Logger.Info?.Print(Ryujinx.Common.Logging.LogClass.Application, $"Application requested cores with index range {lowestCpuCore} to {highestCpuCore}"); + break; } diff --git a/src/Ryujinx.HLE/HOS/Kernel/Threading/KScheduler.cs b/src/Ryujinx.HLE/HOS/Kernel/Threading/KScheduler.cs index 8ef77902c..19f1b8be0 100644 --- a/src/Ryujinx.HLE/HOS/Kernel/Threading/KScheduler.cs +++ b/src/Ryujinx.HLE/HOS/Kernel/Threading/KScheduler.cs @@ -9,13 +9,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading partial class KScheduler : IDisposable { public const int PrioritiesCount = 64; - public const int CpuCoresCount = 4; + public static int CpuCoresCount; private const int RoundRobinTimeQuantumMs = 10; - private static readonly int[] _preemptionPriorities = { 59, 59, 59, 63 }; - - private static readonly int[] _srcCoresHighestPrioThreads = new int[CpuCoresCount]; + private static int[] _srcCoresHighestPrioThreads; private readonly KernelContext _context; private readonly int _coreId; @@ -47,6 +45,16 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading _coreId = coreId; _currentThread = null; + + if (_srcCoresHighestPrioThreads == null) + { + _srcCoresHighestPrioThreads = new int[CpuCoresCount]; + } + } + + private static int PreemptionPriorities(int index) + { + return index == CpuCoresCount - 1 ? 63 : 59; } public static ulong SelectThreads(KernelContext context) @@ -437,7 +445,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading for (int core = 0; core < CpuCoresCount; core++) { - RotateScheduledQueue(context, core, _preemptionPriorities[core]); + RotateScheduledQueue(context, core, PreemptionPriorities(core)); } context.CriticalSection.Leave(); diff --git a/src/Ryujinx/AppHost.cs b/src/Ryujinx/AppHost.cs index a35a79e86..e3bb3b338 100644 --- a/src/Ryujinx/AppHost.cs +++ b/src/Ryujinx/AppHost.cs @@ -918,6 +918,7 @@ namespace Ryujinx.Ava // Initialize Configuration. var memoryConfiguration = ConfigurationState.Instance.System.DramSize.Value; + int cpuCoresCount = 4; //Switch 1 has 4 cores Device = new Switch(new HLEConfiguration( VirtualFileSystem, @@ -934,6 +935,7 @@ namespace Ryujinx.Ava ConfigurationState.Instance.Graphics.VSyncMode, ConfigurationState.Instance.System.EnableDockedMode, ConfigurationState.Instance.System.EnablePtc, + cpuCoresCount, ConfigurationState.Instance.System.EnableInternetAccess, ConfigurationState.Instance.System.EnableFsIntegrityChecks ? IntegrityCheckLevel.ErrorOnInvalid : IntegrityCheckLevel.None, ConfigurationState.Instance.System.FsGlobalAccessLogMode, diff --git a/src/Ryujinx/Headless/HeadlessRyujinx.Init.cs b/src/Ryujinx/Headless/HeadlessRyujinx.Init.cs index 19d2fb94e..5c6a518a8 100644 --- a/src/Ryujinx/Headless/HeadlessRyujinx.Init.cs +++ b/src/Ryujinx/Headless/HeadlessRyujinx.Init.cs @@ -1,4 +1,4 @@ -using DiscordRPC; +using DiscordRPC; using LibHac.Tools.FsSystem; using Ryujinx.Audio.Backends.SDL2; using Ryujinx.Ava; @@ -329,6 +329,8 @@ namespace Ryujinx.Headless renderer = new ThreadedRenderer(renderer); } + int cpuCoresCount = 4; //Switch 1 has 4 cores + HLEConfiguration configuration = new(_virtualFileSystem, _libHacHorizonManager, _contentManager, @@ -343,6 +345,7 @@ namespace Ryujinx.Headless options.VSyncMode, !options.DisableDockedMode, !options.DisablePTC, + cpuCoresCount, options.EnableInternetAccess, !options.DisableFsIntegrityChecks ? IntegrityCheckLevel.ErrorOnInvalid : IntegrityCheckLevel.None, options.FsGlobalAccessLogMode,