aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChocolArm64/Memory/AMemory.cs2
-rw-r--r--ChocolArm64/Memory/IAMemory.cs37
-rw-r--r--Ryujinx.Core/Gpu/BlockLinearSwizzle.cs (renamed from Ryujinx.Graphics/Gpu/BlockLinearSwizzle.cs)2
-rw-r--r--Ryujinx.Core/Gpu/INvGpuEngine.cs9
-rw-r--r--Ryujinx.Core/Gpu/ISwizzle.cs (renamed from Ryujinx.Graphics/Gpu/ISwizzle.cs)2
-rw-r--r--Ryujinx.Core/Gpu/LinearSwizzle.cs (renamed from Ryujinx.Graphics/Gpu/LinearSwizzle.cs)2
-rw-r--r--Ryujinx.Core/Gpu/MacroInterpreter.cs (renamed from Ryujinx.Graphics/Gpu/MacroInterpreter.cs)35
-rw-r--r--Ryujinx.Core/Gpu/NvGpu.cs (renamed from Ryujinx.Graphics/Gpu/NsGpu.cs)35
-rw-r--r--Ryujinx.Core/Gpu/NvGpuEngine.cs (renamed from Ryujinx.Graphics/Gpu/NvGpuEngine.cs)2
-rw-r--r--Ryujinx.Core/Gpu/NvGpuEngine2d.cs (renamed from Ryujinx.Graphics/Gpu/NvGpuEngine2d.cs)40
-rw-r--r--Ryujinx.Core/Gpu/NvGpuEngine2dReg.cs (renamed from Ryujinx.Graphics/Gpu/NvGpuEngine2dReg.cs)2
-rw-r--r--Ryujinx.Core/Gpu/NvGpuEngine3d.cs (renamed from Ryujinx.Graphics/Gpu/NvGpuEngine3d.cs)191
-rw-r--r--Ryujinx.Core/Gpu/NvGpuEngine3dReg.cs (renamed from Ryujinx.Graphics/Gpu/NvGpuEngine3dReg.cs)8
-rw-r--r--Ryujinx.Core/Gpu/NvGpuFifo.cs (renamed from Ryujinx.Graphics/Gpu/NvGpuFifo.cs)47
-rw-r--r--Ryujinx.Core/Gpu/NvGpuFifoMeth.cs (renamed from Ryujinx.Graphics/Gpu/NvGpuFifoMeth.cs)2
-rw-r--r--Ryujinx.Core/Gpu/NvGpuMethod.cs4
-rw-r--r--Ryujinx.Core/Gpu/NvGpuPBEntry.cs (renamed from Ryujinx.Graphics/Gpu/NsGpuPBEntry.cs)6
-rw-r--r--Ryujinx.Core/Gpu/NvGpuPushBuffer.cs (renamed from Ryujinx.Graphics/Gpu/NvGpuPushBuffer.cs)18
-rw-r--r--Ryujinx.Core/Gpu/NvGpuVmm.cs398
-rw-r--r--Ryujinx.Core/Gpu/Texture.cs (renamed from Ryujinx.Graphics/Gpu/Texture.cs)2
-rw-r--r--Ryujinx.Core/Gpu/TextureFactory.cs (renamed from Ryujinx.Graphics/Gpu/TextureFactory.cs)19
-rw-r--r--Ryujinx.Core/Gpu/TextureHelper.cs (renamed from Ryujinx.Graphics/Gpu/TextureHelper.cs)15
-rw-r--r--Ryujinx.Core/Gpu/TextureReader.cs (renamed from Ryujinx.Graphics/Gpu/TextureReader.cs)38
-rw-r--r--Ryujinx.Core/Gpu/TextureSwizzle.cs (renamed from Ryujinx.Graphics/Gpu/TextureSwizzle.cs)2
-rw-r--r--Ryujinx.Core/Gpu/TextureWriter.cs (renamed from Ryujinx.Graphics/Gpu/TextureWriter.cs)15
-rw-r--r--Ryujinx.Core/Loaders/Executable.cs6
-rw-r--r--Ryujinx.Core/OsHle/Horizon.cs4
-rw-r--r--Ryujinx.Core/OsHle/Ipc/IpcHandler.cs4
-rw-r--r--Ryujinx.Core/OsHle/Ipc/IpcMessage.cs25
-rw-r--r--Ryujinx.Core/OsHle/Kernel/KernelErr.cs2
-rw-r--r--Ryujinx.Core/OsHle/Kernel/SvcHandler.cs21
-rw-r--r--Ryujinx.Core/OsHle/Kernel/SvcSystem.cs85
-rw-r--r--Ryujinx.Core/OsHle/Kernel/SvcThreadSync.cs6
-rw-r--r--Ryujinx.Core/OsHle/MemoryAllocator.cs12
-rw-r--r--Ryujinx.Core/OsHle/Process.cs6
-rw-r--r--Ryujinx.Core/OsHle/Services/Nv/INvDrvServices.cs728
-rw-r--r--Ryujinx.Core/OsHle/Services/Nv/NvChNvMap.cs31
-rw-r--r--Ryujinx.Core/OsHle/Services/Nv/NvGpuAS/NvGpuASAllocSpace.cs11
-rw-r--r--Ryujinx.Core/OsHle/Services/Nv/NvGpuAS/NvGpuASIoctl.cs245
-rw-r--r--Ryujinx.Core/OsHle/Services/Nv/NvGpuAS/NvGpuASMapBufferEx.cs13
-rw-r--r--Ryujinx.Core/OsHle/Services/Nv/NvGpuAS/NvGpuASRemap.cs12
-rw-r--r--Ryujinx.Core/OsHle/Services/Nv/NvGpuAS/NvGpuASUnmapBuffer.cs7
-rw-r--r--Ryujinx.Core/OsHle/Services/Nv/NvGpuGpu/NvGpuGpuGetCharacteristics.cs43
-rw-r--r--Ryujinx.Core/OsHle/Services/Nv/NvGpuGpu/NvGpuGpuIoctl.cs155
-rw-r--r--Ryujinx.Core/OsHle/Services/Nv/NvHelper.cs10
-rw-r--r--Ryujinx.Core/OsHle/Services/Nv/NvHostChannel/NvHostChannelIoctl.cs130
-rw-r--r--Ryujinx.Core/OsHle/Services/Nv/NvHostChannel/NvHostChannelSubmitGpfifo.cs11
-rw-r--r--Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlIoctl.cs355
-rw-r--r--Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtRead.cs8
-rw-r--r--Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtWait.cs9
-rw-r--r--Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtWaitEx.cs10
-rw-r--r--Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlUserCtx.cs19
-rw-r--r--Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostEvent.cs10
-rw-r--r--Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostEventState.cs10
-rw-r--r--Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostSyncPt.cs107
-rw-r--r--Ryujinx.Core/OsHle/Services/Nv/NvMap.cs20
-rw-r--r--Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapAlloc.cs12
-rw-r--r--Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapCreate.cs8
-rw-r--r--Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapFree.cs11
-rw-r--r--Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapFromId.cs8
-rw-r--r--Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapGetId.cs8
-rw-r--r--Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapHandle.cs37
-rw-r--r--Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapHandleParam.cs12
-rw-r--r--Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapIoctl.cs302
-rw-r--r--Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapParam.cs9
-rw-r--r--Ryujinx.Core/OsHle/Services/Nv/NvMapFb.cs40
-rw-r--r--Ryujinx.Core/OsHle/Services/Nv/NvResult.cs13
-rw-r--r--Ryujinx.Core/OsHle/Services/Vi/NvFlinger.cs42
-rw-r--r--Ryujinx.Core/OsHle/Utilities/IntUtils.cs15
-rw-r--r--Ryujinx.Core/OsHle/Utilities/MemReader.cs44
-rw-r--r--Ryujinx.Core/OsHle/Utilities/MemWriter.cs38
-rw-r--r--Ryujinx.Core/Switch.cs6
-rw-r--r--Ryujinx.Graphics/Gpu/INvGpuEngine.cs11
-rw-r--r--Ryujinx.Graphics/Gpu/NsGpuMemoryMgr.cs212
-rw-r--r--Ryujinx.Graphics/Gpu/NvGpuMethod.cs6
75 files changed, 2457 insertions, 1425 deletions
diff --git a/ChocolArm64/Memory/AMemory.cs b/ChocolArm64/Memory/AMemory.cs
index d7e11189..6625966f 100644
--- a/ChocolArm64/Memory/AMemory.cs
+++ b/ChocolArm64/Memory/AMemory.cs
@@ -6,7 +6,7 @@ using System.Runtime.InteropServices;
namespace ChocolArm64.Memory
{
- public unsafe class AMemory : IDisposable
+ public unsafe class AMemory : IAMemory, IDisposable
{
private const long ErgMask = (4 << AThreadState.ErgSizeLog2) - 1;
diff --git a/ChocolArm64/Memory/IAMemory.cs b/ChocolArm64/Memory/IAMemory.cs
new file mode 100644
index 00000000..5b7d17bb
--- /dev/null
+++ b/ChocolArm64/Memory/IAMemory.cs
@@ -0,0 +1,37 @@
+namespace ChocolArm64.Memory
+{
+ public interface IAMemory
+ {
+ sbyte ReadSByte(long Position);
+
+ short ReadInt16(long Position);
+
+ int ReadInt32(long Position);
+
+ long ReadInt64(long Position);
+
+ byte ReadByte(long Position);
+
+ ushort ReadUInt16(long Position);
+
+ uint ReadUInt32(long Position);
+
+ ulong ReadUInt64(long Position);
+
+ void WriteSByte(long Position, sbyte Value);
+
+ void WriteInt16(long Position, short Value);
+
+ void WriteInt32(long Position, int Value);
+
+ void WriteInt64(long Position, long Value);
+
+ void WriteByte(long Position, byte Value);
+
+ void WriteUInt16(long Position, ushort Value);
+
+ void WriteUInt32(long Position, uint Value);
+
+ void WriteUInt64(long Position, ulong Value);
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Gpu/BlockLinearSwizzle.cs b/Ryujinx.Core/Gpu/BlockLinearSwizzle.cs
index d2cbb144..eb41ea30 100644
--- a/Ryujinx.Graphics/Gpu/BlockLinearSwizzle.cs
+++ b/Ryujinx.Core/Gpu/BlockLinearSwizzle.cs
@@ -1,4 +1,4 @@
-namespace Ryujinx.Graphics.Gpu
+namespace Ryujinx.Core.Gpu
{
class BlockLinearSwizzle : ISwizzle
{
diff --git a/Ryujinx.Core/Gpu/INvGpuEngine.cs b/Ryujinx.Core/Gpu/INvGpuEngine.cs
new file mode 100644
index 00000000..865ea8ba
--- /dev/null
+++ b/Ryujinx.Core/Gpu/INvGpuEngine.cs
@@ -0,0 +1,9 @@
+namespace Ryujinx.Core.Gpu
+{
+ interface INvGpuEngine
+ {
+ int[] Registers { get; }
+
+ void CallMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry);
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Gpu/ISwizzle.cs b/Ryujinx.Core/Gpu/ISwizzle.cs
index 755051d0..f475be6e 100644
--- a/Ryujinx.Graphics/Gpu/ISwizzle.cs
+++ b/Ryujinx.Core/Gpu/ISwizzle.cs
@@ -1,4 +1,4 @@
-namespace Ryujinx.Graphics.Gpu
+namespace Ryujinx.Core.Gpu
{
interface ISwizzle
{
diff --git a/Ryujinx.Graphics/Gpu/LinearSwizzle.cs b/Ryujinx.Core/Gpu/LinearSwizzle.cs
index c7a6b304..5f8dfdde 100644
--- a/Ryujinx.Graphics/Gpu/LinearSwizzle.cs
+++ b/Ryujinx.Core/Gpu/LinearSwizzle.cs
@@ -1,4 +1,4 @@
-namespace Ryujinx.Graphics.Gpu
+namespace Ryujinx.Core.Gpu
{
class LinearSwizzle : ISwizzle
{
diff --git a/Ryujinx.Graphics/Gpu/MacroInterpreter.cs b/Ryujinx.Core/Gpu/MacroInterpreter.cs
index 233baac8..b799f98f 100644
--- a/Ryujinx.Graphics/Gpu/MacroInterpreter.cs
+++ b/Ryujinx.Core/Gpu/MacroInterpreter.cs
@@ -1,8 +1,7 @@
-using ChocolArm64.Memory;
using System;
using System.Collections.Generic;
-namespace Ryujinx.Graphics.Gpu
+namespace Ryujinx.Core.Gpu
{
class MacroInterpreter
{
@@ -69,7 +68,7 @@ namespace Ryujinx.Graphics.Gpu
Gprs = new int[8];
}
- public void Execute(AMemory Memory, long Position, int Param)
+ public void Execute(NvGpuVmm Vmm, long Position, int Param)
{
Reset();
@@ -77,13 +76,13 @@ namespace Ryujinx.Graphics.Gpu
Pc = Position;
- FetchOpCode(Memory);
+ FetchOpCode(Vmm);
- while (Step(Memory));
+ while (Step(Vmm));
//Due to the delay slot, we still need to execute
//one more instruction before we actually exit.
- Step(Memory);
+ Step(Vmm);
}
private void Reset()
@@ -99,11 +98,11 @@ namespace Ryujinx.Graphics.Gpu
Carry = false;
}
- private bool Step(AMemory Memory)
+ private bool Step(NvGpuVmm Vmm)
{
long BaseAddr = Pc - 4;
- FetchOpCode(Memory);
+ FetchOpCode(Vmm);
if ((OpCode & 7) < 7)
{
@@ -145,7 +144,7 @@ namespace Ryujinx.Graphics.Gpu
{
SetDstGpr(FetchParam());
- Send(Memory, Result);
+ Send(Vmm, Result);
break;
}
@@ -155,7 +154,7 @@ namespace Ryujinx.Graphics.Gpu
{
SetDstGpr(Result);
- Send(Memory, Result);
+ Send(Vmm, Result);
break;
}
@@ -177,7 +176,7 @@ namespace Ryujinx.Graphics.Gpu
SetMethAddr(Result);
- Send(Memory, FetchParam());
+ Send(Vmm, FetchParam());
break;
}
@@ -189,7 +188,7 @@ namespace Ryujinx.Graphics.Gpu
SetMethAddr(Result);
- Send(Memory, (Result >> 12) & 0x3f);
+ Send(Vmm, (Result >> 12) & 0x3f);
break;
}
@@ -212,7 +211,7 @@ namespace Ryujinx.Graphics.Gpu
if (NoDelays)
{
- FetchOpCode(Memory);
+ FetchOpCode(Vmm);
}
return true;
@@ -224,11 +223,11 @@ namespace Ryujinx.Graphics.Gpu
return !Exit;
}
- private void FetchOpCode(AMemory Memory)
+ private void FetchOpCode(NvGpuVmm Vmm)
{
OpCode = PipeOp;
- PipeOp = Memory.ReadInt32(Pc);
+ PipeOp = Vmm.ReadInt32(Pc);
Pc += 4;
}
@@ -408,11 +407,11 @@ namespace Ryujinx.Graphics.Gpu
return Engine.Registers[Reg];
}
- private void Send(AMemory Memory, int Value)
+ private void Send(NvGpuVmm Vmm, int Value)
{
- NsGpuPBEntry PBEntry = new NsGpuPBEntry(MethAddr, 0, Value);
+ NvGpuPBEntry PBEntry = new NvGpuPBEntry(MethAddr, 0, Value);
- Engine.CallMethod(Memory, PBEntry);
+ Engine.CallMethod(Vmm, PBEntry);
MethAddr += MethIncr;
}
diff --git a/Ryujinx.Graphics/Gpu/NsGpu.cs b/Ryujinx.Core/Gpu/NvGpu.cs
index e1088982..71df76ff 100644
--- a/Ryujinx.Graphics/Gpu/NsGpu.cs
+++ b/Ryujinx.Core/Gpu/NvGpu.cs
@@ -1,14 +1,12 @@
using Ryujinx.Graphics.Gal;
using System.Threading;
-namespace Ryujinx.Graphics.Gpu
+namespace Ryujinx.Core.Gpu
{
- public class NsGpu
+ public class NvGpu
{
public IGalRenderer Renderer { get; private set; }
- public NsGpuMemoryMgr MemoryMgr { get; private set; }
-
public NvGpuFifo Fifo { get; private set; }
public NvGpuEngine2d Engine2d { get; private set; }
@@ -18,12 +16,10 @@ namespace Ryujinx.Graphics.Gpu
private bool KeepRunning;
- public NsGpu(IGalRenderer Renderer)
+ public NvGpu(IGalRenderer Renderer)
{
this.Renderer = Renderer;
- MemoryMgr = new NsGpuMemoryMgr();
-
Fifo = new NvGpuFifo(this);
Engine2d = new NvGpuEngine2d(this);
@@ -36,31 +32,6 @@ namespace Ryujinx.Graphics.Gpu
FifoProcessing.Start();
}
- public long GetCpuAddr(long Position)
- {
- return MemoryMgr.GetCpuAddr(Position);
- }
-
- public long MapMemory(long CpuAddr, long Size)
- {
- return MemoryMgr.Map(CpuAddr, Size);
- }
-
- public long MapMemory(long CpuAddr, long GpuAddr, long Size)
- {
- return MemoryMgr.Map(CpuAddr, GpuAddr, Size);
- }
-
- public long ReserveMemory(long Size, long Align)
- {
- return MemoryMgr.Reserve(Size, Align);
- }
-
- public long ReserveMemory(long GpuAddr, long Size, long Align)
- {
- return MemoryMgr.Reserve(GpuAddr, Size, Align);
- }
-
private void ProcessFifo()
{
while (KeepRunning)
diff --git a/Ryujinx.Graphics/Gpu/NvGpuEngine.cs b/Ryujinx.Core/Gpu/NvGpuEngine.cs
index 624915d0..ee0420f7 100644
--- a/Ryujinx.Graphics/Gpu/NvGpuEngine.cs
+++ b/Ryujinx.Core/Gpu/NvGpuEngine.cs
@@ -1,4 +1,4 @@
-namespace Ryujinx.Graphics.Gpu
+namespace Ryujinx.Core.Gpu
{
enum NvGpuEngine
{
diff --git a/Ryujinx.Graphics/Gpu/NvGpuEngine2d.cs b/Ryujinx.Core/Gpu/NvGpuEngine2d.cs
index c2bee167..88395b7a 100644
--- a/Ryujinx.Graphics/Gpu/NvGpuEngine2d.cs
+++ b/Ryujinx.Core/Gpu/NvGpuEngine2d.cs
@@ -1,8 +1,7 @@
-using ChocolArm64.Memory;
using Ryujinx.Graphics.Gal;
using System.Collections.Generic;
-namespace Ryujinx.Graphics.Gpu
+namespace Ryujinx.Core.Gpu
{
public class NvGpuEngine2d : INvGpuEngine
{
@@ -19,11 +18,11 @@ namespace Ryujinx.Graphics.Gpu
public int[] Registers { get; private set; }
- private NsGpu Gpu;
+ private NvGpu Gpu;
private Dictionary<int, NvGpuMethod> Methods;
- public NvGpuEngine2d(NsGpu Gpu)
+ public NvGpuEngine2d(NvGpu Gpu)
{
this.Gpu = Gpu;
@@ -44,11 +43,11 @@ namespace Ryujinx.Graphics.Gpu
AddMethod(0xb5, 1, 1, TextureCopy);
}
- public void CallMethod(AMemory Memory, NsGpuPBEntry PBEntry)
+ public void CallMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
{
if (Methods.TryGetValue(PBEntry.Method, out NvGpuMethod Method))
{
- Method(Memory, PBEntry);
+ Method(Vmm, PBEntry);
}
else
{
@@ -56,7 +55,7 @@ namespace Ryujinx.Graphics.Gpu
}
}
- private void TextureCopy(AMemory Memory, NsGpuPBEntry PBEntry)
+ private void TextureCopy(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
{
CopyOperation Operation = (CopyOperation)ReadRegister(NvGpuEngine2dReg.CopyOperation);
@@ -76,10 +75,10 @@ namespace Ryujinx.Graphics.Gpu
int DstBlockHeight = 1 << ((DstBlkDim >> 4) & 0xf);
- long Tag = MakeInt64From2xInt32(NvGpuEngine2dReg.SrcAddress);
+ long Tag = Vmm.GetPhysicalAddress(MakeInt64From2xInt32(NvGpuEngine2dReg.SrcAddress));
- TryGetCpuAddr(NvGpuEngine2dReg.SrcAddress, out long SrcAddress);
- TryGetCpuAddr(NvGpuEngine2dReg.DstAddress, out long DstAddress);
+ long SrcAddress = MakeInt64From2xInt32(NvGpuEngine2dReg.SrcAddress);
+ long DstAddress = MakeInt64From2xInt32(NvGpuEngine2dReg.DstAddress);
bool IsFbTexture = Gpu.Engine3d.IsFrameBufferPosition(Tag);
@@ -101,31 +100,22 @@ namespace Ryujinx.Graphics.Gpu
{
Gpu.Renderer.GetFrameBufferData(Tag, (byte[] Buffer) =>
{
- CopyTexture(Memory, DstTexture, Buffer);
+ CopyTexture(Vmm, DstTexture, Buffer);
});
}
else
{
long Size = SrcWidth * SrcHeight * 4;
- byte[] Buffer = AMemoryHelper.ReadBytes(Memory, SrcAddress, Size);
+ byte[] Buffer = Vmm.ReadBytes(SrcAddress, Size);
- CopyTexture(Memory, DstTexture, Buffer);
+ CopyTexture(Vmm, DstTexture, Buffer);
}
}
- private void CopyTexture(AMemory Memory, Texture Texture, byte[] Buffer)
+ private void CopyTexture(NvGpuVmm Vmm, Texture Texture, byte[] Buffer)
{
- TextureWriter.Write(Memory, Texture, Buffer);
- }
-
- private bool TryGetCpuAddr(NvGpuEngine2dReg Reg, out long Position)
- {
- Position = MakeInt64From2xInt32(Reg);
-
- Position = Gpu.GetCpuAddr(Position);
-
- return Position != -1;
+ TextureWriter.Write(Vmm, Texture, Buffer);
}
private long MakeInt64From2xInt32(NvGpuEngine2dReg Reg)
@@ -135,7 +125,7 @@ namespace Ryujinx.Graphics.Gpu
(uint)Registers[(int)Reg + 1];
}
- private void WriteRegister(NsGpuPBEntry PBEntry)
+ private void WriteRegister(NvGpuPBEntry PBEntry)
{
int ArgsCount = PBEntry.Arguments.Count;
diff --git a/Ryujinx.Graphics/Gpu/NvGpuEngine2dReg.cs b/Ryujinx.Core/Gpu/NvGpuEngine2dReg.cs
index 903baca8..b4abad00 100644
--- a/Ryujinx.Graphics/Gpu/NvGpuEngine2dReg.cs
+++ b/Ryujinx.Core/Gpu/NvGpuEngine2dReg.cs
@@ -1,4 +1,4 @@
-namespace Ryujinx.Graphics.Gpu
+namespace Ryujinx.Core.Gpu
{
enum NvGpuEngine2dReg
{
diff --git a/Ryujinx.Graphics/Gpu/NvGpuEngine3d.cs b/Ryujinx.Core/Gpu/NvGpuEngine3d.cs
index a6696650..b08b9496 100644
--- a/Ryujinx.Graphics/Gpu/NvGpuEngine3d.cs
+++ b/Ryujinx.Core/Gpu/NvGpuEngine3d.cs
@@ -1,15 +1,14 @@
-using ChocolArm64.Memory;
using Ryujinx.Graphics.Gal;
using System;
using System.Collections.Generic;
-namespace Ryujinx.Graphics.Gpu
+namespace Ryujinx.Core.Gpu
{
public class NvGpuEngine3d : INvGpuEngine
{
public int[] Registers { get; private set; }
- private NsGpu Gpu;
+ private NvGpu Gpu;
private Dictionary<int, NvGpuMethod> Methods;
@@ -20,11 +19,11 @@ namespace Ryujinx.Graphics.Gpu
public int Size;
}
- private ConstBuffer[] ConstBuffers;
+ private ConstBuffer[][] ConstBuffers;
private HashSet<long> FrameBuffers;
- public NvGpuEngine3d(NsGpu Gpu)
+ public NvGpuEngine3d(NvGpu Gpu)
{
this.Gpu = Gpu;
@@ -46,18 +45,23 @@ namespace Ryujinx.Graphics.Gpu
AddMethod(0x674, 1, 1, ClearBuffers);
AddMethod(0x6c3, 1, 1, QueryControl);
AddMethod(0x8e4, 16, 1, CbData);
- AddMethod(0x904, 1, 1, CbBind);
+ AddMethod(0x904, 5, 8, CbBind);
- ConstBuffers = new ConstBuffer[18];
+ ConstBuffers = new ConstBuffer[6][];
+
+ for (int Index = 0; Index < ConstBuffers.Length; Index++)
+ {
+ ConstBuffers[Index] = new ConstBuffer[18];
+ }
FrameBuffers = new HashSet<long>();
}
- public void CallMethod(AMemory Memory, NsGpuPBEntry PBEntry)
+ public void CallMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
{
if (Methods.TryGetValue(PBEntry.Method, out NvGpuMethod Method))
{
- Method(Memory, PBEntry);
+ Method(Vmm, PBEntry);
}
else
{
@@ -65,22 +69,22 @@ namespace Ryujinx.Graphics.Gpu
}
}
- private void VertexEndGl(AMemory Memory, NsGpuPBEntry PBEntry)
+ private void VertexEndGl(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
{
- SetFrameBuffer(0);
+ SetFrameBuffer(Vmm, 0);
- long[] Tags = UploadShaders(Memory);
+ long[] Tags = UploadShaders(Vmm);
Gpu.Renderer.BindProgram();
SetAlphaBlending();
- UploadTextures(Memory, Tags);
- UploadUniforms(Memory);
- UploadVertexArrays(Memory);
+ UploadTextures(Vmm, Tags);
+ UploadUniforms(Vmm);
+ UploadVertexArrays(Vmm);
}
- private void ClearBuffers(AMemory Memory, NsGpuPBEntry PBEntry)
+ private void ClearBuffers(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
{
int Arg0 = PBEntry.Arguments[0];
@@ -90,28 +94,30 @@ namespace Ryujinx.Graphics.Gpu
GalClearBufferFlags Flags = (GalClearBufferFlags)(Arg0 & 0x3f);
- SetFrameBuffer(0);
+ SetFrameBuffer(Vmm, 0);
//TODO: Enable this once the frame buffer problems are fixed.
//Gpu.Renderer.ClearBuffers(Layer, Flags);
}
- private void SetFrameBuffer(int FbIndex)
+ private void SetFrameBuffer(NvGpuVmm Vmm, int FbIndex)
{
- long Address = MakeInt64From2xInt32(NvGpuEngine3dReg.FrameBufferNAddress + FbIndex * 0x10);
+ long VA = MakeInt64From2xInt32(NvGpuEngine3dReg.FrameBufferNAddress + FbIndex * 0x10);
- FrameBuffers.Add(Address);
+ long PA = Vmm.GetPhysicalAddress(VA);
+
+ FrameBuffers.Add(PA);
int Width = ReadRegister(NvGpuEngine3dReg.FrameBufferNWidth + FbIndex * 0x10);
int Height = ReadRegister(NvGpuEngine3dReg.FrameBufferNHeight + FbIndex * 0x10);
//Note: Using the Width/Height results seems to give incorrect results.
//Maybe the size of all frame buffers is hardcoded to screen size? This seems unlikely.
- Gpu.Renderer.CreateFrameBuffer(Address, 1280, 720);
- Gpu.Renderer.BindFrameBuffer(Address);
+ Gpu.Renderer.CreateFrameBuffer(PA, 1280, 720);
+ Gpu.Renderer.BindFrameBuffer(PA);
}
- private long[] UploadShaders(AMemory Memory)
+ private long[] UploadShaders(NvGpuVmm Vmm)
{
long[] Tags = new long[5];
@@ -132,12 +138,10 @@ namespace Ryujinx.Graphics.Gpu
long Tag = BasePosition + (uint)Offset;
- long Position = Gpu.GetCpuAddr(Tag);
-
//TODO: Find a better way to calculate the size.
int Size = 0x20000;
- byte[] Code = AMemoryHelper.ReadBytes(Memory, Position, (uint)Size);
+ byte[] Code = Vmm.ReadBytes(Tag, Size);
GalShaderType ShaderType = GetTypeFromProgram(Index);
@@ -211,16 +215,12 @@ namespace Ryujinx.Graphics.Gpu
}
}
- private void UploadTextures(AMemory Memory, long[] Tags)
+ private void UploadTextures(NvGpuVmm Vmm, long[] Tags)
{
long BaseShPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.ShaderAddress);
int TextureCbIndex = ReadRegister(NvGpuEngine3dReg.TextureCbIndex);
- long BasePosition = ConstBuffers[TextureCbIndex].Position;
-
- long Size = (uint)ConstBuffers[TextureCbIndex].Size;
-
//Note: On the emulator renderer, Texture Unit 0 is
//reserved for drawing the frame buffer.
int TexIndex = 1;
@@ -229,9 +229,9 @@ namespace Ryujinx.Graphics.Gpu
{
foreach (ShaderDeclInfo DeclInfo in Gpu.Renderer.GetTextureUsage(Tags[Index]))
{
- long Position = BasePosition + Index * Size;
+ long Position = ConstBuffers[Index][TextureCbIndex].Position;
- UploadTexture(Memory, Position, TexIndex, DeclInfo.Index);
+ UploadTexture(Vmm, Position, TexIndex, DeclInfo.Index);
Gpu.Renderer.SetUniform1(DeclInfo.Name, TexIndex);
@@ -240,26 +240,28 @@ namespace Ryujinx.Graphics.Gpu
}
}
- private void UploadTexture(AMemory Memory, long BasePosition, int TexIndex, int HndIndex)
+ private void UploadTexture(NvGpuVmm Vmm, long BasePosition, int TexIndex, int HndIndex)
{
long Position = BasePosition + HndIndex * 4;
- int TextureHandle = Memory.ReadInt32(Position);
+ int TextureHandle = Vmm.ReadInt32(Position);
int TicIndex = (TextureHandle >> 0) & 0xfffff;
int TscIndex = (TextureHandle >> 20) & 0xfff;
- TryGetCpuAddr(NvGpuEngine3dReg.TexHeaderPoolOffset, out long TicPosition);
- TryGetCpuAddr(NvGpuEngine3dReg.TexSamplerPoolOffset, out long TscPosition);
+ long TicPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.TexHeaderPoolOffset);
+ long TscPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.TexSamplerPoolOffset);
TicPosition += TicIndex * 0x20;
TscPosition += TscIndex * 0x20;
- GalTextureSampler Sampler = TextureFactory.MakeSampler(Gpu, Memory, TscPosition);
+ GalTextureSampler Sampler = TextureFactory.MakeSampler(Gpu, Vmm, TscPosition);
- long TextureAddress = Memory.ReadInt64(TicPosition + 4) & 0xffffffffffff;
+ long TextureAddress = Vmm.ReadInt64(TicPosition + 4) & 0xffffffffffff;
- if (FrameBuffers.Contains(TextureAddress))
+ TextureAddress = Vmm.GetPhysicalAddress(TextureAddress);
+
+ if (IsFrameBufferPosition(TextureAddress))
{
//This texture is a frame buffer texture,
//we shouldn't read anything from memory and bind
@@ -269,14 +271,14 @@ namespace Ryujinx.Graphics.Gpu
}
else
{
- GalTexture Texture = TextureFactory.MakeTexture(Gpu, Memory, TicPosition);
+ GalTexture Texture = TextureFactory.MakeTexture(Gpu, Vmm, TicPosition);
Gpu.Renderer.SetTextureAndSampler(TexIndex, Texture, Sampler);
Gpu.Renderer.BindTexture(TexIndex);
}
}
- private void UploadUniforms(AMemory Memory)
+ private void UploadUniforms(NvGpuVmm Vmm)
{
long BasePosition = MakeInt64From2xInt32(NvGpuEngine3dReg.ShaderAddress);
@@ -295,13 +297,11 @@ namespace Ryujinx.Graphics.Gpu
for (int Cbuf = 0; Cbuf < ConstBuffers.Length; Cbuf++)
{
- ConstBuffer Cb = ConstBuffers[Cbuf];
+ ConstBuffer Cb = ConstBuffers[Index][Cbuf];
if (Cb.Enabled)
{
- long CbPosition = Cb.Position + Index * Cb.Size;
-
- byte[] Data = AMemoryHelper.ReadBytes(Memory, CbPosition, (uint)Cb.Size);
+ byte[] Data = Vmm.ReadBytes(Cb.Position, (uint)Cb.Size);
Gpu.Renderer.SetConstBuffer(BasePosition + (uint)Offset, Cbuf, Data);
}
@@ -309,7 +309,7 @@ namespace Ryujinx.Graphics.Gpu
}
}
- private void UploadVertexArrays(AMemory Memory)
+ private void UploadVertexArrays(NvGpuVmm Vmm)
{
long IndexPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.IndexArrayAddress);
@@ -328,11 +328,9 @@ namespace Ryujinx.Graphics.Gpu
if (IndexSize != 0)
{
- IndexPosition = Gpu.GetCpuAddr(IndexPosition);
-
int BufferSize = IndexCount * IndexSize;
- byte[] Data = AMemoryHelper.ReadBytes(Memory, IndexPosition, BufferSize);
+ byte[] Data = Vmm.ReadBytes(IndexPosition, BufferSize);
Gpu.Renderer.SetIndexArray(Data, IndexFormat);
}
@@ -382,7 +380,7 @@ namespace Ryujinx.Graphics.Gpu
if (IndexCount != 0)
{
Size = GetVertexCountFromIndexBuffer(
- Memory,
+ Vmm,
IndexPosition,
IndexCount,
IndexSize);
@@ -396,9 +394,7 @@ namespace Ryujinx.Graphics.Gpu
//In this case, we need to use the size of the attribute.
Size *= Stride;
- VertexPosition = Gpu.GetCpuAddr(VertexPosition);
-
- byte[] Data = AMemoryHelper.ReadBytes(Memory, VertexPosition, Size);
+ byte[] Data = Vmm.ReadBytes(VertexPosition, Size);
GalVertexAttrib[] AttribArray = Attribs[Index]?.ToArray() ?? new GalVertexAttrib[0];
@@ -420,10 +416,10 @@ namespace Ryujinx.Graphics.Gpu
}
private int GetVertexCountFromIndexBuffer(
- AMemory Memory,
- long IndexPosition,
- int IndexCount,
- int IndexSize)
+ NvGpuVmm Vmm,
+ long IndexPosition,
+ int IndexCount,
+ int IndexSize)
{
int MaxIndex = -1;
@@ -431,7 +427,7 @@ namespace Ryujinx.Graphics.Gpu
{
while (IndexCount -- > 0)
{
- ushort Value = Memory.ReadUInt16(IndexPosition);
+ ushort Value = Vmm.ReadUInt16(IndexPosition);
IndexPosition += 2;
@@ -445,7 +441,7 @@ namespace Ryujinx.Graphics.Gpu
{
while (IndexCount -- > 0)
{
- byte Value = Memory.ReadByte(IndexPosition++);
+ byte Value = Vmm.ReadByte(IndexPosition++);
if (MaxIndex < Value)
{
@@ -457,7 +453,7 @@ namespace Ryujinx.Graphics.Gpu
{
while (IndexCount -- > 0)
{
- uint Value = Memory.ReadUInt32(IndexPosition);
+ uint Value = Vmm.ReadUInt32(IndexPosition);
IndexPosition += 2;
@@ -475,75 +471,56 @@ namespace Ryujinx.Graphics.Gpu
return MaxIndex + 1;
}
- private void QueryControl(AMemory Memory, NsGpuPBEntry PBEntry)
+ private void QueryControl(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
{
- if (TryGetCpuAddr(NvGpuEngine3dReg.QueryAddress, out long Position))
- {
- int Seq = Registers[(int)NvGpuEngine3dReg.QuerySequence];
- int Ctrl = Registers[(int)NvGpuEngine3dReg.QueryControl];
+ long Position = MakeInt64From2xInt32(NvGpuEngine3dReg.QueryAddress);
- int Mode = Ctrl & 3;
+ int Seq = Registers[(int)NvGpuEngine3dReg.QuerySequence];
+ int Ctrl = Registers[(int)NvGpuEngine3dReg.QueryControl];
- if (Mode == 0)
- {
- //Write mode.
- Memory.WriteInt32(Position, Seq);
- }
+ int Mode = Ctrl & 3;
+
+ if (Mode == 0)
+ {
+ //Write mode.
+ Vmm.WriteInt32(Position, Seq);
}
WriteRegister(PBEntry);
}
- private void CbData(AMemory Memory, NsGpuPBEntry PBEntry)
+ private void CbData(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
{
- if (TryGetCpuAddr(NvGpuEngine3dReg.ConstBufferNAddress, out long Position))
- {
- int Offset = ReadRegister(NvGpuEngine3dReg.ConstBufferNOffset);
+ long Position = MakeInt64From2xInt32(NvGpuEngine3dReg.ConstBufferAddress);
- foreach (int Arg in PBEntry.Arguments)
- {
- Memory.WriteInt32(Position + Offset, Arg);
+ int Offset = ReadRegister(NvGpuEngine3dReg.ConstBufferOffset);
- Offset += 4;
- }
+ foreach (int Arg in PBEntry.Arguments)
+ {
+ Vmm.WriteInt32(Position + Offset, Arg);
- WriteRegister(NvGpuEngine3dReg.ConstBufferNOffset, Offset);
+ Offset += 4;
}
+
+ WriteRegister(NvGpuEngine3dReg.ConstBufferOffset, Offset);
}
- private void CbBind(AMemory Memory, NsGpuPBEntry PBEntry)
+ private void CbBind(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
{
+ int Stage = (PBEntry.Method - 0x904) >> 3;
+
int Index = PBEntry.Arguments[0];
bool Enabled = (Index & 1) != 0;
Index = (Index >> 4) & 0x1f;
- if (TryGetCpuAddr(NvGpuEngine3dReg.ConstBufferNAddress, out long Position))
- {
- ConstBuffers[Index].Position = Position;
- ConstBuffers[Index].Enabled = Enabled;
-
- ConstBuffers[Index].Size = ReadRegister(NvGpuEngine3dReg.ConstBufferNSize);
- }
- }
-
- private int ReadCb(AMemory Memory, int Cbuf, int Offset)
- {
- long Position = ConstBuffers[Cbuf].Position;
-
- int Value = Memory.ReadInt32(Position + Offset);
-
- return Value;
- }
-
- private bool TryGetCpuAddr(NvGpuEngine3dReg Reg, out long Position)
- {
- Position = MakeInt64From2xInt32(Reg);
+ long Position = MakeInt64From2xInt32(NvGpuEngine3dReg.ConstBufferAddress);
- Position = Gpu.GetCpuAddr(Position);
+ ConstBuffers[Stage][Index].Position = Position;
+ ConstBuffers[Stage][Index].Enabled = Enabled;
- return Position != -1;
+ ConstBuffers[Stage][Index].Size = ReadRegister(NvGpuEngine3dReg.ConstBufferSize);
}
private long MakeInt64From2xInt32(NvGpuEngine3dReg Reg)
@@ -553,7 +530,7 @@ namespace Ryujinx.Graphics.Gpu
(uint)Registers[(int)Reg + 1];
}
- private void WriteRegister(NsGpuPBEntry PBEntry)
+ private void WriteRegister(NvGpuPBEntry PBEntry)
{
int ArgsCount = PBEntry.Arguments.Count;
diff --git a/Ryujinx.Graphics/Gpu/NvGpuEngine3dReg.cs b/Ryujinx.Core/Gpu/NvGpuEngine3dReg.cs
index 0d995619..823885ff 100644
--- a/Ryujinx.Graphics/Gpu/NvGpuEngine3dReg.cs
+++ b/Ryujinx.Core/Gpu/NvGpuEngine3dReg.cs
@@ -1,4 +1,4 @@
-namespace Ryujinx.Graphics.Gpu
+namespace Ryujinx.Core.Gpu
{
enum NvGpuEngine3dReg
{
@@ -53,9 +53,9 @@ namespace Ryujinx.Graphics.Gpu
ShaderNOffset = 0x801,
ShaderNMaxGprs = 0x803,
ShaderNType = 0x804,
- ConstBufferNSize = 0x8e0,
- ConstBufferNAddress = 0x8e1,
- ConstBufferNOffset = 0x8e3,
+ ConstBufferSize = 0x8e0,
+ ConstBufferAddress = 0x8e1,
+ ConstBufferOffset = 0x8e3,
TextureCbIndex = 0x982
}
} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Gpu/NvGpuFifo.cs b/Ryujinx.Core/Gpu/NvGpuFifo.cs
index 68c2902a..d0e6fc14 100644
--- a/Ryujinx.Graphics/Gpu/NvGpuFifo.cs
+++ b/Ryujinx.Core/Gpu/NvGpuFifo.cs
@@ -1,16 +1,15 @@
-using ChocolArm64.Memory;
using System.Collections.Concurrent;
-namespace Ryujinx.Graphics.Gpu
+namespace Ryujinx.Core.Gpu
{
public class NvGpuFifo
{
private const int MacrosCount = 0x80;
private const int MacroIndexMask = MacrosCount - 1;
- private NsGpu Gpu;
+ private NvGpu Gpu;
- private ConcurrentQueue<(AMemory, NsGpuPBEntry)> BufferQueue;
+ private ConcurrentQueue<(NvGpuVmm, NvGpuPBEntry)> BufferQueue;
private NvGpuEngine[] SubChannels;
@@ -32,9 +31,9 @@ namespace Ryujinx.Graphics.Gpu
Interpreter?.Fifo.Enqueue(Param);
}
- public void Execute(AMemory Memory, int Param)
+ public void Execute(NvGpuVmm Vmm, int Param)
{
- Interpreter?.Execute(Memory, Position, Param);
+ Interpreter?.Execute(Vmm, Position, Param);
}
}
@@ -43,22 +42,22 @@ namespace Ryujinx.Graphics.Gpu
private CachedMacro[] Macros;
- public NvGpuFifo(NsGpu Gpu)
+ public NvGpuFifo(NvGpu Gpu)
{
this.Gpu = Gpu;
- BufferQueue = new ConcurrentQueue<(AMemory, NsGpuPBEntry)>();
+ BufferQueue = new ConcurrentQueue<(NvGpuVmm, NvGpuPBEntry)>();
SubChannels = new NvGpuEngine[8];
Macros = new CachedMacro[MacrosCount];
}
- public void PushBuffer(AMemory Memory, NsGpuPBEntry[] Buffer)
+ public void PushBuffer(NvGpuVmm Vmm, NvGpuPBEntry[] Buffer)
{
- foreach (NsGpuPBEntry PBEntry in Buffer)
+ foreach (NvGpuPBEntry PBEntry in Buffer)
{
- BufferQueue.Enqueue((Memory, PBEntry));
+ BufferQueue.Enqueue((Vmm, PBEntry));
}
}
@@ -69,9 +68,9 @@ namespace Ryujinx.Graphics.Gpu
public bool Step()
{
- if (BufferQueue.TryDequeue(out (AMemory Memory, NsGpuPBEntry PBEntry) Tuple))
+ if (BufferQueue.TryDequeue(out (NvGpuVmm Vmm, NvGpuPBEntry PBEntry) Tuple))
{
- CallMethod(Tuple.Memory, Tuple.PBEntry);
+ CallMethod(Tuple.Vmm, Tuple.PBEntry);
return true;
}
@@ -79,7 +78,7 @@ namespace Ryujinx.Graphics.Gpu
return false;
}
- private void CallMethod(AMemory Memory, NsGpuPBEntry PBEntry)
+ private void CallMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
{
if (PBEntry.Method < 0x80)
{
@@ -103,11 +102,11 @@ namespace Ryujinx.Graphics.Gpu
case NvGpuFifoMeth.SendMacroCodeData:
{
- long Position = Gpu.GetCpuAddr(CurrMacroPosition);
+ long Position = CurrMacroPosition;
foreach (int Arg in PBEntry.Arguments)
{
- Memory.WriteInt32(Position, Arg);
+ Vmm.WriteInt32(Position, Arg);
CurrMacroPosition += 4;
@@ -127,8 +126,6 @@ namespace Ryujinx.Graphics.Gpu
{
long Position = (long)((ulong)PBEntry.Arguments[0] << 2);
- Position = Gpu.GetCpuAddr(Position);
-
Macros[CurrMacroBindIndex] = new CachedMacro(this, Gpu.Engine3d, Position);
break;
@@ -139,22 +136,22 @@ namespace Ryujinx.Graphics.Gpu
{
switch (SubChannels[PBEntry.SubChannel])
{
- case NvGpuEngine._2d: Call2dMethod(Memory, PBEntry); break;
- case NvGpuEngine._3d: Call3dMethod(Memory, PBEntry); break;
+ case NvGpuEngine._2d: Call2dMethod(Vmm, PBEntry); break;
+ case NvGpuEngine._3d: Call3dMethod(Vmm, PBEntry); break;
}
}
}
- private void Call2dMethod(AMemory Memory, NsGpuPBEntry PBEntry)
+ private void Call2dMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
{
- Gpu.Engine2d.CallMethod(Memory, PBEntry);
+ Gpu.Engine2d.CallMethod(Vmm, PBEntry);
}
- private void Call3dMethod(AMemory Memory, NsGpuPBEntry PBEntry)
+ private void Call3dMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
{
if (PBEntry.Method < 0xe00)
{
- Gpu.Engine3d.CallMethod(Memory, PBEntry);
+ Gpu.Engine3d.CallMethod(Vmm, PBEntry);
}
else
{
@@ -169,7 +166,7 @@ namespace Ryujinx.Graphics.Gpu
}
else
{
- Macros[MacroIndex].Execute(Memory, PBEntry.Arguments[0]);
+ Macros[MacroIndex].Execute(Vmm, PBEntry.Arguments[0]);
}
}
}
diff --git a/Ryujinx.Graphics/Gpu/NvGpuFifoMeth.cs b/Ryujinx.Core/Gpu/NvGpuFifoMeth.cs
index 4287e250..78ec9080 100644
--- a/Ryujinx.Graphics/Gpu/NvGpuFifoMeth.cs
+++ b/Ryujinx.Core/Gpu/NvGpuFifoMeth.cs
@@ -1,4 +1,4 @@
-namespace Ryujinx.Graphics.Gpu
+namespace Ryujinx.Core.Gpu
{
enum NvGpuFifoMeth
{
diff --git a/Ryujinx.Core/Gpu/NvGpuMethod.cs b/Ryujinx.Core/Gpu/NvGpuMethod.cs
new file mode 100644
index 00000000..42e1b553
--- /dev/null
+++ b/Ryujinx.Core/Gpu/NvGpuMethod.cs
@@ -0,0 +1,4 @@
+namespace Ryujinx.Core.Gpu
+{
+ delegate void NvGpuMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry);
+} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Gpu/NsGpuPBEntry.cs b/Ryujinx.Core/Gpu/NvGpuPBEntry.cs
index d405a93c..ebf35b9e 100644
--- a/Ryujinx.Graphics/Gpu/NsGpuPBEntry.cs
+++ b/Ryujinx.Core/Gpu/NvGpuPBEntry.cs
@@ -1,9 +1,9 @@
using System;
using System.Collections.ObjectModel;
-namespace Ryujinx.Graphics.Gpu
+namespace Ryujinx.Core.Gpu
{
- public struct NsGpuPBEntry
+ public struct NvGpuPBEntry
{
public int Method { get; private set; }
@@ -13,7 +13,7 @@ namespace Ryujinx.Graphics.Gpu
public ReadOnlyCollection<int> Arguments => Array.AsReadOnly(m_Arguments);
- public NsGpuPBEntry(int Method, int SubChannel, params int[] Arguments)
+ public NvGpuPBEntry(int Method, int SubChannel, params int[] Arguments)
{
this.Method = Method;
this.SubChannel = SubChannel;
diff --git a/Ryujinx.Graphics/Gpu/NvGpuPushBuffer.cs b/Ryujinx.Core/Gpu/NvGpuPushBuffer.cs
index 8cbb3288..d5588655 100644
--- a/Ryujinx.Graphics/Gpu/NvGpuPushBuffer.cs
+++ b/Ryujinx.Core/Gpu/NvGpuPushBuffer.cs
@@ -1,7 +1,7 @@
using System.Collections.Generic;
using System.IO;
-namespace Ryujinx.Graphics.Gpu
+namespace Ryujinx.Core.Gpu
{
public static class NvGpuPushBuffer
{
@@ -13,13 +13,13 @@ namespace Ryujinx.Graphics.Gpu
IncrementOnce = 5
}
- public static NsGpuPBEntry[] Decode(byte[] Data)
+ public static NvGpuPBEntry[] Decode(byte[] Data)
{
using (MemoryStream MS = new MemoryStream(Data))
{
BinaryReader Reader = new BinaryReader(MS);
- List<NsGpuPBEntry> PushBuffer = new List<NsGpuPBEntry>();
+ List<NvGpuPBEntry> PushBuffer = new List<NvGpuPBEntry>();
bool CanRead() => MS.Position + 4 <= MS.Length;
@@ -38,7 +38,7 @@ namespace Ryujinx.Graphics.Gpu
{
for (int Index = 0; Index < Args && CanRead(); Index++, Meth++)
{
- PushBuffer.Add(new NsGpuPBEntry(Meth, SubC, Reader.ReadInt32()));
+ PushBuffer.Add(new NvGpuPBEntry(Meth, SubC, Reader.ReadInt32()));
}
break;
@@ -58,14 +58,14 @@ namespace Ryujinx.Graphics.Gpu
Arguments[Index] = Reader.ReadInt32();
}
- PushBuffer.Add(new NsGpuPBEntry(Meth, SubC, Arguments));
+ PushBuffer.Add(new NvGpuPBEntry(Meth, SubC, Arguments));
break;
}
case SubmissionMode.Immediate:
{
- PushBuffer.Add(new NsGpuPBEntry(Meth, SubC, Args));
+ PushBuffer.Add(new NvGpuPBEntry(Meth, SubC, Args));
break;
}
@@ -74,9 +74,9 @@ namespace Ryujinx.Graphics.Gpu
{
if (CanRead())
{
- PushBuffer.Add(new NsGpuPBEntry(Meth, SubC, Reader.ReadInt32()));
+ PushBuffer.Add(new NvGpuPBEntry(Meth, SubC, Reader.ReadInt32()));
}
-
+
if (CanRead() && Args > 1)
{
int[] Arguments = new int[Args - 1];
@@ -86,7 +86,7 @@ namespace Ryujinx.Graphics.Gpu
Arguments[Index] = Reader.ReadInt32();
}
- PushBuffer.Add(new NsGpuPBEntry(Meth + 1, SubC, Arguments));
+ PushBuffer.Add(new NvGpuPBEntry(Meth + 1, SubC, Arguments));
}
break;
diff --git a/Ryujinx.Core/Gpu/NvGpuVmm.cs b/Ryujinx.Core/Gpu/NvGpuVmm.cs
new file mode 100644
index 00000000..cf94a6c0
--- /dev/null
+++ b/Ryujinx.Core/Gpu/NvGpuVmm.cs
@@ -0,0 +1,398 @@
+using ChocolArm64.Memory;
+using System.Collections.Concurrent;
+
+namespace Ryujinx.Core.Gpu
+{
+ public class NvGpuVmm : IAMemory
+ {
+ public const long AddrSize = 1L << 40;
+
+ private const int PTLvl0Bits = 14;
+ private const int PTLvl1Bits = 14;
+ private const int PTPageBits = 12;
+
+ private const int PTLvl0Size = 1 << PTLvl0Bits;
+ private const int PTLvl1Size = 1 << PTLvl1Bits;
+ public const int PageSize = 1 << PTPageBits;
+
+ private const int PTLvl0Mask = PTLvl0Size - 1;
+ private const int PTLvl1Mask = PTLvl1Size - 1;
+ public const int PageMask = PageSize - 1;
+
+ 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;
+
+ public NvGpuVmm(AMemory Memory)
+ {
+ this.Memory = Memory;
+
+ Maps = new ConcurrentDictionary<long, MappedMemory>();
+
+ PageTable = new long[PTLvl0Size][];
+ }
+
+ public long Map(long PA, long VA, long Size)
+ {
+ lock (PageTable)
+ {
+ for (long Offset = 0; Offset < Size; Offset += PageSize)
+ {
+ if (GetPte(VA + Offset) != PteReserved)
+ {
+ return Map(PA, Size);
+ }
+ }
+
+ for (long Offset = 0; Offset < Size; Offset += PageSize)
+ {
+ SetPte(VA + Offset, PA + Offset);
+ }
+ }
+
+ return VA;
+ }
+
+ public long Map(long PA, long Size)
+ {
+ lock (PageTable)
+ {
+ long VA = GetFreePosition(Size);
+
+ if (VA != -1)
+ {
+ MappedMemory Map = new MappedMemory(Size);
+
+ Maps.AddOrUpdate(VA, Map, (Key, Old) => Map);
+
+ for (long Offset = 0; Offset < Size; Offset += PageSize)
+ {
+ SetPte(VA + Offset, PA + Offset);
+ }
+ }
+
+ 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)
+ {
+ for (long Offset = 0; Offset < Size; Offset += PageSize)
+ {
+ if (IsPageInUse(VA + Offset))
+ {
+ return Reserve(Size, Align);
+ }
+ }
+
+ for (long Offset = 0; Offset < Size; Offset += PageSize)
+ {
+ SetPte(VA + Offset, PteReserved);
+ }
+ }
+
+ return VA;
+ }
+
+ public long Reserve(long Size, long Align)
+ {
+ lock (PageTable)
+ {
+ long Position = GetFreePosition(Size, Align);
+
+ if (Position != -1)
+ {
+ for (long Offset = 0; Offset < Size; Offset += PageSize)
+ {
+ SetPte(Position + Offset, PteReserved);
+ }
+ }
+
+ return Position;
+ }
+ }
+
+ public void Free(long VA, long Size)
+ {
+ lock (PageTable)
+ {
+ for (long Offset = 0; Offset < Size; Offset += PageSize)
+ {
+ SetPte(VA + Offset, PteUnmapped);
+ }
+ }
+ }
+
+ private long GetFreePosition(long Size, long Align = 1)
+ {
+ long Position = 0;
+ long FreeSize = 0;
+
+ if (Align < 1)
+ {
+ Align = 1;
+ }
+
+ Align = (Align + PageMask) & ~PageMask;
+
+ while (Position + FreeSize < AddrSize)
+ {
+ if (!IsPageInUse(Position + FreeSize))
+ {
+ FreeSize += PageSize;
+
+ if (FreeSize >= Size)
+ {
+ return Position;
+ }
+ }
+ else
+ {
+ Position += FreeSize + PageSize;
+ FreeSize = 0;
+
+ long Remainder = Position % Align;
+
+ if (Remainder != 0)
+ {
+ Position = (Position - Remainder) + Align;
+ }
+ }
+ }
+
+ return -1;
+ }
+
+ public long GetPhysicalAddress(long VA)
+ {
+ long BasePos = GetPte(VA);
+
+ if (BasePos < 0)
+ {
+ return -1;
+ }
+
+ return BasePos + (VA & PageMask);
+ }
+
+ public bool IsRegionFree(long VA, long Size)
+ {
+ for (long Offset = 0; Offset < Size; Offset += PageSize)
+ {
+ if (IsPageInUse(VA + Offset))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private bool IsPageInUse(long VA)
+ {
+ if (VA >> PTLvl0Bits + PTLvl1Bits + PTPageBits != 0)
+ {
+ return false;
+ }
+
+ long L0 = (VA >> PTLvl0Bit) & PTLvl0Mask;
+ long L1 = (VA >> PTLvl1Bit) & PTLvl1Mask;
+
+ if (PageTable[L0] == null)
+ {
+ return false;
+ }
+
+ return PageTable[L0][L1] != PteUnmapped;
+ }
+
+ private long GetPte(long Position)
+ {
+ long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask;
+ long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask;
+
+ if (PageTable[L0] == null)
+ {
+ return -1;
+ }
+
+ return PageTable[L0][L1];
+ }
+
+ private void SetPte(long Position, long TgtAddr)
+ {
+ long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask;
+ long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask;
+
+ if (PageTable[L0] == null)
+ {
+ PageTable[L0] = new long[PTLvl1Size];
+
+ for (int Index = 0; Index < PTLvl1Size; Index++)
+ {
+ PageTable[L0][Index] = PteUnmapped;
+ }
+ }
+
+ PageTable[L0][L1] = TgtAddr;
+ }
+
+ public byte ReadByte(long Position)
+ {
+ Position = GetPhysicalAddress(Position);
+
+ return Memory.ReadByte(Position);
+ }
+
+ public ushort ReadUInt16(long Position)
+ {
+ Position = GetPhysicalAddress(Position);
+
+ return Memory.ReadUInt16(Position);
+ }
+
+ public uint ReadUInt32(long Position)
+ {
+ Position = GetPhysicalAddress(Position);
+
+ return Memory.ReadUInt32(Position);
+ }
+
+ public ulong ReadUInt64(long Position)
+ {
+ Position = GetPhysicalAddress(Position);
+
+ return Memory.ReadUInt64(Position);
+ }
+
+ public sbyte ReadSByte(long Position)
+ {
+ Position = GetPhysicalAddress(Position);
+
+ return Memory.ReadSByte(Position);
+ }
+
+ public short ReadInt16(long Position)
+ {
+ Position = GetPhysicalAddress(Position);
+
+ return Memory.ReadInt16(Position);
+ }
+
+ public int ReadInt32(long Position)
+ {
+ Position = GetPhysicalAddress(Position);
+
+ return Memory.ReadInt32(Position);
+ }
+
+ public long ReadInt64(long Position)
+ {
+ Position = GetPhysicalAddress(Position);
+
+ return Memory.ReadInt64(Position);
+ }
+
+ public byte[] ReadBytes(long Position, long Size)
+ {
+ Position = GetPhysicalAddress(Position);
+
+ return AMemoryHelper.ReadBytes(Memory, Position, Size);
+ }
+
+ public void WriteByte(long Position, byte Value)
+ {
+ Position = GetPhysicalAddress(Position);
+
+ Memory.WriteByte(Position, Value);
+ }
+
+ public void WriteUInt16(long Position, ushort Value)
+ {
+ Position = GetPhysicalAddress(Position);
+
+ Memory.WriteUInt16(Position, Value);
+ }
+
+ public void WriteUInt32(long Position, uint Value)
+ {
+ Position = GetPhysicalAddress(Position);
+
+ Memory.WriteUInt32(Position, Value);
+ }
+
+ public void WriteUInt64(long Position, ulong Value)
+ {
+ Position = GetPhysicalAddress(Position);
+
+ Memory.WriteUInt64(Position, Value);
+ }
+
+ public void WriteSByte(long Position, sbyte Value)
+ {
+ Position = GetPhysicalAddress(Position);
+
+ Memory.WriteSByte(Position, Value);
+ }
+
+ public void WriteInt16(long Position, short Value)
+ {
+ Position = GetPhysicalAddress(Position);
+
+ Memory.WriteInt16(Position, Value);
+ }
+
+ public void WriteInt32(long Position, int Value)
+ {
+ Position = GetPhysicalAddress(Position);
+
+ Memory.WriteInt32(Position, Value);
+ }
+
+ public void WriteInt64(long Position, long Value)
+ {
+ Position = GetPhysicalAddress(Position);
+
+ Memory.WriteInt64(Position, Value);
+ }
+
+ public void WriteBytes(long Position, byte[] Data)
+ {
+ Position = GetPhysicalAddress(Position);
+
+ AMemoryHelper.WriteBytes(Memory, Position, Data);
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Gpu/Texture.cs b/Ryujinx.Core/Gpu/Texture.cs
index cbfa683d..39a35059 100644
--- a/Ryujinx.Graphics/Gpu/Texture.cs
+++ b/Ryujinx.Core/Gpu/Texture.cs
@@ -1,6 +1,6 @@
using Ryujinx.Graphics.Gal;
-namespace Ryujinx.Graphics.Gpu
+namespace Ryujinx.Core.Gpu
{
public struct Texture
{
diff --git a/Ryujinx.Graphics/Gpu/TextureFactory.cs b/Ryujinx.Core/Gpu/TextureFactory.cs
index 7f8580d9..68b48a1f 100644
--- a/Ryujinx.Graphics/Gpu/TextureFactory.cs
+++ b/Ryujinx.Core/Gpu/TextureFactory.cs
@@ -1,14 +1,13 @@
-using ChocolArm64.Memory;
using Ryujinx.Graphics.Gal;
using System;
-namespace Ryujinx.Graphics.Gpu
+namespace Ryujinx.Core.Gpu
{
static class TextureFactory
{
- public static GalTexture MakeTexture(NsGpu Gpu, AMemory Memory, long TicPosition)
+ public static GalTexture MakeTexture(NvGpu Gpu, NvGpuVmm Vmm, long TicPosition)
{
- int[] Tic = ReadWords(Memory, TicPosition, 8);
+ int[] Tic = ReadWords(Vmm, TicPosition, 8);
GalTextureFormat Format = (GalTextureFormat)(Tic[0] & 0x7f);
@@ -16,8 +15,6 @@ namespace Ryujinx.Graphics.Gpu
TextureAddress |= (long)((ushort)Tic[2]) << 32;
- TextureAddress = Gpu.GetCpuAddr(TextureAddress);
-
TextureSwizzle Swizzle = (TextureSwizzle)((Tic[2] >> 21) & 7);
int Pitch = (Tic[3] & 0xffff) << 5;
@@ -38,14 +35,14 @@ namespace Ryujinx.Graphics.Gpu
Swizzle,
Format);
- byte[] Data = TextureReader.Read(Memory, Texture);
+ byte[] Data = TextureReader.Read(Vmm, Texture);
return new GalTexture(Data, Width, Height, Format);
}
- public static GalTextureSampler MakeSampler(NsGpu Gpu, AMemory Memory, long TscPosition)
+ public static GalTextureSampler MakeSampler(NvGpu Gpu, NvGpuVmm Vmm, long TscPosition)
{
- int[] Tsc = ReadWords(Memory, TscPosition, 8);
+ int[] Tsc = ReadWords(Vmm, TscPosition, 8);
GalTextureWrap AddressU = (GalTextureWrap)((Tsc[0] >> 0) & 7);
GalTextureWrap AddressV = (GalTextureWrap)((Tsc[0] >> 3) & 7);
@@ -71,13 +68,13 @@ namespace Ryujinx.Graphics.Gpu
BorderColor);
}
- private static int[] ReadWords(AMemory Memory, long Position, int Count)
+ private static int[] ReadWords(NvGpuVmm Vmm, long Position, int Count)
{
int[] Words = new int[Count];
for (int Index = 0; Index < Count; Index++, Position += 4)
{
- Words[Index] = Memory.ReadInt32(Position);
+ Words[Index] = Vmm.ReadInt32(Position);
}
return Words;
diff --git a/Ryujinx.Graphics/Gpu/TextureHelper.cs b/Ryujinx.Core/Gpu/TextureHelper.cs
index d3c2ac14..f0ebc1f0 100644
--- a/Ryujinx.Graphics/Gpu/TextureHelper.cs
+++ b/Ryujinx.Core/Gpu/TextureHelper.cs
@@ -1,6 +1,7 @@
+using ChocolArm64.Memory;
using System;
-namespace Ryujinx.Graphics.Gpu
+namespace Ryujinx.Core.Gpu
{
static class TextureHelper
{
@@ -19,5 +20,17 @@ namespace Ryujinx.Graphics.Gpu
throw new NotImplementedException(Texture.Swizzle.ToString());
}
+
+ public static (AMemory Memory, long Position) GetMemoryAndPosition(
+ IAMemory Memory,
+ long Position)
+ {
+ if (Memory is NvGpuVmm Vmm)
+ {
+ return (Vmm.Memory, Vmm.GetPhysicalAddress(Position));
+ }
+
+ return ((AMemory)Memory, Position);
+ }
}
}
diff --git a/Ryujinx.Graphics/Gpu/TextureReader.cs b/Ryujinx.Core/Gpu/TextureReader.cs
index 17fd95c5..f3e41046 100644
--- a/Ryujinx.Graphics/Gpu/TextureReader.cs
+++ b/Ryujinx.Core/Gpu/TextureReader.cs
@@ -2,11 +2,11 @@ using ChocolArm64.Memory;
using Ryujinx.Graphics.Gal;
using System;
-namespace Ryujinx.Graphics.Gpu
+namespace Ryujinx.Core.Gpu
{
public static class TextureReader
{
- public static byte[] Read(AMemory Memory, Texture Texture)
+ public static byte[] Read(IAMemory Memory, Texture Texture)
{
switch (Texture.Format)
{
@@ -23,7 +23,7 @@ namespace Ryujinx.Graphics.Gpu
throw new NotImplementedException(Texture.Format.ToString());
}
- private unsafe static byte[] Read2Bpp(AMemory Memory, Texture Texture)
+ private unsafe static byte[] Read2Bpp(IAMemory Memory, Texture Texture)
{
int Width = Texture.Width;
int Height = Texture.Height;
@@ -32,6 +32,10 @@ namespace Ryujinx.Graphics.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.Graphics.Gpu
{
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
- short Pixel = Memory.ReadInt16Unchecked(Texture.Position + Offset);
+ short Pixel = CpuMem.ReadInt16Unchecked(Position + Offset);
*(short*)(BuffPtr + OutOffs) = Pixel;
@@ -52,7 +56,7 @@ namespace Ryujinx.Graphics.Gpu
return Output;
}
- private unsafe static byte[] Read4Bpp(AMemory Memory, Texture Texture)
+ private unsafe static byte[] Read4Bpp(IAMemory Memory, Texture Texture)
{
int Width = Texture.Width;
int Height = Texture.Height;
@@ -61,6 +65,10 @@ namespace Ryujinx.Graphics.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.Graphics.Gpu
{
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
- int Pixel = Memory.ReadInt32Unchecked(Texture.Position + Offset);
+ int Pixel = CpuMem.ReadInt32Unchecked(Position + Offset);
*(int*)(BuffPtr + OutOffs) = Pixel;
@@ -81,7 +89,7 @@ namespace Ryujinx.Graphics.Gpu
return Output;
}
- private unsafe static byte[] Read8Bpt4x4(AMemory Memory, Texture Texture)
+ private unsafe static byte[] Read8Bpt4x4(IAMemory Memory, Texture Texture)
{
int Width = (Texture.Width + 3) / 4;
int Height = (Texture.Height + 3) / 4;
@@ -90,6 +98,10 @@ namespace Ryujinx.Graphics.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.Graphics.Gpu
{
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
- long Tile = Memory.ReadInt64Unchecked(Texture.Position + Offset);
+ long Tile = CpuMem.ReadInt64Unchecked(Position + Offset);
*(long*)(BuffPtr + OutOffs) = Tile;
@@ -110,7 +122,7 @@ namespace Ryujinx.Graphics.Gpu
return Output;
}
- private unsafe static byte[] Read16Bpt4x4(AMemory Memory, Texture Texture)
+ private unsafe static byte[] Read16Bpt4x4(IAMemory Memory, Texture Texture)
{
int Width = (Texture.Width + 3) / 4;
int Height = (Texture.Height + 3) / 4;
@@ -119,6 +131,10 @@ namespace Ryujinx.Graphics.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.Graphics.Gpu
{
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
- long Tile0 = Memory.ReadInt64Unchecked(Texture.Position + Offset + 0);
- long Tile1 = Memory.ReadInt64Unchecked(Texture.Position + Offset + 8);
+ long Tile0 = CpuMem.ReadInt64Unchecked(Position + Offset + 0);
+ long Tile1 = CpuMem.ReadInt64Unchecked(Position + Offset + 8);
*(long*)(BuffPtr + OutOffs + 0) = Tile0;
*(long*)(BuffPtr + OutOffs + 8) = Tile1;
diff --git a/Ryujinx.Graphics/Gpu/TextureSwizzle.cs b/Ryujinx.Core/Gpu/TextureSwizzle.cs
index 7d99279c..3214f45f 100644
--- a/Ryujinx.Graphics/Gpu/TextureSwizzle.cs
+++ b/Ryujinx.Core/Gpu/TextureSwizzle.cs
@@ -1,4 +1,4 @@
-namespace Ryujinx.Graphics.Gpu
+namespace Ryujinx.Core.Gpu
{
public enum TextureSwizzle
{
diff --git a/Ryujinx.Graphics/Gpu/TextureWriter.cs b/Ryujinx.Core/Gpu/TextureWriter.cs
index 2f25de73..125bb8c4 100644
--- a/Ryujinx.Graphics/Gpu/TextureWriter.cs
+++ b/Ryujinx.Core/Gpu/TextureWriter.cs
@@ -2,28 +2,31 @@ using ChocolArm64.Memory;
using Ryujinx.Graphics.Gal;
using System;
-namespace Ryujinx.Graphics.Gpu
+namespace Ryujinx.Core.Gpu
{
public static class TextureWriter
{
- public static void Write(AMemory Memory, Texture Texture, byte[] Data)
+ public static void Write(IAMemory Memory, Texture Texture, byte[] Data)
{
switch (Texture.Format)
{
case GalTextureFormat.A8B8G8R8: Write4Bpp(Memory, Texture, Data); break;
- default:
- throw new NotImplementedException(Texture.Format.ToString());
+ default: throw new NotImplementedException(Texture.Format.ToString());
}
}
- private unsafe static void Write4Bpp(AMemory Memory, Texture Texture, byte[] Data)
+ private unsafe static void Write4Bpp(IAMemory Memory, Texture Texture, byte[] Data)
{
int Width = Texture.Width;
int Height = Texture.Height;
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.Graphics.Gpu
int Pixel = *(int*)(BuffPtr + InOffs);
- Memory.WriteInt32Unchecked(Texture.Position + Offset, Pixel);
+ CpuMem.WriteInt32Unchecked(Position + Offset, Pixel);
InOffs += 4;
}
diff --git a/Ryujinx.Core/Loaders/Executable.cs b/Ryujinx.Core/Loaders/Executable.cs
index 39ee9618..ab7e1979 100644
--- a/Ryujinx.Core/Loaders/Executable.cs
+++ b/Ryujinx.Core/Loaders/Executable.cs
@@ -32,9 +32,9 @@ namespace Ryujinx.Core.Loaders
this.ImageBase = ImageBase;
this.ImageEnd = ImageBase;
- WriteData(ImageBase + Exe.TextOffset, Exe.Text, MemoryType.CodeStatic, AMemoryPerm.RX);
- WriteData(ImageBase + Exe.ROOffset, Exe.RO, MemoryType.Normal, AMemoryPerm.Read);
- WriteData(ImageBase + Exe.DataOffset, Exe.Data, MemoryType.Normal, AMemoryPerm.RW);
+ WriteData(ImageBase + Exe.TextOffset, Exe.Text, MemoryType.CodeStatic, AMemoryPerm.RX);
+ WriteData(ImageBase + Exe.ROOffset, Exe.RO, MemoryType.CodeMutable, AMemoryPerm.Read);
+ WriteData(ImageBase + Exe.DataOffset, Exe.Data, MemoryType.CodeMutable, AMemoryPerm.RW);
if (Exe.Mod0Offset == 0)
{
diff --git a/Ryujinx.Core/OsHle/Horizon.cs b/Ryujinx.Core/OsHle/Horizon.cs
index 0cc3d815..1d4098c7 100644
--- a/Ryujinx.Core/OsHle/Horizon.cs
+++ b/Ryujinx.Core/OsHle/Horizon.cs
@@ -20,6 +20,8 @@ namespace Ryujinx.Core.OsHle
public SystemStateMgr SystemState { get; private set; }
+ internal MemoryAllocator Allocator { get; private set; }
+
internal HSharedMem HidSharedMem { get; private set; }
internal HSharedMem FontSharedMem { get; private set; }
@@ -35,6 +37,8 @@ namespace Ryujinx.Core.OsHle
SystemState = new SystemStateMgr();
+ Allocator = new MemoryAllocator();
+
HidSharedMem = new HSharedMem();
FontSharedMem = new HSharedMem();
diff --git a/Ryujinx.Core/OsHle/Ipc/IpcHandler.cs b/Ryujinx.Core/OsHle/Ipc/IpcHandler.cs
index 42322d41..420890eb 100644
--- a/Ryujinx.Core/OsHle/Ipc/IpcHandler.cs
+++ b/Ryujinx.Core/OsHle/Ipc/IpcHandler.cs
@@ -7,7 +7,7 @@ namespace Ryujinx.Core.OsHle.Ipc
{
static class IpcHandler
{
- public static void IpcCall(
+ public static long IpcCall(
Switch Ns,
Process Process,
AMemory Memory,
@@ -94,6 +94,8 @@ namespace Ryujinx.Core.OsHle.Ipc
AMemoryHelper.WriteBytes(Memory, CmdPtr, Response.GetBytes(CmdPtr));
}
+
+ return 0;
}
private static IpcMessage FillResponse(IpcMessage Response, long Result, params int[] Values)
diff --git a/Ryujinx.Core/OsHle/Ipc/IpcMessage.cs b/Ryujinx.Core/OsHle/Ipc/IpcMessage.cs
index d81f44bd..afcbb3a4 100644
--- a/Ryujinx.Core/OsHle/Ipc/IpcMessage.cs
+++ b/Ryujinx.Core/OsHle/Ipc/IpcMessage.cs
@@ -174,31 +174,6 @@ namespace Ryujinx.Core.OsHle.Ipc
return 0;
}
- public long GetSendBuffPtr()
- {
- if (SendBuff.Count > 0 && SendBuff[0].Size != 0)
- {
- return SendBuff[0].Position;
- }
-
- if (PtrBuff.Count > 0 && PtrBuff[0].Size != 0)
- {
- return PtrBuff[0].Position;
- }
-
- if (ReceiveBuff.Count > 0 && ReceiveBuff[0].Size != 0)
- {
- return ReceiveBuff[0].Position;
- }
-
- if (RecvListBuff.Count > 0 && RecvListBuff[0].Size != 0)
- {
- return RecvListBuff[0].Position;
- }
-
- return -1;
- }
-
public long GetBufferType0x21Position()
{
if (PtrBuff.Count > 0 && PtrBuff[0].Position != 0)
diff --git a/Ryujinx.Core/OsHle/Kernel/KernelErr.cs b/Ryujinx.Core/OsHle/Kernel/KernelErr.cs
index b568405b..87f9cf3b 100644
--- a/Ryujinx.Core/OsHle/Kernel/KernelErr.cs
+++ b/Ryujinx.Core/OsHle/Kernel/KernelErr.cs
@@ -7,6 +7,8 @@ namespace Ryujinx.Core.OsHle.Kernel
public const int InvalidMemRange = 110;
public const int InvalidHandle = 114;
public const int Timeout = 117;
+ public const int Canceled = 118;
+ public const int CountOutOfRange = 119;
public const int InvalidInfo = 120;
}
} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Kernel/SvcHandler.cs b/Ryujinx.Core/OsHle/Kernel/SvcHandler.cs
index e855b77d..1874360b 100644
--- a/Ryujinx.Core/OsHle/Kernel/SvcHandler.cs
+++ b/Ryujinx.Core/OsHle/Kernel/SvcHandler.cs
@@ -5,6 +5,8 @@ using Ryujinx.Core.Logging;
using Ryujinx.Core.OsHle.Handles;
using System;
using System.Collections.Generic;
+using System.Collections.Concurrent;
+using System.Threading;
namespace Ryujinx.Core.OsHle.Kernel
{
@@ -18,12 +20,16 @@ namespace Ryujinx.Core.OsHle.Kernel
private Process Process;
private AMemory Memory;
+ private ConcurrentDictionary<KThread, AutoResetEvent> SyncWaits;
+
private object CondVarLock;
private HashSet<(HSharedMem, long)> MappedSharedMems;
private ulong CurrentHeapSize;
+ private const uint SelfHandle = 0xffff8001;
+
private static Random Rng;
public SvcHandler(Switch Ns, Process Process)
@@ -51,6 +57,7 @@ namespace Ryujinx.Core.OsHle.Kernel
{ 0x16, SvcCloseHandle },
{ 0x17, SvcResetSignal },
{ 0x18, SvcWaitSynchronization },
+ { 0x19, SvcCancelSynchronization },
{ 0x1a, SvcArbitrateLock },
{ 0x1b, SvcArbitrateUnlock },
{ 0x1c, SvcWaitProcessWideKeyAtomic },
@@ -70,6 +77,8 @@ namespace Ryujinx.Core.OsHle.Kernel
this.Process = Process;
this.Memory = Process.Memory;
+ SyncWaits = new ConcurrentDictionary<KThread, AutoResetEvent>();
+
CondVarLock = new object();
MappedSharedMems = new HashSet<(HSharedMem, long)>();
@@ -100,6 +109,18 @@ namespace Ryujinx.Core.OsHle.Kernel
}
}
+ private KThread GetThread(long Tpidr, int Handle)
+ {
+ if ((uint)Handle == SelfHandle)
+ {
+ return Process.GetThread(Tpidr);
+ }
+ else
+ {
+ return Process.HandleTable.GetData<KThread>(Handle);
+ }
+ }
+
public void Dispose()
{
Dispose(true);
diff --git a/Ryujinx.Core/OsHle/Kernel/SvcSystem.cs b/Ryujinx.Core/OsHle/Kernel/SvcSystem.cs
index 601b211c..e5b080a8 100644
--- a/Ryujinx.Core/OsHle/Kernel/SvcSystem.cs
+++ b/Ryujinx.Core/OsHle/Kernel/SvcSystem.cs
@@ -40,7 +40,7 @@ namespace Ryujinx.Core.OsHle.Kernel
if (Obj == null)
{
- Ns.Log.PrintWarning(LogClass.KernelSvc, $"Tried to CloseHandle on invalid handle 0x{Handle:x8}!");
+ Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid handle 0x{Handle:x8}!");
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
@@ -88,9 +88,21 @@ namespace Ryujinx.Core.OsHle.Kernel
int HandlesCount = (int)ThreadState.X2;
ulong Timeout = ThreadState.X3;
+ Ns.Log.PrintDebug(LogClass.KernelSvc,
+ "HandlesPtr = " + HandlesPtr .ToString("x16") + ", " +
+ "HandlesCount = " + HandlesCount.ToString("x8") + ", " +
+ "Timeout = " + Timeout .ToString("x16"));
+
+ if ((uint)HandlesCount > 0x40)
+ {
+ ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.CountOutOfRange);
+
+ return;
+ }
+
KThread CurrThread = Process.GetThread(ThreadState.Tpidr);
- WaitHandle[] Handles = new WaitHandle[HandlesCount];
+ WaitHandle[] Handles = new WaitHandle[HandlesCount + 1];
for (int Index = 0; Index < HandlesCount; Index++)
{
@@ -110,34 +122,73 @@ namespace Ryujinx.Core.OsHle.Kernel
Handles[Index] = SyncObj.WaitEvent;
}
- Process.Scheduler.Suspend(CurrThread.ProcessorId);
+ using (AutoResetEvent WaitEvent = new AutoResetEvent(false))
+ {
+ if (!SyncWaits.TryAdd(CurrThread, WaitEvent))
+ {
+ throw new InvalidOperationException();
+ }
+
+ Handles[HandlesCount] = WaitEvent;
- int HandleIndex;
+ Process.Scheduler.Suspend(CurrThread.ProcessorId);
- ulong Result = 0;
+ int HandleIndex;
- if (Timeout != ulong.MaxValue)
- {
- HandleIndex = WaitHandle.WaitAny(Handles, NsTimeConverter.GetTimeMs(Timeout));
+ ulong Result = 0;
+
+ if (Timeout != ulong.MaxValue)
+ {
+ HandleIndex = WaitHandle.WaitAny(Handles, NsTimeConverter.GetTimeMs(Timeout));
+ }
+ else
+ {
+ HandleIndex = WaitHandle.WaitAny(Handles);
+ }
if (HandleIndex == WaitHandle.WaitTimeout)
{
Result = MakeError(ErrorModule.Kernel, KernelErr.Timeout);
}
+ else if (HandleIndex == HandlesCount)
+ {
+ Result = MakeError(ErrorModule.Kernel, KernelErr.Canceled);
+ }
+
+ SyncWaits.TryRemove(CurrThread, out _);
+
+ Process.Scheduler.Resume(CurrThread);
+
+ ThreadState.X0 = Result;
+
+ if (Result == 0)
+ {
+ ThreadState.X1 = (ulong)HandleIndex;
+ }
}
- else
+ }
+
+ private void SvcCancelSynchronization(AThreadState ThreadState)
+ {
+ int ThreadHandle = (int)ThreadState.X0;
+
+ KThread Thread = GetThread(ThreadState.Tpidr, ThreadHandle);
+
+ if (Thread == null)
{
- HandleIndex = WaitHandle.WaitAny(Handles);
- }
+ Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{ThreadHandle:x8}!");
- Process.Scheduler.Resume(CurrThread);
+ ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
- ThreadState.X0 = Result;
+ return;
+ }
- if (Result == 0)
+ if (SyncWaits.TryRemove(Thread, out AutoResetEvent WaitEvent))
{
- ThreadState.X1 = (ulong)HandleIndex;
+ WaitEvent.Set();
}
+
+ ThreadState.X0 = 0;
}
private void SvcGetSystemTick(AThreadState ThreadState)
@@ -190,13 +241,13 @@ namespace Ryujinx.Core.OsHle.Kernel
IpcMessage Cmd = new IpcMessage(CmdData, CmdPtr);
- IpcHandler.IpcCall(Ns, Process, Memory, Session, Cmd, CmdPtr);
+ long Result = IpcHandler.IpcCall(Ns, Process, Memory, Session, Cmd, CmdPtr);
Thread.Yield();
Process.Scheduler.Resume(CurrThread);
- ThreadState.X0 = 0;
+ ThreadState.X0 = (ulong)Result;
}
else
{
diff --git a/Ryujinx.Core/OsHle/Kernel/SvcThreadSync.cs b/Ryujinx.Core/OsHle/Kernel/SvcThreadSync.cs
index e382cf75..57608cda 100644
--- a/Ryujinx.Core/OsHle/Kernel/SvcThreadSync.cs
+++ b/Ryujinx.Core/OsHle/Kernel/SvcThreadSync.cs
@@ -191,6 +191,8 @@ namespace Ryujinx.Core.OsHle.Kernel
InsertWaitingMutexThread(OwnerThreadHandle, WaitThread);
+ Ns.Log.PrintDebug(LogClass.KernelSvc, "Entering wait state...");
+
Process.Scheduler.EnterWait(CurrThread);
}
@@ -297,6 +299,8 @@ namespace Ryujinx.Core.OsHle.Kernel
}
}
+ Ns.Log.PrintDebug(LogClass.KernelSvc, "Entering wait state...");
+
if (Timeout != ulong.MaxValue)
{
return Process.Scheduler.EnterWait(WaitThread, NsTimeConverter.GetTimeMs(Timeout));
@@ -407,7 +411,7 @@ namespace Ryujinx.Core.OsHle.Kernel
if (CurrThread != WaitThread)
{
- if (WaitThread.NextCondVarThread != null)
+ if (WaitThread.NextMutexThread != null)
{
throw new InvalidOperationException();
}
diff --git a/Ryujinx.Core/OsHle/MemoryAllocator.cs b/Ryujinx.Core/OsHle/MemoryAllocator.cs
new file mode 100644
index 00000000..e57f5264
--- /dev/null
+++ b/Ryujinx.Core/OsHle/MemoryAllocator.cs
@@ -0,0 +1,12 @@
+using System;
+
+namespace Ryujinx.Core.OsHle
+{
+ class MemoryAllocator
+ {
+ public bool TryAllocate(long Size, out long Address)
+ {
+ throw new NotImplementedException();
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Process.cs b/Ryujinx.Core/OsHle/Process.cs
index b8c08856..3ccbc016 100644
--- a/Ryujinx.Core/OsHle/Process.cs
+++ b/Ryujinx.Core/OsHle/Process.cs
@@ -410,11 +410,7 @@ namespace Ryujinx.Core.OsHle
}
}
- INvDrvServices.Fds.DeleteProcess(this);
-
- INvDrvServices.NvMaps .DeleteProcess(this);
- INvDrvServices.NvMapsById.DeleteProcess(this);
- INvDrvServices.NvMapsFb .DeleteProcess(this);
+ INvDrvServices.UnloadProcess(this);
AppletState.Dispose();
diff --git a/Ryujinx.Core/OsHle/Services/Nv/INvDrvServices.cs b/Ryujinx.Core/OsHle/Services/Nv/INvDrvServices.cs
index 2652724d..00209f9d 100644
--- a/Ryujinx.Core/OsHle/Services/Nv/INvDrvServices.cs
+++ b/Ryujinx.Core/OsHle/Services/Nv/INvDrvServices.cs
@@ -2,30 +2,36 @@ using ChocolArm64.Memory;
using Ryujinx.Core.Logging;
using Ryujinx.Core.OsHle.Handles;
using Ryujinx.Core.OsHle.Ipc;
-using Ryujinx.Core.OsHle.Utilities;
-using Ryujinx.Graphics.Gpu;
+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.NvMap;
using System;
using System.Collections.Generic;
-using System.IO;
namespace Ryujinx.Core.OsHle.Services.Nv
{
class INvDrvServices : IpcService, IDisposable
{
- private delegate long ServiceProcessIoctl(ServiceCtx Context);
+ private delegate int IoctlProcessor(ServiceCtx Context, int Cmd);
private Dictionary<int, ServiceProcessRequest> m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
- private Dictionary<(string, int), ServiceProcessIoctl> IoctlCmds;
+ private static Dictionary<string, IoctlProcessor> IoctlProcessors =
+ new Dictionary<string, IoctlProcessor>()
+ {
+ { "/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; }
- public static GlobalStateTable NvMaps { get; private set; }
- public static GlobalStateTable NvMapsById { get; private set; }
- public static GlobalStateTable NvMapsFb { get; private set; }
-
private KEvent Event;
public INvDrvServices()
@@ -37,42 +43,7 @@ namespace Ryujinx.Core.OsHle.Services.Nv
{ 2, Close },
{ 3, Initialize },
{ 4, QueryEvent },
- { 8, SetClientPid },
- };
-
- IoctlCmds = new Dictionary<(string, int), ServiceProcessIoctl>()
- {
- { ("/dev/nvhost-as-gpu", 0x4101), NvGpuAsIoctlBindChannel },
- { ("/dev/nvhost-as-gpu", 0x4102), NvGpuAsIoctlAllocSpace },
- { ("/dev/nvhost-as-gpu", 0x4105), NvGpuAsIoctlUnmap },
- { ("/dev/nvhost-as-gpu", 0x4106), NvGpuAsIoctlMapBufferEx },
- { ("/dev/nvhost-as-gpu", 0x4108), NvGpuAsIoctlGetVaRegions },
- { ("/dev/nvhost-as-gpu", 0x4109), NvGpuAsIoctlInitializeEx },
- { ("/dev/nvhost-as-gpu", 0x4114), NvGpuAsIoctlRemap },
- { ("/dev/nvhost-ctrl", 0x001b), NvHostIoctlCtrlGetConfig },
- { ("/dev/nvhost-ctrl", 0x001d), NvHostIoctlCtrlEventWait },
- { ("/dev/nvhost-ctrl", 0x001e), NvHostIoctlCtrlEventWaitAsync },
- { ("/dev/nvhost-ctrl", 0x001f), NvHostIoctlCtrlEventRegister },
- { ("/dev/nvhost-ctrl-gpu", 0x4701), NvGpuIoctlZcullGetCtxSize },
- { ("/dev/nvhost-ctrl-gpu", 0x4702), NvGpuIoctlZcullGetInfo },
- { ("/dev/nvhost-ctrl-gpu", 0x4703), NvGpuIoctlZbcSetTable },
- { ("/dev/nvhost-ctrl-gpu", 0x4705), NvGpuIoctlGetCharacteristics },
- { ("/dev/nvhost-ctrl-gpu", 0x4706), NvGpuIoctlGetTpcMasks },
- { ("/dev/nvhost-ctrl-gpu", 0x4714), NvGpuIoctlZbcGetActiveSlotMask },
- { ("/dev/nvhost-gpu", 0x4714), NvMapIoctlChannelSetUserData },
- { ("/dev/nvhost-gpu", 0x4801), NvMapIoctlChannelSetNvMap },
- { ("/dev/nvhost-gpu", 0x4808), NvMapIoctlChannelSubmitGpFifo },
- { ("/dev/nvhost-gpu", 0x4809), NvMapIoctlChannelAllocObjCtx },
- { ("/dev/nvhost-gpu", 0x480b), NvMapIoctlChannelZcullBind },
- { ("/dev/nvhost-gpu", 0x480c), NvMapIoctlChannelSetErrorNotifier },
- { ("/dev/nvhost-gpu", 0x480d), NvMapIoctlChannelSetPriority },
- { ("/dev/nvhost-gpu", 0x481a), NvMapIoctlChannelAllocGpFifoEx2 },
- { ("/dev/nvmap", 0x0101), NvMapIocCreate },
- { ("/dev/nvmap", 0x0103), NvMapIocFromId },
- { ("/dev/nvmap", 0x0104), NvMapIocAlloc },
- { ("/dev/nvmap", 0x0105), NvMapIocFree },
- { ("/dev/nvmap", 0x0109), NvMapIocParam },
- { ("/dev/nvmap", 0x010e), NvMapIocGetId },
+ { 8, SetClientPid }
};
Event = new KEvent();
@@ -81,10 +52,6 @@ namespace Ryujinx.Core.OsHle.Services.Nv
static INvDrvServices()
{
Fds = new GlobalStateTable();
-
- NvMaps = new GlobalStateTable();
- NvMapsById = new GlobalStateTable();
- NvMapsFb = new GlobalStateTable();
}
public long Open(ServiceCtx Context)
@@ -104,22 +71,25 @@ namespace Ryujinx.Core.OsHle.Services.Nv
public long Ioctl(ServiceCtx Context)
{
int Fd = Context.RequestData.ReadInt32();
- int Cmd = Context.RequestData.ReadInt32() & 0xffff;
+ int Cmd = Context.RequestData.ReadInt32();
NvFd FdData = Fds.GetData<NvFd>(Context.Process, Fd);
- long Position = Context.Request.GetSendBuffPtr();
-
- Context.ResponseData.Write(0);
+ int Result;
- if (IoctlCmds.TryGetValue((FdData.Name, Cmd), out ServiceProcessIoctl ProcReq))
+ if (IoctlProcessors.TryGetValue(FdData.Name, out IoctlProcessor Process))
{
- return ProcReq(Context);
+ Result = Process(Context, Cmd);
}
else
{
throw new NotImplementedException($"{FdData.Name} {Cmd:x4}");
}
+
+ //TODO: Verify if the error codes needs to be translated.
+ Context.ResponseData.Write(Result);
+
+ return 0;
}
public long Close(ServiceCtx Context)
@@ -138,9 +108,9 @@ namespace Ryujinx.Core.OsHle.Services.Nv
long TransferMemSize = Context.RequestData.ReadInt64();
int TransferMemHandle = Context.Request.HandleDesc.ToCopy[0];
- Context.ResponseData.Write(0);
+ NvMapIoctl.InitializeNvMap(Context);
- NvMapsFb.Add(Context.Process, 0, new NvMapFb());
+ Context.ResponseData.Write(0);
return 0;
}
@@ -169,659 +139,69 @@ namespace Ryujinx.Core.OsHle.Services.Nv
return 0;
}
- private long NvGpuAsIoctlBindChannel(ServiceCtx Context)
- {
- long Position = Context.Request.GetSendBuffPtr();
-
- int Fd = Context.Memory.ReadInt32(Position);
-
- return 0;
- }
-
- private long NvGpuAsIoctlAllocSpace(ServiceCtx Context)
- {
- long Position = Context.Request.GetSendBuffPtr();
-
- MemReader Reader = new MemReader(Context.Memory, Position);
-
- int Pages = Reader.ReadInt32();
- int PageSize = Reader.ReadInt32();
- int Flags = Reader.ReadInt32();
- int Padding = Reader.ReadInt32();
- long Align = Reader.ReadInt64();
-
- if ((Flags & 1) != 0)
- {
- Align = Context.Ns.Gpu.ReserveMemory(Align, (long)Pages * PageSize, 1);
- }
- else
- {
- Align = Context.Ns.Gpu.ReserveMemory((long)Pages * PageSize, Align);
- }
-
- Context.Memory.WriteInt64(Position + 0x10, Align);
-
- return 0;
- }
-
- private long NvGpuAsIoctlUnmap(ServiceCtx Context)
- {
- long Position = Context.Request.GetSendBuffPtr();
-
- MemReader Reader = new MemReader(Context.Memory, Position);
-
- long Offset = Reader.ReadInt64();
-
- Context.Ns.Gpu.MemoryMgr.Unmap(Offset, 0x10000);
-
- return 0;
- }
-
- private long NvGpuAsIoctlMapBufferEx(ServiceCtx Context)
- {
- long Position = Context.Request.GetSendBuffPtr();
-
- MemReader Reader = new MemReader(Context.Memory, Position);
-
- int Flags = Reader.ReadInt32();
- int Kind = Reader.ReadInt32();
- int Handle = Reader.ReadInt32();
- int PageSize = Reader.ReadInt32();
- long BuffAddr = Reader.ReadInt64();
- long MapSize = Reader.ReadInt64();
- long Offset = Reader.ReadInt64();
-
- if (Handle == 0)
- {
- //This is used to store offsets for the Framebuffer(s);
- NvMapFb MapFb = (NvMapFb)NvMapsFb.GetData(Context.Process, 0);
-
- MapFb.AddBufferOffset(BuffAddr);
-
- return 0;
- }
-
- NvMap Map = NvMaps.GetData<NvMap>(Context.Process, Handle);
-
- if (Map == null)
- {
- Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"invalid NvMap Handle {Handle}!");
-
- return -1; //TODO: Corrent error code.
- }
-
- if ((Flags & 1) != 0)
- {
- Offset = Context.Ns.Gpu.MapMemory(Map.CpuAddress, Offset, Map.Size);
- }
- else
- {
- Offset = Context.Ns.Gpu.MapMemory(Map.CpuAddress, Map.Size);
- }
-
- Context.Memory.WriteInt64(Position + 0x20, Offset);
-
- Map.GpuAddress = Offset;
-
- return 0;
- }
-
- private long NvGpuAsIoctlGetVaRegions(ServiceCtx Context)
- {
- long Position = Context.Request.GetSendBuffPtr();
-
- MemReader Reader = new MemReader(Context.Memory, Position);
- MemWriter Writer = new MemWriter(Context.Memory, Position);
-
- long Unused = Reader.ReadInt64();
- int BuffSize = Reader.ReadInt32();
- int Padding = Reader.ReadInt32();
-
- BuffSize = 0x30;
-
- Writer.WriteInt64(Unused);
- Writer.WriteInt32(BuffSize);
- Writer.WriteInt32(Padding);
-
- Writer.WriteInt64(0);
- Writer.WriteInt32(0);
- Writer.WriteInt32(0);
- Writer.WriteInt64(0);
-
- Writer.WriteInt64(0);
- Writer.WriteInt32(0);
- Writer.WriteInt32(0);
- Writer.WriteInt64(0);
-
- return 0;
- }
-
- private long NvGpuAsIoctlInitializeEx(ServiceCtx Context)
- {
- long Position = Context.Request.GetSendBuffPtr();
-
- MemReader Reader = new MemReader(Context.Memory, Position);
-
- int BigPageSize = Reader.ReadInt32();
- int AsFd = Reader.ReadInt32();
- int Flags = Reader.ReadInt32();
- int Reserved = Reader.ReadInt32();
- long Unknown10 = Reader.ReadInt64();
- long Unknown18 = Reader.ReadInt64();
- long Unknown20 = Reader.ReadInt64();
-
- return 0;
- }
-
- private long NvGpuAsIoctlRemap(ServiceCtx Context)
- {
- Context.RequestData.BaseStream.Seek(-4, SeekOrigin.Current);
-
- int Cmd = Context.RequestData.ReadInt32();
-
- int Size = (Cmd >> 16) & 0xff;
-
- int Count = Size / 0x18;
-
- long Position = Context.Request.GetSendBuffPtr();
-
- MemReader Reader = new MemReader(Context.Memory, Position);
-
- for (int Index = 0; Index < Count; Index++)
- {
- int Flags = Reader.ReadInt32();
- int Kind = Reader.ReadInt32();
- int Handle = Reader.ReadInt32();
- int Padding = Reader.ReadInt32();
- int Offset = Reader.ReadInt32();
- int Pages = Reader.ReadInt32();
-
- NvMap Map = NvMaps.GetData<NvMap>(Context.Process, Handle);
-
- if (Map == null)
- {
- Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"invalid NvMap Handle {Handle}!");
-
- return -1; //TODO: Corrent error code.
- }
-
- Context.Ns.Gpu.MapMemory(Map.CpuAddress,
- (long)(uint)Offset << 16,
- (long)(uint)Pages << 16);
- }
-
- //TODO
-
- return 0;
- }
-
- private long NvHostIoctlCtrlGetConfig(ServiceCtx Context)
- {
- long Position = Context.Request.GetSendBuffPtr();
-
- MemReader Reader = new MemReader(Context.Memory, Position);
- MemWriter Writer = new MemWriter(Context.Memory, Position + 0x82);
-
- for (int Index = 0; Index < 0x101; Index++)
- {
- Writer.WriteByte(0);
- }
-
- return 0;
- }
-
- private long NvHostIoctlCtrlEventWait(ServiceCtx Context)
- {
- long Position = Context.Request.GetSendBuffPtr();
-
- MemReader Reader = new MemReader(Context.Memory, Position);
-
- int SyncPtId = Reader.ReadInt32();
- int Threshold = Reader.ReadInt32();
- int Timeout = Reader.ReadInt32();
- int Value = Reader.ReadInt32();
-
- Context.Memory.WriteInt32(Position + 0xc, 0xcafe);
-
- return 0;
- }
-
- private long NvHostIoctlCtrlEventWaitAsync(ServiceCtx Context)
- {
- long Position = Context.Request.GetSendBuffPtr();
-
- MemReader Reader = new MemReader(Context.Memory, Position);
-
- int SyncPtId = Reader.ReadInt32();
- int Threshold = Reader.ReadInt32();
- int Timeout = Reader.ReadInt32();
- int Value = Reader.ReadInt32();
-
- Context.Memory.WriteInt32(Position + 0xc, 0xcafe);
-
- return 0;
- }
-
- private long NvHostIoctlCtrlEventRegister(ServiceCtx Context)
- {
- long Position = Context.Request.GetSendBuffPtr();
-
- MemReader Reader = new MemReader(Context.Memory, Position);
-
- int UserEventId = Reader.ReadInt32();
-
- return 0;
- }
-
- private long NvGpuIoctlZcullGetCtxSize(ServiceCtx Context)
- {
- long Position = Context.Request.GetSendBuffPtr();
-
- Context.Memory.WriteInt32(Position, 1);
-
- return 0;
- }
-
- private long NvGpuIoctlZcullGetInfo(ServiceCtx Context)
- {
- long Position = Context.Request.GetSendBuffPtr();
-
- MemWriter Writer = new MemWriter(Context.Memory, Position);
-
- Writer.WriteInt32(0);
- Writer.WriteInt32(0);
- Writer.WriteInt32(0);
- Writer.WriteInt32(0);
- Writer.WriteInt32(0);
- Writer.WriteInt32(0);
- Writer.WriteInt32(0);
- Writer.WriteInt32(0);
- Writer.WriteInt32(0);
- Writer.WriteInt32(0);
-
- return 0;
- }
-
- private long NvGpuIoctlZbcSetTable(ServiceCtx Context)
- {
- long Position = Context.Request.GetSendBuffPtr();
-
- MemReader Reader = new MemReader(Context.Memory, Position);
-
- int[] ColorDs = new int[4];
- int[] ColorL2 = new int[4];
-
- ColorDs[0] = Reader.ReadInt32();
- ColorDs[1] = Reader.ReadInt32();
- ColorDs[2] = Reader.ReadInt32();
- ColorDs[3] = Reader.ReadInt32();
-
- ColorL2[0] = Reader.ReadInt32();
- ColorL2[1] = Reader.ReadInt32();
- ColorL2[2] = Reader.ReadInt32();
- ColorL2[3] = Reader.ReadInt32();
-
- int Depth = Reader.ReadInt32();
- int Format = Reader.ReadInt32();
- int Type = Reader.ReadInt32();
-
- return 0;
- }
-
- private long NvGpuIoctlGetCharacteristics(ServiceCtx Context)
- {
- long Position = Context.Request.GetSendBuffPtr();
-
- MemReader Reader = new MemReader(Context.Memory, Position);
- MemWriter Writer = new MemWriter(Context.Memory, Position);
-
- //Note: We should just ignore the BuffAddr, because official code
- //does __memcpy_device from Position + 0x10 to BuffAddr.
- long BuffSize = Reader.ReadInt64();
- long BuffAddr = Reader.ReadInt64();
-
- BuffSize = 0xa0;
-
- Writer.WriteInt64(BuffSize);
- Writer.WriteInt64(BuffAddr);
- Writer.WriteInt32(0x120); //NVGPU_GPU_ARCH_GM200
- Writer.WriteInt32(0xb); //NVGPU_GPU_IMPL_GM20B
- Writer.WriteInt32(0xa1);
- Writer.WriteInt32(1);
- Writer.WriteInt64(0x40000);
- Writer.WriteInt64(0);
- Writer.WriteInt32(2);
- Writer.WriteInt32(0x20); //NVGPU_GPU_BUS_TYPE_AXI
- Writer.WriteInt32(0x20000);
- Writer.WriteInt32(0x20000);
- Writer.WriteInt32(0x1b);
- Writer.WriteInt32(0x30000);
- Writer.WriteInt32(1);
- Writer.WriteInt32(0x503);
- Writer.WriteInt32(0x503);
- Writer.WriteInt32(0x80);
- Writer.WriteInt32(0x28);
- Writer.WriteInt32(0);
- Writer.WriteInt64(0x55);
- Writer.WriteInt32(0x902d); //FERMI_TWOD_A
- Writer.WriteInt32(0xb197); //MAXWELL_B
- Writer.WriteInt32(0xb1c0); //MAXWELL_COMPUTE_B
- Writer.WriteInt32(0xb06f); //MAXWELL_CHANNEL_GPFIFO_A
- Writer.WriteInt32(0xa140); //KEPLER_INLINE_TO_MEMORY_B
- Writer.WriteInt32(0xb0b5); //MAXWELL_DMA_COPY_A
- Writer.WriteInt32(1);
- Writer.WriteInt32(0);
- Writer.WriteInt32(2);
- Writer.WriteInt32(1);
- Writer.WriteInt32(0);
- Writer.WriteInt32(1);
- Writer.WriteInt32(0x21d70);
- Writer.WriteInt32(0);
- Writer.WriteByte((byte)'g');
- Writer.WriteByte((byte)'m');
- Writer.WriteByte((byte)'2');
- Writer.WriteByte((byte)'0');
- Writer.WriteByte((byte)'b');
- Writer.WriteByte((byte)'\0');
- Writer.WriteByte((byte)'\0');
- Writer.WriteByte((byte)'\0');
- Writer.WriteInt64(0);
-
- return 0;
- }
-
- private long NvGpuIoctlGetTpcMasks(ServiceCtx Context)
- {
- long Position = Context.Request.GetSendBuffPtr();
-
- MemReader Reader = new MemReader(Context.Memory, Position);
-
- int MaskBuffSize = Reader.ReadInt32();
- int Reserved = Reader.ReadInt32();
- long MaskBuffAddr = Reader.ReadInt64();
- long Unknown = Reader.ReadInt64();
-
- return 0;
- }
-
- private long NvGpuIoctlZbcGetActiveSlotMask(ServiceCtx Context)
- {
- long Position = Context.Request.GetSendBuffPtr();
-
- Context.Memory.WriteInt32(Position + 0, 7);
- Context.Memory.WriteInt32(Position + 4, 1);
-
- return 0;
- }
-
- private long NvMapIoctlChannelSetUserData(ServiceCtx Context)
- {
- long Position = Context.Request.GetSendBuffPtr();
-
- return 0;
- }
-
- private long NvMapIoctlChannelSetNvMap(ServiceCtx Context)
- {
- long Position = Context.Request.GetSendBuffPtr();
-
- int Fd = Context.Memory.ReadInt32(Position);
-
- return 0;
- }
-
- private long NvMapIoctlChannelSubmitGpFifo(ServiceCtx Context)
- {
- long Position = Context.Request.GetSendBuffPtr();
-
- MemReader Reader = new MemReader(Context.Memory, Position);
- MemWriter Writer = new MemWriter(Context.Memory, Position + 0x10);
-
- long GpFifo = Reader.ReadInt64();
- int Count = Reader.ReadInt32();
- int Flags = Reader.ReadInt32();
- int FenceId = Reader.ReadInt32();
- int FenceVal = Reader.ReadInt32();
-
- for (int Index = 0; Index < Count; Index++)
- {
- long GpFifoHdr = Reader.ReadInt64();
-
- long GpuAddr = GpFifoHdr & 0xffffffffff;
-
- int Size = (int)(GpFifoHdr >> 40) & 0x7ffffc;
-
- long CpuAddr = Context.Ns.Gpu.GetCpuAddr(GpuAddr);
-
- if (CpuAddr != -1)
- {
- byte[] Data = AMemoryHelper.ReadBytes(Context.Memory, CpuAddr, Size);
-
- NsGpuPBEntry[] PushBuffer = NvGpuPushBuffer.Decode(Data);
-
- Context.Ns.Gpu.Fifo.PushBuffer(Context.Memory, PushBuffer);
- }
- }
-
- Writer.WriteInt32(0);
- Writer.WriteInt32(0);
-
- return 0;
- }
-
- private long NvMapIoctlChannelAllocObjCtx(ServiceCtx Context)
- {
- long Position = Context.Request.GetSendBuffPtr();
-
- int ClassNum = Context.Memory.ReadInt32(Position + 0);
- int Flags = Context.Memory.ReadInt32(Position + 4);
-
- Context.Memory.WriteInt32(Position + 8, 0);
-
- return 0;
- }
-
- private long NvMapIoctlChannelZcullBind(ServiceCtx Context)
+ private static int ProcessIoctlNvGpuAS(ServiceCtx Context, int Cmd)
{
- long Position = Context.Request.GetSendBuffPtr();
-
- MemReader Reader = new MemReader(Context.Memory, Position);
-
- long GpuVa = Reader.ReadInt64();
- int Mode = Reader.ReadInt32();
- int Padding = Reader.ReadInt32();
-
- return 0;
+ return ProcessIoctl(Context, Cmd, NvGpuASIoctl.ProcessIoctl);
}
- private long NvMapIoctlChannelSetErrorNotifier(ServiceCtx Context)
+ private static int ProcessIoctlNvHostCtrl(ServiceCtx Context, int Cmd)
{
- long Position = Context.Request.GetSendBuffPtr();
-
- MemReader Reader = new MemReader(Context.Memory, Position);
-
- long Offset = Reader.ReadInt64();
- long Size = Reader.ReadInt64();
- int Mem = Reader.ReadInt32();
- int Padding = Reader.ReadInt32();
-
- return 0;
+ return ProcessIoctl(Context, Cmd, NvHostCtrlIoctl.ProcessIoctl);
}
- private long NvMapIoctlChannelSetPriority(ServiceCtx Context)
+ private static int ProcessIoctlNvGpuGpu(ServiceCtx Context, int Cmd)
{
- long Position = Context.Request.GetSendBuffPtr();
-
- int Priority = Context.Memory.ReadInt32(Position);
-
- return 0;
+ return ProcessIoctl(Context, Cmd, NvGpuGpuIoctl.ProcessIoctl);
}
- private long NvMapIoctlChannelAllocGpFifoEx2(ServiceCtx Context)
+ private static int ProcessIoctlNvHostChannel(ServiceCtx Context, int Cmd)
{
- long Position = Context.Request.GetSendBuffPtr();
-
- MemReader Reader = new MemReader(Context.Memory, Position);
- MemWriter Writer = new MemWriter(Context.Memory, Position + 0xc);
-
- int Count = Reader.ReadInt32();
- int Flags = Reader.ReadInt32();
- int Unknown8 = Reader.ReadInt32();
- long Fence = Reader.ReadInt64();
- int Unknown14 = Reader.ReadInt32();
- int Unknown18 = Reader.ReadInt32();
-
- Writer.WriteInt32(0);
- Writer.WriteInt32(0);
-
- return 0;
+ return ProcessIoctl(Context, Cmd, NvHostChannelIoctl.ProcessIoctl);
}
- private long NvMapIocCreate(ServiceCtx Context)
+ private static int ProcessIoctlNvMap(ServiceCtx Context, int Cmd)
{
- long Position = Context.Request.GetSendBuffPtr();
-
- int Size = Context.Memory.ReadInt32(Position);
-
- NvMap Map = new NvMap() { Size = Size };
-
- Map.Handle = NvMaps.Add(Context.Process, Map);
-
- Map.Id = NvMapsById.Add(Context.Process, Map);
-
- Context.Memory.WriteInt32(Position + 4, Map.Handle);
-
- Context.Ns.Log.PrintInfo(LogClass.ServiceNv, $"NvMap {Map.Id} created with size {Size:x8}!");
-
- return 0;
+ return ProcessIoctl(Context, Cmd, NvMapIoctl.ProcessIoctl);
}
- private long NvMapIocFromId(ServiceCtx Context)
+ private static int ProcessIoctl(ServiceCtx Context, int Cmd, IoctlProcessor Processor)
{
- long Position = Context.Request.GetSendBuffPtr();
-
- int Id = Context.Memory.ReadInt32(Position);
-
- NvMap Map = NvMapsById.GetData<NvMap>(Context.Process, Id);
-
- if (Map == null)
+ if (CmdIn(Cmd) && Context.Request.GetBufferType0x21Position() == 0)
{
- Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid NvMap Id {Id}!");
+ Context.Ns.Log.PrintError(LogClass.ServiceNv, "Input buffer is null!");
- return -1; //TODO: Corrent error code.
+ return NvResult.InvalidInput;
}
- Context.Memory.WriteInt32(Position + 4, Map.Handle);
-
- return 0;
- }
-
- private long NvMapIocAlloc(ServiceCtx Context)
- {
- long Position = Context.Request.GetSendBuffPtr();
-
- MemReader Reader = new MemReader(Context.Memory, Position);
-
- int Handle = Reader.ReadInt32();
- int HeapMask = Reader.ReadInt32();
- int Flags = Reader.ReadInt32();
- int Align = Reader.ReadInt32();
- byte Kind = (byte)Reader.ReadInt64();
- long Addr = Reader.ReadInt64();
-
- NvMap Map = NvMaps.GetData<NvMap>(Context.Process, Handle);
-
- if (Map == null)
+ if (CmdOut(Cmd) && Context.Request.GetBufferType0x22Position() == 0)
{
- Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid NvMap Handle {Handle}!");
+ Context.Ns.Log.PrintError(LogClass.ServiceNv, "Output buffer is null!");
- return -1; //TODO: Corrent error code.
+ return NvResult.InvalidInput;
}
- Map.CpuAddress = Addr;
- Map.Align = Align;
- Map.Kind = Kind;
-
- return 0;
+ return Processor(Context, Cmd);
}
- private long NvMapIocFree(ServiceCtx Context)
+ private static bool CmdIn(int Cmd)
{
- long Position = Context.Request.GetSendBuffPtr();
-
- MemReader Reader = new MemReader(Context.Memory, Position);
- MemWriter Writer = new MemWriter(Context.Memory, Position + 8);
-
- int Handle = Reader.ReadInt32();
- int Padding = Reader.ReadInt32();
-
- NvMap Map = NvMaps.GetData<NvMap>(Context.Process, Handle);
-
- if (Map == null)
- {
- Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid NvMap Handle {Handle}!");
-
- return -1; //TODO: Corrent error code.
- }
-
- Writer.WriteInt64(0);
- Writer.WriteInt32(Map.Size);
- Writer.WriteInt32(0);
-
- return 0;
+ return ((Cmd >> 30) & 1) != 0;
}
- private long NvMapIocParam(ServiceCtx Context)
+ private static bool CmdOut(int Cmd)
{
- long Position = Context.Request.GetSendBuffPtr();
-
- MemReader Reader = new MemReader(Context.Memory, Position);
-
- int Handle = Reader.ReadInt32();
- int Param = Reader.ReadInt32();
-
- NvMap Map = NvMaps.GetData<NvMap>(Context.Process, Handle);
-
- if (Map == null)
- {
- Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid NvMap Handle {Handle}!");
-
- return -1; //TODO: Corrent error code.
- }
-
- int Response = 0;
-
- switch (Param)
- {
- case 1: Response = Map.Size; break;
- case 2: Response = Map.Align; break;
- case 4: Response = 0x40000000; break;
- case 5: Response = Map.Kind; break;
- }
-
- Context.Memory.WriteInt32(Position + 8, Response);
-
- return 0;
+ return ((Cmd >> 31) & 1) != 0;
}
- private long NvMapIocGetId(ServiceCtx Context)
+ public static void UnloadProcess(Process Process)
{
- long Position = Context.Request.GetSendBuffPtr();
-
- int Handle = Context.Memory.ReadInt32(Position + 4);
-
- NvMap Map = NvMaps.GetData<NvMap>(Context.Process, Handle);
+ Fds.DeleteProcess(Process);
- if (Map == null)
- {
- Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid NvMap Handle {Handle}!");
-
- return -1; //TODO: Corrent error code.
- }
+ NvGpuASIoctl.UnloadProcess(Process);
- Context.Memory.WriteInt32(Position, Map.Id);
+ NvHostCtrlIoctl.UnloadProcess(Process);
- return 0;
+ NvMapIoctl.UnloadProcess(Process);
}
public void Dispose()
diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvChNvMap.cs b/Ryujinx.Core/OsHle/Services/Nv/NvChNvMap.cs
deleted file mode 100644
index 9ea3ae6e..00000000
--- a/Ryujinx.Core/OsHle/Services/Nv/NvChNvMap.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-using System.Collections.Concurrent;
-
-namespace Ryujinx.Core.OsHle.Services.Nv
-{
- class NvChNvMap
- {
- private static ConcurrentDictionary<Process, IdDictionary> NvMaps;
-
- public void Create(ServiceCtx Context)
- {
- long InputPosition = Context.Request.GetBufferType0x21Position();
- long OutputPosition = Context.Request.GetBufferType0x22Position();
-
- int Size = Context.Memory.ReadInt32(InputPosition);
-
- int Handle = AddNvMap(Context, new NvMap(Size));
-
- Context.Memory.WriteInt32(OutputPosition, Handle);
- }
-
- private int AddNvMap(ServiceCtx Context, NvMap Map)
- {
- return NvMaps[Context.Process].Add(Map);
- }
-
- public NvMap GetNvMap(ServiceCtx Context, int Handle)
- {
- return NvMaps[Context.Process].GetData<NvMap>(Handle);
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvGpuAS/NvGpuASAllocSpace.cs b/Ryujinx.Core/OsHle/Services/Nv/NvGpuAS/NvGpuASAllocSpace.cs
new file mode 100644
index 00000000..7e652d1f
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Services/Nv/NvGpuAS/NvGpuASAllocSpace.cs
@@ -0,0 +1,11 @@
+namespace Ryujinx.Core.OsHle.Services.Nv.NvGpuAS
+{
+ struct NvGpuASAllocSpace
+ {
+ public int Pages;
+ public int PageSize;
+ public int Flags;
+ public int Padding;
+ public long Offset;
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvGpuAS/NvGpuASIoctl.cs b/Ryujinx.Core/OsHle/Services/Nv/NvGpuAS/NvGpuASIoctl.cs
new file mode 100644
index 00000000..6be45d5c
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Services/Nv/NvGpuAS/NvGpuASIoctl.cs
@@ -0,0 +1,245 @@
+using ChocolArm64.Memory;
+using Ryujinx.Core.Gpu;
+using Ryujinx.Core.Logging;
+using Ryujinx.Core.OsHle.Services.Nv.NvMap;
+using System;
+using System.Collections.Concurrent;
+
+namespace Ryujinx.Core.OsHle.Services.Nv.NvGpuAS
+{
+ class NvGpuASIoctl
+ {
+ private const int FlagFixedOffset = 1;
+
+ private static ConcurrentDictionary<Process, NvGpuVmm> Vmms;
+
+ static NvGpuASIoctl()
+ {
+ Vmms = new ConcurrentDictionary<Process, NvGpuVmm>();
+ }
+
+ public static int ProcessIoctl(ServiceCtx Context, int Cmd)
+ {
+ switch (Cmd & 0xffff)
+ {
+ case 0x4101: return BindChannel (Context);
+ case 0x4102: return AllocSpace (Context);
+ case 0x4103: return FreeSpace (Context);
+ case 0x4105: return UnmapBuffer (Context);
+ 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"));
+ }
+
+ private static int BindChannel(ServiceCtx Context)
+ {
+ long InputPosition = Context.Request.GetBufferType0x21Position();
+ long OutputPosition = Context.Request.GetBufferType0x22Position();
+
+ Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed.");
+
+ return NvResult.Success;
+ }
+
+ private static int AllocSpace(ServiceCtx Context)
+ {
+ long InputPosition = Context.Request.GetBufferType0x21Position();
+ long OutputPosition = Context.Request.GetBufferType0x22Position();
+
+ NvGpuASAllocSpace Args = AMemoryHelper.Read<NvGpuASAllocSpace>(Context.Memory, InputPosition);
+
+ NvGpuVmm Vmm = GetVmm(Context);
+
+ ulong Size = (ulong)Args.Pages *
+ (ulong)Args.PageSize;
+
+ if ((Args.Flags & FlagFixedOffset) != 0)
+ {
+ Args.Offset = Vmm.Reserve(Args.Offset, (long)Size, 1);
+ }
+ else
+ {
+ Args.Offset = Vmm.Reserve((long)Size, 1);
+ }
+
+ int Result = NvResult.Success;
+
+ if (Args.Offset < 0)
+ {
+ Args.Offset = 0;
+
+ Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"No memory to allocate size {Size:x16}!");
+
+ Result = NvResult.OutOfMemory;
+ }
+
+ AMemoryHelper.Write(Context.Memory, OutputPosition, Args);
+
+ return Result;
+ }
+
+ private static int FreeSpace(ServiceCtx Context)
+ {
+ long InputPosition = Context.Request.GetBufferType0x21Position();
+ long OutputPosition = Context.Request.GetBufferType0x22Position();
+
+ NvGpuASAllocSpace Args = AMemoryHelper.Read<NvGpuASAllocSpace>(Context.Memory, InputPosition);
+
+ NvGpuVmm Vmm = GetVmm(Context);
+
+ ulong Size = (ulong)Args.Pages *
+ (ulong)Args.PageSize;
+
+ Vmm.Free(Args.Offset, (long)Size);
+
+ return NvResult.Success;
+ }
+
+ private static int UnmapBuffer(ServiceCtx Context)
+ {
+ long InputPosition = Context.Request.GetBufferType0x21Position();
+ long OutputPosition = Context.Request.GetBufferType0x22Position();
+
+ NvGpuASUnmapBuffer Args = AMemoryHelper.Read<NvGpuASUnmapBuffer>(Context.Memory, InputPosition);
+
+ NvGpuVmm Vmm = GetVmm(Context);
+
+ if (!Vmm.Unmap(Args.Offset))
+ {
+ Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid buffer offset {Args.Offset:x16}!");
+ }
+
+ return NvResult.Success;
+ }
+
+ private static int MapBufferEx(ServiceCtx Context)
+ {
+ long InputPosition = Context.Request.GetBufferType0x21Position();
+ long OutputPosition = Context.Request.GetBufferType0x22Position();
+
+ NvGpuASMapBufferEx Args = AMemoryHelper.Read<NvGpuASMapBufferEx>(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;
+ }
+
+ long PA = Map.Address + Args.BufferOffset;
+
+ long Size = Args.MappingSize;
+
+ if (Size == 0)
+ {
+ Size = Map.Size;
+ }
+
+ Size = Map.Size;
+
+ int Result = NvResult.Success;
+
+ //Note: When the fixed offset flag is not set,
+ //the Offset field holds the alignment size instead.
+ if ((Args.Flags & FlagFixedOffset) != 0)
+ {
+ long MapEnd = Args.Offset + Args.MappingSize;
+
+ if ((ulong)MapEnd <= (ulong)Args.Offset)
+ {
+ Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Offset 0x{Args.Offset:x16} and size 0x{Args.MappingSize:x16} results in a overflow!");
+
+ return NvResult.InvalidInput;
+ }
+
+ if ((Args.Offset & NvGpuVmm.PageMask) != 0)
+ {
+ Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Offset 0x{Args.Offset:x16} is not page aligned!");
+
+ return NvResult.InvalidInput;
+ }
+
+ Args.Offset = Vmm.Map(PA, Args.Offset, Size);
+ }
+ else
+ {
+ Args.Offset = Vmm.Map(PA, Size);
+
+ if (Args.Offset < 0)
+ {
+ Args.Offset = 0;
+
+ Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"No memory to map size {Args.MappingSize:x16}!");
+
+ Result = NvResult.InvalidInput;
+ }
+ }
+
+ AMemoryHelper.Write(Context.Memory, OutputPosition, Args);
+
+ return Result;
+ }
+
+ private static int GetVaRegions(ServiceCtx Context)
+ {
+ long InputPosition = Context.Request.GetBufferType0x21Position();
+ long OutputPosition = Context.Request.GetBufferType0x22Position();
+
+ Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed.");
+
+ return NvResult.Success;
+ }
+
+ private static int InitializeEx(ServiceCtx Context)
+ {
+ long InputPosition = Context.Request.GetBufferType0x21Position();
+ long OutputPosition = Context.Request.GetBufferType0x22Position();
+
+ Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed.");
+
+ 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 _);
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvGpuAS/NvGpuASMapBufferEx.cs b/Ryujinx.Core/OsHle/Services/Nv/NvGpuAS/NvGpuASMapBufferEx.cs
new file mode 100644
index 00000000..b8bdd706
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Services/Nv/NvGpuAS/NvGpuASMapBufferEx.cs
@@ -0,0 +1,13 @@
+namespace Ryujinx.Core.OsHle.Services.Nv.NvGpuAS
+{
+ struct NvGpuASMapBufferEx
+ {
+ public int Flags;
+ public int Kind;
+ public int NvMapHandle;
+ public int PageSize;
+ public long BufferOffset;
+ public long MappingSize;
+ public long Offset;
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvGpuAS/NvGpuASRemap.cs b/Ryujinx.Core/OsHle/Services/Nv/NvGpuAS/NvGpuASRemap.cs
new file mode 100644
index 00000000..363ae687
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Services/Nv/NvGpuAS/NvGpuASRemap.cs
@@ -0,0 +1,12 @@
+namespace Ryujinx.Core.OsHle.Services.Nv.NvGpuAS
+{
+ struct NvGpuASRemap
+ {
+ public short Flags;
+ public short Kind;
+ public int NvMapHandle;
+ public int Padding;
+ public int Offset;
+ public int Pages;
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvGpuAS/NvGpuASUnmapBuffer.cs b/Ryujinx.Core/OsHle/Services/Nv/NvGpuAS/NvGpuASUnmapBuffer.cs
new file mode 100644
index 00000000..8b627511
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Services/Nv/NvGpuAS/NvGpuASUnmapBuffer.cs
@@ -0,0 +1,7 @@
+namespace Ryujinx.Core.OsHle.Services.Nv.NvGpuAS
+{
+ struct NvGpuASUnmapBuffer
+ {
+ public long Offset;
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvGpuGpu/NvGpuGpuGetCharacteristics.cs b/Ryujinx.Core/OsHle/Services/Nv/NvGpuGpu/NvGpuGpuGetCharacteristics.cs
new file mode 100644
index 00000000..5d92b508
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Services/Nv/NvGpuGpu/NvGpuGpuGetCharacteristics.cs
@@ -0,0 +1,43 @@
+namespace Ryujinx.Core.OsHle.Services.Nv.NvGpuGpu
+{
+ struct NvGpuGpuGetCharacteristics
+ {
+ public long BufferSize;
+ public long BufferAddress;
+ public int Arch;
+ public int Impl;
+ public int Rev;
+ public int NumGpc;
+ public long L2CacheSize;
+ public long OnBoardVideoMemorySize;
+ public int NumTpcPerGpc;
+ public int BusType;
+ public int BigPageSize;
+ public int CompressionPageSize;
+ public int PdeCoverageBitCount;
+ public int AvailableBigPageSizes;
+ public int GpcMask;
+ public int SmArchSmVersion;
+ public int SmArchSpaVersion;
+ public int SmArchWarpCount;
+ public int GpuVaBitCount;
+ public int Reserved;
+ public long Flags;
+ public int TwodClass;
+ public int ThreedClass;
+ public int ComputeClass;
+ public int GpfifoClass;
+ public int InlineToMemoryClass;
+ public int DmaCopyClass;
+ public int MaxFbpsCount;
+ public int FbpEnMask;
+ public int MaxLtcPerFbp;
+ public int MaxLtsPerLtc;
+ public int MaxTexPerTpc;
+ public int MaxGpcCount;
+ public int RopL2EnMask0;
+ public int RopL2EnMask1;
+ public long ChipName;
+ public long GrCompbitStoreBaseHw;
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvGpuGpu/NvGpuGpuIoctl.cs b/Ryujinx.Core/OsHle/Services/Nv/NvGpuGpu/NvGpuGpuIoctl.cs
new file mode 100644
index 00000000..772b6786
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Services/Nv/NvGpuGpu/NvGpuGpuIoctl.cs
@@ -0,0 +1,155 @@
+using ChocolArm64.Memory;
+using Ryujinx.Core.Logging;
+using System;
+using System.Diagnostics;
+
+namespace Ryujinx.Core.OsHle.Services.Nv.NvGpuGpu
+{
+ class NvGpuGpuIoctl
+ {
+ private static Stopwatch PTimer;
+
+ private static double TicksToNs;
+
+ static NvGpuGpuIoctl()
+ {
+ PTimer = new Stopwatch();
+
+ PTimer.Start();
+
+ TicksToNs = (1.0 / Stopwatch.Frequency) * 1_000_000_000;
+ }
+
+ public static int ProcessIoctl(ServiceCtx Context, int Cmd)
+ {
+ switch (Cmd & 0xffff)
+ {
+ case 0x4701: return ZcullGetCtxSize (Context);
+ case 0x4702: return ZcullGetInfo (Context);
+ case 0x4703: return ZbcSetTable (Context);
+ case 0x4705: return GetCharacteristics(Context);
+ case 0x4706: return GetTpcMasks (Context);
+ case 0x4714: return GetActiveSlotMask (Context);
+ case 0x471c: return GetGpuTime (Context);
+ }
+
+ throw new NotImplementedException(Cmd.ToString("x8"));
+ }
+
+ private static int ZcullGetCtxSize(ServiceCtx Context)
+ {
+ long InputPosition = Context.Request.GetBufferType0x21Position();
+ long OutputPosition = Context.Request.GetBufferType0x22Position();
+
+ Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed.");
+
+ return NvResult.Success;
+ }
+
+ private static int ZcullGetInfo(ServiceCtx Context)
+ {
+ long InputPosition = Context.Request.GetBufferType0x21Position();
+ long OutputPosition = Context.Request.GetBufferType0x22Position();
+
+ Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed.");
+
+ return NvResult.Success;
+ }
+
+ private static int ZbcSetTable(ServiceCtx Context)
+ {
+ long InputPosition = Context.Request.GetBufferType0x21Position();
+ long OutputPosition = Context.Request.GetBufferType0x22Position();
+
+ Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed.");
+
+ return NvResult.Success;
+ }
+
+ private static int GetCharacteristics(ServiceCtx Context)
+ {
+ long InputPosition = Context.Request.GetBufferType0x21Position();
+ long OutputPosition = Context.Request.GetBufferType0x22Position();
+
+ NvGpuGpuGetCharacteristics Args = AMemoryHelper.Read<NvGpuGpuGetCharacteristics>(Context.Memory, InputPosition);
+
+ Args.BufferSize = 0xa0;
+
+ Args.Arch = 0x120;
+ Args.Impl = 0xb;
+ Args.Rev = 0xa1;
+ Args.NumGpc = 0x1;
+ Args.L2CacheSize = 0x40000;
+ Args.OnBoardVideoMemorySize = 0x0;
+ Args.NumTpcPerGpc = 0x2;
+ Args.BusType = 0x20;
+ Args.BigPageSize = 0x20000;
+ Args.CompressionPageSize = 0x20000;
+ Args.PdeCoverageBitCount = 0x1b;
+ Args.AvailableBigPageSizes = 0x30000;
+ Args.GpcMask = 0x1;
+ Args.SmArchSmVersion = 0x503;
+ Args.SmArchSpaVersion = 0x503;
+ Args.SmArchWarpCount = 0x80;
+ Args.GpuVaBitCount = 0x28;
+ Args.Reserved = 0x0;
+ Args.Flags = 0x55;
+ Args.TwodClass = 0x902d;
+ Args.ThreedClass = 0xb197;
+ Args.ComputeClass = 0xb1c0;
+ Args.GpfifoClass = 0xb06f;
+ Args.InlineToMemoryClass = 0xa140;
+ Args.DmaCopyClass = 0xb0b5;
+ Args.MaxFbpsCount = 0x1;
+ Args.FbpEnMask = 0x0;
+ Args.MaxLtcPerFbp = 0x2;
+ Args.MaxLtsPerLtc = 0x1;
+ Args.MaxTexPerTpc = 0x0;
+ Args.MaxGpcCount = 0x1;
+ Args.RopL2EnMask0 = 0x21d70;
+ Args.RopL2EnMask1 = 0x0;
+ Args.ChipName = 0x6230326d67;
+ Args.GrCompbitStoreBaseHw = 0x0;
+
+ AMemoryHelper.Write(Context.Memory, OutputPosition, Args);
+
+ return NvResult.Success;
+ }
+
+ private static int GetTpcMasks(ServiceCtx Context)
+ {
+ long InputPosition = Context.Request.GetBufferType0x21Position();
+ long OutputPosition = Context.Request.GetBufferType0x22Position();
+
+ Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed.");
+
+ return NvResult.Success;
+ }
+
+ private static int GetActiveSlotMask(ServiceCtx Context)
+ {
+ long InputPosition = Context.Request.GetBufferType0x21Position();
+ long OutputPosition = Context.Request.GetBufferType0x22Position();
+
+ Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed.");
+
+ return NvResult.Success;
+ }
+
+ private static int GetGpuTime(ServiceCtx Context)
+ {
+ long OutputPosition = Context.Request.GetBufferType0x22Position();
+
+ Context.Memory.WriteInt64(OutputPosition, GetPTimerNanoSeconds());
+
+ return NvResult.Success;
+ }
+
+ private static long GetPTimerNanoSeconds()
+ {
+ double Ticks = PTimer.ElapsedTicks;
+
+ return (long)(Ticks * TicksToNs) & 0xff_ffff_ffff_ffff;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvHelper.cs b/Ryujinx.Core/OsHle/Services/Nv/NvHelper.cs
new file mode 100644
index 00000000..c5cee361
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Services/Nv/NvHelper.cs
@@ -0,0 +1,10 @@
+namespace Ryujinx.Core.OsHle.Services.Nv
+{
+ static class NvHelper
+ {
+ public static void Crash()
+ {
+
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvHostChannel/NvHostChannelIoctl.cs b/Ryujinx.Core/OsHle/Services/Nv/NvHostChannel/NvHostChannelIoctl.cs
new file mode 100644
index 00000000..85b47533
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Services/Nv/NvHostChannel/NvHostChannelIoctl.cs
@@ -0,0 +1,130 @@
+using ChocolArm64.Memory;
+using Ryujinx.Core.Logging;
+using Ryujinx.Core.OsHle.Services.Nv.NvGpuAS;
+using Ryujinx.Core.Gpu;
+using System;
+
+namespace Ryujinx.Core.OsHle.Services.Nv.NvHostChannel
+{
+ class NvHostChannelIoctl
+ {
+ public static int ProcessIoctl(ServiceCtx Context, int Cmd)
+ {
+ switch (Cmd & 0xffff)
+ {
+ case 0x4714: return SetUserData (Context);
+ case 0x4801: return SetNvMap (Context);
+ case 0x4808: return SubmitGpfifo (Context);
+ case 0x4809: return AllocObjCtx (Context);
+ case 0x480b: return ZcullBind (Context);
+ case 0x480c: return SetErrorNotifier(Context);
+ case 0x480d: return SetPriority (Context);
+ case 0x481a: return AllocGpfifoEx2 (Context);
+ }
+
+ throw new NotImplementedException(Cmd.ToString("x8"));
+ }
+
+ private static int SetUserData(ServiceCtx Context)
+ {
+ long InputPosition = Context.Request.GetBufferType0x21Position();
+ long OutputPosition = Context.Request.GetBufferType0x22Position();
+
+ Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed.");
+
+ return NvResult.Success;
+ }
+
+ private static int SetNvMap(ServiceCtx Context)
+ {
+ long InputPosition = Context.Request.GetBufferType0x21Position();
+ long OutputPosition = Context.Request.GetBufferType0x22Position();
+
+ Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed.");
+
+ return NvResult.Success;
+ }
+
+ private static int SubmitGpfifo(ServiceCtx Context)
+ {
+ long InputPosition = Context.Request.GetBufferType0x21Position();
+ long OutputPosition = Context.Request.GetBufferType0x22Position();
+
+ NvHostChannelSubmitGpfifo Args = AMemoryHelper.Read<NvHostChannelSubmitGpfifo>(Context.Memory, InputPosition);
+
+ NvGpuVmm Vmm = NvGpuASIoctl.GetVmm(Context);
+
+ for (int Index = 0; Index < Args.NumEntries; Index++)
+ {
+ long Gpfifo = Context.Memory.ReadInt64(InputPosition + 0x18 + Index * 8);
+
+ long VA = Gpfifo & 0xff_ffff_ffff;
+
+ int Size = (int)(Gpfifo >> 40) & 0x7ffffc;
+
+ byte[] Data = Vmm.ReadBytes(VA, Size);
+
+ NvGpuPBEntry[] PushBuffer = NvGpuPushBuffer.Decode(Data);
+
+ Context.Ns.Gpu.Fifo.PushBuffer(Vmm, PushBuffer);
+ }
+
+ Args.SyncptId = 0;
+ Args.SyncptValue = 0;
+
+ AMemoryHelper.Write(Context.Memory, OutputPosition, Args);
+
+ return NvResult.Success;
+ }
+
+ private static int AllocObjCtx(ServiceCtx Context)
+ {
+ long InputPosition = Context.Request.GetBufferType0x21Position();
+ long OutputPosition = Context.Request.GetBufferType0x22Position();
+
+ Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed.");
+
+ return NvResult.Success;
+ }
+
+ private static int ZcullBind(ServiceCtx Context)
+ {
+ long InputPosition = Context.Request.GetBufferType0x21Position();
+ long OutputPosition = Context.Request.GetBufferType0x22Position();
+
+ Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed.");
+
+ return NvResult.Success;
+ }
+
+ private static int SetErrorNotifier(ServiceCtx Context)
+ {
+ long InputPosition = Context.Request.GetBufferType0x21Position();
+ long OutputPosition = Context.Request.GetBufferType0x22Position();
+
+ Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed.");
+
+ return NvResult.Success;
+ }
+
+ private static int SetPriority(ServiceCtx Context)
+ {
+ long InputPosition = Context.Request.GetBufferType0x21Position();
+ long OutputPosition = Context.Request.GetBufferType0x22Position();
+
+ Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed.");
+
+ return NvResult.Success;
+ }
+
+ private static int AllocGpfifoEx2(ServiceCtx Context)
+ {
+ long InputPosition = Context.Request.GetBufferType0x21Position();
+ long OutputPosition = Context.Request.GetBufferType0x22Position();
+
+ Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed.");
+
+ return NvResult.Success;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvHostChannel/NvHostChannelSubmitGpfifo.cs b/Ryujinx.Core/OsHle/Services/Nv/NvHostChannel/NvHostChannelSubmitGpfifo.cs
new file mode 100644
index 00000000..4698a3da
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Services/Nv/NvHostChannel/NvHostChannelSubmitGpfifo.cs
@@ -0,0 +1,11 @@
+namespace Ryujinx.Core.OsHle.Services.Nv.NvHostChannel
+{
+ struct NvHostChannelSubmitGpfifo
+ {
+ public long Gpfifo;
+ public int NumEntries;
+ public int Flags;
+ public int SyncptId;
+ public int SyncptValue;
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlIoctl.cs b/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlIoctl.cs
new file mode 100644
index 00000000..8c705d7f
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlIoctl.cs
@@ -0,0 +1,355 @@
+using ChocolArm64.Memory;
+using Ryujinx.Core.Logging;
+using System;
+using System.Collections.Concurrent;
+using System.Threading;
+
+namespace Ryujinx.Core.OsHle.Services.Nv.NvHostCtrl
+{
+ class NvHostCtrlIoctl
+ {
+ private static ConcurrentDictionary<Process, NvHostCtrlUserCtx> UserCtxs;
+
+ static NvHostCtrlIoctl()
+ {
+ UserCtxs = new ConcurrentDictionary<Process, NvHostCtrlUserCtx>();
+ }
+
+ public static int ProcessIoctl(ServiceCtx Context, int Cmd)
+ {
+ switch (Cmd & 0xffff)
+ {
+ case 0x0014: return SyncptRead (Context);
+ case 0x0015: return SyncptIncr (Context);
+ case 0x0016: return SyncptWait (Context);
+ case 0x0019: return SyncptWaitEx (Context);
+ case 0x001a: return SyncptReadMax (Context);
+ case 0x001b: return GetConfig (Context);
+ case 0x001d: return EventWait (Context);
+ case 0x001e: return EventWaitAsync(Context);
+ case 0x001f: return EventRegister (Context);
+ }
+
+ throw new NotImplementedException(Cmd.ToString("x8"));
+ }
+
+ private static int SyncptRead(ServiceCtx Context)
+ {
+ return SyncptReadMinOrMax(Context, Max: false);
+ }
+
+ private static int SyncptIncr(ServiceCtx Context)
+ {
+ long InputPosition = Context.Request.GetBufferType0x21Position();
+
+ int Id = Context.Memory.ReadInt32(InputPosition);
+
+ if ((uint)Id >= NvHostSyncpt.SyncptsCount)
+ {
+ return NvResult.InvalidInput;
+ }
+
+ GetUserCtx(Context).Syncpt.Increment(Id);
+
+ return NvResult.Success;
+ }
+
+ private static int SyncptWait(ServiceCtx Context)
+ {
+ return SyncptWait(Context, Extended: false);
+ }
+
+ private static int SyncptWaitEx(ServiceCtx Context)
+ {
+ return SyncptWait(Context, Extended: true);
+ }
+
+ private static int SyncptReadMax(ServiceCtx Context)
+ {
+ return SyncptReadMinOrMax(Context, Max: true);
+ }
+
+ private static int GetConfig(ServiceCtx Context)
+ {
+ long InputPosition = Context.Request.GetBufferType0x21Position();
+ long OutputPosition = Context.Request.GetBufferType0x22Position();
+
+ string Nv = AMemoryHelper.ReadAsciiString(Context.Memory, InputPosition + 0, 0x41);
+ string Name = AMemoryHelper.ReadAsciiString(Context.Memory, InputPosition + 0x41, 0x41);
+
+ Context.Memory.WriteByte(OutputPosition + 0x82, 0);
+
+ Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed.");
+
+ return NvResult.Success;
+ }
+
+ private static int EventWait(ServiceCtx Context)
+ {
+ return EventWait(Context, Async: false);
+ }
+
+ private static int EventWaitAsync(ServiceCtx Context)
+ {
+ return EventWait(Context, Async: true);
+ }
+
+ private static int EventRegister(ServiceCtx Context)
+ {
+ long InputPosition = Context.Request.GetBufferType0x21Position();
+ long OutputPosition = Context.Request.GetBufferType0x22Position();
+
+ int EventId = Context.Memory.ReadInt32(InputPosition);
+
+ Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed.");
+
+ return NvResult.Success;
+ }
+
+ private static int SyncptReadMinOrMax(ServiceCtx Context, bool Max)
+ {
+ long InputPosition = Context.Request.GetBufferType0x21Position();
+ long OutputPosition = Context.Request.GetBufferType0x22Position();
+
+ NvHostCtrlSyncptRead Args = AMemoryHelper.Read<NvHostCtrlSyncptRead>(Context.Memory, InputPosition);
+
+ if ((uint)Args.Id >= NvHostSyncpt.SyncptsCount)
+ {
+ return NvResult.InvalidInput;
+ }
+
+ if (Max)
+ {
+ Args.Value = GetUserCtx(Context).Syncpt.GetMax(Args.Id);
+ }
+ else
+ {
+ Args.Value = GetUserCtx(Context).Syncpt.GetMin(Args.Id);
+ }
+
+ AMemoryHelper.Write(Context.Memory, OutputPosition, Args);
+
+ return NvResult.Success;
+ }
+
+ private static int SyncptWait(ServiceCtx Context, bool Extended)
+ {
+ long InputPosition = Context.Request.GetBufferType0x21Position();
+ long OutputPosition = Context.Request.GetBufferType0x22Position();
+
+ NvHostCtrlSyncptWait Args = AMemoryHelper.Read<NvHostCtrlSyncptWait>(Context.Memory, InputPosition);
+
+ NvHostSyncpt Syncpt = GetUserCtx(Context).Syncpt;
+
+ if ((uint)Args.Id >= NvHostSyncpt.SyncptsCount)
+ {
+ return NvResult.InvalidInput;
+ }
+
+ int Result;
+
+ if (Syncpt.MinCompare(Args.Id, Args.Thresh))
+ {
+ Result = NvResult.Success;
+ }
+ else if (Args.Timeout == 0)
+ {
+ Result = NvResult.TryAgain;
+ }
+ else
+ {
+ Context.Ns.Log.PrintDebug(LogClass.ServiceNv, "Waiting syncpt with timeout of " + Args.Timeout + "ms...");
+
+ using (ManualResetEvent WaitEvent = new ManualResetEvent(false))
+ {
+ 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.
+ int Timeout = Args.Timeout;
+
+ if (Timeout < -1)
+ {
+ Timeout = int.MaxValue;
+ }
+
+ if (Timeout == -1)
+ {
+ WaitEvent.WaitOne();
+
+ Result = NvResult.Success;
+ }
+ else if (WaitEvent.WaitOne(Timeout))
+ {
+ Result = NvResult.Success;
+ }
+ else
+ {
+ Result = NvResult.TimedOut;
+ }
+ }
+
+ Context.Ns.Log.PrintDebug(LogClass.ServiceNv, "Resuming...");
+ }
+
+ if (Extended)
+ {
+ Context.Memory.WriteInt32(OutputPosition + 0xc, Syncpt.GetMin(Args.Id));
+ }
+
+ return Result;
+ }
+
+ private static int EventWait(ServiceCtx Context, bool Async)
+ {
+ long InputPosition = Context.Request.GetBufferType0x21Position();
+ long OutputPosition = Context.Request.GetBufferType0x22Position();
+
+ NvHostCtrlSyncptWaitEx Args = AMemoryHelper.Read<NvHostCtrlSyncptWaitEx>(Context.Memory, InputPosition);
+
+ if ((uint)Args.Id >= NvHostSyncpt.SyncptsCount)
+ {
+ return NvResult.InvalidInput;
+ }
+
+ void WriteArgs()
+ {
+ AMemoryHelper.Write(Context.Memory, OutputPosition, Args);
+ }
+
+ NvHostSyncpt Syncpt = GetUserCtx(Context).Syncpt;
+
+ if (Syncpt.MinCompare(Args.Id, Args.Thresh))
+ {
+ Args.Value = Syncpt.GetMin(Args.Id);
+
+ WriteArgs();
+
+ return NvResult.Success;
+ }
+
+ if (!Async)
+ {
+ Args.Value = 0;
+ }
+
+ if (Args.Timeout == 0)
+ {
+ WriteArgs();
+
+ return NvResult.TryAgain;
+ }
+
+ NvHostEvent Event;
+
+ int Result, EventIndex;
+
+ if (Async)
+ {
+ EventIndex = Args.Value;
+
+ if ((uint)EventIndex >= NvHostCtrlUserCtx.EventsCount)
+ {
+ return NvResult.InvalidInput;
+ }
+
+ Event = GetUserCtx(Context).Events[EventIndex];
+ }
+ else
+ {
+ Event = GetFreeEvent(Context, Syncpt, Args.Id, out EventIndex);
+ }
+
+ if (Event != null &&
+ (Event.State == NvHostEventState.Registered ||
+ Event.State == NvHostEventState.Free))
+ {
+ Event.Id = Args.Id;
+ Event.Thresh = Args.Thresh;
+
+ Event.State = NvHostEventState.Waiting;
+
+ if (!Async)
+ {
+ Args.Value = ((Args.Id & 0xfff) << 16) | 0x10000000;
+ }
+ else
+ {
+ Args.Value = Args.Id << 4;
+ }
+
+ Args.Value |= EventIndex;
+
+ Result = NvResult.TryAgain;
+ }
+ else
+ {
+ Result = NvResult.InvalidInput;
+ }
+
+ WriteArgs();
+
+ return Result;
+ }
+
+ private static NvHostEvent GetFreeEvent(
+ ServiceCtx Context,
+ NvHostSyncpt Syncpt,
+ int Id,
+ out int EventIndex)
+ {
+ NvHostEvent[] Events = GetUserCtx(Context).Events;
+
+ EventIndex = NvHostCtrlUserCtx.EventsCount;
+
+ int NullIndex = NvHostCtrlUserCtx.EventsCount;
+
+ for (int Index = 0; Index < NvHostCtrlUserCtx.EventsCount; Index++)
+ {
+ NvHostEvent Event = Events[Index];
+
+ if (Event != null)
+ {
+ if (Event.State == NvHostEventState.Registered ||
+ Event.State == NvHostEventState.Free)
+ {
+ EventIndex = Index;
+
+ if (Event.Id == Id)
+ {
+ return Event;
+ }
+ }
+ }
+ else if (NullIndex == NvHostCtrlUserCtx.EventsCount)
+ {
+ NullIndex = Index;
+ }
+ }
+
+ if (NullIndex < NvHostCtrlUserCtx.EventsCount)
+ {
+ EventIndex = NullIndex;
+
+ return Events[NullIndex] = new NvHostEvent();
+ }
+
+ if (EventIndex < NvHostCtrlUserCtx.EventsCount)
+ {
+ return Events[EventIndex];
+ }
+
+ return null;
+ }
+
+ public static NvHostCtrlUserCtx GetUserCtx(ServiceCtx Context)
+ {
+ return UserCtxs.GetOrAdd(Context.Process, (Key) => new NvHostCtrlUserCtx());
+ }
+
+ public static void UnloadProcess(Process Process)
+ {
+ UserCtxs.TryRemove(Process, out _);
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtRead.cs b/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtRead.cs
new file mode 100644
index 00000000..0b05e63a
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtRead.cs
@@ -0,0 +1,8 @@
+namespace Ryujinx.Core.OsHle.Services.Nv.NvHostCtrl
+{
+ struct NvHostCtrlSyncptRead
+ {
+ public int Id;
+ public int Value;
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtWait.cs b/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtWait.cs
new file mode 100644
index 00000000..6746090a
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtWait.cs
@@ -0,0 +1,9 @@
+namespace Ryujinx.Core.OsHle.Services.Nv.NvHostCtrl
+{
+ struct NvHostCtrlSyncptWait
+ {
+ public int Id;
+ public int Thresh;
+ public int Timeout;
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtWaitEx.cs b/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtWaitEx.cs
new file mode 100644
index 00000000..21ba3783
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlSyncPtWaitEx.cs
@@ -0,0 +1,10 @@
+namespace Ryujinx.Core.OsHle.Services.Nv.NvHostCtrl
+{
+ struct NvHostCtrlSyncptWaitEx
+ {
+ public int Id;
+ public int Thresh;
+ public int Timeout;
+ public int Value;
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlUserCtx.cs b/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlUserCtx.cs
new file mode 100644
index 00000000..be71b225
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlUserCtx.cs
@@ -0,0 +1,19 @@
+namespace Ryujinx.Core.OsHle.Services.Nv.NvHostCtrl
+{
+ class NvHostCtrlUserCtx
+ {
+ public const int LocksCount = 16;
+ public const int EventsCount = 64;
+
+ public NvHostSyncpt Syncpt { get; private set; }
+
+ public NvHostEvent[] Events { get; private set; }
+
+ public NvHostCtrlUserCtx()
+ {
+ Syncpt = new NvHostSyncpt();
+
+ Events = new NvHostEvent[EventsCount];
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostEvent.cs b/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostEvent.cs
new file mode 100644
index 00000000..027e25b0
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostEvent.cs
@@ -0,0 +1,10 @@
+namespace Ryujinx.Core.OsHle.Services.Nv.NvHostCtrl
+{
+ class NvHostEvent
+ {
+ public int Id;
+ public int Thresh;
+
+ public NvHostEventState State;
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostEventState.cs b/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostEventState.cs
new file mode 100644
index 00000000..a4bd2cb6
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostEventState.cs
@@ -0,0 +1,10 @@
+namespace Ryujinx.Core.OsHle.Services.Nv.NvHostCtrl
+{
+ enum NvHostEventState
+ {
+ Registered = 0,
+ Waiting = 1,
+ Busy = 2,
+ Free = 5
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostSyncPt.cs b/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostSyncPt.cs
new file mode 100644
index 00000000..96ae16a3
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Services/Nv/NvHostCtrl/NvHostSyncPt.cs
@@ -0,0 +1,107 @@
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Threading;
+
+namespace Ryujinx.Core.OsHle.Services.Nv.NvHostCtrl
+{
+ class NvHostSyncpt
+ {
+ public const int SyncptsCount = 192;
+
+ private int[] CounterMin;
+ private int[] CounterMax;
+
+ private long EventMask;
+
+ private ConcurrentDictionary<EventWaitHandle, int> Waiters;
+
+ public NvHostSyncpt()
+ {
+ CounterMin = new int[SyncptsCount];
+ CounterMax = new int[SyncptsCount];
+
+ Waiters = new ConcurrentDictionary<EventWaitHandle, int>();
+ }
+
+ public int GetMin(int Id)
+ {
+ return CounterMin[Id];
+ }
+
+ public int GetMax(int Id)
+ {
+ return CounterMax[Id];
+ }
+
+ public int Increment(int Id)
+ {
+ if (((EventMask >> Id) & 1) != 0)
+ {
+ Interlocked.Increment(ref CounterMax[Id]);
+ }
+
+ return IncrementMin(Id);
+ }
+
+ public int IncrementMin(int Id)
+ {
+ int Value = Interlocked.Increment(ref CounterMin[Id]);
+
+ WakeUpWaiters(Id, Value);
+
+ return Value;
+ }
+
+ public int IncrementMax(int Id)
+ {
+ return Interlocked.Increment(ref CounterMax[Id]);
+ }
+
+ public void AddWaiter(int Threshold, EventWaitHandle WaitEvent)
+ {
+ if (!Waiters.TryAdd(WaitEvent, Threshold))
+ {
+ throw new InvalidOperationException();
+ }
+ }
+
+ public bool RemoveWaiter(EventWaitHandle WaitEvent)
+ {
+ return Waiters.TryRemove(WaitEvent, out _);
+ }
+
+ private void WakeUpWaiters(int Id, int NewValue)
+ {
+ foreach (KeyValuePair<EventWaitHandle, int> KV in Waiters)
+ {
+ if (MinCompare(Id, NewValue, CounterMax[Id], KV.Value))
+ {
+ KV.Key.Set();
+
+ Waiters.TryRemove(KV.Key, out _);
+ }
+ }
+ }
+
+ public bool MinCompare(int Id, int Threshold)
+ {
+ return MinCompare(Id, CounterMin[Id], CounterMax[Id], Threshold);
+ }
+
+ private bool MinCompare(int Id, int Min, int Max, int Threshold)
+ {
+ int MinDiff = Min - Threshold;
+ int MaxDiff = Max - Threshold;
+
+ if (((EventMask >> Id) & 1) != 0)
+ {
+ return MinDiff >= 0;
+ }
+ else
+ {
+ return (uint)MaxDiff >= (uint)MinDiff;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvMap.cs b/Ryujinx.Core/OsHle/Services/Nv/NvMap.cs
deleted file mode 100644
index 570cef68..00000000
--- a/Ryujinx.Core/OsHle/Services/Nv/NvMap.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-namespace Ryujinx.Core.OsHle.Services.Nv
-{
- class NvMap
- {
- public int Handle;
- public int Id;
- public int Size;
- public int Align;
- public int Kind;
- public long CpuAddress;
- public long GpuAddress;
-
- public NvMap() { }
-
- public NvMap(int Size)
- {
- this.Size = Size;
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapAlloc.cs b/Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapAlloc.cs
new file mode 100644
index 00000000..86e4c238
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapAlloc.cs
@@ -0,0 +1,12 @@
+namespace Ryujinx.Core.OsHle.Services.Nv.NvMap
+{
+ struct NvMapAlloc
+ {
+ public int Handle;
+ public int HeapMask;
+ public int Flags;
+ public int Align;
+ public long Kind;
+ public long Address;
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapCreate.cs b/Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapCreate.cs
new file mode 100644
index 00000000..7d35731c
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapCreate.cs
@@ -0,0 +1,8 @@
+namespace Ryujinx.Core.OsHle.Services.Nv.NvMap
+{
+ struct NvMapCreate
+ {
+ public int Size;
+ public int Handle;
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapFree.cs b/Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapFree.cs
new file mode 100644
index 00000000..ee8bc618
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapFree.cs
@@ -0,0 +1,11 @@
+namespace Ryujinx.Core.OsHle.Services.Nv.NvMap
+{
+ struct NvMapFree
+ {
+ public int Handle;
+ public int Padding;
+ public long RefCount;
+ public int Size;
+ public int Flags;
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapFromId.cs b/Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapFromId.cs
new file mode 100644
index 00000000..377eaa7f
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapFromId.cs
@@ -0,0 +1,8 @@
+namespace Ryujinx.Core.OsHle.Services.Nv.NvMap
+{
+ struct NvMapFromId
+ {
+ public int Id;
+ public int Handle;
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapGetId.cs b/Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapGetId.cs
new file mode 100644
index 00000000..639a5fb4
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapGetId.cs
@@ -0,0 +1,8 @@
+namespace Ryujinx.Core.OsHle.Services.Nv.NvMap
+{
+ struct NvMapGetId
+ {
+ public int Id;
+ public int Handle;
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapHandle.cs b/Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapHandle.cs
new file mode 100644
index 00000000..4a021f6f
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapHandle.cs
@@ -0,0 +1,37 @@
+using System.Threading;
+
+namespace Ryujinx.Core.OsHle.Services.Nv.NvMap
+{
+ class NvMapHandle
+ {
+ public int Handle;
+ public int Id;
+ public int Size;
+ public int Align;
+ public int Kind;
+ public long Address;
+ public bool Allocated;
+
+ private long Dupes;
+
+ public NvMapHandle()
+ {
+ Dupes = 1;
+ }
+
+ public NvMapHandle(int Size) : this()
+ {
+ this.Size = Size;
+ }
+
+ public long IncrementRefCount()
+ {
+ return Interlocked.Increment(ref Dupes);
+ }
+
+ public long DecrementRefCount()
+ {
+ return Interlocked.Decrement(ref Dupes);
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapHandleParam.cs b/Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapHandleParam.cs
new file mode 100644
index 00000000..80ff4c03
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapHandleParam.cs
@@ -0,0 +1,12 @@
+namespace Ryujinx.Core.OsHle.Services.Nv.NvMap
+{
+ enum NvMapHandleParam
+ {
+ Size = 1,
+ Align = 2,
+ Base = 3,
+ Heap = 4,
+ Kind = 5,
+ Compr = 6
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapIoctl.cs b/Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapIoctl.cs
new file mode 100644
index 00000000..f9c1564a
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapIoctl.cs
@@ -0,0 +1,302 @@
+using ChocolArm64.Memory;
+using Ryujinx.Core.Logging;
+using Ryujinx.Core.OsHle.Utilities;
+using Ryujinx.Core.Gpu;
+using System.Collections.Concurrent;
+
+namespace Ryujinx.Core.OsHle.Services.Nv.NvMap
+{
+ class NvMapIoctl
+ {
+ private const int FlagNotFreedYet = 1;
+
+ private static ConcurrentDictionary<Process, IdDictionary> Maps;
+
+ static NvMapIoctl()
+ {
+ Maps = new ConcurrentDictionary<Process, IdDictionary>();
+ }
+
+ public static int ProcessIoctl(ServiceCtx Context, int Cmd)
+ {
+ switch (Cmd & 0xffff)
+ {
+ case 0x0101: return Create(Context);
+ case 0x0103: return FromId(Context);
+ case 0x0104: return Alloc (Context);
+ case 0x0105: return Free (Context);
+ case 0x0109: return Param (Context);
+ case 0x010e: return GetId (Context);
+ }
+
+ Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Unsupported Ioctl command 0x{Cmd:x8}!");
+
+ return NvResult.NotSupported;
+ }
+
+ private static int Create(ServiceCtx Context)
+ {
+ long InputPosition = Context.Request.GetBufferType0x21Position();
+ long OutputPosition = Context.Request.GetBufferType0x22Position();
+
+ NvMapCreate Args = AMemoryHelper.Read<NvMapCreate>(Context.Memory, InputPosition);
+
+ if (Args.Size == 0)
+ {
+ Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid size 0x{Args.Size:x8}!");
+
+ return NvResult.InvalidInput;
+ }
+
+ int Size = IntUtils.RoundUp(Args.Size, NvGpuVmm.PageSize);
+
+ Args.Handle = AddNvMap(Context, new NvMapHandle(Size));
+
+ Context.Ns.Log.PrintInfo(LogClass.ServiceNv, $"Created map {Args.Handle} with size 0x{Size:x8}!");
+
+ AMemoryHelper.Write(Context.Memory, OutputPosition, Args);
+
+ return NvResult.Success;
+ }
+
+ private static int FromId(ServiceCtx Context)
+ {
+ long InputPosition = Context.Request.GetBufferType0x21Position();
+ long OutputPosition = Context.Request.GetBufferType0x22Position();
+
+ NvMapFromId Args = AMemoryHelper.Read<NvMapFromId>(Context.Memory, InputPosition);
+
+ NvMapHandle Map = GetNvMap(Context, Args.Id);
+
+ if (Map == null)
+ {
+ Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{Args.Handle:x8}!");
+
+ return NvResult.InvalidInput;
+ }
+
+ Map.IncrementRefCount();
+
+ Args.Handle = Args.Id;
+
+ AMemoryHelper.Write(Context.Memory, OutputPosition, Args);
+
+ return NvResult.Success;
+ }
+
+ private static int Alloc(ServiceCtx Context)
+ {
+ long InputPosition = Context.Request.GetBufferType0x21Position();
+ long OutputPosition = Context.Request.GetBufferType0x22Position();
+
+ NvMapAlloc Args = AMemoryHelper.Read<NvMapAlloc>(Context.Memory, InputPosition);
+
+ NvMapHandle Map = GetNvMap(Context, Args.Handle);
+
+ 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;
+ }
+
+ if ((uint)Args.Align < NvGpuVmm.PageSize)
+ {
+ Args.Align = NvGpuVmm.PageSize;
+ }
+
+ int Result = NvResult.Success;
+
+ if (!Map.Allocated)
+ {
+ Map.Allocated = true;
+
+ Map.Align = Args.Align;
+ Map.Kind = (byte)Args.Kind;
+
+ int Size = IntUtils.RoundUp(Map.Size, NvGpuVmm.PageSize);
+
+ long Address = Args.Address;
+
+ if (Address == 0)
+ {
+ //When the address is zero, we need to allocate
+ //our own backing memory for the NvMap.
+ if (!Context.Ns.Os.Allocator.TryAllocate((uint)Size, out Address))
+ {
+ Result = NvResult.OutOfMemory;
+ }
+ }
+
+ if (Result == NvResult.Success)
+ {
+ Map.Size = Size;
+ Map.Address = Address;
+ }
+ }
+
+ AMemoryHelper.Write(Context.Memory, OutputPosition, Args);
+
+ return Result;
+ }
+
+ private static int Free(ServiceCtx Context)
+ {
+ long InputPosition = Context.Request.GetBufferType0x21Position();
+ long OutputPosition = Context.Request.GetBufferType0x22Position();
+
+ NvMapFree Args = AMemoryHelper.Read<NvMapFree>(Context.Memory, InputPosition);
+
+ NvMapHandle Map = GetNvMap(Context, Args.Handle);
+
+ if (Map == null)
+ {
+ Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{Args.Handle:x8}!");
+
+ return NvResult.InvalidInput;
+ }
+
+ long RefCount = Map.DecrementRefCount();
+
+ if (RefCount <= 0)
+ {
+ DeleteNvMap(Context, Args.Handle);
+
+ Context.Ns.Log.PrintInfo(LogClass.ServiceNv, $"Deleted map {Args.Handle}!");
+
+ Args.Flags = 0;
+ }
+ else
+ {
+ Args.Flags = FlagNotFreedYet;
+ }
+
+ Args.RefCount = RefCount;
+ Args.Size = Map.Size;
+
+ AMemoryHelper.Write(Context.Memory, OutputPosition, Args);
+
+ return NvResult.Success;
+ }
+
+ private static int Param(ServiceCtx Context)
+ {
+ long InputPosition = Context.Request.GetBufferType0x21Position();
+ long OutputPosition = Context.Request.GetBufferType0x22Position();
+
+ NvMapParam Args = AMemoryHelper.Read<NvMapParam>(Context.Memory, InputPosition);
+
+ NvMapHandle Map = GetNvMap(Context, Args.Handle);
+
+ if (Map == null)
+ {
+ Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{Args.Handle:x8}!");
+
+ return NvResult.InvalidInput;
+ }
+
+ switch ((NvMapHandleParam)Args.Param)
+ {
+ case NvMapHandleParam.Size: Args.Result = Map.Size; break;
+ case NvMapHandleParam.Align: Args.Result = Map.Align; break;
+ case NvMapHandleParam.Heap: Args.Result = 0x40000000; break;
+ case NvMapHandleParam.Kind: Args.Result = Map.Kind; break;
+ case NvMapHandleParam.Compr: Args.Result = 0; break;
+
+ //Note: Base is not supported and returns an error.
+ //Any other value also returns an error.
+ default: return NvResult.InvalidInput;
+ }
+
+ AMemoryHelper.Write(Context.Memory, OutputPosition, Args);
+
+ return NvResult.Success;
+ }
+
+ private static int GetId(ServiceCtx Context)
+ {
+ long InputPosition = Context.Request.GetBufferType0x21Position();
+ long OutputPosition = Context.Request.GetBufferType0x22Position();
+
+ NvMapGetId Args = AMemoryHelper.Read<NvMapGetId>(Context.Memory, InputPosition);
+
+ NvMapHandle Map = GetNvMap(Context, Args.Handle);
+
+ if (Map == null)
+ {
+ Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{Args.Handle:x8}!");
+
+ return NvResult.InvalidInput;
+ }
+
+ Args.Id = Args.Handle;
+
+ AMemoryHelper.Write(Context.Memory, OutputPosition, Args);
+
+ return NvResult.Success;
+ }
+
+ private static int AddNvMap(ServiceCtx Context, NvMapHandle Map)
+ {
+ IdDictionary Dict = Maps.GetOrAdd(Context.Process, (Key) =>
+ {
+ IdDictionary NewDict = new IdDictionary();
+
+ NewDict.Add(0, new NvMapHandle());
+
+ return NewDict;
+ });
+
+ return Dict.Add(Map);
+ }
+
+ private static bool DeleteNvMap(ServiceCtx Context, int Handle)
+ {
+ if (Maps.TryGetValue(Context.Process, out IdDictionary Dict))
+ {
+ return Dict.Delete(Handle) != null;
+ }
+
+ return false;
+ }
+
+ public static void InitializeNvMap(ServiceCtx Context)
+ {
+ IdDictionary Dict = Maps.GetOrAdd(Context.Process, (Key) =>new IdDictionary());
+
+ Dict.Add(0, new NvMapHandle());
+ }
+
+ public static NvMapHandle GetNvMapWithFb(ServiceCtx Context, int Handle)
+ {
+ if (Maps.TryGetValue(Context.Process, out IdDictionary Dict))
+ {
+ return Dict.GetData<NvMapHandle>(Handle);
+ }
+
+ return null;
+ }
+
+ public static NvMapHandle GetNvMap(ServiceCtx Context, int Handle)
+ {
+ if (Handle != 0 && Maps.TryGetValue(Context.Process, out IdDictionary Dict))
+ {
+ return Dict.GetData<NvMapHandle>(Handle);
+ }
+
+ return null;
+ }
+
+ public static void UnloadProcess(Process Process)
+ {
+ Maps.TryRemove(Process, out _);
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapParam.cs b/Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapParam.cs
new file mode 100644
index 00000000..196ef6ab
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Services/Nv/NvMap/NvMapParam.cs
@@ -0,0 +1,9 @@
+namespace Ryujinx.Core.OsHle.Services.Nv.NvMap
+{
+ struct NvMapParam
+ {
+ public int Handle;
+ public int Param;
+ public int Result;
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvMapFb.cs b/Ryujinx.Core/OsHle/Services/Nv/NvMapFb.cs
deleted file mode 100644
index d8a47418..00000000
--- a/Ryujinx.Core/OsHle/Services/Nv/NvMapFb.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-using System;
-using System.Collections.Generic;
-
-namespace Ryujinx.Core.OsHle.Services.Nv
-{
- class NvMapFb
- {
- private List<long> BufferOffs;
-
- public NvMapFb()
- {
- BufferOffs = new List<long>();
- }
-
- public void AddBufferOffset(long Offset)
- {
- BufferOffs.Add(Offset);
- }
-
- public bool HasBufferOffset(int Index)
- {
- if ((uint)Index >= BufferOffs.Count)
- {
- return false;
- }
-
- return true;
- }
-
- public long GetBufferOffset(int Index)
- {
- if ((uint)Index >= BufferOffs.Count)
- {
- throw new ArgumentOutOfRangeException(nameof(Index));
- }
-
- return BufferOffs[Index];
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvResult.cs b/Ryujinx.Core/OsHle/Services/Nv/NvResult.cs
new file mode 100644
index 00000000..5a419165
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Services/Nv/NvResult.cs
@@ -0,0 +1,13 @@
+namespace Ryujinx.Core.OsHle.Services.Nv
+{
+ static class NvResult
+ {
+ public const int Success = 0;
+ public const int TryAgain = -11;
+ public const int OutOfMemory = -12;
+ public const int InvalidInput = -22;
+ public const int NotSupported = -25;
+ public const int Restart = -85;
+ public const int TimedOut = -110;
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Services/Vi/NvFlinger.cs b/Ryujinx.Core/OsHle/Services/Vi/NvFlinger.cs
index 5aa3c3d5..db2f7fa2 100644
--- a/Ryujinx.Core/OsHle/Services/Vi/NvFlinger.cs
+++ b/Ryujinx.Core/OsHle/Services/Vi/NvFlinger.cs
@@ -1,9 +1,9 @@
using ChocolArm64.Memory;
+using Ryujinx.Core.Gpu;
using Ryujinx.Core.Logging;
using Ryujinx.Core.OsHle.Handles;
-using Ryujinx.Core.OsHle.Services.Nv;
+using Ryujinx.Core.OsHle.Services.Nv.NvMap;
using Ryujinx.Graphics.Gal;
-using Ryujinx.Graphics.Gpu;
using System;
using System.Collections.Generic;
using System.IO;
@@ -282,20 +282,12 @@ namespace Ryujinx.Core.OsHle.Services.Android
int FbWidth = 1280;
int FbHeight = 720;
- NvMap Map = GetNvMap(Context, Slot);
+ int NvMapHandle = BitConverter.ToInt32(BufferQueue[Slot].Data.RawData, 0x4c);
+ int BufferOffset = BitConverter.ToInt32(BufferQueue[Slot].Data.RawData, 0x50);
- NvMapFb MapFb = (NvMapFb)INvDrvServices.NvMapsFb.GetData(Context.Process, 0);
+ NvMapHandle Map = NvMapIoctl.GetNvMap(Context, NvMapHandle);;
- long CpuAddr = Map.CpuAddress;
- long GpuAddr = Map.GpuAddress;
-
- if (MapFb.HasBufferOffset(Slot))
- {
- CpuAddr += MapFb.GetBufferOffset(Slot);
-
- //TODO: Enable once the frame buffers problems are fixed.
- //GpuAddr += MapFb.GetBufferOffset(Slot);
- }
+ long FbAddr = Map.Address + BufferOffset;
BufferQueue[Slot].State = BufferState.Acquired;
@@ -352,17 +344,17 @@ namespace Ryujinx.Core.OsHle.Services.Android
//TODO: Support double buffering here aswell, it is broken for GPU
//frame buffers because it seems to be completely out of sync.
- if (Context.Ns.Gpu.Engine3d.IsFrameBufferPosition(GpuAddr))
+ if (Context.Ns.Gpu.Engine3d.IsFrameBufferPosition(FbAddr))
{
//Frame buffer is rendered to by the GPU, we can just
//bind the frame buffer texture, it's not necessary to read anything.
- Renderer.SetFrameBuffer(GpuAddr);
+ Renderer.SetFrameBuffer(FbAddr);
}
else
{
//Frame buffer is not set on the GPU registers, in this case
//assume that the app is manually writing to it.
- Texture Texture = new Texture(CpuAddr, FbWidth, FbHeight);
+ Texture Texture = new Texture(FbAddr, FbWidth, FbHeight);
byte[] Data = TextureReader.Read(Context.Memory, Texture);
@@ -372,22 +364,6 @@ namespace Ryujinx.Core.OsHle.Services.Android
Context.Ns.Gpu.Renderer.QueueAction(() => ReleaseBuffer(Slot));
}
- private NvMap GetNvMap(ServiceCtx Context, int Slot)
- {
- int NvMapHandle = BitConverter.ToInt32(BufferQueue[Slot].Data.RawData, 0x4c);
-
- if (!BitConverter.IsLittleEndian)
- {
- byte[] RawValue = BitConverter.GetBytes(NvMapHandle);
-
- Array.Reverse(RawValue);
-
- NvMapHandle = BitConverter.ToInt32(RawValue, 0);
- }
-
- return INvDrvServices.NvMaps.GetData<NvMap>(Context.Process, NvMapHandle);
- }
-
private void ReleaseBuffer(int Slot)
{
BufferQueue[Slot].State = BufferState.Free;
diff --git a/Ryujinx.Core/OsHle/Utilities/IntUtils.cs b/Ryujinx.Core/OsHle/Utilities/IntUtils.cs
new file mode 100644
index 00000000..4a522465
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Utilities/IntUtils.cs
@@ -0,0 +1,15 @@
+namespace Ryujinx.Core.OsHle.Utilities
+{
+ static class IntUtils
+ {
+ public static int RoundUp(int Value, int Size)
+ {
+ return (Value + (Size - 1)) & ~(Size - 1);
+ }
+
+ public static long RoundUp(long Value, int Size)
+ {
+ return (Value + (Size - 1)) & ~((long)Size - 1);
+ }
+ }
+}
diff --git a/Ryujinx.Core/OsHle/Utilities/MemReader.cs b/Ryujinx.Core/OsHle/Utilities/MemReader.cs
deleted file mode 100644
index fe92f68f..00000000
--- a/Ryujinx.Core/OsHle/Utilities/MemReader.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-using ChocolArm64.Memory;
-
-namespace Ryujinx.Core.OsHle.Utilities
-{
- class MemReader
- {
- private AMemory Memory;
-
- public long Position { get; private set; }
-
- public MemReader(AMemory Memory, long Position)
- {
- this.Memory = Memory;
- this.Position = Position;
- }
-
- public byte ReadByte()
- {
- byte Value = Memory.ReadByte(Position);
-
- Position++;
-
- return Value;
- }
-
- public int ReadInt32()
- {
- int Value = Memory.ReadInt32(Position);
-
- Position += 4;
-
- return Value;
- }
-
- public long ReadInt64()
- {
- long Value = Memory.ReadInt64(Position);
-
- Position += 8;
-
- return Value;
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Utilities/MemWriter.cs b/Ryujinx.Core/OsHle/Utilities/MemWriter.cs
deleted file mode 100644
index 21b6a3b6..00000000
--- a/Ryujinx.Core/OsHle/Utilities/MemWriter.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-using ChocolArm64.Memory;
-
-namespace Ryujinx.Core.OsHle.Utilities
-{
- class MemWriter
- {
- private AMemory Memory;
-
- public long Position { get; private set; }
-
- public MemWriter(AMemory Memory, long Position)
- {
- this.Memory = Memory;
- this.Position = Position;
- }
-
- public void WriteByte(byte Value)
- {
- Memory.WriteByte(Position, Value);
-
- Position++;
- }
-
- public void WriteInt32(int Value)
- {
- Memory.WriteInt32(Position, Value);
-
- Position += 4;
- }
-
- public void WriteInt64(long Value)
- {
- Memory.WriteInt64(Position, Value);
-
- Position += 8;
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Core/Switch.cs b/Ryujinx.Core/Switch.cs
index 02fdc8b6..a755ea0c 100644
--- a/Ryujinx.Core/Switch.cs
+++ b/Ryujinx.Core/Switch.cs
@@ -4,7 +4,7 @@ using Ryujinx.Core.Logging;
using Ryujinx.Core.OsHle;
using Ryujinx.Core.Settings;
using Ryujinx.Graphics.Gal;
-using Ryujinx.Graphics.Gpu;
+using Ryujinx.Core.Gpu;
using System;
namespace Ryujinx.Core
@@ -15,7 +15,7 @@ namespace Ryujinx.Core
public Logger Log { get; private set; }
- internal NsGpu Gpu { get; private set; }
+ internal NvGpu Gpu { get; private set; }
internal VirtualFileSystem VFs { get; private set; }
@@ -45,7 +45,7 @@ namespace Ryujinx.Core
Log = new Logger();
- Gpu = new NsGpu(Renderer);
+ Gpu = new NvGpu(Renderer);
VFs = new VirtualFileSystem();
diff --git a/Ryujinx.Graphics/Gpu/INvGpuEngine.cs b/Ryujinx.Graphics/Gpu/INvGpuEngine.cs
deleted file mode 100644
index 17e9b435..00000000
--- a/Ryujinx.Graphics/Gpu/INvGpuEngine.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-using ChocolArm64.Memory;
-
-namespace Ryujinx.Graphics.Gpu
-{
- interface INvGpuEngine
- {
- int[] Registers { get; }
-
- void CallMethod(AMemory Memory, NsGpuPBEntry PBEntry);
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Gpu/NsGpuMemoryMgr.cs b/Ryujinx.Graphics/Gpu/NsGpuMemoryMgr.cs
deleted file mode 100644
index eff51783..00000000
--- a/Ryujinx.Graphics/Gpu/NsGpuMemoryMgr.cs
+++ /dev/null
@@ -1,212 +0,0 @@
-namespace Ryujinx.Graphics.Gpu
-{
- public class NsGpuMemoryMgr
- {
- private const long AddrSize = 1L << 40;
-
- private const int PTLvl0Bits = 14;
- private const int PTLvl1Bits = 14;
- private const int PTPageBits = 12;
-
- private const int PTLvl0Size = 1 << PTLvl0Bits;
- private const int PTLvl1Size = 1 << PTLvl1Bits;
- private const int PageSize = 1 << PTPageBits;
-
- private const int PTLvl0Mask = PTLvl0Size - 1;
- private const int PTLvl1Mask = PTLvl1Size - 1;
- private const int PageMask = PageSize - 1;
-
- private const int PTLvl0Bit = PTPageBits + PTLvl1Bits;
- private const int PTLvl1Bit = PTPageBits;
-
- private const long PteUnmapped = -1;
- private const long PteReserved = -2;
-
- private long[][] PageTable;
-
- public NsGpuMemoryMgr()
- {
- PageTable = new long[PTLvl0Size][];
- }
-
- public long Map(long CpuAddr, long GpuAddr, long Size)
- {
- CpuAddr &= ~PageMask;
- GpuAddr &= ~PageMask;
-
- for (long Offset = 0; Offset < Size; Offset += PageSize)
- {
- if (GetPTAddr(GpuAddr + Offset) != PteReserved)
- {
- return Map(CpuAddr, Size);
- }
- }
-
- for (long Offset = 0; Offset < Size; Offset += PageSize)
- {
- SetPTAddr(GpuAddr + Offset, CpuAddr + Offset);
- }
-
- return GpuAddr;
- }
-
- public void Unmap(long Position, long Size)
- {
- for (long Offset = 0; Offset < Size; Offset += PageSize)
- {
- SetPTAddr(Position + Offset, PteUnmapped);
- }
- }
-
- public long Map(long CpuAddr, long Size)
- {
- CpuAddr &= ~PageMask;
-
- long Position = GetFreePosition(Size);
-
- if (Position != -1)
- {
- for (long Offset = 0; Offset < Size; Offset += PageSize)
- {
- SetPTAddr(Position + Offset, CpuAddr + Offset);
- }
- }
-
- return Position;
- }
-
- public long Reserve(long GpuAddr, long Size, long Align)
- {
- for (long Offset = 0; Offset < Size; Offset += PageSize)
- {
- if (HasPTAddr(GpuAddr + Offset))
- {
- return Reserve(Size, Align);
- }
- }
-
- for (long Offset = 0; Offset < Size; Offset += PageSize)
- {
- SetPTAddr(GpuAddr + Offset, PteReserved);
- }
-
- return GpuAddr;
- }
-
- public long Reserve(long Size, long Align)
- {
- long Position = GetFreePosition(Size, Align);
-
- if (Position != -1)
- {
- for (long Offset = 0; Offset < Size; Offset += PageSize)
- {
- SetPTAddr(Position + Offset, PteReserved);
- }
- }
-
- return Position;
- }
-
- private long GetFreePosition(long Size, long Align = 1)
- {
- long Position = 0;
- long FreeSize = 0;
-
- if (Align < 1)
- {
- Align = 1;
- }
-
- Align = (Align + PageMask) & ~PageMask;
-
- while (Position + FreeSize < AddrSize)
- {
- if (!HasPTAddr(Position + FreeSize))
- {
- FreeSize += PageSize;
-
- if (FreeSize >= Size)
- {
- return Position;
- }
- }
- else
- {
- Position += FreeSize + PageSize;
- FreeSize = 0;
-
- long Remainder = Position % Align;
-
- if (Remainder != 0)
- {
- Position = (Position - Remainder) + Align;
- }
- }
- }
-
- return -1;
- }
-
- public long GetCpuAddr(long Position)
- {
- long BasePos = GetPTAddr(Position);
-
- if (BasePos < 0)
- {
- return -1;
- }
-
- return BasePos + (Position & PageMask);
- }
-
- private bool HasPTAddr(long Position)
- {
- if (Position >> PTLvl0Bits + PTLvl1Bits + PTPageBits != 0)
- {
- return false;
- }
-
- long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask;
- long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask;
-
- if (PageTable[L0] == null)
- {
- return false;
- }
-
- return PageTable[L0][L1] != PteUnmapped;
- }
-
- private long GetPTAddr(long Position)
- {
- long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask;
- long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask;
-
- if (PageTable[L0] == null)
- {
- return -1;
- }
-
- return PageTable[L0][L1];
- }
-
- private void SetPTAddr(long Position, long TgtAddr)
- {
- long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask;
- long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask;
-
- if (PageTable[L0] == null)
- {
- PageTable[L0] = new long[PTLvl1Size];
-
- for (int Index = 0; Index < PTLvl1Size; Index++)
- {
- PageTable[L0][Index] = PteUnmapped;
- }
- }
-
- PageTable[L0][L1] = TgtAddr;
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Gpu/NvGpuMethod.cs b/Ryujinx.Graphics/Gpu/NvGpuMethod.cs
deleted file mode 100644
index 2923ddff..00000000
--- a/Ryujinx.Graphics/Gpu/NvGpuMethod.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-using ChocolArm64.Memory;
-
-namespace Ryujinx.Graphics.Gpu
-{
- delegate void NvGpuMethod(AMemory Memory, NsGpuPBEntry PBEntry);
-} \ No newline at end of file