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
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); 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 SrcAddress = MakeInt64From2xInt32(NvGpuEngine2dReg.SrcAddress);
long DstAddress = MakeInt64From2xInt32(NvGpuEngine2dReg.DstAddress); long DstAddress = MakeInt64From2xInt32(NvGpuEngine2dReg.DstAddress);

View file

@ -104,7 +104,7 @@ namespace Ryujinx.Core.Gpu
{ {
long VA = MakeInt64From2xInt32(NvGpuEngine3dReg.FrameBufferNAddress + FbIndex * 0x10); long VA = MakeInt64From2xInt32(NvGpuEngine3dReg.FrameBufferNAddress + FbIndex * 0x10);
long PA = Vmm.GetCpuAddr(VA); long PA = Vmm.GetPhysicalAddress(VA);
FrameBuffers.Add(PA); FrameBuffers.Add(PA);
@ -259,7 +259,7 @@ namespace Ryujinx.Core.Gpu
long TextureAddress = Vmm.ReadInt64(TicPosition + 4) & 0xffffffffffff; long TextureAddress = Vmm.ReadInt64(TicPosition + 4) & 0xffffffffffff;
TextureAddress = Vmm.GetCpuAddr(TextureAddress); TextureAddress = Vmm.GetPhysicalAddress(TextureAddress);
if (IsFrameBufferPosition(TextureAddress)) if (IsFrameBufferPosition(TextureAddress))
{ {

View file

@ -1,4 +1,5 @@
using ChocolArm64.Memory; using ChocolArm64.Memory;
using System.Collections.Concurrent;
namespace Ryujinx.Core.Gpu namespace Ryujinx.Core.Gpu
{ {
@ -21,17 +22,31 @@ namespace Ryujinx.Core.Gpu
private const int PTLvl0Bit = PTPageBits + PTLvl1Bits; private const int PTLvl0Bit = PTPageBits + PTLvl1Bits;
private const int PTLvl1Bit = PTPageBits; 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 PteUnmapped = -1;
private const long PteReserved = -2; private const long PteReserved = -2;
private long[][] PageTable; private long[][] PageTable;
private AMemory Memory;
public NvGpuVmm(AMemory Memory) public NvGpuVmm(AMemory Memory)
{ {
this.Memory = Memory; this.Memory = Memory;
Maps = new ConcurrentDictionary<long, MappedMemory>();
PageTable = new long[PTLvl0Size][]; PageTable = new long[PTLvl0Size][];
} }
@ -60,20 +75,36 @@ namespace Ryujinx.Core.Gpu
{ {
lock (PageTable) 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) 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) public long Reserve(long VA, long Size, long Align)
{ {
lock (PageTable) lock (PageTable)
@ -164,7 +195,7 @@ namespace Ryujinx.Core.Gpu
return -1; return -1;
} }
public long GetCpuAddr(long VA) public long GetPhysicalAddress(long VA)
{ {
long BasePos = GetPte(VA); long BasePos = GetPte(VA);
@ -240,126 +271,126 @@ namespace Ryujinx.Core.Gpu
public byte ReadByte(long Position) public byte ReadByte(long Position)
{ {
Position = GetCpuAddr(Position); Position = GetPhysicalAddress(Position);
return Memory.ReadByte(Position); return Memory.ReadByte(Position);
} }
public ushort ReadUInt16(long Position) public ushort ReadUInt16(long Position)
{ {
Position = GetCpuAddr(Position); Position = GetPhysicalAddress(Position);
return Memory.ReadUInt16(Position); return Memory.ReadUInt16(Position);
} }
public uint ReadUInt32(long Position) public uint ReadUInt32(long Position)
{ {
Position = GetCpuAddr(Position); Position = GetPhysicalAddress(Position);
return Memory.ReadUInt32(Position); return Memory.ReadUInt32(Position);
} }
public ulong ReadUInt64(long Position) public ulong ReadUInt64(long Position)
{ {
Position = GetCpuAddr(Position); Position = GetPhysicalAddress(Position);
return Memory.ReadUInt64(Position); return Memory.ReadUInt64(Position);
} }
public sbyte ReadSByte(long Position) public sbyte ReadSByte(long Position)
{ {
Position = GetCpuAddr(Position); Position = GetPhysicalAddress(Position);
return Memory.ReadSByte(Position); return Memory.ReadSByte(Position);
} }
public short ReadInt16(long Position) public short ReadInt16(long Position)
{ {
Position = GetCpuAddr(Position); Position = GetPhysicalAddress(Position);
return Memory.ReadInt16(Position); return Memory.ReadInt16(Position);
} }
public int ReadInt32(long Position) public int ReadInt32(long Position)
{ {
Position = GetCpuAddr(Position); Position = GetPhysicalAddress(Position);
return Memory.ReadInt32(Position); return Memory.ReadInt32(Position);
} }
public long ReadInt64(long Position) public long ReadInt64(long Position)
{ {
Position = GetCpuAddr(Position); Position = GetPhysicalAddress(Position);
return Memory.ReadInt64(Position); return Memory.ReadInt64(Position);
} }
public byte[] ReadBytes(long Position, long Size) public byte[] ReadBytes(long Position, long Size)
{ {
Position = GetCpuAddr(Position); Position = GetPhysicalAddress(Position);
return AMemoryHelper.ReadBytes(Memory, Position, Size); return AMemoryHelper.ReadBytes(Memory, Position, Size);
} }
public void WriteByte(long Position, byte Value) public void WriteByte(long Position, byte Value)
{ {
Position = GetCpuAddr(Position); Position = GetPhysicalAddress(Position);
Memory.WriteByte(Position, Value); Memory.WriteByte(Position, Value);
} }
public void WriteUInt16(long Position, ushort Value) public void WriteUInt16(long Position, ushort Value)
{ {
Position = GetCpuAddr(Position); Position = GetPhysicalAddress(Position);
Memory.WriteUInt16(Position, Value); Memory.WriteUInt16(Position, Value);
} }
public void WriteUInt32(long Position, uint Value) public void WriteUInt32(long Position, uint Value)
{ {
Position = GetCpuAddr(Position); Position = GetPhysicalAddress(Position);
Memory.WriteUInt32(Position, Value); Memory.WriteUInt32(Position, Value);
} }
public void WriteUInt64(long Position, ulong Value) public void WriteUInt64(long Position, ulong Value)
{ {
Position = GetCpuAddr(Position); Position = GetPhysicalAddress(Position);
Memory.WriteUInt64(Position, Value); Memory.WriteUInt64(Position, Value);
} }
public void WriteSByte(long Position, sbyte Value) public void WriteSByte(long Position, sbyte Value)
{ {
Position = GetCpuAddr(Position); Position = GetPhysicalAddress(Position);
Memory.WriteSByte(Position, Value); Memory.WriteSByte(Position, Value);
} }
public void WriteInt16(long Position, short Value) public void WriteInt16(long Position, short Value)
{ {
Position = GetCpuAddr(Position); Position = GetPhysicalAddress(Position);
Memory.WriteInt16(Position, Value); Memory.WriteInt16(Position, Value);
} }
public void WriteInt32(long Position, int Value) public void WriteInt32(long Position, int Value)
{ {
Position = GetCpuAddr(Position); Position = GetPhysicalAddress(Position);
Memory.WriteInt32(Position, Value); Memory.WriteInt32(Position, Value);
} }
public void WriteInt64(long Position, long Value) public void WriteInt64(long Position, long Value)
{ {
Position = GetCpuAddr(Position); Position = GetPhysicalAddress(Position);
Memory.WriteInt64(Position, Value); Memory.WriteInt64(Position, Value);
} }
public void WriteBytes(long Position, byte[] Data) public void WriteBytes(long Position, byte[] Data)
{ {
Position = GetCpuAddr(Position); Position = GetPhysicalAddress(Position);
AMemoryHelper.WriteBytes(Memory, Position, Data); AMemoryHelper.WriteBytes(Memory, Position, Data);
} }

View file

@ -1,3 +1,4 @@
using ChocolArm64.Memory;
using System; using System;
namespace Ryujinx.Core.Gpu namespace Ryujinx.Core.Gpu
@ -19,5 +20,17 @@ namespace Ryujinx.Core.Gpu
throw new NotImplementedException(Texture.Swizzle.ToString()); 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); ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, Width, 2);
(AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition(
Memory,
Texture.Position);
fixed (byte* BuffPtr = Output) fixed (byte* BuffPtr = Output)
{ {
long OutOffs = 0; long OutOffs = 0;
@ -41,7 +45,7 @@ namespace Ryujinx.Core.Gpu
{ {
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y); long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
short Pixel = Memory.ReadInt16(Texture.Position + Offset); short Pixel = CpuMem.ReadInt16Unchecked(Position + Offset);
*(short*)(BuffPtr + OutOffs) = Pixel; *(short*)(BuffPtr + OutOffs) = Pixel;
@ -61,6 +65,10 @@ namespace Ryujinx.Core.Gpu
ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, Width, 4); ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, Width, 4);
(AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition(
Memory,
Texture.Position);
fixed (byte* BuffPtr = Output) fixed (byte* BuffPtr = Output)
{ {
long OutOffs = 0; long OutOffs = 0;
@ -70,7 +78,7 @@ namespace Ryujinx.Core.Gpu
{ {
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y); long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
int Pixel = Memory.ReadInt32(Texture.Position + Offset); int Pixel = CpuMem.ReadInt32Unchecked(Position + Offset);
*(int*)(BuffPtr + OutOffs) = Pixel; *(int*)(BuffPtr + OutOffs) = Pixel;
@ -90,6 +98,10 @@ namespace Ryujinx.Core.Gpu
ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, Width, 8); ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, Width, 8);
(AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition(
Memory,
Texture.Position);
fixed (byte* BuffPtr = Output) fixed (byte* BuffPtr = Output)
{ {
long OutOffs = 0; long OutOffs = 0;
@ -99,7 +111,7 @@ namespace Ryujinx.Core.Gpu
{ {
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y); long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
long Tile = Memory.ReadInt64(Texture.Position + Offset); long Tile = CpuMem.ReadInt64Unchecked(Position + Offset);
*(long*)(BuffPtr + OutOffs) = Tile; *(long*)(BuffPtr + OutOffs) = Tile;
@ -119,6 +131,10 @@ namespace Ryujinx.Core.Gpu
ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, Width, 16); ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, Width, 16);
(AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition(
Memory,
Texture.Position);
fixed (byte* BuffPtr = Output) fixed (byte* BuffPtr = Output)
{ {
long OutOffs = 0; long OutOffs = 0;
@ -128,8 +144,8 @@ namespace Ryujinx.Core.Gpu
{ {
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y); long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
long Tile0 = Memory.ReadInt64(Texture.Position + Offset + 0); long Tile0 = CpuMem.ReadInt64Unchecked(Position + Offset + 0);
long Tile1 = Memory.ReadInt64(Texture.Position + Offset + 8); long Tile1 = CpuMem.ReadInt64Unchecked(Position + Offset + 8);
*(long*)(BuffPtr + OutOffs + 0) = Tile0; *(long*)(BuffPtr + OutOffs + 0) = Tile0;
*(long*)(BuffPtr + OutOffs + 8) = Tile1; *(long*)(BuffPtr + OutOffs + 8) = Tile1;

View file

@ -12,8 +12,7 @@ namespace Ryujinx.Core.Gpu
{ {
case GalTextureFormat.A8B8G8R8: Write4Bpp(Memory, Texture, Data); break; case GalTextureFormat.A8B8G8R8: Write4Bpp(Memory, Texture, Data); break;
default: default: throw new NotImplementedException(Texture.Format.ToString());
throw new NotImplementedException(Texture.Format.ToString());
} }
} }
@ -24,6 +23,10 @@ namespace Ryujinx.Core.Gpu
ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, Width, 4); ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, Width, 4);
(AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition(
Memory,
Texture.Position);
fixed (byte* BuffPtr = Data) fixed (byte* BuffPtr = Data)
{ {
long InOffs = 0; long InOffs = 0;
@ -35,7 +38,7 @@ namespace Ryujinx.Core.Gpu
int Pixel = *(int*)(BuffPtr + InOffs); int Pixel = *(int*)(BuffPtr + InOffs);
Memory.WriteInt32(Texture.Position + Offset, Pixel); CpuMem.WriteInt32Unchecked(Position + Offset, Pixel);
InOffs += 4; InOffs += 4;
} }

View file

@ -40,7 +40,7 @@ namespace Ryujinx.Core.OsHle.Kernel
if (Obj == null) 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); 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) private void SendSyncRequest(AThreadState ThreadState, long CmdPtr, long Size, int Handle)
{ {
//Process.PrintStackTrace(ThreadState);
KThread CurrThread = Process.GetThread(ThreadState.Tpidr); KThread CurrThread = Process.GetThread(ThreadState.Tpidr);
byte[] CmdData = AMemoryHelper.ReadBytes(Memory, CmdPtr, Size); 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(); AppletState.Dispose();

View file

@ -1,10 +1,11 @@
using ChocolArm64.Memory; using ChocolArm64.Memory;
using Ryujinx.Core.Logging;
using Ryujinx.Core.OsHle.Handles; using Ryujinx.Core.OsHle.Handles;
using Ryujinx.Core.OsHle.Ipc; using Ryujinx.Core.OsHle.Ipc;
using Ryujinx.Core.OsHle.Services.Nv.NvGpuAS; 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.NvHostChannel;
using Ryujinx.Core.OsHle.Services.Nv.NvHostCtrl; using Ryujinx.Core.OsHle.Services.Nv.NvHostCtrl;
using Ryujinx.Core.OsHle.Services.Nv.NvHostCtrlGpu;
using Ryujinx.Core.OsHle.Services.Nv.NvMap; using Ryujinx.Core.OsHle.Services.Nv.NvMap;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -13,20 +14,20 @@ namespace Ryujinx.Core.OsHle.Services.Nv
{ {
class INvDrvServices : IpcService, IDisposable 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; private Dictionary<int, ServiceProcessRequest> m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
private static Dictionary<string, ProcessIoctl> IoctlProcessors = private static Dictionary<string, IoctlProcessor> IoctlProcessors =
new Dictionary<string, ProcessIoctl>() new Dictionary<string, IoctlProcessor>()
{ {
{ "/dev/nvhost-as-gpu", NvGpuASIoctl .ProcessIoctl }, { "/dev/nvhost-as-gpu", ProcessIoctlNvGpuAS },
{ "/dev/nvhost-ctrl", NvHostCtrlIoctl .ProcessIoctl }, { "/dev/nvhost-ctrl", ProcessIoctlNvHostCtrl },
{ "/dev/nvhost-ctrl-gpu", NvHostCtrlGpuIoctl.ProcessIoctl }, { "/dev/nvhost-ctrl-gpu", ProcessIoctlNvGpuGpu },
{ "/dev/nvhost-gpu", NvHostChannelIoctl.ProcessIoctl }, { "/dev/nvhost-gpu", ProcessIoctlNvHostChannel },
{ "/dev/nvmap", NvMapIoctl .ProcessIoctl } { "/dev/nvmap", ProcessIoctlNvMap }
}; };
public static GlobalStateTable Fds { get; private set; } public static GlobalStateTable Fds { get; private set; }
@ -76,7 +77,7 @@ namespace Ryujinx.Core.OsHle.Services.Nv
int Result; int Result;
if (IoctlProcessors.TryGetValue(FdData.Name, out ProcessIoctl Process)) if (IoctlProcessors.TryGetValue(FdData.Name, out IoctlProcessor Process))
{ {
Result = Process(Context, Cmd); Result = Process(Context, Cmd);
} }
@ -137,6 +138,71 @@ namespace Ryujinx.Core.OsHle.Services.Nv
return 0; 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() public void Dispose()
{ {
Dispose(true); Dispose(true);

View file

@ -29,6 +29,7 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvGpuAS
case 0x4106: return MapBufferEx (Context); case 0x4106: return MapBufferEx (Context);
case 0x4108: return GetVaRegions(Context); case 0x4108: return GetVaRegions(Context);
case 0x4109: return InitializeEx(Context); case 0x4109: return InitializeEx(Context);
case 0x4114: return Remap (Context);
} }
throw new NotImplementedException(Cmd.ToString("x8")); throw new NotImplementedException(Cmd.ToString("x8"));
@ -107,10 +108,10 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvGpuAS
NvGpuVmm Vmm = GetVmm(Context); 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}!"); Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid buffer offset {Args.Offset:x16}!");
}*/ }
return NvResult.Success; return NvResult.Success;
} }
@ -126,6 +127,13 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvGpuAS
NvMapHandle Map = NvMapIoctl.GetNvMapWithFb(Context, Args.NvMapHandle); 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 PA = Map.Address + Args.BufferOffset;
long Size = Args.MappingSize; long Size = Args.MappingSize;
@ -200,9 +208,38 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvGpuAS
return NvResult.Success; 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) public static NvGpuVmm GetVmm(ServiceCtx Context)
{ {
return Vmms.GetOrAdd(Context.Process, (Key) => new NvGpuVmm(Context.Memory)); 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 BufferSize;
public long BufferAddress; public long BufferAddress;

View file

@ -3,15 +3,15 @@ using Ryujinx.Core.Logging;
using System; using System;
using System.Diagnostics; 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 Stopwatch PTimer;
private static double TicksToNs; private static double TicksToNs;
static NvHostCtrlGpuIoctl() static NvGpuGpuIoctl()
{ {
PTimer = new Stopwatch(); PTimer = new Stopwatch();
@ -71,7 +71,7 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvHostCtrlGpu
long InputPosition = Context.Request.GetBufferType0x21Position(); long InputPosition = Context.Request.GetBufferType0x21Position();
long OutputPosition = Context.Request.GetBufferType0x22Position(); long OutputPosition = Context.Request.GetBufferType0x22Position();
NvHostCtrlGpuCharacteristics Args = AMemoryHelper.Read<NvHostCtrlGpuCharacteristics>(Context.Memory, InputPosition); NvGpuGpuGetCharacteristics Args = AMemoryHelper.Read<NvGpuGpuGetCharacteristics>(Context.Memory, InputPosition);
Args.BufferSize = 0xa0; Args.BufferSize = 0xa0;

View file

@ -69,7 +69,8 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvHostChannel
Context.Ns.Gpu.Fifo.PushBuffer(Vmm, PushBuffer); Context.Ns.Gpu.Fifo.PushBuffer(Vmm, PushBuffer);
} }
Args.SyncptId = 5; Args.SyncptId = 0;
Args.SyncptValue = 0;
AMemoryHelper.Write(Context.Memory, OutputPosition, Args); AMemoryHelper.Write(Context.Memory, OutputPosition, Args);

View file

@ -8,19 +8,11 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvHostCtrl
{ {
class NvHostCtrlIoctl class NvHostCtrlIoctl
{ {
private const int LocksCount = 16; private static ConcurrentDictionary<Process, NvHostCtrlUserCtx> UserCtxs;
private const int EventsCount = 64;
private static ConcurrentDictionary<Process, NvHostEvent[]> EventArrays;
private static ConcurrentDictionary<Process, NvHostSyncpt> NvSyncPts;
static NvHostCtrlIoctl() static NvHostCtrlIoctl()
{ {
EventArrays = new ConcurrentDictionary<Process, NvHostEvent[]>(); UserCtxs = new ConcurrentDictionary<Process, NvHostCtrlUserCtx>();
NvSyncPts = new ConcurrentDictionary<Process, NvHostSyncpt>();
} }
public static int ProcessIoctl(ServiceCtx Context, int Cmd) 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); int Id = Context.Memory.ReadInt32(InputPosition);
if ((uint)Id >= NvHostSyncpt.SyncPtsCount) if ((uint)Id >= NvHostSyncpt.SyncptsCount)
{ {
return NvResult.InvalidInput; return NvResult.InvalidInput;
} }
GetSyncPt(Context).Increment(Id); GetUserCtx(Context).Syncpt.Increment(Id);
return NvResult.Success; return NvResult.Success;
} }
@ -109,8 +101,6 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvHostCtrl
int EventId = Context.Memory.ReadInt32(InputPosition); int EventId = Context.Memory.ReadInt32(InputPosition);
Context.Ns.Log.PrintInfo(LogClass.ServiceNv, EventId.ToString());
Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed.");
return NvResult.Success; return NvResult.Success;
@ -123,18 +113,18 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvHostCtrl
NvHostCtrlSyncptRead Args = AMemoryHelper.Read<NvHostCtrlSyncptRead>(Context.Memory, InputPosition); NvHostCtrlSyncptRead Args = AMemoryHelper.Read<NvHostCtrlSyncptRead>(Context.Memory, InputPosition);
if ((uint)Args.Id >= NvHostSyncpt.SyncPtsCount) if ((uint)Args.Id >= NvHostSyncpt.SyncptsCount)
{ {
return NvResult.InvalidInput; return NvResult.InvalidInput;
} }
if (Max) if (Max)
{ {
Args.Value = GetSyncPt(Context).GetMax(Args.Id); Args.Value = GetUserCtx(Context).Syncpt.GetMax(Args.Id);
} }
else else
{ {
Args.Value = GetSyncPt(Context).GetMin(Args.Id); Args.Value = GetUserCtx(Context).Syncpt.GetMin(Args.Id);
} }
AMemoryHelper.Write(Context.Memory, OutputPosition, Args); 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); 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; return NvResult.InvalidInput;
} }
int Result; int Result;
if (SyncPt.MinCompare(Args.Id, Args.Thresh)) if (Syncpt.MinCompare(Args.Id, Args.Thresh))
{ {
Result = NvResult.Success; Result = NvResult.Success;
} }
@ -172,7 +162,7 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvHostCtrl
using (ManualResetEvent WaitEvent = new ManualResetEvent(false)) 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, //Note: Negative (> INT_MAX) timeouts aren't valid on .NET,
//in this case we just use the maximum timeout possible. //in this case we just use the maximum timeout possible.
@ -204,7 +194,7 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvHostCtrl
if (Extended) if (Extended)
{ {
Context.Memory.WriteInt32(OutputPosition + 0xc, SyncPt.GetMin(Args.Id)); Context.Memory.WriteInt32(OutputPosition + 0xc, Syncpt.GetMin(Args.Id));
} }
return Result; return Result;
@ -217,7 +207,7 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvHostCtrl
NvHostCtrlSyncptWaitEx Args = AMemoryHelper.Read<NvHostCtrlSyncptWaitEx>(Context.Memory, InputPosition); NvHostCtrlSyncptWaitEx Args = AMemoryHelper.Read<NvHostCtrlSyncptWaitEx>(Context.Memory, InputPosition);
if ((uint)Args.Id >= NvHostSyncpt.SyncPtsCount) if ((uint)Args.Id >= NvHostSyncpt.SyncptsCount)
{ {
return NvResult.InvalidInput; return NvResult.InvalidInput;
} }
@ -227,13 +217,11 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvHostCtrl
AMemoryHelper.Write(Context.Memory, OutputPosition, Args); 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(); WriteArgs();
@ -260,16 +248,16 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvHostCtrl
{ {
EventIndex = Args.Value; EventIndex = Args.Value;
if ((uint)EventIndex >= EventsCount) if ((uint)EventIndex >= NvHostCtrlUserCtx.EventsCount)
{ {
return NvResult.InvalidInput; return NvResult.InvalidInput;
} }
Event = GetEvents(Context)[EventIndex]; Event = GetUserCtx(Context).Events[EventIndex];
} }
else else
{ {
Event = GetFreeEvent(Context, SyncPt, Args.Id, out EventIndex); Event = GetFreeEvent(Context, Syncpt, Args.Id, out EventIndex);
} }
if (Event != null && if (Event != null &&
@ -306,17 +294,17 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvHostCtrl
private static NvHostEvent GetFreeEvent( private static NvHostEvent GetFreeEvent(
ServiceCtx Context, ServiceCtx Context,
NvHostSyncpt SyncPt, NvHostSyncpt Syncpt,
int Id, int Id,
out int EventIndex) 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]; 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; NullIndex = Index;
} }
} }
if (NullIndex < EventsCount) if (NullIndex < NvHostCtrlUserCtx.EventsCount)
{ {
EventIndex = NullIndex; EventIndex = NullIndex;
return Events[NullIndex] = new NvHostEvent(); return Events[NullIndex] = new NvHostEvent();
} }
if (EventIndex < EventsCount) if (EventIndex < NvHostCtrlUserCtx.EventsCount)
{ {
return Events[EventIndex]; return Events[EventIndex];
} }
@ -354,14 +342,14 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvHostCtrl
return null; 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 class NvHostSyncpt
{ {
public const int SyncPtsCount = 192; public const int SyncptsCount = 192;
private int[] CounterMin; private int[] CounterMin;
private int[] CounterMax; private int[] CounterMax;
@ -18,8 +18,8 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvHostCtrl
public NvHostSyncpt() public NvHostSyncpt()
{ {
CounterMin = new int[SyncPtsCount]; CounterMin = new int[SyncptsCount];
CounterMax = new int[SyncPtsCount]; CounterMax = new int[SyncptsCount];
Waiters = new ConcurrentDictionary<EventWaitHandle, int>(); Waiters = new ConcurrentDictionary<EventWaitHandle, int>();
} }

View file

@ -10,11 +10,11 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvMap
{ {
private const int FlagNotFreedYet = 1; private const int FlagNotFreedYet = 1;
private static ConcurrentDictionary<Process, IdDictionary> NvMaps; private static ConcurrentDictionary<Process, IdDictionary> Maps;
static NvMapIoctl() static NvMapIoctl()
{ {
NvMaps = new ConcurrentDictionary<Process, IdDictionary>(); Maps = new ConcurrentDictionary<Process, IdDictionary>();
} }
public static int ProcessIoctl(ServiceCtx Context, int Cmd) public static int ProcessIoctl(ServiceCtx Context, int Cmd)
@ -43,6 +43,8 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvMap
if (Args.Size == 0) if (Args.Size == 0)
{ {
Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid size 0x{Args.Size:x8}!");
return NvResult.InvalidInput; return NvResult.InvalidInput;
} }
@ -68,6 +70,8 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvMap
if (Map == null) if (Map == null)
{ {
Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{Args.Handle:x8}!");
return NvResult.InvalidInput; return NvResult.InvalidInput;
} }
@ -91,11 +95,15 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvMap
if (Map == null) if (Map == null)
{ {
Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{Args.Handle:x8}!");
return NvResult.InvalidInput; return NvResult.InvalidInput;
} }
if ((Args.Align & (Args.Align - 1)) != 0) if ((Args.Align & (Args.Align - 1)) != 0)
{ {
Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid alignment 0x{Args.Align:x8}!");
return NvResult.InvalidInput; return NvResult.InvalidInput;
} }
@ -150,6 +158,8 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvMap
if (Map == null) if (Map == null)
{ {
Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{Args.Handle:x8}!");
return NvResult.InvalidInput; return NvResult.InvalidInput;
} }
@ -187,6 +197,8 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvMap
if (Map == null) if (Map == null)
{ {
Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{Args.Handle:x8}!");
return NvResult.InvalidInput; return NvResult.InvalidInput;
} }
@ -219,6 +231,8 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvMap
if (Map == null) if (Map == null)
{ {
Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{Args.Handle:x8}!");
return NvResult.InvalidInput; return NvResult.InvalidInput;
} }
@ -231,23 +245,23 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvMap
private static int AddNvMap(ServiceCtx Context, NvMapHandle Map) 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) 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; return false;
@ -255,16 +269,16 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvMap
public static void InitializeNvMap(ServiceCtx Context) 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) 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; return null;
@ -272,12 +286,17 @@ namespace Ryujinx.Core.OsHle.Services.Nv.NvMap
public static NvMapHandle GetNvMap(ServiceCtx Context, int Handle) 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; return null;
} }
public static void UnloadProcess(Process Process)
{
Maps.TryRemove(Process, out _);
}
} }
} }