mirror of
				https://github.com/Ryujinx/Ryujinx.git
				synced 2025-10-25 20:33:56 -07:00 
			
		
		
		
	* Initial test for texture sync * WIP new texture flushing setup * Improve rules for incompatible overlaps Fixes a lot of issues with Unreal Engine games. Still a few minor issues (some caused by dma fast path?) Needs docs and cleanup. * Cleanup, improvements Improve rules for fast DMA * Small tweak to group together flushes of overlapping handles. * Fixes, flush overlapping texture data for ASTC and BC4/5 compressed textures. Fixes the new Life is Strange game. * Flush overlaps before init data, fix 3d texture size/overlap stuff * Fix 3D Textures, faster single layer flush Note: nosy people can no longer merge this with Vulkan. (unless they are nosy enough to implement the new backend methods) * Remove unused method * Minor cleanup * More cleanup * Use the More Fun and Hopefully No Driver Bugs method for getting compressed tex too This one's for metro * Address feedback, ASTC+ETC to FormatClass * Change offset to use Span slice rather than IntPtr Add * Fix this too
		
			
				
	
	
		
			137 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			137 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using System;
 | |
| using System.Runtime.CompilerServices;
 | |
| using System.Runtime.InteropServices;
 | |
| using OpenTK.Graphics.OpenGL;
 | |
| using Ryujinx.Common.Logging;
 | |
| using Ryujinx.Graphics.GAL;
 | |
| using Ryujinx.Graphics.OpenGL.Image;
 | |
| 
 | |
| namespace Ryujinx.Graphics.OpenGL
 | |
| {
 | |
|     class PersistentBuffers : IDisposable
 | |
|     {
 | |
|         private PersistentBuffer _main = new PersistentBuffer();
 | |
|         private PersistentBuffer _background = new PersistentBuffer();
 | |
| 
 | |
|         public PersistentBuffer Default => BackgroundContextWorker.InBackground ? _background : _main;
 | |
| 
 | |
|         public void Dispose()
 | |
|         {
 | |
|             _main?.Dispose();
 | |
|             _background?.Dispose();
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     class PersistentBuffer : IDisposable
 | |
|     {
 | |
|         private IntPtr _bufferMap;
 | |
|         private int _copyBufferHandle;
 | |
|         private int _copyBufferSize;
 | |
| 
 | |
|         private byte[] _data;
 | |
|         private IntPtr _dataMap;
 | |
| 
 | |
|         private void EnsureBuffer(int requiredSize)
 | |
|         {
 | |
|             if (_copyBufferSize < requiredSize && _copyBufferHandle != 0)
 | |
|             {
 | |
|                 GL.DeleteBuffer(_copyBufferHandle);
 | |
| 
 | |
|                 _copyBufferHandle = 0;
 | |
|             }
 | |
| 
 | |
|             if (_copyBufferHandle == 0)
 | |
|             {
 | |
|                 _copyBufferHandle = GL.GenBuffer();
 | |
|                 _copyBufferSize = requiredSize;
 | |
| 
 | |
|                 GL.BindBuffer(BufferTarget.CopyWriteBuffer, _copyBufferHandle);
 | |
|                 GL.BufferStorage(BufferTarget.CopyWriteBuffer, requiredSize, IntPtr.Zero, BufferStorageFlags.MapReadBit | BufferStorageFlags.MapPersistentBit);
 | |
| 
 | |
|                 _bufferMap = GL.MapBufferRange(BufferTarget.CopyWriteBuffer, IntPtr.Zero, requiredSize, BufferAccessMask.MapReadBit | BufferAccessMask.MapPersistentBit);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public unsafe IntPtr GetHostArray(int requiredSize)
 | |
|         {
 | |
|             if (_data == null || _data.Length < requiredSize)
 | |
|             {
 | |
|                 _data = GC.AllocateUninitializedArray<byte>(requiredSize, true);
 | |
| 
 | |
|                 _dataMap = (IntPtr)Unsafe.AsPointer(ref MemoryMarshal.GetArrayDataReference(_data));
 | |
|             }
 | |
| 
 | |
|             return _dataMap;
 | |
|         }
 | |
| 
 | |
|         private void Sync()
 | |
|         {
 | |
|             GL.MemoryBarrier(MemoryBarrierFlags.ClientMappedBufferBarrierBit);
 | |
| 
 | |
|             IntPtr sync = GL.FenceSync(SyncCondition.SyncGpuCommandsComplete, WaitSyncFlags.None);
 | |
|             WaitSyncStatus syncResult = GL.ClientWaitSync(sync, ClientWaitSyncFlags.SyncFlushCommandsBit, 1000000000);
 | |
| 
 | |
|             if (syncResult == WaitSyncStatus.TimeoutExpired)
 | |
|             {
 | |
|                 Logger.Error?.PrintMsg(LogClass.Gpu, $"Failed to sync persistent buffer state within 1000ms. Continuing...");
 | |
|             }
 | |
| 
 | |
|             GL.DeleteSync(sync);
 | |
|         }
 | |
| 
 | |
|         public unsafe ReadOnlySpan<byte> GetTextureData(TextureView view, int size)
 | |
|         {
 | |
|             EnsureBuffer(size);
 | |
| 
 | |
|             GL.BindBuffer(BufferTarget.PixelPackBuffer, _copyBufferHandle);
 | |
| 
 | |
|             view.WriteToPbo(0, false);
 | |
| 
 | |
|             GL.BindBuffer(BufferTarget.PixelPackBuffer, 0);
 | |
| 
 | |
|             Sync();
 | |
| 
 | |
|             return new ReadOnlySpan<byte>(_bufferMap.ToPointer(), size);
 | |
|         }
 | |
| 
 | |
|         public unsafe ReadOnlySpan<byte> GetTextureData(TextureView view, int size, int layer, int level)
 | |
|         {
 | |
|             EnsureBuffer(size);
 | |
| 
 | |
|             GL.BindBuffer(BufferTarget.PixelPackBuffer, _copyBufferHandle);
 | |
| 
 | |
|             int offset = view.WriteToPbo2D(0, layer, level);
 | |
| 
 | |
|             GL.BindBuffer(BufferTarget.PixelPackBuffer, 0);
 | |
| 
 | |
|             Sync();
 | |
| 
 | |
|             return new ReadOnlySpan<byte>(_bufferMap.ToPointer(), size).Slice(offset);
 | |
|         }
 | |
| 
 | |
|         public unsafe ReadOnlySpan<byte> GetBufferData(BufferHandle buffer, int offset, int size)
 | |
|         {
 | |
|             EnsureBuffer(size);
 | |
| 
 | |
|             GL.BindBuffer(BufferTarget.CopyReadBuffer, buffer.ToInt32());
 | |
|             GL.BindBuffer(BufferTarget.CopyWriteBuffer, _copyBufferHandle);
 | |
| 
 | |
|             GL.CopyBufferSubData(BufferTarget.CopyReadBuffer, BufferTarget.CopyWriteBuffer, (IntPtr)offset, IntPtr.Zero, size);
 | |
| 
 | |
|             GL.BindBuffer(BufferTarget.CopyWriteBuffer, 0);
 | |
| 
 | |
|             Sync();
 | |
| 
 | |
|             return new ReadOnlySpan<byte>(_bufferMap.ToPointer(), size);
 | |
|         }
 | |
| 
 | |
|         public void Dispose()
 | |
|         {
 | |
|             if (_copyBufferHandle != 0)
 | |
|             {
 | |
|                 GL.DeleteBuffer(_copyBufferHandle);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 |