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
This commit is contained in:
parent
d06c6604fa
commit
cd6d2f699b
18 changed files with 323 additions and 120 deletions
|
@ -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);
|
||||
|
|
|
@ -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))
|
||||
{
|
||||
|
|
|
@ -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<long, MappedMemory> 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<long, MappedMemory>();
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -410,7 +410,7 @@ namespace Ryujinx.Core.OsHle
|
|||
}
|
||||
}
|
||||
|
||||
INvDrvServices.Fds.DeleteProcess(this);
|
||||
INvDrvServices.UnloadProcess(this);
|
||||
|
||||
AppletState.Dispose();
|
||||
|
||||
|
|
|
@ -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<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
private static Dictionary<string, ProcessIoctl> IoctlProcessors =
|
||||
new Dictionary<string, ProcessIoctl>()
|
||||
private static Dictionary<string, IoctlProcessor> IoctlProcessors =
|
||||
new Dictionary<string, IoctlProcessor>()
|
||||
{
|
||||
{ "/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);
|
||||
|
|
|
@ -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<NvGpuASRemap>(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 _);
|
||||
}
|
||||
}
|
||||
}
|
12
Ryujinx.Core/OsHle/Services/Nv/NvGpuAS/NvGpuASRemap.cs
Normal file
12
Ryujinx.Core/OsHle/Services/Nv/NvGpuAS/NvGpuASRemap.cs
Normal file
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
|
@ -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<NvHostCtrlGpuCharacteristics>(Context.Memory, InputPosition);
|
||||
NvGpuGpuGetCharacteristics Args = AMemoryHelper.Read<NvGpuGpuGetCharacteristics>(Context.Memory, InputPosition);
|
||||
|
||||
Args.BufferSize = 0xa0;
|
||||
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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<Process, NvHostEvent[]> EventArrays;
|
||||
|
||||
private static ConcurrentDictionary<Process, NvHostSyncpt> NvSyncPts;
|
||||
private static ConcurrentDictionary<Process, NvHostCtrlUserCtx> UserCtxs;
|
||||
|
||||
static NvHostCtrlIoctl()
|
||||
{
|
||||
EventArrays = new ConcurrentDictionary<Process, NvHostEvent[]>();
|
||||
|
||||
NvSyncPts = new ConcurrentDictionary<Process, NvHostSyncpt>();
|
||||
UserCtxs = new ConcurrentDictionary<Process, NvHostCtrlUserCtx>();
|
||||
}
|
||||
|
||||
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<NvHostCtrlSyncptRead>(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<NvHostCtrlSyncptWait>(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<NvHostCtrlSyncptWaitEx>(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 _);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<EventWaitHandle, int>();
|
||||
}
|
||||
|
|
|
@ -10,11 +10,11 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvMap
|
|||
{
|
||||
private const int FlagNotFreedYet = 1;
|
||||
|
||||
private static ConcurrentDictionary<Process, IdDictionary> NvMaps;
|
||||
private static ConcurrentDictionary<Process, IdDictionary> Maps;
|
||||
|
||||
static NvMapIoctl()
|
||||
{
|
||||
NvMaps = new ConcurrentDictionary<Process, IdDictionary>();
|
||||
Maps = new ConcurrentDictionary<Process, IdDictionary>();
|
||||
}
|
||||
|
||||
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<NvMapHandle>(Handle);
|
||||
return Dict.GetData<NvMapHandle>(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<NvMapHandle>(Handle);
|
||||
return Dict.GetData<NvMapHandle>(Handle);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void UnloadProcess(Process Process)
|
||||
{
|
||||
Maps.TryRemove(Process, out _);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue