Buffer.cs 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. using Ryujinx.Graphics.GAL;
  2. using System;
  3. namespace Ryujinx.Graphics.Gpu.Memory
  4. {
  5. /// <summary>
  6. /// Buffer, used to store vertex and index data, uniform and storage buffers, and others.
  7. /// </summary>
  8. class Buffer : IRange, IDisposable
  9. {
  10. private readonly GpuContext _context;
  11. /// <summary>
  12. /// Host buffer object.
  13. /// </summary>
  14. public IBuffer HostBuffer { get; }
  15. /// <summary>
  16. /// Start address of the buffer in guest memory.
  17. /// </summary>
  18. public ulong Address { get; }
  19. /// <summary>
  20. /// Size of the buffer in bytes.
  21. /// </summary>
  22. public ulong Size { get; }
  23. /// <summary>
  24. /// End address of the buffer in guest memory.
  25. /// </summary>
  26. public ulong EndAddress => Address + Size;
  27. private int[] _sequenceNumbers;
  28. /// <summary>
  29. /// Creates a new instance of the buffer.
  30. /// </summary>
  31. /// <param name="context">GPU context that the buffer belongs to</param>
  32. /// <param name="address">Start address of the buffer</param>
  33. /// <param name="size">Size of the buffer in bytes</param>
  34. public Buffer(GpuContext context, ulong address, ulong size)
  35. {
  36. _context = context;
  37. Address = address;
  38. Size = size;
  39. HostBuffer = context.Renderer.CreateBuffer((int)size);
  40. _sequenceNumbers = new int[size / MemoryManager.PageSize];
  41. Invalidate();
  42. }
  43. /// <summary>
  44. /// Gets a sub-range from the buffer.
  45. /// This can be used to bind and use sub-ranges of the buffer on the host API.
  46. /// </summary>
  47. /// <param name="address">Start address of the sub-range, must be greater or equal to the buffer address</param>
  48. /// <param name="size">Size in bytes of the sub-range, must be less than or equal to the buffer size</param>
  49. /// <returns>The buffer sub-range</returns>
  50. public BufferRange GetRange(ulong address, ulong size)
  51. {
  52. int offset = (int)(address - Address);
  53. return new BufferRange(HostBuffer, offset, (int)size);
  54. }
  55. /// <summary>
  56. /// Checks if a given range overlaps with the buffer.
  57. /// </summary>
  58. /// <param name="address">Start address of the range</param>
  59. /// <param name="size">Size in bytes of the range</param>
  60. /// <returns>True if the range overlaps, false otherwise</returns>
  61. public bool OverlapsWith(ulong address, ulong size)
  62. {
  63. return Address < address + size && address < EndAddress;
  64. }
  65. /// <summary>
  66. /// Performs guest to host memory synchronization of the buffer data.
  67. /// This causes the buffer data to be overwritten if a write was detected from the CPU,
  68. /// since the last call to this method.
  69. /// </summary>
  70. /// <param name="address">Start address of the range to synchronize</param>
  71. /// <param name="size">Size in bytes of the range to synchronize</param>
  72. public void SynchronizeMemory(ulong address, ulong size)
  73. {
  74. int currentSequenceNumber = _context.SequenceNumber;
  75. bool needsSync = false;
  76. ulong buffOffset = address - Address;
  77. ulong buffEndOffset = (buffOffset + size + MemoryManager.PageMask) & ~MemoryManager.PageMask;
  78. int startIndex = (int)(buffOffset / MemoryManager.PageSize);
  79. int endIndex = (int)(buffEndOffset / MemoryManager.PageSize);
  80. for (int index = startIndex; index < endIndex; index++)
  81. {
  82. if (_sequenceNumbers[index] != currentSequenceNumber)
  83. {
  84. _sequenceNumbers[index] = currentSequenceNumber;
  85. needsSync = true;
  86. }
  87. }
  88. if (!needsSync)
  89. {
  90. return;
  91. }
  92. (ulong, ulong)[] modifiedRanges = _context.PhysicalMemory.GetModifiedRanges(address, size, ResourceName.Buffer);
  93. for (int index = 0; index < modifiedRanges.Length; index++)
  94. {
  95. (ulong mAddress, ulong mSize) = modifiedRanges[index];
  96. int offset = (int)(mAddress - Address);
  97. HostBuffer.SetData(offset, _context.PhysicalMemory.Read(mAddress, mSize));
  98. }
  99. }
  100. /// <summary>
  101. /// Performs copy of all the buffer data from one buffer to another.
  102. /// </summary>
  103. /// <param name="destination">The destination buffer to copy the data into</param>
  104. /// <param name="dstOffset">The offset of the destination buffer to copy into</param>
  105. public void CopyTo(Buffer destination, int dstOffset)
  106. {
  107. HostBuffer.CopyTo(destination.HostBuffer, 0, dstOffset, (int)Size);
  108. }
  109. /// <summary>
  110. /// Flushes a range of the buffer.
  111. /// This writes the range data back into guest memory.
  112. /// </summary>
  113. /// <param name="address">Start address of the range</param>
  114. /// <param name="size">Size in bytes of the range</param>
  115. public void Flush(ulong address, ulong size)
  116. {
  117. int offset = (int)(address - Address);
  118. byte[] data = HostBuffer.GetData(offset, (int)size);
  119. _context.PhysicalMemory.Write(address, data);
  120. }
  121. /// <summary>
  122. /// Invalidates all the buffer data, causing it to be read from guest memory.
  123. /// </summary>
  124. public void Invalidate()
  125. {
  126. HostBuffer.SetData(0, _context.PhysicalMemory.Read(Address, Size));
  127. }
  128. /// <summary>
  129. /// Disposes the host buffer.
  130. /// </summary>
  131. public void Dispose()
  132. {
  133. HostBuffer.Dispose();
  134. }
  135. }
  136. }