mirror of
https://github.com/PCSX2/pcsx2.git
synced 2025-12-16 04:08:48 +00:00
GS: Add dumping of transfer bitmaps.
This commit is contained in:
parent
a8c549baee
commit
f83e11892b
@ -473,8 +473,8 @@ static void PrintCommandLineHelp(const char* progname)
|
||||
std::fprintf(stderr, " -help: Displays this information and exits.\n");
|
||||
std::fprintf(stderr, " -version: Displays version information and exits.\n");
|
||||
std::fprintf(stderr, " -dumpdir <dir>: Frame dump directory (will be dumped as filename_frameN.png).\n");
|
||||
std::fprintf(stderr, " -dump [rt|tex|z|f|a|i]: Enabling dumping of render target, texture, z buffer, frame, "
|
||||
"alphas, and info (context, vertices), respectively, per draw. Generates lots of data.\n");
|
||||
std::fprintf(stderr, " -dump [rt|tex|z|f|a|i|tr]: Enabling dumping of render target, texture, z buffer, frame, "
|
||||
"alphas, and info (context, vertices, transfers (list)), transfers (images), respectively, per draw. Generates lots of data.\n");
|
||||
std::fprintf(stderr, " -dumprange N[,L,B]: Start dumping from draw N (base 0), stops after L draws, and only "
|
||||
"those draws that are multiples of B (intersection of -dumprange and -dumprangef used)."
|
||||
"Defaults to 0,-1,1 (all draws). Only used if -dump used.\n");
|
||||
@ -558,6 +558,8 @@ bool GSRunner::ParseCommandLineArgs(int argc, char* argv[], VMBootParameters& pa
|
||||
s_settings_interface.SetBoolValue("EmuCore/GS", "SaveAlpha", true);
|
||||
if (str.find("i") != std::string::npos)
|
||||
s_settings_interface.SetBoolValue("EmuCore/GS", "SaveInfo", true);
|
||||
if (str.find("tr") != std::string::npos)
|
||||
s_settings_interface.SetBoolValue("EmuCore/GS", "SaveTransferImages", true);
|
||||
continue;
|
||||
}
|
||||
else if (CHECK_ARG_PARAM("-dumprange"))
|
||||
|
||||
@ -71,6 +71,13 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QCheckBox" name="saveTransferImages">
|
||||
<property name="text">
|
||||
<string>Save Transfer Image Data</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
|
||||
@ -109,6 +109,7 @@ DebugSettingsWidget::DebugSettingsWidget(SettingsWindow* settings_dialog, QWidge
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_gs.saveDepth, "EmuCore/GS", "SaveDepth", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_gs.saveAlpha, "EmuCore/GS", "SaveAlpha", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_gs.saveInfo, "EmuCore/GS", "SaveInfo", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_gs.saveTransferImages, "EmuCore/GS", "SaveTransferImages", false);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_gs.saveDrawStart, "EmuCore/GS", "SaveDrawStart", 0);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_gs.saveDrawCount, "EmuCore/GS", "SaveDrawCount", 5000);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_gs.saveFrameStart, "EmuCore/GS", "SaveFrameStart", 0);
|
||||
@ -213,6 +214,7 @@ void DebugSettingsWidget::onDrawDumpingChanged()
|
||||
m_gs.saveDepth->setEnabled(enabled);
|
||||
m_gs.saveAlpha->setEnabled(enabled);
|
||||
m_gs.saveInfo->setEnabled(enabled);
|
||||
m_gs.saveTransferImages->setEnabled(enabled);
|
||||
m_gs.saveDrawStart->setEnabled(enabled);
|
||||
m_gs.saveDrawCount->setEnabled(enabled);
|
||||
m_gs.saveFrameStart->setEnabled(enabled);
|
||||
|
||||
@ -774,6 +774,7 @@ struct Pcsx2Config
|
||||
SaveDepth : 1,
|
||||
SaveAlpha : 1,
|
||||
SaveInfo : 1,
|
||||
SaveTransferImages : 1,
|
||||
DumpReplaceableTextures : 1,
|
||||
DumpReplaceableMipmaps : 1,
|
||||
DumpTexturesWithFMVActive : 1,
|
||||
|
||||
@ -651,7 +651,7 @@ void GSLocalMemory::ReadTexture(const GSOffset& off, const GSVector4i& r, u8* ds
|
||||
|
||||
//
|
||||
|
||||
void GSLocalMemory::SaveBMP(const std::string& fn, u32 bp, u32 bw, u32 psm, int w, int h)
|
||||
void GSLocalMemory::SaveBMP(const std::string& fn, u32 bp, u32 bw, u32 psm, int w, int h, int x, int y)
|
||||
{
|
||||
int pitch = w * 4;
|
||||
int size = pitch * h;
|
||||
@ -671,7 +671,7 @@ void GSLocalMemory::SaveBMP(const std::string& fn, u32 bp, u32 bw, u32 psm, int
|
||||
{
|
||||
for (int i = 0; i < w; i++)
|
||||
{
|
||||
((u32*)p)[i] = (this->*rp)(i, j, TEX0.TBP0, TEX0.TBW);
|
||||
((u32*)p)[i] = (this->*rp)(x + i, y + j, TEX0.TBP0, TEX0.TBW);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1121,7 +1121,7 @@ public:
|
||||
|
||||
//
|
||||
|
||||
void SaveBMP(const std::string& fn, u32 bp, u32 bw, u32 psm, int w, int h);
|
||||
void SaveBMP(const std::string& fn, u32 bp, u32 bw, u32 psm, int w, int h, int x = 0, int y = 0);
|
||||
};
|
||||
|
||||
constexpr inline GSOffset GSOffset::fromKnownPSM(u32 bp, u32 bw, GS_PSM psm)
|
||||
|
||||
@ -15,6 +15,7 @@
|
||||
#include <algorithm>
|
||||
#include <cfloat>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <bit>
|
||||
|
||||
@ -457,7 +458,7 @@ void GSState::DumpDrawInfo(bool dump_regs, bool dump_verts, bool dump_transfers)
|
||||
if (dump_transfers)
|
||||
{
|
||||
s = GetDrawDumpPath("%05d_transfers.txt", s_n);
|
||||
DumpTransfers(s);
|
||||
DumpTransferList(s);
|
||||
}
|
||||
}
|
||||
|
||||
@ -729,7 +730,7 @@ void GSState::DumpVertices(const std::string& filename)
|
||||
file << CLOSE_MAP << std::endl;
|
||||
}
|
||||
|
||||
void GSState::DumpTransfers(const std::string& filename)
|
||||
void GSState::DumpTransferList(const std::string& filename)
|
||||
{
|
||||
// Only create the file if there are transfers to dump
|
||||
std::optional<std::ofstream> file;
|
||||
@ -792,9 +793,6 @@ void GSState::DumpTransfers(const std::string& filename)
|
||||
(*file) << INDENT << "rect: [" << std::dec << transfer.rect.x << DEL << transfer.rect.y << DEL <<
|
||||
transfer.rect.z << DEL << transfer.rect.w << "]" << std::endl;
|
||||
|
||||
// Dump draw number
|
||||
(*file) << INDENT << "draw: " << std::dec << transfer.draw << std::endl;
|
||||
|
||||
// Dump zero_clear
|
||||
(*file) << INDENT << "zero_clear: " << (transfer.zero_clear ? "true" : "false") << std::endl;
|
||||
|
||||
@ -802,6 +800,41 @@ void GSState::DumpTransfers(const std::string& filename)
|
||||
}
|
||||
}
|
||||
|
||||
void GSState::DumpTransferImages()
|
||||
{
|
||||
// Only create the file if there are transfers to dump
|
||||
std::optional<std::ofstream> file;
|
||||
|
||||
int transfer_n = 0;
|
||||
for (int i = 0; i < static_cast<int>(m_draw_transfers.size()); ++i)
|
||||
{
|
||||
if (m_draw_transfers[i].draw != s_n - 1)
|
||||
continue; // skip transfers that did not start in the previous draw
|
||||
|
||||
const GSUploadQueue& transfer = m_draw_transfers[i];
|
||||
|
||||
std::string filename;
|
||||
if (transfer.ee_to_gs)
|
||||
{
|
||||
// Transferring EE->GS then only the destination info is relevant.
|
||||
filename = GetDrawDumpPath("%05d_transfer%02d_EE_to_GS_%03x_%d_%s_%d_%d_%d_%d.png",
|
||||
s_n, transfer_n++, transfer.blit.DBP, transfer.blit.DBW, GSUtil::GetPSMName(transfer.blit.DPSM),
|
||||
transfer.rect.x, transfer.rect.y, transfer.rect.z, transfer.rect.w);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Transferring GS->GS then the source info is relevant.
|
||||
filename = GetDrawDumpPath("%05d_transfer%02d_GS_to_GS_%03x_%d_%s_%03x_%d_%s_%d_%d_%d_%d.bmp",
|
||||
s_n, transfer_n++, transfer.blit.SBP, transfer.blit.SBW, GSUtil::GetPSMName(transfer.blit.SPSM),
|
||||
transfer.blit.DBP, transfer.blit.DBW, GSUtil::GetPSMName(transfer.blit.DPSM),
|
||||
transfer.rect.x, transfer.rect.y, transfer.rect.z, transfer.rect.w);
|
||||
}
|
||||
|
||||
m_mem.SaveBMP(filename, transfer.blit.DBP, transfer.blit.DBW, transfer.blit.DPSM,
|
||||
transfer.rect.width(), transfer.rect.height(), transfer.rect.x, transfer.rect.y);
|
||||
}
|
||||
}
|
||||
|
||||
__inline void GSState::CheckFlushes()
|
||||
{
|
||||
if (m_dirty_gs_regs && m_index.tail > 0)
|
||||
@ -2029,12 +2062,18 @@ void GSState::FlushPrim()
|
||||
const bool skip_draw = (m_context->TEST.ZTE && m_context->TEST.ZTST == ZTST_NEVER);
|
||||
m_quad_check_valid = false;
|
||||
|
||||
if (GSConfig.SaveInfo && GSConfig.ShouldDump(s_n, g_perfmon.GetFrame()))
|
||||
if (GSConfig.ShouldDump(s_n, g_perfmon.GetFrame()))
|
||||
{
|
||||
// Only dump registers/vertices if we are drawing.
|
||||
// Always dump the transfers since these are relevant for debugging regardless of
|
||||
// whether the draw is skipped or not.
|
||||
DumpDrawInfo(!skip_draw, !skip_draw, true);
|
||||
if (GSConfig.SaveInfo)
|
||||
{
|
||||
// Only dump registers/vertices if we are drawing.
|
||||
// Always dump the transfers since these are relevant for debugging regardless of
|
||||
// whether the draw is skipped or not.
|
||||
DumpDrawInfo(!skip_draw, !skip_draw, true);
|
||||
}
|
||||
|
||||
if (GSConfig.SaveTransferImages)
|
||||
DumpTransferImages();
|
||||
}
|
||||
|
||||
if (!skip_draw)
|
||||
|
||||
@ -444,7 +444,8 @@ public:
|
||||
|
||||
void DumpDrawInfo(bool dump_regs, bool dump_verts, bool dump_transfers);
|
||||
void DumpVertices(const std::string& filename);
|
||||
void DumpTransfers(const std::string& filename);
|
||||
void DumpTransferList(const std::string& filename);
|
||||
void DumpTransferImages();
|
||||
|
||||
bool TrianglesAreQuads(bool shuffle_check = false);
|
||||
PRIM_OVERLAP PrimitiveOverlap();
|
||||
|
||||
@ -987,6 +987,7 @@ void Pcsx2Config::GSOptions::LoadSave(SettingsWrapper& wrap)
|
||||
SettingsWrapBitBoolEx(SaveDepth, "SaveDepth");
|
||||
SettingsWrapBitBoolEx(SaveAlpha, "SaveAlpha");
|
||||
SettingsWrapBitBoolEx(SaveInfo, "SaveInfo");
|
||||
SettingsWrapBitBoolEx(SaveTransferImages, "SaveTransferImages");
|
||||
SettingsWrapBitBool(DumpReplaceableTextures);
|
||||
SettingsWrapBitBool(DumpReplaceableMipmaps);
|
||||
SettingsWrapBitBool(DumpTexturesWithFMVActive);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user