Ryujinx/Ryujinx.Core/OsHle/Horizon.cs

187 lines
4.9 KiB
C#
Raw Normal View History

using Ryujinx.Core.Loaders.Executables;
using Ryujinx.Core.OsHle.Handles;
using System;
2018-02-05 00:08:20 +01:00
using System.Collections.Concurrent;
using System.IO;
namespace Ryujinx.Core.OsHle
2018-02-05 00:08:20 +01:00
{
public class Horizon : IDisposable
2018-02-05 00:08:20 +01:00
{
internal const int HidSize = 0x40000;
internal const int FontSize = 0x50;
private KProcessScheduler Scheduler;
2018-02-05 00:08:20 +01:00
private ConcurrentDictionary<int, Process> Processes;
internal HSharedMem HidSharedMem { get; private set; }
internal HSharedMem FontSharedMem { get; private set; }
internal KEvent VsyncEvent { get; private set; }
2018-02-05 00:08:20 +01:00
private Switch Ns;
public Horizon(Switch Ns)
{
this.Ns = Ns;
Scheduler = new KProcessScheduler();
2018-02-05 00:08:20 +01:00
Processes = new ConcurrentDictionary<int, Process>();
HidSharedMem = new HSharedMem();
FontSharedMem = new HSharedMem();
VsyncEvent = new KEvent();
2018-02-05 00:08:20 +01:00
}
public void LoadCart(string ExeFsDir, string RomFsFile = null)
{
if (RomFsFile != null)
{
Ns.VFs.LoadRomFs(RomFsFile);
}
Process MainProcess = MakeProcess();
2018-02-05 00:08:20 +01:00
void LoadNso(string FileName)
{
foreach (string File in Directory.GetFiles(ExeFsDir, FileName))
{
if (Path.GetExtension(File) != string.Empty)
{
continue;
}
Logging.Info(LogClass.Loader, $"Loading {Path.GetFileNameWithoutExtension(File)}...");
2018-02-05 00:08:20 +01:00
using (FileStream Input = new FileStream(File, FileMode.Open))
{
Nso Program = new Nso(Input);
MainProcess.LoadProgram(Program);
}
}
}
LoadNso("rtld");
MainProcess.SetEmptyArgs();
LoadNso("main");
LoadNso("subsdk*");
LoadNso("sdk");
MainProcess.Run();
}
public void LoadProgram(string FileName)
2018-02-05 00:08:20 +01:00
{
bool IsNro = Path.GetExtension(FileName).ToLower() == ".nro";
Process MainProcess = MakeProcess();
2018-02-05 00:08:20 +01:00
using (FileStream Input = new FileStream(FileName, FileMode.Open))
{
MainProcess.LoadProgram(IsNro
? (IExecutable)new Nro(Input)
: (IExecutable)new Nso(Input));
2018-02-05 00:08:20 +01:00
}
MainProcess.SetEmptyArgs();
MainProcess.Run(IsNro);
2018-02-05 00:08:20 +01:00
}
public void SignalVsync() => VsyncEvent.WaitEvent.Set();
private Process MakeProcess()
2018-02-05 00:08:20 +01:00
{
Process Process;
lock (Processes)
2018-02-05 00:08:20 +01:00
{
int ProcessId = 0;
while (Processes.ContainsKey(ProcessId))
{
ProcessId++;
}
Process = new Process(Ns, Scheduler, ProcessId);
Processes.TryAdd(ProcessId, Process);
2018-02-05 00:08:20 +01:00
}
InitializeProcess(Process);
return Process;
2018-02-05 00:08:20 +01:00
}
private void InitializeProcess(Process Process)
{
Process.AppletState.SetFocus(true);
}
internal void ExitProcess(int ProcessId)
{
if (Processes.TryGetValue(ProcessId, out Process Process) && Process.NeedsHbAbi)
{
string NextNro = Homebrew.ReadHbAbiNextLoadPath(Process.Memory, Process.HbAbiDataPosition);
Logging.Info(LogClass.Loader, $"HbAbi NextLoadPath {NextNro}");
if (NextNro == string.Empty)
{
NextNro = "sdmc:/hbmenu.nro";
}
NextNro = NextNro.Replace("sdmc:", string.Empty);
NextNro = Ns.VFs.GetFullPath(Ns.VFs.GetSdCardPath(), NextNro);
if (File.Exists(NextNro))
{
LoadProgram(NextNro);
}
}
if (Processes.TryRemove(ProcessId, out Process))
{
Process.StopAllThreadsAsync();
Process.Dispose();
if (Processes.Count == 0)
{
Ns.OnFinish(EventArgs.Empty);
}
}
}
2018-02-05 00:08:20 +01:00
internal bool TryGetProcess(int ProcessId, out Process Process)
{
return Processes.TryGetValue(ProcessId, out Process);
2018-02-05 00:08:20 +01:00
}
public void Dispose()
2018-02-05 00:08:20 +01:00
{
Dispose(true);
}
2018-02-05 00:08:20 +01:00
protected virtual void Dispose(bool Disposing)
{
if (Disposing)
2018-02-05 00:08:20 +01:00
{
foreach (Process Process in Processes.Values)
{
Process.StopAllThreadsAsync();
Process.Dispose();
}
VsyncEvent.Dispose();
2018-04-19 05:19:22 +02:00
Scheduler.Dispose();
2018-02-05 00:08:20 +01:00
}
}
}
}