mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-02-13 07:58:36 +02:00
FifoPlayer: Add an "Analyzer" tab which allows browsing through all rendered objects per frame and through all register setting commands per object
This commit is contained in:
parent
96d56cd8ef
commit
700123c55b
@ -95,6 +95,7 @@ bool FifoPlayer::Play()
|
|||||||
WriteAllMemoryUpdates();
|
WriteAllMemoryUpdates();
|
||||||
|
|
||||||
WriteFrame(m_File->GetFrame(m_CurrentFrame), m_FrameInfo[m_CurrentFrame]);
|
WriteFrame(m_File->GetFrame(m_CurrentFrame), m_FrameInfo[m_CurrentFrame]);
|
||||||
|
|
||||||
++m_CurrentFrame;
|
++m_CurrentFrame;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,6 +44,8 @@ public:
|
|||||||
u32 GetFrameObjectCount();
|
u32 GetFrameObjectCount();
|
||||||
u32 GetCurrentFrameNum() { return m_CurrentFrame; }
|
u32 GetCurrentFrameNum() { return m_CurrentFrame; }
|
||||||
|
|
||||||
|
const AnalyzedFrameInfo& GetAnalyzedFrameInfo(u32 frame) { return m_FrameInfo[frame]; }
|
||||||
|
|
||||||
// Frame range
|
// Frame range
|
||||||
u32 GetFrameRangeStart() { return m_FrameRangeStart; }
|
u32 GetFrameRangeStart() { return m_FrameRangeStart; }
|
||||||
void SetFrameRangeStart(u32 start);
|
void SetFrameRangeStart(u32 start);
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include "Thread.h"
|
#include "Thread.h"
|
||||||
#include "FifoPlayer/FifoPlayer.h"
|
#include "FifoPlayer/FifoPlayer.h"
|
||||||
#include "FifoPlayer/FifoRecorder.h"
|
#include "FifoPlayer/FifoRecorder.h"
|
||||||
|
#include "OpcodeDecoding.h"
|
||||||
#include <wx/spinctrl.h>
|
#include <wx/spinctrl.h>
|
||||||
|
|
||||||
DECLARE_EVENT_TYPE(RECORDING_FINISHED_EVENT, -1)
|
DECLARE_EVENT_TYPE(RECORDING_FINISHED_EVENT, -1)
|
||||||
@ -65,6 +66,10 @@ FifoPlayerDlg::~FifoPlayerDlg()
|
|||||||
m_FramesToRecordCtrl->Disconnect(wxEVT_COMMAND_SPINCTRL_UPDATED, wxSpinEventHandler(FifoPlayerDlg::OnNumFramesToRecord), NULL, this);
|
m_FramesToRecordCtrl->Disconnect(wxEVT_COMMAND_SPINCTRL_UPDATED, wxSpinEventHandler(FifoPlayerDlg::OnNumFramesToRecord), NULL, this);
|
||||||
m_Close->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(FifoPlayerDlg::OnCloseClick), NULL, this);
|
m_Close->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(FifoPlayerDlg::OnCloseClick), NULL, this);
|
||||||
|
|
||||||
|
m_framesList->Disconnect(wxEVT_COMMAND_LISTBOX_SELECTED, wxCommandEventHandler(FifoPlayerDlg::OnFrameListSelectionChanged), NULL, this);
|
||||||
|
m_objectsList->Disconnect(wxEVT_COMMAND_LISTBOX_SELECTED, wxCommandEventHandler(FifoPlayerDlg::OnObjectListSelectionChanged), NULL, this);
|
||||||
|
m_objectCmdList->Disconnect(wxEVT_COMMAND_LISTBOX_SELECTED, wxCommandEventHandler(FifoPlayerDlg::OnObjectCmdListSelectionChanged), NULL, this);
|
||||||
|
|
||||||
FifoPlayer::GetInstance().SetFrameWrittenCallback(NULL);
|
FifoPlayer::GetInstance().SetFrameWrittenCallback(NULL);
|
||||||
|
|
||||||
sMutex.lock();
|
sMutex.lock();
|
||||||
@ -80,6 +85,8 @@ void FifoPlayerDlg::CreateGUIControls()
|
|||||||
sMain = new wxBoxSizer(wxVERTICAL);
|
sMain = new wxBoxSizer(wxVERTICAL);
|
||||||
|
|
||||||
m_Notebook = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0);
|
m_Notebook = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0);
|
||||||
|
|
||||||
|
{
|
||||||
m_PlayPage = new wxPanel(m_Notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
|
m_PlayPage = new wxPanel(m_Notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
|
||||||
wxBoxSizer* sPlayPage;
|
wxBoxSizer* sPlayPage;
|
||||||
sPlayPage = new wxBoxSizer(wxVERTICAL);
|
sPlayPage = new wxBoxSizer(wxVERTICAL);
|
||||||
@ -151,6 +158,9 @@ void FifoPlayerDlg::CreateGUIControls()
|
|||||||
m_PlayPage->Layout();
|
m_PlayPage->Layout();
|
||||||
sPlayPage->Fit(m_PlayPage);
|
sPlayPage->Fit(m_PlayPage);
|
||||||
m_Notebook->AddPage(m_PlayPage, _("Play"), true);
|
m_Notebook->AddPage(m_PlayPage, _("Play"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
m_RecordPage = new wxPanel(m_Notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
|
m_RecordPage = new wxPanel(m_Notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
|
||||||
wxBoxSizer* sRecordPage;
|
wxBoxSizer* sRecordPage;
|
||||||
sRecordPage = new wxBoxSizer(wxVERTICAL);
|
sRecordPage = new wxBoxSizer(wxVERTICAL);
|
||||||
@ -199,6 +209,36 @@ void FifoPlayerDlg::CreateGUIControls()
|
|||||||
m_RecordPage->Layout();
|
m_RecordPage->Layout();
|
||||||
sRecordPage->Fit(m_RecordPage);
|
sRecordPage->Fit(m_RecordPage);
|
||||||
m_Notebook->AddPage(m_RecordPage, _("Record"), false);
|
m_Notebook->AddPage(m_RecordPage, _("Record"), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Analyze page
|
||||||
|
{
|
||||||
|
m_AnalyzePage = new wxPanel(m_Notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
|
||||||
|
wxBoxSizer* sAnalyzePage;
|
||||||
|
sAnalyzePage = new wxBoxSizer(wxVERTICAL);
|
||||||
|
|
||||||
|
wxStaticBoxSizer* sTestSizer;
|
||||||
|
sTestSizer = new wxStaticBoxSizer(new wxStaticBox(m_AnalyzePage, wxID_ANY, _("Frame info")), wxHORIZONTAL);
|
||||||
|
|
||||||
|
m_framesList = new wxListBox(m_AnalyzePage, wxID_ANY);
|
||||||
|
m_framesList->SetMinSize(wxSize(100, 250));
|
||||||
|
sTestSizer->Add(m_framesList, 0, wxALL, 5);
|
||||||
|
|
||||||
|
m_objectsList = new wxListBox(m_AnalyzePage, wxID_ANY);
|
||||||
|
m_objectsList->SetMinSize(wxSize(110, 250));
|
||||||
|
sTestSizer->Add(m_objectsList, 0, wxALL, 5);
|
||||||
|
|
||||||
|
m_objectCmdList = new wxListBox(m_AnalyzePage, wxID_ANY);
|
||||||
|
m_objectCmdList->SetMinSize(wxSize(175, 250));
|
||||||
|
sTestSizer->Add(m_objectCmdList, 0, wxALL, 5);
|
||||||
|
|
||||||
|
sAnalyzePage->Add(sTestSizer, 0, wxEXPAND, 5);
|
||||||
|
|
||||||
|
m_AnalyzePage->SetSizer(sAnalyzePage);
|
||||||
|
m_AnalyzePage->Layout();
|
||||||
|
sAnalyzePage->Fit(m_AnalyzePage);
|
||||||
|
m_Notebook->AddPage(m_AnalyzePage, _("Analyze"), false);
|
||||||
|
}
|
||||||
|
|
||||||
sMain->Add(m_Notebook, 1, wxEXPAND | wxALL, 5);
|
sMain->Add(m_Notebook, 1, wxEXPAND | wxALL, 5);
|
||||||
|
|
||||||
@ -231,7 +271,11 @@ void FifoPlayerDlg::CreateGUIControls()
|
|||||||
m_RecordStop->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(FifoPlayerDlg::OnRecordStop), NULL, this);
|
m_RecordStop->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(FifoPlayerDlg::OnRecordStop), NULL, this);
|
||||||
m_Save->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(FifoPlayerDlg::OnSaveFile), NULL, this);
|
m_Save->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(FifoPlayerDlg::OnSaveFile), NULL, this);
|
||||||
m_FramesToRecordCtrl->Connect(wxEVT_COMMAND_SPINCTRL_UPDATED, wxSpinEventHandler(FifoPlayerDlg::OnNumFramesToRecord), NULL, this);
|
m_FramesToRecordCtrl->Connect(wxEVT_COMMAND_SPINCTRL_UPDATED, wxSpinEventHandler(FifoPlayerDlg::OnNumFramesToRecord), NULL, this);
|
||||||
m_Close->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(FifoPlayerDlg::OnCloseClick), NULL, this);
|
Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(FifoPlayerDlg::OnCloseClick), NULL, this);
|
||||||
|
|
||||||
|
m_framesList->Connect(wxEVT_COMMAND_LISTBOX_SELECTED, wxCommandEventHandler(FifoPlayerDlg::OnFrameListSelectionChanged), NULL, this);
|
||||||
|
m_objectsList->Connect(wxEVT_COMMAND_LISTBOX_SELECTED, wxCommandEventHandler(FifoPlayerDlg::OnObjectListSelectionChanged), NULL, this);
|
||||||
|
m_objectCmdList->Connect(wxEVT_COMMAND_LISTBOX_SELECTED, wxCommandEventHandler(FifoPlayerDlg::OnObjectCmdListSelectionChanged), NULL, this);
|
||||||
|
|
||||||
Connect(RECORDING_FINISHED_EVENT, wxCommandEventHandler(FifoPlayerDlg::OnRecordingFinished), NULL, this);
|
Connect(RECORDING_FINISHED_EVENT, wxCommandEventHandler(FifoPlayerDlg::OnRecordingFinished), NULL, this);
|
||||||
Connect(FRAME_WRITTEN_EVENT, wxCommandEventHandler(FifoPlayerDlg::OnFrameWritten), NULL, this);
|
Connect(FRAME_WRITTEN_EVENT, wxCommandEventHandler(FifoPlayerDlg::OnFrameWritten), NULL, this);
|
||||||
@ -243,6 +287,7 @@ void FifoPlayerDlg::OnPaint(wxPaintEvent& event)
|
|||||||
{
|
{
|
||||||
UpdatePlayGui();
|
UpdatePlayGui();
|
||||||
UpdateRecorderGui();
|
UpdateRecorderGui();
|
||||||
|
UpdateAnalyzerGui();
|
||||||
|
|
||||||
event.Skip();
|
event.Skip();
|
||||||
}
|
}
|
||||||
@ -250,6 +295,7 @@ void FifoPlayerDlg::OnPaint(wxPaintEvent& event)
|
|||||||
void FifoPlayerDlg::OnFrameFrom(wxSpinEvent& event)
|
void FifoPlayerDlg::OnFrameFrom(wxSpinEvent& event)
|
||||||
{
|
{
|
||||||
FifoPlayer &player = FifoPlayer::GetInstance();
|
FifoPlayer &player = FifoPlayer::GetInstance();
|
||||||
|
|
||||||
player.SetFrameRangeStart(event.GetPosition());
|
player.SetFrameRangeStart(event.GetPosition());
|
||||||
|
|
||||||
m_FrameFromCtrl->SetValue(player.GetFrameRangeStart());
|
m_FrameFromCtrl->SetValue(player.GetFrameRangeStart());
|
||||||
@ -326,6 +372,141 @@ void FifoPlayerDlg::OnNumFramesToRecord(wxSpinEvent& event)
|
|||||||
m_FramesToRecord = -1;
|
m_FramesToRecord = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FifoPlayerDlg::OnFrameListSelectionChanged(wxCommandEvent& event)
|
||||||
|
{
|
||||||
|
FifoPlayer& player = FifoPlayer::GetInstance();
|
||||||
|
|
||||||
|
m_objectsList->Clear();
|
||||||
|
if (event.GetInt() != -1)
|
||||||
|
{
|
||||||
|
int num_objects = player.GetAnalyzedFrameInfo(event.GetInt()).objectStarts.size();
|
||||||
|
for (int i = 0; i < num_objects; ++i)
|
||||||
|
m_objectsList->Append(wxString::Format(wxT("Object %i"), i));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call OnObjectListSelectionChanged
|
||||||
|
m_objectsList->SetSelection(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FifoPlayerDlg::OnObjectListSelectionChanged (wxCommandEvent& event)
|
||||||
|
{
|
||||||
|
FifoPlayer& player = FifoPlayer::GetInstance();
|
||||||
|
|
||||||
|
int frame_idx = m_framesList->GetSelection();
|
||||||
|
int object_idx = event.GetInt();
|
||||||
|
|
||||||
|
m_objectCmdList->Clear();
|
||||||
|
if (frame_idx != -1 && object_idx != -1)
|
||||||
|
{
|
||||||
|
const AnalyzedFrameInfo& frame = player.GetAnalyzedFrameInfo(frame_idx);
|
||||||
|
const FifoFrameInfo& fifo_frame = player.GetFile()->GetFrame(frame_idx);
|
||||||
|
const u8* objectdata_start = &fifo_frame.fifoData[frame.objectStarts[object_idx]];
|
||||||
|
const u8* objectdata_end = &fifo_frame.fifoData[frame.objectEnds[object_idx]];
|
||||||
|
u8* objectdata = (u8*)objectdata_start;
|
||||||
|
const int obj_offset = objectdata_start - &fifo_frame.fifoData[frame.objectStarts[0]];
|
||||||
|
|
||||||
|
int cmd = *objectdata++;
|
||||||
|
int stream_size = Common::swap16(objectdata);
|
||||||
|
objectdata += 2;
|
||||||
|
int vertex_size = (objectdata_end - objectdata) / stream_size;
|
||||||
|
wxString newLabel = wxString::Format(wxT("%08X: %02X %04X "), obj_offset, cmd, stream_size);
|
||||||
|
if ((objectdata_end - objectdata) % stream_size) newLabel += _("NOTE: Stream size doesn't match actual data length\n");
|
||||||
|
while (objectdata < objectdata_end)
|
||||||
|
{
|
||||||
|
// Group bytes by vertex
|
||||||
|
newLabel += wxString::Format(wxT("%02X"), *objectdata++);
|
||||||
|
if (((objectdata - (objectdata_start+3)) % vertex_size) == 0) newLabel += wxT(" ");
|
||||||
|
}
|
||||||
|
m_objectCmdList->Append(newLabel);
|
||||||
|
|
||||||
|
|
||||||
|
// Between objectdata_end and next_objdata_start, there are register setting commands
|
||||||
|
if (object_idx + 1 < frame.objectStarts.size())
|
||||||
|
{
|
||||||
|
const u8* next_objdata_start = &fifo_frame.fifoData[frame.objectStarts[object_idx+1]];
|
||||||
|
while (objectdata < next_objdata_start)
|
||||||
|
{
|
||||||
|
int cmd = *objectdata++;
|
||||||
|
switch (cmd)
|
||||||
|
{
|
||||||
|
case GX_NOP:
|
||||||
|
newLabel = _("NOP");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x44:
|
||||||
|
newLabel = _("0x44");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GX_CMD_INVL_VC:
|
||||||
|
newLabel = _("GX_CMD_INVL_VC");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GX_LOAD_CP_REG:
|
||||||
|
{
|
||||||
|
u32 cmd2 = *objectdata++;
|
||||||
|
u32 value = Common::swap32(objectdata);
|
||||||
|
objectdata += 4;
|
||||||
|
|
||||||
|
newLabel = wxString::Format(wxT("CP %02X %08X"), cmd2, value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GX_LOAD_XF_REG:
|
||||||
|
{
|
||||||
|
u32 cmd2 = Common::swap32(objectdata);
|
||||||
|
objectdata += 4;
|
||||||
|
u8 streamSize = ((cmd2 >> 16) & 15) + 1;
|
||||||
|
|
||||||
|
newLabel = wxString::Format(wxT("XF %08X(%02X) ..."), cmd2, streamSize);
|
||||||
|
|
||||||
|
objectdata += streamSize * 4;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GX_LOAD_INDX_A:
|
||||||
|
case GX_LOAD_INDX_B:
|
||||||
|
case GX_LOAD_INDX_C:
|
||||||
|
case GX_LOAD_INDX_D:
|
||||||
|
objectdata += 4;
|
||||||
|
newLabel = wxString::Format(wxT("LOAD INDX %s"), (cmd == GX_LOAD_INDX_A) ? "A" :
|
||||||
|
(cmd == GX_LOAD_INDX_B) ? "B" :
|
||||||
|
(cmd == GX_LOAD_INDX_C) ? "C" : "D");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GX_CMD_CALL_DL:
|
||||||
|
// The recorder should have expanded display lists into the fifo stream and skipped the call to start them
|
||||||
|
// That is done to make it easier to track where memory is updated
|
||||||
|
_assert_(false);
|
||||||
|
objectdata += 8;
|
||||||
|
newLabel = wxString::Format(wxT("CALL DL"));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GX_LOAD_BP_REG:
|
||||||
|
{
|
||||||
|
u32 cmd2 = Common::swap32(objectdata);
|
||||||
|
objectdata += 4;
|
||||||
|
newLabel = wxString::Format(wxT("BP %02X %06X"), cmd2 >> 24, cmd2 & 0xFFFFFF);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
newLabel = _("Unexpected 0x80 call? Aborting...");
|
||||||
|
objectdata = (u8*)next_objdata_start;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
m_objectCmdList->Append(newLabel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Call OnObjectCmdListSelectionChanged
|
||||||
|
m_objectCmdList->SetSelection(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FifoPlayerDlg::OnObjectCmdListSelectionChanged (wxCommandEvent& event)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void FifoPlayerDlg::OnCloseClick(wxCommandEvent& WXUNUSED(event))
|
void FifoPlayerDlg::OnCloseClick(wxCommandEvent& WXUNUSED(event))
|
||||||
{
|
{
|
||||||
Hide();
|
Hide();
|
||||||
@ -375,6 +556,23 @@ void FifoPlayerDlg::UpdateRecorderGui()
|
|||||||
m_Save->Enable(GetSaveButtonEnabled());
|
m_Save->Enable(GetSaveButtonEnabled());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FifoPlayerDlg::UpdateAnalyzerGui()
|
||||||
|
{
|
||||||
|
FifoPlayer &player = FifoPlayer::GetInstance();
|
||||||
|
FifoDataFile* file = player.GetFile();
|
||||||
|
|
||||||
|
int num_frames = (file) ? player.GetFile()->GetFrameCount() : 0;
|
||||||
|
if (m_framesList->GetCount() != num_frames)
|
||||||
|
{
|
||||||
|
m_framesList->Clear();
|
||||||
|
for (int i = 0; i < num_frames; ++i)
|
||||||
|
{
|
||||||
|
m_framesList->Append(wxString::Format(wxT("Frame %i"), i));
|
||||||
|
}
|
||||||
|
m_framesList->SetSelection(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
wxString FifoPlayerDlg::CreateFileFrameCountLabel() const
|
wxString FifoPlayerDlg::CreateFileFrameCountLabel() const
|
||||||
{
|
{
|
||||||
FifoDataFile *file = FifoPlayer::GetInstance().GetFile();
|
FifoDataFile *file = FifoPlayer::GetInstance().GetFile();
|
||||||
|
@ -47,8 +47,13 @@ private:
|
|||||||
void OnRecordingFinished(wxCommandEvent& event);
|
void OnRecordingFinished(wxCommandEvent& event);
|
||||||
void OnFrameWritten(wxCommandEvent& event);
|
void OnFrameWritten(wxCommandEvent& event);
|
||||||
|
|
||||||
|
void OnFrameListSelectionChanged(wxCommandEvent& event);
|
||||||
|
void OnObjectListSelectionChanged(wxCommandEvent& event);
|
||||||
|
void OnObjectCmdListSelectionChanged(wxCommandEvent& event);
|
||||||
|
|
||||||
void UpdatePlayGui();
|
void UpdatePlayGui();
|
||||||
void UpdateRecorderGui();
|
void UpdateRecorderGui();
|
||||||
|
void UpdateAnalyzerGui();
|
||||||
|
|
||||||
wxString CreateFileFrameCountLabel() const;
|
wxString CreateFileFrameCountLabel() const;
|
||||||
wxString CreateCurrentFrameLabel() const;
|
wxString CreateCurrentFrameLabel() const;
|
||||||
@ -89,6 +94,12 @@ private:
|
|||||||
wxButton* m_Save;
|
wxButton* m_Save;
|
||||||
wxStaticText* m_FramesToRecordLabel;
|
wxStaticText* m_FramesToRecordLabel;
|
||||||
wxSpinCtrl* m_FramesToRecordCtrl;
|
wxSpinCtrl* m_FramesToRecordCtrl;
|
||||||
|
|
||||||
|
wxPanel* m_AnalyzePage;
|
||||||
|
wxListBox* m_framesList;
|
||||||
|
wxListBox* m_objectsList;
|
||||||
|
wxListBox* m_objectCmdList;
|
||||||
|
|
||||||
wxButton* m_Close;
|
wxButton* m_Close;
|
||||||
|
|
||||||
s32 m_FramesToRecord;
|
s32 m_FramesToRecord;
|
||||||
|
Loading…
Reference in New Issue
Block a user