Initial support for GPU channels (#2372)

* Ground work for separate GPU channels

* Rename TextureManager to TextureCache

* Decouple texture bindings management from the texture cache

* Rename BufferManager to BufferCache

* Decouple buffer bindings management from the buffer cache

* More comments and proper disposal

* PR feedback

* Force host state update on channel switch

* Typo

* PR feedback

* Missing using
This commit is contained in:
gdkchan 2021-06-23 20:51:41 -03:00 committed by GitHub
parent 12a7a2ead8
commit a10b2c5ff2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 1745 additions and 1456 deletions

View file

@ -25,6 +25,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
/// </summary>
private struct CommandBuffer
{
/// <summary>
/// Processor used to process the command buffer. Contains channel state.
/// </summary>
public GPFifoProcessor Processor;
/// <summary>
/// The type of the command buffer.
/// </summary>
@ -60,11 +65,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
private readonly ConcurrentQueue<CommandBuffer> _commandBufferQueue;
private CommandBuffer _currentCommandBuffer;
private GPFifoProcessor _prevChannelProcessor;
private readonly bool _ibEnable;
private readonly GpuContext _context;
private readonly AutoResetEvent _event;
private readonly GPFifoProcessor _processor;
private bool _interrupt;
@ -78,8 +83,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
_ibEnable = true;
_context = context;
_event = new AutoResetEvent(false);
_processor = new GPFifoProcessor(context);
}
/// <summary>
@ -94,11 +97,13 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
/// Push a GPFIFO entry in the form of a prefetched command buffer.
/// It is intended to be used by nvservices to handle special cases.
/// </summary>
/// <param name="processor">Processor used to process <paramref name="commandBuffer"/></param>
/// <param name="commandBuffer">The command buffer containing the prefetched commands</param>
public void PushHostCommandBuffer(int[] commandBuffer)
internal void PushHostCommandBuffer(GPFifoProcessor processor, int[] commandBuffer)
{
_commandBufferQueue.Enqueue(new CommandBuffer
{
Processor = processor,
Type = CommandBufferType.Prefetch,
Words = commandBuffer,
EntryAddress = ulong.MaxValue,
@ -109,9 +114,10 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
/// <summary>
/// Create a CommandBuffer from a GPFIFO entry.
/// </summary>
/// <param name="processor">Processor used to process the command buffer pointed to by <paramref name="entry"/></param>
/// <param name="entry">The GPFIFO entry</param>
/// <returns>A new CommandBuffer based on the GPFIFO entry</returns>
private CommandBuffer CreateCommandBuffer(GPEntry entry)
private static CommandBuffer CreateCommandBuffer(GPFifoProcessor processor, GPEntry entry)
{
CommandBufferType type = CommandBufferType.Prefetch;
@ -124,6 +130,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
return new CommandBuffer
{
Processor = processor,
Type = type,
Words = null,
EntryAddress = startAddress,
@ -134,8 +141,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
/// <summary>
/// Pushes GPFIFO entries.
/// </summary>
/// <param name="processor">Processor used to process the command buffers pointed to by <paramref name="entries"/></param>
/// <param name="entries">GPFIFO entries</param>
public void PushEntries(ReadOnlySpan<ulong> entries)
internal void PushEntries(GPFifoProcessor processor, ReadOnlySpan<ulong> entries)
{
bool beforeBarrier = true;
@ -143,7 +151,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
{
ulong entry = entries[index];
CommandBuffer commandBuffer = CreateCommandBuffer(Unsafe.As<ulong, GPEntry>(ref entry));
CommandBuffer commandBuffer = CreateCommandBuffer(processor, Unsafe.As<ulong, GPEntry>(ref entry));
if (beforeBarrier && commandBuffer.Type == CommandBufferType.Prefetch)
{
@ -173,12 +181,24 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
/// </summary>
public void DispatchCalls()
{
// Use this opportunity to also dispose any pending channels that were closed.
_context.DisposePendingChannels();
// Process command buffers.
while (_ibEnable && !_interrupt && _commandBufferQueue.TryDequeue(out CommandBuffer entry))
{
_currentCommandBuffer = entry;
_currentCommandBuffer.Fetch(_context);
_processor.Process(_currentCommandBuffer.Words);
// If we are changing the current channel,
// we need to force all the host state to be updated.
if (_prevChannelProcessor != entry.Processor)
{
_prevChannelProcessor = entry.Processor;
entry.Processor.ForceAllDirty();
}
entry.Processor.Process(_currentCommandBuffer.Words);
}
_interrupt = false;