NsGpuMemoryMgr.cs 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. namespace Ryujinx.Graphics.Gpu
  2. {
  3. public class NsGpuMemoryMgr
  4. {
  5. private const long AddrSize = 1L << 40;
  6. private const int PTLvl0Bits = 14;
  7. private const int PTLvl1Bits = 14;
  8. private const int PTPageBits = 12;
  9. private const int PTLvl0Size = 1 << PTLvl0Bits;
  10. private const int PTLvl1Size = 1 << PTLvl1Bits;
  11. private const int PageSize = 1 << PTPageBits;
  12. private const int PTLvl0Mask = PTLvl0Size - 1;
  13. private const int PTLvl1Mask = PTLvl1Size - 1;
  14. private const int PageMask = PageSize - 1;
  15. private const int PTLvl0Bit = PTPageBits + PTLvl1Bits;
  16. private const int PTLvl1Bit = PTPageBits;
  17. private const long PteUnmapped = -1;
  18. private const long PteReserved = -2;
  19. private long[][] PageTable;
  20. public NsGpuMemoryMgr()
  21. {
  22. PageTable = new long[PTLvl0Size][];
  23. }
  24. public long Map(long CpuAddr, long GpuAddr, long Size)
  25. {
  26. CpuAddr &= ~PageMask;
  27. GpuAddr &= ~PageMask;
  28. for (long Offset = 0; Offset < Size; Offset += PageSize)
  29. {
  30. if (GetPTAddr(GpuAddr + Offset) != PteReserved)
  31. {
  32. return Map(CpuAddr, Size);
  33. }
  34. }
  35. for (long Offset = 0; Offset < Size; Offset += PageSize)
  36. {
  37. SetPTAddr(GpuAddr + Offset, CpuAddr + Offset);
  38. }
  39. return GpuAddr;
  40. }
  41. public void Unmap(long Position, long Size)
  42. {
  43. for (long Offset = 0; Offset < Size; Offset += PageSize)
  44. {
  45. SetPTAddr(Position + Offset, PteUnmapped);
  46. }
  47. }
  48. public long Map(long CpuAddr, long Size)
  49. {
  50. CpuAddr &= ~PageMask;
  51. long Position = GetFreePosition(Size);
  52. if (Position != -1)
  53. {
  54. for (long Offset = 0; Offset < Size; Offset += PageSize)
  55. {
  56. SetPTAddr(Position + Offset, CpuAddr + Offset);
  57. }
  58. }
  59. return Position;
  60. }
  61. public long Reserve(long GpuAddr, long Size, long Align)
  62. {
  63. for (long Offset = 0; Offset < Size; Offset += PageSize)
  64. {
  65. if (HasPTAddr(GpuAddr + Offset))
  66. {
  67. return Reserve(Size, Align);
  68. }
  69. }
  70. for (long Offset = 0; Offset < Size; Offset += PageSize)
  71. {
  72. SetPTAddr(GpuAddr + Offset, PteReserved);
  73. }
  74. return GpuAddr;
  75. }
  76. public long Reserve(long Size, long Align)
  77. {
  78. long Position = GetFreePosition(Size, Align);
  79. if (Position != -1)
  80. {
  81. for (long Offset = 0; Offset < Size; Offset += PageSize)
  82. {
  83. SetPTAddr(Position + Offset, PteReserved);
  84. }
  85. }
  86. return Position;
  87. }
  88. private long GetFreePosition(long Size, long Align = 1)
  89. {
  90. long Position = 0;
  91. long FreeSize = 0;
  92. if (Align < 1)
  93. {
  94. Align = 1;
  95. }
  96. Align = (Align + PageMask) & ~PageMask;
  97. while (Position + FreeSize < AddrSize)
  98. {
  99. if (!HasPTAddr(Position + FreeSize))
  100. {
  101. FreeSize += PageSize;
  102. if (FreeSize >= Size)
  103. {
  104. return Position;
  105. }
  106. }
  107. else
  108. {
  109. Position += FreeSize + PageSize;
  110. FreeSize = 0;
  111. long Remainder = Position % Align;
  112. if (Remainder != 0)
  113. {
  114. Position = (Position - Remainder) + Align;
  115. }
  116. }
  117. }
  118. return -1;
  119. }
  120. public long GetCpuAddr(long Position)
  121. {
  122. long BasePos = GetPTAddr(Position);
  123. if (BasePos < 0)
  124. {
  125. return -1;
  126. }
  127. return BasePos + (Position & PageMask);
  128. }
  129. private bool HasPTAddr(long Position)
  130. {
  131. if (Position >> PTLvl0Bits + PTLvl1Bits + PTPageBits != 0)
  132. {
  133. return false;
  134. }
  135. long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask;
  136. long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask;
  137. if (PageTable[L0] == null)
  138. {
  139. return false;
  140. }
  141. return PageTable[L0][L1] != PteUnmapped;
  142. }
  143. private long GetPTAddr(long Position)
  144. {
  145. long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask;
  146. long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask;
  147. if (PageTable[L0] == null)
  148. {
  149. return -1;
  150. }
  151. return PageTable[L0][L1];
  152. }
  153. private void SetPTAddr(long Position, long TgtAddr)
  154. {
  155. long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask;
  156. long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask;
  157. if (PageTable[L0] == null)
  158. {
  159. PageTable[L0] = new long[PTLvl1Size];
  160. for (int Index = 0; Index < PTLvl1Size; Index++)
  161. {
  162. PageTable[L0][Index] = PteUnmapped;
  163. }
  164. }
  165. PageTable[L0][L1] = TgtAddr;
  166. }
  167. }
  168. }