コード例 #1
0
ファイル: ZwinderBuffer.cs プロジェクト: zcatt/BizHawk
        /// <summary>
        /// Maybe captures a state, if the conditions are favorable
        /// </summary>
        /// <param name="frame">frame number to capture</param>
        /// <param name="callback">will be called with the stream if capture is to be performed</param>
        /// <param name="indexInvalidated">
        /// If provided, will be called with the index of states that are about to be removed.  This will happen during
        /// calls to Write() inside `callback`, and any reuse of the old state will have to happen immediately
        /// </param>
        public void Capture(int frame, Action <Stream> callback, Action <int> indexInvalidated = null, bool force = false)
        {
            if (!force && !ShouldCapture(frame))
            {
                return;
            }

            if (Count == STATEMASK)
            {
                indexInvalidated?.Invoke(0);
                _firstStateIndex = (_firstStateIndex + 1) & STATEMASK;
            }

            var start          = (_states[HeadStateIndex].Start + _states[HeadStateIndex].Size) & _sizeMask;
            var initialMaxSize = Count > 0
                                        ? (_states[_firstStateIndex].Start - start) & _sizeMask
                                        : Size;
            Func <long> notifySizeReached = () =>
            {
                if (Count == 0)
                {
                    throw new IOException("A single state must not be larger than the buffer");
                }
                indexInvalidated?.Invoke(0);
                _firstStateIndex = (_firstStateIndex + 1) & STATEMASK;
                return(Count > 0
                                        ? (_states[_firstStateIndex].Start - start) & _sizeMask
                                        : Size);
            };
            var stream = new SaveStateStream(_buffer, start, _sizeMask, initialMaxSize, notifySizeReached);

            if (_useCompression)
            {
                using var compressor = new DeflateStream(stream, CompressionLevel.Fastest, leaveOpen: true);
                callback(compressor);
            }
            else
            {
                callback(stream);
            }

            _states[_nextStateIndex].Frame = frame;
            _states[_nextStateIndex].Start = start;
            _states[_nextStateIndex].Size  = (int)stream.Length;
            _nextStateIndex = (_nextStateIndex + 1) & STATEMASK;

            //Util.DebugWriteLine($"Size: {Size >> 20}MiB, Used: {Used >> 20}MiB, States: {Count}");
        }
コード例 #2
0
ファイル: ZeldaWinder.cs プロジェクト: swipswaps/BizHawk
        public unsafe void Capture(int frame)
        {
            Sync();
            if (!_active)
            {
                return;
            }
            if (_masterFrame == -1)
            {
                var sss = new SaveStateStream(this);
                _stateSource.SaveStateBinary(new BinaryWriter(sss));
                (_master, _scratch) = (_scratch, _master);
                _masterLength       = (int)sss.Position;
                _masterFrame        = frame;
                _count++;
                return;
            }
            if (!_buffer.WillCapture(_masterFrame))
            {
                return;
            }

            {
                var sss = new SaveStateStream(this);
                _stateSource.SaveStateBinary(new BinaryWriter(sss));

                Work(() =>
                {
                    _buffer.Capture(_masterFrame, underlyingStream_ =>
                    {
                        var zeldas = SpanStream.GetOrBuild(underlyingStream_);
                        if (_master.Length < _scratch.Length)
                        {
                            var replacement = new byte[_scratch.Length];
                            Array.Copy(_master, replacement, _master.Length);
                            _master = replacement;
                        }

                        var lengthHolder     = _masterLength;
                        var lengthHolderSpan = new ReadOnlySpan <byte>(&lengthHolder, 4);

                        zeldas.Write(lengthHolderSpan);

                        fixed(byte *older_ = _master)
                        fixed(byte *newer_ = _scratch)
                        {
                            int *older       = (int *)older_;
                            int *newer       = (int *)newer_;
                            int lastIndex    = (Math.Min(_masterLength, (int)sss.Position) + 3) / 4;
                            int lastOldIndex = (_masterLength + 3) / 4;
                            int *olderEnd    = older + lastIndex;

                            int *from = older;
                            int *to   = older;

                            while (older < olderEnd)
                            {
                                if (*older++ == *newer++)
                                {
                                    if (to < from)
                                    {
                                        // Save on [to, from]
                                        lengthHolder = (int)(from - to);
                                        zeldas.Write(lengthHolderSpan);
                                        zeldas.Write(new ReadOnlySpan <byte>(to, lengthHolder * 4));
                                    }
                                    to = older;
                                }
                                else
                                {
                                    if (from < to)
                                    {
                                        // encode gap [from, to]
                                        lengthHolder = (int)(to - from) | IS_GAP;
                                        zeldas.Write(lengthHolderSpan);
                                    }
                                    from = older;
                                }
                            }
                            if (from < to)
                            {
                                // encode gap [from, to]
                                lengthHolder = (int)(to - from) | IS_GAP;
                                zeldas.Write(lengthHolderSpan);
                            }
                            if (lastOldIndex > lastIndex)
                            {
                                from += lastOldIndex - lastIndex;
                            }
                            if (to < from)
                            {
                                // Save on [to, from]
                                lengthHolder = (int)(from - to);
                                zeldas.Write(lengthHolderSpan);
                                zeldas.Write(new ReadOnlySpan <byte>(to, lengthHolder * 4));
                            }
                        }

                        (_master, _scratch) = (_scratch, _master);
                        _masterLength       = (int)sss.Position;
                        _masterFrame        = frame;
                        _count++;
                    });
                });
            }
        }