Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tools: Add additional options for dumping in GS runner. #12229

Merged
merged 3 commits into from
Feb 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 117 additions & 2 deletions pcsx2-gsrunner/Main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ void Host::BeginPresentFrame()
GSJoinSnapshotThreads();

// queue dumping of this frame
std::string dump_path(fmt::format("{}_frame{}.png", s_output_prefix, s_dump_frame_number));
std::string dump_path(fmt::format("{}_frame{:05}.png", s_output_prefix, s_dump_frame_number));
GSQueueSnapshot(dump_path);
}

Expand Down Expand Up @@ -443,8 +443,17 @@ 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, " -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");
std::fprintf(stderr, " -dumprangef NF[,LF,BF]: Start dumping from frame NF (base 0), stops after LF frames, "
"and only those frames that are multiples of BF (intersection of -dumprange and -dumprangef used).\n"
"Defaults to 0,-1,1 (all frames). Only used if -dump is used.\n");
std::fprintf(stderr, " -loop <count>: Loops dump playback N times. Defaults to 1. 0 will loop infinitely.\n");
std::fprintf(stderr, " -renderer <renderer>: Sets the graphics renderer. Defaults to Auto.\n");
std::fprintf(stderr, " -swthreads <threads>: Sets the number of threads for the software renderer.\n");
std::fprintf(stderr, " -window: Forces a window to be displayed.\n");
std::fprintf(stderr, " -surfaceless: Disables showing a window.\n");
std::fprintf(stderr, " -logfile <filename>: Writes emu log to filename.\n");
Expand All @@ -465,6 +474,7 @@ void GSRunner::InitializeConsole()

bool GSRunner::ParseCommandLineArgs(int argc, char* argv[], VMBootParameters& params)
{
std::string dumpdir; // Save from argument -dumpdir for creating sub-directories
bool no_more_args = false;
for (int i = 1; i < argc; i++)
{
Expand All @@ -485,7 +495,7 @@ bool GSRunner::ParseCommandLineArgs(int argc, char* argv[], VMBootParameters& pa
}
else if (CHECK_ARG_PARAM("-dumpdir"))
{
s_output_prefix = StringUtil::StripWhitespace(argv[++i]);
dumpdir = s_output_prefix = StringUtil::StripWhitespace(argv[++i]);
if (s_output_prefix.empty())
{
Console.Error("Invalid dump directory specified.");
Expand All @@ -500,6 +510,86 @@ bool GSRunner::ParseCommandLineArgs(int argc, char* argv[], VMBootParameters& pa

continue;
}
else if (CHECK_ARG_PARAM("-dump"))
{
std::string str(argv[++i]);

s_settings_interface.SetBoolValue("EmuCore/GS", "dump", true);

if (str.find("rt") != std::string::npos)
s_settings_interface.SetBoolValue("EmuCore/GS", "save", true);
if (str.find("f") != std::string::npos)
s_settings_interface.SetBoolValue("EmuCore/GS", "savef", true);
if (str.find("tex") != std::string::npos)
s_settings_interface.SetBoolValue("EmuCore/GS", "savet", true);
if (str.find("z") != std::string::npos)
s_settings_interface.SetBoolValue("EmuCore/GS", "savez", true);
if (str.find("a") != std::string::npos)
s_settings_interface.SetBoolValue("EmuCore/GS", "savea", true);
if (str.find("i") != std::string::npos)
s_settings_interface.SetBoolValue("EmuCore/GS", "savei", true);
continue;
}
else if (CHECK_ARG_PARAM("-dumprange"))
{
std::string str(argv[++i]);

std::vector<std::string_view> split = StringUtil::SplitString(str, ',');
int start = 0;
int num = -1;
int by = 1;
if (split.size() > 0)
{
start = StringUtil::FromChars<int>(split[0]).value_or(0);
}
if (split.size() > 1)
{
num = StringUtil::FromChars<int>(split[1]).value_or(-1);
}
if (split.size() > 2)
{
by = std::max(1, StringUtil::FromChars<int>(split[2]).value_or(1));
}
s_settings_interface.SetIntValue("EmuCore/GS", "saven", start);
s_settings_interface.SetIntValue("EmuCore/GS", "savel", num);
s_settings_interface.SetIntValue("EmuCore/GS", "saveb", by);
continue;
}
else if (CHECK_ARG_PARAM("-dumprangef"))
{
std::string str(argv[++i]);

std::vector<std::string_view> split = StringUtil::SplitString(str, ',');
int start = 0;
int num = -1;
int by = 1;
if (split.size() > 0)
{
start = StringUtil::FromChars<int>(split[0]).value_or(0);
}
if (split.size() > 1)
{
num = StringUtil::FromChars<int>(split[1]).value_or(-1);
}
if (split.size() > 2)
{
by = std::max(1, StringUtil::FromChars<int>(split[2]).value_or(1));
}
s_settings_interface.SetIntValue("EmuCore/GS", "savenf", start);
s_settings_interface.SetIntValue("EmuCore/GS", "savelf", num);
s_settings_interface.SetIntValue("EmuCore/GS", "savebf", by);
continue;
}
else if (CHECK_ARG_PARAM("-dumpdirhw"))
{
s_settings_interface.SetStringValue("EmuCore/GS", "HWDumpDirectory", argv[++i]);
continue;
}
else if (CHECK_ARG_PARAM("-dumpdirsw"))
{
s_settings_interface.SetStringValue("EmuCore/GS", "SWDumpDirectory", argv[++i]);
continue;
}
else if (CHECK_ARG_PARAM("-loop"))
{
s_loop_count = StringUtil::FromChars<s32>(argv[++i]).value_or(0);
Expand Down Expand Up @@ -543,6 +633,19 @@ bool GSRunner::ParseCommandLineArgs(int argc, char* argv[], VMBootParameters& pa
s_settings_interface.SetIntValue("EmuCore/GS", "Renderer", static_cast<int>(type));
continue;
}
else if (CHECK_ARG_PARAM("-swthreads"))
{
const int swthreads = StringUtil::FromChars<int>(argv[++i]).value_or(0);
if (swthreads < 0)
{
Console.WriteLn("Invalid number of software threads");
return false;
}

Console.WriteLn(fmt::format("Setting number of software threads to {}", swthreads));
s_settings_interface.SetIntValue("EmuCore/GS", "SWExtraThreads", swthreads);
continue;
}
else if (CHECK_ARG_PARAM("-renderhacks"))
{
std::string str(argv[++i]);
Expand Down Expand Up @@ -643,6 +746,18 @@ bool GSRunner::ParseCommandLineArgs(int argc, char* argv[], VMBootParameters& pa
return false;
}

if (s_settings_interface.GetBoolValue("EmuCore/GS", "dump") && !dumpdir.empty())
{
if (s_settings_interface.GetStringValue("EmuCore/GS", "HWDumpDirectory").empty())
s_settings_interface.SetStringValue("EmuCore/GS", "HWDumpDirectory", dumpdir.c_str());
if (s_settings_interface.GetStringValue("EmuCore/GS", "SWDumpDirectory").empty())
s_settings_interface.SetStringValue("EmuCore/GS", "SWDumpDirectory", dumpdir.c_str());

// Disable saving frames with SaveSnapshotToMemory()
// Instead we save more "raw" snapshots when using -dump.
s_output_prefix = "";
}

// set up the frame dump directory
if (!s_output_prefix.empty())
{
Expand Down
9 changes: 9 additions & 0 deletions pcsx2/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -745,6 +745,8 @@ struct Pcsx2Config
SaveFrame : 1,
SaveTexture : 1,
SaveDepth : 1,
SaveAlpha : 1,
SaveInfo : 1,
DumpReplaceableTextures : 1,
DumpReplaceableMipmaps : 1,
DumpTexturesWithFMVActive : 1,
Expand Down Expand Up @@ -822,6 +824,10 @@ struct Pcsx2Config

int SaveN = 0;
int SaveL = 5000;
int SaveB = 1;
int SaveNF = 0;
int SaveLF = -1;
int SaveBF = 1;

s8 ExclusiveFullscreenControl = -1;
GSScreenshotSize ScreenshotSize = GSScreenshotSize::WindowResolution;
Expand Down Expand Up @@ -865,6 +871,9 @@ struct Pcsx2Config

bool operator==(const GSOptions& right) const;
bool operator!=(const GSOptions& right) const;

// Should we dump this draw/frame?
bool ShouldDump(int draw, int frame) const;
};

struct SPU2Options
Expand Down
7 changes: 3 additions & 4 deletions pcsx2/GS/GSDrawingContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -203,16 +203,15 @@ void GSDrawingContext::Dump(const std::string& filename)
"\tTBW:%u\n"
"\tPSM:0x%x\n"
"\tTW:%u\n"
"\tTH:%u\n"
"\tTCC:%u\n"
"\tTFX:%u\n"
"\tCBP:0x%x\n"
"\tCPSM:0x%x\n"
"\tCSM:%u\n"
"\tCSA:%u\n"
"\tCLD:%u\n"
"\tTH:%u\n",
TEX0.TBP0, TEX0.TBW, TEX0.PSM, TEX0.TW, TEX0.TCC, TEX0.TFX, TEX0.CBP, TEX0.CPSM, TEX0.CSM, TEX0.CSA, TEX0.CLD,
static_cast<uint32_t>(TEX0.TH));
"\tCLD:%u\n\n",
TEX0.TBP0, TEX0.TBW, TEX0.PSM, TEX0.TW, static_cast<uint32_t>(TEX0.TH), TEX0.TCC, TEX0.TFX, TEX0.CBP, TEX0.CPSM, TEX0.CSM, TEX0.CSA, TEX0.CLD);

fprintf(fp,
"TEX1\n"
Expand Down
1 change: 0 additions & 1 deletion pcsx2/GS/GSDrawingEnvironment.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@ class alignas(32) GSDrawingEnvironment

fprintf(fp, "SCANMSK\n"
"\tMSK:%u\n\n"
"\n"
, SCANMSK.MSK);

fprintf(fp, "TEXA\n"
Expand Down
6 changes: 1 addition & 5 deletions pcsx2/GS/GSLocalMemory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -662,11 +662,7 @@ void GSLocalMemory::SaveBMP(const std::string& fn, u32 bp, u32 bw, u32 psm, int
}
}

#ifdef PCSX2_DEVBUILD
GSPng::Save(GSPng::RGB_A_PNG, fn, static_cast<u8*>(bits), w, h, pitch, GSConfig.PNGCompressionLevel, false);
#else
GSPng::Save(GSPng::RGB_PNG, fn, static_cast<u8*>(bits), w, h, pitch, GSConfig.PNGCompressionLevel, false);
#endif
GSPng::Save((IsDevBuild || GSConfig.SaveAlpha) ? GSPng::RGB_A_PNG : GSPng::RGB_PNG, fn, static_cast<u8*>(bits), w, h, pitch, GSConfig.PNGCompressionLevel, false);

_aligned_free(bits);
}
Expand Down
10 changes: 5 additions & 5 deletions pcsx2/GS/GSState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,7 @@ void GSState::DumpVertices(const std::string& filename)
file << std::fixed << std::setprecision(4);
for (u32 i = 0; i < count; ++i)
{
file << "\t" << "v" << i << ": ";
file << "\t" << std::dec << "v" << i << ": ";
GSVertex v = buffer[m_index.buff[i]];

const float x = (v.XYZ.X - (int)m_context->XYOFFSET.OFX) / 16.0f;
Expand All @@ -461,7 +461,7 @@ void GSState::DumpVertices(const std::string& filename)
file << std::fixed << std::setprecision(6);
for (u32 i = 0; i < count; ++i)
{
file << "\t" << "v" << i << ": ";
file << "\t" << std::dec << "v" << i << ": ";
GSVertex v = buffer[m_index.buff[i]];

file << std::setfill('0') << std::setw(3) << unsigned(v.RGBAQ.R) << DEL;
Expand All @@ -479,7 +479,7 @@ void GSState::DumpVertices(const std::string& filename)
file << "TEXTURE COORDS (" << qualifier << ")" << std::endl;;
for (u32 i = 0; i < count; ++i)
{
file << "\t" << "v" << i << ": ";
file << "\t" << "v" << std::dec << i << ": ";
const GSVertex v = buffer[m_index.buff[i]];

// note
Expand Down Expand Up @@ -1994,7 +1994,7 @@ void GSState::InitReadFIFO(u8* mem, int len)
// Read the image all in one go.
m_mem.ReadImageX(m_tr.x, m_tr.y, m_tr.buff, m_tr.total, m_env.BITBLTBUF, m_env.TRXPOS, m_env.TRXREG);

if (GSConfig.DumpGSData && GSConfig.SaveRT && s_n >= GSConfig.SaveN)
if (GSConfig.SaveRT && GSConfig.ShouldDump(s_n, g_perfmon.GetFrame()))
{
const std::string s(GetDrawDumpPath(
"%05d_read_%05x_%d_%d_%d_%d_%d_%d.bmp",
Expand Down Expand Up @@ -2742,7 +2742,7 @@ int GSState::Defrost(const freezeData* fd)
m_mem.m_clut.Reset();
(PRIM->CTXT == 0) ? ApplyTEX0<0>(m_context->TEX0) : ApplyTEX0<1>(m_context->TEX0);

g_perfmon.SetFrame(5000);
g_perfmon.SetFrame(0);

ResetPCRTC();

Expand Down
4 changes: 2 additions & 2 deletions pcsx2/GS/Renderers/Common/GSRenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -546,9 +546,9 @@ void GSRenderer::EndPresentFrame()

void GSRenderer::VSync(u32 field, bool registers_written, bool idle_frame)
{
if (GSConfig.DumpGSData && s_n >= GSConfig.SaveN)
if (GSConfig.SaveInfo && GSConfig.ShouldDump(s_n, g_perfmon.GetFrame()))
{
DumpGSPrivRegs(*m_regs, GetDrawDumpPath("vsync_%05d_f%lld_gs_reg.txt", s_n, g_perfmon.GetFrame()));
DumpGSPrivRegs(*m_regs, GetDrawDumpPath("%05d_f%05lld_vsync_gs_reg.txt", s_n, g_perfmon.GetFrame()));
}

const int fb_sprite_blits = g_perfmon.GetDisplayFramebufferSpriteBlits();
Expand Down
7 changes: 2 additions & 5 deletions pcsx2/GS/Renderers/Common/GSTexture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,8 @@ bool GSTexture::Save(const std::string& fn)
return res;
}

#ifdef PCSX2_DEVBUILD
GSPng::Format format = GSPng::RGB_A_PNG;
#else
GSPng::Format format = GSPng::RGB_PNG;
#endif
GSPng::Format format = (IsDevBuild || GSConfig.SaveAlpha) ? GSPng::RGB_A_PNG : GSPng::RGB_PNG;

switch (m_format)
{
case Format::UNorm8:
Expand Down
Loading