aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics/Gpu/NsGpuMemoryMgr.cs
diff options
context:
space:
mode:
authoremmauss <emmausssss@gmail.com>2018-02-20 22:09:23 +0200
committergdkchan <gab.dark.100@gmail.com>2018-02-20 17:09:23 -0300
commit62b827f474f0aa2152dd339fcc7cf31084e16a0b (patch)
tree0e5c55b341aee4db0ccb841a084f253ec5e05657 /Ryujinx.Graphics/Gpu/NsGpuMemoryMgr.cs
parentcb665bb715834526d73c9469d16114b287faaecd (diff)
Split main project into core,graphics and chocolarm4 subproject (#29)
Diffstat (limited to 'Ryujinx.Graphics/Gpu/NsGpuMemoryMgr.cs')
-rw-r--r--Ryujinx.Graphics/Gpu/NsGpuMemoryMgr.cs204
1 files changed, 204 insertions, 0 deletions
diff --git a/Ryujinx.Graphics/Gpu/NsGpuMemoryMgr.cs b/Ryujinx.Graphics/Gpu/NsGpuMemoryMgr.cs
new file mode 100644
index 00000000..54fabc67
--- /dev/null
+++ b/Ryujinx.Graphics/Gpu/NsGpuMemoryMgr.cs
@@ -0,0 +1,204 @@
+namespace Ryujinx.Graphics.Gpu
+{
+ 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 + PTLvl0Bits;
+ 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 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