mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-27 08:05:41 +00:00
Qt: Add dump VRAM and SPU RAM actions
This commit is contained in:
parent
5746dcdbd4
commit
2b5cfb272c
|
@ -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");
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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())
|
||||||
|
|
|
@ -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();
|
||||||
|
|
Loading…
Reference in a new issue