Ryujinx/Ryujinx.Graphics.OpenGL/Sync.cs
riperiperi f2cdceb846
Force command flush after creating a syncpoint (#2056)
* Force command flush after creating GL sync

* This is not required, as the commands were flushed on creation.

* Move comment.
2021-03-30 01:10:43 +02:00

133 lines
3.7 KiB
C#

using OpenTK.Graphics.OpenGL;
using Ryujinx.Common.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Ryujinx.Graphics.OpenGL
{
class Sync : IDisposable
{
private class SyncHandle
{
public ulong ID;
public IntPtr Handle;
}
private ulong _firstHandle = 0;
private List<SyncHandle> Handles = new List<SyncHandle>();
public void Create(ulong id)
{
SyncHandle handle = new SyncHandle
{
ID = id,
Handle = GL.FenceSync(SyncCondition.SyncGpuCommandsComplete, WaitSyncFlags.None)
};
// Force commands to flush up to the syncpoint.
GL.ClientWaitSync(handle.Handle, ClientWaitSyncFlags.SyncFlushCommandsBit, 0);
lock (Handles)
{
Handles.Add(handle);
}
}
public void Wait(ulong id)
{
SyncHandle result = null;
lock (Handles)
{
if ((long)(_firstHandle - id) > 0)
{
return; // The handle has already been signalled or deleted.
}
foreach (SyncHandle handle in Handles)
{
if (handle.ID == id)
{
result = handle;
break;
}
}
}
if (result != null)
{
lock (result)
{
if (result.Handle == IntPtr.Zero)
{
return;
}
WaitSyncStatus syncResult = GL.ClientWaitSync(result.Handle, ClientWaitSyncFlags.None, 1000000000);
if (syncResult == WaitSyncStatus.TimeoutExpired)
{
Logger.Error?.PrintMsg(LogClass.Gpu, $"GL Sync Object {result.ID} failed to signal within 1000ms. Continuing...");
}
}
}
}
public void Cleanup()
{
// Iterate through handles and remove any that have already been signalled.
while (true)
{
SyncHandle first = null;
lock (Handles)
{
first = Handles.FirstOrDefault();
}
if (first == null) break;
WaitSyncStatus syncResult = GL.ClientWaitSync(first.Handle, ClientWaitSyncFlags.None, 0);
if (syncResult == WaitSyncStatus.AlreadySignaled)
{
// Delete the sync object.
lock (Handles)
{
lock (first)
{
_firstHandle = first.ID + 1;
Handles.RemoveAt(0);
GL.DeleteSync(first.Handle);
first.Handle = IntPtr.Zero;
}
}
} else
{
// This sync handle and any following have not been reached yet.
break;
}
}
}
public void Dispose()
{
lock (Handles)
{
foreach (SyncHandle handle in Handles)
{
lock (handle)
{
GL.DeleteSync(handle.Handle);
handle.Handle = IntPtr.Zero;
}
}
Handles.Clear();
}
}
}
}