From cd6d2f699be6f33a2979c974c23138248a229e79 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Mon, 7 May 2018 14:29:41 -0300 Subject: [PATCH] Try to fix perf regression reading/writing textures, moved syncpts and events to a UserCtx class, delete global state when the process exits, other minor tweaks --- Ryujinx.Core/Gpu/NvGpuEngine2d.cs | 2 +- Ryujinx.Core/Gpu/NvGpuEngine3d.cs | 4 +- Ryujinx.Core/Gpu/NvGpuVmm.cs | 81 +++++++++++------ Ryujinx.Core/Gpu/TextureHelper.cs | 13 +++ Ryujinx.Core/Gpu/TextureReader.cs | 26 ++++-- Ryujinx.Core/Gpu/TextureWriter.cs | 9 +- Ryujinx.Core/OsHle/Kernel/SvcSystem.cs | 4 +- Ryujinx.Core/OsHle/Process.cs | 2 +- .../OsHle/Services/Nv/INvDrvServices.cs | 86 ++++++++++++++++--- .../OsHle/Services/Nv/NvGpuAS/NvGpuASIoctl.cs | 41 ++++++++- .../OsHle/Services/Nv/NvGpuAS/NvGpuASRemap.cs | 12 +++ .../NvGpuGpuGetCharacteristics.cs} | 4 +- .../NvGpuGpuIoctl.cs} | 8 +- .../Nv/NvHostChannel/NvHostChannelIoctl.cs | 3 +- .../Services/Nv/NvHostCtrl/NvHostCtrlIoctl.cs | 74 +++++++--------- .../Nv/NvHostCtrl/NvHostCtrlUserCtx.cs | 19 ++++ .../Services/Nv/NvHostCtrl/NvHostSyncPt.cs | 6 +- .../OsHle/Services/Nv/NvMap/NvMapIoctl.cs | 49 +++++++---- 18 files changed, 323 insertions(+), 120 deletions(-) create mode 100644 Ryujinx.Core/OsHle/Services/Nv/NvGpuAS/NvGpuASRemap.cs rename Ryujinx.Core/OsHle/Services/Nv/{NvHostCtrlGpu/NvHostCtrlGpuCharacteristics.cs => NvGpuGpu/NvGpuGpuGetCharacteristics.cs} (93%) rename Ryujinx.Core/OsHle/Services/Nv/{NvHostCtrlGpu/NvHostCtrlGpuIoctl.cs => NvGpuGpu/NvGpuGpuIoctl.cs} (95%) create mode 100644 Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlUserCtx.cs diff --git a/Ryujinx.Core/Gpu/NvGpuEngine2d.cs b/Ryujinx.Core/Gpu/NvGpuEngine2d.cs index e18b73a668..88395b7ab5 100644 --- a/Ryujinx.Core/Gpu/NvGpuEngine2d.cs +++ b/Ryujinx.Core/Gpu/NvGpuEngine2d.cs @@ -75,7 +75,7 @@ namespace Ryujinx.Core.Gpu int DstBlockHeight = 1 << ((DstBlkDim >> 4) & 0xf); - long Tag = Vmm.GetCpuAddr(MakeInt64From2xInt32(NvGpuEngine2dReg.SrcAddress)); + long Tag = Vmm.GetPhysicalAddress(MakeInt64From2xInt32(NvGpuEngine2dReg.SrcAddress)); long SrcAddress = MakeInt64From2xInt32(NvGpuEngine2dReg.SrcAddress); long DstAddress = MakeInt64From2xInt32(NvGpuEngine2dReg.DstAddress); diff --git a/Ryujinx.Core/Gpu/NvGpuEngine3d.cs b/Ryujinx.Core/Gpu/NvGpuEngine3d.cs index f94cb0a7de..b08b949617 100644 --- a/Ryujinx.Core/Gpu/NvGpuEngine3d.cs +++ b/Ryujinx.Core/Gpu/NvGpuEngine3d.cs @@ -104,7 +104,7 @@ namespace Ryujinx.Core.Gpu { long VA = MakeInt64From2xInt32(NvGpuEngine3dReg.FrameBufferNAddress + FbIndex * 0x10); - long PA = Vmm.GetCpuAddr(VA); + long PA = Vmm.GetPhysicalAddress(VA); FrameBuffers.Add(PA); @@ -259,7 +259,7 @@ namespace Ryujinx.Core.Gpu long TextureAddress = Vmm.ReadInt64(TicPosition + 4) & 0xffffffffffff; - TextureAddress = Vmm.GetCpuAddr(TextureAddress); + TextureAddress = Vmm.GetPhysicalAddress(TextureAddress); if (IsFrameBufferPosition(TextureAddress)) { diff --git a/Ryujinx.Core/Gpu/NvGpuVmm.cs b/Ryujinx.Core/Gpu/NvGpuVmm.cs index ad16aed625..cf94a6c016 100644 --- a/Ryujinx.Core/Gpu/NvGpuVmm.cs +++ b/Ryujinx.Core/Gpu/NvGpuVmm.cs @@ -1,4 +1,5 @@ using ChocolArm64.Memory; +using System.Collections.Concurrent; namespace Ryujinx.Core.Gpu { @@ -21,17 +22,31 @@ namespace Ryujinx.Core.Gpu private const int PTLvl0Bit = PTPageBits + PTLvl1Bits; private const int PTLvl1Bit = PTPageBits; + public AMemory Memory { get; private set; } + + private struct MappedMemory + { + public long Size; + + public MappedMemory(long Size) + { + this.Size = Size; + } + } + + private ConcurrentDictionary Maps; + private const long PteUnmapped = -1; private const long PteReserved = -2; private long[][] PageTable; - private AMemory Memory; - public NvGpuVmm(AMemory Memory) { this.Memory = Memory; + Maps = new ConcurrentDictionary(); + PageTable = new long[PTLvl0Size][]; } @@ -60,20 +75,36 @@ namespace Ryujinx.Core.Gpu { lock (PageTable) { - long Position = GetFreePosition(Size); + long VA = GetFreePosition(Size); - if (Position != -1) + if (VA != -1) { + MappedMemory Map = new MappedMemory(Size); + + Maps.AddOrUpdate(VA, Map, (Key, Old) => Map); + for (long Offset = 0; Offset < Size; Offset += PageSize) { - SetPte(Position + Offset, PA + Offset); + SetPte(VA + Offset, PA + Offset); } } - return Position; + return VA; } } + public bool Unmap(long VA) + { + if (Maps.TryRemove(VA, out MappedMemory Map)) + { + Free(VA, Map.Size); + + return true; + } + + return false; + } + public long Reserve(long VA, long Size, long Align) { lock (PageTable) @@ -164,7 +195,7 @@ namespace Ryujinx.Core.Gpu return -1; } - public long GetCpuAddr(long VA) + public long GetPhysicalAddress(long VA) { long BasePos = GetPte(VA); @@ -240,126 +271,126 @@ namespace Ryujinx.Core.Gpu public byte ReadByte(long Position) { - Position = GetCpuAddr(Position); + Position = GetPhysicalAddress(Position); return Memory.ReadByte(Position); } public ushort ReadUInt16(long Position) { - Position = GetCpuAddr(Position); + Position = GetPhysicalAddress(Position); return Memory.ReadUInt16(Position); } public uint ReadUInt32(long Position) { - Position = GetCpuAddr(Position); + Position = GetPhysicalAddress(Position); return Memory.ReadUInt32(Position); } public ulong ReadUInt64(long Position) { - Position = GetCpuAddr(Position); + Position = GetPhysicalAddress(Position); return Memory.ReadUInt64(Position); } public sbyte ReadSByte(long Position) { - Position = GetCpuAddr(Position); + Position = GetPhysicalAddress(Position); return Memory.ReadSByte(Position); } public short ReadInt16(long Position) { - Position = GetCpuAddr(Position); + Position = GetPhysicalAddress(Position); return Memory.ReadInt16(Position); } public int ReadInt32(long Position) { - Position = GetCpuAddr(Position); + Position = GetPhysicalAddress(Position); return Memory.ReadInt32(Position); } public long ReadInt64(long Position) { - Position = GetCpuAddr(Position); + Position = GetPhysicalAddress(Position); return Memory.ReadInt64(Position); } public byte[] ReadBytes(long Position, long Size) { - Position = GetCpuAddr(Position); + Position = GetPhysicalAddress(Position); return AMemoryHelper.ReadBytes(Memory, Position, Size); } public void WriteByte(long Position, byte Value) { - Position = GetCpuAddr(Position); + Position = GetPhysicalAddress(Position); Memory.WriteByte(Position, Value); } public void WriteUInt16(long Position, ushort Value) { - Position = GetCpuAddr(Position); + Position = GetPhysicalAddress(Position); Memory.WriteUInt16(Position, Value); } public void WriteUInt32(long Position, uint Value) { - Position = GetCpuAddr(Position); + Position = GetPhysicalAddress(Position); Memory.WriteUInt32(Position, Value); } public void WriteUInt64(long Position, ulong Value) { - Position = GetCpuAddr(Position); + Position = GetPhysicalAddress(Position); Memory.WriteUInt64(Position, Value); } public void WriteSByte(long Position, sbyte Value) { - Position = GetCpuAddr(Position); + Position = GetPhysicalAddress(Position); Memory.WriteSByte(Position, Value); } public void WriteInt16(long Position, short Value) { - Position = GetCpuAddr(Position); + Position = GetPhysicalAddress(Position); Memory.WriteInt16(Position, Value); } public void WriteInt32(long Position, int Value) { - Position = GetCpuAddr(Position); + Position = GetPhysicalAddress(Position); Memory.WriteInt32(Position, Value); } public void WriteInt64(long Position, long Value) { - Position = GetCpuAddr(Position); + Position = GetPhysicalAddress(Position); Memory.WriteInt64(Position, Value); } public void WriteBytes(long Position, byte[] Data) { - Position = GetCpuAddr(Position); + Position = GetPhysicalAddress(Position); AMemoryHelper.WriteBytes(Memory, Position, Data); } diff --git a/Ryujinx.Core/Gpu/TextureHelper.cs b/Ryujinx.Core/Gpu/TextureHelper.cs index 1a5ffca4a2..f0ebc1f043 100644 --- a/Ryujinx.Core/Gpu/TextureHelper.cs +++ b/Ryujinx.Core/Gpu/TextureHelper.cs @@ -1,3 +1,4 @@ +using ChocolArm64.Memory; using System; namespace Ryujinx.Core.Gpu @@ -19,5 +20,17 @@ namespace Ryujinx.Core.Gpu throw new NotImplementedException(Texture.Swizzle.ToString()); } + + public static (AMemory Memory, long Position) GetMemoryAndPosition( + IAMemory Memory, + long Position) + { + if (Memory is NvGpuVmm Vmm) + { + return (Vmm.Memory, Vmm.GetPhysicalAddress(Position)); + } + + return ((AMemory)Memory, Position); + } } } diff --git a/Ryujinx.Core/Gpu/TextureReader.cs b/Ryujinx.Core/Gpu/TextureReader.cs index a36931499f..f3e41046ae 100644 --- a/Ryujinx.Core/Gpu/TextureReader.cs +++ b/Ryujinx.Core/Gpu/TextureReader.cs @@ -32,6 +32,10 @@ namespace Ryujinx.Core.Gpu ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, Width, 2); + (AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition( + Memory, + Texture.Position); + fixed (byte* BuffPtr = Output) { long OutOffs = 0; @@ -41,7 +45,7 @@ namespace Ryujinx.Core.Gpu { long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y); - short Pixel = Memory.ReadInt16(Texture.Position + Offset); + short Pixel = CpuMem.ReadInt16Unchecked(Position + Offset); *(short*)(BuffPtr + OutOffs) = Pixel; @@ -61,6 +65,10 @@ namespace Ryujinx.Core.Gpu ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, Width, 4); + (AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition( + Memory, + Texture.Position); + fixed (byte* BuffPtr = Output) { long OutOffs = 0; @@ -70,7 +78,7 @@ namespace Ryujinx.Core.Gpu { long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y); - int Pixel = Memory.ReadInt32(Texture.Position + Offset); + int Pixel = CpuMem.ReadInt32Unchecked(Position + Offset); *(int*)(BuffPtr + OutOffs) = Pixel; @@ -90,6 +98,10 @@ namespace Ryujinx.Core.Gpu ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, Width, 8); + (AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition( + Memory, + Texture.Position); + fixed (byte* BuffPtr = Output) { long OutOffs = 0; @@ -99,7 +111,7 @@ namespace Ryujinx.Core.Gpu { long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y); - long Tile = Memory.ReadInt64(Texture.Position + Offset); + long Tile = CpuMem.ReadInt64Unchecked(Position + Offset); *(long*)(BuffPtr + OutOffs) = Tile; @@ -119,6 +131,10 @@ namespace Ryujinx.Core.Gpu ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, Width, 16); + (AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition( + Memory, + Texture.Position); + fixed (byte* BuffPtr = Output) { long OutOffs = 0; @@ -128,8 +144,8 @@ namespace Ryujinx.Core.Gpu { long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y); - long Tile0 = Memory.ReadInt64(Texture.Position + Offset + 0); - long Tile1 = Memory.ReadInt64(Texture.Position + Offset + 8); + long Tile0 = CpuMem.ReadInt64Unchecked(Position + Offset + 0); + long Tile1 = CpuMem.ReadInt64Unchecked(Position + Offset + 8); *(long*)(BuffPtr + OutOffs + 0) = Tile0; *(long*)(BuffPtr + OutOffs + 8) = Tile1; diff --git a/Ryujinx.Core/Gpu/TextureWriter.cs b/Ryujinx.Core/Gpu/TextureWriter.cs index 957aef3d3b..125bb8c4f5 100644 --- a/Ryujinx.Core/Gpu/TextureWriter.cs +++ b/Ryujinx.Core/Gpu/TextureWriter.cs @@ -12,8 +12,7 @@ namespace Ryujinx.Core.Gpu { case GalTextureFormat.A8B8G8R8: Write4Bpp(Memory, Texture, Data); break; - default: - throw new NotImplementedException(Texture.Format.ToString()); + default: throw new NotImplementedException(Texture.Format.ToString()); } } @@ -24,6 +23,10 @@ namespace Ryujinx.Core.Gpu ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, Width, 4); + (AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition( + Memory, + Texture.Position); + fixed (byte* BuffPtr = Data) { long InOffs = 0; @@ -35,7 +38,7 @@ namespace Ryujinx.Core.Gpu int Pixel = *(int*)(BuffPtr + InOffs); - Memory.WriteInt32(Texture.Position + Offset, Pixel); + CpuMem.WriteInt32Unchecked(Position + Offset, Pixel); InOffs += 4; } diff --git a/Ryujinx.Core/OsHle/Kernel/SvcSystem.cs b/Ryujinx.Core/OsHle/Kernel/SvcSystem.cs index 18dc0dc3eb..e5b080a88f 100644 --- a/Ryujinx.Core/OsHle/Kernel/SvcSystem.cs +++ b/Ryujinx.Core/OsHle/Kernel/SvcSystem.cs @@ -40,7 +40,7 @@ namespace Ryujinx.Core.OsHle.Kernel if (Obj == null) { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Tried to CloseHandle on invalid handle 0x{Handle:x8}!"); + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid handle 0x{Handle:x8}!"); ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); @@ -229,8 +229,6 @@ namespace Ryujinx.Core.OsHle.Kernel private void SendSyncRequest(AThreadState ThreadState, long CmdPtr, long Size, int Handle) { - //Process.PrintStackTrace(ThreadState); - KThread CurrThread = Process.GetThread(ThreadState.Tpidr); byte[] CmdData = AMemoryHelper.ReadBytes(Memory, CmdPtr, Size); diff --git a/Ryujinx.Core/OsHle/Process.cs b/Ryujinx.Core/OsHle/Process.cs index ac4d72b68b..3ccbc01692 100644 --- a/Ryujinx.Core/OsHle/Process.cs +++ b/Ryujinx.Core/OsHle/Process.cs @@ -410,7 +410,7 @@ namespace Ryujinx.Core.OsHle } } - INvDrvServices.Fds.DeleteProcess(this); + INvDrvServices.UnloadProcess(this); AppletState.Dispose(); diff --git a/Ryujinx.Core/OsHle/Services/Nv/INvDrvServices.cs b/Ryujinx.Core/OsHle/Services/Nv/INvDrvServices.cs index e32815351f..aca171b412 100644 --- a/Ryujinx.Core/OsHle/Services/Nv/INvDrvServices.cs +++ b/Ryujinx.Core/OsHle/Services/Nv/INvDrvServices.cs @@ -1,10 +1,11 @@ using ChocolArm64.Memory; +using Ryujinx.Core.Logging; using Ryujinx.Core.OsHle.Handles; using Ryujinx.Core.OsHle.Ipc; using Ryujinx.Core.OsHle.Services.Nv.NvGpuAS; +using Ryujinx.Core.OsHle.Services.Nv.NvGpuGpu; using Ryujinx.Core.OsHle.Services.Nv.NvHostChannel; using Ryujinx.Core.OsHle.Services.Nv.NvHostCtrl; -using Ryujinx.Core.OsHle.Services.Nv.NvHostCtrlGpu; using Ryujinx.Core.OsHle.Services.Nv.NvMap; using System; using System.Collections.Generic; @@ -13,20 +14,20 @@ namespace Ryujinx.Core.OsHle.Services.Nv { class INvDrvServices : IpcService, IDisposable { - private delegate int ProcessIoctl(ServiceCtx Context, int Cmd); + private delegate int IoctlProcessor(ServiceCtx Context, int Cmd); private Dictionary m_Commands; public override IReadOnlyDictionary Commands => m_Commands; - private static Dictionary IoctlProcessors = - new Dictionary() + private static Dictionary IoctlProcessors = + new Dictionary() { - { "/dev/nvhost-as-gpu", NvGpuASIoctl .ProcessIoctl }, - { "/dev/nvhost-ctrl", NvHostCtrlIoctl .ProcessIoctl }, - { "/dev/nvhost-ctrl-gpu", NvHostCtrlGpuIoctl.ProcessIoctl }, - { "/dev/nvhost-gpu", NvHostChannelIoctl.ProcessIoctl }, - { "/dev/nvmap", NvMapIoctl .ProcessIoctl } + { "/dev/nvhost-as-gpu", ProcessIoctlNvGpuAS }, + { "/dev/nvhost-ctrl", ProcessIoctlNvHostCtrl }, + { "/dev/nvhost-ctrl-gpu", ProcessIoctlNvGpuGpu }, + { "/dev/nvhost-gpu", ProcessIoctlNvHostChannel }, + { "/dev/nvmap", ProcessIoctlNvMap } }; public static GlobalStateTable Fds { get; private set; } @@ -76,7 +77,7 @@ namespace Ryujinx.Core.OsHle.Services.Nv int Result; - if (IoctlProcessors.TryGetValue(FdData.Name, out ProcessIoctl Process)) + if (IoctlProcessors.TryGetValue(FdData.Name, out IoctlProcessor Process)) { Result = Process(Context, Cmd); } @@ -137,6 +138,71 @@ namespace Ryujinx.Core.OsHle.Services.Nv return 0; } + private static int ProcessIoctlNvGpuAS(ServiceCtx Context, int Cmd) + { + return ProcessIoctl(Context, Cmd, NvGpuASIoctl.ProcessIoctl); + } + + private static int ProcessIoctlNvHostCtrl(ServiceCtx Context, int Cmd) + { + return ProcessIoctl(Context, Cmd, NvHostCtrlIoctl.ProcessIoctl); + } + + private static int ProcessIoctlNvGpuGpu(ServiceCtx Context, int Cmd) + { + return ProcessIoctl(Context, Cmd, NvGpuGpuIoctl.ProcessIoctl); + } + + private static int ProcessIoctlNvHostChannel(ServiceCtx Context, int Cmd) + { + return ProcessIoctl(Context, Cmd, NvHostChannelIoctl.ProcessIoctl); + } + + private static int ProcessIoctlNvMap(ServiceCtx Context, int Cmd) + { + return ProcessIoctl(Context, Cmd, NvMapIoctl.ProcessIoctl); + } + + private static int ProcessIoctl(ServiceCtx Context, int Cmd, IoctlProcessor Processor) + { + if (CmdIn(Cmd) && Context.Request.GetBufferType0x21Position() == 0) + { + Context.Ns.Log.PrintError(LogClass.ServiceNv, "Input buffer is null!"); + + return NvResult.InvalidInput; + } + + if (CmdOut(Cmd) && Context.Request.GetBufferType0x22Position() == 0) + { + Context.Ns.Log.PrintError(LogClass.ServiceNv, "Output buffer is null!"); + + return NvResult.InvalidInput; + } + + return Processor(Context, Cmd); + } + + private static bool CmdIn(int Cmd) + { + return ((Cmd >> 30) & 1) != 0; + } + + private static bool CmdOut(int Cmd) + { + return ((Cmd >> 31) & 1) != 0; + } + + public static void UnloadProcess(Process Process) + { + Fds.DeleteProcess(Process); + + NvGpuASIoctl.UnloadProcess(Process); + + NvHostCtrlIoctl.UnloadProcess(Process); + + NvMapIoctl.UnloadProcess(Process); + } + public void Dispose() { Dispose(true); diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvGpuAS/NvGpuASIoctl.cs b/Ryujinx.Core/OsHle/Services/Nv/NvGpuAS/NvGpuASIoctl.cs index 17953b7f11..6be45d5c17 100644 --- a/Ryujinx.Core/OsHle/Services/Nv/NvGpuAS/NvGpuASIoctl.cs +++ b/Ryujinx.Core/OsHle/Services/Nv/NvGpuAS/NvGpuASIoctl.cs @@ -29,6 +29,7 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvGpuAS case 0x4106: return MapBufferEx (Context); case 0x4108: return GetVaRegions(Context); case 0x4109: return InitializeEx(Context); + case 0x4114: return Remap (Context); } throw new NotImplementedException(Cmd.ToString("x8")); @@ -107,10 +108,10 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvGpuAS NvGpuVmm Vmm = GetVmm(Context); - /*if (!Vmm.Unmap(Args.Offset)) + if (!Vmm.Unmap(Args.Offset)) { Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid buffer offset {Args.Offset:x16}!"); - }*/ + } return NvResult.Success; } @@ -126,6 +127,13 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvGpuAS NvMapHandle Map = NvMapIoctl.GetNvMapWithFb(Context, Args.NvMapHandle); + if (Map == null) + { + Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid NvMap handle 0x{Args.NvMapHandle:x8}!"); + + return NvResult.InvalidInput; + } + long PA = Map.Address + Args.BufferOffset; long Size = Args.MappingSize; @@ -200,9 +208,38 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvGpuAS return NvResult.Success; } + private static int Remap(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21Position(); + + NvGpuASRemap Args = AMemoryHelper.Read(Context.Memory, InputPosition); + + NvGpuVmm Vmm = GetVmm(Context); + + NvMapHandle Map = NvMapIoctl.GetNvMapWithFb(Context, Args.NvMapHandle); + + if (Map == null) + { + Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid NvMap handle 0x{Args.NvMapHandle:x8}!"); + + return NvResult.InvalidInput; + } + + //FIXME: This is most likely wrong... + Vmm.Map(Map.Address, (long)(uint)Args.Offset << 16, + (long)(uint)Args.Pages << 16); + + return NvResult.Success; + } + public static NvGpuVmm GetVmm(ServiceCtx Context) { return Vmms.GetOrAdd(Context.Process, (Key) => new NvGpuVmm(Context.Memory)); } + + public static void UnloadProcess(Process Process) + { + Vmms.TryRemove(Process, out _); + } } } \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvGpuAS/NvGpuASRemap.cs b/Ryujinx.Core/OsHle/Services/Nv/NvGpuAS/NvGpuASRemap.cs new file mode 100644 index 0000000000..363ae687eb --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Nv/NvGpuAS/NvGpuASRemap.cs @@ -0,0 +1,12 @@ +namespace Ryujinx.Core.OsHle.Services.Nv.NvGpuAS +{ + struct NvGpuASRemap + { + public short Flags; + public short Kind; + public int NvMapHandle; + public int Padding; + public int Offset; + public int Pages; + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrlGpu/NvHostCtrlGpuCharacteristics.cs b/Ryujinx.Core/OsHle/Services/Nv/NvGpuGpu/NvGpuGpuGetCharacteristics.cs similarity index 93% rename from Ryujinx.Core/OsHle/Services/Nv/NvHostCtrlGpu/NvHostCtrlGpuCharacteristics.cs rename to Ryujinx.Core/OsHle/Services/Nv/NvGpuGpu/NvGpuGpuGetCharacteristics.cs index ba0e7a5b0e..5d92b50837 100644 --- a/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrlGpu/NvHostCtrlGpuCharacteristics.cs +++ b/Ryujinx.Core/OsHle/Services/Nv/NvGpuGpu/NvGpuGpuGetCharacteristics.cs @@ -1,6 +1,6 @@ -namespace Ryujinx.Core.OsHle.Services.Nv.NvHostCtrlGpu +namespace Ryujinx.Core.OsHle.Services.Nv.NvGpuGpu { - struct NvHostCtrlGpuCharacteristics + struct NvGpuGpuGetCharacteristics { public long BufferSize; public long BufferAddress; diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrlGpu/NvHostCtrlGpuIoctl.cs b/Ryujinx.Core/OsHle/Services/Nv/NvGpuGpu/NvGpuGpuIoctl.cs similarity index 95% rename from Ryujinx.Core/OsHle/Services/Nv/NvHostCtrlGpu/NvHostCtrlGpuIoctl.cs rename to Ryujinx.Core/OsHle/Services/Nv/NvGpuGpu/NvGpuGpuIoctl.cs index e90fd988c5..772b6786eb 100644 --- a/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrlGpu/NvHostCtrlGpuIoctl.cs +++ b/Ryujinx.Core/OsHle/Services/Nv/NvGpuGpu/NvGpuGpuIoctl.cs @@ -3,15 +3,15 @@ using Ryujinx.Core.Logging; using System; using System.Diagnostics; -namespace Ryujinx.Core.OsHle.Services.Nv.NvHostCtrlGpu +namespace Ryujinx.Core.OsHle.Services.Nv.NvGpuGpu { - class NvHostCtrlGpuIoctl + class NvGpuGpuIoctl { private static Stopwatch PTimer; private static double TicksToNs; - static NvHostCtrlGpuIoctl() + static NvGpuGpuIoctl() { PTimer = new Stopwatch(); @@ -71,7 +71,7 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvHostCtrlGpu long InputPosition = Context.Request.GetBufferType0x21Position(); long OutputPosition = Context.Request.GetBufferType0x22Position(); - NvHostCtrlGpuCharacteristics Args = AMemoryHelper.Read(Context.Memory, InputPosition); + NvGpuGpuGetCharacteristics Args = AMemoryHelper.Read(Context.Memory, InputPosition); Args.BufferSize = 0xa0; diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvHostChannel/NvHostChannelIoctl.cs b/Ryujinx.Core/OsHle/Services/Nv/NvHostChannel/NvHostChannelIoctl.cs index 78334014cb..85b4753398 100644 --- a/Ryujinx.Core/OsHle/Services/Nv/NvHostChannel/NvHostChannelIoctl.cs +++ b/Ryujinx.Core/OsHle/Services/Nv/NvHostChannel/NvHostChannelIoctl.cs @@ -69,7 +69,8 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvHostChannel Context.Ns.Gpu.Fifo.PushBuffer(Vmm, PushBuffer); } - Args.SyncptId = 5; + Args.SyncptId = 0; + Args.SyncptValue = 0; AMemoryHelper.Write(Context.Memory, OutputPosition, Args); diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlIoctl.cs b/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlIoctl.cs index 9028d95b99..8c705d7f03 100644 --- a/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlIoctl.cs +++ b/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlIoctl.cs @@ -8,19 +8,11 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvHostCtrl { class NvHostCtrlIoctl { - private const int LocksCount = 16; - - private const int EventsCount = 64; - - private static ConcurrentDictionary EventArrays; - - private static ConcurrentDictionary NvSyncPts; + private static ConcurrentDictionary UserCtxs; static NvHostCtrlIoctl() { - EventArrays = new ConcurrentDictionary(); - - NvSyncPts = new ConcurrentDictionary(); + UserCtxs = new ConcurrentDictionary(); } public static int ProcessIoctl(ServiceCtx Context, int Cmd) @@ -52,12 +44,12 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvHostCtrl int Id = Context.Memory.ReadInt32(InputPosition); - if ((uint)Id >= NvHostSyncpt.SyncPtsCount) + if ((uint)Id >= NvHostSyncpt.SyncptsCount) { return NvResult.InvalidInput; } - GetSyncPt(Context).Increment(Id); + GetUserCtx(Context).Syncpt.Increment(Id); return NvResult.Success; } @@ -109,8 +101,6 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvHostCtrl int EventId = Context.Memory.ReadInt32(InputPosition); - Context.Ns.Log.PrintInfo(LogClass.ServiceNv, EventId.ToString()); - Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); return NvResult.Success; @@ -123,18 +113,18 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvHostCtrl NvHostCtrlSyncptRead Args = AMemoryHelper.Read(Context.Memory, InputPosition); - if ((uint)Args.Id >= NvHostSyncpt.SyncPtsCount) + if ((uint)Args.Id >= NvHostSyncpt.SyncptsCount) { return NvResult.InvalidInput; } if (Max) { - Args.Value = GetSyncPt(Context).GetMax(Args.Id); + Args.Value = GetUserCtx(Context).Syncpt.GetMax(Args.Id); } else { - Args.Value = GetSyncPt(Context).GetMin(Args.Id); + Args.Value = GetUserCtx(Context).Syncpt.GetMin(Args.Id); } AMemoryHelper.Write(Context.Memory, OutputPosition, Args); @@ -149,16 +139,16 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvHostCtrl NvHostCtrlSyncptWait Args = AMemoryHelper.Read(Context.Memory, InputPosition); - NvHostSyncpt SyncPt = GetSyncPt(Context); + NvHostSyncpt Syncpt = GetUserCtx(Context).Syncpt; - if ((uint)Args.Id >= NvHostSyncpt.SyncPtsCount) + if ((uint)Args.Id >= NvHostSyncpt.SyncptsCount) { return NvResult.InvalidInput; } int Result; - if (SyncPt.MinCompare(Args.Id, Args.Thresh)) + if (Syncpt.MinCompare(Args.Id, Args.Thresh)) { Result = NvResult.Success; } @@ -172,7 +162,7 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvHostCtrl using (ManualResetEvent WaitEvent = new ManualResetEvent(false)) { - SyncPt.AddWaiter(Args.Thresh, WaitEvent); + Syncpt.AddWaiter(Args.Thresh, WaitEvent); //Note: Negative (> INT_MAX) timeouts aren't valid on .NET, //in this case we just use the maximum timeout possible. @@ -204,7 +194,7 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvHostCtrl if (Extended) { - Context.Memory.WriteInt32(OutputPosition + 0xc, SyncPt.GetMin(Args.Id)); + Context.Memory.WriteInt32(OutputPosition + 0xc, Syncpt.GetMin(Args.Id)); } return Result; @@ -217,7 +207,7 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvHostCtrl NvHostCtrlSyncptWaitEx Args = AMemoryHelper.Read(Context.Memory, InputPosition); - if ((uint)Args.Id >= NvHostSyncpt.SyncPtsCount) + if ((uint)Args.Id >= NvHostSyncpt.SyncptsCount) { return NvResult.InvalidInput; } @@ -227,13 +217,11 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvHostCtrl AMemoryHelper.Write(Context.Memory, OutputPosition, Args); } - NvHostSyncpt SyncPt = GetSyncPt(Context); + NvHostSyncpt Syncpt = GetUserCtx(Context).Syncpt; - Context.Ns.Log.PrintInfo(LogClass.ServiceNv, Args.Id + " " + Args.Thresh + " " + Args.Timeout + " " + Args.Value + " " + Async + " " + SyncPt.GetMin(Args.Id)); - - if (SyncPt.MinCompare(Args.Id, Args.Thresh)) + if (Syncpt.MinCompare(Args.Id, Args.Thresh)) { - Args.Value = SyncPt.GetMin(Args.Id); + Args.Value = Syncpt.GetMin(Args.Id); WriteArgs(); @@ -260,16 +248,16 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvHostCtrl { EventIndex = Args.Value; - if ((uint)EventIndex >= EventsCount) + if ((uint)EventIndex >= NvHostCtrlUserCtx.EventsCount) { return NvResult.InvalidInput; } - Event = GetEvents(Context)[EventIndex]; + Event = GetUserCtx(Context).Events[EventIndex]; } else { - Event = GetFreeEvent(Context, SyncPt, Args.Id, out EventIndex); + Event = GetFreeEvent(Context, Syncpt, Args.Id, out EventIndex); } if (Event != null && @@ -306,17 +294,17 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvHostCtrl private static NvHostEvent GetFreeEvent( ServiceCtx Context, - NvHostSyncpt SyncPt, + NvHostSyncpt Syncpt, int Id, out int EventIndex) { - NvHostEvent[] Events = GetEvents(Context); + NvHostEvent[] Events = GetUserCtx(Context).Events; - EventIndex = EventsCount; + EventIndex = NvHostCtrlUserCtx.EventsCount; - int NullIndex = EventsCount; + int NullIndex = NvHostCtrlUserCtx.EventsCount; - for (int Index = 0; Index < EventsCount; Index++) + for (int Index = 0; Index < NvHostCtrlUserCtx.EventsCount; Index++) { NvHostEvent Event = Events[Index]; @@ -333,20 +321,20 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvHostCtrl } } } - else if (NullIndex == EventsCount) + else if (NullIndex == NvHostCtrlUserCtx.EventsCount) { NullIndex = Index; } } - if (NullIndex < EventsCount) + if (NullIndex < NvHostCtrlUserCtx.EventsCount) { EventIndex = NullIndex; return Events[NullIndex] = new NvHostEvent(); } - if (EventIndex < EventsCount) + if (EventIndex < NvHostCtrlUserCtx.EventsCount) { return Events[EventIndex]; } @@ -354,14 +342,14 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvHostCtrl return null; } - public static NvHostSyncpt GetSyncPt(ServiceCtx Context) + public static NvHostCtrlUserCtx GetUserCtx(ServiceCtx Context) { - return NvSyncPts.GetOrAdd(Context.Process, (Key) => new NvHostSyncpt()); + return UserCtxs.GetOrAdd(Context.Process, (Key) => new NvHostCtrlUserCtx()); } - private static NvHostEvent[] GetEvents(ServiceCtx Context) + public static void UnloadProcess(Process Process) { - return EventArrays.GetOrAdd(Context.Process, (Key) => new NvHostEvent[EventsCount]); + UserCtxs.TryRemove(Process, out _); } } } \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlUserCtx.cs b/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlUserCtx.cs new file mode 100644 index 0000000000..be71b2252a --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlUserCtx.cs @@ -0,0 +1,19 @@ +namespace Ryujinx.Core.OsHle.Services.Nv.NvHostCtrl +{ + class NvHostCtrlUserCtx + { + public const int LocksCount = 16; + public const int EventsCount = 64; + + public NvHostSyncpt Syncpt { get; private set; } + + public NvHostEvent[] Events { get; private set; } + + public NvHostCtrlUserCtx() + { + Syncpt = new NvHostSyncpt(); + + Events = new NvHostEvent[EventsCount]; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostSyncPt.cs b/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostSyncPt.cs index f49cfa3b68..96ae16a390 100644 --- a/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostSyncPt.cs +++ b/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostSyncPt.cs @@ -7,7 +7,7 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvHostCtrl { class NvHostSyncpt { - public const int SyncPtsCount = 192; + public const int SyncptsCount = 192; private int[] CounterMin; private int[] CounterMax; @@ -18,8 +18,8 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvHostCtrl public NvHostSyncpt() { - CounterMin = new int[SyncPtsCount]; - CounterMax = new int[SyncPtsCount]; + CounterMin = new int[SyncptsCount]; + CounterMax = new int[SyncptsCount]; Waiters = new ConcurrentDictionary(); } diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapIoctl.cs b/Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapIoctl.cs index cf1eeb06d2..f9c1564a5a 100644 --- a/Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapIoctl.cs +++ b/Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapIoctl.cs @@ -10,11 +10,11 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvMap { private const int FlagNotFreedYet = 1; - private static ConcurrentDictionary NvMaps; + private static ConcurrentDictionary Maps; static NvMapIoctl() { - NvMaps = new ConcurrentDictionary(); + Maps = new ConcurrentDictionary(); } public static int ProcessIoctl(ServiceCtx Context, int Cmd) @@ -43,6 +43,8 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvMap if (Args.Size == 0) { + Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid size 0x{Args.Size:x8}!"); + return NvResult.InvalidInput; } @@ -68,6 +70,8 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvMap if (Map == null) { + Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{Args.Handle:x8}!"); + return NvResult.InvalidInput; } @@ -91,11 +95,15 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvMap if (Map == null) { + Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{Args.Handle:x8}!"); + return NvResult.InvalidInput; } if ((Args.Align & (Args.Align - 1)) != 0) { + Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid alignment 0x{Args.Align:x8}!"); + return NvResult.InvalidInput; } @@ -150,6 +158,8 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvMap if (Map == null) { + Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{Args.Handle:x8}!"); + return NvResult.InvalidInput; } @@ -187,6 +197,8 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvMap if (Map == null) { + Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{Args.Handle:x8}!"); + return NvResult.InvalidInput; } @@ -219,6 +231,8 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvMap if (Map == null) { + Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{Args.Handle:x8}!"); + return NvResult.InvalidInput; } @@ -231,23 +245,23 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvMap private static int AddNvMap(ServiceCtx Context, NvMapHandle Map) { - IdDictionary Maps = NvMaps.GetOrAdd(Context.Process, (Key) => + IdDictionary Dict = Maps.GetOrAdd(Context.Process, (Key) => { - IdDictionary Dict = new IdDictionary(); + IdDictionary NewDict = new IdDictionary(); - Dict.Add(0, new NvMapHandle()); + NewDict.Add(0, new NvMapHandle()); - return Dict; + return NewDict; }); - return Maps.Add(Map); + return Dict.Add(Map); } private static bool DeleteNvMap(ServiceCtx Context, int Handle) { - if (NvMaps.TryGetValue(Context.Process, out IdDictionary Maps)) + if (Maps.TryGetValue(Context.Process, out IdDictionary Dict)) { - return Maps.Delete(Handle) != null; + return Dict.Delete(Handle) != null; } return false; @@ -255,16 +269,16 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvMap public static void InitializeNvMap(ServiceCtx Context) { - IdDictionary Maps = NvMaps.GetOrAdd(Context.Process, (Key) =>new IdDictionary()); + IdDictionary Dict = Maps.GetOrAdd(Context.Process, (Key) =>new IdDictionary()); - Maps.Add(0, new NvMapHandle()); + Dict.Add(0, new NvMapHandle()); } public static NvMapHandle GetNvMapWithFb(ServiceCtx Context, int Handle) { - if (NvMaps.TryGetValue(Context.Process, out IdDictionary Maps)) + if (Maps.TryGetValue(Context.Process, out IdDictionary Dict)) { - return Maps.GetData(Handle); + return Dict.GetData(Handle); } return null; @@ -272,12 +286,17 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvMap public static NvMapHandle GetNvMap(ServiceCtx Context, int Handle) { - if (Handle != 0 && NvMaps.TryGetValue(Context.Process, out IdDictionary Maps)) + if (Handle != 0 && Maps.TryGetValue(Context.Process, out IdDictionary Dict)) { - return Maps.GetData(Handle); + return Dict.GetData(Handle); } return null; } + + public static void UnloadProcess(Process Process) + { + Maps.TryRemove(Process, out _); + } } } \ No newline at end of file