Buffer.cs 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  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<Buffer>, IDisposable
  9. {
  10. private GpuContext _context;
  11. private IBuffer _buffer;
  12. /// <summary>
  13. /// Host buffer object.
  14. /// </summary>
  15. public IBuffer HostBuffer => _buffer;
  16. /// <summary>
  17. /// Start address of the buffer in guest memory.
  18. /// </summary>
  19. public ulong Address { get; }
  20. /// <summary>
  21. /// Size of the buffer in bytes.
  22. /// </summary>
  23. public ulong Size { get; }
  24. /// <summary>
  25. /// End address of the buffer in guest memory.
  26. /// </summary>
  27. public ulong EndAddress => Address + Size;
  28. private int[] _sequenceNumbers;
  29. /// <summary>
  30. /// Creates a new instance of the buffer.
  31. /// </summary>
  32. /// <param name="context">GPU context that the buffer belongs to</param>
  33. /// <param name="address">Start address of the buffer</param>
  34. /// <param name="size">Size of the buffer in bytes</param>
  35. public Buffer(GpuContext context, ulong address, ulong size)
  36. {
  37. _context = context;
  38. Address = address;
  39. Size = size;
  40. _buffer = context.Renderer.CreateBuffer((int)size);
  41. _sequenceNumbers = new int[size / MemoryManager.PageSize];
  42. Invalidate();
  43. }
  44. /// <summary>
  45. /// Gets a sub-range from the buffer.
  46. /// This can be used to bind and use sub-ranges of the buffer on the host API.
  47. /// </summary>
  48. /// <param name="address">Start address of the sub-range, must be greater 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(_buffer, 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. /// This causes the buffer data to be overwritten if a write was detected from the CPU,
  69. /// since the last call to this method.
  70. /// </summary>
  71. /// <param name="address">Start address of the range to synchronize</param>
  72. /// <param name="size">Size in bytes of the range to synchronize</param>
  73. public void SynchronizeMemory(ulong address, ulong size)
  74. {
  75. int currentSequenceNumber = _context.SequenceNumber;
  76. bool needsSync = false;
  77. ulong buffOffset = address - Address;
  78. ulong buffEndOffset = (buffOffset + size + MemoryManager.PageMask) & ~MemoryManager.PageMask;
  79. int startIndex = (int)(buffOffset / MemoryManager.PageSize);
  80. int endIndex = (int)(buffEndOffset / MemoryManager.PageSize);
  81. for (int index = startIndex; index < endIndex; index++)
  82. {
  83. if (_sequenceNumbers[index] != currentSequenceNumber)
  84. {
  85. _sequenceNumbers[index] = currentSequenceNumber;
  86. needsSync = true;
  87. }
  88. }
  89. if (!needsSync)
  90. {
  91. return;
  92. }
  93. (ulong, ulong)[] modifiedRanges = _context.PhysicalMemory.GetModifiedRanges(address, size, ResourceName.Buffer);
  94. for (int index = 0; index < modifiedRanges.Length; index++)
  95. {
  96. (ulong mAddress, ulong mSize) = modifiedRanges[index];
  97. int offset = (int)(mAddress - Address);
  98. _buffer.SetData(offset, _context.PhysicalMemory.Read(mAddress, mSize));
  99. }
  100. }
  101. /// <summary>
  102. /// Performs copy of all the buffer data from one buffer to another.
  103. /// </summary>
  104. /// <param name="destination">The destination buffer to copy the data into</param>
  105. /// <param name="dstOffset">The offset of the destination buffer to copy into</param>
  106. public void CopyTo(Buffer destination, int dstOffset)
  107. {
  108. _buffer.CopyTo(destination._buffer, 0, dstOffset, (int)Size);
  109. }
  110. /// <summary>
  111. /// Flushes a range of the buffer.
  112. /// This writes the range data back into guest memory.
  113. /// </summary>
  114. /// <param name="address">Start address of the range</param>
  115. /// <param name="size">Size in bytes of the range</param>
  116. public void Flush(ulong address, ulong size)
  117. {
  118. int offset = (int)(address - Address);
  119. byte[] data = _buffer.GetData(offset, (int)size);
  120. _context.PhysicalMemory.Write(address, data);
  121. }
  122. /// <summary>
  123. /// Invalidates all the buffer data, causing it to be read from guest memory.
  124. /// </summary>
  125. public void Invalidate()
  126. {
  127. _buffer.SetData(0, _context.PhysicalMemory.Read(Address, Size));
  128. }
  129. /// <summary>
  130. /// Disposes the host buffer.
  131. /// </summary>
  132. public void Dispose()
  133. {
  134. _buffer.Dispose();
  135. }
  136. }
  137. }