PersistentBuffers.cs 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  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> GetBufferData(BufferHandle buffer, int offset, int size)
  74. {
  75. EnsureBuffer(size);
  76. GL.BindBuffer(BufferTarget.CopyReadBuffer, buffer.ToInt32());
  77. GL.BindBuffer(BufferTarget.CopyWriteBuffer, _copyBufferHandle);
  78. GL.CopyBufferSubData(BufferTarget.CopyReadBuffer, BufferTarget.CopyWriteBuffer, (IntPtr)offset, IntPtr.Zero, size);
  79. GL.BindBuffer(BufferTarget.CopyWriteBuffer, 0);
  80. Sync();
  81. return new ReadOnlySpan<byte>(_bufferMap.ToPointer(), size);
  82. }
  83. public void Dispose()
  84. {
  85. if (_copyBufferHandle != 0)
  86. {
  87. GL.DeleteBuffer(_copyBufferHandle);
  88. }
  89. }
  90. }
  91. }