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:
gdkchan 2018-05-07 14:29:41 -03:00
parent d06c6604fa
commit cd6d2f699b
18 changed files with 323 additions and 120 deletions

View file

@ -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);

View file

@ -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))
{

View file

@ -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);
}

View file

@ -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);
}
}
}

View file

@ -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;

View file

@ -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;
}

View file

@ -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);

View file

@ -410,7 +410,7 @@ namespace Ryujinx.Core.OsHle
}
}
INvDrvServices.Fds.DeleteProcess(this);
INvDrvServices.UnloadProcess(this);
AppletState.Dispose();

View file

@ -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);

View file

@ -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 _);
}
}
}

View 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;
}
}

View file

@ -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;

View file

@ -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;

View file

@ -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);

View file

@ -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 _);
}
}
}

View file

@ -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];
}
}
}

View file

@ -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>();
}

View file

@ -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 _);
}
}
}