From f876bd2a805805d9e5dc350b65e8d02fbc5b88b5 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Tue, 27 Feb 2018 20:45:07 -0300 Subject: [PATCH 01/17] Change SvcGetInfo 5 to return actual heap size, remove AMemoryAlloc since it is no longer needed with direct memory access, move some memory management logic out of AMemoryMgr, change default virtual filesystem path to AppData --- ChocolArm64/Memory/AMemory.cs | 4 +- ChocolArm64/Memory/AMemoryAlloc.cs | 35 ---- ChocolArm64/Memory/AMemoryMapInfo.cs | 2 +- ChocolArm64/Memory/AMemoryMgr.cs | 198 ++++++++--------------- Ryujinx.Core/Loaders/Executable.cs | 4 +- Ryujinx.Core/OsHle/Handles/HSharedMem.cs | 2 +- Ryujinx.Core/OsHle/Homebrew.cs | 2 +- Ryujinx.Core/OsHle/Horizon.cs | 23 +-- Ryujinx.Core/OsHle/MemoryInfo.cs | 28 ---- Ryujinx.Core/OsHle/MemoryRegions.cs | 21 ++- Ryujinx.Core/OsHle/Process.cs | 52 +++--- Ryujinx.Core/OsHle/Svc/SvcHandler.cs | 3 + Ryujinx.Core/OsHle/Svc/SvcMemory.cs | 65 ++++++-- Ryujinx.Core/OsHle/Svc/SvcSystem.cs | 128 +++++++-------- Ryujinx.Core/VirtualFs.cs | 12 +- Ryujinx.Graphics/Gpu/NsGpuMemoryMgr.cs | 2 +- Ryujinx.Tests/Cpu/CpuTest.cs | 7 +- 17 files changed, 251 insertions(+), 337 deletions(-) delete mode 100644 ChocolArm64/Memory/AMemoryAlloc.cs delete mode 100644 Ryujinx.Core/OsHle/MemoryInfo.cs diff --git a/ChocolArm64/Memory/AMemory.cs b/ChocolArm64/Memory/AMemory.cs index f2abffbf47..0d202fed30 100644 --- a/ChocolArm64/Memory/AMemory.cs +++ b/ChocolArm64/Memory/AMemory.cs @@ -41,9 +41,9 @@ namespace ChocolArm64.Memory private byte* RamPtr; - public AMemory(IntPtr Ram, AMemoryAlloc Allocator) + public AMemory(IntPtr Ram) { - Manager = new AMemoryMgr(Allocator); + Manager = new AMemoryMgr(); Monitors = new Dictionary(); diff --git a/ChocolArm64/Memory/AMemoryAlloc.cs b/ChocolArm64/Memory/AMemoryAlloc.cs deleted file mode 100644 index b11e779314..0000000000 --- a/ChocolArm64/Memory/AMemoryAlloc.cs +++ /dev/null @@ -1,35 +0,0 @@ -using ChocolArm64.Exceptions; - -namespace ChocolArm64.Memory -{ - public class AMemoryAlloc - { - private long PhysPos; - - public long Alloc(long Size) - { - long Position = PhysPos; - - Size = AMemoryHelper.PageRoundUp(Size); - - PhysPos += Size; - - if (PhysPos > AMemoryMgr.RamSize || PhysPos < 0) - { - throw new VmmOutOfMemoryException(Size); - } - - return Position; - } - - public void Free(long Position) - { - //TODO - } - - public long GetFreeMem() - { - return AMemoryMgr.RamSize - PhysPos; - } - } -} \ No newline at end of file diff --git a/ChocolArm64/Memory/AMemoryMapInfo.cs b/ChocolArm64/Memory/AMemoryMapInfo.cs index 44b2cc079e..02dd3055cc 100644 --- a/ChocolArm64/Memory/AMemoryMapInfo.cs +++ b/ChocolArm64/Memory/AMemoryMapInfo.cs @@ -1,6 +1,6 @@ namespace ChocolArm64.Memory { - public struct AMemoryMapInfo + public class AMemoryMapInfo { public long Position { get; private set; } public long Size { get; private set; } diff --git a/ChocolArm64/Memory/AMemoryMgr.cs b/ChocolArm64/Memory/AMemoryMgr.cs index c8869e03e1..bc36445242 100644 --- a/ChocolArm64/Memory/AMemoryMgr.cs +++ b/ChocolArm64/Memory/AMemoryMgr.cs @@ -1,3 +1,5 @@ +using System; + namespace ChocolArm64.Memory { public class AMemoryMgr @@ -5,22 +7,20 @@ namespace ChocolArm64.Memory public const long AddrSize = RamSize; public const long RamSize = 4L * 1024 * 1024 * 1024; - private const int PTLvl0Bits = 11; - private const int PTLvl1Bits = 13; - private const int PTPageBits = 12; + private const int PTLvl0Bits = 10; + private const int PTLvl1Bits = 10; + private const int PTPageBits = 12; - private const int PTLvl0Size = 1 << PTLvl0Bits; - private const int PTLvl1Size = 1 << PTLvl1Bits; - public const int PageSize = 1 << PTPageBits; + private const int PTLvl0Size = 1 << PTLvl0Bits; + private const int PTLvl1Size = 1 << PTLvl1Bits; + public const int PageSize = 1 << PTPageBits; - private const int PTLvl0Mask = PTLvl0Size - 1; - private const int PTLvl1Mask = PTLvl1Size - 1; - public const int PageMask = PageSize - 1; + private const int PTLvl0Mask = PTLvl0Size - 1; + private const int PTLvl1Mask = PTLvl1Size - 1; + public const int PageMask = PageSize - 1; - private const int PTLvl0Bit = PTPageBits + PTLvl0Bits; - private const int PTLvl1Bit = PTPageBits; - - private AMemoryAlloc Allocator; + private const int PTLvl0Bit = PTPageBits + PTLvl1Bits; + private const int PTLvl1Bit = PTPageBits; private enum PTMap { @@ -47,132 +47,24 @@ namespace ChocolArm64.Memory private PTEntry[][] PageTable; - private bool IsHeapInitialized; - - public long HeapAddr { get; private set; } - public long HeapSize { get; private set; } - - public AMemoryMgr(AMemoryAlloc Allocator) + public AMemoryMgr() { - this.Allocator = Allocator; - PageTable = new PTEntry[PTLvl0Size][]; } - public long GetTotalMemorySize() + public void Map(long Position, long Size, int Type, AMemoryPerm Perm) { - return Allocator.GetFreeMem() + GetUsedMemorySize(); + SetPTEntry(Position, Size, new PTEntry(PTMap.Mapped, Perm, Type, 0)); } - public long GetUsedMemorySize() + public void Unmap(long Position, long Size) { - long Size = 0; - - for (int L0 = 0; L0 < PageTable.Length; L0++) - { - if (PageTable[L0] == null) - { - continue; - } - - for (int L1 = 0; L1 < PageTable[L0].Length; L1++) - { - Size += PageTable[L0][L1].Map != PTMap.Unmapped ? PageSize : 0; - } - } - - return Size; + SetPTEntry(Position, Size, new PTEntry(PTMap.Unmapped, 0, 0, 0)); } - public bool SetHeapAddr(long Position) + public void Unmap(long Position, long Size, int Type) { - if (!IsHeapInitialized) - { - HeapAddr = Position; - - IsHeapInitialized = true; - - return true; - } - - return false; - } - - public void SetHeapSize(long Size, int Type) - { - //TODO: Return error when theres no enough space to allocate heap. - Size = AMemoryHelper.PageRoundUp(Size); - - long Position = HeapAddr; - - if ((ulong)Size < (ulong)HeapSize) - { - //Try to free now free area if size is smaller than old size. - Position += Size; - - while ((ulong)Size < (ulong)HeapSize) - { - Allocator.Free(Position); - - Position += PageSize; - } - } - else - { - //Allocate extra needed size. - Position += HeapSize; - Size -= HeapSize; - - MapPhys(Position, Size, Type, AMemoryPerm.RW); - } - - HeapSize = Size; - } - - public void MapPhys(long Position, long Size, int Type, AMemoryPerm Perm) - { - while (Size > 0) - { - if (!IsMapped(Position)) - { - SetPTEntry(Position, new PTEntry(PTMap.Mapped, Perm, Type, 0)); - } - - long CPgSize = PageSize - (Position & PageMask); - - Position += CPgSize; - Size -= CPgSize; - } - } - - public void MapMirror(long Src, long Dst, long Size, int Type) - { - Src = AMemoryHelper.PageRoundDown(Src); - Dst = AMemoryHelper.PageRoundDown(Dst); - - Size = AMemoryHelper.PageRoundUp(Size); - - long PagesCount = Size / PageSize; - - while (PagesCount-- > 0) - { - PTEntry SrcEntry = GetPTEntry(Src); - PTEntry DstEntry = GetPTEntry(Dst); - - DstEntry.Map = PTMap.Mapped; - DstEntry.Type = Type; - DstEntry.Perm = SrcEntry.Perm; - - SrcEntry.Perm = AMemoryPerm.None; - - SrcEntry.Attr |= 1; - - SetPTEntry(Src, SrcEntry); - SetPTEntry(Dst, DstEntry); - - Src += PageSize; - Dst += PageSize; - } + SetPTEntry(Position, Size, Type, new PTEntry(PTMap.Unmapped, 0, 0, 0)); } public void Reprotect(long Position, long Size, AMemoryPerm Perm) @@ -197,12 +89,22 @@ namespace ChocolArm64.Memory public AMemoryMapInfo GetMapInfo(long Position) { + if (!IsValidPosition(Position)) + { + return null; + } + Position = AMemoryHelper.PageRoundDown(Position); PTEntry BaseEntry = GetPTEntry(Position); bool IsSameSegment(long Pos) { + if (!IsValidPosition(Pos)) + { + return false; + } + PTEntry Entry = GetPTEntry(Pos); return Entry.Map == BaseEntry.Map && @@ -269,6 +171,16 @@ namespace ChocolArm64.Memory return GetPTEntry(Position).Perm.HasFlag(Perm); } + public bool IsValidPosition(long Position) + { + if (Position >> PTLvl0Bits + PTLvl1Bits + PTPageBits != 0) + { + return false; + } + + return true; + } + public bool IsMapped(long Position) { if (Position >> PTLvl0Bits + PTLvl1Bits + PTPageBits != 0) @@ -300,8 +212,38 @@ namespace ChocolArm64.Memory return PageTable[L0][L1]; } + private void SetPTEntry(long Position, long Size, PTEntry Entry) + { + while (Size > 0) + { + SetPTEntry(Position, Entry); + + Position += PageSize; + Size -= PageSize; + } + } + + private void SetPTEntry(long Position, long Size, int Type, PTEntry Entry) + { + while (Size > 0) + { + if (GetPTEntry(Position).Type == Type) + { + SetPTEntry(Position, Entry); + } + + Position += PageSize; + Size -= PageSize; + } + } + private void SetPTEntry(long Position, PTEntry Entry) { + if (!IsValidPosition(Position)) + { + throw new ArgumentOutOfRangeException(nameof(Position)); + } + long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask; long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask; diff --git a/Ryujinx.Core/Loaders/Executable.cs b/Ryujinx.Core/Loaders/Executable.cs index 95cb7d6f6c..fa204460f6 100644 --- a/Ryujinx.Core/Loaders/Executable.cs +++ b/Ryujinx.Core/Loaders/Executable.cs @@ -96,7 +96,7 @@ namespace Ryujinx.Core.Loaders MemoryType Type, AMemoryPerm Perm) { - Memory.Manager.MapPhys(Position, Data.Count, (int)Type, AMemoryPerm.Write); + Memory.Manager.Map(Position, Data.Count, (int)Type, AMemoryPerm.Write); for (int Index = 0; Index < Data.Count; Index++) { @@ -108,7 +108,7 @@ namespace Ryujinx.Core.Loaders private void MapBss(long Position, long Size) { - Memory.Manager.MapPhys(Position, Size, (int)MemoryType.Normal, AMemoryPerm.RW); + Memory.Manager.Map(Position, Size, (int)MemoryType.Normal, AMemoryPerm.RW); } private ElfRel GetRelocation(long Position) diff --git a/Ryujinx.Core/OsHle/Handles/HSharedMem.cs b/Ryujinx.Core/OsHle/Handles/HSharedMem.cs index 3d56ff9209..9cd0a0d47e 100644 --- a/Ryujinx.Core/OsHle/Handles/HSharedMem.cs +++ b/Ryujinx.Core/OsHle/Handles/HSharedMem.cs @@ -12,7 +12,7 @@ namespace Ryujinx.Core.OsHle.Handles public EventHandler MemoryMapped; public EventHandler MemoryUnmapped; - public HSharedMem(long PhysPos) + public HSharedMem() { Positions = new List(); } diff --git a/Ryujinx.Core/OsHle/Homebrew.cs b/Ryujinx.Core/OsHle/Homebrew.cs index f177b37e36..e2e95e4d41 100644 --- a/Ryujinx.Core/OsHle/Homebrew.cs +++ b/Ryujinx.Core/OsHle/Homebrew.cs @@ -7,7 +7,7 @@ namespace Ryujinx.Core.OsHle //http://switchbrew.org/index.php?title=Homebrew_ABI public static void WriteHbAbiData(AMemory Memory, long Position, int MainThreadHandle) { - Memory.Manager.MapPhys(Position, AMemoryMgr.PageSize, (int)MemoryType.Normal, AMemoryPerm.RW); + Memory.Manager.Map(Position, AMemoryMgr.PageSize, (int)MemoryType.Normal, AMemoryPerm.RW); //MainThreadHandle WriteConfigEntry(Memory, ref Position, 1, 0, MainThreadHandle); diff --git a/Ryujinx.Core/OsHle/Horizon.cs b/Ryujinx.Core/OsHle/Horizon.cs index 9929102d60..c238914398 100644 --- a/Ryujinx.Core/OsHle/Horizon.cs +++ b/Ryujinx.Core/OsHle/Horizon.cs @@ -1,4 +1,3 @@ -using ChocolArm64.Memory; using Ryujinx.Core.Loaders.Executables; using Ryujinx.Core.OsHle.Handles; using Ryujinx.Core.OsHle.Utilities; @@ -16,9 +15,6 @@ namespace Ryujinx.Core.OsHle internal int HidHandle { get; private set; } internal int FontHandle { get; private set; } - public long HidOffset { get; private set; } - public long FontOffset { get; private set; } - internal IdPool IdGen { get; private set; } internal IdPool NvMapIds { get; private set; } @@ -33,8 +29,6 @@ namespace Ryujinx.Core.OsHle private HSharedMem HidSharedMem; - private AMemoryAlloc Allocator; - private Switch Ns; public Horizon(Switch Ns) @@ -53,18 +47,13 @@ namespace Ryujinx.Core.OsHle Processes = new ConcurrentDictionary(); - Allocator = new AMemoryAlloc(); - - HidOffset = Allocator.Alloc(HidSize); - FontOffset = Allocator.Alloc(FontSize); - - HidSharedMem = new HSharedMem(HidOffset); + HidSharedMem = new HSharedMem(); HidSharedMem.MemoryMapped += HidInit; HidHandle = Handles.GenerateId(HidSharedMem); - FontHandle = Handles.GenerateId(new HSharedMem(FontOffset)); + FontHandle = Handles.GenerateId(new HSharedMem()); } public void LoadCart(string ExeFsDir, string RomFsFile = null) @@ -76,7 +65,7 @@ namespace Ryujinx.Core.OsHle int ProcessId = IdGen.GenerateId(); - Process MainProcess = new Process(Ns, Allocator, ProcessId); + Process MainProcess = new Process(Ns, ProcessId); void LoadNso(string FileName) { @@ -106,7 +95,6 @@ namespace Ryujinx.Core.OsHle LoadNso("subsdk*"); LoadNso("sdk"); - MainProcess.InitializeHeap(); MainProcess.Run(); Processes.TryAdd(ProcessId, MainProcess); @@ -118,7 +106,7 @@ namespace Ryujinx.Core.OsHle int ProcessId = IdGen.GenerateId(); - Process MainProcess = new Process(Ns, Allocator, ProcessId); + Process MainProcess = new Process(Ns, ProcessId); using (FileStream Input = new FileStream(FileName, FileMode.Open)) { @@ -128,7 +116,6 @@ namespace Ryujinx.Core.OsHle } MainProcess.SetEmptyArgs(); - MainProcess.InitializeHeap(); MainProcess.Run(IsNro); Processes.TryAdd(ProcessId, MainProcess); @@ -186,7 +173,7 @@ namespace Ryujinx.Core.OsHle if (SharedMem.TryGetLastVirtualPosition(out long Position)) { - Logging.Info($"HID shared memory successfully mapped to {Position:x16}!"); + Logging.Info($"HID shared memory successfully mapped to 0x{Position:x16}!"); Ns.Hid.Init(Position); } diff --git a/Ryujinx.Core/OsHle/MemoryInfo.cs b/Ryujinx.Core/OsHle/MemoryInfo.cs deleted file mode 100644 index 76a4bef3ba..0000000000 --- a/Ryujinx.Core/OsHle/MemoryInfo.cs +++ /dev/null @@ -1,28 +0,0 @@ -using ChocolArm64.Memory; - -namespace Ryujinx.Core.OsHle -{ - struct MemoryInfo - { - public long BaseAddress; - public long Size; - public int MemType; - public int MemAttr; - public int MemPerm; - public int IpcRefCount; - public int DeviceRefCount; - public int Padding; //SBZ - - public MemoryInfo(AMemoryMapInfo MapInfo) - { - BaseAddress = MapInfo.Position; - Size = MapInfo.Size; - MemType = MapInfo.Type; - MemAttr = MapInfo.Attr; - MemPerm = (int)MapInfo.Perm; - IpcRefCount = 0; - DeviceRefCount = 0; - Padding = 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/MemoryRegions.cs b/Ryujinx.Core/OsHle/MemoryRegions.cs index 86d266f60d..3b69042607 100644 --- a/Ryujinx.Core/OsHle/MemoryRegions.cs +++ b/Ryujinx.Core/OsHle/MemoryRegions.cs @@ -1,11 +1,28 @@ +using ChocolArm64.Memory; + namespace Ryujinx.Core.OsHle { static class MemoryRegions { - public const long MapRegionAddress = 0x80000000; + public const long AddrSpaceStart = 0x08000000; + + public const long MapRegionAddress = 0x10000000; public const long MapRegionSize = 0x40000000; + public const long MainStackSize = 0x100000; + + public const long MainStackAddress = AMemoryMgr.AddrSize - MainStackSize; + + public const long TlsPagesSize = 0x4000; + + public const long TlsPagesAddress = MainStackAddress - TlsPagesSize; + public const long HeapRegionAddress = MapRegionAddress + MapRegionSize; - public const long HeapRegionSize = 0x40000000; + + public const long TotalMemoryUsed = HeapRegionAddress + TlsPagesSize + MainStackSize; + + public const long TotalMemoryAvailable = AMemoryMgr.RamSize - AddrSpaceStart; + + public const long AddrSpaceSize = AMemoryMgr.AddrSize - AddrSpaceStart; } } \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Process.cs b/Ryujinx.Core/OsHle/Process.cs index 9ca9a2bd5c..f0b568c8ce 100644 --- a/Ryujinx.Core/OsHle/Process.cs +++ b/Ryujinx.Core/OsHle/Process.cs @@ -15,19 +15,15 @@ namespace Ryujinx.Core.OsHle { public class Process : IDisposable { - private const int MaxStackSize = 8 * 1024 * 1024; - private const int TlsSize = 0x200; private const int TotalTlsSlots = 32; - private const int TlsTotalSize = TotalTlsSlots * TlsSize; - private const long TlsPageAddr = (AMemoryMgr.AddrSize - TlsTotalSize) & ~AMemoryMgr.PageMask; private Switch Ns; - private ATranslator Translator; - public int ProcessId { get; private set; } + private ATranslator Translator; + public AMemory Memory { get; private set; } public KProcessScheduler Scheduler { get; private set; } @@ -44,12 +40,12 @@ namespace Ryujinx.Core.OsHle private long ImageBase; - public Process(Switch Ns, AMemoryAlloc Allocator, int ProcessId) + public Process(Switch Ns, int ProcessId) { this.Ns = Ns; this.ProcessId = ProcessId; - Memory = new AMemory(Ns.Ram, Allocator); + Memory = new AMemory(Ns.Ram); Scheduler = new KProcessScheduler(); @@ -61,13 +57,12 @@ namespace Ryujinx.Core.OsHle Executables = new List(); - ImageBase = 0x8000000; + ImageBase = MemoryRegions.AddrSpaceStart; - Memory.Manager.MapPhys( - TlsPageAddr, - TlsTotalSize, - (int)MemoryType.ThreadLocal, - AMemoryPerm.RW); + MapRWMemRegion( + MemoryRegions.TlsPagesAddress, + MemoryRegions.TlsPagesSize, + MemoryType.ThreadLocal); } public void LoadProgram(IExecutable Program) @@ -86,11 +81,6 @@ namespace Ryujinx.Core.OsHle ImageBase += AMemoryMgr.PageSize; } - public void InitializeHeap() - { - Memory.Manager.SetHeapAddr(MemoryRegions.HeapRegionAddress); - } - public bool Run(bool UseHbAbi = false) { if (Executables.Count == 0) @@ -98,11 +88,14 @@ namespace Ryujinx.Core.OsHle return false; } - long StackBot = TlsPageAddr - MaxStackSize; + MapRWMemRegion( + MemoryRegions.MainStackAddress, + MemoryRegions.MainStackSize, + MemoryType.Normal); + + long StackTop = MemoryRegions.MainStackAddress + MemoryRegions.MainStackSize; - Memory.Manager.MapPhys(StackBot, MaxStackSize, (int)MemoryType.Normal, AMemoryPerm.RW); - - int Handle = MakeThread(Executables[0].ImageBase, TlsPageAddr, 0, 0, 0); + int Handle = MakeThread(Executables[0].ImageBase, StackTop, 0, 0, 0); if (Handle == -1) { @@ -113,7 +106,7 @@ namespace Ryujinx.Core.OsHle if (UseHbAbi) { - long HbAbiDataPosition = (Executables[0].ImageEnd + 0xfff) & ~0xfff; + long HbAbiDataPosition = AMemoryHelper.PageRoundUp(Executables[0].ImageEnd); Homebrew.WriteHbAbiData(Memory, HbAbiDataPosition, Handle); @@ -126,6 +119,11 @@ namespace Ryujinx.Core.OsHle return true; } + private void MapRWMemRegion(long Position, long Size, MemoryType Type) + { + Memory.Manager.Map(Position, Size, (int)Type, AMemoryPerm.RW); + } + public void StopAllThreads() { if (MainThread != null) @@ -188,12 +186,14 @@ namespace Ryujinx.Core.OsHle return -1; } + long Tpidr = MemoryRegions.TlsPagesAddress + TlsSlot * 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.Tpidr = TlsPageAddr + TlsSlot * TlsSize; + Thread.ThreadState.Tpidr = Tpidr; Thread.ThreadState.X0 = (ulong)ArgsPtr; Thread.ThreadState.X1 = (ulong)Handle; Thread.ThreadState.X31 = (ulong)StackTop; @@ -267,7 +267,7 @@ namespace Ryujinx.Core.OsHle private int GetTlsSlot(long Position) { - return (int)((Position - TlsPageAddr) / TlsSize); + return (int)((Position - MemoryRegions.TlsPagesAddress) / TlsSize); } public HThread GetThread(long Tpidr) diff --git a/Ryujinx.Core/OsHle/Svc/SvcHandler.cs b/Ryujinx.Core/OsHle/Svc/SvcHandler.cs index ec53f47ff2..212d30a6c3 100644 --- a/Ryujinx.Core/OsHle/Svc/SvcHandler.cs +++ b/Ryujinx.Core/OsHle/Svc/SvcHandler.cs @@ -17,6 +17,8 @@ namespace Ryujinx.Core.OsHle.Svc private AMemory Memory; private static Random Rng; + + private ulong CurrentHeapSize; public SvcHandler(Switch Ns, Process Process) { @@ -25,6 +27,7 @@ namespace Ryujinx.Core.OsHle.Svc { 0x01, SvcSetHeapSize }, { 0x03, SvcSetMemoryAttribute }, { 0x04, SvcMapMemory }, + { 0x05, SvcUnmapMemory }, { 0x06, SvcQueryMemory }, { 0x07, SvcExitProcess }, { 0x08, SvcCreateThread }, diff --git a/Ryujinx.Core/OsHle/Svc/SvcMemory.cs b/Ryujinx.Core/OsHle/Svc/SvcMemory.cs index 6ca27f16d0..e7559a1408 100644 --- a/Ryujinx.Core/OsHle/Svc/SvcMemory.cs +++ b/Ryujinx.Core/OsHle/Svc/SvcMemory.cs @@ -10,10 +10,21 @@ namespace Ryujinx.Core.OsHle.Svc { uint Size = (uint)ThreadState.X1; - Memory.Manager.SetHeapSize(Size, (int)MemoryType.Heap); + long Position = MemoryRegions.HeapRegionAddress; + + if (Size > CurrentHeapSize) + { + Memory.Manager.Map(Position, Size, (int)MemoryType.Heap, AMemoryPerm.RW); + } + else + { + Memory.Manager.Unmap(Position + Size, (long)CurrentHeapSize - Size); + } + + CurrentHeapSize = Size; ThreadState.X0 = (int)SvcResult.Success; - ThreadState.X1 = (ulong)Memory.Manager.HeapAddr; + ThreadState.X1 = (ulong)Position; } private void SvcSetMemoryAttribute(AThreadState ThreadState) @@ -42,7 +53,30 @@ namespace Ryujinx.Core.OsHle.Svc long Src = (long)ThreadState.X1; long Size = (long)ThreadState.X2; - Memory.Manager.MapMirror(Src, Dst, Size, (int)MemoryType.MappedMemory); + AMemoryMapInfo SrcInfo = Memory.Manager.GetMapInfo(Src); + + Memory.Manager.Map(Dst, Size, (int)MemoryType.MappedMemory, SrcInfo.Perm); + + Memory.Manager.Reprotect(Src, Size, AMemoryPerm.None); + + Memory.Manager.SetAttrBit(Src, Size, 0); + + ThreadState.X0 = (int)SvcResult.Success; + } + + private void SvcUnmapMemory(AThreadState ThreadState) + { + long Dst = (long)ThreadState.X0; + long Src = (long)ThreadState.X1; + long Size = (long)ThreadState.X2; + + AMemoryMapInfo DstInfo = Memory.Manager.GetMapInfo(Dst); + + Memory.Manager.Unmap(Dst, Size, (int)MemoryType.MappedMemory); + + Memory.Manager.Reprotect(Src, Size, DstInfo.Perm); + + Memory.Manager.ClearAttrBit(Src, Size, 0); ThreadState.X0 = (int)SvcResult.Success; } @@ -54,17 +88,22 @@ namespace Ryujinx.Core.OsHle.Svc AMemoryMapInfo MapInfo = Memory.Manager.GetMapInfo(Position); - MemoryInfo Info = new MemoryInfo(MapInfo); + if (MapInfo == null) + { + //TODO: Correct error code. + ThreadState.X0 = ulong.MaxValue; - Memory.WriteInt64(InfoPtr + 0x00, Info.BaseAddress); - Memory.WriteInt64(InfoPtr + 0x08, Info.Size); - Memory.WriteInt32(InfoPtr + 0x10, Info.MemType); - Memory.WriteInt32(InfoPtr + 0x14, Info.MemAttr); - Memory.WriteInt32(InfoPtr + 0x18, Info.MemPerm); - Memory.WriteInt32(InfoPtr + 0x1c, Info.IpcRefCount); - Memory.WriteInt32(InfoPtr + 0x20, Info.DeviceRefCount); - Memory.WriteInt32(InfoPtr + 0x24, Info.Padding); + return; + } + Memory.WriteInt64(InfoPtr + 0x00, MapInfo.Position); + Memory.WriteInt64(InfoPtr + 0x08, MapInfo.Size); + Memory.WriteInt32(InfoPtr + 0x10, MapInfo.Type); + Memory.WriteInt32(InfoPtr + 0x14, MapInfo.Attr); + Memory.WriteInt32(InfoPtr + 0x18, (int)MapInfo.Perm); + Memory.WriteInt32(InfoPtr + 0x1c, 0); + Memory.WriteInt32(InfoPtr + 0x20, 0); + Memory.WriteInt32(InfoPtr + 0x24, 0); //TODO: X1. ThreadState.X0 = (int)SvcResult.Success; @@ -84,7 +123,7 @@ namespace Ryujinx.Core.OsHle.Svc { SharedMem.AddVirtualPosition(Src); - Memory.Manager.MapPhys(Src, Size, (int)MemoryType.SharedMemory, (AMemoryPerm)Perm); + Memory.Manager.Map(Src, Size, (int)MemoryType.SharedMemory, (AMemoryPerm)Perm); ThreadState.X0 = (int)SvcResult.Success; } diff --git a/Ryujinx.Core/OsHle/Svc/SvcSystem.cs b/Ryujinx.Core/OsHle/Svc/SvcSystem.cs index 3b9142c789..51b2e26c6f 100644 --- a/Ryujinx.Core/OsHle/Svc/SvcSystem.cs +++ b/Ryujinx.Core/OsHle/Svc/SvcSystem.cs @@ -11,7 +11,14 @@ namespace Ryujinx.Core.OsHle.Svc { partial class SvcHandler { - private void SvcExitProcess(AThreadState ThreadState) => Ns.Os.ExitProcess(ThreadState.ProcessId); + private const int AllowedCpuIdBitmask = 0b1111; + + private const bool EnableProcessDebugging = false; + + private void SvcExitProcess(AThreadState ThreadState) + { + Ns.Os.ExitProcess(ThreadState.ProcessId); + } private void SvcCloseHandle(AThreadState ThreadState) { @@ -162,79 +169,62 @@ namespace Ryujinx.Core.OsHle.Svc switch (InfoType) { - case 0: ThreadState.X1 = AllowedCpuIdBitmask(); break; - case 2: ThreadState.X1 = GetMapRegionBaseAddr(); break; - case 3: ThreadState.X1 = GetMapRegionSize(); break; - case 4: ThreadState.X1 = GetHeapRegionBaseAddr(); break; - case 5: ThreadState.X1 = GetHeapRegionSize(); break; - case 6: ThreadState.X1 = GetTotalMem(); break; - case 7: ThreadState.X1 = GetUsedMem(); break; - case 8: ThreadState.X1 = IsCurrentProcessBeingDebugged(); break; - case 11: ThreadState.X1 = GetRnd64(); break; - case 12: ThreadState.X1 = GetAddrSpaceBaseAddr(); break; - case 13: ThreadState.X1 = GetAddrSpaceSize(); break; - case 14: ThreadState.X1 = GetMapRegionBaseAddr(); break; - case 15: ThreadState.X1 = GetMapRegionSize(); break; + case 0: + ThreadState.X1 = AllowedCpuIdBitmask; + break; + + case 2: + ThreadState.X1 = MemoryRegions.MapRegionAddress; + break; + + case 3: + ThreadState.X1 = MemoryRegions.MapRegionSize; + break; + + case 4: + ThreadState.X1 = MemoryRegions.HeapRegionAddress; + break; + + case 5: + ThreadState.X1 = CurrentHeapSize; + break; + + case 6: + ThreadState.X1 = MemoryRegions.TotalMemoryAvailable; + break; + + case 7: + ThreadState.X1 = MemoryRegions.TotalMemoryUsed + CurrentHeapSize; + break; + + case 8: + ThreadState.X1 = EnableProcessDebugging ? 1 : 0; + break; + + case 11: + ThreadState.X1 = (ulong)Rng.Next() + ((ulong)Rng.Next() << 32); + break; + + case 12: + ThreadState.X1 = MemoryRegions.AddrSpaceStart; + break; + + case 13: + ThreadState.X1 = MemoryRegions.AddrSpaceSize; + break; + + case 14: + ThreadState.X1 = MemoryRegions.MapRegionAddress; + break; + + case 15: + ThreadState.X1 = MemoryRegions.MapRegionSize; + break; default: throw new NotImplementedException($"SvcGetInfo: {InfoType} {Handle} {InfoId}"); } ThreadState.X0 = (int)SvcResult.Success; } - - private ulong AllowedCpuIdBitmask() - { - return 0xF; //Mephisto value. - } - - private ulong GetMapRegionBaseAddr() - { - return MemoryRegions.MapRegionAddress; - } - - private ulong GetMapRegionSize() - { - return MemoryRegions.MapRegionSize; - } - - private ulong GetHeapRegionBaseAddr() - { - return MemoryRegions.HeapRegionAddress; - } - - private ulong GetHeapRegionSize() - { - return MemoryRegions.HeapRegionSize; - } - - private ulong GetTotalMem() - { - return (ulong)Memory.Manager.GetTotalMemorySize(); - } - - private ulong GetUsedMem() - { - return (ulong)Memory.Manager.GetUsedMemorySize(); - } - - private ulong IsCurrentProcessBeingDebugged() - { - return (ulong)0; - } - - private ulong GetRnd64() - { - return (ulong)Rng.Next() + ((ulong)Rng.Next() << 32); - } - - private ulong GetAddrSpaceBaseAddr() - { - return 0x08000000; - } - - private ulong GetAddrSpaceSize() - { - return AMemoryMgr.AddrSize - GetAddrSpaceBaseAddr(); - } } } diff --git a/Ryujinx.Core/VirtualFs.cs b/Ryujinx.Core/VirtualFs.cs index 0c91111659..195fb6a3c6 100644 --- a/Ryujinx.Core/VirtualFs.cs +++ b/Ryujinx.Core/VirtualFs.cs @@ -5,9 +5,9 @@ namespace Ryujinx.Core { class VirtualFs : IDisposable { - private const string BasePath = "Fs"; - private const string SavesPath = "Saves"; - private const string SdCardPath = "SdCard"; + private const string BasePath = "RyuFs"; + private const string NandPath = "nand"; + private const string SdCardPath = "sdmc"; public Stream RomFs { get; private set; } @@ -35,7 +35,7 @@ namespace Ryujinx.Core public string GetSdCardPath() => MakeDirAndGetFullPath(SdCardPath); - public string GetGameSavesPath() => MakeDirAndGetFullPath(SavesPath); + public string GetGameSavesPath() => MakeDirAndGetFullPath(NandPath); private string MakeDirAndGetFullPath(string Dir) { @@ -56,7 +56,9 @@ namespace Ryujinx.Core public string GetBasePath() { - return Path.Combine(Directory.GetCurrentDirectory(), BasePath); + string AppDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); + + return Path.Combine(AppDataPath, BasePath); } public void Dispose() diff --git a/Ryujinx.Graphics/Gpu/NsGpuMemoryMgr.cs b/Ryujinx.Graphics/Gpu/NsGpuMemoryMgr.cs index 54fabc6719..7f50640d59 100644 --- a/Ryujinx.Graphics/Gpu/NsGpuMemoryMgr.cs +++ b/Ryujinx.Graphics/Gpu/NsGpuMemoryMgr.cs @@ -16,7 +16,7 @@ namespace Ryujinx.Graphics.Gpu private const int PTLvl1Mask = PTLvl1Size - 1; private const int PageMask = PageSize - 1; - private const int PTLvl0Bit = PTPageBits + PTLvl0Bits; + private const int PTLvl0Bit = PTPageBits + PTLvl1Bits; private const int PTLvl1Bit = PTPageBits; private const long PteUnmapped = -1; diff --git a/Ryujinx.Tests/Cpu/CpuTest.cs b/Ryujinx.Tests/Cpu/CpuTest.cs index bf9d90e33d..a56eeb7281 100644 --- a/Ryujinx.Tests/Cpu/CpuTest.cs +++ b/Ryujinx.Tests/Cpu/CpuTest.cs @@ -17,7 +17,6 @@ namespace Ryujinx.Tests.Cpu private long EntryPoint; private IntPtr Ram; - private AMemoryAlloc Allocator; private AMemory Memory; private AThread Thread; @@ -31,9 +30,8 @@ namespace Ryujinx.Tests.Cpu Ram = Marshal.AllocHGlobal((IntPtr)AMemoryMgr.RamSize); ATranslator Translator = new ATranslator(); - Allocator = new AMemoryAlloc(); - Memory = new AMemory(Ram, Allocator); - Memory.Manager.MapPhys(Position, Size, 2, AMemoryPerm.Read | AMemoryPerm.Write | AMemoryPerm.Execute); + Memory = new AMemory(Ram); + Memory.Manager.Map(Position, Size, 2, AMemoryPerm.Read | AMemoryPerm.Write | AMemoryPerm.Execute); Thread = new AThread(Translator, Memory, ThreadPriority.Normal, EntryPoint); } @@ -42,7 +40,6 @@ namespace Ryujinx.Tests.Cpu { Thread = null; Memory = null; - Allocator = null; Marshal.FreeHGlobal(Ram); } From 7f0bee2ff8d6eca1f10a29d5c9e5e7663cb34143 Mon Sep 17 00:00:00 2001 From: Ac_K Date: Wed, 28 Feb 2018 04:31:52 +0100 Subject: [PATCH 02/17] Stubs implementations (#45) Services Bsd, Nifm & SSL stubs implementations Objects IGeneralService, IRequest stubs implementations. Fake-Fix GetAvailableLanguageCodes stub too ^^! --- Ryujinx.Core/OsHle/Services/Bsd/ServiceBsd.cs | 60 +++++++++++++++++++ .../OsHle/Services/Nifm/IGeneralService.cs | 34 +++++++++++ Ryujinx.Core/OsHle/Services/Nifm/IRequest.cs | 49 +++++++++++++++ .../OsHle/Services/Nifm/ServiceNifm.cs | 29 +++++++++ Ryujinx.Core/OsHle/Services/ServiceFactory.cs | 6 ++ Ryujinx.Core/OsHle/Services/Set/ServiceSet.cs | 11 ++-- Ryujinx.Core/OsHle/Services/Ssl/ServiceSsl.cs | 20 +++++++ 7 files changed, 203 insertions(+), 6 deletions(-) create mode 100644 Ryujinx.Core/OsHle/Services/Bsd/ServiceBsd.cs create mode 100644 Ryujinx.Core/OsHle/Services/Nifm/IGeneralService.cs create mode 100644 Ryujinx.Core/OsHle/Services/Nifm/IRequest.cs create mode 100644 Ryujinx.Core/OsHle/Services/Nifm/ServiceNifm.cs create mode 100644 Ryujinx.Core/OsHle/Services/Ssl/ServiceSsl.cs diff --git a/Ryujinx.Core/OsHle/Services/Bsd/ServiceBsd.cs b/Ryujinx.Core/OsHle/Services/Bsd/ServiceBsd.cs new file mode 100644 index 0000000000..fa47d94456 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Bsd/ServiceBsd.cs @@ -0,0 +1,60 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.IpcServices.Bsd +{ + class ServiceBsd : IIpcService + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public ServiceBsd() + { + m_Commands = new Dictionary() + { + { 0, Initialize }, + { 1, StartMonitoring } + }; + } + + //Initialize(u32, u32, u32, u32, u32, u32, u32, u32, u64 pid, u64 transferMemorySize, pid, KObject) -> u32 bsd_errno + public long Initialize(ServiceCtx Context) + { + /* + typedef struct { + u32 version; // Observed 1 on 2.0 LibAppletWeb, 2 on 3.0. + + u32 tcp_tx_buf_size; // Size of the TCP transfer (send) buffer (initial or fixed). + u32 tcp_rx_buf_size; // Size of the TCP recieve buffer (initial or fixed). + u32 tcp_tx_buf_max_size; // Maximum size of the TCP transfer (send) buffer. If it is 0, the size of the buffer is fixed to its initial value. + u32 tcp_rx_buf_max_size; // Maximum size of the TCP receive buffer. If it is 0, the size of the buffer is fixed to its initial value. + + u32 udp_tx_buf_size; // Size of the UDP transfer (send) buffer (typically 0x2400 bytes). + u32 udp_rx_buf_size; // Size of the UDP receive buffer (typically 0xA500 bytes). + + u32 sb_efficiency; // Number of buffers for each socket (standard values range from 1 to 8). + } BsdBufferConfig; + */ + + long Pid = Context.RequestData.ReadInt64(); + long TransferMemorySize = Context.RequestData.ReadInt64(); + + // Two other args are unknown! + + Context.ResponseData.Write(0); + + //Todo: Stub + + return 0; + } + + //StartMonitoring(u64, pid) + public long StartMonitoring(ServiceCtx Context) + { + //Todo: Stub + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Nifm/IGeneralService.cs b/Ryujinx.Core/OsHle/Services/Nifm/IGeneralService.cs new file mode 100644 index 0000000000..c31ee36b20 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Nifm/IGeneralService.cs @@ -0,0 +1,34 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; + +namespace Ryujinx.Core.OsHle.IpcServices.Nifm +{ + class IGeneralService : IIpcService + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public IGeneralService() + { + m_Commands = new Dictionary() + { + { 4, CreateRequest } + }; + } + + //CreateRequest(i32) + public long CreateRequest(ServiceCtx Context) + { + int Unknown = Context.RequestData.ReadInt32(); + + MakeObject(Context, new IRequest()); + + //Todo: Stub + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Nifm/IRequest.cs b/Ryujinx.Core/OsHle/Services/Nifm/IRequest.cs new file mode 100644 index 0000000000..6110e5fbe2 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Nifm/IRequest.cs @@ -0,0 +1,49 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.IpcServices.Nifm +{ + class IRequest : IIpcService + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public IRequest() + { + m_Commands = new Dictionary() + { + { 0, GetRequestState }, + { 1, GetResult }, + { 2, GetSystemEventReadableHandles } + }; + } + + // -> i32 + public long GetRequestState(ServiceCtx Context) + { + Context.ResponseData.Write(0); + + //Todo: Stub + + return 0; + } + + public long GetResult(ServiceCtx Context) + { + //Todo: Stub + + return 0; + } + + //GetSystemEventReadableHandles() -> (KObject, KObject) + public long GetSystemEventReadableHandles(ServiceCtx Context) + { + Context.Response.HandleDesc = IpcHandleDesc.MakeMove(0xbadcafe); + + //Todo: Stub + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Nifm/ServiceNifm.cs b/Ryujinx.Core/OsHle/Services/Nifm/ServiceNifm.cs new file mode 100644 index 0000000000..7e183389b2 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Nifm/ServiceNifm.cs @@ -0,0 +1,29 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; + +namespace Ryujinx.Core.OsHle.IpcServices.Nifm +{ + class ServiceNifm : IIpcService + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public ServiceNifm() + { + m_Commands = new Dictionary() + { + { 4, CreateGeneralServiceOld } + }; + } + + public long CreateGeneralServiceOld(ServiceCtx Context) + { + MakeObject(Context, new IGeneralService()); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/ServiceFactory.cs b/Ryujinx.Core/OsHle/Services/ServiceFactory.cs index 54fa38ab78..aae624534e 100644 --- a/Ryujinx.Core/OsHle/Services/ServiceFactory.cs +++ b/Ryujinx.Core/OsHle/Services/ServiceFactory.cs @@ -2,16 +2,19 @@ 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.Sm; +using Ryujinx.Core.OsHle.IpcServices.Ssl; using Ryujinx.Core.OsHle.IpcServices.Time; using Ryujinx.Core.OsHle.IpcServices.Vi; using System; @@ -31,16 +34,19 @@ namespace Ryujinx.Core.OsHle.IpcServices case "appletOE": return new ServiceAppletOE(); case "audout:u": return new ServiceAudOut(); case "audren:u": return new ServiceAudRen(); + 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 "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(); diff --git a/Ryujinx.Core/OsHle/Services/Set/ServiceSet.cs b/Ryujinx.Core/OsHle/Services/Set/ServiceSet.cs index 05e409b0d1..c60e1712aa 100644 --- a/Ryujinx.Core/OsHle/Services/Set/ServiceSet.cs +++ b/Ryujinx.Core/OsHle/Services/Set/ServiceSet.cs @@ -1,5 +1,6 @@ using ChocolArm64.Memory; using Ryujinx.Core.OsHle.Ipc; +using System; using System.Collections.Generic; namespace Ryujinx.Core.OsHle.IpcServices.Set @@ -30,12 +31,10 @@ namespace Ryujinx.Core.OsHle.IpcServices.Set short Size = Context.Request.RecvListBuff[0].Size; //This should return an array of ints with values matching the LanguageCode enum. - byte[] Data = new byte[Size]; - - Data[0] = 0; - Data[1] = 1; - - AMemoryHelper.WriteBytes(Context.Memory, Position, Data); + foreach (long value in new long[] { 0L, 1L, 2L, 3L, 4L, 5L, 6L, 7L }) + { + AMemoryHelper.WriteBytes(Context.Memory, Position += 8, BitConverter.GetBytes(value)); + } } Context.ResponseData.Write(LangCodesCount); diff --git a/Ryujinx.Core/OsHle/Services/Ssl/ServiceSsl.cs b/Ryujinx.Core/OsHle/Services/Ssl/ServiceSsl.cs new file mode 100644 index 0000000000..23934b1405 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Ssl/ServiceSsl.cs @@ -0,0 +1,20 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.IpcServices.Ssl +{ + class ServiceSsl : IIpcService + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public ServiceSsl() + { + m_Commands = new Dictionary() + { + //{ 0, Function } + }; + } + } +} \ No newline at end of file From 424e0459403fd7ffeb8980b16a6a9e3a1201c5e6 Mon Sep 17 00:00:00 2001 From: Ac_K Date: Wed, 28 Feb 2018 21:58:04 +0100 Subject: [PATCH 03/17] More stubs (#47) * Stubs implementations Services Bsd, Nifm & SSL stubs implementations Objects IGeneralService, IRequest stubs implementations. Fake-Fix GetAvailableLanguageCodes stub too ^^! * More stubs - Fix SvcGetInfo loops by gdkchan. - Implement stub for Sfdnsres service. - Add more stubs for Bsd service. * Update ServiceSfdnsres.cs --- Ryujinx.Core/OsHle/MemoryRegions.cs | 2 +- Ryujinx.Core/OsHle/Services/Bsd/ServiceBsd.cs | 40 ++++++++++++++++++- Ryujinx.Core/OsHle/Services/ServiceFactory.cs | 2 + .../Services/Sfdnsres/ServiceSfdnsres.cs | 20 ++++++++++ 4 files changed, 61 insertions(+), 3 deletions(-) create mode 100644 Ryujinx.Core/OsHle/Services/Sfdnsres/ServiceSfdnsres.cs diff --git a/Ryujinx.Core/OsHle/MemoryRegions.cs b/Ryujinx.Core/OsHle/MemoryRegions.cs index 3b69042607..e362ba9fd7 100644 --- a/Ryujinx.Core/OsHle/MemoryRegions.cs +++ b/Ryujinx.Core/OsHle/MemoryRegions.cs @@ -7,7 +7,7 @@ namespace Ryujinx.Core.OsHle public const long AddrSpaceStart = 0x08000000; public const long MapRegionAddress = 0x10000000; - public const long MapRegionSize = 0x40000000; + public const long MapRegionSize = 0x10000000; public const long MainStackSize = 0x100000; diff --git a/Ryujinx.Core/OsHle/Services/Bsd/ServiceBsd.cs b/Ryujinx.Core/OsHle/Services/Bsd/ServiceBsd.cs index fa47d94456..b594441272 100644 --- a/Ryujinx.Core/OsHle/Services/Bsd/ServiceBsd.cs +++ b/Ryujinx.Core/OsHle/Services/Bsd/ServiceBsd.cs @@ -13,8 +13,11 @@ namespace Ryujinx.Core.OsHle.IpcServices.Bsd { m_Commands = new Dictionary() { - { 0, Initialize }, - { 1, StartMonitoring } + { 0, Initialize }, + { 1, StartMonitoring }, + { 2, Socket }, + { 10, Send }, + { 14, Connect } }; } @@ -56,5 +59,38 @@ namespace Ryujinx.Core.OsHle.IpcServices.Bsd return 0; } + + //Socket(u32 domain, u32 type, u32 protocol) -> (i32 ret, u32 bsd_errno) + public long Socket(ServiceCtx Context) + { + Context.ResponseData.Write(0); + Context.ResponseData.Write(0); + + //Todo: Stub + + return 0; + } + + //Connect(u32 socket, buffer) -> (i32 ret, u32 bsd_errno) + public long Connect(ServiceCtx Context) + { + Context.ResponseData.Write(0); + Context.ResponseData.Write(0); + + //Todo: Stub + + return 0; + } + + //Send(u32 socket, u32 flags, buffer) -> (i32 ret, u32 bsd_errno) + public long Send(ServiceCtx Context) + { + Context.ResponseData.Write(0); + Context.ResponseData.Write(0); + + //Todo: Stub + + return 0; + } } } \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/ServiceFactory.cs b/Ryujinx.Core/OsHle/Services/ServiceFactory.cs index aae624534e..c5da717e78 100644 --- a/Ryujinx.Core/OsHle/Services/ServiceFactory.cs +++ b/Ryujinx.Core/OsHle/Services/ServiceFactory.cs @@ -13,6 +13,7 @@ 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; @@ -45,6 +46,7 @@ namespace Ryujinx.Core.OsHle.IpcServices case "pctl:a": return new ServicePctl(); case "pl:u": return new ServicePl(); case "set": return new ServiceSet(); + case "sfdnsres": return new ServiceSfdnsres(); case "sm:": return new ServiceSm(); case "ssl": return new ServiceSsl(); case "time:s": return new ServiceTime(); diff --git a/Ryujinx.Core/OsHle/Services/Sfdnsres/ServiceSfdnsres.cs b/Ryujinx.Core/OsHle/Services/Sfdnsres/ServiceSfdnsres.cs new file mode 100644 index 0000000000..f110ae736f --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Sfdnsres/ServiceSfdnsres.cs @@ -0,0 +1,20 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.IpcServices.Sfdnsres +{ + class ServiceSfdnsres : IIpcService + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public ServiceSfdnsres() + { + m_Commands = new Dictionary() + { + //{ 0, Function } + }; + } + } +} From eacd432387677dc0513255f8c3661f5c3ef05d65 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Wed, 28 Feb 2018 19:21:04 -0300 Subject: [PATCH 04/17] Fix wrong rotation direction on nvflinger --- Ryujinx.Core/OsHle/Services/Vi/NvFlinger.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Ryujinx.Core/OsHle/Services/Vi/NvFlinger.cs b/Ryujinx.Core/OsHle/Services/Vi/NvFlinger.cs index 85a06cea41..3e45c44196 100644 --- a/Ryujinx.Core/OsHle/Services/Vi/NvFlinger.cs +++ b/Ryujinx.Core/OsHle/Services/Vi/NvFlinger.cs @@ -274,7 +274,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android if (BufferQueue[Slot].Transform.HasFlag(HalTransform.Rotate90)) { - Rotate = MathF.PI * 0.5f; + Rotate = -MathF.PI * 0.5f; } byte* Fb = (byte*)Context.Ns.Ram + NvMap.Address; From 5d8a615c21eff7888ff4e36c122123560bcb0886 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Wed, 28 Feb 2018 23:37:40 -0300 Subject: [PATCH 05/17] Enable hardware frame buffer texture scaling --- Ryujinx.Core/OsHle/Services/Vi/NvFlinger.cs | 47 +++++++++++++++++-- Ryujinx.Graphics/Gal/IGalRenderer.cs | 13 ++++- Ryujinx.Graphics/Gal/OpenGL/FbVtxShader.glsl | 6 ++- Ryujinx.Graphics/Gal/OpenGL/FrameBuffer.cs | 6 ++- Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs | 15 ++++-- 5 files changed, 75 insertions(+), 12 deletions(-) diff --git a/Ryujinx.Core/OsHle/Services/Vi/NvFlinger.cs b/Ryujinx.Core/OsHle/Services/Vi/NvFlinger.cs index 3e45c44196..b745867e92 100644 --- a/Ryujinx.Core/OsHle/Services/Vi/NvFlinger.cs +++ b/Ryujinx.Core/OsHle/Services/Vi/NvFlinger.cs @@ -35,12 +35,22 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android Acquired } + private struct Rect + { + public int Top; + public int Left; + public int Right; + public int Bottom; + } + private struct BufferEntry { public BufferState State; public HalTransform Transform; + public Rect Crop; + public GbpBuffer Data; } @@ -168,6 +178,11 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android BufferQueue[Slot].Transform = (HalTransform)Transform; + BufferQueue[Slot].Crop.Top = CropTop; + BufferQueue[Slot].Crop.Left = CropLeft; + BufferQueue[Slot].Crop.Right = CropRight; + BufferQueue[Slot].Crop.Bottom = CropBottom; + BufferQueue[Slot].State = BufferState.Queued; SendFrameBuffer(Context, Slot); @@ -256,20 +271,44 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android return; } - BufferQueue[Slot].State = BufferState.Acquired; + BufferQueue[Slot].State = BufferState.Acquired; + + Rect Crop = BufferQueue[Slot].Crop; + + int RealWidth = FbWidth; + int RealHeight = FbHeight; float ScaleX = 1; float ScaleY = 1; + float OffsX = 0; + float OffsY = 0; + + if (Crop.Right != 0 && + Crop.Bottom != 0) + { + RealWidth = Crop.Right - Crop.Left; + RealHeight = Crop.Bottom - Crop.Top; + + ScaleX = (float)FbWidth / RealWidth; + ScaleY = (float)FbHeight / RealHeight; + + OffsX = -(float)Crop.Left / Crop.Right; + OffsY = -(float)Crop.Top / Crop.Bottom; + + OffsX += ScaleX - 1; + OffsY += ScaleY - 1; + } + float Rotate = 0; if (BufferQueue[Slot].Transform.HasFlag(HalTransform.FlipX)) { - ScaleX = -1; + ScaleX = -ScaleX; } if (BufferQueue[Slot].Transform.HasFlag(HalTransform.FlipY)) { - ScaleY = -1; + ScaleY = -ScaleY; } if (BufferQueue[Slot].Transform.HasFlag(HalTransform.Rotate90)) @@ -287,6 +326,8 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android FbHeight, ScaleX, ScaleY, + OffsX, + OffsY, Rotate); BufferQueue[Slot].State = BufferState.Free; diff --git a/Ryujinx.Graphics/Gal/IGalRenderer.cs b/Ryujinx.Graphics/Gal/IGalRenderer.cs index 5854c54a6b..83d2c699f8 100644 --- a/Ryujinx.Graphics/Gal/IGalRenderer.cs +++ b/Ryujinx.Graphics/Gal/IGalRenderer.cs @@ -10,9 +10,20 @@ namespace Ryujinx.Graphics.Gal void InitializeFrameBuffer(); void Render(); void SetWindowSize(int Width, int Height); - void SetFrameBuffer(byte* Fb, int Width, int Height, float SX, float SY, float R); + void SetFrameBuffer( + byte* Fb, + int Width, + int Height, + float ScaleX, + float ScaleY, + float OffsX, + float OffsY, + float Rotate); + void SendVertexBuffer(int Index, byte[] Buffer, int Stride, GalVertexAttrib[] Attribs); + void SendR8G8B8A8Texture(int Index, byte[] Buffer, int Width, int Height); + void BindTexture(int Index); } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/OpenGL/FbVtxShader.glsl b/Ryujinx.Graphics/Gal/OpenGL/FbVtxShader.glsl index 933fa6aa97..35d560c09b 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/FbVtxShader.glsl +++ b/Ryujinx.Graphics/Gal/OpenGL/FbVtxShader.glsl @@ -2,8 +2,9 @@ precision highp float; -uniform vec2 window_size; uniform mat2 transform; +uniform vec2 window_size; +uniform vec2 offset; layout(location = 0) in vec2 in_position; layout(location = 1) in vec2 in_tex_coord; @@ -22,5 +23,6 @@ vec2 get_scale_ratio(void) { void main(void) { tex_coord = in_tex_coord; - gl_Position = vec4((transform * in_position) * get_scale_ratio(), 0, 1); + vec2 t_pos = (transform * in_position) + offset; + gl_Position = vec4(t_pos * get_scale_ratio(), 0, 1); } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/OpenGL/FrameBuffer.cs b/Ryujinx.Graphics/Gal/OpenGL/FrameBuffer.cs index c66c0cb754..7dc4bffe34 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/FrameBuffer.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/FrameBuffer.cs @@ -135,7 +135,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL GL.BindVertexArray(0); } - public unsafe void Set(byte* Fb, int Width, int Height, Matrix2 Transform) + public unsafe void Set(byte* Fb, int Width, int Height, Matrix2 Transform, Vector2 Offs) { if (Fb == null) { @@ -172,6 +172,10 @@ namespace Ryujinx.Graphics.Gal.OpenGL int WindowSizeUniformLocation = GL.GetUniformLocation(PrgShaderHandle, "window_size"); GL.Uniform2(WindowSizeUniformLocation, new Vector2(WindowWidth, WindowHeight)); + + int OffsetUniformLocation = GL.GetUniformLocation(PrgShaderHandle, "offset"); + + GL.Uniform2(OffsetUniformLocation, Offs); } public void Render() diff --git a/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs b/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs index 5ae5e22597..bdedfc1a87 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs @@ -1,6 +1,7 @@ using OpenTK; using OpenTK.Graphics.OpenGL; using System; +using System.Collections.Concurrent; using System.Collections.Generic; namespace Ryujinx.Graphics.Gal.OpenGL @@ -24,7 +25,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL private Texture[] Textures; - private Queue ActionsQueue; + private ConcurrentQueue ActionsQueue; private FrameBuffer FbRenderer; @@ -34,7 +35,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL Textures = new Texture[8]; - ActionsQueue = new Queue(); + ActionsQueue = new ConcurrentQueue(); } public void InitializeFrameBuffer() @@ -51,9 +52,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL { int Count = ActionsQueue.Count; - while (Count-- > 0) + while (Count-- > 0 && ActionsQueue.TryDequeue(out Action RenderAction)) { - ActionsQueue.Dequeue()(); + RenderAction(); } } @@ -86,6 +87,8 @@ namespace Ryujinx.Graphics.Gal.OpenGL int Height, float ScaleX, float ScaleY, + float OffsX, + float OffsY, float Rotate) { Matrix2 Transform; @@ -93,7 +96,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL Transform = Matrix2.CreateScale(ScaleX, ScaleY); Transform *= Matrix2.CreateRotation(Rotate); - FbRenderer.Set(Fb, Width, Height, Transform); + Vector2 Offs = new Vector2(OffsX, OffsY); + + FbRenderer.Set(Fb, Width, Height, Transform, Offs); } public void SendVertexBuffer(int Index, byte[] Buffer, int Stride, GalVertexAttrib[] Attribs) From 65e04e9854fd5d7292ba235b05f80cecd89abec2 Mon Sep 17 00:00:00 2001 From: emmauss Date: Thu, 1 Mar 2018 22:23:55 +0200 Subject: [PATCH 06/17] stub set_sys (#49) --- Ryujinx.Core/OsHle/Services/ServiceFactory.cs | 1 + .../OsHle/Services/Set/ServiceSetSys.cs | 35 +++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 Ryujinx.Core/OsHle/Services/Set/ServiceSetSys.cs diff --git a/Ryujinx.Core/OsHle/Services/ServiceFactory.cs b/Ryujinx.Core/OsHle/Services/ServiceFactory.cs index c5da717e78..31c8aa2c86 100644 --- a/Ryujinx.Core/OsHle/Services/ServiceFactory.cs +++ b/Ryujinx.Core/OsHle/Services/ServiceFactory.cs @@ -46,6 +46,7 @@ namespace Ryujinx.Core.OsHle.IpcServices 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(); diff --git a/Ryujinx.Core/OsHle/Services/Set/ServiceSetSys.cs b/Ryujinx.Core/OsHle/Services/Set/ServiceSetSys.cs new file mode 100644 index 0000000000..68b3035426 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Set/ServiceSetSys.cs @@ -0,0 +1,35 @@ +using ChocolArm64.Memory; +using Ryujinx.Core.OsHle.Ipc; +using System; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.IpcServices.Set +{ + class ServiceSetSys : IIpcService + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public ServiceSetSys() + { + m_Commands = new Dictionary() + { + { 23, GetColorSetId }, + { 24, SetColorSetId } + }; + } + + public static long GetColorSetId(ServiceCtx Context) + { + //Use white system theme + Context.ResponseData.Write(1); + return 0; + } + + public static long SetColorSetId(ServiceCtx Context) + { + return 0; + } + } +} \ No newline at end of file From 1d71e33171f78fb40b097108fbd5915f18c608c4 Mon Sep 17 00:00:00 2001 From: Ac_K Date: Fri, 2 Mar 2018 05:06:05 +0100 Subject: [PATCH 07/17] Update IAudioOut.cs (#51) Little improvements, sound looks a little better... --- Ryujinx.Core/OsHle/Services/Aud/IAudioOut.cs | 66 +++++++++++--------- 1 file changed, 38 insertions(+), 28 deletions(-) diff --git a/Ryujinx.Core/OsHle/Services/Aud/IAudioOut.cs b/Ryujinx.Core/OsHle/Services/Aud/IAudioOut.cs index a45b23ccd5..0562d4b9a5 100644 --- a/Ryujinx.Core/OsHle/Services/Aud/IAudioOut.cs +++ b/Ryujinx.Core/OsHle/Services/Aud/IAudioOut.cs @@ -1,4 +1,4 @@ -using ChocolArm64.Memory; +using ChocolArm64.Memory; using Ryujinx.Core.OsHle.Handles; using Ryujinx.Core.OsHle.Ipc; using OpenTK.Audio; @@ -39,7 +39,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud //IAudioOut private AudioOutState State = AudioOutState.Stopped; - private Queue KeysQueue = new Queue(); + private Queue BufferIdQueue = new Queue(); //OpenAL private bool OpenALInstalled = true; @@ -71,7 +71,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud OpenALInstalled = false; } - if (OpenALInstalled) AL.Listener(ALListenerf.Gain, (float)8.0); //Add more gain to it + if (OpenALInstalled) AL.Listener(ALListenerf.Gain, 8.0f); //Add more gain to it } return 0; @@ -88,6 +88,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud AL.SourceStop(Source); AL.DeleteSource(Source); + AL.DeleteBuffers(1, ref Buffer); } State = AudioOutState.Stopped; } @@ -99,9 +100,8 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud { long BufferId = Context.RequestData.ReadInt64(); - KeysQueue.Enqueue(BufferId); - byte[] AudioOutBuffer = AMemoryHelper.ReadBytes(Context.Memory, Context.Request.SendBuff[0].Position, sizeof(long) * 5); + using (MemoryStream MS = new MemoryStream(AudioOutBuffer)) { BinaryReader Reader = new BinaryReader(MS); @@ -111,18 +111,34 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud long SizeDataInSampleBuffer = Reader.ReadInt64(); long OffsetDataInSampleBuffer = Reader.ReadInt64(); - byte[] AudioSampleBuffer = AMemoryHelper.ReadBytes(Context.Memory, PointerSampleBuffer + OffsetDataInSampleBuffer, (int)SizeDataInSampleBuffer); - - if (OpenALInstalled) + if (SizeDataInSampleBuffer > 0) { - if (AudioCtx == null) //Needed to call the instance of AudioContext() - return 0; + BufferIdQueue.Enqueue(BufferId); - Buffer = AL.GenBuffer(); - AL.BufferData(Buffer, ALFormat.Stereo16, AudioSampleBuffer, AudioSampleBuffer.Length, 48000); + byte[] AudioSampleBuffer = AMemoryHelper.ReadBytes(Context.Memory, PointerSampleBuffer + OffsetDataInSampleBuffer, (int)SizeDataInSampleBuffer); - Source = AL.GenSource(); - AL.SourceQueueBuffer(Source, Buffer); + if (OpenALInstalled) + { + if (AudioCtx == null) //Needed to call the instance of AudioContext() + return 0; + + Source = AL.GenSource(); + Buffer = AL.GenBuffer(); + + AL.BufferData(Buffer, ALFormat.Stereo16, AudioSampleBuffer, AudioSampleBuffer.Length, 48000); + AL.SourceQueueBuffer(Source, Buffer); + AL.SourcePlay(Source); + + int State; + + do AL.GetSource(Source, ALGetSourcei.SourceState, out State); + while ((ALSourceState)State == ALSourceState.Playing); + + AL.SourceStop(Source); + AL.SourceUnqueueBuffer(Buffer); + AL.DeleteSource(Source); + AL.DeleteBuffers(1, ref Buffer); + } } } @@ -140,25 +156,19 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud public long GetReleasedAudioOutBuffer(ServiceCtx Context) { - long TempKey = 0; + int ReleasedBuffersCount = 0; - if (KeysQueue.Count > 0) TempKey = KeysQueue.Dequeue(); - - AMemoryHelper.WriteBytes(Context.Memory, Context.Request.ReceiveBuff[0].Position, BitConverter.GetBytes(TempKey)); - - int ReleasedBuffersCount = 1; - Context.ResponseData.Write(ReleasedBuffersCount); - - if (OpenALInstalled) + for(int i = 0; i < BufferIdQueue.Count; i++) { - if (AudioCtx == null) //Needed to call the instance of AudioContext() - return 0; + long BufferId = BufferIdQueue.Dequeue(); - AL.SourcePlay(Source); - int[] FreeBuffers = AL.SourceUnqueueBuffers(Source, 1); - AL.DeleteBuffers(FreeBuffers); + AMemoryHelper.WriteBytes(Context.Memory, Context.Request.ReceiveBuff[0].Position + (8 * i), BitConverter.GetBytes(BufferId)); + + ReleasedBuffersCount++; } + Context.ResponseData.Write(ReleasedBuffersCount); + return 0; } From f39a864050589ac7e757a9d72b46ac693125b382 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Fri, 2 Mar 2018 19:21:54 -0300 Subject: [PATCH 08/17] Add EXT, CMTST (vector) and UMULL (vector) instructions --- ChocolArm64/AOpCodeTable.cs | 3 ++ ChocolArm64/Decoder/AOpCodeSimdExt.cs | 14 +++++++ .../Instruction/AInstEmitSimdArithmetic.cs | 5 +++ ChocolArm64/Instruction/AInstEmitSimdCmp.cs | 39 +++++++++++++++++++ ChocolArm64/Instruction/AInstEmitSimdMove.cs | 25 ++++++++++++ 5 files changed, 86 insertions(+) create mode 100644 ChocolArm64/Decoder/AOpCodeSimdExt.cs diff --git a/ChocolArm64/AOpCodeTable.cs b/ChocolArm64/AOpCodeTable.cs index 14ca231baf..470b70e04e 100644 --- a/ChocolArm64/AOpCodeTable.cs +++ b/ChocolArm64/AOpCodeTable.cs @@ -142,11 +142,13 @@ namespace ChocolArm64 Set("0>101110<<1xxxxx001111xxxxxxxxxx", AInstEmit.Cmhs_V, typeof(AOpCodeSimdReg)); Set("0>101110<<100000100110xxxxxxxxxx", AInstEmit.Cmle_V, typeof(AOpCodeSimd)); Set("0>001110<<100000101010xxxxxxxxxx", AInstEmit.Cmlt_V, typeof(AOpCodeSimd)); + Set("0>001110<<1xxxxx100011xxxxxxxxxx", AInstEmit.Cmtst_V, typeof(AOpCodeSimdReg)); Set("0x00111000100000010110xxxxxxxxxx", AInstEmit.Cnt_V, typeof(AOpCodeSimd)); Set("0x001110000xxxxx000011xxxxxxxxxx", AInstEmit.Dup_Gp, typeof(AOpCodeSimdIns)); Set("01011110000xxxxx000001xxxxxxxxxx", AInstEmit.Dup_S, typeof(AOpCodeSimdIns)); Set("0x001110000xxxxx000001xxxxxxxxxx", AInstEmit.Dup_V, typeof(AOpCodeSimdIns)); Set("0x101110001xxxxx000111xxxxxxxxxx", AInstEmit.Eor_V, typeof(AOpCodeSimdReg)); + Set("0>101110000xxxxx0101110<<1xxxxx010001xxxxxxxxxx", AInstEmit.Ushl_V, typeof(AOpCodeSimdReg)); Set("0x10111100>>>xxx101001xxxxxxxxxx", AInstEmit.Ushll_V, typeof(AOpCodeSimdShImm)); Set("011111110>>>>xxx000001xxxxxxxxxx", AInstEmit.Ushr_S, typeof(AOpCodeSimdShImm)); diff --git a/ChocolArm64/Decoder/AOpCodeSimdExt.cs b/ChocolArm64/Decoder/AOpCodeSimdExt.cs new file mode 100644 index 0000000000..cf22d6546f --- /dev/null +++ b/ChocolArm64/Decoder/AOpCodeSimdExt.cs @@ -0,0 +1,14 @@ +using ChocolArm64.Instruction; + +namespace ChocolArm64.Decoder +{ + class AOpCodeSimdExt : AOpCodeSimdReg + { + public int Imm4 { get; private set; } + + public AOpCodeSimdExt(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) + { + int Imm4 = (OpCode >> 11) & 0xf; + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Instruction/AInstEmitSimdArithmetic.cs b/ChocolArm64/Instruction/AInstEmitSimdArithmetic.cs index e790d67865..9c1bc28626 100644 --- a/ChocolArm64/Instruction/AInstEmitSimdArithmetic.cs +++ b/ChocolArm64/Instruction/AInstEmitSimdArithmetic.cs @@ -406,5 +406,10 @@ namespace ChocolArm64.Instruction { EmitVectorWidenRmBinaryOpZx(Context, () => Context.Emit(OpCodes.Add)); } + + public static void Umull_V(AILEmitterCtx Context) + { + EmitVectorWidenRnRmBinaryOpZx(Context, () => Context.Emit(OpCodes.Mul)); + } } } \ No newline at end of file diff --git a/ChocolArm64/Instruction/AInstEmitSimdCmp.cs b/ChocolArm64/Instruction/AInstEmitSimdCmp.cs index 97ccf0ab4e..76861b73ba 100644 --- a/ChocolArm64/Instruction/AInstEmitSimdCmp.cs +++ b/ChocolArm64/Instruction/AInstEmitSimdCmp.cs @@ -46,6 +46,45 @@ namespace ChocolArm64.Instruction EmitVectorCmp(Context, OpCodes.Blt_S); } + public static void Cmtst_V(AILEmitterCtx Context) + { + AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; + + int Bytes = Context.CurrOp.GetBitsCount() >> 3; + + ulong SzMask = ulong.MaxValue >> (64 - (8 << Op.Size)); + + for (int Index = 0; Index < (Bytes >> Op.Size); Index++) + { + EmitVectorExtractZx(Context, Op.Rn, Index, Op.Size); + EmitVectorExtractZx(Context, Op.Rm, Index, Op.Size); + + AILLabel LblTrue = new AILLabel(); + AILLabel LblEnd = new AILLabel(); + + Context.Emit(OpCodes.And); + + Context.EmitLdc_I4(0); + + Context.Emit(OpCodes.Bne_Un_S, LblTrue); + + EmitVectorInsert(Context, Op.Rd, Index, Op.Size, 0); + + Context.Emit(OpCodes.Br_S, LblEnd); + + Context.MarkLabel(LblTrue); + + EmitVectorInsert(Context, Op.Rd, Index, Op.Size, (long)SzMask); + + Context.MarkLabel(LblEnd); + } + + if (Op.RegisterSize == ARegisterSize.SIMD64) + { + EmitVectorZeroUpper(Context, Op.Rd); + } + } + public static void Fccmp_S(AILEmitterCtx Context) { AOpCodeSimdFcond Op = (AOpCodeSimdFcond)Context.CurrOp; diff --git a/ChocolArm64/Instruction/AInstEmitSimdMove.cs b/ChocolArm64/Instruction/AInstEmitSimdMove.cs index aabb8f3470..a4e533709e 100644 --- a/ChocolArm64/Instruction/AInstEmitSimdMove.cs +++ b/ChocolArm64/Instruction/AInstEmitSimdMove.cs @@ -57,6 +57,31 @@ namespace ChocolArm64.Instruction } } + public static void Ext_V(AILEmitterCtx Context) + { + AOpCodeSimdExt Op = (AOpCodeSimdExt)Context.CurrOp; + + int Bytes = Context.CurrOp.GetBitsCount() >> 3; + + for (int Index = 0; Index < Bytes; Index++) + { + int Position = Op.Imm4 + Index; + + int Reg = Position < Bytes ? Op.Rn : Op.Rm; + + Position &= Bytes - 1; + + EmitVectorExtractZx(Context, Reg, Position, 0); + + EmitVectorInsert(Context, Op.Rd, Index, 0); + } + + if (Op.RegisterSize == ARegisterSize.SIMD64) + { + EmitVectorZeroUpper(Context, Op.Rd); + } + } + public static void Fcsel_S(AILEmitterCtx Context) { AOpCodeSimdFcond Op = (AOpCodeSimdFcond)Context.CurrOp; From 829b1b1cc0a7dced1946500c1f27b4a7277ddb26 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Fri, 2 Mar 2018 20:03:28 -0300 Subject: [PATCH 09/17] Add REV64 (vector) instruction --- ChocolArm64/AOpCodeTable.cs | 1 + ChocolArm64/Instruction/AInstEmitSimdLogical.cs | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/ChocolArm64/AOpCodeTable.cs b/ChocolArm64/AOpCodeTable.cs index 470b70e04e..13df4d9868 100644 --- a/ChocolArm64/AOpCodeTable.cs +++ b/ChocolArm64/AOpCodeTable.cs @@ -230,6 +230,7 @@ namespace ChocolArm64 Set("0x10111000100000010110xxxxxxxxxx", AInstEmit.Not_V, typeof(AOpCodeSimd)); Set("0x001110101xxxxx000111xxxxxxxxxx", AInstEmit.Orr_V, typeof(AOpCodeSimdReg)); Set("0x00111100000xxx< Context.Emit(OpCodes.Or)); } + + public static void Rev64_V(AILEmitterCtx Context) + { + Action Emit = () => + { + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.ReverseBits64)); + }; + + EmitVectorUnaryOpZx(Context, Emit); + } } } \ No newline at end of file From efef605b260119642fa023c8488fb3ff4501cafd Mon Sep 17 00:00:00 2001 From: gdkchan Date: Fri, 2 Mar 2018 20:24:16 -0300 Subject: [PATCH 10/17] Fix REV64 (vector) instruction --- ChocolArm64/AOpCodeTable.cs | 2 +- .../Instruction/AInstEmitSimdLogical.cs | 26 ++++++++++++++----- ChocolArm64/Instruction/ASoftFallback.cs | 2 +- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/ChocolArm64/AOpCodeTable.cs b/ChocolArm64/AOpCodeTable.cs index 13df4d9868..e192f5ec5e 100644 --- a/ChocolArm64/AOpCodeTable.cs +++ b/ChocolArm64/AOpCodeTable.cs @@ -230,7 +230,7 @@ namespace ChocolArm64 Set("0x10111000100000010110xxxxxxxxxx", AInstEmit.Not_V, typeof(AOpCodeSimd)); Set("0x001110101xxxxx000111xxxxxxxxxx", AInstEmit.Orr_V, typeof(AOpCodeSimdReg)); Set("0x00111100000xxx< + AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; + + int Bytes = Context.CurrOp.GetBitsCount() >> 3; + + int Elems = Bytes >> Op.Size; + + int RevIndex = Elems - 1; + + for (int Index = 0; Index < (Bytes >> Op.Size); Index++) { - ASoftFallback.EmitCall(Context, nameof(ASoftFallback.ReverseBits64)); - }; - - EmitVectorUnaryOpZx(Context, Emit); + EmitVectorExtractZx(Context, Op.Rn, RevIndex--, Op.Size); + + EmitVectorInsert(Context, Op.Rd, Index, Op.Size); + } + + if (Op.RegisterSize == ARegisterSize.SIMD64) + { + EmitVectorZeroUpper(Context, Op.Rd); + } } } } \ No newline at end of file diff --git a/ChocolArm64/Instruction/ASoftFallback.cs b/ChocolArm64/Instruction/ASoftFallback.cs index 5127182ddc..797d815736 100644 --- a/ChocolArm64/Instruction/ASoftFallback.cs +++ b/ChocolArm64/Instruction/ASoftFallback.cs @@ -75,7 +75,7 @@ namespace ChocolArm64.Instruction private static ulong ReverseBytes(ulong Value, RevSize Size) { - Value = ((Value & 0xff00ff00ff00ff00) >> 8) | ((Value & 0x00ff00ff00ff00ff) << 8); + Value = ((Value & 0xff00ff00ff00ff00) >> 8) | ((Value & 0x00ff00ff00ff00ff) << 8); if (Size == RevSize.Rev16) { From c14c69a10c936f485a4420c93499bd4c3efa8b09 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Fri, 2 Mar 2018 22:49:17 -0300 Subject: [PATCH 11/17] Refactor HID, fix issues (#48) * Refactor HID, fix issues * Fix on touch screen code with wrong offset * Don't use magic values * Replace more magic values with actual variables, fix touch screen coordinates on different window sizes --- Ryujinx.Core/Config.cs | 3 +- Ryujinx.Core/Hid.cs | 225 -------------------- Ryujinx.Core/Hid/Hid.cs | 235 +++++++++++++++++++++ Ryujinx.Core/Hid/HidController.cs | 188 ----------------- Ryujinx.Core/Hid/HidControllerButtons.cs | 35 +++ Ryujinx.Core/Hid/HidControllerColorDesc.cs | 10 + Ryujinx.Core/Hid/HidControllerConnState.cs | 11 + Ryujinx.Core/Hid/HidControllerId.cs | 16 ++ Ryujinx.Core/Hid/HidControllerLayouts.cs | 13 ++ Ryujinx.Core/Hid/HidControllerType.cs | 14 ++ Ryujinx.Core/Hid/HidJoystickPosition.cs | 8 + Ryujinx.Core/Hid/HidKeyboard.cs | 33 --- Ryujinx.Core/Hid/HidMouse.cs | 37 ---- Ryujinx.Core/Hid/HidTouchPoint.cs | 11 + Ryujinx.Core/Hid/HidTouchScreen.cs | 55 ----- Ryujinx.Core/Hid/HidUnknown.cs | 81 ------- Ryujinx.Core/Hid/JoyCon.cs | 25 +-- Ryujinx.Core/Hid/JoyConColor.cs | 23 ++ Ryujinx.Core/OsHle/Process.cs | 10 + Ryujinx.Core/OsHle/Svc/SvcMemory.cs | 2 + Ryujinx.Core/Switch.cs | 17 +- Ryujinx/Ui/GLScreen.cs | 148 ++++++++----- 22 files changed, 491 insertions(+), 709 deletions(-) delete mode 100644 Ryujinx.Core/Hid.cs create mode 100644 Ryujinx.Core/Hid/Hid.cs delete mode 100644 Ryujinx.Core/Hid/HidController.cs create mode 100644 Ryujinx.Core/Hid/HidControllerButtons.cs create mode 100644 Ryujinx.Core/Hid/HidControllerColorDesc.cs create mode 100644 Ryujinx.Core/Hid/HidControllerConnState.cs create mode 100644 Ryujinx.Core/Hid/HidControllerId.cs create mode 100644 Ryujinx.Core/Hid/HidControllerLayouts.cs create mode 100644 Ryujinx.Core/Hid/HidControllerType.cs create mode 100644 Ryujinx.Core/Hid/HidJoystickPosition.cs delete mode 100644 Ryujinx.Core/Hid/HidKeyboard.cs delete mode 100644 Ryujinx.Core/Hid/HidMouse.cs create mode 100644 Ryujinx.Core/Hid/HidTouchPoint.cs delete mode 100644 Ryujinx.Core/Hid/HidTouchScreen.cs delete mode 100644 Ryujinx.Core/Hid/HidUnknown.cs create mode 100644 Ryujinx.Core/Hid/JoyConColor.cs diff --git a/Ryujinx.Core/Config.cs b/Ryujinx.Core/Config.cs index 7db49319c9..c9a76de343 100644 --- a/Ryujinx.Core/Config.cs +++ b/Ryujinx.Core/Config.cs @@ -1,4 +1,5 @@ -using System; +using Ryujinx.Core.Input; +using System; using System.Collections.Generic; using System.IO; using System.Linq; diff --git a/Ryujinx.Core/Hid.cs b/Ryujinx.Core/Hid.cs deleted file mode 100644 index bd83e92d47..0000000000 --- a/Ryujinx.Core/Hid.cs +++ /dev/null @@ -1,225 +0,0 @@ -using Ryujinx.Core.OsHle; -using System; -using System.Runtime.InteropServices; - -namespace Ryujinx.Core -{ - public class Hid - { - /* - Thanks to: - https://github.com/reswitched/libtransistor/blob/development/lib/hid.c - https://github.com/reswitched/libtransistor/blob/development/include/libtransistor/hid.h - https://github.com/switchbrew/libnx/blob/master/nx/source/services/hid.c - https://github.com/switchbrew/libnx/blob/master/nx/include/switch/services/hid.h - - struct HidSharedMemory - { - header[0x400]; - touchscreen[0x3000]; - mouse[0x400]; - keyboard[0x400]; - unkSection1[0x400]; - unkSection2[0x400]; - unkSection3[0x400]; - unkSection4[0x400]; - unkSection5[0x200]; - unkSection6[0x200]; - unkSection7[0x200]; - unkSection8[0x800]; - controllerSerials[0x4000]; - controllers[0x5000 * 10]; - unkSection9[0x4600]; - } - */ - - private const int Hid_Num_Entries = 17; - private Switch Ns; - private long SharedMemOffset; - - public Hid(Switch Ns) - { - this.Ns = Ns; - } - - public void Init(long HidOffset) - { - unsafe - { - if (HidOffset == 0 || HidOffset + Horizon.HidSize > uint.MaxValue) - { - return; - } - - SharedMemOffset = HidOffset; - - uint InnerOffset = (uint)Marshal.SizeOf(typeof(HidSharedMemHeader)); - - IntPtr HidPtr = new IntPtr(Ns.Ram.ToInt64() + (uint)SharedMemOffset + InnerOffset); - - HidTouchScreen TouchScreen = new HidTouchScreen(); - TouchScreen.Header.TimestampTicks = (ulong)Environment.TickCount; - TouchScreen.Header.NumEntries = (ulong)Hid_Num_Entries; - TouchScreen.Header.LatestEntry = 0; - TouchScreen.Header.MaxEntryIndex = (ulong)Hid_Num_Entries - 1; - TouchScreen.Header.Timestamp = (ulong)Environment.TickCount; - - Marshal.StructureToPtr(TouchScreen, HidPtr, false); - - InnerOffset += (uint)Marshal.SizeOf(typeof(HidTouchScreen)); - HidPtr = new IntPtr(Ns.Ram.ToInt64() + (uint)SharedMemOffset + InnerOffset); - - HidMouse Mouse = new HidMouse(); - Mouse.Header.TimestampTicks = (ulong)Environment.TickCount; - Mouse.Header.NumEntries = (ulong)Hid_Num_Entries; - Mouse.Header.LatestEntry = 0; - Mouse.Header.MaxEntryIndex = (ulong)Hid_Num_Entries - 1; - - //TODO: Write this structure when the input is implemented - //Marshal.StructureToPtr(Mouse, HidPtr, false); - - InnerOffset += (uint)Marshal.SizeOf(typeof(HidMouse)); - HidPtr = new IntPtr(Ns.Ram.ToInt64() + (uint)SharedMemOffset + InnerOffset); - - HidKeyboard Keyboard = new HidKeyboard(); - Keyboard.Header.TimestampTicks = (ulong)Environment.TickCount; - Keyboard.Header.NumEntries = (ulong)Hid_Num_Entries; - Keyboard.Header.LatestEntry = 0; - Keyboard.Header.MaxEntryIndex = (ulong)Hid_Num_Entries - 1; - - //TODO: Write this structure when the input is implemented - //Marshal.StructureToPtr(Keyboard, HidPtr, false); - - InnerOffset += (uint)Marshal.SizeOf(typeof(HidKeyboard)) + - (uint)Marshal.SizeOf(typeof(HidUnknownSection1)) + - (uint)Marshal.SizeOf(typeof(HidUnknownSection2)) + - (uint)Marshal.SizeOf(typeof(HidUnknownSection3)) + - (uint)Marshal.SizeOf(typeof(HidUnknownSection4)) + - (uint)Marshal.SizeOf(typeof(HidUnknownSection5)) + - (uint)Marshal.SizeOf(typeof(HidUnknownSection6)) + - (uint)Marshal.SizeOf(typeof(HidUnknownSection7)) + - (uint)Marshal.SizeOf(typeof(HidUnknownSection8)) + - (uint)Marshal.SizeOf(typeof(HidControllerSerials)); - - //Increase the loop to initialize more controller. - for (int i = 8; i < Enum.GetNames(typeof(HidControllerID)).Length - 1; i++) - { - HidPtr = new IntPtr(Ns.Ram.ToInt64() + (uint)SharedMemOffset + InnerOffset + (uint)(Marshal.SizeOf(typeof(HidController)) * i)); - - HidController Controller = new HidController(); - Controller.Header.Type = (uint)(HidControllerType.ControllerType_Handheld | HidControllerType.ControllerType_JoyconPair); - Controller.Header.IsHalf = 0; - Controller.Header.SingleColorsDescriptor = (uint)(HidControllerColorDescription.ColorDesc_ColorsNonexistent); - Controller.Header.SingleColorBody = 0; - Controller.Header.SingleColorButtons = 0; - Controller.Header.SplitColorsDescriptor = 0; - Controller.Header.LeftColorBody = (uint)JoyConColor.Body_Neon_Red; - Controller.Header.LeftColorButtons = (uint)JoyConColor.Buttons_Neon_Red; - Controller.Header.RightColorBody = (uint)JoyConColor.Body_Neon_Blue; - Controller.Header.RightColorButtons = (uint)JoyConColor.Buttons_Neon_Blue; - - Controller.Layouts = new HidControllerLayout[Enum.GetNames(typeof(HidControllerLayouts)).Length]; - Controller.Layouts[(int)HidControllerLayouts.Main] = new HidControllerLayout(); - Controller.Layouts[(int)HidControllerLayouts.Main].Header.LatestEntry = (ulong)Hid_Num_Entries; - - Marshal.StructureToPtr(Controller, HidPtr, false); - } - - Logging.Info("HID Initialized!"); - } - } - - public void SendControllerButtons(HidControllerID ControllerId, - HidControllerLayouts Layout, - HidControllerKeys Buttons, - JoystickPosition LeftJoystick, - JoystickPosition RightJoystick) - { - uint InnerOffset = (uint)Marshal.SizeOf(typeof(HidSharedMemHeader)) + - (uint)Marshal.SizeOf(typeof(HidTouchScreen)) + - (uint)Marshal.SizeOf(typeof(HidMouse)) + - (uint)Marshal.SizeOf(typeof(HidKeyboard)) + - (uint)Marshal.SizeOf(typeof(HidUnknownSection1)) + - (uint)Marshal.SizeOf(typeof(HidUnknownSection2)) + - (uint)Marshal.SizeOf(typeof(HidUnknownSection3)) + - (uint)Marshal.SizeOf(typeof(HidUnknownSection4)) + - (uint)Marshal.SizeOf(typeof(HidUnknownSection5)) + - (uint)Marshal.SizeOf(typeof(HidUnknownSection6)) + - (uint)Marshal.SizeOf(typeof(HidUnknownSection7)) + - (uint)Marshal.SizeOf(typeof(HidUnknownSection8)) + - (uint)Marshal.SizeOf(typeof(HidControllerSerials)) + - ((uint)(Marshal.SizeOf(typeof(HidController)) * (int)ControllerId)) + - (uint)Marshal.SizeOf(typeof(HidControllerHeader)) + - (uint)Layout * (uint)Marshal.SizeOf(typeof(HidControllerLayout)); - - IntPtr HidPtr = new IntPtr(Ns.Ram.ToInt64() + (uint)SharedMemOffset + InnerOffset); - - HidControllerLayoutHeader OldControllerHeaderLayout = (HidControllerLayoutHeader)Marshal.PtrToStructure(HidPtr, typeof(HidControllerLayoutHeader)); - - HidControllerLayoutHeader ControllerLayoutHeader = new HidControllerLayoutHeader - { - TimestampTicks = (ulong)Environment.TickCount, - NumEntries = (ulong)Hid_Num_Entries, - MaxEntryIndex = (ulong)Hid_Num_Entries - 1, - LatestEntry = (OldControllerHeaderLayout.LatestEntry < (ulong)Hid_Num_Entries ? OldControllerHeaderLayout.LatestEntry + 1 : 0) - }; - - Marshal.StructureToPtr(ControllerLayoutHeader, HidPtr, false); - - InnerOffset += (uint)Marshal.SizeOf(typeof(HidControllerLayoutHeader)) + (uint)((uint)(ControllerLayoutHeader.LatestEntry) * Marshal.SizeOf(typeof(HidControllerInputEntry))); - HidPtr = new IntPtr(Ns.Ram.ToInt64() + (uint)SharedMemOffset + InnerOffset); - - HidControllerInputEntry ControllerInputEntry = new HidControllerInputEntry - { - Timestamp = (ulong)Environment.TickCount, - Timestamp_2 = (ulong)Environment.TickCount, - Buttons = (ulong)Buttons, - Joysticks = new JoystickPosition[(int)HidControllerJoystick.Joystick_Num_Sticks] - }; - ControllerInputEntry.Joysticks[(int)HidControllerJoystick.Joystick_Left] = LeftJoystick; - ControllerInputEntry.Joysticks[(int)HidControllerJoystick.Joystick_Right] = RightJoystick; - ControllerInputEntry.ConnectionState = (ulong)(HidControllerConnectionState.Controller_State_Connected | HidControllerConnectionState.Controller_State_Wired); - - Marshal.StructureToPtr(ControllerInputEntry, HidPtr, false); - } - - public void SendTouchPoint(HidTouchScreenEntryTouch TouchPoint) - { - uint InnerOffset = (uint)Marshal.SizeOf(typeof(HidSharedMemHeader)); - - IntPtr HidPtr = new IntPtr(Ns.Ram.ToInt64() + (uint)SharedMemOffset + InnerOffset); - - HidTouchScreenHeader OldTouchScreenHeader = (HidTouchScreenHeader)Marshal.PtrToStructure(HidPtr,typeof(HidTouchScreenHeader)); - - HidTouchScreenHeader TouchScreenHeader = new HidTouchScreenHeader() - { - TimestampTicks = (ulong)Environment.TickCount, - NumEntries = (ulong)Hid_Num_Entries, - MaxEntryIndex = (ulong)Hid_Num_Entries - 1, - Timestamp = (ulong)Environment.TickCount, - LatestEntry = OldTouchScreenHeader.LatestEntry < Hid_Num_Entries-1 ? OldTouchScreenHeader.LatestEntry + 1 : 0 - }; - - Marshal.StructureToPtr(TouchScreenHeader, HidPtr, false); - - InnerOffset += (uint)Marshal.SizeOf(typeof(HidTouchScreenHeader)) - + (uint)((uint)(OldTouchScreenHeader.LatestEntry) * Marshal.SizeOf(typeof(HidTouchScreenEntry))); - HidPtr = new IntPtr(Ns.Ram.ToInt64() + (uint)SharedMemOffset + InnerOffset); - - HidTouchScreenEntry hidTouchScreenEntry = new HidTouchScreenEntry() - { - Header = new HidTouchScreenEntryHeader() - { - Timestamp = (ulong)Environment.TickCount, - NumTouches = 1 - }, - Touches = new HidTouchScreenEntryTouch[16] - }; - - //Only supports single touch - hidTouchScreenEntry.Touches[0] = TouchPoint; - - Marshal.StructureToPtr(hidTouchScreenEntry, HidPtr, false); - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/Hid/Hid.cs b/Ryujinx.Core/Hid/Hid.cs new file mode 100644 index 0000000000..4dbac40cbd --- /dev/null +++ b/Ryujinx.Core/Hid/Hid.cs @@ -0,0 +1,235 @@ +using ChocolArm64.Memory; +using System.Diagnostics; + +namespace Ryujinx.Core.Input +{ + public class Hid + { + /* + * Reference: + * https://github.com/reswitched/libtransistor/blob/development/lib/hid.c + * https://github.com/reswitched/libtransistor/blob/development/include/libtransistor/hid.h + * https://github.com/switchbrew/libnx/blob/master/nx/source/services/hid.c + * https://github.com/switchbrew/libnx/blob/master/nx/include/switch/services/hid.h + */ + + private const int HidHeaderSize = 0x400; + private const int HidTouchScreenSize = 0x3000; + private const int HidMouseSize = 0x400; + private const int HidKeyboardSize = 0x400; + private const int HidUnkSection1Size = 0x400; + private const int HidUnkSection2Size = 0x400; + private const int HidUnkSection3Size = 0x400; + private const int HidUnkSection4Size = 0x400; + private const int HidUnkSection5Size = 0x200; + private const int HidUnkSection6Size = 0x200; + private const int HidUnkSection7Size = 0x200; + private const int HidUnkSection8Size = 0x800; + private const int HidControllerSerialsSize = 0x4000; + private const int HidControllersSize = 0x32000; + private const int HidUnkSection9Size = 0x800; + + private const int HidTouchHeaderSize = 0x28; + private const int HidTouchEntrySize = 0x298; + + private const int HidTouchEntryHeaderSize = 0x10; + private const int HidTouchEntryTouchSize = 0x28; + + private const int HidControllerSize = 0x5000; + private const int HidControllerHeaderSize = 0x28; + private const int HidControllerLayoutsSize = 0x350; + + private const int HidControllersLayoutHeaderSize = 0x20; + private const int HidControllersInputEntrySize = 0x30; + + private const int HidHeaderOffset = 0; + private const int HidTouchScreenOffset = HidHeaderOffset + HidHeaderSize; + private const int HidMouseOffset = HidTouchScreenOffset + HidTouchScreenSize; + private const int HidKeyboardOffset = HidMouseOffset + HidMouseSize; + private const int HidUnkSection1Offset = HidKeyboardOffset + HidKeyboardSize; + private const int HidUnkSection2Offset = HidUnkSection1Offset + HidUnkSection1Size; + private const int HidUnkSection3Offset = HidUnkSection2Offset + HidUnkSection2Size; + private const int HidUnkSection4Offset = HidUnkSection3Offset + HidUnkSection3Size; + private const int HidUnkSection5Offset = HidUnkSection4Offset + HidUnkSection4Size; + private const int HidUnkSection6Offset = HidUnkSection5Offset + HidUnkSection5Size; + private const int HidUnkSection7Offset = HidUnkSection6Offset + HidUnkSection6Size; + private const int HidUnkSection8Offset = HidUnkSection7Offset + HidUnkSection7Size; + private const int HidControllerSerialsOffset = HidUnkSection8Offset + HidUnkSection8Size; + private const int HidControllersOffset = HidControllerSerialsOffset + HidControllerSerialsSize; + private const int HidUnkSection9Offset = HidControllersOffset + HidControllersSize; + + private const int HidEntryCount = 17; + + private long SharedMemOffset; + + private Switch Ns; + + public Hid(Switch Ns) + { + this.Ns = Ns; + } + + public void Init(long HidOffset) + { + SharedMemOffset = HidOffset; + + InitializeJoyconPair( + JoyConColor.Body_Neon_Red, + JoyConColor.Buttons_Neon_Red, + JoyConColor.Body_Neon_Blue, + JoyConColor.Buttons_Neon_Blue); + } + + public void InitializeJoyconPair( + JoyConColor LeftColorBody, + JoyConColor LeftColorButtons, + JoyConColor RightColorBody, + JoyConColor RightColorButtons) + { + long BaseControllerOffset = HidControllersOffset + 8 * HidControllerSize; + + HidControllerType Type = + HidControllerType.ControllerType_Handheld | + HidControllerType.ControllerType_JoyconPair; + + bool IsHalf = false; + + HidControllerColorDesc SingleColorDesc = + HidControllerColorDesc.ColorDesc_ColorsNonexistent; + + JoyConColor SingleColorBody = JoyConColor.Black; + JoyConColor SingleColorButtons = JoyConColor.Black; + + HidControllerColorDesc SplitColorDesc = 0; + + WriteInt32(BaseControllerOffset + 0x0, (int)Type); + + WriteInt32(BaseControllerOffset + 0x4, IsHalf ? 1 : 0); + + WriteInt32(BaseControllerOffset + 0x8, (int)SingleColorDesc); + WriteInt32(BaseControllerOffset + 0xc, (int)SingleColorBody); + WriteInt32(BaseControllerOffset + 0x10, (int)SingleColorButtons); + WriteInt32(BaseControllerOffset + 0x14, (int)SplitColorDesc); + + WriteInt32(BaseControllerOffset + 0x18, (int)LeftColorBody); + WriteInt32(BaseControllerOffset + 0x1c, (int)LeftColorButtons); + + WriteInt32(BaseControllerOffset + 0x20, (int)RightColorBody); + WriteInt32(BaseControllerOffset + 0x24, (int)RightColorButtons); + } + + public void SetJoyconButton( + HidControllerId ControllerId, + HidControllerLayouts ControllerLayout, + HidControllerButtons Buttons, + HidJoystickPosition LeftStick, + HidJoystickPosition RightStick) + { + long ControllerOffset = HidControllersOffset + (int)ControllerId * HidControllerSize; + + ControllerOffset += HidControllerHeaderSize; + + ControllerOffset += (int)ControllerLayout * HidControllerLayoutsSize; + + long LastEntry = ReadInt64(ControllerOffset + 0x10); + + long CurrEntry = (LastEntry + 1) % HidEntryCount; + + long Timestamp = Stopwatch.GetTimestamp(); + + WriteInt64(ControllerOffset + 0x0, Timestamp); + WriteInt64(ControllerOffset + 0x8, HidEntryCount); + WriteInt64(ControllerOffset + 0x10, CurrEntry); + WriteInt64(ControllerOffset + 0x18, HidEntryCount - 1); + + ControllerOffset += HidControllersLayoutHeaderSize; + + ControllerOffset += CurrEntry * HidControllersInputEntrySize; + + WriteInt64(ControllerOffset + 0x0, Timestamp); + WriteInt64(ControllerOffset + 0x8, Timestamp); + + WriteInt64(ControllerOffset + 0x10, (uint)Buttons); + + WriteInt32(ControllerOffset + 0x18, LeftStick.DX); + WriteInt32(ControllerOffset + 0x1c, LeftStick.DY); + + WriteInt64(ControllerOffset + 0x20, RightStick.DX); + WriteInt64(ControllerOffset + 0x24, RightStick.DY); + + WriteInt64(ControllerOffset + 0x28, + (uint)HidControllerConnState.Controller_State_Connected | + (uint)HidControllerConnState.Controller_State_Wired); + } + + public void SetTouchPoints(params HidTouchPoint[] Points) + { + long LastEntry = ReadInt64(HidTouchScreenOffset + 0x10); + + long CurrEntry = (LastEntry + 1) % HidEntryCount; + + long Timestamp = Stopwatch.GetTimestamp(); + + WriteInt64(HidTouchScreenOffset + 0x0, Timestamp); + WriteInt64(HidTouchScreenOffset + 0x8, HidEntryCount); + WriteInt64(HidTouchScreenOffset + 0x10, CurrEntry); + WriteInt64(HidTouchScreenOffset + 0x18, HidEntryCount - 1); + WriteInt64(HidTouchScreenOffset + 0x20, Timestamp); + + long TouchEntryOffset = HidTouchScreenOffset + HidTouchHeaderSize; + + TouchEntryOffset += CurrEntry * HidTouchEntrySize; + + WriteInt64(TouchEntryOffset + 0x0, Timestamp); + WriteInt64(TouchEntryOffset + 0x8, Points.Length); + + TouchEntryOffset += HidTouchEntryHeaderSize; + + const int Padding = 0; + + int Index = 0; + + foreach (HidTouchPoint Point in Points) + { + WriteInt64(TouchEntryOffset + 0x0, Timestamp); + WriteInt32(TouchEntryOffset + 0x8, Padding); + WriteInt32(TouchEntryOffset + 0xc, Index++); + WriteInt32(TouchEntryOffset + 0x10, Point.X); + WriteInt32(TouchEntryOffset + 0x14, Point.Y); + WriteInt32(TouchEntryOffset + 0x18, Point.DiameterX); + WriteInt32(TouchEntryOffset + 0x1c, Point.DiameterY); + WriteInt32(TouchEntryOffset + 0x20, Point.Angle); + WriteInt32(TouchEntryOffset + 0x24, Padding); + + TouchEntryOffset += HidTouchEntryTouchSize; + } + } + + private unsafe long ReadInt64(long Position) + { + Position += SharedMemOffset; + + if ((ulong)Position + 8 > AMemoryMgr.AddrSize) return 0; + + return *((long*)((byte*)Ns.Ram + Position)); + } + + private unsafe void WriteInt32(long Position, int Value) + { + Position += SharedMemOffset; + + if ((ulong)Position + 4 > AMemoryMgr.AddrSize) return; + + *((int*)((byte*)Ns.Ram + Position)) = Value; + } + + private unsafe void WriteInt64(long Position, long Value) + { + Position += SharedMemOffset; + + if ((ulong)Position + 8 > AMemoryMgr.AddrSize) return; + + *((long*)((byte*)Ns.Ram + Position)) = Value; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/Hid/HidController.cs b/Ryujinx.Core/Hid/HidController.cs deleted file mode 100644 index 641bc55695..0000000000 --- a/Ryujinx.Core/Hid/HidController.cs +++ /dev/null @@ -1,188 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace Ryujinx.Core -{ - [Flags] - public enum HidControllerKeys - { - KEY_A = (1 << 0), - KEY_B = (1 << 1), - KEY_X = (1 << 2), - KEY_Y = (1 << 3), - KEY_LSTICK = (1 << 4), - KEY_RSTICK = (1 << 5), - KEY_L = (1 << 6), - KEY_R = (1 << 7), - KEY_ZL = (1 << 8), - KEY_ZR = (1 << 9), - KEY_PLUS = (1 << 10), - KEY_MINUS = (1 << 11), - KEY_DLEFT = (1 << 12), - KEY_DUP = (1 << 13), - KEY_DRIGHT = (1 << 14), - KEY_DDOWN = (1 << 15), - KEY_LSTICK_LEFT = (1 << 16), - KEY_LSTICK_UP = (1 << 17), - KEY_LSTICK_RIGHT = (1 << 18), - KEY_LSTICK_DOWN = (1 << 19), - KEY_RSTICK_LEFT = (1 << 20), - KEY_RSTICK_UP = (1 << 21), - KEY_RSTICK_RIGHT = (1 << 22), - KEY_RSTICK_DOWN = (1 << 23), - KEY_SL = (1 << 24), - KEY_SR = (1 << 25), - - // Pseudo-key for at least one finger on the touch screen - KEY_TOUCH = (1 << 26), - - // Buttons by orientation (for single Joy-Con), also works with Joy-Con pairs, Pro Controller - KEY_JOYCON_RIGHT = (1 << 0), - KEY_JOYCON_DOWN = (1 << 1), - KEY_JOYCON_UP = (1 << 2), - KEY_JOYCON_LEFT = (1 << 3), - - // Generic catch-all directions, also works for single Joy-Con - KEY_UP = KEY_DUP | KEY_LSTICK_UP | KEY_RSTICK_UP, - KEY_DOWN = KEY_DDOWN | KEY_LSTICK_DOWN | KEY_RSTICK_DOWN, - KEY_LEFT = KEY_DLEFT | KEY_LSTICK_LEFT | KEY_RSTICK_LEFT, - KEY_RIGHT = KEY_DRIGHT | KEY_LSTICK_RIGHT | KEY_RSTICK_RIGHT, - } - - public enum HidControllerID - { - CONTROLLER_PLAYER_1 = 0, - CONTROLLER_PLAYER_2 = 1, - CONTROLLER_PLAYER_3 = 2, - CONTROLLER_PLAYER_4 = 3, - CONTROLLER_PLAYER_5 = 4, - CONTROLLER_PLAYER_6 = 5, - CONTROLLER_PLAYER_7 = 6, - CONTROLLER_PLAYER_8 = 7, - CONTROLLER_HANDHELD = 8, - CONTROLLER_UNKNOWN = 9 - } - - public enum HidControllerJoystick - { - Joystick_Left = 0, - Joystick_Right = 1, - Joystick_Num_Sticks = 2 - } - - public enum HidControllerLayouts - { - Pro_Controller, - Handheld_Joined, - Joined, - Left, - Right, - Main_No_Analog, - Main - } - - [Flags] - public enum HidControllerConnectionState - { - Controller_State_Connected = (1 << 0), - Controller_State_Wired = (1 << 1) - } - - [Flags] - public enum HidControllerType - { - ControllerType_ProController = (1 << 0), - ControllerType_Handheld = (1 << 1), - ControllerType_JoyconPair = (1 << 2), - ControllerType_JoyconLeft = (1 << 3), - ControllerType_JoyconRight = (1 << 4) - } - - public enum HidControllerColorDescription - { - ColorDesc_ColorsNonexistent = (1 << 1), - } - - [StructLayout(LayoutKind.Sequential, Size = 0x8)] - public struct JoystickPosition - { - public int DX; - public int DY; - } - - [StructLayout(LayoutKind.Sequential, Size = 0x20)] - public struct HidControllerMAC - { - public ulong Timestamp; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public byte[] MAC; - public ulong Unknown; - public ulong Timestamp_2; - } - - [StructLayout(LayoutKind.Sequential, Size = 0x28)] - public struct HidControllerHeader - { - public uint Type; - public uint IsHalf; - public uint SingleColorsDescriptor; - public uint SingleColorBody; - public uint SingleColorButtons; - public uint SplitColorsDescriptor; - public uint LeftColorBody; - public uint LeftColorButtons; - public uint RightColorBody; - public uint RightColorButtons; - } - - [StructLayout(LayoutKind.Sequential, Size = 0x20)] - public struct HidControllerLayoutHeader - { - public ulong TimestampTicks; - public ulong NumEntries; - public ulong LatestEntry; - public ulong MaxEntryIndex; - } - - [StructLayout(LayoutKind.Sequential, Size = 0x30)] - public struct HidControllerInputEntry - { - public ulong Timestamp; - public ulong Timestamp_2; - public ulong Buttons; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = (int)HidControllerJoystick.Joystick_Num_Sticks)] - public JoystickPosition[] Joysticks; - public ulong ConnectionState; - } - - [StructLayout(LayoutKind.Sequential, Size = 0x350)] - public struct HidControllerLayout - { - public HidControllerLayoutHeader Header; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)] - public HidControllerInputEntry[] Entries; - } - - [StructLayout(LayoutKind.Sequential, Size = 0x5000)] - public struct HidController - { - public HidControllerHeader Header; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)] - public HidControllerLayout[] Layouts; - /* - pro_controller - handheld_joined - joined - left - right - main_no_analog - main - */ - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x2A70)] - public byte[] Unknown_1; - public HidControllerMAC MacLeft; - public HidControllerMAC MacRight; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0xDF8)] - public byte[] Unknown_2; - } -} diff --git a/Ryujinx.Core/Hid/HidControllerButtons.cs b/Ryujinx.Core/Hid/HidControllerButtons.cs new file mode 100644 index 0000000000..65eb3f82fe --- /dev/null +++ b/Ryujinx.Core/Hid/HidControllerButtons.cs @@ -0,0 +1,35 @@ +using System; + +namespace Ryujinx.Core.Input +{ + [Flags] + public enum HidControllerButtons + { + KEY_A = (1 << 0), + KEY_B = (1 << 1), + KEY_X = (1 << 2), + KEY_Y = (1 << 3), + KEY_LSTICK = (1 << 4), + KEY_RSTICK = (1 << 5), + KEY_L = (1 << 6), + KEY_R = (1 << 7), + KEY_ZL = (1 << 8), + KEY_ZR = (1 << 9), + KEY_PLUS = (1 << 10), + KEY_MINUS = (1 << 11), + KEY_DLEFT = (1 << 12), + KEY_DUP = (1 << 13), + KEY_DRIGHT = (1 << 14), + KEY_DDOWN = (1 << 15), + KEY_LSTICK_LEFT = (1 << 16), + KEY_LSTICK_UP = (1 << 17), + KEY_LSTICK_RIGHT = (1 << 18), + KEY_LSTICK_DOWN = (1 << 19), + KEY_RSTICK_LEFT = (1 << 20), + KEY_RSTICK_UP = (1 << 21), + KEY_RSTICK_RIGHT = (1 << 22), + KEY_RSTICK_DOWN = (1 << 23), + KEY_SL = (1 << 24), + KEY_SR = (1 << 25) + } +} \ No newline at end of file diff --git a/Ryujinx.Core/Hid/HidControllerColorDesc.cs b/Ryujinx.Core/Hid/HidControllerColorDesc.cs new file mode 100644 index 0000000000..fc7fa2178a --- /dev/null +++ b/Ryujinx.Core/Hid/HidControllerColorDesc.cs @@ -0,0 +1,10 @@ +using System; + +namespace Ryujinx.Core.Input +{ + [Flags] + public enum HidControllerColorDesc + { + ColorDesc_ColorsNonexistent = (1 << 1) + } +} \ No newline at end of file diff --git a/Ryujinx.Core/Hid/HidControllerConnState.cs b/Ryujinx.Core/Hid/HidControllerConnState.cs new file mode 100644 index 0000000000..7f47a7f92f --- /dev/null +++ b/Ryujinx.Core/Hid/HidControllerConnState.cs @@ -0,0 +1,11 @@ +using System; + +namespace Ryujinx.Core.Input +{ + [Flags] + public enum HidControllerConnState + { + Controller_State_Connected = (1 << 0), + Controller_State_Wired = (1 << 1) + } +} \ No newline at end of file diff --git a/Ryujinx.Core/Hid/HidControllerId.cs b/Ryujinx.Core/Hid/HidControllerId.cs new file mode 100644 index 0000000000..84b68d27ef --- /dev/null +++ b/Ryujinx.Core/Hid/HidControllerId.cs @@ -0,0 +1,16 @@ +namespace Ryujinx.Core.Input +{ + public enum HidControllerId + { + CONTROLLER_PLAYER_1 = 0, + CONTROLLER_PLAYER_2 = 1, + CONTROLLER_PLAYER_3 = 2, + CONTROLLER_PLAYER_4 = 3, + CONTROLLER_PLAYER_5 = 4, + CONTROLLER_PLAYER_6 = 5, + CONTROLLER_PLAYER_7 = 6, + CONTROLLER_PLAYER_8 = 7, + CONTROLLER_HANDHELD = 8, + CONTROLLER_UNKNOWN = 9 + } +} \ No newline at end of file diff --git a/Ryujinx.Core/Hid/HidControllerLayouts.cs b/Ryujinx.Core/Hid/HidControllerLayouts.cs new file mode 100644 index 0000000000..e04c40b2d6 --- /dev/null +++ b/Ryujinx.Core/Hid/HidControllerLayouts.cs @@ -0,0 +1,13 @@ +namespace Ryujinx.Core.Input +{ + public enum HidControllerLayouts + { + Pro_Controller = 0, + Handheld_Joined = 1, + Joined = 2, + Left = 3, + Right = 4, + Main_No_Analog = 5, + Main = 6 + } +} \ No newline at end of file diff --git a/Ryujinx.Core/Hid/HidControllerType.cs b/Ryujinx.Core/Hid/HidControllerType.cs new file mode 100644 index 0000000000..a4eb674c8c --- /dev/null +++ b/Ryujinx.Core/Hid/HidControllerType.cs @@ -0,0 +1,14 @@ +using System; + +namespace Ryujinx.Core.Input +{ + [Flags] + public enum HidControllerType + { + ControllerType_ProController = (1 << 0), + ControllerType_Handheld = (1 << 1), + ControllerType_JoyconPair = (1 << 2), + ControllerType_JoyconLeft = (1 << 3), + ControllerType_JoyconRight = (1 << 4) + } +} \ No newline at end of file diff --git a/Ryujinx.Core/Hid/HidJoystickPosition.cs b/Ryujinx.Core/Hid/HidJoystickPosition.cs new file mode 100644 index 0000000000..61f8189f42 --- /dev/null +++ b/Ryujinx.Core/Hid/HidJoystickPosition.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.Core.Input +{ + public struct HidJoystickPosition + { + public int DX; + public int DY; + } +} \ No newline at end of file diff --git a/Ryujinx.Core/Hid/HidKeyboard.cs b/Ryujinx.Core/Hid/HidKeyboard.cs deleted file mode 100644 index f9987f68b2..0000000000 --- a/Ryujinx.Core/Hid/HidKeyboard.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Ryujinx.Core -{ - [StructLayout(LayoutKind.Sequential, Size = 0x20)] - public struct HidKeyboardHeader - { - public ulong TimestampTicks; - public ulong NumEntries; - public ulong LatestEntry; - public ulong MaxEntryIndex; - } - - [StructLayout(LayoutKind.Sequential, Size = 0x38)] - public struct HidKeyboardEntry - { - public ulong Timestamp; - public ulong Timestamp_2; - public ulong Modifier; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public uint[] Keys; - } - - [StructLayout(LayoutKind.Sequential, Size = 0x400)] - public struct HidKeyboard - { - public HidKeyboardHeader Header; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)] - public HidKeyboardEntry[] Entries; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x28)] - public byte[] Padding; - } -} diff --git a/Ryujinx.Core/Hid/HidMouse.cs b/Ryujinx.Core/Hid/HidMouse.cs deleted file mode 100644 index 9a019dd5ff..0000000000 --- a/Ryujinx.Core/Hid/HidMouse.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Ryujinx.Core -{ - [StructLayout(LayoutKind.Sequential, Size = 0x20)] - public struct HidMouseHeader - { - public ulong TimestampTicks; - public ulong NumEntries; - public ulong LatestEntry; - public ulong MaxEntryIndex; - } - - [StructLayout(LayoutKind.Sequential, Size = 0x30)] - public struct HidMouseEntry - { - public ulong Timestamp; - public ulong Timestamp_2; - public uint X; - public uint Y; - public uint VelocityX; - public uint VelocityY; - public uint ScrollVelocityX; - public uint ScrollVelocityY; - public ulong Buttons; - } - - [StructLayout(LayoutKind.Sequential, Size = 0x400)] - public struct HidMouse - { - public HidMouseHeader Header; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)] - public HidMouseEntry[] Entries; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0xB0)] - public byte[] Padding; - } -} diff --git a/Ryujinx.Core/Hid/HidTouchPoint.cs b/Ryujinx.Core/Hid/HidTouchPoint.cs new file mode 100644 index 0000000000..1207e1d536 --- /dev/null +++ b/Ryujinx.Core/Hid/HidTouchPoint.cs @@ -0,0 +1,11 @@ +namespace Ryujinx.Core.Input +{ + public struct HidTouchPoint + { + public int X; + public int Y; + public int DiameterX; + public int DiameterY; + public int Angle; + } +} \ No newline at end of file diff --git a/Ryujinx.Core/Hid/HidTouchScreen.cs b/Ryujinx.Core/Hid/HidTouchScreen.cs deleted file mode 100644 index 755ebadca9..0000000000 --- a/Ryujinx.Core/Hid/HidTouchScreen.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Ryujinx.Core -{ - [StructLayout(LayoutKind.Sequential, Size = 0x28)] - public struct HidTouchScreenHeader - { - public ulong TimestampTicks; - public ulong NumEntries; - public ulong LatestEntry; - public ulong MaxEntryIndex; - public ulong Timestamp; - } - - [StructLayout(LayoutKind.Sequential, Size = 0x10)] - public struct HidTouchScreenEntryHeader - { - public ulong Timestamp; - public ulong NumTouches; - } - - [StructLayout(LayoutKind.Sequential, Size = 0x28)] - public struct HidTouchScreenEntryTouch - { - public ulong Timestamp; - public uint Padding; - public uint TouchIndex; - public uint X; - public uint Y; - public uint DiameterX; - public uint DiameterY; - public uint Angle; - public uint Padding_2; - } - - [StructLayout(LayoutKind.Sequential, Size = 0x298)] - public struct HidTouchScreenEntry - { - public HidTouchScreenEntryHeader Header; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - public HidTouchScreenEntryTouch[] Touches; - public ulong Unknown; - } - - [StructLayout(LayoutKind.Sequential, Size = 0x3000)] - public struct HidTouchScreen - { - public HidTouchScreenHeader Header; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)] - public HidTouchScreenEntry[] Entries; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x3C0)] - public byte[] Padding; - } - -} \ No newline at end of file diff --git a/Ryujinx.Core/Hid/HidUnknown.cs b/Ryujinx.Core/Hid/HidUnknown.cs deleted file mode 100644 index c3fe68a833..0000000000 --- a/Ryujinx.Core/Hid/HidUnknown.cs +++ /dev/null @@ -1,81 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Ryujinx.Core -{ - [StructLayout(LayoutKind.Sequential, Size = 0x400)] - public struct HidSharedMemHeader - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x400)] - public byte[] Padding; - } - - [StructLayout(LayoutKind.Sequential, Size = 0x400)] - public struct HidUnknownSection1 - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x400)] - public byte[] Padding; - } - - [StructLayout(LayoutKind.Sequential, Size = 0x400)] - public struct HidUnknownSection2 - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x400)] - public byte[] Padding; - } - - [StructLayout(LayoutKind.Sequential, Size = 0x400)] - public struct HidUnknownSection3 - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x400)] - public byte[] Padding; - } - - [StructLayout(LayoutKind.Sequential, Size = 0x400)] - public struct HidUnknownSection4 - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x400)] - public byte[] Padding; - } - - [StructLayout(LayoutKind.Sequential, Size = 0x200)] - public struct HidUnknownSection5 - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x200)] - public byte[] Padding; - } - - [StructLayout(LayoutKind.Sequential, Size = 0x200)] - public struct HidUnknownSection6 - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x200)] - public byte[] Padding; - } - - [StructLayout(LayoutKind.Sequential, Size = 0x200)] - public struct HidUnknownSection7 - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x200)] - public byte[] Padding; - } - - [StructLayout(LayoutKind.Sequential, Size = 0x800)] - public struct HidUnknownSection8 - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x800)] - public byte[] Padding; - } - - [StructLayout(LayoutKind.Sequential, Size = 0x4000)] - public struct HidControllerSerials - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x4000)] - public byte[] Padding; - } - - [StructLayout(LayoutKind.Sequential, Size = 0x4600)] - public struct HidUnknownSection9 - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x4600)] - public byte[] Padding; - } -} diff --git a/Ryujinx.Core/Hid/JoyCon.cs b/Ryujinx.Core/Hid/JoyCon.cs index 8c9518e58e..1aef82fe08 100644 --- a/Ryujinx.Core/Hid/JoyCon.cs +++ b/Ryujinx.Core/Hid/JoyCon.cs @@ -1,27 +1,6 @@ -namespace Ryujinx +//TODO: This is only used by Config, it doesn't belong to Core. +namespace Ryujinx.Core.Input { - /// - /// Common RGB color hex codes for JoyCon coloring. - /// - public enum JoyConColor //Thanks to CTCaer - { - Body_Grey = 0x828282, - Body_Neon_Blue = 0x0AB9E6, - Body_Neon_Red = 0xFF3C28, - Body_Neon_Yellow = 0xE6FF00, - Body_Neon_Pink = 0xFF3278, - Body_Neon_Green = 0x1EDC00, - Body_Red = 0xE10F00, - - Buttons_Grey = 0x0F0F0F, - Buttons_Neon_Blue = 0x001E1E, - Buttons_Neon_Red = 0x1E0A0A, - Buttons_Neon_Yellow = 0x142800, - Buttons_Neon_Pink = 0x28001E, - Buttons_Neon_Green = 0x002800, - Buttons_Red = 0x280A0A - } - public struct JoyConLeft { public int StickUp; diff --git a/Ryujinx.Core/Hid/JoyConColor.cs b/Ryujinx.Core/Hid/JoyConColor.cs new file mode 100644 index 0000000000..21d89fe423 --- /dev/null +++ b/Ryujinx.Core/Hid/JoyConColor.cs @@ -0,0 +1,23 @@ +namespace Ryujinx.Core.Input +{ + public enum JoyConColor //Thanks to CTCaer + { + Black = 0, + + Body_Grey = 0x828282, + Body_Neon_Blue = 0x0AB9E6, + Body_Neon_Red = 0xFF3C28, + Body_Neon_Yellow = 0xE6FF00, + Body_Neon_Pink = 0xFF3278, + Body_Neon_Green = 0x1EDC00, + Body_Red = 0xE10F00, + + Buttons_Grey = 0x0F0F0F, + Buttons_Neon_Blue = 0x001E1E, + Buttons_Neon_Red = 0x1E0A0A, + Buttons_Neon_Yellow = 0x142800, + Buttons_Neon_Pink = 0x28001E, + Buttons_Neon_Green = 0x002800, + Buttons_Red = 0x280A0A + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Process.cs b/Ryujinx.Core/OsHle/Process.cs index f0b568c8ce..84a21a8c1b 100644 --- a/Ryujinx.Core/OsHle/Process.cs +++ b/Ryujinx.Core/OsHle/Process.cs @@ -242,6 +242,16 @@ namespace Ryujinx.Core.OsHle Logging.Trace($"Executing at 0x{e.Position:x16} {e.SubName}"); } + public void EnableCpuTracing() + { + Translator.EnableCpuTrace = true; + } + + public void DisableCpuTracing() + { + Translator.EnableCpuTrace = false; + } + private int GetFreeTlsSlot(AThread Thread) { for (int Index = 1; Index < TotalTlsSlots; Index++) diff --git a/Ryujinx.Core/OsHle/Svc/SvcMemory.cs b/Ryujinx.Core/OsHle/Svc/SvcMemory.cs index e7559a1408..6969d37936 100644 --- a/Ryujinx.Core/OsHle/Svc/SvcMemory.cs +++ b/Ryujinx.Core/OsHle/Svc/SvcMemory.cs @@ -121,6 +121,8 @@ namespace Ryujinx.Core.OsHle.Svc if (SharedMem != null) { + AMemoryHelper.FillWithZeros(Memory, Src, (int)Size); + SharedMem.AddVirtualPosition(Src); Memory.Manager.Map(Src, Size, (int)MemoryType.SharedMemory, (AMemoryPerm)Perm); diff --git a/Ryujinx.Core/Switch.cs b/Ryujinx.Core/Switch.cs index 8fd7979e44..0d5f8e72fd 100644 --- a/Ryujinx.Core/Switch.cs +++ b/Ryujinx.Core/Switch.cs @@ -1,4 +1,5 @@ using ChocolArm64.Memory; +using Ryujinx.Core.Input; using Ryujinx.Core.OsHle; using Ryujinx.Graphics.Gal; using Ryujinx.Graphics.Gpu; @@ -14,7 +15,7 @@ namespace Ryujinx.Core internal NsGpu Gpu { get; private set; } internal Horizon Os { get; private set; } internal VirtualFs VFs { get; private set; } - internal Hid Hid { get; private set; } + public Hid Hid { get; private set; } public event EventHandler Finish; @@ -43,20 +44,6 @@ namespace Ryujinx.Core Os.LoadProgram(FileName); } - public void SendControllerButtons(HidControllerID ControllerId, - HidControllerLayouts Layout, - HidControllerKeys Buttons, - JoystickPosition LeftJoystick, - JoystickPosition RightJoystick) - { - Hid.SendControllerButtons(ControllerId, Layout, Buttons, LeftJoystick, RightJoystick); - } - - public void SendTouchScreenEntry(HidTouchScreenEntryTouch TouchPoint) - { - Hid.SendTouchPoint(TouchPoint); - } - internal virtual void OnFinish(EventArgs e) { Finish?.Invoke(this, e); diff --git a/Ryujinx/Ui/GLScreen.cs b/Ryujinx/Ui/GLScreen.cs index 3219303eb5..be49d1fc97 100644 --- a/Ryujinx/Ui/GLScreen.cs +++ b/Ryujinx/Ui/GLScreen.cs @@ -1,7 +1,9 @@ using OpenTK; using OpenTK.Graphics; using OpenTK.Graphics.OpenGL; +using OpenTK.Input; using Ryujinx.Core; +using Ryujinx.Core.Input; using Ryujinx.Graphics.Gal; using System; @@ -9,6 +11,12 @@ namespace Ryujinx { public class GLScreen : GameWindow { + private const int TouchScreenWidth = 1280; + private const int TouchScreenHeight = 720; + + private const float TouchScreenRatioX = (float)TouchScreenWidth / TouchScreenHeight; + private const float TouchScreenRatioY = (float)TouchScreenHeight / TouchScreenWidth; + private Switch Ns; private IGalRenderer Renderer; @@ -32,86 +40,124 @@ namespace Ryujinx protected override void OnUpdateFrame(FrameEventArgs e) { - HidControllerKeys CurrentButton = 0; - JoystickPosition LeftJoystick; - JoystickPosition RightJoystick; - + HidControllerButtons CurrentButton = 0; + HidJoystickPosition LeftJoystick; + HidJoystickPosition RightJoystick; if (Keyboard[OpenTK.Input.Key.Escape]) this.Exit(); - //RightJoystick int LeftJoystickDX = 0; int LeftJoystickDY = 0; - if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Left.StickUp]) LeftJoystickDY = short.MaxValue; - if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Left.StickDown]) LeftJoystickDY = -short.MaxValue; - if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Left.StickLeft]) LeftJoystickDX = -short.MaxValue; - if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Left.StickRight]) LeftJoystickDX = short.MaxValue; - if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Left.StickButton]) CurrentButton |= HidControllerKeys.KEY_LSTICK; - - //LeftButtons - if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Left.DPadUp]) CurrentButton |= HidControllerKeys.KEY_DUP; - if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Left.DPadDown]) CurrentButton |= HidControllerKeys.KEY_DDOWN; - if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Left.DPadLeft]) CurrentButton |= HidControllerKeys.KEY_DLEFT; - if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Left.DPadRight]) CurrentButton |= HidControllerKeys.KEY_DRIGHT; - if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Left.ButtonMinus]) CurrentButton |= HidControllerKeys.KEY_MINUS; - if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Left.ButtonL]) CurrentButton |= HidControllerKeys.KEY_L; - if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Left.ButtonZL]) CurrentButton |= HidControllerKeys.KEY_ZL; - - //RightJoystick int RightJoystickDX = 0; int RightJoystickDY = 0; - if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Right.StickUp]) RightJoystickDY = short.MaxValue; - if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Right.StickDown]) RightJoystickDY = -short.MaxValue; - if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Right.StickLeft]) RightJoystickDX = -short.MaxValue; - if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Right.StickRight]) RightJoystickDX = short.MaxValue; - if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Right.StickButton]) CurrentButton |= HidControllerKeys.KEY_RSTICK; + + //RightJoystick + if (Keyboard[(Key)Config.FakeJoyCon.Left.StickUp]) LeftJoystickDY = short.MaxValue; + if (Keyboard[(Key)Config.FakeJoyCon.Left.StickDown]) LeftJoystickDY = -short.MaxValue; + if (Keyboard[(Key)Config.FakeJoyCon.Left.StickLeft]) LeftJoystickDX = -short.MaxValue; + if (Keyboard[(Key)Config.FakeJoyCon.Left.StickRight]) LeftJoystickDX = short.MaxValue; + + //LeftButtons + if (Keyboard[(Key)Config.FakeJoyCon.Left.StickButton]) CurrentButton |= HidControllerButtons.KEY_LSTICK; + if (Keyboard[(Key)Config.FakeJoyCon.Left.DPadUp]) CurrentButton |= HidControllerButtons.KEY_DUP; + if (Keyboard[(Key)Config.FakeJoyCon.Left.DPadDown]) CurrentButton |= HidControllerButtons.KEY_DDOWN; + if (Keyboard[(Key)Config.FakeJoyCon.Left.DPadLeft]) CurrentButton |= HidControllerButtons.KEY_DLEFT; + if (Keyboard[(Key)Config.FakeJoyCon.Left.DPadRight]) CurrentButton |= HidControllerButtons.KEY_DRIGHT; + if (Keyboard[(Key)Config.FakeJoyCon.Left.ButtonMinus]) CurrentButton |= HidControllerButtons.KEY_MINUS; + if (Keyboard[(Key)Config.FakeJoyCon.Left.ButtonL]) CurrentButton |= HidControllerButtons.KEY_L; + if (Keyboard[(Key)Config.FakeJoyCon.Left.ButtonZL]) CurrentButton |= HidControllerButtons.KEY_ZL; + + //RightJoystick + if (Keyboard[(Key)Config.FakeJoyCon.Right.StickUp]) RightJoystickDY = short.MaxValue; + if (Keyboard[(Key)Config.FakeJoyCon.Right.StickDown]) RightJoystickDY = -short.MaxValue; + if (Keyboard[(Key)Config.FakeJoyCon.Right.StickLeft]) RightJoystickDX = -short.MaxValue; + if (Keyboard[(Key)Config.FakeJoyCon.Right.StickRight]) RightJoystickDX = short.MaxValue; //RightButtons - if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Right.ButtonA]) CurrentButton |= HidControllerKeys.KEY_A; - if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Right.ButtonB]) CurrentButton |= HidControllerKeys.KEY_B; - if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Right.ButtonX]) CurrentButton |= HidControllerKeys.KEY_X; - if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Right.ButtonY]) CurrentButton |= HidControllerKeys.KEY_Y; - if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Right.ButtonPlus]) CurrentButton |= HidControllerKeys.KEY_PLUS; - if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Right.ButtonR]) CurrentButton |= HidControllerKeys.KEY_R; - if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Right.ButtonZR]) CurrentButton |= HidControllerKeys.KEY_ZR; + if (Keyboard[(Key)Config.FakeJoyCon.Right.StickButton]) CurrentButton |= HidControllerButtons.KEY_RSTICK; + if (Keyboard[(Key)Config.FakeJoyCon.Right.ButtonA]) CurrentButton |= HidControllerButtons.KEY_A; + if (Keyboard[(Key)Config.FakeJoyCon.Right.ButtonB]) CurrentButton |= HidControllerButtons.KEY_B; + if (Keyboard[(Key)Config.FakeJoyCon.Right.ButtonX]) CurrentButton |= HidControllerButtons.KEY_X; + if (Keyboard[(Key)Config.FakeJoyCon.Right.ButtonY]) CurrentButton |= HidControllerButtons.KEY_Y; + if (Keyboard[(Key)Config.FakeJoyCon.Right.ButtonPlus]) CurrentButton |= HidControllerButtons.KEY_PLUS; + if (Keyboard[(Key)Config.FakeJoyCon.Right.ButtonR]) CurrentButton |= HidControllerButtons.KEY_R; + if (Keyboard[(Key)Config.FakeJoyCon.Right.ButtonZR]) CurrentButton |= HidControllerButtons.KEY_ZR; - LeftJoystick = new JoystickPosition + LeftJoystick = new HidJoystickPosition { DX = LeftJoystickDX, DY = LeftJoystickDY }; - RightJoystick = new JoystickPosition + RightJoystick = new HidJoystickPosition { DX = RightJoystickDX, DY = RightJoystickDY }; + bool HasTouch = false; + //Get screen touch position from left mouse click - //Opentk always captures mouse events, even if out of focus, so check if window is focused. - if (Mouse != null && Focused) - if (Mouse.GetState().LeftButton == OpenTK.Input.ButtonState.Pressed) + //OpenTK always captures mouse events, even if out of focus, so check if window is focused. + if (Focused && Mouse?.GetState().LeftButton == OpenTK.Input.ButtonState.Pressed) + { + int ScrnWidth = Width; + int ScrnHeight = Height; + + if (Width > Height * TouchScreenRatioX) { - HidTouchScreenEntryTouch CurrentPoint = new HidTouchScreenEntryTouch + ScrnWidth = (int)(Height * TouchScreenRatioX); + } + else + { + ScrnHeight = (int)(Width * TouchScreenRatioY); + } + + int StartX = (Width - ScrnWidth) >> 1; + int StartY = (Height - ScrnHeight) >> 1; + + int EndX = StartX + ScrnWidth; + int EndY = StartY + ScrnHeight; + + if (Mouse.X >= StartX && + Mouse.Y >= StartY && + Mouse.X < EndX && + Mouse.Y < EndY) + { + int ScrnMouseX = Mouse.X - StartX; + int ScrnMouseY = Mouse.Y - StartY; + + int MX = (int)(((float)ScrnMouseX / ScrnWidth) * TouchScreenWidth); + int MY = (int)(((float)ScrnMouseY / ScrnHeight) * TouchScreenHeight); + + HidTouchPoint CurrentPoint = new HidTouchPoint { - Timestamp = (uint)Environment.TickCount, - X = (uint)Mouse.X, - Y = (uint)Mouse.Y, + X = MX, + Y = MY, //Placeholder values till more data is acquired DiameterX = 10, DiameterY = 10, - Angle = 90, - - //Only support single touch - TouchIndex = 0, + Angle = 90 }; - if (Mouse.X > -1 && Mouse.Y > -1) - Ns.SendTouchScreenEntry(CurrentPoint); - } - //We just need one pair of JoyCon because it's emulate by the keyboard. - Ns.SendControllerButtons(HidControllerID.CONTROLLER_HANDHELD, HidControllerLayouts.Main, CurrentButton, LeftJoystick, RightJoystick); + HasTouch = true; + + Ns.Hid.SetTouchPoints(CurrentPoint); + } + } + + if (!HasTouch) + { + Ns.Hid.SetTouchPoints(); + } + + Ns.Hid.SetJoyconButton( + HidControllerId.CONTROLLER_HANDHELD, + HidControllerLayouts.Main, + CurrentButton, + LeftJoystick, + RightJoystick); } protected override void OnRenderFrame(FrameEventArgs e) From 646af2498c8ef74546f73ed993f9037e4882493b Mon Sep 17 00:00:00 2001 From: gdkchan Date: Sat, 3 Mar 2018 02:24:04 -0300 Subject: [PATCH 12/17] Fix paths using ascii instead of utf8 on IFileSystem --- .../OsHle/Services/FspSrv/IFileSystem.cs | 47 ++++++++++++++----- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/Ryujinx.Core/OsHle/Services/FspSrv/IFileSystem.cs b/Ryujinx.Core/OsHle/Services/FspSrv/IFileSystem.cs index ee9de8bc8c..7db0815485 100644 --- a/Ryujinx.Core/OsHle/Services/FspSrv/IFileSystem.cs +++ b/Ryujinx.Core/OsHle/Services/FspSrv/IFileSystem.cs @@ -3,6 +3,7 @@ using Ryujinx.Core.OsHle.Ipc; using System; using System.Collections.Generic; using System.IO; +using System.Text; using static Ryujinx.Core.OsHle.IpcServices.ErrorCode; using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; @@ -49,7 +50,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.FspSrv { long Position = Context.Request.PtrBuff[0].Position; - string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position); + string Name = ReadUtf8String(Context.Memory, Position); long Mode = Context.RequestData.ReadInt64(); int Size = Context.RequestData.ReadInt32(); @@ -83,7 +84,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.FspSrv { long Position = Context.Request.PtrBuff[0].Position; - string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position); + string Name = ReadUtf8String(Context.Memory, Position); string FileName = Context.Ns.VFs.GetFullPath(Path, Name); @@ -106,7 +107,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.FspSrv { long Position = Context.Request.PtrBuff[0].Position; - string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position); + string Name = ReadUtf8String(Context.Memory, Position); string DirName = Context.Ns.VFs.GetFullPath(Path, Name); @@ -144,7 +145,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.FspSrv { long Position = Context.Request.PtrBuff[0].Position; - string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position); + string Name = ReadUtf8String(Context.Memory, Position); string DirName = Context.Ns.VFs.GetFullPath(Path, Name); @@ -168,8 +169,8 @@ namespace Ryujinx.Core.OsHle.IpcServices.FspSrv long OldPosition = Context.Request.PtrBuff[0].Position; long NewPosition = Context.Request.PtrBuff[0].Position; - string OldName = AMemoryHelper.ReadAsciiString(Context.Memory, OldPosition); - string NewName = AMemoryHelper.ReadAsciiString(Context.Memory, NewPosition); + string OldName = ReadUtf8String(Context.Memory, OldPosition); + string NewName = ReadUtf8String(Context.Memory, NewPosition); string OldFileName = Context.Ns.VFs.GetFullPath(Path, OldName); string NewFileName = Context.Ns.VFs.GetFullPath(Path, NewName); @@ -199,8 +200,8 @@ namespace Ryujinx.Core.OsHle.IpcServices.FspSrv long OldPosition = Context.Request.PtrBuff[0].Position; long NewPosition = Context.Request.PtrBuff[0].Position; - string OldName = AMemoryHelper.ReadAsciiString(Context.Memory, OldPosition); - string NewName = AMemoryHelper.ReadAsciiString(Context.Memory, NewPosition); + string OldName = ReadUtf8String(Context.Memory, OldPosition); + string NewName = ReadUtf8String(Context.Memory, NewPosition); string OldDirName = Context.Ns.VFs.GetFullPath(Path, OldName); string NewDirName = Context.Ns.VFs.GetFullPath(Path, NewName); @@ -229,7 +230,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.FspSrv { long Position = Context.Request.PtrBuff[0].Position; - string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position); + string Name = ReadUtf8String(Context.Memory, Position); string FileName = Context.Ns.VFs.GetFullPath(Path, Name); @@ -257,7 +258,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.FspSrv int FilterFlags = Context.RequestData.ReadInt32(); - string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position); + string Name = ReadUtf8String(Context.Memory, Position); string FileName = Context.Ns.VFs.GetFullPath(Path, Name); @@ -293,7 +294,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.FspSrv int FilterFlags = Context.RequestData.ReadInt32(); - string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position); + string Name = ReadUtf8String(Context.Memory, Position); string DirName = Context.Ns.VFs.GetFullPath(Path, Name); @@ -330,7 +331,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.FspSrv { long Position = Context.Request.PtrBuff[0].Position; - string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position); + string Name = ReadUtf8String(Context.Memory, Position); Context.ResponseData.Write(Context.Ns.VFs.GetDrive().AvailableFreeSpace); @@ -341,7 +342,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.FspSrv { long Position = Context.Request.PtrBuff[0].Position; - string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position); + string Name = ReadUtf8String(Context.Memory, Position); Context.ResponseData.Write(Context.Ns.VFs.GetDrive().TotalSize); @@ -379,5 +380,25 @@ namespace Ryujinx.Core.OsHle.IpcServices.FspSrv OpenPaths.Remove(DirInterface.HostPath); } } + + private string ReadUtf8String(AMemory Memory, long Position) + { + using (MemoryStream MS = new MemoryStream()) + { + while (true) + { + byte Value = Memory.ReadByte(Position++); + + if (Value == 0) + { + break; + } + + MS.WriteByte(Value); + } + + return Encoding.UTF8.GetString(MS.ToArray()); + } + } } } \ No newline at end of file From 7d48886750dadf839eb2bb37e3a81314b5497c36 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Sat, 3 Mar 2018 14:04:58 -0300 Subject: [PATCH 13/17] Fix Rename* functions on FspSrv, add a separate class do hold system settings on Switch --- .../OsHle/Services/FspSrv/IFileSystem.cs | 41 +++++++++---------- .../OsHle/Services/Set/ServiceSetSys.cs | 4 +- Ryujinx.Core/Settings/ColorSet.cs | 8 ++++ Ryujinx.Core/Settings/SetSys.cs | 7 ++++ Ryujinx.Core/Switch.cs | 11 +++-- 5 files changed, 44 insertions(+), 27 deletions(-) create mode 100644 Ryujinx.Core/Settings/ColorSet.cs create mode 100644 Ryujinx.Core/Settings/SetSys.cs diff --git a/Ryujinx.Core/OsHle/Services/FspSrv/IFileSystem.cs b/Ryujinx.Core/OsHle/Services/FspSrv/IFileSystem.cs index 7db0815485..3593bafbbe 100644 --- a/Ryujinx.Core/OsHle/Services/FspSrv/IFileSystem.cs +++ b/Ryujinx.Core/OsHle/Services/FspSrv/IFileSystem.cs @@ -50,7 +50,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.FspSrv { long Position = Context.Request.PtrBuff[0].Position; - string Name = ReadUtf8String(Context.Memory, Position); + string Name = ReadUtf8String(Context); long Mode = Context.RequestData.ReadInt64(); int Size = Context.RequestData.ReadInt32(); @@ -84,7 +84,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.FspSrv { long Position = Context.Request.PtrBuff[0].Position; - string Name = ReadUtf8String(Context.Memory, Position); + string Name = ReadUtf8String(Context); string FileName = Context.Ns.VFs.GetFullPath(Path, Name); @@ -107,7 +107,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.FspSrv { long Position = Context.Request.PtrBuff[0].Position; - string Name = ReadUtf8String(Context.Memory, Position); + string Name = ReadUtf8String(Context); string DirName = Context.Ns.VFs.GetFullPath(Path, Name); @@ -145,7 +145,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.FspSrv { long Position = Context.Request.PtrBuff[0].Position; - string Name = ReadUtf8String(Context.Memory, Position); + string Name = ReadUtf8String(Context); string DirName = Context.Ns.VFs.GetFullPath(Path, Name); @@ -166,11 +166,8 @@ namespace Ryujinx.Core.OsHle.IpcServices.FspSrv public long RenameFile(ServiceCtx Context) { - long OldPosition = Context.Request.PtrBuff[0].Position; - long NewPosition = Context.Request.PtrBuff[0].Position; - - string OldName = ReadUtf8String(Context.Memory, OldPosition); - string NewName = ReadUtf8String(Context.Memory, NewPosition); + string OldName = ReadUtf8String(Context, 0); + string NewName = ReadUtf8String(Context, 1); string OldFileName = Context.Ns.VFs.GetFullPath(Path, OldName); string NewFileName = Context.Ns.VFs.GetFullPath(Path, NewName); @@ -197,11 +194,8 @@ namespace Ryujinx.Core.OsHle.IpcServices.FspSrv public long RenameDirectory(ServiceCtx Context) { - long OldPosition = Context.Request.PtrBuff[0].Position; - long NewPosition = Context.Request.PtrBuff[0].Position; - - string OldName = ReadUtf8String(Context.Memory, OldPosition); - string NewName = ReadUtf8String(Context.Memory, NewPosition); + string OldName = ReadUtf8String(Context, 0); + string NewName = ReadUtf8String(Context, 1); string OldDirName = Context.Ns.VFs.GetFullPath(Path, OldName); string NewDirName = Context.Ns.VFs.GetFullPath(Path, NewName); @@ -230,7 +224,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.FspSrv { long Position = Context.Request.PtrBuff[0].Position; - string Name = ReadUtf8String(Context.Memory, Position); + string Name = ReadUtf8String(Context); string FileName = Context.Ns.VFs.GetFullPath(Path, Name); @@ -258,7 +252,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.FspSrv int FilterFlags = Context.RequestData.ReadInt32(); - string Name = ReadUtf8String(Context.Memory, Position); + string Name = ReadUtf8String(Context); string FileName = Context.Ns.VFs.GetFullPath(Path, Name); @@ -294,7 +288,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.FspSrv int FilterFlags = Context.RequestData.ReadInt32(); - string Name = ReadUtf8String(Context.Memory, Position); + string Name = ReadUtf8String(Context); string DirName = Context.Ns.VFs.GetFullPath(Path, Name); @@ -331,7 +325,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.FspSrv { long Position = Context.Request.PtrBuff[0].Position; - string Name = ReadUtf8String(Context.Memory, Position); + string Name = ReadUtf8String(Context); Context.ResponseData.Write(Context.Ns.VFs.GetDrive().AvailableFreeSpace); @@ -342,7 +336,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.FspSrv { long Position = Context.Request.PtrBuff[0].Position; - string Name = ReadUtf8String(Context.Memory, Position); + string Name = ReadUtf8String(Context); Context.ResponseData.Write(Context.Ns.VFs.GetDrive().TotalSize); @@ -381,13 +375,16 @@ namespace Ryujinx.Core.OsHle.IpcServices.FspSrv } } - private string ReadUtf8String(AMemory Memory, long Position) + private string ReadUtf8String(ServiceCtx Context, int Index = 0) { + long Position = Context.Request.PtrBuff[Index].Position; + long Size = Context.Request.PtrBuff[Index].Size; + using (MemoryStream MS = new MemoryStream()) { - while (true) + while (Size-- > 0) { - byte Value = Memory.ReadByte(Position++); + byte Value = Context.Memory.ReadByte(Position++); if (Value == 0) { diff --git a/Ryujinx.Core/OsHle/Services/Set/ServiceSetSys.cs b/Ryujinx.Core/OsHle/Services/Set/ServiceSetSys.cs index 68b3035426..41c5d8b3b3 100644 --- a/Ryujinx.Core/OsHle/Services/Set/ServiceSetSys.cs +++ b/Ryujinx.Core/OsHle/Services/Set/ServiceSetSys.cs @@ -22,8 +22,8 @@ namespace Ryujinx.Core.OsHle.IpcServices.Set public static long GetColorSetId(ServiceCtx Context) { - //Use white system theme - Context.ResponseData.Write(1); + Context.ResponseData.Write((int)Context.Ns.Settings.ThemeColor); + return 0; } diff --git a/Ryujinx.Core/Settings/ColorSet.cs b/Ryujinx.Core/Settings/ColorSet.cs new file mode 100644 index 0000000000..43483363fa --- /dev/null +++ b/Ryujinx.Core/Settings/ColorSet.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.Core.Settings +{ + public enum ColorSet + { + BasicWhite = 0, + BasicBlack = 1 + } +} diff --git a/Ryujinx.Core/Settings/SetSys.cs b/Ryujinx.Core/Settings/SetSys.cs new file mode 100644 index 0000000000..d8b6eb6ef5 --- /dev/null +++ b/Ryujinx.Core/Settings/SetSys.cs @@ -0,0 +1,7 @@ +namespace Ryujinx.Core.Settings +{ + public class SetSys + { + public ColorSet ThemeColor; + } +} diff --git a/Ryujinx.Core/Switch.cs b/Ryujinx.Core/Switch.cs index 0d5f8e72fd..6f41da8144 100644 --- a/Ryujinx.Core/Switch.cs +++ b/Ryujinx.Core/Switch.cs @@ -1,6 +1,7 @@ using ChocolArm64.Memory; using Ryujinx.Core.Input; using Ryujinx.Core.OsHle; +using Ryujinx.Core.Settings; using Ryujinx.Graphics.Gal; using Ryujinx.Graphics.Gpu; using System; @@ -15,7 +16,9 @@ namespace Ryujinx.Core internal NsGpu Gpu { get; private set; } internal Horizon Os { get; private set; } internal VirtualFs VFs { get; private set; } - public Hid Hid { get; private set; } + + public Hid Hid { get; private set; } + public SetSys Settings { get; private set; } public event EventHandler Finish; @@ -24,9 +27,11 @@ namespace Ryujinx.Core Ram = Marshal.AllocHGlobal((IntPtr)AMemoryMgr.RamSize); Gpu = new NsGpu(Renderer); - Os = new Horizon(this); VFs = new VirtualFs(); - Hid = new Hid(this); + + Hid = new Hid(this); + Os = new Horizon(this); + Settings = new SetSys(); } public void FinalizeAllProcesses() From 8dcffe6a5103920ab63e46f93029b27e311335f3 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Sun, 4 Mar 2018 00:06:44 -0300 Subject: [PATCH 14/17] Fix hid touch screen timestamp, add more log info --- Ryujinx.Core/Hid/Hid.cs | 14 ++++++++++++-- Ryujinx.Core/OsHle/Process.cs | 14 +++++++++++++- Ryujinx.Core/OsHle/Services/FspSrv/IFileSystem.cs | 1 - Ryujinx.Core/OsHle/Services/Hid/ServiceHid.cs | 6 ++++++ Ryujinx.Core/OsHle/Services/Nv/ServiceNvDrv.cs | 4 +++- Ryujinx/Ui/GLScreen.cs | 4 ++-- 6 files changed, 36 insertions(+), 7 deletions(-) diff --git a/Ryujinx.Core/Hid/Hid.cs b/Ryujinx.Core/Hid/Hid.cs index 4dbac40cbd..c76782cffe 100644 --- a/Ryujinx.Core/Hid/Hid.cs +++ b/Ryujinx.Core/Hid/Hid.cs @@ -164,6 +164,8 @@ namespace Ryujinx.Core.Input public void SetTouchPoints(params HidTouchPoint[] Points) { + Logging.Debug("hid touch"); + long LastEntry = ReadInt64(HidTouchScreenOffset + 0x10); long CurrEntry = (LastEntry + 1) % HidEntryCount; @@ -178,9 +180,13 @@ namespace Ryujinx.Core.Input long TouchEntryOffset = HidTouchScreenOffset + HidTouchHeaderSize; - TouchEntryOffset += CurrEntry * HidTouchEntrySize; + long LastEntryOffset = TouchEntryOffset + LastEntry * HidTouchEntrySize; - WriteInt64(TouchEntryOffset + 0x0, Timestamp); + long LastTimestamp = ReadInt64(LastEntryOffset); + + TouchEntryOffset += CurrEntry * HidTouchEntrySize; + + WriteInt64(TouchEntryOffset + 0x0, LastTimestamp + 1); WriteInt64(TouchEntryOffset + 0x8, Points.Length); TouchEntryOffset += HidTouchEntryHeaderSize; @@ -220,6 +226,8 @@ namespace Ryujinx.Core.Input if ((ulong)Position + 4 > AMemoryMgr.AddrSize) return; + Logging.Debug($"hid wr32 {Position:x8} {Value:x8}"); + *((int*)((byte*)Ns.Ram + Position)) = Value; } @@ -229,6 +237,8 @@ namespace Ryujinx.Core.Input if ((ulong)Position + 8 > AMemoryMgr.AddrSize) return; + Logging.Debug($"hid wr64 {Position:x8} {Value:x16}"); + *((long*)((byte*)Ns.Ram + Position)) = Value; } } diff --git a/Ryujinx.Core/OsHle/Process.cs b/Ryujinx.Core/OsHle/Process.cs index 84a21a8c1b..f549b02792 100644 --- a/Ryujinx.Core/OsHle/Process.cs +++ b/Ryujinx.Core/OsHle/Process.cs @@ -239,7 +239,19 @@ namespace Ryujinx.Core.OsHle private void CpuTraceHandler(object sender, ACpuTraceEventArgs e) { - Logging.Trace($"Executing at 0x{e.Position:x16} {e.SubName}"); + string NsoName = string.Empty; + + for (int Index = Executables.Count - 1; Index >= 0; Index--) + { + if (e.Position >= Executables[Index].ImageBase) + { + NsoName = $"{(e.Position - Executables[Index].ImageBase):x16}"; + + break; + } + } + + Logging.Trace($"Executing at 0x{e.Position:x16} {e.SubName} {NsoName}"); } public void EnableCpuTracing() diff --git a/Ryujinx.Core/OsHle/Services/FspSrv/IFileSystem.cs b/Ryujinx.Core/OsHle/Services/FspSrv/IFileSystem.cs index 3593bafbbe..569a7dd6b4 100644 --- a/Ryujinx.Core/OsHle/Services/FspSrv/IFileSystem.cs +++ b/Ryujinx.Core/OsHle/Services/FspSrv/IFileSystem.cs @@ -1,4 +1,3 @@ -using ChocolArm64.Memory; using Ryujinx.Core.OsHle.Ipc; using System; using System.Collections.Generic; diff --git a/Ryujinx.Core/OsHle/Services/Hid/ServiceHid.cs b/Ryujinx.Core/OsHle/Services/Hid/ServiceHid.cs index b0e5f44e27..cc30a771e0 100644 --- a/Ryujinx.Core/OsHle/Services/Hid/ServiceHid.cs +++ b/Ryujinx.Core/OsHle/Services/Hid/ServiceHid.cs @@ -26,6 +26,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Hid { 121, GetNpadJoyHoldType }, { 200, GetVibrationDeviceInfo }, { 203, CreateActiveVibrationDeviceList }, + { 206, SendVibrationValues } }; } @@ -104,5 +105,10 @@ namespace Ryujinx.Core.OsHle.IpcServices.Hid return 0; } + + public long SendVibrationValues(ServiceCtx Context) + { + return 0; + } } } \ 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 1de0ab7062..2f2238914b 100644 --- a/Ryujinx.Core/OsHle/Services/Nv/ServiceNvDrv.cs +++ b/Ryujinx.Core/OsHle/Services/Nv/ServiceNvDrv.cs @@ -532,6 +532,8 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices Context.Memory.WriteInt32(Position + 4, Handle); + Logging.Info($"NvMap {Id} created with size {Size:x8}!"); + return 0; } @@ -580,7 +582,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices NvMap.Kind = Kind; } - Logging.Debug($"NvMapIocAlloc at {NvMap.Address:x16}"); + Logging.Debug($"{NvMap.Address:x16}"); return 0; } diff --git a/Ryujinx/Ui/GLScreen.cs b/Ryujinx/Ui/GLScreen.cs index be49d1fc97..1e48b28056 100644 --- a/Ryujinx/Ui/GLScreen.cs +++ b/Ryujinx/Ui/GLScreen.cs @@ -44,7 +44,7 @@ namespace Ryujinx HidJoystickPosition LeftJoystick; HidJoystickPosition RightJoystick; - if (Keyboard[OpenTK.Input.Key.Escape]) this.Exit(); + if (Keyboard[Key.Escape]) this.Exit(); int LeftJoystickDX = 0; int LeftJoystickDY = 0; @@ -99,7 +99,7 @@ namespace Ryujinx //Get screen touch position from left mouse click //OpenTK always captures mouse events, even if out of focus, so check if window is focused. - if (Focused && Mouse?.GetState().LeftButton == OpenTK.Input.ButtonState.Pressed) + if (Focused && Mouse?.GetState().LeftButton == ButtonState.Pressed) { int ScrnWidth = Width; int ScrnHeight = Height; From 479443564c5372ec9c768a9d41b1ffbdbbd5dd41 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Sun, 4 Mar 2018 00:09:16 -0300 Subject: [PATCH 15/17] Remove unneeded log messages --- Ryujinx.Core/Hid/Hid.cs | 6 ------ Ryujinx.Core/OsHle/Services/Nv/ServiceNvDrv.cs | 2 -- 2 files changed, 8 deletions(-) diff --git a/Ryujinx.Core/Hid/Hid.cs b/Ryujinx.Core/Hid/Hid.cs index c76782cffe..d7227889a6 100644 --- a/Ryujinx.Core/Hid/Hid.cs +++ b/Ryujinx.Core/Hid/Hid.cs @@ -164,8 +164,6 @@ namespace Ryujinx.Core.Input public void SetTouchPoints(params HidTouchPoint[] Points) { - Logging.Debug("hid touch"); - long LastEntry = ReadInt64(HidTouchScreenOffset + 0x10); long CurrEntry = (LastEntry + 1) % HidEntryCount; @@ -226,8 +224,6 @@ namespace Ryujinx.Core.Input if ((ulong)Position + 4 > AMemoryMgr.AddrSize) return; - Logging.Debug($"hid wr32 {Position:x8} {Value:x8}"); - *((int*)((byte*)Ns.Ram + Position)) = Value; } @@ -237,8 +233,6 @@ namespace Ryujinx.Core.Input if ((ulong)Position + 8 > AMemoryMgr.AddrSize) return; - Logging.Debug($"hid wr64 {Position:x8} {Value:x16}"); - *((long*)((byte*)Ns.Ram + Position)) = Value; } } diff --git a/Ryujinx.Core/OsHle/Services/Nv/ServiceNvDrv.cs b/Ryujinx.Core/OsHle/Services/Nv/ServiceNvDrv.cs index 2f2238914b..0ea1d2ac0a 100644 --- a/Ryujinx.Core/OsHle/Services/Nv/ServiceNvDrv.cs +++ b/Ryujinx.Core/OsHle/Services/Nv/ServiceNvDrv.cs @@ -582,8 +582,6 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices NvMap.Kind = Kind; } - Logging.Debug($"{NvMap.Address:x16}"); - return 0; } From ee9df32e3e13fe982c8154a6454566c8edfa13d3 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Sun, 4 Mar 2018 01:41:35 -0300 Subject: [PATCH 16/17] Do not block execution on audout append buffer --- Ryujinx.Core/OsHle/Services/Aud/IAudioOut.cs | 42 +++++++++++++++----- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/Ryujinx.Core/OsHle/Services/Aud/IAudioOut.cs b/Ryujinx.Core/OsHle/Services/Aud/IAudioOut.cs index 0562d4b9a5..c58d9e804c 100644 --- a/Ryujinx.Core/OsHle/Services/Aud/IAudioOut.cs +++ b/Ryujinx.Core/OsHle/Services/Aud/IAudioOut.cs @@ -9,7 +9,7 @@ using System.IO; namespace Ryujinx.Core.OsHle.IpcServices.Aud { - class IAudioOut : IIpcService + class IAudioOut : IIpcService, IDisposable { private Dictionary m_Commands; @@ -121,6 +121,8 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud { if (AudioCtx == null) //Needed to call the instance of AudioContext() return 0; + + EnsureAudioFinalized(); Source = AL.GenSource(); Buffer = AL.GenBuffer(); @@ -128,16 +130,6 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud AL.BufferData(Buffer, ALFormat.Stereo16, AudioSampleBuffer, AudioSampleBuffer.Length, 48000); AL.SourceQueueBuffer(Source, Buffer); AL.SourcePlay(Source); - - int State; - - do AL.GetSource(Source, ALGetSourcei.SourceState, out State); - while ((ALSourceState)State == ALSourceState.Playing); - - AL.SourceStop(Source); - AL.SourceUnqueueBuffer(Buffer); - AL.DeleteSource(Source); - AL.DeleteBuffers(1, ref Buffer); } } } @@ -186,5 +178,33 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud { return 0; } + + private void EnsureAudioFinalized() + { + if (Source != 0 || + Buffer != 0) + { + AL.SourceStop(Source); + AL.SourceUnqueueBuffer(Buffer); + AL.DeleteSource(Source); + AL.DeleteBuffers(1, ref Buffer); + + Source = 0; + Buffer = 0; + } + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + EnsureAudioFinalized(); + } + } } } From 3edb66f389ac279bdcde26c5682aa39b9bf5f853 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Sun, 4 Mar 2018 14:09:59 -0300 Subject: [PATCH 17/17] Improve CPU initial translation speeds (#50) * Add background translation to the CPU * Do not use a separate thread for translation, implement 2 tiers translation * Remove unnecessary usings * Lower MinCallCountForReJit * Remove unused variable --- ChocolArm64/ATranslatedSub.cs | 104 +++++++++++------- ChocolArm64/ATranslatedSubType.cs | 9 ++ ChocolArm64/ATranslator.cs | 81 +++++++++++--- ChocolArm64/Decoder/ADecoder.cs | 16 ++- ChocolArm64/Instruction/AInstEmitException.cs | 13 +++ ChocolArm64/Instruction/AInstEmitFlow.cs | 81 ++++++++++++-- ChocolArm64/Translation/AILEmitter.cs | 42 +++---- ChocolArm64/Translation/AILEmitterCtx.cs | 58 +++++++--- ChocolArm64/Translation/ALocalAlloc.cs | 18 +-- .../OsHle/Services/Set/ServiceSetSys.cs | 4 +- 10 files changed, 319 insertions(+), 107 deletions(-) create mode 100644 ChocolArm64/ATranslatedSubType.cs diff --git a/ChocolArm64/ATranslatedSub.cs b/ChocolArm64/ATranslatedSub.cs index 71a6793a2a..414038ab6e 100644 --- a/ChocolArm64/ATranslatedSub.cs +++ b/ChocolArm64/ATranslatedSub.cs @@ -2,6 +2,7 @@ using ChocolArm64.Memory; using ChocolArm64.State; using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Reflection; using System.Reflection.Emit; @@ -13,35 +14,47 @@ namespace ChocolArm64 private AA64Subroutine ExecDelegate; - private bool HasDelegate; - - public static Type[] FixedArgTypes { get; private set; } - public static int StateArgIdx { get; private set; } public static int MemoryArgIdx { get; private set; } + public static Type[] FixedArgTypes { get; private set; } + public DynamicMethod Method { get; private set; } - public HashSet SubCalls { get; private set; } + public ReadOnlyCollection Params { get; private set; } - public List Params { get; private set; } + private HashSet Callees; - public bool NeedsReJit { get; private set; } + private ATranslatedSubType Type; - public ATranslatedSub() + private int CallCount; + + private bool NeedsReJit; + + private int MinCallCountForReJit = 250; + + public ATranslatedSub(DynamicMethod Method, List Params, HashSet Callees) { - SubCalls = new HashSet(); - } + if (Method == null) + { + throw new ArgumentNullException(nameof(Method)); + } - public ATranslatedSub(DynamicMethod Method, List Params) : this() - { if (Params == null) { throw new ArgumentNullException(nameof(Params)); } - this.Method = Method; - this.Params = Params; + if (Callees == null) + { + throw new ArgumentNullException(nameof(Callees)); + } + + this.Method = Method; + this.Params = Params.AsReadOnly(); + this.Callees = Callees; + + PrepareDelegate(); } static ATranslatedSub() @@ -69,36 +82,53 @@ namespace ChocolArm64 } } - public long Execute(AThreadState ThreadState, AMemory Memory) + private void PrepareDelegate() { - if (!HasDelegate) + string Name = $"{Method.Name}_Dispatch"; + + DynamicMethod Mthd = new DynamicMethod(Name, typeof(long), FixedArgTypes); + + ILGenerator Generator = Mthd.GetILGenerator(); + + Generator.EmitLdargSeq(FixedArgTypes.Length); + + foreach (ARegister Reg in Params) { - string Name = $"{Method.Name}_Dispatch"; + Generator.EmitLdarg(StateArgIdx); - DynamicMethod Mthd = new DynamicMethod(Name, typeof(long), FixedArgTypes); - - ILGenerator Generator = Mthd.GetILGenerator(); - - Generator.EmitLdargSeq(FixedArgTypes.Length); - - foreach (ARegister Reg in Params) - { - Generator.EmitLdarg(StateArgIdx); - - Generator.Emit(OpCodes.Ldfld, Reg.GetField()); - } - - Generator.Emit(OpCodes.Call, Method); - Generator.Emit(OpCodes.Ret); - - ExecDelegate = (AA64Subroutine)Mthd.CreateDelegate(typeof(AA64Subroutine)); - - HasDelegate = true; + Generator.Emit(OpCodes.Ldfld, Reg.GetField()); } + Generator.Emit(OpCodes.Call, Method); + Generator.Emit(OpCodes.Ret); + + ExecDelegate = (AA64Subroutine)Mthd.CreateDelegate(typeof(AA64Subroutine)); + } + + public bool ShouldReJit() + { + if (Type == ATranslatedSubType.SubTier0) + { + if (CallCount < MinCallCountForReJit) + { + CallCount++; + } + + return CallCount == MinCallCountForReJit; + } + + return Type == ATranslatedSubType.SubTier1 && NeedsReJit; + } + + public long Execute(AThreadState ThreadState, AMemory Memory) + { return ExecDelegate(ThreadState, Memory); } - public void MarkForReJit() => NeedsReJit = true; + public void SetType(ATranslatedSubType Type) => this.Type = Type; + + public bool HasCallee(long Position) => Callees.Contains(Position); + + public void MarkForReJit() => NeedsReJit = true; } } \ No newline at end of file diff --git a/ChocolArm64/ATranslatedSubType.cs b/ChocolArm64/ATranslatedSubType.cs new file mode 100644 index 0000000000..e9f3e0bf00 --- /dev/null +++ b/ChocolArm64/ATranslatedSubType.cs @@ -0,0 +1,9 @@ +namespace ChocolArm64 +{ + enum ATranslatedSubType + { + SubBlock, + SubTier0, + SubTier1 + } +} \ No newline at end of file diff --git a/ChocolArm64/ATranslator.cs b/ChocolArm64/ATranslator.cs index 2daf7bbc96..ab434e2267 100644 --- a/ChocolArm64/ATranslator.cs +++ b/ChocolArm64/ATranslator.cs @@ -7,11 +7,14 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Reflection.Emit; +using System.Threading; namespace ChocolArm64 { public class ATranslator { + private HashSet SubBlocks; + private ConcurrentDictionary CachedSubs; private ConcurrentDictionary SymbolTable; @@ -24,6 +27,8 @@ namespace ChocolArm64 public ATranslator(IReadOnlyDictionary SymbolTable = null) { + SubBlocks = new HashSet(); + CachedSubs = new ConcurrentDictionary(); if (SymbolTable != null) @@ -38,9 +43,9 @@ namespace ChocolArm64 KeepRunning = true; } - public void StopExecution() => KeepRunning = false; + internal void StopExecution() => KeepRunning = false; - public void ExecuteSubroutine(AThread Thread, long Position) + internal void ExecuteSubroutine(AThread Thread, long Position) { do { @@ -54,9 +59,14 @@ namespace ChocolArm64 CpuTrace?.Invoke(this, new ACpuTraceEventArgs(Position, SubName)); } - if (!CachedSubs.TryGetValue(Position, out ATranslatedSub Sub) || Sub.NeedsReJit) + if (!CachedSubs.TryGetValue(Position, out ATranslatedSub Sub)) { - Sub = TranslateSubroutine(Thread.Memory, Position); + Sub = TranslateTier0(Thread.Memory, Position); + } + + if (Sub.ShouldReJit()) + { + TranslateTier1(Thread.Memory, Position); } Position = Sub.Execute(Thread.ThreadState, Thread.Memory); @@ -86,19 +96,57 @@ namespace ChocolArm64 return CachedSubs.ContainsKey(Position); } - private ATranslatedSub TranslateSubroutine(AMemory Memory, long Position) + private ATranslatedSub TranslateTier0(AMemory Memory, long Position) + { + ABlock Block = ADecoder.DecodeBasicBlock(this, Memory, Position); + + ABlock[] Graph = new ABlock[] { Block }; + + string SubName = GetSubName(Position); + + AILEmitterCtx Context = new AILEmitterCtx(this, Graph, Block, SubName); + + do + { + Context.EmitOpCode(); + } + while (Context.AdvanceOpCode()); + + ATranslatedSub Subroutine = Context.GetSubroutine(); + + if (SubBlocks.Contains(Position)) + { + SubBlocks.Remove(Position); + + Subroutine.SetType(ATranslatedSubType.SubBlock); + } + else + { + Subroutine.SetType(ATranslatedSubType.SubTier0); + } + + CachedSubs.AddOrUpdate(Position, Subroutine, (Key, OldVal) => Subroutine); + + AOpCode LastOp = Block.GetLastOp(); + + if (LastOp.Emitter != AInstEmit.Ret && + LastOp.Emitter != AInstEmit.Br) + { + SubBlocks.Add(LastOp.Position + 4); + } + + return Subroutine; + } + + private void TranslateTier1(AMemory Memory, long Position) { (ABlock[] Graph, ABlock Root) Cfg = ADecoder.DecodeSubroutine(this, Memory, Position); - string SubName = SymbolTable.GetOrAdd(Position, $"Sub{Position:x16}"); + string SubName = GetSubName(Position); PropagateName(Cfg.Graph, SubName); - AILEmitterCtx Context = new AILEmitterCtx( - this, - Cfg.Graph, - Cfg.Root, - SubName); + AILEmitterCtx Context = new AILEmitterCtx(this, Cfg.Graph, Cfg.Root, SubName); if (Context.CurrBlock.Position != Position) { @@ -115,7 +163,7 @@ namespace ChocolArm64 //since we can now call it directly which is faster. foreach (ATranslatedSub TS in CachedSubs.Values) { - if (TS.SubCalls.Contains(Position)) + if (TS.HasCallee(Position)) { TS.MarkForReJit(); } @@ -123,9 +171,14 @@ namespace ChocolArm64 ATranslatedSub Subroutine = Context.GetSubroutine(); - CachedSubs.AddOrUpdate(Position, Subroutine, (Key, OldVal) => Subroutine); + Subroutine.SetType(ATranslatedSubType.SubTier1); - return Subroutine; + CachedSubs.AddOrUpdate(Position, Subroutine, (Key, OldVal) => Subroutine); + } + + private string GetSubName(long Position) + { + return SymbolTable.GetOrAdd(Position, $"Sub{Position:x16}"); } private void PropagateName(ABlock[] Graph, string Name) diff --git a/ChocolArm64/Decoder/ADecoder.cs b/ChocolArm64/Decoder/ADecoder.cs index 4430229034..2375c18572 100644 --- a/ChocolArm64/Decoder/ADecoder.cs +++ b/ChocolArm64/Decoder/ADecoder.cs @@ -18,6 +18,18 @@ namespace ChocolArm64.Decoder OpActivators = new ConcurrentDictionary(); } + public static ABlock DecodeBasicBlock( + ATranslator Translator, + AMemory Memory, + long Start) + { + ABlock Block = new ABlock(Start); + + FillBlock(Memory, Block); + + return Block; + } + public static (ABlock[] Graph, ABlock Root) DecodeSubroutine( ATranslator Translator, AMemory Memory, @@ -72,8 +84,8 @@ namespace ChocolArm64.Decoder } } - if ((!(LastOp is AOpCodeBImmAl) && - !(LastOp is AOpCodeBReg)) || HasCachedSub) + if (!((LastOp is AOpCodeBImmAl) || + (LastOp is AOpCodeBReg)) || HasCachedSub) { Current.Next = Enqueue(Current.EndPosition); } diff --git a/ChocolArm64/Instruction/AInstEmitException.cs b/ChocolArm64/Instruction/AInstEmitException.cs index 209ba56f5b..fe348edd17 100644 --- a/ChocolArm64/Instruction/AInstEmitException.cs +++ b/ChocolArm64/Instruction/AInstEmitException.cs @@ -2,6 +2,7 @@ using ChocolArm64.Decoder; using ChocolArm64.State; using ChocolArm64.Translation; using System.Reflection; +using System.Reflection.Emit; namespace ChocolArm64.Instruction { @@ -37,6 +38,12 @@ namespace ChocolArm64.Instruction { Context.EmitLoadState(Context.CurrBlock.Next); } + else + { + Context.EmitLdc_I8(Op.Position + 4); + + Context.Emit(OpCodes.Ret); + } } public static void Und(AILEmitterCtx Context) @@ -60,6 +67,12 @@ namespace ChocolArm64.Instruction { Context.EmitLoadState(Context.CurrBlock.Next); } + else + { + Context.EmitLdc_I8(Op.Position + 4); + + Context.Emit(OpCodes.Ret); + } } } } \ No newline at end of file diff --git a/ChocolArm64/Instruction/AInstEmitFlow.cs b/ChocolArm64/Instruction/AInstEmitFlow.cs index be68aa6c97..91262834f9 100644 --- a/ChocolArm64/Instruction/AInstEmitFlow.cs +++ b/ChocolArm64/Instruction/AInstEmitFlow.cs @@ -11,14 +11,24 @@ namespace ChocolArm64.Instruction { AOpCodeBImmAl Op = (AOpCodeBImmAl)Context.CurrOp; - Context.Emit(OpCodes.Br, Context.GetLabel(Op.Imm)); + if (Context.CurrBlock.Branch != null) + { + Context.Emit(OpCodes.Br, Context.GetLabel(Op.Imm)); + } + else + { + Context.EmitStoreState(); + Context.EmitLdc_I8(Op.Imm); + + Context.Emit(OpCodes.Ret); + } } public static void B_Cond(AILEmitterCtx Context) { AOpCodeBImmCond Op = (AOpCodeBImmCond)Context.CurrOp; - Context.EmitCondBranch(Context.GetLabel(Op.Imm), Op.Cond); + EmitBranch(Context, Op.Cond); } public static void Bl(AILEmitterCtx Context) @@ -48,10 +58,7 @@ namespace ChocolArm64.Instruction Context.Emit(OpCodes.Pop); - if (Context.CurrBlock.Next != null) - { - Context.EmitLoadState(Context.CurrBlock.Next); - } + Context.EmitLoadState(Context.CurrBlock.Next); } else { @@ -93,7 +100,7 @@ namespace ChocolArm64.Instruction Context.EmitLdintzr(Op.Rt); Context.EmitLdc_I(0); - Context.Emit(ILOp, Context.GetLabel(Op.Imm)); + EmitBranch(Context, ILOp); } public static void Ret(AILEmitterCtx Context) @@ -118,7 +125,65 @@ namespace ChocolArm64.Instruction Context.EmitLdc_I(0); - Context.Emit(ILOp, Context.GetLabel(Op.Imm)); + EmitBranch(Context, ILOp); + } + + private static void EmitBranch(AILEmitterCtx Context, ACond Cond) + { + AOpCodeBImm Op = (AOpCodeBImm)Context.CurrOp; + + if (Context.CurrBlock.Next != null && + Context.CurrBlock.Branch != null) + { + Context.EmitCondBranch(Context.GetLabel(Op.Imm), Cond); + } + else + { + Context.EmitStoreState(); + + AILLabel LblTaken = new AILLabel(); + + Context.EmitCondBranch(LblTaken, Cond); + + Context.EmitLdc_I8(Op.Position + 4); + + Context.Emit(OpCodes.Ret); + + Context.MarkLabel(LblTaken); + + Context.EmitLdc_I8(Op.Imm); + + Context.Emit(OpCodes.Ret); + } + } + + private static void EmitBranch(AILEmitterCtx Context, OpCode ILOp) + { + AOpCodeBImm Op = (AOpCodeBImm)Context.CurrOp; + + if (Context.CurrBlock.Next != null && + Context.CurrBlock.Branch != null) + { + Context.Emit(ILOp, Context.GetLabel(Op.Imm)); + } + else + { + Context.EmitStoreState(); + + AILLabel LblTaken = new AILLabel(); + + Context.Emit(ILOp, LblTaken); + + Context.EmitLdc_I8(Op.Position + 4); + + Context.Emit(OpCodes.Ret); + + Context.MarkLabel(LblTaken); + + Context.EmitLdc_I8(Op.Imm); + + Context.Emit(OpCodes.Ret); + } } } } \ No newline at end of file diff --git a/ChocolArm64/Translation/AILEmitter.cs b/ChocolArm64/Translation/AILEmitter.cs index 8f6e1210f0..af37a6c752 100644 --- a/ChocolArm64/Translation/AILEmitter.cs +++ b/ChocolArm64/Translation/AILEmitter.cs @@ -58,11 +58,13 @@ namespace ChocolArm64.Translation this.Root = ILBlocks[Array.IndexOf(Graph, Root)]; } - public ATranslatedSub GetSubroutine() + public AILBlock GetILBlock(int Index) => ILBlocks[Index]; + + public ATranslatedSub GetSubroutine(HashSet Callees) { LocalAlloc = new ALocalAlloc(ILBlocks, Root); - InitSubroutine(); + InitSubroutine(Callees); InitLocals(); foreach (AILBlock ILBlock in ILBlocks) @@ -73,24 +75,7 @@ namespace ChocolArm64.Translation return Subroutine; } - public AILBlock GetILBlock(int Index) => ILBlocks[Index]; - - private void InitLocals() - { - int ParamsStart = ATranslatedSub.FixedArgTypes.Length; - - Locals = new Dictionary(); - - for (int Index = 0; Index < Subroutine.Params.Count; Index++) - { - ARegister Reg = Subroutine.Params[Index]; - - Generator.EmitLdarg(Index + ParamsStart); - Generator.EmitStloc(GetLocalIndex(Reg)); - } - } - - private void InitSubroutine() + private void InitSubroutine(HashSet Callees) { List Params = new List(); @@ -114,9 +99,24 @@ namespace ChocolArm64.Translation Generator = Mthd.GetILGenerator(); - Subroutine = new ATranslatedSub(Mthd, Params); + Subroutine = new ATranslatedSub(Mthd, Params, Callees); } + private void InitLocals() + { + int ParamsStart = ATranslatedSub.FixedArgTypes.Length; + + Locals = new Dictionary(); + + for (int Index = 0; Index < Subroutine.Params.Count; Index++) + { + ARegister Reg = Subroutine.Params[Index]; + + Generator.EmitLdarg(Index + ParamsStart); + Generator.EmitStloc(GetLocalIndex(Reg)); + } + } + private Type[] GetParamTypes(IList Params) { Type[] FixedArgs = ATranslatedSub.FixedArgTypes; diff --git a/ChocolArm64/Translation/AILEmitterCtx.cs b/ChocolArm64/Translation/AILEmitterCtx.cs index ffcfa851ae..4665946941 100644 --- a/ChocolArm64/Translation/AILEmitterCtx.cs +++ b/ChocolArm64/Translation/AILEmitterCtx.cs @@ -12,14 +12,9 @@ namespace ChocolArm64.Translation { private ATranslator Translator; - private Dictionary Labels; + private HashSet Callees; - private AILEmitter Emitter; - - private AILBlock ILBlock; - - private AOpCode OptOpLastCompare; - private AOpCode OptOpLastFlagSet; + private Dictionary Labels; private int BlkIndex; private int OpcIndex; @@ -29,6 +24,13 @@ namespace ChocolArm64.Translation public ABlock CurrBlock => Graph[BlkIndex]; public AOpCode CurrOp => Graph[BlkIndex].OpCodes[OpcIndex]; + private AILEmitter Emitter; + + private AILBlock ILBlock; + + private AOpCode OptOpLastCompare; + private AOpCode OptOpLastFlagSet; + //This is the index of the temporary register, used to store temporary //values needed by some functions, since IL doesn't have a swap instruction. //You can use any value here as long it doesn't conflict with the indices @@ -45,10 +47,27 @@ namespace ChocolArm64.Translation ABlock Root, string SubName) { + if (Translator == null) + { + throw new ArgumentNullException(nameof(Translator)); + } + + if (Graph == null) + { + throw new ArgumentNullException(nameof(Graph)); + } + + if (Root == null) + { + throw new ArgumentNullException(nameof(Root)); + } + this.Translator = Translator; this.Graph = Graph; this.Root = Root; + Callees = new HashSet(); + Labels = new Dictionary(); Emitter = new AILEmitter(Graph, Root, SubName); @@ -57,23 +76,27 @@ namespace ChocolArm64.Translation OpcIndex = -1; - if (!AdvanceOpCode()) + if (Graph.Length == 0 || !AdvanceOpCode()) { throw new ArgumentException(nameof(Graph)); } } - public ATranslatedSub GetSubroutine() => Emitter.GetSubroutine(); + public ATranslatedSub GetSubroutine() + { + return Emitter.GetSubroutine(Callees); + } public bool AdvanceOpCode() { + if (OpcIndex + 1 == CurrBlock.OpCodes.Count && + BlkIndex + 1 == Graph.Length) + { + return false; + } + while (++OpcIndex >= (CurrBlock?.OpCodes.Count ?? 0)) { - if (BlkIndex + 1 >= Graph.Length) - { - return false; - } - BlkIndex++; OpcIndex = -1; @@ -100,6 +123,13 @@ namespace ChocolArm64.Translation public bool TryOptEmitSubroutineCall() { + Callees.Add(((AOpCodeBImm)CurrOp).Imm); + + if (CurrBlock.Next == null) + { + return false; + } + if (!Translator.TryGetCachedSub(CurrOp, out ATranslatedSub Sub)) { return false; diff --git a/ChocolArm64/Translation/ALocalAlloc.cs b/ChocolArm64/Translation/ALocalAlloc.cs index f23af9c767..8e9047804d 100644 --- a/ChocolArm64/Translation/ALocalAlloc.cs +++ b/ChocolArm64/Translation/ALocalAlloc.cs @@ -67,14 +67,15 @@ namespace ChocolArm64.Translation public long VecOutputs; } - private const int MaxOptGraphLength = 55; + private const int MaxOptGraphLength = 40; public ALocalAlloc(AILBlock[] Graph, AILBlock Root) { IntPaths = new Dictionary(); VecPaths = new Dictionary(); - if (Graph.Length < MaxOptGraphLength) + if (Graph.Length > 1 && + Graph.Length < MaxOptGraphLength) { InitializeOptimal(Graph, Root); } @@ -179,10 +180,8 @@ namespace ChocolArm64.Translation { //This is WAY faster than InitializeOptimal, but results in //uneeded loads and stores, so the resulting code will be slower. - long IntInputs = 0; - long IntOutputs = 0; - long VecInputs = 0; - long VecOutputs = 0; + long IntInputs = 0, IntOutputs = 0; + long VecInputs = 0, VecOutputs = 0; foreach (AILBlock Block in Graph) { @@ -196,8 +195,11 @@ namespace ChocolArm64.Translation //in those cases if we attempt to write an output registers that was //not written, we will be just writing zero and messing up the old register value. //So we just need to ensure that all outputs are loaded. - IntInputs |= IntOutputs; - VecInputs |= VecOutputs; + if (Graph.Length > 1) + { + IntInputs |= IntOutputs; + VecInputs |= VecOutputs; + } foreach (AILBlock Block in Graph) { diff --git a/Ryujinx.Core/OsHle/Services/Set/ServiceSetSys.cs b/Ryujinx.Core/OsHle/Services/Set/ServiceSetSys.cs index 41c5d8b3b3..dee6573d35 100644 --- a/Ryujinx.Core/OsHle/Services/Set/ServiceSetSys.cs +++ b/Ryujinx.Core/OsHle/Services/Set/ServiceSetSys.cs @@ -1,6 +1,4 @@ -using ChocolArm64.Memory; -using Ryujinx.Core.OsHle.Ipc; -using System; +using Ryujinx.Core.OsHle.Ipc; using System.Collections.Generic; namespace Ryujinx.Core.OsHle.IpcServices.Set