Buffer.cs 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  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. }
  42. /// <summary>
  43. /// Gets a sub-range from the buffer.
  44. /// </summary>
  45. /// <remarks>
  46. /// This can be used to bind and use sub-ranges of the buffer on the host API.
  47. /// </remarks>
  48. /// <param name="address">Start address of the sub-range, must be greater than or equal to the buffer address</param>
  49. /// <param name="size">Size in bytes of the sub-range, must be less than or equal to the buffer size</param>
  50. /// <returns>The buffer sub-range</returns>
  51. public BufferRange GetRange(ulong address, ulong size)
  52. {
  53. int offset = (int)(address - Address);
  54. return new BufferRange(HostBuffer, offset, (int)size);
  55. }
  56. /// <summary>
  57. /// Checks if a given range overlaps with the buffer.
  58. /// </summary>
  59. /// <param name="address">Start address of the range</param>
  60. /// <param name="size">Size in bytes of the range</param>
  61. /// <returns>True if the range overlaps, false otherwise</returns>
  62. public bool OverlapsWith(ulong address, ulong size)
  63. {
  64. return Address < address + size && address < EndAddress;
  65. }
  66. /// <summary>
  67. /// Performs guest to host memory synchronization of the buffer data.
  68. /// </summary>
  69. /// <remarks>
  70. /// This causes the buffer data to be overwritten if a write was detected from the CPU,
  71. /// since the last call to this method.
  72. /// </remarks>
  73. /// <param name="address">Start address of the range to synchronize</param>
  74. /// <param name="size">Size in bytes of the range to synchronize</param>
  75. public void SynchronizeMemory(ulong address, ulong size)
  76. {
  77. int currentSequenceNumber = _context.SequenceNumber;
  78. bool needsSync = false;
  79. ulong buffOffset = address - Address;
  80. ulong buffEndOffset = (buffOffset + size + MemoryManager.PageMask) & ~MemoryManager.PageMask;
  81. int startIndex = (int)(buffOffset / MemoryManager.PageSize);
  82. int endIndex = (int)(buffEndOffset / MemoryManager.PageSize);
  83. for (int index = startIndex; index < endIndex; index++)
  84. {
  85. if (_sequenceNumbers[index] != currentSequenceNumber)
  86. {
  87. _sequenceNumbers[index] = currentSequenceNumber;
  88. needsSync = true;
  89. }
  90. }
  91. if (!needsSync)
  92. {
  93. return;
  94. }
  95. (ulong, ulong)[] modifiedRanges = _context.PhysicalMemory.GetModifiedRanges(address, size, ResourceName.Buffer);
  96. for (int index = 0; index < modifiedRanges.Length; index++)
  97. {
  98. (ulong mAddress, ulong mSize) = modifiedRanges[index];
  99. int offset = (int)(mAddress - Address);
  100. HostBuffer.SetData(offset, _context.PhysicalMemory.GetSpan(mAddress, mSize));
  101. }
  102. }
  103. /// <summary>
  104. /// Performs copy of all the buffer data from one buffer to another.
  105. /// </summary>
  106. /// <param name="destination">The destination buffer to copy the data into</param>
  107. /// <param name="dstOffset">The offset of the destination buffer to copy into</param>
  108. public void CopyTo(Buffer destination, int dstOffset)
  109. {
  110. HostBuffer.CopyTo(destination.HostBuffer, 0, dstOffset, (int)Size);
  111. }
  112. /// <summary>
  113. /// Flushes a range of the buffer.
  114. /// This writes the range data back into guest memory.
  115. /// </summary>
  116. /// <param name="address">Start address of the range</param>
  117. /// <param name="size">Size in bytes of the range</param>
  118. public void Flush(ulong address, ulong size)
  119. {
  120. int offset = (int)(address - Address);
  121. byte[] data = HostBuffer.GetData(offset, (int)size);
  122. _context.PhysicalMemory.Write(address, data);
  123. }
  124. /// <summary>
  125. /// Disposes the host buffer.
  126. /// </summary>
  127. public void Dispose()
  128. {
  129. HostBuffer.Dispose();
  130. }
  131. }
  132. }