Move all frame dumping logic in GS handler.

Fixes a bunch of incomplete dump issues, race conditions and potential crashes.
This commit is contained in:
Jean-Philip Desjardins 2023-11-24 13:51:20 -05:00
parent d5208b7322
commit 97cf4123b9
5 changed files with 54 additions and 76 deletions

View file

@ -324,19 +324,6 @@ std::future<bool> CPS2VM::LoadState(const fs::path& statePath)
return future;
}
void CPS2VM::TriggerFrameDump(const FrameDumpCallback& frameDumpCallback)
{
#ifdef DEBUGGER_INCLUDED
m_mailBox.SendCall(
[=]() {
std::unique_lock<std::mutex> frameDumpCallbackMutexLock(m_frameDumpCallbackMutex);
if(m_frameDumpCallback) return;
m_frameDumpCallback = frameDumpCallback;
},
false);
#endif
}
CPS2VM::CPU_UTILISATION_INFO CPS2VM::GetCpuUtilisationInfo() const
{
return m_cpuUtilisation;
@ -633,7 +620,6 @@ void CPS2VM::CreateGsHandlerImpl(const CGSHandler::FactoryFunction& factoryFunct
gs->Release();
delete gs;
}
m_OnNewFrameConnection = m_ee->m_gs->OnNewFrame.Connect(std::bind(&CPS2VM::OnGsNewFrame, this));
}
void CPS2VM::DestroyGsHandlerImpl()
@ -679,26 +665,6 @@ void CPS2VM::DestroySoundHandlerImpl()
m_soundHandler = nullptr;
}
void CPS2VM::OnGsNewFrame()
{
#ifdef DEBUGGER_INCLUDED
std::unique_lock<std::mutex> dumpFrameCallbackMutexLock(m_frameDumpCallbackMutex);
if(m_dumpingFrame && !m_frameDump.GetPackets().empty())
{
m_ee->m_gs->EndFrameDump();
m_frameDumpCallback(m_frameDump);
m_dumpingFrame = false;
m_frameDumpCallback = FrameDumpCallback();
}
else if(m_frameDumpCallback)
{
m_frameDump.Reset();
m_ee->m_gs->BeginFrameDump(&m_frameDump);
m_dumpingFrame = true;
}
#endif
}
void CPS2VM::UpdateEe()
{
#ifdef PROFILE

View file

@ -13,7 +13,6 @@
#include "ee/Ee_SubSystem.h"
#include "iop/Iop_SubSystem.h"
#include "../tools/PsfPlayer/Source/SoundHandler.h"
#include "FrameDump.h"
#include "FrameLimiter.h"
#include "Profiler.h"
@ -32,7 +31,6 @@ public:
typedef std::unique_ptr<COpticalMedia> OpticalMediaPtr;
typedef std::unique_ptr<Ee::CSubSystem> EeSubSystemPtr;
typedef std::unique_ptr<Iop::CSubSystem> IopSubSystemPtr;
typedef std::function<void(const CFrameDump&)> FrameDumpCallback;
typedef Framework::CSignal<void(const CProfiler::ZoneArray&)> ProfileFrameDoneSignal;
typedef std::function<void(CPS2VM*)> ExecutableReloadedHandler;
@ -79,8 +77,6 @@ public:
std::future<bool> SaveState(const fs::path&);
std::future<bool> LoadState(const fs::path&);
void TriggerFrameDump(const FrameDumpCallback&);
CPU_UTILISATION_INFO GetCpuUtilisationInfo() const;
#ifdef DEBUGGER_INCLUDED
@ -142,8 +138,6 @@ private:
void UpdateIop();
void UpdateSpu();
void OnGsNewFrame();
void SetIopOpticalMedia(COpticalMedia*);
void RegisterModulesInPadHandler();
@ -179,13 +173,6 @@ private:
bool m_singleStepVu0 = false;
bool m_singleStepVu1 = false;
#ifdef DEBUGGER_INCLUDED
CFrameDump m_frameDump;
FrameDumpCallback m_frameDumpCallback;
std::mutex m_frameDumpCallbackMutex;
bool m_dumpingFrame = false;
#endif
//SPU update parameters
enum
{
@ -211,5 +198,4 @@ private:
CPS2OS::RequestLoadExecutableEvent::Connection m_OnRequestLoadExecutableConnection;
Framework::CSignal<void()>::Connection m_OnCrtModeChangeConnection;
Framework::CSignal<void(uint32)>::Connection m_OnNewFrameConnection;
};

View file

@ -336,22 +336,38 @@ void CGSHandler::Copy(CGSHandler* source)
SendGSCall([&]() { WriteBackMemoryCache(); });
}
void CGSHandler::BeginFrameDump(CFrameDump* frameDump)
void CGSHandler::TriggerFrameDump(const FrameDumpCallback& frameDumpCallback)
{
m_frameDump = frameDump;
//This is expected to be called from the GS thread
SyncMemoryCache();
memcpy(m_frameDump->GetInitialGsRam(), GetRam(), RAMSIZE);
memcpy(m_frameDump->GetInitialGsRegisters(), GetRegisters(), CGSHandler::REGISTER_MAX * sizeof(uint64));
m_frameDump->SetInitialSMODE2(GetSMODE2());
#ifdef DEBUGGER_INCLUDED
m_mailBox.SendCall(
[=]() {
if(m_frameDumpCallback) return;
m_frameDumpCallback = frameDumpCallback;
});
#endif
}
void CGSHandler::EndFrameDump()
void CGSHandler::UpdateFrameDumpState()
{
assert(m_frameDump);
m_frameDump = nullptr;
#ifdef DEBUGGER_INCLUDED
if(m_frameDump && !m_frameDump->GetPackets().empty())
{
m_frameDumpCallback(*m_frameDump.get());
m_frameDumpCallback = FrameDumpCallback();
m_frameDump.reset();
}
else if(m_frameDumpCallback)
{
m_frameDump = std::make_unique<CFrameDump>();
//This is expected to be called from the GS thread
SyncMemoryCache();
memcpy(m_frameDump->GetInitialGsRam(), GetRam(), RAMSIZE);
memcpy(m_frameDump->GetInitialGsRegisters(), GetRegisters(), CGSHandler::REGISTER_MAX * sizeof(uint64));
m_frameDump->SetInitialSMODE2(GetSMODE2());
}
#endif
}
void CGSHandler::InitFromFrameDump(CFrameDump* frameDump)
@ -570,6 +586,7 @@ void CGSHandler::MarkNewFrame()
{
OnNewFrame(m_drawCallCount);
m_drawCallCount = 0;
UpdateFrameDumpState();
#ifdef _DEBUG
CLog::GetInstance().Print(LOG_NAME, "Frame Done.\r\n---------------------------------------------------------------------------------\r\n");
#endif
@ -614,14 +631,14 @@ void CGSHandler::FeedImageData(const void* data, uint32 length)
std::vector<uint8> imageData(length + 0x10);
memcpy(imageData.data(), data, length);
#ifdef DEBUGGER_INCLUDED
if(m_frameDump)
{
m_frameDump->AddImagePacket(imageData.data(), length);
}
#endif
SendGSCall(
[this, imageData = std::move(imageData), length]() {
#ifdef DEBUGGER_INCLUDED
if(m_frameDump)
{
m_frameDump->AddImagePacket(imageData.data(), length);
}
#endif
FeedImageDataImpl(imageData.data(), length);
});
}
@ -638,13 +655,18 @@ void CGSHandler::ProcessWriteBuffer(const CGsPacketMetadata* metadata)
assert(m_writeBufferProcessIndex <= m_writeBufferSize);
assert(m_writeBufferSubmitIndex <= m_writeBufferProcessIndex);
#ifdef DEBUGGER_INCLUDED
if(m_frameDump)
if(uint32 packetSize = m_writeBufferSize - m_writeBufferProcessIndex; packetSize != 0)
{
uint32 packetSize = m_writeBufferSize - m_writeBufferProcessIndex;
if(packetSize != 0)
{
m_frameDump->AddRegisterPacket(m_currentWriteBuffer + m_writeBufferProcessIndex, packetSize, metadata);
}
SendGSCall(
[this,
packet = m_currentWriteBuffer + m_writeBufferProcessIndex,
packetSize,
metadata = metadata ? *metadata : CGsPacketMetadata()]() {
if(m_frameDump)
{
m_frameDump->AddRegisterPacket(packet, packetSize, &metadata);
}
});
}
#endif
for(uint32 writeIndex = m_writeBufferProcessIndex; writeIndex < m_writeBufferSize; writeIndex++)

View file

@ -813,6 +813,8 @@ public:
typedef std::vector<RegisterWrite> RegisterWriteList;
typedef std::function<CGSHandler*(void)> FactoryFunction;
typedef std::function<void(const CFrameDump&)> FrameDumpCallback;
typedef Framework::CSignal<void()> FlipCompleteEvent;
typedef Framework::CSignal<void(uint32)> NewFrameEvent;
@ -831,8 +833,7 @@ public:
virtual void LoadState(Framework::CZipArchiveReader&);
void Copy(CGSHandler*);
void BeginFrameDump(CFrameDump*);
void EndFrameDump();
void TriggerFrameDump(const FrameDumpCallback&);
void InitFromFrameDump(CFrameDump*);
@ -1042,6 +1043,8 @@ protected:
void ReadImageDataImpl(void*, uint32);
void SubmitWriteBufferImpl(const RegisterWrite*, const RegisterWrite*);
void UpdateFrameDumpState();
void BeginTransfer();
virtual void BeginTransferWrite();
@ -1124,7 +1127,8 @@ protected:
#endif
std::atomic<int> m_framesInFlight;
bool m_threadDone = false;
CFrameDump* m_frameDump = nullptr;
std::unique_ptr<CFrameDump> m_frameDump;
FrameDumpCallback m_frameDumpCallback;
bool m_regsDirty = false;
bool m_drawEnabled = true;
CINTC* m_intc = nullptr;

View file

@ -962,7 +962,7 @@ fs::path MainWindow::GetFrameDumpDirectoryPath()
void MainWindow::DumpNextFrame()
{
m_virtualMachine->TriggerFrameDump(
m_virtualMachine->m_ee->m_gs->TriggerFrameDump(
[&](const CFrameDump& frameDump) {
try
{