More rewind cleanup.

This commit is contained in:
J.D. Purcell 2017-04-04 23:26:22 -04:00
parent 9a7e7496c9
commit a47e69507f
1 changed files with 40 additions and 58 deletions

View File

@ -8,9 +8,11 @@ namespace BizHawk.Client.Common
{ {
public class Rewinder public class Rewinder
{ {
private const int MaxByteArraySize = 0x7FFFFFC7; // .NET won't let us allocate more than this in one array
private StreamBlobDatabase _rewindBuffer; private StreamBlobDatabase _rewindBuffer;
private byte[] _rewindBufferBacking; private byte[] _rewindBufferBacking;
private long? _overrideMemoryLimit; private long _memoryLimit = MaxByteArraySize;
private RewindThreader _rewindThread; private RewindThreader _rewindThread;
private byte[] _lastState; private byte[] _lastState;
private int _rewindFrequency = 1; private int _rewindFrequency = 1;
@ -63,14 +65,13 @@ namespace BizHawk.Client.Common
if (Global.Emulator.HasSavestates()) if (Global.Emulator.HasSavestates())
{ {
// This is the first frame. Capture the state, and put it in LastState for future deltas to be compared against. int stateSize = Global.Emulator.AsStatable().SaveStateBinary().Length;
_lastState = (byte[])Global.Emulator.AsStatable().SaveStateBinary().Clone();
if (_lastState.Length >= Global.Config.Rewind_LargeStateSize) if (stateSize >= Global.Config.Rewind_LargeStateSize)
{ {
SetRewindParams(Global.Config.RewindEnabledLarge, Global.Config.RewindFrequencyLarge); SetRewindParams(Global.Config.RewindEnabledLarge, Global.Config.RewindFrequencyLarge);
} }
else if (_lastState.Length >= Global.Config.Rewind_MediumStateSize) else if (stateSize >= Global.Config.Rewind_MediumStateSize)
{ {
SetRewindParams(Global.Config.RewindEnabledMedium, Global.Config.RewindFrequencyMedium); SetRewindParams(Global.Config.RewindEnabledMedium, Global.Config.RewindFrequencyMedium);
} }
@ -86,11 +87,6 @@ namespace BizHawk.Client.Common
_rewindDeltaEnable = Global.Config.Rewind_UseDelta; _rewindDeltaEnable = Global.Config.Rewind_UseDelta;
if (!RewindActive || !_rewindDeltaEnable)
{
_lastState = null;
}
if (RewindActive) if (RewindActive)
{ {
var capacity = Global.Config.Rewind_BufferSize * (long)1024 * 1024; var capacity = Global.Config.Rewind_BufferSize * (long)1024 * 1024;
@ -115,7 +111,7 @@ namespace BizHawk.Client.Common
_rewindBuffer = null; _rewindBuffer = null;
} }
_lastState = null; _lastState = new byte[0];
} }
private void DoMessage(string message) private void DoMessage(string message)
@ -144,31 +140,25 @@ namespace BizHawk.Client.Common
private byte[] BufferManage(byte[] inbuf, ref long size, bool allocate) private byte[] BufferManage(byte[] inbuf, ref long size, bool allocate)
{ {
if (allocate) if (!allocate)
{ {
const int MaxByteArraySize = 0x7FFFFFC7; _rewindBufferBacking = inbuf;
if (size > MaxByteArraySize) return null;
{
// .NET won't let us allocate more than this in one array
size = MaxByteArraySize;
} }
if (_overrideMemoryLimit != null) size = Math.Min(size, _memoryLimit);
{
size = Math.Min(_overrideMemoryLimit.Value, size);
}
// if we have an appropriate buffer free, return it // if we have an appropriate buffer free, return it
if (_rewindBufferBacking != null) if (_rewindBufferBacking != null)
{
if (_rewindBufferBacking.LongLength == size)
{ {
var buf = _rewindBufferBacking; var buf = _rewindBufferBacking;
_rewindBufferBacking = null;
return buf;
}
_rewindBufferBacking = null; _rewindBufferBacking = null;
if (buf.LongLength == size)
{
return buf;
}
} }
// otherwise, allocate it // otherwise, allocate it
@ -181,18 +171,12 @@ namespace BizHawk.Client.Common
catch (OutOfMemoryException) catch (OutOfMemoryException)
{ {
size /= 2; size /= 2;
_overrideMemoryLimit = size; _memoryLimit = size;
} }
} }
while (size > 1); while (size > 1);
throw new OutOfMemoryException(); throw new OutOfMemoryException();
} }
else
{
_rewindBufferBacking = inbuf;
return null;
}
}
public void Capture() public void Capture()
{ {
@ -356,9 +340,7 @@ namespace BizHawk.Client.Common
// of the current state (see comment in the following method). For deltas, since // of the current state (see comment in the following method). For deltas, since
// each one records how to get back to the previous state, once we've gone back to // each one records how to get back to the previous state, once we've gone back to
// the second item, it's already resulted in the first state being loaded. The // the second item, it's already resulted in the first state being loaded. The
// first item is actually a junk delta that records how to get from the first // first item is just a junk entry with the initial value of _lastState (0 bytes).
// captured state to the "previous" state, which in this case is the one that was
// grabbed during rewinder initialization.
if (_rewindBuffer.Count <= 1 || (Global.MovieSession.Movie.IsActive && Global.MovieSession.Movie.InputLogLength == 0)) if (_rewindBuffer.Count <= 1 || (Global.MovieSession.Movie.IsActive && Global.MovieSession.Movie.InputLogLength == 0))
{ {
break; break;