From 4608333a560e9d92f518689ee7ed6730a652dca8 Mon Sep 17 00:00:00 2001 From: hrydgard Date: Sat, 30 Aug 2008 16:05:32 +0000 Subject: [PATCH] State saving progress. Most core state seems to be saved/loaded correctly, not so for video yet unfortunately. git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@386 8ced0084-cf51-0410-be5f-012b33b47a6e --- Source/Core/Common/Src/ChunkFile.h | 26 +++++ Source/Core/Core/Src/CoreTiming.cpp | 96 +++++++++++++++++-- Source/Core/Core/Src/CoreTiming.h | 14 ++- Source/Core/Core/Src/HW/HW.cpp | 6 +- Source/Core/Core/Src/HW/SystemTimers.cpp | 1 - Source/Core/Core/Src/PowerPC/PowerPC.cpp | 1 - Source/Core/Core/Src/State.cpp | 10 +- Source/Core/VideoCommon/Src/Fifo.cpp | 5 +- Source/Core/VideoCommon/Src/VideoState.cpp | 35 +++---- .../Plugin_VideoDX9/Src/ShaderManager.cpp | 2 +- .../Plugins/Plugin_VideoOGL/Src/Globals.cpp | 5 +- 11 files changed, 159 insertions(+), 42 deletions(-) diff --git a/Source/Core/Common/Src/ChunkFile.h b/Source/Core/Common/Src/ChunkFile.h index d7e4291535..eb31926a48 100644 --- a/Source/Core/Common/Src/ChunkFile.h +++ b/Source/Core/Common/Src/ChunkFile.h @@ -18,6 +18,15 @@ #ifndef _POINTERWRAP_H #define _POINTERWRAP_H +// Extremely simple serialization framework. + +// (mis)-features: +// + Super fast +// + Very simple +// + Same code is used for serialization and deserializaition (in most cases) +// - Zero backwards/forwards compatibility +// - Serialization code for anything complex has to be manually written. + #include #include @@ -25,6 +34,13 @@ #include "Common.h" +template +struct LinkedListItem : public T +{ + LinkedListItem *next; +}; + + class PointerWrap { public: @@ -61,10 +77,14 @@ public: // Store maps to file. Very useful. template void Do(std::map &x) { + // TODO + PanicAlert("Do(map<>) does not yet work."); } // Store vectors. template void Do(std::vector &x) { + // TODO + PanicAlert("Do(vector<>) does not yet work."); } template @@ -76,6 +96,12 @@ public: void Do(T &x) { DoVoid((void *)&x, sizeof(x)); } + + template + void DoLinkedList(LinkedListItem **list_start) { + // TODO + PanicAlert("Do(vector<>) does not yet work."); + } }; #endif // _POINTERWRAP_H diff --git a/Source/Core/Core/Src/CoreTiming.cpp b/Source/Core/Core/Src/CoreTiming.cpp index 54a5a9d3fc..a8da759768 100644 --- a/Source/Core/Core/Src/CoreTiming.cpp +++ b/Source/Core/Core/Src/CoreTiming.cpp @@ -20,6 +20,7 @@ #include "Thread.h" #include "PowerPC/PowerPC.h" #include "CoreTiming.h" +#include "StringUtil.h" // TODO(ector): Replace new/delete in this file with a simple memory pool // Don't expect a massive speedup though. @@ -35,14 +36,16 @@ struct EventType std::vector event_types; -struct Event +struct BaseEvent { s64 time; u64 userdata; - Event *next; int type; +// Event *next; }; +typedef LinkedListItem Event; + // STATE_TO_SAVE (how?) Event *first; Event *tsFirst; @@ -55,6 +58,8 @@ s64 idledCycles; Common::CriticalSection externalEventSection; +void (*advanceCallback)(int cyclesExecuted); + int RegisterEvent(const char *name, TimedCallback callback) { EventType type; @@ -71,14 +76,72 @@ void UnregisterAllEvents() event_types.clear(); } +void Init() +{ + downcount = maxSliceLength; + slicelength = maxSliceLength; + globalTimer = 0; + idledCycles = 0; +} + +void Shutdown() +{ + ClearPendingEvents(); + UnregisterAllEvents(); +} + void DoState(PointerWrap &p) { externalEventSection.Enter(); p.Do(downcount); p.Do(slicelength); - p.Do(maxSliceLength); p.Do(globalTimer); p.Do(idledCycles); + // OK, here we're gonna need to specialize depending on the mode. + // Should do something generic to serialize linked lists. + switch (p.GetMode()) { + case PointerWrap::MODE_READ: + { + ClearPendingEvents(); + if (first) + PanicAlert("Clear failed."); + int more_events = 0; + Event *prev = 0; + while (true) { + p.Do(more_events); + if (!more_events) + break; + Event *ev = new Event; + if (!prev) + first = ev; + else + prev->next = ev; + p.Do(ev->time); + p.Do(ev->type); + p.Do(ev->userdata); + ev->next = 0; + prev = ev; + ev = ev->next; + } + } + break; + case PointerWrap::MODE_MEASURE: + case PointerWrap::MODE_WRITE: + { + Event *ev = first; + int more_events = 1; + while (ev) { + p.Do(more_events); + p.Do(ev->time); + p.Do(ev->type); + p.Do(ev->userdata); + ev = ev->next; + } + more_events = 0; + p.Do(more_events); + break; + } + } externalEventSection.Leave(); } @@ -106,14 +169,12 @@ void ScheduleEvent_Threadsafe(int cyclesIntoFuture, int event_type, u64 userdata externalEventSection.Leave(); } -void Clear() +void ClearPendingEvents() { - globalTimer = 0; - idledCycles = 0; while (first) { Event *e = first->next; - delete [] first; + delete first; first = e; } } @@ -172,9 +233,6 @@ void ScheduleEvent(int cyclesIntoFuture, int event_type, u64 userdata) AddEventToQueue(ne); } -void (*advanceCallback)(int cyclesExecuted); - - void RegisterAdvanceCallback(void (*callback)(int cyclesExecuted)) { advanceCallback = callback; @@ -302,5 +360,23 @@ void Idle() Advance(); } +std::string GetScheduledEventsSummary() +{ + Event *ptr = first; + std::string text = "Scheduled events\n"; + text.reserve(1000); + while (ptr) + { + int t = ptr->type; + if (t < 0 || t >= event_types.size()) + PanicAlert("Invalid event type %i", t); + const char *name = event_types[ptr->type].name; + if (!name) + name = "[unknown]"; + text += StringFromFormat("%s : %i %08x%08x\n", event_types[ptr->type].name, ptr->time, ptr->userdata >> 32, ptr->userdata); + ptr = ptr->next; + } + return text; +} }; // end of namespace diff --git a/Source/Core/Core/Src/CoreTiming.h b/Source/Core/Core/Src/CoreTiming.h index 9f08e3cc80..09f4ea4f9f 100644 --- a/Source/Core/Core/Src/CoreTiming.h +++ b/Source/Core/Core/Src/CoreTiming.h @@ -25,11 +25,18 @@ // callback. You then schedule events using the type id you get back. #include "Common.h" + +#include + #include "ChunkFile.h" namespace CoreTiming { + +void Init(); +void Shutdown(); + typedef void (*TimedCallback)(u64 userdata, int cyclesLate); u64 GetTicks(); @@ -58,13 +65,16 @@ void Advance(); // Pretend that the main CPU has executed enough cycles to reach the next event. void Idle(); -// Clear all pending events. This should ONLY be done on exit. -void Clear(); +// Clear all pending events. This should ONLY be done on exit or state load. +void ClearPendingEvents(); + void LogPendingEvents(); void SetMaximumSlice(int maximumSliceLength); void RegisterAdvanceCallback(void (*callback)(int cyclesExecuted)); +std::string GetScheduledEventsSummary(); + extern int downcount; extern int slicelength; diff --git a/Source/Core/Core/Src/HW/HW.cpp b/Source/Core/Core/Src/HW/HW.cpp index a132670db9..33ea6fdcf4 100644 --- a/Source/Core/Core/Src/HW/HW.cpp +++ b/Source/Core/Core/Src/HW/HW.cpp @@ -45,6 +45,8 @@ namespace HW { void Init() { + CoreTiming::Init(); + Thunk_Init(); // not really hw, but this way we know it's inited first :P State_Init(); @@ -83,8 +85,7 @@ namespace HW State_Shutdown(); Thunk_Shutdown(); - - CoreTiming::UnregisterAllEvents(); + CoreTiming::Shutdown(); } void DoState(PointerWrap &p) @@ -100,7 +101,6 @@ namespace HW GPFifo::DoState(p); ExpansionInterface::DoState(p); AudioInterface::DoState(p); - CoreTiming::DoState(p); WII_IPCInterface::DoState(p); } } diff --git a/Source/Core/Core/Src/HW/SystemTimers.cpp b/Source/Core/Core/Src/HW/SystemTimers.cpp index 10615acca7..eb9dc676c4 100644 --- a/Source/Core/Core/Src/HW/SystemTimers.cpp +++ b/Source/Core/Core/Src/HW/SystemTimers.cpp @@ -217,7 +217,6 @@ void Init() void Shutdown() { Common::Timer::RestoreResolution(); - CoreTiming::Clear(); } } // namespace diff --git a/Source/Core/Core/Src/PowerPC/PowerPC.cpp b/Source/Core/Core/Src/PowerPC/PowerPC.cpp index 2a2d3cd358..997dc8cc7f 100644 --- a/Source/Core/Core/Src/PowerPC/PowerPC.cpp +++ b/Source/Core/Core/Src/PowerPC/PowerPC.cpp @@ -44,7 +44,6 @@ namespace PowerPC void DoState(PointerWrap &p) { p.Do(ppcState); - p.Do(state); } void ResetRegisters() diff --git a/Source/Core/Core/Src/State.cpp b/Source/Core/Core/Src/State.cpp index e6bb40ea07..d43e5a88c1 100644 --- a/Source/Core/Core/Src/State.cpp +++ b/Source/Core/Core/Src/State.cpp @@ -41,7 +41,7 @@ void DoState(PointerWrap &p) PowerPC::DoState(p); HW::DoState(p); CoreTiming::DoState(p); - PluginVideo::Video_DoState(p.GetPPtr(), p.GetMode()); + // PluginVideo::Video_DoState(p.GetPPtr(), p.GetMode()); } void SaveStateCallback(u64 userdata, int cyclesLate) @@ -59,6 +59,7 @@ void SaveStateCallback(u64 userdata, int cyclesLate) FILE *f = fopen(cur_filename.c_str(), "wb"); fwrite(buffer, sz, 1, f); fclose(f); + delete [] buffer; Core::DisplayMessage("Saved State", 2000); @@ -68,17 +69,20 @@ void LoadStateCallback(u64 userdata, int cyclesLate) { Jit64::ClearCache(); - FILE *f = fopen(cur_filename.c_str(), "r"); + FILE *f = fopen(cur_filename.c_str(), "rb"); fseek(f, 0, SEEK_END); int sz = ftell(f); fseek(f, 0, SEEK_SET); u8 *buffer = new u8[sz]; - fread(buffer, sz, 1, f); + int x; + if (x=fread(buffer, 1, sz, f) != sz) + PanicAlert("wtf? %d %d", x, sz); fclose(f); u8 *ptr = buffer; PointerWrap p(&ptr, PointerWrap::MODE_READ); DoState(p); + delete [] buffer; Core::DisplayMessage("Loaded State", 2000); } diff --git a/Source/Core/VideoCommon/Src/Fifo.cpp b/Source/Core/VideoCommon/Src/Fifo.cpp index b665b37fc6..254c6960d1 100644 --- a/Source/Core/VideoCommon/Src/Fifo.cpp +++ b/Source/Core/VideoCommon/Src/Fifo.cpp @@ -33,16 +33,15 @@ static int size = 0; static int readptr = 0; void Fifo_DoState(PointerWrap &p) { - p.Do(size); p.DoArray(videoBuffer, size); - + p.Do(size); p.Do(readptr); } void Fifo_Init() { videoBuffer = (u8*)AllocateMemoryPages(FIFO_SIZE); - fifo.Init(videoBuffer, videoBuffer); //zero length. there is no data yet. + fifo.Init(videoBuffer, videoBuffer); //zero length. there is no data yet. } void Fifo_Shutdown() diff --git a/Source/Core/VideoCommon/Src/VideoState.cpp b/Source/Core/VideoCommon/Src/VideoState.cpp index 65ec2e05c3..8e187c585e 100644 --- a/Source/Core/VideoCommon/Src/VideoState.cpp +++ b/Source/Core/VideoCommon/Src/VideoState.cpp @@ -23,22 +23,25 @@ #include "TextureDecoder.h" #include "Fifo.h" +static void DoState(PointerWrap &p) { + // BP Memory + p.Do(bpmem); + // CP Memory + p.DoArray(arraybases, 16); + p.DoArray(arraystrides, 16); + p.Do(MatrixIndexA); + p.Do(MatrixIndexB); + // XF Memory + p.Do(xfregs); + p.DoArray(xfmem, XFMEM_SIZE); + // Texture decoder + p.DoArray(texMem, TMEM_SIZE); + + // FIFO + Fifo_DoState(p); +} + void VideoCommon_DoState(PointerWrap &p) { - // BP Memory - p.Do(bpmem); - // CP Memory - p.Do(arraybases); - p.Do(arraystrides); - p.Do(MatrixIndexA); - p.Do(MatrixIndexB); - // XF Memory - p.Do(xfregs); - p.Do(xfmem); - // Texture decoder - p.Do(texMem); - - // FIFO - Fifo_DoState(p); - + DoState(p); //TODO: search for more data that should be saved and add it here } diff --git a/Source/Plugins/Plugin_VideoDX9/Src/ShaderManager.cpp b/Source/Plugins/Plugin_VideoDX9/Src/ShaderManager.cpp index 3f8517d8e2..455b0aa07b 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/ShaderManager.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/ShaderManager.cpp @@ -179,7 +179,7 @@ void VShaderCache::Cleanup() for (VSCache::iterator iter=vshaders.begin(); iter!=vshaders.end();iter++) { VSCacheEntry &entry = iter->second; - if (entry.frameCount + float MValueX, MValueY; // Since it can Stretch to fit Window, we need two different multiplication values// int frameCount; - Config g_Config; + Statistics stats; void Statistics::ResetFrame() { - memset(&thisFrame,0,sizeof(ThisFrame)); + memset(&thisFrame, 0, sizeof(ThisFrame)); } Config::Config()