GpuChannel.cs
1 using Ryujinx.Graphics.GAL; 2 using Ryujinx.Graphics.Gpu.Engine.GPFifo; 3 using Ryujinx.Graphics.Gpu.Image; 4 using Ryujinx.Graphics.Gpu.Memory; 5 using System; 6 using System.Threading; 7 8 namespace Ryujinx.Graphics.Gpu 9 { 10 /// <summary> 11 /// Represents a GPU channel. 12 /// </summary> 13 public class GpuChannel : IDisposable 14 { 15 private readonly GpuContext _context; 16 private readonly GPFifoDevice _device; 17 private readonly GPFifoProcessor _processor; 18 private MemoryManager _memoryManager; 19 20 /// <summary> 21 /// Channel buffer bindings manager. 22 /// </summary> 23 internal BufferManager BufferManager { get; } 24 25 /// <summary> 26 /// Channel texture bindings manager. 27 /// </summary> 28 internal TextureManager TextureManager { get; } 29 30 /// <summary> 31 /// Current channel memory manager. 32 /// </summary> 33 internal MemoryManager MemoryManager => _memoryManager; 34 35 /// <summary> 36 /// Host hardware capabilities from the GPU context. 37 /// </summary> 38 internal ref Capabilities Capabilities => ref _context.Capabilities; 39 40 /// <summary> 41 /// Creates a new instance of a GPU channel. 42 /// </summary> 43 /// <param name="context">GPU context that the channel belongs to</param> 44 internal GpuChannel(GpuContext context) 45 { 46 _context = context; 47 _device = context.GPFifo; 48 _processor = new GPFifoProcessor(context, this); 49 BufferManager = new BufferManager(context, this); 50 TextureManager = new TextureManager(context, this); 51 } 52 53 /// <summary> 54 /// Binds a memory manager to the channel. 55 /// All submitted and in-flight commands will use the specified memory manager for any memory operations. 56 /// </summary> 57 /// <param name="memoryManager">The new memory manager to be bound</param> 58 public void BindMemory(MemoryManager memoryManager) 59 { 60 var oldMemoryManager = Interlocked.Exchange(ref _memoryManager, memoryManager ?? throw new ArgumentNullException(nameof(memoryManager))); 61 62 memoryManager.Physical.IncrementReferenceCount(); 63 64 if (oldMemoryManager != null) 65 { 66 oldMemoryManager.Physical.BufferCache.NotifyBuffersModified -= BufferManager.Rebind; 67 oldMemoryManager.Physical.DecrementReferenceCount(); 68 oldMemoryManager.MemoryUnmapped -= MemoryUnmappedHandler; 69 } 70 71 memoryManager.Physical.BufferCache.NotifyBuffersModified += BufferManager.Rebind; 72 memoryManager.MemoryUnmapped += MemoryUnmappedHandler; 73 74 // Since the memory manager changed, make sure we will get pools from addresses of the new memory manager. 75 TextureManager.ReloadPools(); 76 memoryManager.Physical.BufferCache.QueuePrune(); 77 } 78 79 /// <summary> 80 /// Memory mappings change event handler. 81 /// </summary> 82 /// <param name="sender">Memory manager where the mappings changed</param> 83 /// <param name="e">Information about the region that is being changed</param> 84 private void MemoryUnmappedHandler(object sender, UnmapEventArgs e) 85 { 86 TextureManager.ReloadPools(); 87 88 var memoryManager = Volatile.Read(ref _memoryManager); 89 memoryManager?.Physical.BufferCache.QueuePrune(); 90 } 91 92 /// <summary> 93 /// Writes data directly to the state of the specified class. 94 /// </summary> 95 /// <param name="classId">ID of the class to write the data into</param> 96 /// <param name="offset">State offset in bytes</param> 97 /// <param name="value">Value to be written</param> 98 public void Write(ClassId classId, int offset, uint value) 99 { 100 _processor.Write(classId, offset, (int)value); 101 } 102 103 /// <summary> 104 /// Push a GPFIFO entry in the form of a prefetched command buffer. 105 /// It is intended to be used by nvservices to handle special cases. 106 /// </summary> 107 /// <param name="commandBuffer">The command buffer containing the prefetched commands</param> 108 public void PushHostCommandBuffer(int[] commandBuffer) 109 { 110 _device.PushHostCommandBuffer(_processor, commandBuffer); 111 } 112 113 /// <summary> 114 /// Pushes GPFIFO entries. 115 /// </summary> 116 /// <param name="entries">GPFIFO entries</param> 117 public void PushEntries(ReadOnlySpan<ulong> entries) 118 { 119 _device.PushEntries(_processor, entries); 120 } 121 122 /// <summary> 123 /// Disposes the GPU channel. 124 /// It's an error to use the GPU channel after disposal. 125 /// </summary> 126 public void Dispose() 127 { 128 GC.SuppressFinalize(this); 129 _context.DeferredActions.Enqueue(Destroy); 130 } 131 132 /// <summary> 133 /// Performs disposal of the host GPU resources used by this channel, that are not shared. 134 /// This must only be called from the render thread. 135 /// </summary> 136 private void Destroy() 137 { 138 _processor.Dispose(); 139 TextureManager.Dispose(); 140 141 var oldMemoryManager = Interlocked.Exchange(ref _memoryManager, null); 142 if (oldMemoryManager != null) 143 { 144 oldMemoryManager.Physical.BufferCache.NotifyBuffersModified -= BufferManager.Rebind; 145 oldMemoryManager.Physical.DecrementReferenceCount(); 146 oldMemoryManager.MemoryUnmapped -= MemoryUnmappedHandler; 147 } 148 } 149 } 150 }