Qt: Add dump VRAM and SPU RAM actions

This commit is contained in:
Connor McLaughlin 2021-01-13 19:24:41 +10:00
parent 5746dcdbd4
commit 2b5cfb272c
9 changed files with 131 additions and 12 deletions

View file

@ -3,6 +3,7 @@
#include "common/heap_array.h" #include "common/heap_array.h"
#include "common/log.h" #include "common/log.h"
#include "common/state_wrapper.h" #include "common/state_wrapper.h"
#include "common/string_util.h"
#include "dma.h" #include "dma.h"
#include "host_display.h" #include "host_display.h"
#include "host_interface.h" #include "host_interface.h"
@ -1453,6 +1454,26 @@ void GPU::SetTextureWindow(u32 value)
m_draw_mode.texture_window_changed = true; m_draw_mode.texture_window_changed = true;
} }
bool GPU::DumpVRAMToFile(const char* filename)
{
ReadVRAM(0, 0, VRAM_WIDTH, VRAM_HEIGHT);
const char* extension = std::strrchr(filename, '.');
if (extension && StringUtil::Strcasecmp(extension, ".png") == 0)
{
return DumpVRAMToFile(filename, VRAM_WIDTH, VRAM_HEIGHT, sizeof(u16) * VRAM_WIDTH, m_vram_ptr, true);
}
else if (extension && StringUtil::Strcasecmp(extension, ".bin") == 0)
{
return FileSystem::WriteBinaryFile(filename, m_vram_ptr, VRAM_WIDTH * VRAM_HEIGHT * sizeof(u16));
}
else
{
Log_ErrorPrintf("Unknown extension: '%s'", filename);
return false;
}
}
bool GPU::DumpVRAMToFile(const char* filename, u32 width, u32 height, u32 stride, const void* buffer, bool remove_alpha) bool GPU::DumpVRAMToFile(const char* filename, u32 width, u32 height, u32 stride, const void* buffer, bool remove_alpha)
{ {
auto fp = FileSystem::OpenManagedCFile(filename, "wb"); auto fp = FileSystem::OpenManagedCFile(filename, "wb");

View file

@ -160,6 +160,9 @@ public:
// Returns the video clock frequency. // Returns the video clock frequency.
TickCount GetCRTCFrequency() const; TickCount GetCRTCFrequency() const;
// Dumps raw VRAM to a file.
bool DumpVRAMToFile(const char* filename);
protected: protected:
TickCount CRTCTicksToSystemTicks(TickCount crtc_ticks, TickCount fractional_ticks) const; TickCount CRTCTicksToSystemTicks(TickCount crtc_ticks, TickCount fractional_ticks) const;
TickCount SystemTicksToCRTCTicks(TickCount sysclk_ticks, TickCount* fractional_ticks) const; TickCount SystemTicksToCRTCTicks(TickCount sysclk_ticks, TickCount* fractional_ticks) const;

View file

@ -17,6 +17,12 @@ class TimingEvent;
class SPU class SPU
{ {
public: public:
enum : u32
{
RAM_SIZE = 512 * 1024,
RAM_MASK = RAM_SIZE - 1,
};
SPU(); SPU();
~SPU(); ~SPU();
@ -47,9 +53,11 @@ public:
/// Stops dumping audio to file, if started. /// Stops dumping audio to file, if started.
bool StopDumpingAudio(); bool StopDumpingAudio();
/// Access to SPU RAM.
const std::array<u8, RAM_SIZE>& GetRAM() const { return m_ram; }
std::array<u8, RAM_SIZE>& GetRAM() { return m_ram; }
private: private:
static constexpr u32 RAM_SIZE = 512 * 1024;
static constexpr u32 RAM_MASK = RAM_SIZE - 1;
static constexpr u32 SPU_BASE = 0x1F801C00; static constexpr u32 SPU_BASE = 0x1F801C00;
static constexpr u32 NUM_VOICES = 24; static constexpr u32 NUM_VOICES = 24;
static constexpr u32 NUM_VOICE_REGISTERS = 8; static constexpr u32 NUM_VOICE_REGISTERS = 8;

View file

@ -1635,11 +1635,30 @@ void UpdateMemoryCards()
bool DumpRAM(const char* filename) bool DumpRAM(const char* filename)
{ {
auto fp = FileSystem::OpenManagedCFile(filename, "wb"); if (!IsValid())
if (!fp)
return false; return false;
return std::fwrite(Bus::g_ram, Bus::RAM_SIZE, 1, fp.get()) == 1; return FileSystem::WriteBinaryFile(filename, Bus::g_ram, Bus::RAM_SIZE);
}
bool DumpVRAM(const char* filename)
{
if (!IsValid())
return false;
g_gpu->RestoreGraphicsAPIState();
const bool result = g_gpu->DumpVRAMToFile(filename);
g_gpu->ResetGraphicsAPIState();
return result;
}
bool DumpSPURAM(const char* filename)
{
if (!IsValid())
return false;
return FileSystem::WriteBinaryFile(filename, g_spu.GetRAM().data(), SPU::RAM_SIZE);
} }
bool HasMedia() bool HasMedia()

View file

@ -175,6 +175,12 @@ void UpdateMemoryCards();
/// Dumps RAM to a file. /// Dumps RAM to a file.
bool DumpRAM(const char* filename); bool DumpRAM(const char* filename);
/// Dumps video RAM to a file.
bool DumpVRAM(const char* filename);
/// Dumps sound RAM to a file.
bool DumpSPURAM(const char* filename);
bool HasMedia(); bool HasMedia();
bool InsertMedia(const char* path); bool InsertMedia(const char* path);
void RemoveMedia(); void RemoveMedia();

View file

@ -821,6 +821,9 @@ void MainWindow::updateEmulationActions(bool starting, bool running)
m_ui.menuCheats->setDisabled(starting || !running); m_ui.menuCheats->setDisabled(starting || !running);
m_ui.actionCheatManager->setDisabled(starting || !running); m_ui.actionCheatManager->setDisabled(starting || !running);
m_ui.actionCPUDebugger->setDisabled(starting || !running); m_ui.actionCPUDebugger->setDisabled(starting || !running);
m_ui.actionDumpRAM->setDisabled(starting || !running);
m_ui.actionDumpVRAM->setDisabled(starting || !running);
m_ui.actionDumpSPURAM->setDisabled(starting || !running);
m_ui.actionSaveState->setDisabled(starting || !running); m_ui.actionSaveState->setDisabled(starting || !running);
m_ui.menuSaveState->setDisabled(starting || !running); m_ui.menuSaveState->setDisabled(starting || !running);
@ -1041,12 +1044,29 @@ void MainWindow::connectSignals()
m_host_interface->stopDumpingAudio(); m_host_interface->stopDumpingAudio();
}); });
connect(m_ui.actionDumpRAM, &QAction::triggered, [this]() { connect(m_ui.actionDumpRAM, &QAction::triggered, [this]() {
const QString filename = QFileDialog::getSaveFileName(this, tr("Destination File")); const QString filename =
QFileDialog::getSaveFileName(this, tr("Destination File"), QString(), tr("Binary Files (*.bin)"));
if (filename.isEmpty()) if (filename.isEmpty())
return; return;
m_host_interface->dumpRAM(filename); m_host_interface->dumpRAM(filename);
}); });
connect(m_ui.actionDumpVRAM, &QAction::triggered, [this]() {
const QString filename = QFileDialog::getSaveFileName(this, tr("Destination File"), QString(),
tr("Binary Files (*.bin);;PNG Images (*.png)"));
if (filename.isEmpty())
return;
m_host_interface->dumpVRAM(filename);
});
connect(m_ui.actionDumpSPURAM, &QAction::triggered, [this]() {
const QString filename =
QFileDialog::getSaveFileName(this, tr("Destination File"), QString(), tr("Binary Files (*.bin)"));
if (filename.isEmpty())
return;
m_host_interface->dumpSPURAM(filename);
});
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.actionDebugShowVRAM, "Debug", "ShowVRAM"); SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.actionDebugShowVRAM, "Debug", "ShowVRAM");
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.actionDebugShowGPUState, "Debug", "ShowGPUState"); SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.actionDebugShowGPUState, "Debug", "ShowGPUState");
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.actionDebugShowCDROMState, "Debug", SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.actionDebugShowCDROMState, "Debug",

View file

@ -174,13 +174,16 @@
<addaction name="actionDisableInterlacing"/> <addaction name="actionDisableInterlacing"/>
<addaction name="actionForceNTSCTimings"/> <addaction name="actionForceNTSCTimings"/>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="actionCPUDebugger"/>
<addaction name="separator"/>
<addaction name="actionDumpRAM"/>
<addaction name="actionDumpVRAM"/>
<addaction name="actionDumpSPURAM"/>
<addaction name="separator"/>
<addaction name="actionDebugDumpCPUtoVRAMCopies"/> <addaction name="actionDebugDumpCPUtoVRAMCopies"/>
<addaction name="actionDebugDumpVRAMtoCPUCopies"/> <addaction name="actionDebugDumpVRAMtoCPUCopies"/>
<addaction name="actionDumpAudio"/> <addaction name="actionDumpAudio"/>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="actionCPUDebugger"/>
<addaction name="actionDumpRAM"/>
<addaction name="separator"/>
<addaction name="actionDebugShowVRAM"/> <addaction name="actionDebugShowVRAM"/>
<addaction name="actionDebugShowGPUState"/> <addaction name="actionDebugShowGPUState"/>
<addaction name="actionDebugShowCDROMState"/> <addaction name="actionDebugShowCDROMState"/>
@ -611,6 +614,16 @@
<string>Dump RAM...</string> <string>Dump RAM...</string>
</property> </property>
</action> </action>
<action name="actionDumpVRAM">
<property name="text">
<string>Dump VRAM...</string>
</property>
</action>
<action name="actionDumpSPURAM">
<property name="text">
<string>Dump SPU RAM...</string>
</property>
</action>
<action name="actionDebugShowGPUState"> <action name="actionDebugShowGPUState">
<property name="checkable"> <property name="checkable">
<bool>true</bool> <bool>true</bool>

View file

@ -1292,9 +1292,6 @@ void QtHostInterface::dumpRAM(const QString& filename)
return; return;
} }
if (System::IsShutdown())
return;
const std::string filename_str = filename.toStdString(); const std::string filename_str = filename.toStdString();
if (System::DumpRAM(filename_str.c_str())) if (System::DumpRAM(filename_str.c_str()))
ReportFormattedMessage("RAM dumped to '%s'", filename_str.c_str()); ReportFormattedMessage("RAM dumped to '%s'", filename_str.c_str());
@ -1302,6 +1299,36 @@ void QtHostInterface::dumpRAM(const QString& filename)
ReportFormattedMessage("Failed to dump RAM to '%s'", filename_str.c_str()); ReportFormattedMessage("Failed to dump RAM to '%s'", filename_str.c_str());
} }
void QtHostInterface::dumpVRAM(const QString& filename)
{
if (!isOnWorkerThread())
{
QMetaObject::invokeMethod(this, "dumpVRAM", Qt::QueuedConnection, Q_ARG(const QString&, filename));
return;
}
const std::string filename_str = filename.toStdString();
if (System::DumpVRAM(filename_str.c_str()))
ReportFormattedMessage("VRAM dumped to '%s'", filename_str.c_str());
else
ReportFormattedMessage("Failed to dump VRAM to '%s'", filename_str.c_str());
}
void QtHostInterface::dumpSPURAM(const QString& filename)
{
if (!isOnWorkerThread())
{
QMetaObject::invokeMethod(this, "dumpSPURAM", Qt::QueuedConnection, Q_ARG(const QString&, filename));
return;
}
const std::string filename_str = filename.toStdString();
if (System::DumpSPURAM(filename_str.c_str()))
ReportFormattedMessage("SPU RAM dumped to '%s'", filename_str.c_str());
else
ReportFormattedMessage("Failed to dump SPU RAM to '%s'", filename_str.c_str());
}
void QtHostInterface::saveScreenshot() void QtHostInterface::saveScreenshot()
{ {
if (!isOnWorkerThread()) if (!isOnWorkerThread())

View file

@ -169,6 +169,8 @@ public Q_SLOTS:
void stopDumpingAudio(); void stopDumpingAudio();
void singleStepCPU(); void singleStepCPU();
void dumpRAM(const QString& filename); void dumpRAM(const QString& filename);
void dumpVRAM(const QString& filename);
void dumpSPURAM(const QString& filename);
void saveScreenshot(); void saveScreenshot();
void redrawDisplayWindow(); void redrawDisplayWindow();
void toggleFullscreen(); void toggleFullscreen();