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,