diff --git a/ChocolArm64/AThread.cs b/ChocolArm64/AThread.cs index cec268175f..62f9d2d396 100644 --- a/ChocolArm64/AThread.cs +++ b/ChocolArm64/AThread.cs @@ -14,43 +14,30 @@ namespace ChocolArm64 private ATranslator Translator; - private ThreadPriority Priority; - private Thread Work; public event EventHandler WorkFinished; public int ThreadId => ThreadState.ThreadId; - public bool IsAlive => Work.IsAlive; + private int IsExecuting; - private bool IsExecuting; - - private object ExecuteLock; - - public AThread(ATranslator Translator, AMemory Memory, ThreadPriority Priority, long EntryPoint) + public AThread(ATranslator Translator, AMemory Memory, long EntryPoint) { this.Translator = Translator; this.Memory = Memory; - this.Priority = Priority; this.EntryPoint = EntryPoint; ThreadState = new AThreadState(); - ExecuteLock = new object(); - } - public void StopExecution() => Translator.StopExecution(); + ThreadState.Running = true; + } public bool Execute() { - lock (ExecuteLock) + if (Interlocked.Exchange(ref IsExecuting, 1) == 1) { - if (IsExecuting) - { - return false; - } - - IsExecuting = true; + return false; } Work = new Thread(delegate() @@ -62,11 +49,11 @@ namespace ChocolArm64 WorkFinished?.Invoke(this, EventArgs.Empty); }); - Work.Priority = Priority; - Work.Start(); return true; } + + public void StopExecution() => ThreadState.Running = false; } } \ No newline at end of file diff --git a/ChocolArm64/ATranslator.cs b/ChocolArm64/ATranslator.cs index 1f4a922ab2..02c18efd2b 100644 --- a/ChocolArm64/ATranslator.cs +++ b/ChocolArm64/ATranslator.cs @@ -22,8 +22,6 @@ namespace ChocolArm64 public bool EnableCpuTrace { get; set; } - private bool KeepRunning; - public ATranslator(IReadOnlyDictionary SymbolTable = null) { SubBlocks = new HashSet(); @@ -38,12 +36,8 @@ namespace ChocolArm64 { this.SymbolTable = new ConcurrentDictionary(); } - - KeepRunning = true; } - internal void StopExecution() => KeepRunning = false; - internal void ExecuteSubroutine(AThread Thread, long Position) { do @@ -70,7 +64,7 @@ namespace ChocolArm64 Position = Sub.Execute(Thread.ThreadState, Thread.Memory); } - while (Position != 0 && KeepRunning); + while (Position != 0 && Thread.ThreadState.Running); } internal bool TryGetCachedSub(AOpCode OpCode, out ATranslatedSub Sub) diff --git a/ChocolArm64/Instruction/AInstEmitException.cs b/ChocolArm64/Instruction/AInstEmitException.cs index fe348edd17..3964c94979 100644 --- a/ChocolArm64/Instruction/AInstEmitException.cs +++ b/ChocolArm64/Instruction/AInstEmitException.cs @@ -34,6 +34,22 @@ namespace ChocolArm64.Instruction Context.EmitCall(MthdInfo); + //Check if the thread should still be running, if it isn't then we return 0 + //to force a return to the dispatcher and then exit the thread. + Context.EmitLdarg(ATranslatedSub.StateArgIdx); + + Context.EmitCallPropGet(typeof(AThreadState), nameof(AThreadState.Running)); + + AILLabel LblEnd = new AILLabel(); + + Context.Emit(OpCodes.Brtrue_S, LblEnd); + + Context.EmitLdc_I8(0); + + Context.Emit(OpCodes.Ret); + + Context.MarkLabel(LblEnd); + if (Context.CurrBlock.Next != null) { Context.EmitLoadState(Context.CurrBlock.Next); diff --git a/ChocolArm64/State/AThreadState.cs b/ChocolArm64/State/AThreadState.cs index d86f5bf9c8..ec8621b89b 100644 --- a/ChocolArm64/State/AThreadState.cs +++ b/ChocolArm64/State/AThreadState.cs @@ -29,6 +29,8 @@ namespace ChocolArm64.State public int ProcessId; public int ThreadId; + public bool Running { get; set; } + public long TpidrEl0 { get; set; } public long Tpidr { get; set; } diff --git a/Ryujinx.Core/Hid/Hid.cs b/Ryujinx.Core/Hid/Hid.cs index c287564d3a..f25a943752 100644 --- a/Ryujinx.Core/Hid/Hid.cs +++ b/Ryujinx.Core/Hid/Hid.cs @@ -63,17 +63,13 @@ namespace Ryujinx.Core.Input private object ShMemLock; - private long[] ShMemPositions; + private (AMemory, long)[] ShMemPositions; - private AMemory Memory; - - public Hid(AMemory Memory) + public Hid() { - this.Memory = Memory; - ShMemLock = new object(); - ShMemPositions = new long[0]; + ShMemPositions = new (AMemory, long)[0]; } internal void ShMemMap(object sender, EventArgs e) @@ -84,11 +80,11 @@ namespace Ryujinx.Core.Input { ShMemPositions = SharedMem.GetVirtualPositions(); - long BasePosition = ShMemPositions[ShMemPositions.Length - 1]; + (AMemory Memory, long Position) ShMem = ShMemPositions[ShMemPositions.Length - 1]; - Logging.Info($"HID shared memory successfully mapped to 0x{BasePosition:x16}!"); + Logging.Info($"HID shared memory successfully mapped to 0x{ShMem.Position:x16}!"); - Init(BasePosition); + Init(ShMem.Memory, ShMem.Position); } } @@ -102,10 +98,11 @@ namespace Ryujinx.Core.Input } } - private void Init(long BasePosition) + private void Init(AMemory Memory, long Position) { InitializeJoyconPair( - BasePosition, + Memory, + Position, JoyConColor.Body_Neon_Red, JoyConColor.Buttons_Neon_Red, JoyConColor.Body_Neon_Blue, @@ -113,13 +110,14 @@ namespace Ryujinx.Core.Input } private void InitializeJoyconPair( - long BasePosition, + AMemory Memory, + long Position, JoyConColor LeftColorBody, JoyConColor LeftColorButtons, JoyConColor RightColorBody, JoyConColor RightColorButtons) { - long BaseControllerOffset = BasePosition + HidControllersOffset + 8 * HidControllerSize; + long BaseControllerOffset = Position + HidControllersOffset + 8 * HidControllerSize; HidControllerType Type = HidControllerType.ControllerType_Handheld | @@ -160,7 +158,7 @@ namespace Ryujinx.Core.Input { lock (ShMemLock) { - foreach (long Position in ShMemPositions) + foreach ((AMemory Memory, long Position) in ShMemPositions) { long ControllerOffset = Position + HidControllersOffset; @@ -207,7 +205,7 @@ namespace Ryujinx.Core.Input { lock (ShMemLock) { - foreach (long Position in ShMemPositions) + foreach ((AMemory Memory, long Position) in ShMemPositions) { long TouchScreenOffset = Position + HidTouchScreenOffset; diff --git a/Ryujinx.Core/Logging.cs b/Ryujinx.Core/Logging.cs index d544a5d64f..89064ccbc8 100644 --- a/Ryujinx.Core/Logging.cs +++ b/Ryujinx.Core/Logging.cs @@ -8,7 +8,8 @@ namespace Ryujinx.Core { public static class Logging { - private static Stopwatch ExecutionTime = new Stopwatch(); + private static Stopwatch ExecutionTime; + private const string LogFileName = "Ryujinx.log"; private static bool EnableInfo = Config.LoggingEnableInfo; @@ -23,6 +24,10 @@ namespace Ryujinx.Core static Logging() { if (File.Exists(LogFileName)) File.Delete(LogFileName); + + ExecutionTime = new Stopwatch(); + + ExecutionTime.Start(); } public static string GetExecutionTime() diff --git a/Ryujinx.Core/OsHle/CondVar.cs b/Ryujinx.Core/OsHle/CondVar.cs index ac3ba57498..f5fe3d292e 100644 --- a/Ryujinx.Core/OsHle/CondVar.cs +++ b/Ryujinx.Core/OsHle/CondVar.cs @@ -4,7 +4,7 @@ using System.Threading; namespace Ryujinx.Core.OsHle { - public class CondVar + class CondVar { private Process Process; diff --git a/Ryujinx.Core/OsHle/Handles/HDomain.cs b/Ryujinx.Core/OsHle/Handles/HDomain.cs index ca287a5fda..ac99b03a6b 100644 --- a/Ryujinx.Core/OsHle/Handles/HDomain.cs +++ b/Ryujinx.Core/OsHle/Handles/HDomain.cs @@ -1,58 +1,48 @@ -using Ryujinx.Core.OsHle.Utilities; using System; -using System.Collections.Generic; namespace Ryujinx.Core.OsHle.Handles { - class HDomain : HSession + class HDomain : HSession, IDisposable { - private Dictionary Objects; - - private IdPool ObjIds; + private IdDictionary Objects; public HDomain(HSession Session) : base(Session) { - Objects = new Dictionary(); - - ObjIds = new IdPool(); + Objects = new IdDictionary(); } - public int GenerateObjectId(object Obj) + public int Add(object Obj) { - int Id = ObjIds.GenerateId(); - - if (Id == -1) - { - throw new InvalidOperationException(); - } - - Objects.Add(Id, Obj); - - return Id; + return Objects.Add(Obj); } - public void DeleteObject(int Id) + public bool Delete(int Id) { - if (Objects.TryGetValue(Id, out object Obj)) - { - if (Obj is IDisposable DisposableObj) - { - DisposableObj.Dispose(); - } - - ObjIds.DeleteId(Id); - Objects.Remove(Id); - } + return Objects.Delete(Id); } public object GetObject(int Id) { - if (Objects.TryGetValue(Id, out object Obj)) - { - return Obj; - } + return Objects.GetData(Id); + } - return null; + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool Disposing) + { + if (Disposing) + { + foreach (object Obj in Objects) + { + if (Obj is IDisposable DisposableObj) + { + DisposableObj.Dispose(); + } + } + } } } } \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Handles/HNvMap.cs b/Ryujinx.Core/OsHle/Handles/HNvMap.cs deleted file mode 100644 index 09173730b3..0000000000 --- a/Ryujinx.Core/OsHle/Handles/HNvMap.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace Ryujinx.Core.OsHle.Handles -{ - class HNvMap - { - public int Id { get; private set; } - public int Size { get; private set; } - - public int Align { get; set; } - public int Kind { get; set; } - public long Address { get; set; } - - public HNvMap(int Id, int Size) - { - this.Id = Id; - this.Size = Size; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Handles/HSharedMem.cs b/Ryujinx.Core/OsHle/Handles/HSharedMem.cs index eb173e9652..b6bdc89878 100644 --- a/Ryujinx.Core/OsHle/Handles/HSharedMem.cs +++ b/Ryujinx.Core/OsHle/Handles/HSharedMem.cs @@ -1,3 +1,4 @@ +using ChocolArm64.Memory; using System; using System.Collections.Generic; @@ -5,37 +6,37 @@ namespace Ryujinx.Core.OsHle.Handles { class HSharedMem { - private List Positions; + private List<(AMemory, long)> Positions; public EventHandler MemoryMapped; public EventHandler MemoryUnmapped; public HSharedMem() { - Positions = new List(); + Positions = new List<(AMemory, long)>(); } - public void AddVirtualPosition(long Position) + public void AddVirtualPosition(AMemory Memory, long Position) { lock (Positions) { - Positions.Add(Position); + Positions.Add((Memory, Position)); MemoryMapped?.Invoke(this, EventArgs.Empty); } } - public void RemoveVirtualPosition(long Position) + public void RemoveVirtualPosition(AMemory Memory, long Position) { lock (Positions) { - Positions.Remove(Position); + Positions.Remove((Memory, Position)); MemoryUnmapped?.Invoke(this, EventArgs.Empty); } } - public long[] GetVirtualPositions() + public (AMemory, long)[] GetVirtualPositions() { return Positions.ToArray(); } diff --git a/Ryujinx.Core/OsHle/Handles/KProcessHandleTable.cs b/Ryujinx.Core/OsHle/Handles/KProcessHandleTable.cs new file mode 100644 index 0000000000..1156e035fd --- /dev/null +++ b/Ryujinx.Core/OsHle/Handles/KProcessHandleTable.cs @@ -0,0 +1,63 @@ +using System; + +namespace Ryujinx.Core.OsHle.Handles +{ + class KProcessHandleTable : IDisposable + { + private IdDictionary Handles; + + public KProcessHandleTable() + { + Handles = new IdDictionary(); + } + + public int OpenHandle(object Obj) + { + return Handles.Add(Obj); + } + + public T GetData(int Handle) + { + return Handles.GetData(Handle); + } + + public bool ReplaceData(int Id, object Data) + { + return Handles.ReplaceData(Id, Data); + } + + public bool CloseHandle(int Handle) + { + object Data = Handles.GetData(Handle); + + if (Data is HTransferMem TMem) + { + TMem.Memory.Manager.Reprotect( + TMem.Position, + TMem.Size, + TMem.Perm); + } + + return Handles.Delete(Handle); + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool Disposing) + { + if (Disposing) + { + foreach (object Obj in Handles) + { + if (Obj is IDisposable DisposableObj) + { + DisposableObj.Dispose(); + } + } + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Homebrew.cs b/Ryujinx.Core/OsHle/Homebrew.cs index e2e95e4d41..2a717ca738 100644 --- a/Ryujinx.Core/OsHle/Homebrew.cs +++ b/Ryujinx.Core/OsHle/Homebrew.cs @@ -37,5 +37,33 @@ namespace Ryujinx.Core.OsHle Position += 0x18; } + + public static string ReadHbAbiNextLoadPath(AMemory Memory, long Position) + { + string FileName = null; + + while (true) + { + long Key = Memory.ReadInt64(Position); + + if (Key == 2) + { + long Value0 = Memory.ReadInt64(Position + 0x08); + long Value1 = Memory.ReadInt64(Position + 0x10); + + FileName = AMemoryHelper.ReadAsciiString(Memory, Value0, (int)(Value1 - Value0)); + + break; + } + else if (Key == 0) + { + break; + } + + Position += 0x18; + } + + return FileName; + } } } diff --git a/Ryujinx.Core/OsHle/Horizon.cs b/Ryujinx.Core/OsHle/Horizon.cs index c61e18e98f..c3f8cd8b00 100644 --- a/Ryujinx.Core/OsHle/Horizon.cs +++ b/Ryujinx.Core/OsHle/Horizon.cs @@ -1,33 +1,23 @@ using Ryujinx.Core.Loaders.Executables; using Ryujinx.Core.OsHle.Handles; -using Ryujinx.Core.OsHle.Utilities; using System; using System.Collections.Concurrent; using System.IO; namespace Ryujinx.Core.OsHle { - public class Horizon + public class Horizon : IDisposable { internal const int HidSize = 0x40000; internal const int FontSize = 0x50; - internal int HidHandle { get; private set; } - internal int FontHandle { get; private set; } - - internal IdPool IdGen { get; private set; } - internal IdPool NvMapIds { get; private set; } - - internal IdPoolWithObj Handles { get; private set; } - internal IdPoolWithObj Fds { get; private set; } - internal IdPoolWithObj Displays { get; private set; } - - public ConcurrentDictionary Mutexes { get; private set; } - public ConcurrentDictionary CondVars { get; private set; } + internal ConcurrentDictionary Mutexes { get; private set; } + internal ConcurrentDictionary CondVars { get; private set; } private ConcurrentDictionary Processes; internal HSharedMem HidSharedMem; + internal HSharedMem FontSharedMem; private Switch Ns; @@ -35,25 +25,13 @@ namespace Ryujinx.Core.OsHle { this.Ns = Ns; - IdGen = new IdPool(); - NvMapIds = new IdPool(); - - Handles = new IdPoolWithObj(); - Fds = new IdPoolWithObj(); - Displays = new IdPoolWithObj(); - Mutexes = new ConcurrentDictionary(); CondVars = new ConcurrentDictionary(); Processes = new ConcurrentDictionary(); - HidSharedMem = new HSharedMem(); - - HidHandle = Handles.GenerateId(HidSharedMem); - - FontHandle = Handles.GenerateId(new HSharedMem()); - - HidSharedMem.AddVirtualPosition(0); + HidSharedMem = new HSharedMem(); + FontSharedMem = new HSharedMem(); } public void LoadCart(string ExeFsDir, string RomFsFile = null) @@ -63,9 +41,7 @@ namespace Ryujinx.Core.OsHle Ns.VFs.LoadRomFs(RomFsFile); } - int ProcessId = IdGen.GenerateId(); - - Process MainProcess = new Process(Ns, ProcessId); + Process MainProcess = MakeProcess(); void LoadNso(string FileName) { @@ -96,17 +72,13 @@ namespace Ryujinx.Core.OsHle LoadNso("sdk"); MainProcess.Run(); - - Processes.TryAdd(ProcessId, MainProcess); } public void LoadProgram(string FileName) { bool IsNro = Path.GetExtension(FileName).ToLower() == ".nro"; - int ProcessId = IdGen.GenerateId(); - - Process MainProcess = new Process(Ns, ProcessId); + Process MainProcess = MakeProcess(); using (FileStream Input = new FileStream(FileName, FileMode.Open)) { @@ -117,34 +89,67 @@ namespace Ryujinx.Core.OsHle MainProcess.SetEmptyArgs(); MainProcess.Run(IsNro); - - Processes.TryAdd(ProcessId, MainProcess); } - public void FinalizeAllProcesses() + private Process MakeProcess() { - foreach (Process Process in Processes.Values) + Process Process; + + lock (Processes) { - Process.StopAllThreads(); + int ProcessId = 0; + + while (Processes.ContainsKey(ProcessId)) + { + ProcessId++; + } + + Process = new Process(Ns, ProcessId); + + Processes.TryAdd(ProcessId, Process); + } + + return Process; + } + + internal void ExitProcess(int ProcessId) + { + if (Processes.TryGetValue(ProcessId, out Process Process) && Process.NeedsHbAbi) + { + string NextNro = Homebrew.ReadHbAbiNextLoadPath(Process.Memory, Process.HbAbiDataPosition); + + Logging.Info($"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)) + { + //TODO: Those dictionaries shouldn't even exist, + //the Mutex and CondVar helper classes should be static. + Mutexes.Clear(); + CondVars.Clear(); + + LoadProgram(NextNro); + } + } + + if (Processes.TryRemove(ProcessId, out Process)) + { + Process.StopAllThreadsAsync(); Process.Dispose(); - } - } - internal bool ExitProcess(int ProcessId) - { - bool Success = Processes.TryRemove(ProcessId, out Process Process); - - if (Success) - { - Process.StopAllThreads(); + if (Processes.Count == 0) + { + Ns.OnFinish(EventArgs.Empty); + } } - - if (Processes.Count == 0) - { - Ns.OnFinish(EventArgs.Empty); - } - - return Success; } internal bool TryGetProcess(int ProcessId, out Process Process) @@ -152,19 +157,21 @@ namespace Ryujinx.Core.OsHle return Processes.TryGetValue(ProcessId, out Process); } - internal void CloseHandle(int Handle) + public void Dispose() { - object HndData = Handles.GetData(Handle); + Dispose(true); + } - if (HndData is HTransferMem TransferMem) + protected virtual void Dispose(bool Disposing) + { + if (Disposing) { - TransferMem.Memory.Manager.Reprotect( - TransferMem.Position, - TransferMem.Size, - TransferMem.Perm); + foreach (Process Process in Processes.Values) + { + Process.StopAllThreadsAsync(); + Process.Dispose(); + } } - - Handles.Delete(Handle); } } } \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Utilities/IdPoolWithObj.cs b/Ryujinx.Core/OsHle/IdDictionary.cs similarity index 50% rename from Ryujinx.Core/OsHle/Utilities/IdPoolWithObj.cs rename to Ryujinx.Core/OsHle/IdDictionary.cs index f0a339df3a..0b90924616 100644 --- a/Ryujinx.Core/OsHle/Utilities/IdPoolWithObj.cs +++ b/Ryujinx.Core/OsHle/IdDictionary.cs @@ -3,31 +3,40 @@ using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; -namespace Ryujinx.Core.OsHle.Utilities +namespace Ryujinx.Core.OsHle { - class IdPoolWithObj : IEnumerable> + class IdDictionary : IEnumerable { - private IdPool Ids; - private ConcurrentDictionary Objs; - public IdPoolWithObj() - { - Ids = new IdPool(); + private int FreeIdHint = 1; + public IdDictionary() + { Objs = new ConcurrentDictionary(); } - public int GenerateId(object Data) + public int Add(object Data) { - int Id = Ids.GenerateId(); - - if (Id == -1 || !Objs.TryAdd(Id, Data)) + if (Objs.TryAdd(FreeIdHint, Data)) { - throw new InvalidOperationException(); + return FreeIdHint++; } - return Id; + return AddSlow(Data); + } + + private int AddSlow(object Data) + { + for (int Id = 1; Id < int.MaxValue; Id++) + { + if (Objs.TryAdd(Id, Data)) + { + return Id; + } + } + + throw new InvalidOperationException(); } public bool ReplaceData(int Id, object Data) @@ -42,6 +51,16 @@ namespace Ryujinx.Core.OsHle.Utilities return false; } + public object GetData(int Id) + { + if (Objs.TryGetValue(Id, out object Data)) + { + return Data; + } + + return null; + } + public T GetData(int Id) { if (Objs.TryGetValue(Id, out object Data) && Data is T) @@ -52,7 +71,7 @@ namespace Ryujinx.Core.OsHle.Utilities return default(T); } - public void Delete(int Id) + public bool Delete(int Id) { if (Objs.TryRemove(Id, out object Obj)) { @@ -61,18 +80,22 @@ namespace Ryujinx.Core.OsHle.Utilities DisposableObj.Dispose(); } - Ids.DeleteId(Id); + FreeIdHint = Id; + + return true; } + + return false; } - IEnumerator> IEnumerable>.GetEnumerator() + IEnumerator IEnumerable.GetEnumerator() { - return Objs.GetEnumerator(); + return Objs.Values.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { - return Objs.GetEnumerator(); + return Objs.Values.GetEnumerator(); } } } \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Ipc/IpcHandler.cs b/Ryujinx.Core/OsHle/Ipc/IpcHandler.cs index 2495d7014c..f2179a962c 100644 --- a/Ryujinx.Core/OsHle/Ipc/IpcHandler.cs +++ b/Ryujinx.Core/OsHle/Ipc/IpcHandler.cs @@ -13,6 +13,7 @@ namespace Ryujinx.Core.OsHle.Ipc public static void IpcCall( Switch Ns, + Process Process, AMemory Memory, HSession Session, IpcMessage Request, @@ -60,7 +61,7 @@ namespace Ryujinx.Core.OsHle.Ipc } else if (Request.DomCmd == IpcDomCmd.DeleteObj) { - Dom.DeleteObject(Request.DomObjId); + Dom.Delete(Request.DomObjId); Response = FillResponse(Response, 0); @@ -100,6 +101,7 @@ namespace Ryujinx.Core.OsHle.Ipc ServiceCtx Context = new ServiceCtx( Ns, + Process, Memory, Session, Request, @@ -124,15 +126,43 @@ namespace Ryujinx.Core.OsHle.Ipc switch (CmdId) { - case 0: Request = IpcConvertSessionToDomain(Ns, Session, Response, HndId); break; - case 3: Request = IpcQueryBufferPointerSize(Response); break; - case 2: //IpcDuplicateSession, differences is unknown. - case 4: Request = IpcDuplicateSessionEx(Ns, Session, Response, ReqReader); break; + case 0: + { + HDomain Dom = new HDomain(Session); + + Process.HandleTable.ReplaceData(HndId, Dom); + + Request = FillResponse(Response, 0, Dom.Add(Dom)); + + break; + } + + case 3: + { + Request = FillResponse(Response, 0, 0x500); + + break; + } + + //TODO: Whats the difference between IpcDuplicateSession/Ex? + case 2: + case 4: + { + int Unknown = ReqReader.ReadInt32(); + + int Handle = Process.HandleTable.OpenHandle(Session); + + Response.HandleDesc = IpcHandleDesc.MakeMove(Handle); + + Request = FillResponse(Response, 0); + + break; + } default: throw new NotImplementedException(CmdId.ToString()); } } - else if (Request.Type == IpcMessageType.Unknown2) + else if (Request.Type == IpcMessageType.CloseSession) { //TODO } @@ -145,39 +175,6 @@ namespace Ryujinx.Core.OsHle.Ipc } } - private static IpcMessage IpcConvertSessionToDomain( - Switch Ns, - HSession Session, - IpcMessage Response, - int HndId) - { - HDomain Dom = new HDomain(Session); - - Ns.Os.Handles.ReplaceData(HndId, Dom); - - return FillResponse(Response, 0, Dom.GenerateObjectId(Dom)); - } - - private static IpcMessage IpcDuplicateSessionEx( - Switch Ns, - HSession Session, - IpcMessage Response, - BinaryReader ReqReader) - { - int Unknown = ReqReader.ReadInt32(); - - int Handle = Ns.Os.Handles.GenerateId(Session); - - Response.HandleDesc = IpcHandleDesc.MakeMove(Handle); - - return FillResponse(Response, 0); - } - - private static IpcMessage IpcQueryBufferPointerSize(IpcMessage Response) - { - return FillResponse(Response, 0, 0x500); - } - private static IpcMessage FillResponse(IpcMessage Response, long Result, params int[] Values) { using (MemoryStream MS = new MemoryStream()) diff --git a/Ryujinx.Core/OsHle/Ipc/IpcMessageType.cs b/Ryujinx.Core/OsHle/Ipc/IpcMessageType.cs index 8027508de2..560af41e74 100644 --- a/Ryujinx.Core/OsHle/Ipc/IpcMessageType.cs +++ b/Ryujinx.Core/OsHle/Ipc/IpcMessageType.cs @@ -2,9 +2,9 @@ namespace Ryujinx.Core.OsHle.Ipc { enum IpcMessageType { - Response = 0, - Unknown2 = 2, - Request = 4, - Control = 5 + Response = 0, + CloseSession = 2, + Request = 4, + Control = 5 } } \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Mutex.cs b/Ryujinx.Core/OsHle/Mutex.cs index c95ed77164..c619e12174 100644 --- a/Ryujinx.Core/OsHle/Mutex.cs +++ b/Ryujinx.Core/OsHle/Mutex.cs @@ -4,7 +4,7 @@ using System.Threading; namespace Ryujinx.Core.OsHle { - public class Mutex + class Mutex { private const int MutexHasListenersMask = 0x40000000; diff --git a/Ryujinx.Core/OsHle/Process.cs b/Ryujinx.Core/OsHle/Process.cs index a919f1af6d..a8719e1c29 100644 --- a/Ryujinx.Core/OsHle/Process.cs +++ b/Ryujinx.Core/OsHle/Process.cs @@ -9,25 +9,32 @@ using Ryujinx.Core.OsHle.Svc; using System; using System.Collections.Concurrent; using System.Collections.Generic; -using System.Threading; namespace Ryujinx.Core.OsHle { - public class Process : IDisposable + class Process : IDisposable { - private const int TlsSize = 0x200; - private const int TotalTlsSlots = 32; + private const int TlsSize = 0x200; + private const int TotalTlsSlots = 32; private Switch Ns; + public bool NeedsHbAbi { get; private set; } + + public long HbAbiDataPosition { get; private set; } + public int ProcessId { get; private set; } private ATranslator Translator; public AMemory Memory { get; private set; } + public ServiceMgr Services { get; private set; } + public KProcessScheduler Scheduler { get; private set; } + public KProcessHandleTable HandleTable { get; private set; } + private SvcHandler SvcHandler; private ConcurrentDictionary TlsSlots; @@ -40,14 +47,22 @@ namespace Ryujinx.Core.OsHle private long ImageBase; + private bool ShouldDispose; + + private bool Disposed; + public Process(Switch Ns, int ProcessId) { this.Ns = Ns; this.ProcessId = ProcessId; - Memory = Ns.Memory; + Memory = new AMemory(); - Scheduler = new KProcessScheduler(); + Services = new ServiceMgr(); + + HandleTable = new KProcessHandleTable(); + + Scheduler = new KProcessScheduler(); SvcHandler = new SvcHandler(Ns, this); @@ -67,6 +82,11 @@ namespace Ryujinx.Core.OsHle public void LoadProgram(IExecutable Program) { + if (Disposed) + { + throw new ObjectDisposedException(nameof(Process)); + } + Logging.Info($"Image base at 0x{ImageBase:x16}."); Executable Executable = new Executable(Program, Memory, ImageBase); @@ -78,11 +98,19 @@ namespace Ryujinx.Core.OsHle public void SetEmptyArgs() { + //TODO: This should be part of Run. ImageBase += AMemoryMgr.PageSize; } - public bool Run(bool UseHbAbi = false) + public bool Run(bool NeedsHbAbi = false) { + if (Disposed) + { + throw new ObjectDisposedException(nameof(Process)); + } + + this.NeedsHbAbi = NeedsHbAbi; + if (Executables.Count == 0) { return false; @@ -102,11 +130,11 @@ namespace Ryujinx.Core.OsHle return false; } - MainThread = Ns.Os.Handles.GetData(Handle); + MainThread = HandleTable.GetData(Handle); - if (UseHbAbi) + if (NeedsHbAbi) { - long HbAbiDataPosition = AMemoryHelper.PageRoundUp(Executables[0].ImageEnd); + HbAbiDataPosition = AMemoryHelper.PageRoundUp(Executables[0].ImageEnd); Homebrew.WriteHbAbiData(Memory, HbAbiDataPosition, Handle); @@ -124,22 +152,21 @@ namespace Ryujinx.Core.OsHle Memory.Manager.Map(Position, Size, (int)Type, AMemoryPerm.RW); } - public void StopAllThreads() + public void StopAllThreadsAsync() { + if (Disposed) + { + throw new ObjectDisposedException(nameof(Process)); + } + if (MainThread != null) { - while (MainThread.Thread.IsAlive) - { - MainThread.Thread.StopExecution(); - } + MainThread.Thread.StopExecution(); } foreach (AThread Thread in TlsSlots.Values) { - while (Thread.IsAlive) - { - Thread.StopExecution(); - } + Thread.StopExecution(); } } @@ -150,49 +177,26 @@ namespace Ryujinx.Core.OsHle int Priority, int ProcessorId) { - ThreadPriority ThreadPrio; - - if (Priority < 12) + if (Disposed) { - ThreadPrio = ThreadPriority.Highest; - } - else if (Priority < 24) - { - ThreadPrio = ThreadPriority.AboveNormal; - } - else if (Priority < 36) - { - ThreadPrio = ThreadPriority.Normal; - } - else if (Priority < 48) - { - ThreadPrio = ThreadPriority.BelowNormal; - } - else - { - ThreadPrio = ThreadPriority.Lowest; + throw new ObjectDisposedException(nameof(Process)); } - AThread Thread = new AThread(GetTranslator(), Memory, ThreadPrio, EntryPoint); + AThread Thread = new AThread(GetTranslator(), Memory, EntryPoint); HThread ThreadHnd = new HThread(Thread, ProcessorId, Priority); - int Handle = Ns.Os.Handles.GenerateId(ThreadHnd); + int Handle = HandleTable.OpenHandle(ThreadHnd); - int TlsSlot = GetFreeTlsSlot(Thread); + int ThreadId = GetFreeTlsSlot(Thread); - if (TlsSlot == -1 || Handle == -1) - { - return -1; - } - - long Tpidr = MemoryRegions.TlsPagesAddress + TlsSlot * TlsSize; + long Tpidr = MemoryRegions.TlsPagesAddress + ThreadId * TlsSize; Thread.ThreadState.Break += BreakHandler; Thread.ThreadState.SvcCall += SvcHandler.SvcCall; Thread.ThreadState.Undefined += UndefinedHandler; Thread.ThreadState.ProcessId = ProcessId; - Thread.ThreadState.ThreadId = Ns.Os.IdGen.GenerateId(); + Thread.ThreadState.ThreadId = ThreadId; Thread.ThreadState.Tpidr = Tpidr; Thread.ThreadState.X0 = (ulong)ArgsPtr; Thread.ThreadState.X1 = (ulong)Handle; @@ -224,7 +228,7 @@ namespace Ryujinx.Core.OsHle foreach (Executable Exe in Executables) { foreach (KeyValuePair KV in Exe.SymbolTable) - { + { SymbolTable.TryAdd(Exe.ImageBase + KV.Key, KV.Value); } } @@ -274,16 +278,28 @@ namespace Ryujinx.Core.OsHle } } - return -1; + throw new InvalidOperationException(); } private void ThreadFinished(object sender, EventArgs e) { if (sender is AThread Thread) { - TlsSlots.TryRemove(GetTlsSlot(Thread.ThreadState.Tpidr), out _); + Logging.Info($"Thread {Thread.ThreadId} exiting..."); - Ns.Os.IdGen.DeleteId(Thread.ThreadId); + TlsSlots.TryRemove(GetTlsSlot(Thread.ThreadState.Tpidr), out _); + } + + if (TlsSlots.Count == 0) + { + if (ShouldDispose) + { + Dispose(); + } + + Logging.Info($"No threads running, now exiting Process {ProcessId}..."); + + Ns.Os.ExitProcess(ProcessId); } } @@ -309,9 +325,30 @@ namespace Ryujinx.Core.OsHle protected virtual void Dispose(bool Disposing) { - if (Disposing) + if (Disposing && !Disposed) { + //If there is still some thread running, disposing the objects is not + //safe as the thread may try to access those resources. Instead, we set + //the flag to have the Process disposed when all threads finishes. + //Note: This may not happen if the guest code gets stuck on a infinite loop. + if (TlsSlots.Count > 0) + { + ShouldDispose = true; + + Logging.Info($"Process {ProcessId} waiting all threads terminate..."); + + return; + } + + Disposed = true; + + Services.Dispose(); + HandleTable.Dispose(); Scheduler.Dispose(); + SvcHandler.Dispose(); + Memory.Dispose(); + + Logging.Info($"Process {ProcessId} exiting..."); } } } diff --git a/Ryujinx.Core/OsHle/ServiceCtx.cs b/Ryujinx.Core/OsHle/ServiceCtx.cs index 31ecce3dec..60c378d5a7 100644 --- a/Ryujinx.Core/OsHle/ServiceCtx.cs +++ b/Ryujinx.Core/OsHle/ServiceCtx.cs @@ -8,6 +8,7 @@ namespace Ryujinx.Core.OsHle class ServiceCtx { public Switch Ns { get; private set; } + public Process Process { get; private set; } public AMemory Memory { get; private set; } public HSession Session { get; private set; } public IpcMessage Request { get; private set; } @@ -17,6 +18,7 @@ namespace Ryujinx.Core.OsHle public ServiceCtx( Switch Ns, + Process Process, AMemory Memory, HSession Session, IpcMessage Request, @@ -25,6 +27,7 @@ namespace Ryujinx.Core.OsHle BinaryWriter ResponseData) { this.Ns = Ns; + this.Process = Process; this.Memory = Memory; this.Session = Session; this.Request = Request; diff --git a/Ryujinx.Core/OsHle/ServiceMgr.cs b/Ryujinx.Core/OsHle/ServiceMgr.cs new file mode 100644 index 0000000000..cbf6386f9d --- /dev/null +++ b/Ryujinx.Core/OsHle/ServiceMgr.cs @@ -0,0 +1,109 @@ +using Ryujinx.Core.OsHle.IpcServices; +using Ryujinx.Core.OsHle.IpcServices.Acc; +using Ryujinx.Core.OsHle.IpcServices.Am; +using Ryujinx.Core.OsHle.IpcServices.Apm; +using Ryujinx.Core.OsHle.IpcServices.Aud; +using Ryujinx.Core.OsHle.IpcServices.Bsd; +using Ryujinx.Core.OsHle.IpcServices.Friend; +using Ryujinx.Core.OsHle.IpcServices.FspSrv; +using Ryujinx.Core.OsHle.IpcServices.Hid; +using Ryujinx.Core.OsHle.IpcServices.Lm; +using Ryujinx.Core.OsHle.IpcServices.Nifm; +using Ryujinx.Core.OsHle.IpcServices.Ns; +using Ryujinx.Core.OsHle.IpcServices.NvServices; +using Ryujinx.Core.OsHle.IpcServices.Pctl; +using Ryujinx.Core.OsHle.IpcServices.Pl; +using Ryujinx.Core.OsHle.IpcServices.Set; +using Ryujinx.Core.OsHle.IpcServices.Sfdnsres; +using Ryujinx.Core.OsHle.IpcServices.Sm; +using Ryujinx.Core.OsHle.IpcServices.Ssl; +using Ryujinx.Core.OsHle.IpcServices.Time; +using Ryujinx.Core.OsHle.IpcServices.Vi; +using System; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle +{ + class ServiceMgr : IDisposable + { + private Dictionary Services; + + public ServiceMgr() + { + Services = new Dictionary(); + } + + public IIpcService GetService(string Name) + { + lock (Services) + { + if (!Services.TryGetValue(Name, out IIpcService Service)) + { + switch (Name) + { + case "acc:u0": Service = new ServiceAcc(); break; + case "aoc:u": Service = new ServiceNs(); break; + case "apm": Service = new ServiceApm(); break; + case "apm:p": Service = new ServiceApm(); break; + case "appletOE": Service = new ServiceAppletOE(); break; + case "audout:u": Service = new ServiceAudOut(); break; + case "audren:u": Service = new ServiceAudRen(); break; + case "bsd:u": Service = new ServiceBsd(); break; + case "friend:a": Service = new ServiceFriend(); break; + case "fsp-srv": Service = new ServiceFspSrv(); break; + case "hid": Service = new ServiceHid(); break; + case "lm": Service = new ServiceLm(); break; + case "nifm:u": Service = new ServiceNifm(); break; + case "nvdrv": Service = new ServiceNvDrv(); break; + case "nvdrv:a": Service = new ServiceNvDrv(); break; + case "pctl:a": Service = new ServicePctl(); break; + case "pl:u": Service = new ServicePl(); break; + case "set": Service = new ServiceSet(); break; + case "set:sys": Service = new ServiceSetSys(); break; + case "sfdnsres": Service = new ServiceSfdnsres(); break; + case "sm:": Service = new ServiceSm(); break; + case "ssl": Service = new ServiceSsl(); break; + case "time:s": Service = new ServiceTime(); break; + case "time:u": Service = new ServiceTime(); break; + case "vi:m": Service = new ServiceVi(); break; + case "vi:s": Service = new ServiceVi(); break; + case "vi:u": Service = new ServiceVi(); break; + } + + if (Service == null) + { + throw new NotImplementedException(Name); + } + + Services.Add(Name, Service); + } + + return Service; + } + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool Disposing) + { + if (Disposing) + { + lock (Services) + { + foreach (IIpcService Service in Services.Values) + { + if (Service is IDisposable DisposableSrv) + { + DisposableSrv.Dispose(); + } + } + + Services.Clear(); + } + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Aud/IAudioOut.cs b/Ryujinx.Core/OsHle/Services/Aud/IAudioOut.cs index c58d9e804c..2312920f6c 100644 --- a/Ryujinx.Core/OsHle/Services/Aud/IAudioOut.cs +++ b/Ryujinx.Core/OsHle/Services/Aud/IAudioOut.cs @@ -139,7 +139,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud public long RegisterBufferEvent(ServiceCtx Context) { - int Handle = Context.Ns.Os.Handles.GenerateId(new HEvent()); + int Handle = Context.Process.HandleTable.OpenHandle(new HEvent()); Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); diff --git a/Ryujinx.Core/OsHle/Services/Aud/IAudioRenderer.cs b/Ryujinx.Core/OsHle/Services/Aud/IAudioRenderer.cs index bfde0b65b1..4d29371fbd 100644 --- a/Ryujinx.Core/OsHle/Services/Aud/IAudioRenderer.cs +++ b/Ryujinx.Core/OsHle/Services/Aud/IAudioRenderer.cs @@ -56,7 +56,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud public long QuerySystemEvent(ServiceCtx Context) { - int Handle = Context.Ns.Os.Handles.GenerateId(new HEvent()); + int Handle = Context.Process.HandleTable.OpenHandle(new HEvent()); Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); diff --git a/Ryujinx.Core/OsHle/Services/Hid/IAppletResource.cs b/Ryujinx.Core/OsHle/Services/Hid/IAppletResource.cs index d22e0ff23b..ef437c022f 100644 --- a/Ryujinx.Core/OsHle/Services/Hid/IAppletResource.cs +++ b/Ryujinx.Core/OsHle/Services/Hid/IAppletResource.cs @@ -10,21 +10,23 @@ namespace Ryujinx.Core.OsHle.IpcServices.Hid public IReadOnlyDictionary Commands => m_Commands; - private HSharedMem Handle; + private HSharedMem HidSharedMem; - public IAppletResource(HSharedMem Handle) + public IAppletResource(HSharedMem HidSharedMem) { m_Commands = new Dictionary() { { 0, GetSharedMemoryHandle } }; - this.Handle = Handle; + this.HidSharedMem = HidSharedMem; } - public static long GetSharedMemoryHandle(ServiceCtx Context) + public long GetSharedMemoryHandle(ServiceCtx Context) { - Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Context.Ns.Os.HidHandle); + int Handle = Context.Process.HandleTable.OpenHandle(HidSharedMem); + + Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); return 0; } diff --git a/Ryujinx.Core/OsHle/Services/Hid/ServiceHid.cs b/Ryujinx.Core/OsHle/Services/Hid/ServiceHid.cs index cc30a771e0..b1f930725f 100644 --- a/Ryujinx.Core/OsHle/Services/Hid/ServiceHid.cs +++ b/Ryujinx.Core/OsHle/Services/Hid/ServiceHid.cs @@ -1,4 +1,3 @@ -using Ryujinx.Core.OsHle.Handles; using Ryujinx.Core.OsHle.Ipc; using System.Collections.Generic; @@ -32,9 +31,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Hid public long CreateAppletResource(ServiceCtx Context) { - HSharedMem HidHndData = Context.Ns.Os.Handles.GetData(Context.Ns.Os.HidHandle); - - MakeObject(Context, new IAppletResource(HidHndData)); + MakeObject(Context, new IAppletResource(Context.Ns.Os.HidSharedMem)); return 0; } diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvFd.cs b/Ryujinx.Core/OsHle/Services/Nv/NvFd.cs new file mode 100644 index 0000000000..dbce74adfc --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Nv/NvFd.cs @@ -0,0 +1,12 @@ +namespace Ryujinx.Core.OsHle.IpcServices.NvServices +{ + class NvFd + { + public string Name { get; private set; } + + public NvFd(string Name) + { + this.Name = Name; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvMap.cs b/Ryujinx.Core/OsHle/Services/Nv/NvMap.cs new file mode 100644 index 0000000000..ca844f9f28 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Nv/NvMap.cs @@ -0,0 +1,12 @@ +namespace Ryujinx.Core.OsHle.IpcServices.NvServices +{ + class NvMap + { + public int Handle; + public int Id; + public int Size; + public int Align; + public int Kind; + public long Address; + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Nv/ServiceNvDrv.cs b/Ryujinx.Core/OsHle/Services/Nv/ServiceNvDrv.cs index 3c0c46fec9..67ad44919a 100644 --- a/Ryujinx.Core/OsHle/Services/Nv/ServiceNvDrv.cs +++ b/Ryujinx.Core/OsHle/Services/Nv/ServiceNvDrv.cs @@ -1,5 +1,4 @@ using ChocolArm64.Memory; -using Ryujinx.Core.OsHle.Handles; using Ryujinx.Core.OsHle.Ipc; using Ryujinx.Core.OsHle.Utilities; using Ryujinx.Graphics.Gpu; @@ -12,41 +11,17 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices { private delegate long ServiceProcessIoctl(ServiceCtx Context); - private static Dictionary<(string, int), ServiceProcessIoctl> IoctlCmds = - new Dictionary<(string, int), ServiceProcessIoctl>() - { - { ("/dev/nvhost-as-gpu", 0x4101), NvGpuAsIoctlBindChannel }, - { ("/dev/nvhost-as-gpu", 0x4102), NvGpuAsIoctlAllocSpace }, - { ("/dev/nvhost-as-gpu", 0x4106), NvGpuAsIoctlMapBufferEx }, - { ("/dev/nvhost-as-gpu", 0x4108), NvGpuAsIoctlGetVaRegions }, - { ("/dev/nvhost-as-gpu", 0x4109), NvGpuAsIoctlInitializeEx }, - { ("/dev/nvhost-ctrl", 0x001b), NvHostIoctlCtrlGetConfig }, - { ("/dev/nvhost-ctrl", 0x001d), NvHostIoctlCtrlEventWait }, - { ("/dev/nvhost-ctrl-gpu", 0x4701), NvGpuIoctlZcullGetCtxSize }, - { ("/dev/nvhost-ctrl-gpu", 0x4702), NvGpuIoctlZcullGetInfo }, - { ("/dev/nvhost-ctrl-gpu", 0x4705), NvGpuIoctlGetCharacteristics }, - { ("/dev/nvhost-ctrl-gpu", 0x4706), NvGpuIoctlGetTpcMasks }, - { ("/dev/nvhost-ctrl-gpu", 0x4714), NvGpuIoctlZbcGetActiveSlotMask }, - { ("/dev/nvhost-gpu", 0x4714), NvMapIoctlChannelSetUserData }, - { ("/dev/nvhost-gpu", 0x4801), NvMapIoctlChannelSetNvMap }, - { ("/dev/nvhost-gpu", 0x4808), NvMapIoctlChannelSubmitGpFifo }, - { ("/dev/nvhost-gpu", 0x4809), NvMapIoctlChannelAllocObjCtx }, - { ("/dev/nvhost-gpu", 0x480b), NvMapIoctlChannelZcullBind }, - { ("/dev/nvhost-gpu", 0x480c), NvMapIoctlChannelSetErrorNotifier }, - { ("/dev/nvhost-gpu", 0x480d), NvMapIoctlChannelSetPriority }, - { ("/dev/nvhost-gpu", 0x481a), NvMapIoctlChannelAllocGpFifoEx2 }, - { ("/dev/nvmap", 0x0101), NvMapIocCreate }, - { ("/dev/nvmap", 0x0103), NvMapIocFromId }, - { ("/dev/nvmap", 0x0104), NvMapIocAlloc }, - { ("/dev/nvmap", 0x0105), NvMapIocFree }, - { ("/dev/nvmap", 0x0109), NvMapIocParam }, - { ("/dev/nvmap", 0x010e), NvMapIocGetId }, - }; - private Dictionary m_Commands; public IReadOnlyDictionary Commands => m_Commands; + private Dictionary<(string, int), ServiceProcessIoctl> IoctlCmds; + + private IdDictionary Fds; + + private IdDictionary NvMaps; + private IdDictionary NvMapsById; + public ServiceNvDrv() { m_Commands = new Dictionary() @@ -58,15 +33,50 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices { 4, QueryEvent }, { 8, SetClientPid }, }; + + IoctlCmds = new Dictionary<(string, int), ServiceProcessIoctl>() + { + { ("/dev/nvhost-as-gpu", 0x4101), NvGpuAsIoctlBindChannel }, + { ("/dev/nvhost-as-gpu", 0x4102), NvGpuAsIoctlAllocSpace }, + { ("/dev/nvhost-as-gpu", 0x4106), NvGpuAsIoctlMapBufferEx }, + { ("/dev/nvhost-as-gpu", 0x4108), NvGpuAsIoctlGetVaRegions }, + { ("/dev/nvhost-as-gpu", 0x4109), NvGpuAsIoctlInitializeEx }, + { ("/dev/nvhost-ctrl", 0x001b), NvHostIoctlCtrlGetConfig }, + { ("/dev/nvhost-ctrl", 0x001d), NvHostIoctlCtrlEventWait }, + { ("/dev/nvhost-ctrl-gpu", 0x4701), NvGpuIoctlZcullGetCtxSize }, + { ("/dev/nvhost-ctrl-gpu", 0x4702), NvGpuIoctlZcullGetInfo }, + { ("/dev/nvhost-ctrl-gpu", 0x4705), NvGpuIoctlGetCharacteristics }, + { ("/dev/nvhost-ctrl-gpu", 0x4706), NvGpuIoctlGetTpcMasks }, + { ("/dev/nvhost-ctrl-gpu", 0x4714), NvGpuIoctlZbcGetActiveSlotMask }, + { ("/dev/nvhost-gpu", 0x4714), NvMapIoctlChannelSetUserData }, + { ("/dev/nvhost-gpu", 0x4801), NvMapIoctlChannelSetNvMap }, + { ("/dev/nvhost-gpu", 0x4808), NvMapIoctlChannelSubmitGpFifo }, + { ("/dev/nvhost-gpu", 0x4809), NvMapIoctlChannelAllocObjCtx }, + { ("/dev/nvhost-gpu", 0x480b), NvMapIoctlChannelZcullBind }, + { ("/dev/nvhost-gpu", 0x480c), NvMapIoctlChannelSetErrorNotifier }, + { ("/dev/nvhost-gpu", 0x480d), NvMapIoctlChannelSetPriority }, + { ("/dev/nvhost-gpu", 0x481a), NvMapIoctlChannelAllocGpFifoEx2 }, + { ("/dev/nvmap", 0x0101), NvMapIocCreate }, + { ("/dev/nvmap", 0x0103), NvMapIocFromId }, + { ("/dev/nvmap", 0x0104), NvMapIocAlloc }, + { ("/dev/nvmap", 0x0105), NvMapIocFree }, + { ("/dev/nvmap", 0x0109), NvMapIocParam }, + { ("/dev/nvmap", 0x010e), NvMapIocGetId }, + }; + + Fds = new IdDictionary(); + + NvMaps = new IdDictionary(); + NvMapsById = new IdDictionary(); } - public static long Open(ServiceCtx Context) + public long Open(ServiceCtx Context) { long NamePtr = Context.Request.SendBuff[0].Position; string Name = AMemoryHelper.ReadAsciiString(Context.Memory, NamePtr); - int Fd = Context.Ns.Os.Fds.GenerateId(new FileDesc(Name)); + int Fd = Fds.Add(new NvFd(Name)); Context.ResponseData.Write(Fd); Context.ResponseData.Write(0); @@ -74,12 +84,12 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices return 0; } - public static long Ioctl(ServiceCtx Context) + public long Ioctl(ServiceCtx Context) { int Fd = Context.RequestData.ReadInt32(); int Cmd = Context.RequestData.ReadInt32() & 0xffff; - FileDesc FdData = Context.Ns.Os.Fds.GetData(Fd); + NvFd FdData = Fds.GetData(Fd); long Position = Context.Request.GetSendBuffPtr(); @@ -95,18 +105,18 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices } } - public static long Close(ServiceCtx Context) + public long Close(ServiceCtx Context) { int Fd = Context.RequestData.ReadInt32(); - Context.Ns.Os.Fds.Delete(Fd); + Fds.Delete(Fd); Context.ResponseData.Write(0); return 0; } - public static long Initialize(ServiceCtx Context) + public long Initialize(ServiceCtx Context) { long TransferMemSize = Context.RequestData.ReadInt64(); int TransferMemHandle = Context.Request.HandleDesc.ToCopy[0]; @@ -116,7 +126,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices return 0; } - public static long QueryEvent(ServiceCtx Context) + public long QueryEvent(ServiceCtx Context) { int Fd = Context.RequestData.ReadInt32(); int EventId = Context.RequestData.ReadInt32(); @@ -128,7 +138,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices return 0; } - public static long SetClientPid(ServiceCtx Context) + public long SetClientPid(ServiceCtx Context) { long Pid = Context.RequestData.ReadInt64(); @@ -137,7 +147,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices return 0; } - private static long NvGpuAsIoctlBindChannel(ServiceCtx Context) + private long NvGpuAsIoctlBindChannel(ServiceCtx Context) { long Position = Context.Request.GetSendBuffPtr(); @@ -146,7 +156,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices return 0; } - private static long NvGpuAsIoctlAllocSpace(ServiceCtx Context) + private long NvGpuAsIoctlAllocSpace(ServiceCtx Context) { long Position = Context.Request.GetSendBuffPtr(); @@ -172,7 +182,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices return 0; } - private static long NvGpuAsIoctlMapBufferEx(ServiceCtx Context) + private long NvGpuAsIoctlMapBufferEx(ServiceCtx Context) { long Position = Context.Request.GetSendBuffPtr(); @@ -186,18 +196,29 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices long MapSize = Reader.ReadInt64(); long Offset = Reader.ReadInt64(); - HNvMap NvMap = Context.Ns.Os.Handles.GetData(Handle); - - if (NvMap != null) + if (Handle == 0) { - if ((Flags & 1) != 0) - { - Offset = Context.Ns.Gpu.MapMemory(NvMap.Address, Offset, NvMap.Size); - } - else - { - Offset = Context.Ns.Gpu.MapMemory(NvMap.Address, NvMap.Size); - } + //Handle 0 is valid here, but it refers to something else. + //TODO: Figure out what, for now just return success. + return 0; + } + + NvMap Map = NvMaps.GetData(Handle); + + if (Map == null) + { + Logging.Warn($"Trying to use invalid NvMap Handle {Handle}!"); + + return -1; //TODO: Corrent error code. + } + + if ((Flags & 1) != 0) + { + Offset = Context.Ns.Gpu.MapMemory(Map.Address, Offset, Map.Size); + } + else + { + Offset = Context.Ns.Gpu.MapMemory(Map.Address, Map.Size); } Context.Memory.WriteInt64(Position + 0x20, Offset); @@ -205,7 +226,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices return 0; } - private static long NvGpuAsIoctlGetVaRegions(ServiceCtx Context) + private long NvGpuAsIoctlGetVaRegions(ServiceCtx Context) { long Position = Context.Request.GetSendBuffPtr(); @@ -235,7 +256,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices return 0; } - private static long NvGpuAsIoctlInitializeEx(ServiceCtx Context) + private long NvGpuAsIoctlInitializeEx(ServiceCtx Context) { long Position = Context.Request.GetSendBuffPtr(); @@ -252,7 +273,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices return 0; } - private static long NvHostIoctlCtrlGetConfig(ServiceCtx Context) + private long NvHostIoctlCtrlGetConfig(ServiceCtx Context) { long Position = Context.Request.GetSendBuffPtr(); @@ -267,7 +288,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices return 0; } - private static long NvHostIoctlCtrlEventWait(ServiceCtx Context) + private long NvHostIoctlCtrlEventWait(ServiceCtx Context) { long Position = Context.Request.GetSendBuffPtr(); @@ -283,7 +304,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices return 0; } - private static long NvGpuIoctlZcullGetCtxSize(ServiceCtx Context) + private long NvGpuIoctlZcullGetCtxSize(ServiceCtx Context) { long Position = Context.Request.GetSendBuffPtr(); @@ -292,7 +313,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices return 0; } - private static long NvGpuIoctlZcullGetInfo(ServiceCtx Context) + private long NvGpuIoctlZcullGetInfo(ServiceCtx Context) { long Position = Context.Request.GetSendBuffPtr(); @@ -312,7 +333,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices return 0; } - private static long NvGpuIoctlGetCharacteristics(ServiceCtx Context) + private long NvGpuIoctlGetCharacteristics(ServiceCtx Context) { long Position = Context.Request.GetSendBuffPtr(); @@ -374,7 +395,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices return 0; } - private static long NvGpuIoctlGetTpcMasks(ServiceCtx Context) + private long NvGpuIoctlGetTpcMasks(ServiceCtx Context) { long Position = Context.Request.GetSendBuffPtr(); @@ -388,7 +409,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices return 0; } - private static long NvGpuIoctlZbcGetActiveSlotMask(ServiceCtx Context) + private long NvGpuIoctlZbcGetActiveSlotMask(ServiceCtx Context) { long Position = Context.Request.GetSendBuffPtr(); @@ -398,14 +419,14 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices return 0; } - private static long NvMapIoctlChannelSetUserData(ServiceCtx Context) + private long NvMapIoctlChannelSetUserData(ServiceCtx Context) { long Position = Context.Request.GetSendBuffPtr(); return 0; } - private static long NvMapIoctlChannelSetNvMap(ServiceCtx Context) + private long NvMapIoctlChannelSetNvMap(ServiceCtx Context) { long Position = Context.Request.GetSendBuffPtr(); @@ -414,7 +435,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices return 0; } - private static long NvMapIoctlChannelSubmitGpFifo(ServiceCtx Context) + private long NvMapIoctlChannelSubmitGpFifo(ServiceCtx Context) { long Position = Context.Request.GetSendBuffPtr(); @@ -453,7 +474,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices return 0; } - private static long NvMapIoctlChannelAllocObjCtx(ServiceCtx Context) + private long NvMapIoctlChannelAllocObjCtx(ServiceCtx Context) { long Position = Context.Request.GetSendBuffPtr(); @@ -465,7 +486,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices return 0; } - private static long NvMapIoctlChannelZcullBind(ServiceCtx Context) + private long NvMapIoctlChannelZcullBind(ServiceCtx Context) { long Position = Context.Request.GetSendBuffPtr(); @@ -478,7 +499,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices return 0; } - private static long NvMapIoctlChannelSetErrorNotifier(ServiceCtx Context) + private long NvMapIoctlChannelSetErrorNotifier(ServiceCtx Context) { long Position = Context.Request.GetSendBuffPtr(); @@ -492,7 +513,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices return 0; } - private static long NvMapIoctlChannelSetPriority(ServiceCtx Context) + private long NvMapIoctlChannelSetPriority(ServiceCtx Context) { long Position = Context.Request.GetSendBuffPtr(); @@ -501,7 +522,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices return 0; } - private static long NvMapIoctlChannelAllocGpFifoEx2(ServiceCtx Context) + private long NvMapIoctlChannelAllocGpFifoEx2(ServiceCtx Context) { long Position = Context.Request.GetSendBuffPtr(); @@ -521,47 +542,46 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices return 0; } - private static long NvMapIocCreate(ServiceCtx Context) + private long NvMapIocCreate(ServiceCtx Context) { long Position = Context.Request.GetSendBuffPtr(); int Size = Context.Memory.ReadInt32(Position); - int Id = Context.Ns.Os.NvMapIds.GenerateId(); + NvMap Map = new NvMap() { Size = Size }; - int Handle = Context.Ns.Os.Handles.GenerateId(new HNvMap(Id, Size)); + Map.Handle = NvMaps.Add(Map); - Context.Memory.WriteInt32(Position + 4, Handle); + Map.Id = NvMapsById.Add(Map); - Logging.Info($"NvMap {Id} created with size {Size:x8}!"); + Context.Memory.WriteInt32(Position + 4, Map.Handle); + + Logging.Info($"NvMap {Map.Id} created with size {Size:x8}!"); return 0; } - private static long NvMapIocFromId(ServiceCtx Context) + private long NvMapIocFromId(ServiceCtx Context) { long Position = Context.Request.GetSendBuffPtr(); int Id = Context.Memory.ReadInt32(Position); - int Handle = -1; + NvMap Map = NvMapsById.GetData(Id); - foreach (KeyValuePair KV in Context.Ns.Os.Handles) + if (Map == null) { - if (KV.Value is HNvMap NvMap && NvMap.Id == Id) - { - Handle = KV.Key; - - break; - } + Logging.Warn($"Trying to use invalid NvMap Id {Id}!"); + + return -1; //TODO: Corrent error code. } - Context.Memory.WriteInt32(Position + 4, Handle); + Context.Memory.WriteInt32(Position + 4, Map.Handle); return 0; } - private static long NvMapIocAlloc(ServiceCtx Context) + private long NvMapIocAlloc(ServiceCtx Context) { long Position = Context.Request.GetSendBuffPtr(); @@ -574,38 +594,49 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices byte Kind = (byte)Reader.ReadInt64(); long Addr = Reader.ReadInt64(); - HNvMap NvMap = Context.Ns.Os.Handles.GetData(Handle); + NvMap Map = NvMaps.GetData(Handle); - if (NvMap != null) + if (Map == null) { - NvMap.Address = Addr; - NvMap.Align = Align; - NvMap.Kind = Kind; + Logging.Warn($"Trying to use invalid NvMap Handle {Handle}!"); + + return -1; //TODO: Corrent error code. } + Map.Address = Addr; + Map.Align = Align; + Map.Kind = Kind; + return 0; } - private static long NvMapIocFree(ServiceCtx Context) + private long NvMapIocFree(ServiceCtx Context) { long Position = Context.Request.GetSendBuffPtr(); MemReader Reader = new MemReader(Context.Memory, Position); MemWriter Writer = new MemWriter(Context.Memory, Position + 8); - int Handle = Reader.ReadInt32(); - int Padding = Reader.ReadInt32(); + int Handle = Reader.ReadInt32(); + int Padding = Reader.ReadInt32(); - HNvMap NvMap = Context.Ns.Os.Handles.GetData(Handle); + NvMap Map = NvMaps.GetData(Handle); + + if (Map == null) + { + Logging.Warn($"Trying to use invalid NvMap Handle {Handle}!"); + + return -1; //TODO: Corrent error code. + } Writer.WriteInt64(0); - Writer.WriteInt32(NvMap.Size); + Writer.WriteInt32(Map.Size); Writer.WriteInt32(0); return 0; } - private static long NvMapIocParam(ServiceCtx Context) + private long NvMapIocParam(ServiceCtx Context) { long Position = Context.Request.GetSendBuffPtr(); @@ -614,16 +645,23 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices int Handle = Reader.ReadInt32(); int Param = Reader.ReadInt32(); - HNvMap NvMap = Context.Ns.Os.Handles.GetData(Handle); + NvMap Map = NvMaps.GetData(Handle); + + if (Map == null) + { + Logging.Warn($"Trying to use invalid NvMap Handle {Handle}!"); + + return -1; //TODO: Corrent error code. + } int Response = 0; - + switch (Param) { - case 1: Response = NvMap.Size; break; - case 2: Response = NvMap.Align; break; - case 4: Response = 0x40000000; break; - case 5: Response = NvMap.Kind; break; + case 1: Response = Map.Size; break; + case 2: Response = Map.Align; break; + case 4: Response = 0x40000000; break; + case 5: Response = Map.Kind; break; } Context.Memory.WriteInt32(Position + 8, Response); @@ -631,17 +669,29 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices return 0; } - private static long NvMapIocGetId(ServiceCtx Context) + private long NvMapIocGetId(ServiceCtx Context) { long Position = Context.Request.GetSendBuffPtr(); int Handle = Context.Memory.ReadInt32(Position + 4); - HNvMap NvMap = Context.Ns.Os.Handles.GetData(Handle); + NvMap Map = NvMaps.GetData(Handle); - Context.Memory.WriteInt32(Position, NvMap.Id); + if (Map == null) + { + Logging.Warn($"Trying to use invalid NvMap Handle {Handle}!"); + + return -1; //TODO: Corrent error code. + } + + Context.Memory.WriteInt32(Position, Map.Id); return 0; } + + public NvMap GetNvMap(int Handle) + { + return NvMaps.GetData(Handle); + } } } \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/ObjHelper.cs b/Ryujinx.Core/OsHle/Services/ObjHelper.cs index ff71838a69..89d986aeb0 100644 --- a/Ryujinx.Core/OsHle/Services/ObjHelper.cs +++ b/Ryujinx.Core/OsHle/Services/ObjHelper.cs @@ -9,13 +9,13 @@ namespace Ryujinx.Core.OsHle.IpcServices { if (Context.Session is HDomain Dom) { - Context.Response.ResponseObjIds.Add(Dom.GenerateObjectId(Obj)); + Context.Response.ResponseObjIds.Add(Dom.Add(Obj)); } else { HSessionObj HndData = new HSessionObj(Context.Session, Obj); - int VHandle = Context.Ns.Os.Handles.GenerateId(HndData); + int VHandle = Context.Process.HandleTable.OpenHandle(HndData); Context.Response.HandleDesc = IpcHandleDesc.MakeMove(VHandle); } diff --git a/Ryujinx.Core/OsHle/Services/Pl/ServicePl.cs b/Ryujinx.Core/OsHle/Services/Pl/ServicePl.cs index abc34ed213..bb795f3f49 100644 --- a/Ryujinx.Core/OsHle/Services/Pl/ServicePl.cs +++ b/Ryujinx.Core/OsHle/Services/Pl/ServicePl.cs @@ -20,30 +20,32 @@ namespace Ryujinx.Core.OsHle.IpcServices.Pl }; } - public static long GetLoadState(ServiceCtx Context) + public long GetLoadState(ServiceCtx Context) { Context.ResponseData.Write(1); //Loaded return 0; } - public static long GetFontSize(ServiceCtx Context) + public long GetFontSize(ServiceCtx Context) { Context.ResponseData.Write(Horizon.FontSize); return 0; } - public static long GetSharedMemoryAddressOffset(ServiceCtx Context) + public long GetSharedMemoryAddressOffset(ServiceCtx Context) { Context.ResponseData.Write(0); return 0; } - public static long GetSharedMemoryNativeHandle(ServiceCtx Context) + public long GetSharedMemoryNativeHandle(ServiceCtx Context) { - Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Context.Ns.Os.FontHandle); + int Handle = Context.Process.HandleTable.OpenHandle(Context.Ns.Os.FontSharedMem); + + Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); return 0; } diff --git a/Ryujinx.Core/OsHle/Services/ServiceFactory.cs b/Ryujinx.Core/OsHle/Services/ServiceFactory.cs deleted file mode 100644 index 2b855d25b7..0000000000 --- a/Ryujinx.Core/OsHle/Services/ServiceFactory.cs +++ /dev/null @@ -1,64 +0,0 @@ -using Ryujinx.Core.OsHle.IpcServices.Acc; -using Ryujinx.Core.OsHle.IpcServices.Am; -using Ryujinx.Core.OsHle.IpcServices.Apm; -using Ryujinx.Core.OsHle.IpcServices.Aud; -using Ryujinx.Core.OsHle.IpcServices.Bsd; -using Ryujinx.Core.OsHle.IpcServices.Friend; -using Ryujinx.Core.OsHle.IpcServices.FspSrv; -using Ryujinx.Core.OsHle.IpcServices.Hid; -using Ryujinx.Core.OsHle.IpcServices.Lm; -using Ryujinx.Core.OsHle.IpcServices.Nifm; -using Ryujinx.Core.OsHle.IpcServices.Ns; -using Ryujinx.Core.OsHle.IpcServices.NvServices; -using Ryujinx.Core.OsHle.IpcServices.Pctl; -using Ryujinx.Core.OsHle.IpcServices.Pl; -using Ryujinx.Core.OsHle.IpcServices.Set; -using Ryujinx.Core.OsHle.IpcServices.Sfdnsres; -using Ryujinx.Core.OsHle.IpcServices.Sm; -using Ryujinx.Core.OsHle.IpcServices.Ssl; -using Ryujinx.Core.OsHle.IpcServices.Time; -using Ryujinx.Core.OsHle.IpcServices.Vi; -using System; - -namespace Ryujinx.Core.OsHle.IpcServices -{ - static class ServiceFactory - { - public static IIpcService MakeService(string Name) - { - switch (Name) - { - case "acc:u0": return new ServiceAcc(); - case "aoc:u": return new ServiceNs(); - case "apm": return new ServiceApm(); - case "apm:p": return new ServiceApm(); - case "appletOE": return new ServiceAppletOE(); - case "audout:u": return new ServiceAudOut(); - case "audren:u": return new ServiceAudRen(); - case "bsd:s": return new ServiceBsd(); - case "bsd:u": return new ServiceBsd(); - case "friend:a": return new ServiceFriend(); - case "fsp-srv": return new ServiceFspSrv(); - case "hid": return new ServiceHid(); - case "lm": return new ServiceLm(); - case "nifm:u": return new ServiceNifm(); - case "nvdrv": return new ServiceNvDrv(); - case "nvdrv:a": return new ServiceNvDrv(); - case "pctl:a": return new ServicePctl(); - case "pl:u": return new ServicePl(); - case "set": return new ServiceSet(); - case "set:sys": return new ServiceSetSys(); - case "sfdnsres": return new ServiceSfdnsres(); - case "sm:": return new ServiceSm(); - case "ssl": return new ServiceSsl(); - case "time:s": return new ServiceTime(); - case "time:u": return new ServiceTime(); - case "vi:m": return new ServiceVi(); - case "vi:s": return new ServiceVi(); - case "vi:u": return new ServiceVi(); - } - - throw new NotImplementedException(Name); - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Sm/ServiceSm.cs b/Ryujinx.Core/OsHle/Services/Sm/ServiceSm.cs index a5f1b329b8..cb745e3738 100644 --- a/Ryujinx.Core/OsHle/Services/Sm/ServiceSm.cs +++ b/Ryujinx.Core/OsHle/Services/Sm/ServiceSm.cs @@ -55,9 +55,9 @@ namespace Ryujinx.Core.OsHle.IpcServices.Sm return 0; } - HSession Session = new HSession(ServiceFactory.MakeService(Name)); + HSession Session = new HSession(Context.Process.Services.GetService(Name)); - int Handle = Context.Ns.Os.Handles.GenerateId(Session); + int Handle = Context.Process.HandleTable.OpenHandle(Session); Context.Response.HandleDesc = IpcHandleDesc.MakeMove(Handle); diff --git a/Ryujinx.Core/OsHle/Display.cs b/Ryujinx.Core/OsHle/Services/Vi/Display.cs similarity index 79% rename from Ryujinx.Core/OsHle/Display.cs rename to Ryujinx.Core/OsHle/Services/Vi/Display.cs index 590841fc50..ceadc39311 100644 --- a/Ryujinx.Core/OsHle/Display.cs +++ b/Ryujinx.Core/OsHle/Services/Vi/Display.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.Core.OsHle +namespace Ryujinx.Core.OsHle.IpcServices.Vi { class Display { diff --git a/Ryujinx.Core/OsHle/Services/Vi/IApplicationDisplayService.cs b/Ryujinx.Core/OsHle/Services/Vi/IApplicationDisplayService.cs index 4e40b99b3d..0ff1f90993 100644 --- a/Ryujinx.Core/OsHle/Services/Vi/IApplicationDisplayService.cs +++ b/Ryujinx.Core/OsHle/Services/Vi/IApplicationDisplayService.cs @@ -15,6 +15,8 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi public IReadOnlyDictionary Commands => m_Commands; + private IdDictionary Displays; + public IApplicationDisplayService() { m_Commands = new Dictionary() @@ -28,14 +30,17 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi { 2020, OpenLayer }, { 2021, CloseLayer }, { 2030, CreateStrayLayer }, + { 2031, DestroyStrayLayer }, { 2101, SetLayerScalingMode }, { 5202, GetDisplayVSyncEvent } }; + + Displays = new IdDictionary(); } public long GetRelayService(ServiceCtx Context) { - MakeObject(Context, new IHOSBinderDriver()); + MakeObject(Context, new IHOSBinderDriver(Context.Ns.Gpu.Renderer)); return 0; } @@ -56,7 +61,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi public long GetIndirectDisplayTransactionService(ServiceCtx Context) { - MakeObject(Context, new IHOSBinderDriver()); + MakeObject(Context, new IHOSBinderDriver(Context.Ns.Gpu.Renderer)); return 0; } @@ -65,7 +70,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi { string Name = GetDisplayName(Context); - long DisplayId = Context.Ns.Os.Displays.GenerateId(new Display(Name)); + long DisplayId = Displays.Add(new Display(Name)); Context.ResponseData.Write(DisplayId); @@ -76,7 +81,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi { int DisplayId = Context.RequestData.ReadInt32(); - Context.Ns.Os.Displays.Delete(DisplayId); + Displays.Delete(DisplayId); return 0; } @@ -99,6 +104,8 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi public long CloseLayer(ServiceCtx Context) { + long LayerId = Context.RequestData.ReadInt64(); + return 0; } @@ -109,7 +116,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi long ParcelPtr = Context.Request.ReceiveBuff[0].Position; - Display Disp = Context.Ns.Os.Displays.GetData((int)DisplayId); + Display Disp = Displays.GetData((int)DisplayId); byte[] Parcel = MakeIGraphicsBufferProducer(ParcelPtr); @@ -121,6 +128,11 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi return 0; } + public long DestroyStrayLayer(ServiceCtx Context) + { + return 0; + } + public long SetLayerScalingMode(ServiceCtx Context) { int ScalingMode = Context.RequestData.ReadInt32(); @@ -133,7 +145,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi { string Name = GetDisplayName(Context); - int Handle = Context.Ns.Os.Handles.GenerateId(new HEvent()); + int Handle = Context.Process.HandleTable.OpenHandle(new HEvent()); Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); diff --git a/Ryujinx.Core/OsHle/Services/Vi/IHOSBinderDriver.cs b/Ryujinx.Core/OsHle/Services/Vi/IHOSBinderDriver.cs index a89c1df824..b24a773bfe 100644 --- a/Ryujinx.Core/OsHle/Services/Vi/IHOSBinderDriver.cs +++ b/Ryujinx.Core/OsHle/Services/Vi/IHOSBinderDriver.cs @@ -1,6 +1,7 @@ using ChocolArm64.Memory; using Ryujinx.Core.OsHle.Ipc; using Ryujinx.Core.OsHle.IpcServices.Android; +using Ryujinx.Graphics.Gal; using System; using System.Collections.Generic; @@ -14,7 +15,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi private NvFlinger Flinger; - public IHOSBinderDriver() + public IHOSBinderDriver(IGalRenderer Renderer) { m_Commands = new Dictionary() { @@ -23,7 +24,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi { 2, GetNativeHandle } }; - Flinger = new NvFlinger(); + Flinger = new NvFlinger(Renderer); } public long TransactParcel(ServiceCtx Context) diff --git a/Ryujinx.Core/OsHle/Services/Vi/NvFlinger.cs b/Ryujinx.Core/OsHle/Services/Vi/NvFlinger.cs index 1d394fb4a7..5309dcabb7 100644 --- a/Ryujinx.Core/OsHle/Services/Vi/NvFlinger.cs +++ b/Ryujinx.Core/OsHle/Services/Vi/NvFlinger.cs @@ -1,5 +1,6 @@ using ChocolArm64.Memory; -using Ryujinx.Core.OsHle.Handles; +using Ryujinx.Core.OsHle.IpcServices.NvServices; +using Ryujinx.Graphics.Gal; using System; using System.IO; using System.Collections.Generic; @@ -54,18 +55,27 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android public GbpBuffer Data; } + private IGalRenderer Renderer; + private BufferEntry[] BufferQueue; private ManualResetEvent WaitBufferFree; + + private object RenderQueueLock; + + private int RenderQueueCount; + + private bool NvFlingerDisposed; private bool KeepRunning; - public NvFlinger() + public NvFlinger(IGalRenderer Renderer) { Commands = new Dictionary<(string, int), ServiceProcessParcel>() { { ("android.gui.IGraphicBufferProducer", 0x1), GbpRequestBuffer }, { ("android.gui.IGraphicBufferProducer", 0x3), GbpDequeueBuffer }, + { ("android.gui.IGraphicBufferProducer", 0x4), GbpDetachBuffer }, { ("android.gui.IGraphicBufferProducer", 0x7), GbpQueueBuffer }, { ("android.gui.IGraphicBufferProducer", 0x8), GbpCancelBuffer }, { ("android.gui.IGraphicBufferProducer", 0x9), GbpQuery }, @@ -74,10 +84,14 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android { ("android.gui.IGraphicBufferProducer", 0xe), GbpPreallocBuffer } }; + this.Renderer = Renderer; + BufferQueue = new BufferEntry[0x40]; WaitBufferFree = new ManualResetEvent(false); + RenderQueueLock = new object(); + KeepRunning = true; } @@ -193,6 +207,11 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android return MakeReplyParcel(Context, 1280, 720, 0, 0, 0); } + private long GbpDetachBuffer(ServiceCtx Context, BinaryReader ParcelReader) + { + return MakeReplyParcel(Context, 0); + } + private long GbpCancelBuffer(ServiceCtx Context, BinaryReader ParcelReader) { //TODO: Errors. @@ -266,7 +285,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android long FbSize = (uint)FbWidth * FbHeight * 4; - HNvMap NvMap = GetNvMap(Context, Slot); + NvMap NvMap = GetNvMap(Context, Slot); if ((ulong)(NvMap.Address + FbSize) > AMemoryMgr.AddrSize) { @@ -330,7 +349,17 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android Rotate = -MathF.PI * 0.5f; } - byte* Fb = (byte*)Context.Ns.Memory.Ram + NvMap.Address; + lock (RenderQueueLock) + { + if (NvFlingerDisposed) + { + return; + } + + Interlocked.Increment(ref RenderQueueCount); + } + + byte* Fb = (byte*)Context.Memory.Ram + NvMap.Address; Context.Ns.Gpu.Renderer.QueueAction(delegate() { @@ -346,6 +375,8 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android BufferQueue[Slot].State = BufferState.Free; + Interlocked.Decrement(ref RenderQueueCount); + lock (WaitBufferFree) { WaitBufferFree.Set(); @@ -353,7 +384,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android }); } - private HNvMap GetNvMap(ServiceCtx Context, int Slot) + private NvMap GetNvMap(ServiceCtx Context, int Slot) { int NvMapHandle = BitConverter.ToInt32(BufferQueue[Slot].Data.RawData, 0x4c); @@ -366,7 +397,9 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android NvMapHandle = BitConverter.ToInt32(RawValue, 0); } - return Context.Ns.Os.Handles.GetData(NvMapHandle); + ServiceNvDrv NvDrv = (ServiceNvDrv)Context.Process.Services.GetService("nvdrv"); + + return NvDrv.GetNvMap(NvMapHandle); } private int GetFreeSlotBlocking(int Width, int Height) @@ -432,10 +465,24 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android Dispose(true); } - protected virtual void Dispose(bool disposing) + protected virtual void Dispose(bool Disposing) { - if (disposing) + if (Disposing && !NvFlingerDisposed) { + lock (RenderQueueLock) + { + NvFlingerDisposed = true; + } + + //Ensure that all pending actions was sent before + //we can safely assume that the class was disposed. + while (RenderQueueCount > 0) + { + Thread.Yield(); + } + + Renderer.ResetFrameBuffer(); + lock (WaitBufferFree) { KeepRunning = false; diff --git a/Ryujinx.Core/OsHle/Svc/SvcHandler.cs b/Ryujinx.Core/OsHle/Svc/SvcHandler.cs index b3e6262db1..3ce56a3cd7 100644 --- a/Ryujinx.Core/OsHle/Svc/SvcHandler.cs +++ b/Ryujinx.Core/OsHle/Svc/SvcHandler.cs @@ -1,12 +1,13 @@ using ChocolArm64.Events; using ChocolArm64.Memory; using ChocolArm64.State; +using Ryujinx.Core.OsHle.Handles; using System; using System.Collections.Generic; namespace Ryujinx.Core.OsHle.Svc { - partial class SvcHandler + partial class SvcHandler : IDisposable { private delegate void SvcFunc(AThreadState ThreadState); @@ -16,10 +17,12 @@ namespace Ryujinx.Core.OsHle.Svc private Process Process; private AMemory Memory; - private static Random Rng; - + private HashSet<(HSharedMem, long)> MappedSharedMems; + private ulong CurrentHeapSize; + private static Random Rng; + public SvcHandler(Switch Ns, Process Process) { SvcFuncs = new Dictionary() @@ -32,6 +35,7 @@ namespace Ryujinx.Core.OsHle.Svc { 0x07, SvcExitProcess }, { 0x08, SvcCreateThread }, { 0x09, SvcStartThread }, + { 0x0a, SvcExitThread }, { 0x0b, SvcSleepThread }, { 0x0c, SvcGetThreadPriority }, { 0x0d, SvcSetThreadPriority }, @@ -60,6 +64,8 @@ namespace Ryujinx.Core.OsHle.Svc this.Ns = Ns; this.Process = Process; this.Memory = Process.Memory; + + MappedSharedMems = new HashSet<(HSharedMem, long)>(); } static SvcHandler() @@ -84,5 +90,26 @@ namespace Ryujinx.Core.OsHle.Svc throw new NotImplementedException(e.Id.ToString("x4")); } } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool Disposing) + { + if (Disposing) + { + lock (MappedSharedMems) + { + foreach ((HSharedMem SharedMem, long Position) in MappedSharedMems) + { + SharedMem.RemoveVirtualPosition(Memory, Position); + } + + MappedSharedMems.Clear(); + } + } + } } } \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Svc/SvcMemory.cs b/Ryujinx.Core/OsHle/Svc/SvcMemory.cs index c15f449bf1..80f24d2bd5 100644 --- a/Ryujinx.Core/OsHle/Svc/SvcMemory.cs +++ b/Ryujinx.Core/OsHle/Svc/SvcMemory.cs @@ -165,7 +165,7 @@ namespace Ryujinx.Core.OsHle.Svc return; } - HSharedMem SharedMem = Ns.Os.Handles.GetData(Handle); + HSharedMem SharedMem = Process.HandleTable.GetData(Handle); if (SharedMem != null) { @@ -175,7 +175,12 @@ namespace Ryujinx.Core.OsHle.Svc Memory.Manager.Reprotect(Src, Size, (AMemoryPerm)Perm); - SharedMem.AddVirtualPosition(Src); + lock (MappedSharedMems) + { + MappedSharedMems.Add((SharedMem, Src)); + } + + SharedMem.AddVirtualPosition(Memory, Src); ThreadState.X0 = 0; } @@ -198,12 +203,19 @@ namespace Ryujinx.Core.OsHle.Svc return; } - HSharedMem HndData = Ns.Os.Handles.GetData(Handle); + HSharedMem SharedMem = Process.HandleTable.GetData(Handle); - if (HndData != null) + if (SharedMem != null) { Memory.Manager.Unmap(Src, Size, (int)MemoryType.SharedMemory); + SharedMem.RemoveVirtualPosition(Memory, Src); + + lock (MappedSharedMems) + { + MappedSharedMems.Remove((SharedMem, Src)); + } + ThreadState.X0 = 0; } @@ -229,12 +241,12 @@ namespace Ryujinx.Core.OsHle.Svc Memory.Manager.Reprotect(Src, Size, (AMemoryPerm)Perm); - HTransferMem HndData = new HTransferMem(Memory, MapInfo.Perm, Src, Size); + HTransferMem TMem = new HTransferMem(Memory, MapInfo.Perm, Src, Size); - int Handle = Ns.Os.Handles.GenerateId(HndData); - - ThreadState.X1 = (ulong)Handle; + ulong Handle = (ulong)Process.HandleTable.OpenHandle(TMem); + ThreadState.X0 = 0; + ThreadState.X1 = Handle; } private static bool IsValidPosition(long Position) diff --git a/Ryujinx.Core/OsHle/Svc/SvcSystem.cs b/Ryujinx.Core/OsHle/Svc/SvcSystem.cs index f700903526..671a32d361 100644 --- a/Ryujinx.Core/OsHle/Svc/SvcSystem.cs +++ b/Ryujinx.Core/OsHle/Svc/SvcSystem.cs @@ -3,7 +3,6 @@ using ChocolArm64.State; using Ryujinx.Core.OsHle.Exceptions; using Ryujinx.Core.OsHle.Handles; using Ryujinx.Core.OsHle.Ipc; -using Ryujinx.Core.OsHle.IpcServices; using System; using System.Threading; @@ -35,7 +34,7 @@ namespace Ryujinx.Core.OsHle.Svc { int Handle = (int)ThreadState.X0; - Ns.Os.CloseHandle(Handle); + Process.HandleTable.CloseHandle(Handle); ThreadState.X0 = 0; } @@ -80,10 +79,12 @@ namespace Ryujinx.Core.OsHle.Svc //TODO: Validate that app has perms to access the service, and that the service //actually exists, return error codes otherwise. - HSession Session = new HSession(ServiceFactory.MakeService(Name)); + HSession Session = new HSession(Process.Services.GetService(Name)); - ThreadState.X1 = (ulong)Ns.Os.Handles.GenerateId(Session); + ulong Handle = (ulong)Process.HandleTable.OpenHandle(Session); + ThreadState.X0 = 0; + ThreadState.X1 = Handle; } private void SvcSendSyncRequest(AThreadState ThreadState) @@ -119,13 +120,21 @@ namespace Ryujinx.Core.OsHle.Svc byte[] CmdData = AMemoryHelper.ReadBytes(Memory, CmdPtr, (int)Size); - HSession Session = Ns.Os.Handles.GetData(Handle); + HSession Session = Process.HandleTable.GetData(Handle); IpcMessage Cmd = new IpcMessage(CmdData, CmdPtr, Session is HDomain); if (Session != null) { - IpcHandler.IpcCall(Ns, Memory, Session, Cmd, ThreadState.ThreadId, CmdPtr, Handle); + IpcHandler.IpcCall( + Ns, + Process, + Memory, + Session, + Cmd, + ThreadState.ThreadId, + CmdPtr, + Handle); byte[] Response = AMemoryHelper.ReadBytes(Memory, CmdPtr, (int)Size); diff --git a/Ryujinx.Core/OsHle/Svc/SvcThread.cs b/Ryujinx.Core/OsHle/Svc/SvcThread.cs index 6afd2e6106..231ee2a237 100644 --- a/Ryujinx.Core/OsHle/Svc/SvcThread.cs +++ b/Ryujinx.Core/OsHle/Svc/SvcThread.cs @@ -39,7 +39,7 @@ namespace Ryujinx.Core.OsHle.Svc { int Handle = (int)ThreadState.X0; - HThread Thread = Ns.Os.Handles.GetData(Handle); + HThread Thread = Process.HandleTable.GetData(Handle); if (Thread != null) { @@ -51,6 +51,13 @@ namespace Ryujinx.Core.OsHle.Svc //TODO: Error codes. } + private void SvcExitThread(AThreadState ThreadState) + { + HThread CurrThread = Process.GetThread(ThreadState.Tpidr); + + CurrThread.Thread.StopExecution(); + } + private void SvcSleepThread(AThreadState ThreadState) { ulong NanoSecs = ThreadState.X0; @@ -71,7 +78,7 @@ namespace Ryujinx.Core.OsHle.Svc { int Handle = (int)ThreadState.X1; - HThread Thread = Ns.Os.Handles.GetData(Handle); + HThread Thread = Process.HandleTable.GetData(Handle); if (Thread != null) { @@ -87,7 +94,7 @@ namespace Ryujinx.Core.OsHle.Svc int Handle = (int)ThreadState.X1; int Prio = (int)ThreadState.X0; - HThread Thread = Ns.Os.Handles.GetData(Handle); + HThread Thread = Process.HandleTable.GetData(Handle); if (Thread != null) { @@ -110,7 +117,7 @@ namespace Ryujinx.Core.OsHle.Svc { int Handle = (int)ThreadState.X0; - HThread Thread = Ns.Os.Handles.GetData(Handle); + HThread Thread = Process.HandleTable.GetData(Handle); if (Thread != null) { diff --git a/Ryujinx.Core/OsHle/Svc/SvcThreadSync.cs b/Ryujinx.Core/OsHle/Svc/SvcThreadSync.cs index 6e488da589..38356073e6 100644 --- a/Ryujinx.Core/OsHle/Svc/SvcThreadSync.cs +++ b/Ryujinx.Core/OsHle/Svc/SvcThreadSync.cs @@ -13,7 +13,7 @@ namespace Ryujinx.Core.OsHle.Svc long MutexAddress = (long)ThreadState.X1; int RequestingThreadHandle = (int)ThreadState.X2; - HThread RequestingThread = Ns.Os.Handles.GetData(RequestingThreadHandle); + HThread RequestingThread = Process.HandleTable.GetData(RequestingThreadHandle); Mutex M = new Mutex(Process, MutexAddress, OwnerThreadHandle); @@ -43,7 +43,7 @@ namespace Ryujinx.Core.OsHle.Svc int ThreadHandle = (int)ThreadState.X2; long Timeout = (long)ThreadState.X3; - HThread Thread = Ns.Os.Handles.GetData(ThreadHandle); + HThread Thread = Process.HandleTable.GetData(ThreadHandle); Mutex M = new Mutex(Process, MutexAddress, ThreadHandle); diff --git a/Ryujinx.Core/OsHle/Utilities/IdPool.cs b/Ryujinx.Core/OsHle/Utilities/IdPool.cs deleted file mode 100644 index a7e181fa23..0000000000 --- a/Ryujinx.Core/OsHle/Utilities/IdPool.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System.Collections.Generic; - -namespace Ryujinx.Core.OsHle.Utilities -{ - class IdPool - { - private HashSet Ids; - - private int CurrId; - private int MinId; - private int MaxId; - - public IdPool(int Min, int Max) - { - Ids = new HashSet(); - - CurrId = Min; - MinId = Min; - MaxId = Max; - } - - public IdPool() : this(1, int.MaxValue) { } - - public int GenerateId() - { - lock (Ids) - { - for (int Cnt = MinId; Cnt < MaxId; Cnt++) - { - if (Ids.Add(CurrId)) - { - return CurrId; - } - - if (CurrId++ == MaxId) - { - CurrId = MinId; - } - } - - return -1; - } - } - - public bool DeleteId(int Id) - { - lock (Ids) - { - return Ids.Remove(Id); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/Switch.cs b/Ryujinx.Core/Switch.cs index f7ce109f6f..487f3bdb99 100644 --- a/Ryujinx.Core/Switch.cs +++ b/Ryujinx.Core/Switch.cs @@ -1,4 +1,3 @@ -using ChocolArm64.Memory; using Ryujinx.Core.Input; using Ryujinx.Core.OsHle; using Ryujinx.Core.Settings; @@ -10,8 +9,6 @@ namespace Ryujinx.Core { public class Switch : IDisposable { - internal AMemory Memory { get; private set; } - internal NsGpu Gpu { get; private set; } internal Horizon Os { get; private set; } internal VirtualFs VFs { get; private set; } @@ -24,13 +21,11 @@ namespace Ryujinx.Core public Switch(IGalRenderer Renderer) { - Memory = new AMemory(); - Gpu = new NsGpu(Renderer); VFs = new VirtualFs(); - Hid = new Hid(Memory); + Hid = new Hid(); Statistics = new PerformanceStatistics(); @@ -42,11 +37,6 @@ namespace Ryujinx.Core Settings = new SetSys(); } - public void FinalizeAllProcesses() - { - Os.FinalizeAllProcesses(); - } - public void LoadCart(string ExeFsDir, string RomFsFile = null) { Os.LoadCart(ExeFsDir, RomFsFile); @@ -67,12 +57,11 @@ namespace Ryujinx.Core Dispose(true); } - protected virtual void Dispose(bool disposing) + protected virtual void Dispose(bool Disposing) { - if (disposing) + if (Disposing) { - Memory.Dispose(); - + Os.Dispose(); VFs.Dispose(); } } diff --git a/Ryujinx.Graphics/Gal/IGalRenderer.cs b/Ryujinx.Graphics/Gal/IGalRenderer.cs index 83d2c699f8..aa4eac4e14 100644 --- a/Ryujinx.Graphics/Gal/IGalRenderer.cs +++ b/Ryujinx.Graphics/Gal/IGalRenderer.cs @@ -8,6 +8,7 @@ namespace Ryujinx.Graphics.Gal void RunActions(); void InitializeFrameBuffer(); + void ResetFrameBuffer(); void Render(); void SetWindowSize(int Width, int Height); void SetFrameBuffer( diff --git a/Ryujinx.Graphics/Gal/OpenGL/FrameBuffer.cs b/Ryujinx.Graphics/Gal/OpenGL/FrameBuffer.cs index 7dc4bffe34..b761811f64 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/FrameBuffer.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/FrameBuffer.cs @@ -24,6 +24,8 @@ namespace Ryujinx.Graphics.Gal.OpenGL private byte* FbPtr; + private object FbPtrLock; + public FrameBuffer(int Width, int Height) { if (Width < 0) @@ -36,6 +38,8 @@ namespace Ryujinx.Graphics.Gal.OpenGL throw new ArgumentOutOfRangeException(nameof(Height)); } + FbPtrLock = new object(); + TexWidth = Width; TexHeight = Height; @@ -152,7 +156,10 @@ namespace Ryujinx.Graphics.Gal.OpenGL throw new ArgumentOutOfRangeException(nameof(Height)); } - FbPtr = Fb; + lock (FbPtrLock) + { + FbPtr = Fb; + } if (Width != TexWidth || Height != TexHeight) @@ -178,17 +185,28 @@ namespace Ryujinx.Graphics.Gal.OpenGL GL.Uniform2(OffsetUniformLocation, Offs); } + public void Reset() + { + lock (FbPtrLock) + { + FbPtr = null; + } + } + public void Render() { - if (FbPtr == null) + lock (FbPtrLock) { - return; - } + if (FbPtr == null) + { + return; + } - for (int Y = 0; Y < TexHeight; Y++) - for (int X = 0; X < TexWidth; X++) - { - Pixels[X + Y * TexWidth] = *((int*)(FbPtr + GetSwizzleOffset(X, Y))); + for (int Y = 0; Y < TexHeight; Y++) + for (int X = 0; X < TexWidth; X++) + { + Pixels[X + Y * TexWidth] = *((int*)(FbPtr + GetSwizzleOffset(X, Y))); + } } GL.BindTexture(TextureTarget.Texture2D, TexHandle); diff --git a/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs b/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs index bdedfc1a87..002e54dadc 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs @@ -43,6 +43,11 @@ namespace Ryujinx.Graphics.Gal.OpenGL FbRenderer = new FrameBuffer(1280, 720); } + public void ResetFrameBuffer() + { + FbRenderer.Reset(); + } + public void QueueAction(Action ActionMthd) { ActionsQueue.Enqueue(ActionMthd); diff --git a/Ryujinx.Tests/Cpu/CpuTest.cs b/Ryujinx.Tests/Cpu/CpuTest.cs index 0b35a7a6c3..b5bbdbc171 100644 --- a/Ryujinx.Tests/Cpu/CpuTest.cs +++ b/Ryujinx.Tests/Cpu/CpuTest.cs @@ -28,7 +28,7 @@ namespace Ryujinx.Tests.Cpu ATranslator Translator = new ATranslator(); Memory = new AMemory(); Memory.Manager.Map(Position, Size, 2, AMemoryPerm.Read | AMemoryPerm.Write | AMemoryPerm.Execute); - Thread = new AThread(Translator, Memory, ThreadPriority.Normal, EntryPoint); + Thread = new AThread(Translator, Memory, EntryPoint); } [TearDown]