Interrupt GPU command processing when a frame's fence is reached. (#1741)

* Interrupt GPU command processing when a frame's fence is reached.

* Accumulate times rather than %s

* Accurate timer for vsync

Spin wait for the last .667ms of a frame. Avoids issues caused by signalling 16ms vsync. (periodic stutters in smo)

* Use event wait for better timing.

* Fix lazy wait

Windows doesn't seem to want to do 1ms consistently, so force a spin if we're less than 2ms.

* A bit more efficiency on frame waits.

Should now wait the remainder 0.6667 instead of 1.6667 sometimes (odd waits above 1ms are reliable, unlike 1ms waits)

* Better swap interval 0 solution

737 fps without breaking a sweat. Downside: Vsync can no longer be disabled on games that use the event heavily (link's awakening - which is ok since it breaks anyways)

* Fix comment.

* Address Comments.
This commit is contained in:
riperiperi 2020-12-17 18:39:52 +00:00 committed by GitHub
parent eae39f80e7
commit 10aa11ce13
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 146 additions and 30 deletions

View file

@ -66,6 +66,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
private readonly AutoResetEvent _event;
private readonly GPFifoProcessor _processor;
private bool _interrupt;
/// <summary>
/// Creates a new instance of the GPU General Purpose FIFO device.
/// </summary>
@ -163,7 +165,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
/// <returns>True if commands were received, false if wait timed out</returns>
public bool WaitForCommands()
{
return _event.WaitOne(8) && !_commandBufferQueue.IsEmpty;
return !_commandBufferQueue.IsEmpty || (_event.WaitOne(8) && !_commandBufferQueue.IsEmpty);
}
/// <summary>
@ -171,13 +173,23 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
/// </summary>
public void DispatchCalls()
{
while (_ibEnable && _commandBufferQueue.TryDequeue(out CommandBuffer entry))
while (_ibEnable && !_interrupt && _commandBufferQueue.TryDequeue(out CommandBuffer entry))
{
_currentCommandBuffer = entry;
_currentCommandBuffer.Fetch(_context);
_processor.Process(_currentCommandBuffer.Words);
}
_interrupt = false;
}
/// <summary>
/// Interrupts command processing. This will break out of the DispatchCalls loop.
/// </summary>
public void Interrupt()
{
_interrupt = true;
}
/// <summary>