/ src / Ryujinx.Graphics.Gpu / GpuChannel.cs
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  }