From 918ec1bde3b84650e0ad18e0fe712381dc1276f9 Mon Sep 17 00:00:00 2001 From: LotP1 <68976644+LotP1@users.noreply.github.com> Date: Fri, 10 Jan 2025 04:43:18 +0100 Subject: [PATCH] cores rework (#505) This PR changes the core count to be defined in the device instead of being a const value. This is mostly a change for future features I want to implement and should not impact any functionality. The console will now log the range of cores requested from the application, and for now, if the requested range is not 0 to 2 (the 3 cores used for application emulation), it will give an error message which tells the user to contact me on discord. I'm doing this because I'm interested in finding applications/games that don't use 3 cores and the error will be removed in the future once I've gotten enough data. --- src/Ryujinx.HLE/HOS/Horizon.cs | 2 +- src/Ryujinx.HLE/HOS/Kernel/KernelContext.cs | 1 + src/Ryujinx.HLE/HOS/Kernel/KernelStatic.cs | 2 +- src/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs | 2 +- .../HOS/Kernel/Process/KProcessCapabilities.cs | 17 +++++++++++------ .../HOS/Kernel/SupervisorCall/Syscall.cs | 2 +- .../HOS/Kernel/Threading/KScheduler.cs | 18 +++++++++++++----- src/Ryujinx.HLE/HOS/Services/ServerBase.cs | 6 +++--- src/Ryujinx.HLE/Switch.cs | 2 ++ src/Ryujinx/Headless/HeadlessRyujinx.Init.cs | 2 +- 10 files changed, 35 insertions(+), 19 deletions(-) diff --git a/src/Ryujinx.HLE/HOS/Horizon.cs b/src/Ryujinx.HLE/HOS/Horizon.cs index f9c5ddecf..627b649df 100644 --- a/src/Ryujinx.HLE/HOS/Horizon.cs +++ b/src/Ryujinx.HLE/HOS/Horizon.cs @@ -284,7 +284,7 @@ namespace Ryujinx.HLE.HOS ProcessCreationInfo creationInfo = new("Service", 1, 0, 0x8000000, 1, Flags, 0, 0); uint[] defaultCapabilities = { - 0x030363F7, + (((uint)KScheduler.CpuCoresCount - 1) << 24) + (((uint)KScheduler.CpuCoresCount - 1) << 16) + 0x63F7u, 0x1FFFFFCF, 0x207FFFEF, 0x47E0060F, diff --git a/src/Ryujinx.HLE/HOS/Kernel/KernelContext.cs b/src/Ryujinx.HLE/HOS/Kernel/KernelContext.cs index 89d788c54..7e2e9cacc 100644 --- a/src/Ryujinx.HLE/HOS/Kernel/KernelContext.cs +++ b/src/Ryujinx.HLE/HOS/Kernel/KernelContext.cs @@ -63,6 +63,7 @@ namespace Ryujinx.HLE.HOS.Kernel TickSource = tickSource; Device = device; Memory = memory; + KScheduler.CpuCoresCount = device.CpuCoresCount; Running = true; diff --git a/src/Ryujinx.HLE/HOS/Kernel/KernelStatic.cs b/src/Ryujinx.HLE/HOS/Kernel/KernelStatic.cs index f5ecba752..e05fc8397 100644 --- a/src/Ryujinx.HLE/HOS/Kernel/KernelStatic.cs +++ b/src/Ryujinx.HLE/HOS/Kernel/KernelStatic.cs @@ -37,7 +37,7 @@ namespace Ryujinx.HLE.HOS.Kernel return result; } - process.DefaultCpuCore = 3; + process.DefaultCpuCore = KScheduler.CpuCoresCount - 1; context.Processes.TryAdd(process.Pid, process); 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..5c9f4f100 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 (discord.gg/ryujinx)!"); + 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/SupervisorCall/Syscall.cs b/src/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs index 2f487243d..1b6433af6 100644 --- a/src/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs +++ b/src/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs @@ -2683,7 +2683,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return KernelResult.InvalidCombination; } - if ((uint)preferredCore > 3) + if ((uint)preferredCore > KScheduler.CpuCoresCount - 1) { if ((preferredCore | 2) != -1) { 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.HLE/HOS/Services/ServerBase.cs b/src/Ryujinx.HLE/HOS/Services/ServerBase.cs index f67699b90..40329aa36 100644 --- a/src/Ryujinx.HLE/HOS/Services/ServerBase.cs +++ b/src/Ryujinx.HLE/HOS/Services/ServerBase.cs @@ -24,14 +24,14 @@ namespace Ryujinx.HLE.HOS.Services // not large enough. private const int PointerBufferSize = 0x8000; - private readonly static uint[] _defaultCapabilities = { - 0x030363F7, + private static uint[] _defaultCapabilities => [ + (((uint)KScheduler.CpuCoresCount - 1) << 24) + (((uint)KScheduler.CpuCoresCount - 1) << 16) + 0x63F7u, 0x1FFFFFCF, 0x207FFFEF, 0x47E0060F, 0x0048BFFF, 0x01007FFF, - }; + ]; // The amount of time Dispose() will wait to Join() the thread executing the ServerLoop() private static readonly TimeSpan _threadJoinTimeout = TimeSpan.FromSeconds(3); diff --git a/src/Ryujinx.HLE/Switch.cs b/src/Ryujinx.HLE/Switch.cs index 25e65354f..e15fab03a 100644 --- a/src/Ryujinx.HLE/Switch.cs +++ b/src/Ryujinx.HLE/Switch.cs @@ -32,6 +32,8 @@ namespace Ryujinx.HLE public TamperMachine TamperMachine { get; } public IHostUIHandler UIHandler { get; } + public int CpuCoresCount = 4; //Switch 1 has 4 cores + public VSyncMode VSyncMode { get; set; } = VSyncMode.Switch; public bool CustomVSyncIntervalEnabled { get; set; } = false; public int CustomVSyncInterval { get; set; } diff --git a/src/Ryujinx/Headless/HeadlessRyujinx.Init.cs b/src/Ryujinx/Headless/HeadlessRyujinx.Init.cs index 19d2fb94e..7d75ac7c1 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;