1 /*
2  *  Copyright (C) 2016-2018 Team Kodi
3  *  This file is part of Kodi - https://kodi.tv
4  *
5  *  SPDX-License-Identifier: GPL-2.0-or-later
6  *  See LICENSES/README.md for more information.
7  */
8 
9 #include "DeltaPairMemoryStream.h"
10 
11 #include "utils/log.h"
12 
13 using namespace KODI;
14 using namespace RETRO;
15 
Reset()16 void CDeltaPairMemoryStream::Reset()
17 {
18   CLinearMemoryStream::Reset();
19 
20   m_rewindBuffer.clear();
21 }
22 
SubmitFrameInternal()23 void CDeltaPairMemoryStream::SubmitFrameInternal()
24 {
25   m_rewindBuffer.emplace_back();
26   MemoryFrame& frame = m_rewindBuffer.back();
27 
28   // Record frame history
29   frame.frameHistoryCount = m_currentFrameHistory++;
30 
31   uint32_t* currentFrame = m_currentFrame.get();
32   uint32_t* nextFrame = m_nextFrame.get();
33 
34   for (size_t i = 0; i < m_paddedFrameSize; i++)
35   {
36     uint32_t xor_val = currentFrame[i] ^ nextFrame[i];
37     if (xor_val)
38     {
39       DeltaPair pair = {i, xor_val};
40       frame.buffer.push_back(pair);
41     }
42   }
43 
44   // Delta is generated, bring the new frame forward (m_nextFrame is now disposable)
45   std::swap(m_currentFrame, m_nextFrame);
46 
47   m_bHasNextFrame = false;
48 
49   if (PastFramesAvailable() + 1 > MaxFrameCount())
50     CullPastFrames(1);
51 }
52 
PastFramesAvailable() const53 uint64_t CDeltaPairMemoryStream::PastFramesAvailable() const
54 {
55   return static_cast<uint64_t>(m_rewindBuffer.size());
56 }
57 
RewindFrames(uint64_t frameCount)58 uint64_t CDeltaPairMemoryStream::RewindFrames(uint64_t frameCount)
59 {
60   uint64_t rewound;
61 
62   for (rewound = 0; rewound < frameCount; rewound++)
63   {
64     if (m_rewindBuffer.empty())
65       break;
66 
67     const MemoryFrame& frame = m_rewindBuffer.back();
68     const DeltaPair* buffer = frame.buffer.data();
69 
70     size_t bufferSize = frame.buffer.size();
71 
72     // buffer pointer redirection violates data-dependency requirements...
73     // no vectorization for us :(
74     for (size_t i = 0; i < bufferSize; i++)
75       m_currentFrame[buffer[i].pos] ^= buffer[i].delta;
76 
77     // Restore frame history
78     m_currentFrameHistory = frame.frameHistoryCount;
79 
80     m_rewindBuffer.pop_back();
81   }
82 
83   return rewound;
84 }
85 
CullPastFrames(uint64_t frameCount)86 void CDeltaPairMemoryStream::CullPastFrames(uint64_t frameCount)
87 {
88   for (uint64_t removedCount = 0; removedCount < frameCount; removedCount++)
89   {
90     if (m_rewindBuffer.empty())
91     {
92       CLog::Log(LOGDEBUG,
93                 "CDeltaPairMemoryStream: Tried to cull %d frames too many. Check your math!",
94                 frameCount - removedCount);
95       break;
96     }
97     m_rewindBuffer.pop_front();
98   }
99 }
100