PersistentBuffers.cs 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. using System;
  2. using System.Runtime.CompilerServices;
  3. using System.Runtime.InteropServices;
  4. using OpenTK.Graphics.OpenGL;
  5. using Ryujinx.Common.Logging;
  6. using Ryujinx.Graphics.GAL;
  7. using Ryujinx.Graphics.OpenGL.Image;
  8. namespace Ryujinx.Graphics.OpenGL
  9. {
  10. class PersistentBuffers : IDisposable
  11. {
  12. private PersistentBuffer _main = new PersistentBuffer();
  13. private PersistentBuffer _background = new PersistentBuffer();
  14. public PersistentBuffer Default => BackgroundContextWorker.InBackground ? _background : _main;
  15. public void Dispose()
  16. {
  17. _main?.Dispose();
  18. _background?.Dispose();
  19. }
  20. }
  21. class PersistentBuffer : IDisposable
  22. {
  23. private IntPtr _bufferMap;
  24. private int _copyBufferHandle;
  25. private int _copyBufferSize;
  26. private byte[] _data;
  27. private IntPtr _dataMap;
  28. private void EnsureBuffer(int requiredSize)
  29. {
  30. if (_copyBufferSize < requiredSize && _copyBufferHandle != 0)
  31. {
  32. GL.DeleteBuffer(_copyBufferHandle);
  33. _copyBufferHandle = 0;
  34. }
  35. if (_copyBufferHandle == 0)
  36. {
  37. _copyBufferHandle = GL.GenBuffer();
  38. _copyBufferSize = requiredSize;
  39. GL.BindBuffer(BufferTarget.CopyWriteBuffer, _copyBufferHandle);
  40. GL.BufferStorage(BufferTarget.CopyWriteBuffer, requiredSize, IntPtr.Zero, BufferStorageFlags.MapReadBit | BufferStorageFlags.MapPersistentBit);
  41. _bufferMap = GL.MapBufferRange(BufferTarget.CopyWriteBuffer, IntPtr.Zero, requiredSize, BufferAccessMask.MapReadBit | BufferAccessMask.MapPersistentBit);
  42. }
  43. }
  44. public unsafe IntPtr GetHostArray(int requiredSize)
  45. {
  46. if (_data == null || _data.Length < requiredSize)
  47. {
  48. _data = GC.AllocateUninitializedArray<byte>(requiredSize, true);
  49. _dataMap = (IntPtr)Unsafe.AsPointer(ref MemoryMarshal.GetArrayDataReference(_data));
  50. }
  51. return _dataMap;
  52. }
  53. private void Sync()
  54. {
  55. GL.MemoryBarrier(MemoryBarrierFlags.ClientMappedBufferBarrierBit);
  56. IntPtr sync = GL.FenceSync(SyncCondition.SyncGpuCommandsComplete, WaitSyncFlags.None);
  57. WaitSyncStatus syncResult = GL.ClientWaitSync(sync, ClientWaitSyncFlags.SyncFlushCommandsBit, 1000000000);
  58. if (syncResult == WaitSyncStatus.TimeoutExpired)
  59. {
  60. Logger.Error?.PrintMsg(LogClass.Gpu, $"Failed to sync persistent buffer state within 1000ms. Continuing...");
  61. }
  62. GL.DeleteSync(sync);
  63. }
  64. public unsafe ReadOnlySpan<byte> GetTextureData(TextureView view, int size)
  65. {
  66. EnsureBuffer(size);
  67. GL.BindBuffer(BufferTarget.PixelPackBuffer, _copyBufferHandle);
  68. view.WriteToPbo(0, false);
  69. GL.BindBuffer(BufferTarget.PixelPackBuffer, 0);
  70. Sync();
  71. return new ReadOnlySpan<byte>(_bufferMap.ToPointer(), size);
  72. }
  73. public unsafe ReadOnlySpan<byte> GetTextureData(TextureView view, int size, int layer, int level)
  74. {
  75. EnsureBuffer(size);
  76. GL.BindBuffer(BufferTarget.PixelPackBuffer, _copyBufferHandle);
  77. int offset = view.WriteToPbo2D(0, layer, level);
  78. GL.BindBuffer(BufferTarget.PixelPackBuffer, 0);
  79. Sync();
  80. return new ReadOnlySpan<byte>(_bufferMap.ToPointer(), size).Slice(offset);
  81. }
  82. public unsafe ReadOnlySpan<byte> GetBufferData(BufferHandle buffer, int offset, int size)
  83. {
  84. EnsureBuffer(size);
  85. GL.BindBuffer(BufferTarget.CopyReadBuffer, buffer.ToInt32());
  86. GL.BindBuffer(BufferTarget.CopyWriteBuffer, _copyBufferHandle);
  87. GL.CopyBufferSubData(BufferTarget.CopyReadBuffer, BufferTarget.CopyWriteBuffer, (IntPtr)offset, IntPtr.Zero, size);
  88. GL.BindBuffer(BufferTarget.CopyWriteBuffer, 0);
  89. Sync();
  90. return new ReadOnlySpan<byte>(_bufferMap.ToPointer(), size);
  91. }
  92. public void Dispose()
  93. {
  94. if (_copyBufferHandle != 0)
  95. {
  96. GL.DeleteBuffer(_copyBufferHandle);
  97. }
  98. }
  99. }
  100. }