Run ahead support (+ improved save/load state performance)

Note: Run ahead currently doesn't work well with netplay, movies and rewind
This commit is contained in:
Sour 2019-12-26 12:03:38 -05:00
parent 30c7eea6fa
commit 5f2c502be9
15 changed files with 301 additions and 123 deletions

View file

@ -90,6 +90,14 @@ void Console::Release()
_movieManager.reset(); _movieManager.reset();
} }
void Console::RunFrame()
{
uint32_t frameCount = _ppu->GetFrameCount();
while(frameCount == _ppu->GetFrameCount()) {
_cpu->Exec();
}
}
void Console::Run() void Console::Run()
{ {
if(!_cpu) { if(!_cpu) {
@ -98,9 +106,9 @@ void Console::Run()
auto emulationLock = _emulationLock.AcquireSafe(); auto emulationLock = _emulationLock.AcquireSafe();
auto lock = _runLock.AcquireSafe(); auto lock = _runLock.AcquireSafe();
uint32_t previousFrameCount = 0;
_stopFlag = false; _stopFlag = false;
_isRunAheadFrame = false;
PlatformUtilities::EnableHighResolutionTimer(); PlatformUtilities::EnableHighResolutionTimer();
@ -116,29 +124,25 @@ void Console::Run()
_lastFrameTimer.Reset(); _lastFrameTimer.Reset();
while(!_stopFlag) { while(!_stopFlag) {
_cpu->Exec(); bool useRunAhead = _settings->GetEmulationConfig().RunAheadFrames > 0 && !_debugger && !_rewindManager->IsRewinding() && _settings->GetEmulationSpeed() > 0 && _settings->GetEmulationSpeed() <= 100;
if(useRunAhead) {
if(previousFrameCount != _ppu->GetFrameCount()) { RunFrameWithRunAhead();
} else {
RunFrame();
_rewindManager->ProcessEndOfFrame(); _rewindManager->ProcessEndOfFrame();
ProcessSystemActions();
WaitForLock();
if(_pauseOnNextFrame) {
_pauseOnNextFrame = false;
_paused = true;
}
if(_paused && !_stopFlag && !_debugger) {
WaitForPauseEnd();
}
previousFrameCount = _ppu->GetFrameCount();
if(_controlManager->GetSystemActionManager()->IsResetPressed()) {
Reset();
} else if(_controlManager->GetSystemActionManager()->IsPowerCyclePressed()) {
PowerCycle();
}
} }
WaitForLock();
if(_pauseOnNextFrame) {
_pauseOnNextFrame = false;
_paused = true;
}
if(_paused && !_stopFlag && !_debugger) {
WaitForPauseEnd();
}
} }
_movieManager->Stop(); _movieManager->Stop();
@ -148,6 +152,48 @@ void Console::Run()
PlatformUtilities::RestoreTimerResolution(); PlatformUtilities::RestoreTimerResolution();
} }
bool Console::ProcessSystemActions()
{
if(_controlManager->GetSystemActionManager()->IsResetPressed()) {
Reset();
return true;
} else if(_controlManager->GetSystemActionManager()->IsPowerCyclePressed()) {
PowerCycle();
return true;
}
return false;
}
void Console::RunFrameWithRunAhead()
{
stringstream runAheadState;
uint32_t frameCount = _settings->GetEmulationConfig().RunAheadFrames;
//Run a single frame and save the state (no audio/video)
_isRunAheadFrame = true;
RunFrame();
Serialize(runAheadState, 0);
while(frameCount > 1) {
//Run extra frames if the requested run ahead frame count is higher than 1
frameCount--;
RunFrame();
}
_isRunAheadFrame = false;
//Run one frame normally (with audio/video output)
RunFrame();
_rewindManager->ProcessEndOfFrame();
bool wasReset = ProcessSystemActions();
if(!wasReset) {
//Load the state we saved earlier
_isRunAheadFrame = true;
Deserialize(runAheadState, SaveStateManager::FileFormatVersion, false);
_isRunAheadFrame = false;
}
}
void Console::ProcessEndOfFrame() void Console::ProcessEndOfFrame()
{ {
#ifndef LIBRETRO #ifndef LIBRETRO
@ -156,25 +202,27 @@ void Console::ProcessEndOfFrame()
_cart->GetCoprocessor()->ProcessEndOfFrame(); _cart->GetCoprocessor()->ProcessEndOfFrame();
} }
_frameLimiter->ProcessFrame(); if(!_isRunAheadFrame) {
while(_frameLimiter->WaitForNextFrame()) { _frameLimiter->ProcessFrame();
if(_stopFlag || _frameDelay != GetFrameDelay() || _paused || _pauseOnNextFrame || _lockCounter > 0) { while(_frameLimiter->WaitForNextFrame()) {
//Need to process another event, stop sleeping if(_stopFlag || _frameDelay != GetFrameDelay() || _paused || _pauseOnNextFrame || _lockCounter > 0) {
break; //Need to process another event, stop sleeping
break;
}
} }
}
double newFrameDelay = GetFrameDelay(); double newFrameDelay = GetFrameDelay();
if(newFrameDelay != _frameDelay) { if(newFrameDelay != _frameDelay) {
_frameDelay = newFrameDelay; _frameDelay = newFrameDelay;
_frameLimiter->SetDelay(_frameDelay); _frameLimiter->SetDelay(_frameDelay);
} }
PreferencesConfig cfg = _settings->GetPreferences(); PreferencesConfig cfg = _settings->GetPreferences();
if(cfg.ShowDebugInfo) { if(cfg.ShowDebugInfo) {
double lastFrameTime = _lastFrameTimer.GetElapsedMS(); double lastFrameTime = _lastFrameTimer.GetElapsedMS();
_lastFrameTimer.Reset(); _lastFrameTimer.Reset();
_stats->DisplayStats(this, lastFrameTime); _stats->DisplayStats(this, lastFrameTime);
}
} }
_controlManager->UpdateInputState(); _controlManager->UpdateInputState();
@ -554,7 +602,7 @@ void Console::WaitForLock()
} }
} }
void Console::Serialize(ostream &out) void Console::Serialize(ostream &out, int compressionLevel)
{ {
Serializer serializer(SaveStateManager::FileFormatVersion); Serializer serializer(SaveStateManager::FileFormatVersion);
serializer.Stream(_cpu.get()); serializer.Stream(_cpu.get());
@ -568,12 +616,12 @@ void Console::Serialize(ostream &out)
if(_msu1) { if(_msu1) {
serializer.Stream(_msu1.get()); serializer.Stream(_msu1.get());
} }
serializer.Save(out); serializer.Save(out, compressionLevel);
} }
void Console::Deserialize(istream &in, uint32_t fileFormatVersion) void Console::Deserialize(istream &in, uint32_t fileFormatVersion, bool compressed)
{ {
Serializer serializer(in, fileFormatVersion); Serializer serializer(in, fileFormatVersion, compressed);
serializer.Stream(_cpu.get()); serializer.Stream(_cpu.get());
serializer.Stream(_memoryManager.get()); serializer.Stream(_memoryManager.get());
serializer.Stream(_ppu.get()); serializer.Stream(_ppu.get());
@ -731,6 +779,11 @@ bool Console::IsRunning()
return _cpu != nullptr; return _cpu != nullptr;
} }
bool Console::IsRunAheadFrame()
{
return _isRunAheadFrame;
}
template<CpuType type> template<CpuType type>
void Console::ProcessMemoryRead(uint32_t addr, uint8_t value, MemoryOperationType opType) void Console::ProcessMemoryRead(uint32_t addr, uint8_t value, MemoryOperationType opType)
{ {

View file

@ -82,6 +82,8 @@ private:
ConsoleRegion _region; ConsoleRegion _region;
uint32_t _masterClockRate; uint32_t _masterClockRate;
atomic<bool> _isRunAheadFrame;
unique_ptr<DebugStats> _stats; unique_ptr<DebugStats> _stats;
unique_ptr<FrameLimiter> _frameLimiter; unique_ptr<FrameLimiter> _frameLimiter;
Timer _lastFrameTimer; Timer _lastFrameTimer;
@ -92,6 +94,10 @@ private:
void WaitForLock(); void WaitForLock();
void WaitForPauseEnd(); void WaitForPauseEnd();
void RunFrame();
bool ProcessSystemActions();
void RunFrameWithRunAhead();
public: public:
Console(); Console();
~Console(); ~Console();
@ -99,6 +105,7 @@ public:
void Initialize(); void Initialize();
void Release(); void Release();
void Run(); void Run();
void RunSingleFrame(); void RunSingleFrame();
void Stop(bool sendNotification); void Stop(bool sendNotification);
@ -123,8 +130,8 @@ public:
void Lock(); void Lock();
void Unlock(); void Unlock();
void Serialize(ostream &out); void Serialize(ostream &out, int compressionLevel = 1);
void Deserialize(istream &in, uint32_t fileFormatVersion); void Deserialize(istream &in, uint32_t fileFormatVersion, bool compressed = true);
shared_ptr<SoundMixer> GetSoundMixer(); shared_ptr<SoundMixer> GetSoundMixer();
shared_ptr<VideoRenderer> GetVideoRenderer(); shared_ptr<VideoRenderer> GetVideoRenderer();
@ -155,6 +162,8 @@ public:
thread::id GetEmulationThreadId(); thread::id GetEmulationThreadId();
bool IsRunning(); bool IsRunning();
bool IsInputRecordingEnabled();
bool IsRunAheadFrame();
template<CpuType type> void ProcessMemoryRead(uint32_t addr, uint8_t value, MemoryOperationType opType); template<CpuType type> void ProcessMemoryRead(uint32_t addr, uint8_t value, MemoryOperationType opType);
template<CpuType type> void ProcessMemoryWrite(uint32_t addr, uint8_t value, MemoryOperationType opType); template<CpuType type> void ProcessMemoryWrite(uint32_t addr, uint8_t value, MemoryOperationType opType);

View file

@ -163,8 +163,10 @@ void ControlManager::UpdateInputState()
debugger->ProcessEvent(EventType::InputPolled); debugger->ProcessEvent(EventType::InputPolled);
} }
for(IInputRecorder* recorder : _inputRecorders) { if(!_console->IsRunAheadFrame()) {
recorder->RecordInput(_controlDevices); for(IInputRecorder* recorder : _inputRecorders) {
recorder->RecordInput(_controlDevices);
}
} }
//MessageManager::Log(log); //MessageManager::Log(log);

View file

@ -476,6 +476,10 @@ bool Ppu::ProcessEndOfScanline(uint16_t hClock)
(_settings->GetEmulationSpeed() == 0 || _settings->GetEmulationSpeed() > 150) && (_settings->GetEmulationSpeed() == 0 || _settings->GetEmulationSpeed() > 150) &&
_frameSkipTimer.GetElapsedMS() < 10 _frameSkipTimer.GetElapsedMS() < 10
); );
if(_console->IsRunAheadFrame()) {
_skipRender = true;
}
//Update overclock timings once per frame //Update overclock timings once per frame
UpdateNmiScanline(); UpdateNmiScanline();

View file

@ -44,6 +44,10 @@ void RewindManager::ClearBuffer()
void RewindManager::ProcessNotification(ConsoleNotificationType type, void * parameter) void RewindManager::ProcessNotification(ConsoleNotificationType type, void * parameter)
{ {
if(_console->IsRunAheadFrame()) {
return;
}
if(type == ConsoleNotificationType::PpuFrameDone) { if(type == ConsoleNotificationType::PpuFrameDone) {
_hasHistory = _history.size() >= 2; _hasHistory = _history.size() >= 2;
if(_settings->GetRewindBufferSize() > 0) { if(_settings->GetRewindBufferSize() > 0) {

View file

@ -273,6 +273,8 @@ struct EmulationConfig
ConsoleRegion Region = ConsoleRegion::Auto; ConsoleRegion Region = ConsoleRegion::Auto;
uint32_t RunAheadFrames = 0;
bool EnableRandomPowerOnState = false; bool EnableRandomPowerOnState = false;
bool EnableStrictBoardMappings = false; bool EnableStrictBoardMappings = false;

View file

@ -93,7 +93,7 @@ void SoundMixer::PlayAudioBuffer(int16_t* samples, uint32_t sampleCount)
} }
shared_ptr<RewindManager> rewindManager = _console->GetRewindManager(); shared_ptr<RewindManager> rewindManager = _console->GetRewindManager();
if(rewindManager && rewindManager->SendAudio(out, count)) { if(!_console->IsRunAheadFrame() && rewindManager && rewindManager->SendAudio(out, count)) {
bool isRecording = _waveRecorder || _console->GetVideoRenderer()->IsRecording(); bool isRecording = _waveRecorder || _console->GetVideoRenderer()->IsRecording();
if(isRecording) { if(isRecording) {
if(_waveRecorder) { if(_waveRecorder) {

View file

@ -41,11 +41,9 @@ public:
{ {
if(_needReset) { if(_needReset) {
SetBit(SystemActionManager::Buttons::ResetButton); SetBit(SystemActionManager::Buttons::ResetButton);
_needReset = false;
} }
if(_needPowerCycle) { if(_needPowerCycle) {
SetBit(SystemActionManager::Buttons::PowerButton); SetBit(SystemActionManager::Buttons::PowerButton);
_needPowerCycle = false;
} }
} }
@ -81,11 +79,13 @@ public:
bool IsResetPressed() bool IsResetPressed()
{ {
_needReset = false;
return IsPressed(SystemActionManager::Buttons::ResetButton); return IsPressed(SystemActionManager::Buttons::ResetButton);
} }
bool IsPowerCyclePressed() bool IsPowerCyclePressed()
{ {
_needPowerCycle = false;
return IsPressed(SystemActionManager::Buttons::PowerButton); return IsPressed(SystemActionManager::Buttons::PowerButton);
} }
}; };

View file

@ -158,6 +158,10 @@ uint32_t VideoDecoder::GetFrameCount()
void VideoDecoder::UpdateFrameSync(uint16_t *ppuOutputBuffer, uint16_t width, uint16_t height, uint32_t frameNumber, bool forRewind) void VideoDecoder::UpdateFrameSync(uint16_t *ppuOutputBuffer, uint16_t width, uint16_t height, uint32_t frameNumber, bool forRewind)
{ {
if(_console->IsRunAheadFrame()) {
return;
}
if(_frameChanged) { if(_frameChanged) {
//Last frame isn't done decoding yet - sometimes Signal() introduces a 25-30ms delay //Last frame isn't done decoding yet - sometimes Signal() introduces a 25-30ms delay
while(_frameChanged) { while(_frameChanged) {
@ -177,6 +181,10 @@ void VideoDecoder::UpdateFrameSync(uint16_t *ppuOutputBuffer, uint16_t width, ui
void VideoDecoder::UpdateFrame(uint16_t *ppuOutputBuffer, uint16_t width, uint16_t height, uint32_t frameNumber) void VideoDecoder::UpdateFrame(uint16_t *ppuOutputBuffer, uint16_t width, uint16_t height, uint32_t frameNumber)
{ {
if(_console->IsRunAheadFrame()) {
return;
}
if(_frameChanged) { if(_frameChanged) {
//Last frame isn't done decoding yet - sometimes Signal() introduces a 25-30ms delay //Last frame isn't done decoding yet - sometimes Signal() introduces a 25-30ms delay
while(_frameChanged) { while(_frameChanged) {

View file

@ -15,6 +15,8 @@ namespace Mesen.GUI.Config
[MinMax(0, 5000)] public UInt32 RewindSpeed = 100; [MinMax(0, 5000)] public UInt32 RewindSpeed = 100;
public ConsoleRegion Region = ConsoleRegion.Auto; public ConsoleRegion Region = ConsoleRegion.Auto;
[MinMax(0, 10)] public UInt32 RunAheadFrames = 0;
[MarshalAs(UnmanagedType.I1)] public bool EnableRandomPowerOnState = false; [MarshalAs(UnmanagedType.I1)] public bool EnableRandomPowerOnState = false;
[MarshalAs(UnmanagedType.I1)] public bool EnableStrictBoardMappings = false; [MarshalAs(UnmanagedType.I1)] public bool EnableStrictBoardMappings = false;

View file

@ -282,7 +282,9 @@
<Control ID="lblTurboSpeed">Fast Forward Speed:</Control> <Control ID="lblTurboSpeed">Fast Forward Speed:</Control>
<Control ID="lblRewindSpeedHint">% (0 = Maximum speed)</Control> <Control ID="lblRewindSpeedHint">% (0 = Maximum speed)</Control>
<Control ID="lblRewindSpeed">Rewind Speed:</Control> <Control ID="lblRewindSpeed">Rewind Speed:</Control>
<Control ID="lblRunAhead">Run Ahead:</Control>
<Control ID="lblRunAheadFrames">frames (reduces input lag, increases CPU usage)</Control>
<Control ID="tpgAdvanced">Advanced</Control> <Control ID="tpgAdvanced">Advanced</Control>
<Control ID="lblDeveloperSettings">Recommended settings for developers (homebrew / ROM hacking)</Control> <Control ID="lblDeveloperSettings">Recommended settings for developers (homebrew / ROM hacking)</Control>
<Control ID="lblMiscSettings">Miscellaneous Settings</Control> <Control ID="lblMiscSettings">Miscellaneous Settings</Control>

View file

@ -31,6 +31,10 @@
this.tabMain = new System.Windows.Forms.TabControl(); this.tabMain = new System.Windows.Forms.TabControl();
this.tpgGeneral = new System.Windows.Forms.TabPage(); this.tpgGeneral = new System.Windows.Forms.TabPage();
this.tableLayoutPanel4 = new System.Windows.Forms.TableLayoutPanel(); this.tableLayoutPanel4 = new System.Windows.Forms.TableLayoutPanel();
this.flowLayoutPanel5 = new System.Windows.Forms.FlowLayoutPanel();
this.nudRunAheadFrames = new Mesen.GUI.Controls.MesenNumericUpDown();
this.lblRunAheadFrames = new System.Windows.Forms.Label();
this.lblRunAhead = new System.Windows.Forms.Label();
this.label1 = new System.Windows.Forms.Label(); this.label1 = new System.Windows.Forms.Label();
this.flowLayoutPanel9 = new System.Windows.Forms.FlowLayoutPanel(); this.flowLayoutPanel9 = new System.Windows.Forms.FlowLayoutPanel();
this.nudTurboSpeed = new Mesen.GUI.Controls.MesenNumericUpDown(); this.nudTurboSpeed = new Mesen.GUI.Controls.MesenNumericUpDown();
@ -50,6 +54,7 @@
this.chkEnableRandomPowerOnState = new Mesen.GUI.Controls.ctrlRiskyOption(); this.chkEnableRandomPowerOnState = new Mesen.GUI.Controls.ctrlRiskyOption();
this.cboRamPowerOnState = new System.Windows.Forms.ComboBox(); this.cboRamPowerOnState = new System.Windows.Forms.ComboBox();
this.lblRamPowerOnState = new System.Windows.Forms.Label(); this.lblRamPowerOnState = new System.Windows.Forms.Label();
this.chkEnableStrictBoardMappings = new Mesen.GUI.Controls.ctrlRiskyOption();
this.tpgOverclocking = new System.Windows.Forms.TabPage(); this.tpgOverclocking = new System.Windows.Forms.TabPage();
this.picHint = new System.Windows.Forms.PictureBox(); this.picHint = new System.Windows.Forms.PictureBox();
this.tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel(); this.tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel();
@ -63,10 +68,10 @@
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
this.nudGsuClockSpeed = new Mesen.GUI.Controls.MesenNumericUpDown(); this.nudGsuClockSpeed = new Mesen.GUI.Controls.MesenNumericUpDown();
this.lblGsuClockSpeed = new System.Windows.Forms.Label(); this.lblGsuClockSpeed = new System.Windows.Forms.Label();
this.chkEnableStrictBoardMappings = new Mesen.GUI.Controls.ctrlRiskyOption();
this.tabMain.SuspendLayout(); this.tabMain.SuspendLayout();
this.tpgGeneral.SuspendLayout(); this.tpgGeneral.SuspendLayout();
this.tableLayoutPanel4.SuspendLayout(); this.tableLayoutPanel4.SuspendLayout();
this.flowLayoutPanel5.SuspendLayout();
this.flowLayoutPanel9.SuspendLayout(); this.flowLayoutPanel9.SuspendLayout();
this.flowLayoutPanel6.SuspendLayout(); this.flowLayoutPanel6.SuspendLayout();
this.flowLayoutPanel10.SuspendLayout(); this.flowLayoutPanel10.SuspendLayout();
@ -83,7 +88,7 @@
// baseConfigPanel // baseConfigPanel
// //
this.baseConfigPanel.Location = new System.Drawing.Point(0, 290); this.baseConfigPanel.Location = new System.Drawing.Point(0, 290);
this.baseConfigPanel.Size = new System.Drawing.Size(414, 29); this.baseConfigPanel.Size = new System.Drawing.Size(445, 29);
this.baseConfigPanel.TabIndex = 4; this.baseConfigPanel.TabIndex = 4;
// //
// tabMain // tabMain
@ -95,7 +100,7 @@
this.tabMain.Location = new System.Drawing.Point(0, 0); this.tabMain.Location = new System.Drawing.Point(0, 0);
this.tabMain.Name = "tabMain"; this.tabMain.Name = "tabMain";
this.tabMain.SelectedIndex = 0; this.tabMain.SelectedIndex = 0;
this.tabMain.Size = new System.Drawing.Size(414, 290); this.tabMain.Size = new System.Drawing.Size(445, 290);
this.tabMain.TabIndex = 2; this.tabMain.TabIndex = 2;
// //
// tpgGeneral // tpgGeneral
@ -104,7 +109,7 @@
this.tpgGeneral.Location = new System.Drawing.Point(4, 22); this.tpgGeneral.Location = new System.Drawing.Point(4, 22);
this.tpgGeneral.Name = "tpgGeneral"; this.tpgGeneral.Name = "tpgGeneral";
this.tpgGeneral.Padding = new System.Windows.Forms.Padding(3); this.tpgGeneral.Padding = new System.Windows.Forms.Padding(3);
this.tpgGeneral.Size = new System.Drawing.Size(406, 264); this.tpgGeneral.Size = new System.Drawing.Size(437, 264);
this.tpgGeneral.TabIndex = 2; this.tpgGeneral.TabIndex = 2;
this.tpgGeneral.Text = "General"; this.tpgGeneral.Text = "General";
this.tpgGeneral.UseVisualStyleBackColor = true; this.tpgGeneral.UseVisualStyleBackColor = true;
@ -115,6 +120,8 @@
this.tableLayoutPanel4.ColumnCount = 2; this.tableLayoutPanel4.ColumnCount = 2;
this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel4.Controls.Add(this.flowLayoutPanel5, 1, 4);
this.tableLayoutPanel4.Controls.Add(this.lblRunAhead, 0, 4);
this.tableLayoutPanel4.Controls.Add(this.label1, 0, 3); this.tableLayoutPanel4.Controls.Add(this.label1, 0, 3);
this.tableLayoutPanel4.Controls.Add(this.flowLayoutPanel9, 1, 1); this.tableLayoutPanel4.Controls.Add(this.flowLayoutPanel9, 1, 1);
this.tableLayoutPanel4.Controls.Add(this.lblTurboSpeed, 0, 1); this.tableLayoutPanel4.Controls.Add(this.lblTurboSpeed, 0, 1);
@ -126,15 +133,79 @@
this.tableLayoutPanel4.Dock = System.Windows.Forms.DockStyle.Fill; this.tableLayoutPanel4.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel4.Location = new System.Drawing.Point(3, 3); this.tableLayoutPanel4.Location = new System.Drawing.Point(3, 3);
this.tableLayoutPanel4.Name = "tableLayoutPanel4"; this.tableLayoutPanel4.Name = "tableLayoutPanel4";
this.tableLayoutPanel4.RowCount = 5; this.tableLayoutPanel4.RowCount = 6;
this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle()); this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle()); this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle()); this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle()); this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel4.Size = new System.Drawing.Size(400, 258); this.tableLayoutPanel4.Size = new System.Drawing.Size(431, 258);
this.tableLayoutPanel4.TabIndex = 0; this.tableLayoutPanel4.TabIndex = 0;
// //
// flowLayoutPanel5
//
this.flowLayoutPanel5.AutoSize = true;
this.flowLayoutPanel5.Controls.Add(this.nudRunAheadFrames);
this.flowLayoutPanel5.Controls.Add(this.lblRunAheadFrames);
this.flowLayoutPanel5.Dock = System.Windows.Forms.DockStyle.Fill;
this.flowLayoutPanel5.Location = new System.Drawing.Point(111, 108);
this.flowLayoutPanel5.Margin = new System.Windows.Forms.Padding(0);
this.flowLayoutPanel5.Name = "flowLayoutPanel5";
this.flowLayoutPanel5.Size = new System.Drawing.Size(320, 27);
this.flowLayoutPanel5.TabIndex = 20;
//
// nudRunAheadFrames
//
this.nudRunAheadFrames.DecimalPlaces = 0;
this.nudRunAheadFrames.Increment = new decimal(new int[] {
1,
0,
0,
0});
this.nudRunAheadFrames.IsHex = false;
this.nudRunAheadFrames.Location = new System.Drawing.Point(3, 3);
this.nudRunAheadFrames.Maximum = new decimal(new int[] {
10,
0,
0,
0});
this.nudRunAheadFrames.MaximumSize = new System.Drawing.Size(10000, 20);
this.nudRunAheadFrames.Minimum = new decimal(new int[] {
0,
0,
0,
0});
this.nudRunAheadFrames.MinimumSize = new System.Drawing.Size(0, 21);
this.nudRunAheadFrames.Name = "nudRunAheadFrames";
this.nudRunAheadFrames.Size = new System.Drawing.Size(48, 21);
this.nudRunAheadFrames.TabIndex = 1;
this.nudRunAheadFrames.Value = new decimal(new int[] {
0,
0,
0,
0});
//
// lblRunAheadFrames
//
this.lblRunAheadFrames.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.lblRunAheadFrames.AutoSize = true;
this.lblRunAheadFrames.Location = new System.Drawing.Point(57, 7);
this.lblRunAheadFrames.Name = "lblRunAheadFrames";
this.lblRunAheadFrames.Size = new System.Drawing.Size(236, 13);
this.lblRunAheadFrames.TabIndex = 2;
this.lblRunAheadFrames.Text = "frames (reduces input lag, increases CPU usage)";
//
// lblRunAhead
//
this.lblRunAhead.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.lblRunAhead.AutoSize = true;
this.lblRunAhead.Location = new System.Drawing.Point(3, 115);
this.lblRunAhead.Name = "lblRunAhead";
this.lblRunAhead.Size = new System.Drawing.Size(64, 13);
this.lblRunAhead.TabIndex = 19;
this.lblRunAhead.Text = "Run Ahead:";
//
// label1 // label1
// //
this.label1.Anchor = System.Windows.Forms.AnchorStyles.Left; this.label1.Anchor = System.Windows.Forms.AnchorStyles.Left;
@ -154,7 +225,7 @@
this.flowLayoutPanel9.Location = new System.Drawing.Point(111, 27); this.flowLayoutPanel9.Location = new System.Drawing.Point(111, 27);
this.flowLayoutPanel9.Margin = new System.Windows.Forms.Padding(0); this.flowLayoutPanel9.Margin = new System.Windows.Forms.Padding(0);
this.flowLayoutPanel9.Name = "flowLayoutPanel9"; this.flowLayoutPanel9.Name = "flowLayoutPanel9";
this.flowLayoutPanel9.Size = new System.Drawing.Size(289, 27); this.flowLayoutPanel9.Size = new System.Drawing.Size(320, 27);
this.flowLayoutPanel9.TabIndex = 14; this.flowLayoutPanel9.TabIndex = 14;
// //
// nudTurboSpeed // nudTurboSpeed
@ -217,7 +288,7 @@
this.flowLayoutPanel6.Location = new System.Drawing.Point(111, 0); this.flowLayoutPanel6.Location = new System.Drawing.Point(111, 0);
this.flowLayoutPanel6.Margin = new System.Windows.Forms.Padding(0); this.flowLayoutPanel6.Margin = new System.Windows.Forms.Padding(0);
this.flowLayoutPanel6.Name = "flowLayoutPanel6"; this.flowLayoutPanel6.Name = "flowLayoutPanel6";
this.flowLayoutPanel6.Size = new System.Drawing.Size(289, 27); this.flowLayoutPanel6.Size = new System.Drawing.Size(320, 27);
this.flowLayoutPanel6.TabIndex = 11; this.flowLayoutPanel6.TabIndex = 11;
// //
// nudEmulationSpeed // nudEmulationSpeed
@ -290,7 +361,7 @@
this.flowLayoutPanel10.Location = new System.Drawing.Point(111, 54); this.flowLayoutPanel10.Location = new System.Drawing.Point(111, 54);
this.flowLayoutPanel10.Margin = new System.Windows.Forms.Padding(0); this.flowLayoutPanel10.Margin = new System.Windows.Forms.Padding(0);
this.flowLayoutPanel10.Name = "flowLayoutPanel10"; this.flowLayoutPanel10.Name = "flowLayoutPanel10";
this.flowLayoutPanel10.Size = new System.Drawing.Size(289, 27); this.flowLayoutPanel10.Size = new System.Drawing.Size(320, 27);
this.flowLayoutPanel10.TabIndex = 16; this.flowLayoutPanel10.TabIndex = 16;
// //
// nudRewindSpeed // nudRewindSpeed
@ -349,7 +420,7 @@
this.tpgAdvanced.Location = new System.Drawing.Point(4, 22); this.tpgAdvanced.Location = new System.Drawing.Point(4, 22);
this.tpgAdvanced.Name = "tpgAdvanced"; this.tpgAdvanced.Name = "tpgAdvanced";
this.tpgAdvanced.Padding = new System.Windows.Forms.Padding(3); this.tpgAdvanced.Padding = new System.Windows.Forms.Padding(3);
this.tpgAdvanced.Size = new System.Drawing.Size(406, 264); this.tpgAdvanced.Size = new System.Drawing.Size(437, 264);
this.tpgAdvanced.TabIndex = 3; this.tpgAdvanced.TabIndex = 3;
this.tpgAdvanced.Text = "Advanced"; this.tpgAdvanced.Text = "Advanced";
this.tpgAdvanced.UseVisualStyleBackColor = true; this.tpgAdvanced.UseVisualStyleBackColor = true;
@ -371,7 +442,7 @@
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel2.Size = new System.Drawing.Size(400, 258); this.tableLayoutPanel2.Size = new System.Drawing.Size(431, 258);
this.tableLayoutPanel2.TabIndex = 5; this.tableLayoutPanel2.TabIndex = 5;
// //
// chkEnableRandomPowerOnState // chkEnableRandomPowerOnState
@ -403,13 +474,23 @@
this.lblRamPowerOnState.TabIndex = 0; this.lblRamPowerOnState.TabIndex = 0;
this.lblRamPowerOnState.Text = "Default power on state for RAM:"; this.lblRamPowerOnState.Text = "Default power on state for RAM:";
// //
// chkEnableStrictBoardMappings
//
this.chkEnableStrictBoardMappings.Checked = false;
this.tableLayoutPanel2.SetColumnSpan(this.chkEnableStrictBoardMappings, 2);
this.chkEnableStrictBoardMappings.Location = new System.Drawing.Point(0, 51);
this.chkEnableStrictBoardMappings.Name = "chkEnableStrictBoardMappings";
this.chkEnableStrictBoardMappings.Size = new System.Drawing.Size(400, 24);
this.chkEnableStrictBoardMappings.TabIndex = 7;
this.chkEnableStrictBoardMappings.Text = "Use strict board mappings (breaks some romhacks)";
//
// tpgOverclocking // tpgOverclocking
// //
this.tpgOverclocking.Controls.Add(this.picHint); this.tpgOverclocking.Controls.Add(this.picHint);
this.tpgOverclocking.Controls.Add(this.tableLayoutPanel3); this.tpgOverclocking.Controls.Add(this.tableLayoutPanel3);
this.tpgOverclocking.Location = new System.Drawing.Point(4, 22); this.tpgOverclocking.Location = new System.Drawing.Point(4, 22);
this.tpgOverclocking.Name = "tpgOverclocking"; this.tpgOverclocking.Name = "tpgOverclocking";
this.tpgOverclocking.Size = new System.Drawing.Size(406, 264); this.tpgOverclocking.Size = new System.Drawing.Size(437, 264);
this.tpgOverclocking.TabIndex = 4; this.tpgOverclocking.TabIndex = 4;
this.tpgOverclocking.Text = "Overclocking"; this.tpgOverclocking.Text = "Overclocking";
this.tpgOverclocking.UseVisualStyleBackColor = true; this.tpgOverclocking.UseVisualStyleBackColor = true;
@ -442,7 +523,7 @@
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle()); this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle()); this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel3.Size = new System.Drawing.Size(406, 264); this.tableLayoutPanel3.Size = new System.Drawing.Size(437, 264);
this.tableLayoutPanel3.TabIndex = 1; this.tableLayoutPanel3.TabIndex = 1;
// //
// lblOverclockHint // lblOverclockHint
@ -461,7 +542,7 @@
this.grpPpuTiming.Dock = System.Windows.Forms.DockStyle.Fill; this.grpPpuTiming.Dock = System.Windows.Forms.DockStyle.Fill;
this.grpPpuTiming.Location = new System.Drawing.Point(3, 57); this.grpPpuTiming.Location = new System.Drawing.Point(3, 57);
this.grpPpuTiming.Name = "grpPpuTiming"; this.grpPpuTiming.Name = "grpPpuTiming";
this.grpPpuTiming.Size = new System.Drawing.Size(400, 71); this.grpPpuTiming.Size = new System.Drawing.Size(431, 71);
this.grpPpuTiming.TabIndex = 7; this.grpPpuTiming.TabIndex = 7;
this.grpPpuTiming.TabStop = false; this.grpPpuTiming.TabStop = false;
this.grpPpuTiming.Text = "PPU Vertical Blank Configuration"; this.grpPpuTiming.Text = "PPU Vertical Blank Configuration";
@ -482,7 +563,7 @@
this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle()); this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle()); this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel5.Size = new System.Drawing.Size(394, 52); this.tableLayoutPanel5.Size = new System.Drawing.Size(425, 52);
this.tableLayoutPanel5.TabIndex = 0; this.tableLayoutPanel5.TabIndex = 0;
// //
// nudExtraScanlinesAfterNmi // nudExtraScanlinesAfterNmi
@ -582,7 +663,7 @@
this.tableLayoutPanel1.Name = "tableLayoutPanel1"; this.tableLayoutPanel1.Name = "tableLayoutPanel1";
this.tableLayoutPanel1.RowCount = 1; this.tableLayoutPanel1.RowCount = 1;
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel1.Size = new System.Drawing.Size(406, 25); this.tableLayoutPanel1.Size = new System.Drawing.Size(437, 25);
this.tableLayoutPanel1.TabIndex = 8; this.tableLayoutPanel1.TabIndex = 8;
// //
// nudGsuClockSpeed // nudGsuClockSpeed
@ -628,21 +709,11 @@
this.lblGsuClockSpeed.TabIndex = 0; this.lblGsuClockSpeed.TabIndex = 0;
this.lblGsuClockSpeed.Text = "Super FX clock speed (%):"; this.lblGsuClockSpeed.Text = "Super FX clock speed (%):";
// //
// chkEnableStrictBoardMappings
//
this.chkEnableStrictBoardMappings.Checked = false;
this.tableLayoutPanel2.SetColumnSpan(this.chkEnableStrictBoardMappings, 2);
this.chkEnableStrictBoardMappings.Location = new System.Drawing.Point(0, 51);
this.chkEnableStrictBoardMappings.Name = "chkEnableStrictBoardMappings";
this.chkEnableStrictBoardMappings.Size = new System.Drawing.Size(400, 24);
this.chkEnableStrictBoardMappings.TabIndex = 7;
this.chkEnableStrictBoardMappings.Text = "Use strict board mappings (breaks some romhacks)";
//
// frmEmulationConfig // frmEmulationConfig
// //
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(414, 319); this.ClientSize = new System.Drawing.Size(445, 319);
this.Controls.Add(this.tabMain); this.Controls.Add(this.tabMain);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.MaximizeBox = false; this.MaximizeBox = false;
@ -657,6 +728,8 @@
this.tpgGeneral.PerformLayout(); this.tpgGeneral.PerformLayout();
this.tableLayoutPanel4.ResumeLayout(false); this.tableLayoutPanel4.ResumeLayout(false);
this.tableLayoutPanel4.PerformLayout(); this.tableLayoutPanel4.PerformLayout();
this.flowLayoutPanel5.ResumeLayout(false);
this.flowLayoutPanel5.PerformLayout();
this.flowLayoutPanel9.ResumeLayout(false); this.flowLayoutPanel9.ResumeLayout(false);
this.flowLayoutPanel9.PerformLayout(); this.flowLayoutPanel9.PerformLayout();
this.flowLayoutPanel6.ResumeLayout(false); this.flowLayoutPanel6.ResumeLayout(false);
@ -718,5 +791,9 @@
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2; private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2;
private Controls.ctrlRiskyOption chkEnableRandomPowerOnState; private Controls.ctrlRiskyOption chkEnableRandomPowerOnState;
private Controls.ctrlRiskyOption chkEnableStrictBoardMappings; private Controls.ctrlRiskyOption chkEnableStrictBoardMappings;
} private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel5;
private Controls.MesenNumericUpDown nudRunAheadFrames;
private System.Windows.Forms.Label lblRunAheadFrames;
private System.Windows.Forms.Label lblRunAhead;
}
} }

View file

@ -26,6 +26,7 @@ namespace Mesen.GUI.Forms.Config
AddBinding(nameof(EmulationConfig.TurboSpeed), nudTurboSpeed); AddBinding(nameof(EmulationConfig.TurboSpeed), nudTurboSpeed);
AddBinding(nameof(EmulationConfig.RewindSpeed), nudRewindSpeed); AddBinding(nameof(EmulationConfig.RewindSpeed), nudRewindSpeed);
AddBinding(nameof(EmulationConfig.Region), cboRegion); AddBinding(nameof(EmulationConfig.Region), cboRegion);
AddBinding(nameof(EmulationConfig.RunAheadFrames), nudRunAheadFrames);
AddBinding(nameof(EmulationConfig.RamPowerOnState), cboRamPowerOnState); AddBinding(nameof(EmulationConfig.RamPowerOnState), cboRamPowerOnState);
AddBinding(nameof(EmulationConfig.EnableRandomPowerOnState), chkEnableRandomPowerOnState); AddBinding(nameof(EmulationConfig.EnableRandomPowerOnState), chkEnableRandomPowerOnState);

View file

@ -8,49 +8,60 @@ Serializer::Serializer(uint32_t version)
{ {
_version = version; _version = version;
_block.Data = vector<uint8_t>(0x50000); _block.reset(new BlockData());
_block.Position = 0; _block->Data = vector<uint8_t>(0x50000);
_block->Position = 0;
_saving = true; _saving = true;
} }
Serializer::Serializer(istream &file, uint32_t version) Serializer::Serializer(istream &file, uint32_t version, bool compressed)
{ {
_version = version; _version = version;
_block.Position = 0; _block.reset(new BlockData());
_block->Position = 0;
_saving = false; _saving = false;
uint32_t decompressedSize; if(compressed) {
file.read((char*)&decompressedSize, sizeof(decompressedSize)); uint32_t decompressedSize;
file.read((char*)&decompressedSize, sizeof(decompressedSize));
uint32_t compressedSize; uint32_t compressedSize;
file.read((char*)&compressedSize, sizeof(compressedSize)); file.read((char*)&compressedSize, sizeof(compressedSize));
vector<uint8_t> compressedData(compressedSize, 0); vector<uint8_t> compressedData(compressedSize, 0);
file.read((char*)compressedData.data(), compressedSize); file.read((char*)compressedData.data(), compressedSize);
_block.Data = vector<uint8_t>(decompressedSize, 0); _block->Data = vector<uint8_t>(decompressedSize, 0);
unsigned long decompSize = decompressedSize; unsigned long decompSize = decompressedSize;
uncompress(_block.Data.data(), &decompSize, compressedData.data(), (unsigned long)compressedData.size()); uncompress(_block->Data.data(), &decompSize, compressedData.data(), (unsigned long)compressedData.size());
} else {
file.seekg(0, std::ios::end);
uint32_t size = (uint32_t)file.tellg();
file.seekg(0, std::ios::beg);
_block->Data = vector<uint8_t>(size, 0);
file.read((char*)_block->Data.data(), size);
}
} }
void Serializer::EnsureCapacity(uint32_t typeSize) void Serializer::EnsureCapacity(uint32_t typeSize)
{ {
//Make sure the current block/stream is large enough to fit the next write //Make sure the current block/stream is large enough to fit the next write
uint32_t oldSize = (uint32_t)_block.Data.size(); uint32_t oldSize = (uint32_t)_block->Data.size();
if(oldSize == 0) { if(oldSize == 0) {
oldSize = typeSize * 2; oldSize = typeSize * 2;
} }
uint32_t sizeRequired = _block.Position + typeSize; uint32_t sizeRequired = _block->Position + typeSize;
uint32_t newSize = oldSize; uint32_t newSize = oldSize;
while(newSize < sizeRequired) { while(newSize < sizeRequired) {
newSize *= 2; newSize *= 2;
} }
_block.Data.resize(newSize); _block->Data.resize(newSize);
} }
void Serializer::RecursiveStream() void Serializer::RecursiveStream()
@ -59,18 +70,18 @@ void Serializer::RecursiveStream()
void Serializer::StreamStartBlock() void Serializer::StreamStartBlock()
{ {
BlockData block; unique_ptr<BlockData> block(new BlockData());
block.Position = 0; block->Position = 0;
if(!_saving) { if(!_saving) {
VectorInfo<uint8_t> vectorInfo = { &block.Data }; VectorInfo<uint8_t> vectorInfo = { &block->Data };
InternalStream(vectorInfo); InternalStream(vectorInfo);
} else { } else {
block.Data = vector<uint8_t>(0x100); block->Data = vector<uint8_t>(0x100);
} }
_blocks.push_back(_block); _blocks.push_back(std::move(_block));
_block = block; _block = std::move(block);
} }
void Serializer::StreamEndBlock() void Serializer::StreamEndBlock()
@ -79,28 +90,32 @@ void Serializer::StreamEndBlock()
throw std::runtime_error("Invalid call to end block"); throw std::runtime_error("Invalid call to end block");
} }
BlockData block = _block; unique_ptr<BlockData> block = std::move(_block);
_block = _blocks.back(); _block = std::move(_blocks.back());
_blocks.pop_back(); _blocks.pop_back();
if(_saving) { if(_saving) {
ArrayInfo<uint8_t> arrayInfo { block.Data.data(), block.Position }; ArrayInfo<uint8_t> arrayInfo { block->Data.data(), block->Position };
InternalStream(arrayInfo); InternalStream(arrayInfo);
} }
} }
void Serializer::Save(ostream& file, int compressionLevel) void Serializer::Save(ostream& file, int compressionLevel)
{ {
unsigned long compressedSize = compressBound((unsigned long)_block.Position); if(compressionLevel == 0) {
uint8_t* compressedData = new uint8_t[compressedSize]; file.write((char*)_block->Data.data(), _block->Position);
compress2(compressedData, &compressedSize, (unsigned char*)_block.Data.data(), (unsigned long)_block.Position, compressionLevel); } else {
unsigned long compressedSize = compressBound((unsigned long)_block->Position);
uint8_t* compressedData = new uint8_t[compressedSize];
compress2(compressedData, &compressedSize, (unsigned char*)_block->Data.data(), (unsigned long)_block->Position, compressionLevel);
uint32_t size = (uint32_t)compressedSize; uint32_t size = (uint32_t)compressedSize;
file.write((char*)&_block.Position, sizeof(uint32_t)); file.write((char*)&_block->Position, sizeof(uint32_t));
file.write((char*)&size, sizeof(uint32_t)); file.write((char*)&size, sizeof(uint32_t));
file.write((char*)compressedData, compressedSize); file.write((char*)compressedData, compressedSize);
delete[] compressedData; delete[] compressedData;
}
} }
void Serializer::WriteEmptyBlock(ostream* file) void Serializer::WriteEmptyBlock(ostream* file)

View file

@ -34,9 +34,8 @@ struct BlockData
class Serializer class Serializer
{ {
private: private:
vector<BlockData> _blocks; vector<unique_ptr<BlockData>> _blocks;
unique_ptr<BlockData> _block;
BlockData _block;
uint32_t _version = 0; uint32_t _version = 0;
bool _saving = false; bool _saving = false;
@ -60,7 +59,7 @@ private:
public: public:
Serializer(uint32_t version); Serializer(uint32_t version);
Serializer(istream &file, uint32_t version); Serializer(istream &file, uint32_t version, bool compressed = true);
uint32_t GetVersion() { return _version; } uint32_t GetVersion() { return _version; }
bool IsSaving() { return _saving; } bool IsSaving() { return _saving; }
@ -87,15 +86,15 @@ void Serializer::StreamElement(T &value, T defaultValue)
EnsureCapacity(typeSize); EnsureCapacity(typeSize);
for(int i = 0; i < typeSize; i++) { for(int i = 0; i < typeSize; i++) {
_block.Data[_block.Position++] = bytes[i]; _block->Data[_block->Position++] = bytes[i];
} }
} else { } else {
if(_block.Position + sizeof(T) <= _block.Data.size()) { if(_block->Position + sizeof(T) <= _block->Data.size()) {
memcpy(&value, _block.Data.data() + _block.Position, sizeof(T)); memcpy(&value, _block->Data.data() + _block->Position, sizeof(T));
_block.Position += sizeof(T); _block->Position += sizeof(T);
} else { } else {
value = defaultValue; value = defaultValue;
_block.Position = (uint32_t)_block.Data.size(); _block->Position = (uint32_t)_block->Data.size();
} }
} }
} }
@ -115,11 +114,11 @@ void Serializer::InternalStream(ArrayInfo<T> &info)
EnsureCapacity(info.ElementCount * sizeof(T)); EnsureCapacity(info.ElementCount * sizeof(T));
if(_saving) { if(_saving) {
memcpy(_block.Data.data() + _block.Position, info.Array, info.ElementCount * sizeof(T)); memcpy(_block->Data.data() + _block->Position, info.Array, info.ElementCount * sizeof(T));
} else { } else {
memcpy(info.Array, _block.Data.data() + _block.Position, info.ElementCount * sizeof(T)); memcpy(info.Array, _block->Data.data() + _block->Position, info.ElementCount * sizeof(T));
} }
_block.Position += info.ElementCount * sizeof(T); _block->Position += info.ElementCount * sizeof(T);
} }
template<typename T> template<typename T>