From 406258471939264f3ac30616b1bc7cd10e3a414f Mon Sep 17 00:00:00 2001 From: nattthebear Date: Thu, 13 Aug 2020 21:08:48 -0400 Subject: [PATCH] zwinderbuffer: use memoryblock instead of junko .net arrays. This bad boy can hold more than 1GB of shite now --- .../rewind/ZwinderBuffer.cs | 103 +++++++----------- 1 file changed, 37 insertions(+), 66 deletions(-) diff --git a/src/BizHawk.Client.Common/rewind/ZwinderBuffer.cs b/src/BizHawk.Client.Common/rewind/ZwinderBuffer.cs index 38fd29fb75..ddb11ada7f 100644 --- a/src/BizHawk.Client.Common/rewind/ZwinderBuffer.cs +++ b/src/BizHawk.Client.Common/rewind/ZwinderBuffer.cs @@ -1,6 +1,8 @@ using System; using System.IO; using System.IO.Compression; +using System.Runtime.InteropServices; +using BizHawk.BizInvoke; using BizHawk.Common; namespace BizHawk.Client.Common @@ -25,7 +27,8 @@ namespace BizHawk.Client.Common Size = 1L << (int)Math.Floor(Math.Log(targetSize, 2)); _sizeMask = Size - 1; - _buffer = new byte[Size]; + _buffer = new MemoryBlock((ulong)Size); + _buffer.Protect(_buffer.Start, _buffer.Size, MemoryBlock.Protection.RW); _targetFrameLength = settings.TargetFrameLength; _states = new StateInfo[STATEMASK + 1]; _useCompression = settings.UseCompression; @@ -59,7 +62,7 @@ namespace BizHawk.Client.Common public long Size { get; } private readonly long _sizeMask; - private readonly byte[] _buffer; + private readonly MemoryBlock _buffer; private readonly int _targetFrameLength; @@ -233,12 +236,19 @@ namespace BizHawk.Client.Common { var startByte = _states[_firstStateIndex].Start; var endByte = _states[HeadStateIndex].Start + _states[HeadStateIndex].Size; + // TODO: Use spans to avoid these extra copies in .net core if (startByte > endByte) { - writer.BaseStream.Write(_buffer, (int)startByte, (int)(Size - startByte)); + { + var stream = _buffer.GetStream(_buffer.Start + (ulong)startByte, (ulong)(Size - startByte), false); + stream.CopyTo(writer.BaseStream); + } startByte = 0; } - writer.BaseStream.Write(_buffer, (int)startByte, (int)(endByte - startByte)); + { + var stream = _buffer.GetStream(_buffer.Start + (ulong)startByte, (ulong)(endByte - startByte), false); + stream.CopyTo(writer.BaseStream); + } } } @@ -254,7 +264,9 @@ namespace BizHawk.Client.Common _states[i].Start = nextByte; nextByte += _states[i].Size; } - reader.Read(_buffer, 0, (int)nextByte); + // TODO: Use spans to avoid this extra copy in .net core + var dest = _buffer.GetStream(_buffer.Start, (ulong)nextByte, true); + WaterboxUtils.CopySome(reader.BaseStream, dest, nextByte); } public static ZwinderBuffer Create(BinaryReader reader) @@ -277,7 +289,7 @@ namespace BizHawk.Client.Common return ret; } - private class SaveStateStream : Stream, ISpanStream + private unsafe class SaveStateStream : Stream, ISpanStream { /// /// @@ -293,21 +305,22 @@ namespace BizHawk.Client.Common /// or abort processing with an IOException. This must fail if size is going to exceed buffer.Length, as nothing else /// is preventing that case. /// - public SaveStateStream(byte[] buffer, long offset, long mask, long notifySize, Func notifySizeReached) + public SaveStateStream(MemoryBlock buffer, long offset, long mask, long notifySize, Func notifySizeReached) { - _buffer = buffer; + _ptr = (byte*)Z.US(buffer.Start); _offset = offset; _mask = mask; _notifySize = notifySize; _notifySizeReached = notifySizeReached; } - private readonly byte[] _buffer; + private readonly byte* _ptr; private readonly long _offset; private readonly long _mask; private long _position; private long _notifySize; private readonly Func _notifySizeReached; + private long BufferLength => _mask + 1; public override bool CanRead => false; public override bool CanSeek => false; @@ -325,29 +338,7 @@ namespace BizHawk.Client.Common public override void Write(byte[] buffer, int offset, int count) { - long requestedSize = _position + count; - while (requestedSize > _notifySize) - _notifySize = _notifySizeReached(); - long n = count; - if (n > 0) - { - var start = (_position + _offset) & _mask; - var end = (start + n) & _mask; - if (end < start) - { - long m = _buffer.LongLength - start; - Array.Copy(buffer, offset, _buffer, start, m); - offset += (int)m; - n -= m; - _position += m; - start = 0; - } - if (n > 0) - { - Array.Copy(buffer, offset, _buffer, start, n); - _position += n; - } - } + Write(new ReadOnlySpan(buffer, offset, count)); } public void Write(ReadOnlySpan buffer) @@ -362,10 +353,10 @@ namespace BizHawk.Client.Common var end = (start + n) & _mask; if (end < start) { - long m = _buffer.LongLength - start; + long m = BufferLength - start; // Array.Copy(buffer, offset, _buffer, start, m); - buffer.Slice(0, (int)m).CopyTo(new Span(_buffer, (int)start, (int)m)); + buffer.Slice(0, (int)m).CopyTo(new Span(_ptr + start, (int)m)); // offset += (int)m; buffer = buffer.Slice((int)m); @@ -377,7 +368,7 @@ namespace BizHawk.Client.Common if (n > 0) { // Array.Copy(buffer, offset, _buffer, start, n); - buffer.CopyTo(new Span(_buffer, (int)start, (int)n)); + buffer.CopyTo(new Span(_ptr + start, (int)n)); _position += n; } @@ -389,25 +380,26 @@ namespace BizHawk.Client.Common long requestedSize = _position + 1; while (requestedSize > _notifySize) _notifySize = _notifySizeReached(); - _buffer[(_position++ + _offset) & _mask] = value; + _ptr[(_position++ + _offset) & _mask] = value; } } - private class LoadStateStream : Stream, ISpanStream + private unsafe class LoadStateStream : Stream, ISpanStream { - public LoadStateStream(byte[] buffer, long offset, long size, long mask) + public LoadStateStream(MemoryBlock buffer, long offset, long size, long mask) { - _buffer = buffer; + _ptr = (byte*)Z.US(buffer.Start); _offset = offset; _size = size; _mask = mask; } - private readonly byte[] _buffer; + private readonly byte* _ptr; private readonly long _offset; private readonly long _size; private long _position; private readonly long _mask; + private long BufferLength => _mask + 1; public override bool CanRead => true; public override bool CanSeek => false; @@ -423,28 +415,7 @@ namespace BizHawk.Client.Common public override int Read(byte[] buffer, int offset, int count) { - long n = Math.Min(_size - _position, count); - int ret = (int)n; - if (n > 0) - { - var start = (_position + _offset) & _mask; - var end = (start + n) & _mask; - if (end < start) - { - long m = _buffer.LongLength - start; - Array.Copy(_buffer, start, buffer, offset, m); - offset += (int)m; - n -= m; - _position += m; - start = 0; - } - if (n > 0) - { - Array.Copy(_buffer, start, buffer, offset, n); - _position += n; - } - } - return ret; + return Read(new Span(buffer, offset, count)); } public unsafe int Read(Span buffer) @@ -457,10 +428,10 @@ namespace BizHawk.Client.Common var end = (start + n) & _mask; if (end < start) { - long m = _buffer.LongLength - start; + long m = BufferLength - start; // Array.Copy(_buffer, start, buffer, offset, m); - new ReadOnlySpan(_buffer, (int)start, (int)m).CopyTo(buffer); + new ReadOnlySpan(_ptr + start, (int)m).CopyTo(buffer); // offset += (int)m; buffer = buffer.Slice((int)m); @@ -472,7 +443,7 @@ namespace BizHawk.Client.Common if (n > 0) { // Array.Copy(_buffer, start, buffer, offset, n); - new ReadOnlySpan(_buffer, (int)start, (int)n).CopyTo(buffer); + new ReadOnlySpan(_ptr + start, (int)n).CopyTo(buffer); _position += n; } } @@ -482,7 +453,7 @@ namespace BizHawk.Client.Common public override int ReadByte() { return _position < _size - ? _buffer[(_position++ + _offset) & _mask] + ? _ptr[(_position++ + _offset) & _mask] : -1; }