NsGpuMemoryMgr.cs 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. namespace Ryujinx.Graphics.Gpu
  2. {
  3. 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 + PTLvl0Bits;
  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 long Map(long CpuAddr, long Size)
  42. {
  43. CpuAddr &= ~PageMask;
  44. long Position = GetFreePosition(Size);
  45. if (Position != -1)
  46. {
  47. for (long Offset = 0; Offset < Size; Offset += PageSize)
  48. {
  49. SetPTAddr(Position + Offset, CpuAddr + Offset);
  50. }
  51. }
  52. return Position;
  53. }
  54. public long Reserve(long GpuAddr, long Size, long Align)
  55. {
  56. for (long Offset = 0; Offset < Size; Offset += PageSize)
  57. {
  58. if (HasPTAddr(GpuAddr + Offset))
  59. {
  60. return Reserve(Size, Align);
  61. }
  62. }
  63. for (long Offset = 0; Offset < Size; Offset += PageSize)
  64. {
  65. SetPTAddr(GpuAddr + Offset, PteReserved);
  66. }
  67. return GpuAddr;
  68. }
  69. public long Reserve(long Size, long Align)
  70. {
  71. long Position = GetFreePosition(Size, Align);
  72. if (Position != -1)
  73. {
  74. for (long Offset = 0; Offset < Size; Offset += PageSize)
  75. {
  76. SetPTAddr(Position + Offset, PteReserved);
  77. }
  78. }
  79. return Position;
  80. }
  81. private long GetFreePosition(long Size, long Align = 1)
  82. {
  83. long Position = 0;
  84. long FreeSize = 0;
  85. if (Align < 1)
  86. {
  87. Align = 1;
  88. }
  89. Align = (Align + PageMask) & ~PageMask;
  90. while (Position + FreeSize < AddrSize)
  91. {
  92. if (!HasPTAddr(Position + FreeSize))
  93. {
  94. FreeSize += PageSize;
  95. if (FreeSize >= Size)
  96. {
  97. return Position;
  98. }
  99. }
  100. else
  101. {
  102. Position += FreeSize + PageSize;
  103. FreeSize = 0;
  104. long Remainder = Position % Align;
  105. if (Remainder != 0)
  106. {
  107. Position = (Position - Remainder) + Align;
  108. }
  109. }
  110. }
  111. return -1;
  112. }
  113. public long GetCpuAddr(long Position)
  114. {
  115. long BasePos = GetPTAddr(Position);
  116. if (BasePos < 0)
  117. {
  118. return -1;
  119. }
  120. return BasePos + (Position & PageMask);
  121. }
  122. private bool HasPTAddr(long Position)
  123. {
  124. if (Position >> PTLvl0Bits + PTLvl1Bits + PTPageBits != 0)
  125. {
  126. return false;
  127. }
  128. long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask;
  129. long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask;
  130. if (PageTable[L0] == null)
  131. {
  132. return false;
  133. }
  134. return PageTable[L0][L1] != PteUnmapped;
  135. }
  136. private long GetPTAddr(long Position)
  137. {
  138. long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask;
  139. long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask;
  140. if (PageTable[L0] == null)
  141. {
  142. return -1;
  143. }
  144. return PageTable[L0][L1];
  145. }
  146. private void SetPTAddr(long Position, long TgtAddr)
  147. {
  148. long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask;
  149. long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask;
  150. if (PageTable[L0] == null)
  151. {
  152. PageTable[L0] = new long[PTLvl1Size];
  153. for (int Index = 0; Index < PTLvl1Size; Index++)
  154. {
  155. PageTable[L0][Index] = PteUnmapped;
  156. }
  157. }
  158. PageTable[L0][L1] = TgtAddr;
  159. }
  160. }
  161. }