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);
|
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);
|
||||||
|
|
|
@ -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))
|
||||||
{
|
{
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -410,7 +410,7 @@ namespace Ryujinx.Core.OsHle
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
INvDrvServices.Fds.DeleteProcess(this);
|
INvDrvServices.UnloadProcess(this);
|
||||||
|
|
||||||
AppletState.Dispose();
|
AppletState.Dispose();
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 _);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
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 BufferSize;
|
||||||
public long BufferAddress;
|
public long BufferAddress;
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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 _);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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
|
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>();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 _);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Add table
Add a link
Reference in a new issue