BizHawk/BizHawk.Client.Common/rewind/RewindThreader.cs

117 lines
2.5 KiB
C#

using System;
using System.Collections.Concurrent;
using System.Threading;
namespace BizHawk.Client.Common
{
public class RewindThreader : IDisposable
{
private readonly bool _isThreaded;
private readonly Action<byte[]> _performCapture;
private readonly Action<int> _performRewind;
private readonly BlockingCollection<Job> _jobs = new BlockingCollection<Job>(16);
private readonly ConcurrentStack<byte[]> _stateBufferPool = new ConcurrentStack<byte[]>();
private readonly EventWaitHandle _rewindCompletedEvent;
private readonly Thread _thread;
public RewindThreader(Action<byte[]> performCapture, Action<int> performRewind, bool isThreaded)
{
_isThreaded = isThreaded;
_performCapture = performCapture;
_performRewind = performRewind;
if (_isThreaded)
{
_rewindCompletedEvent = new EventWaitHandle(false, EventResetMode.AutoReset);
_thread = new Thread(ThreadProc) { IsBackground = true };
_thread.Start();
}
}
public void Dispose()
{
if (!_isThreaded)
{
return;
}
_jobs.CompleteAdding();
_thread.Join();
_rewindCompletedEvent.Dispose();
}
public void Rewind(int frames)
{
if (!_isThreaded)
{
_performRewind(frames);
return;
}
_jobs.Add(new Job
{
Type = JobType.Rewind,
Frames = frames
});
_rewindCompletedEvent.WaitOne();
}
public void Capture(byte[] coreSavestate)
{
if (!_isThreaded)
{
_performCapture(coreSavestate);
return;
}
byte[] savestateCopy = null;
while (_stateBufferPool.TryPop(out savestateCopy) && savestateCopy.Length != coreSavestate.Length)
{
savestateCopy = null;
}
if (savestateCopy == null)
{
savestateCopy = new byte[coreSavestate.Length];
}
Buffer.BlockCopy(coreSavestate, 0, savestateCopy, 0, coreSavestate.Length);
_jobs.Add(new Job
{
Type = JobType.Capture,
CoreState = savestateCopy
});
}
private void ThreadProc()
{
foreach (Job job in _jobs.GetConsumingEnumerable())
{
if (job.Type == JobType.Capture)
{
_performCapture(job.CoreState);
_stateBufferPool.Push(job.CoreState);
}
if (job.Type == JobType.Rewind)
{
_performRewind(job.Frames);
_rewindCompletedEvent.Set();
}
}
}
private enum JobType
{
Capture, Rewind
}
private sealed class Job
{
public JobType Type { get; set; }
public byte[] CoreState { get; set; }
public int Frames { get; set; }
}
}
}