Skip to content

Commit

Permalink
Add option for dump every mod B frames/draws.
Browse files Browse the repository at this point in the history
  • Loading branch information
TJnotJT committed Jan 24, 2025
1 parent b171d2a commit b429b4e
Show file tree
Hide file tree
Showing 7 changed files with 74 additions and 69 deletions.
24 changes: 20 additions & 4 deletions pcsx2-gsrunner/Main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -445,10 +445,12 @@ static void PrintCommandLineHelp(const char* progname)
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]: Enabling dunmping of render target, texture, z buffer, frame, "
"and alphas (respectively) per draw. Always enables dumping context/vertices. Generates lots of data.\n");
std::fprintf(stderr, " -dumprange N[,L]: Start dumping from draw N (base 0) and stops after L draws (smaller of -dumprange and -dumrangef used)."
"Defaults to N=0 and L=-1 (all draws). Only used if -dump used.\n");
std::fprintf(stderr, " -dumprangef NF[,LF]: Start dumping from frame NF (base 0) and stops after LF frames (smaller of -dumprange and -dumrangef used).\n"
"Defaults to NF=0 and LF=-1 (all frames). Only used if -dump is used.\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 -dumrangef used)."
"Defaults to N=0,L=-1,B=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 -dumrangef used).\n"
"Defaults to NF=0,LF=-1,BF=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, " -window: Forces a window to be displayed.\n");
Expand Down Expand Up @@ -514,8 +516,10 @@ bool GSRunner::ParseCommandLineArgs(int argc, char* argv[], VMBootParameters& pa
s_settings_interface.SetBoolValue("EmuCore/GS", "dump", true);
s_settings_interface.SetIntValue("EmuCore/GS", "saven", 0);
s_settings_interface.SetIntValue("EmuCore/GS", "savel", -1);
s_settings_interface.SetIntValue("EmuCore/GS", "saveb", 1);
s_settings_interface.SetIntValue("EmuCore/GS", "savenf", 0);
s_settings_interface.SetIntValue("EmuCore/GS", "savelf", -1);
s_settings_interface.SetIntValue("EmuCore/GS", "savelf", 1);

if (str.find("rt") != std::string::npos)
s_settings_interface.SetBoolValue("EmuCore/GS", "save", true);
Expand All @@ -536,6 +540,7 @@ bool GSRunner::ParseCommandLineArgs(int argc, char* argv[], VMBootParameters& pa
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);
Expand All @@ -544,8 +549,13 @@ bool GSRunner::ParseCommandLineArgs(int argc, char* argv[], VMBootParameters& pa
{
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"))
Expand All @@ -555,6 +565,7 @@ bool GSRunner::ParseCommandLineArgs(int argc, char* argv[], VMBootParameters& pa
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);
Expand All @@ -563,8 +574,13 @@ bool GSRunner::ParseCommandLineArgs(int argc, char* argv[], VMBootParameters& pa
{
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", "savelb", by);
continue;
}
else if (CHECK_ARG_PARAM("-dumpdirhw"))
Expand Down
5 changes: 5 additions & 0 deletions pcsx2/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -823,8 +823,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 @@ -868,6 +870,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
2 changes: 1 addition & 1 deletion pcsx2/GS/GSState.cpp
Original file line number Diff line number Diff line change
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 && g_perfmon.GetFrame() >= GSConfig.SaveNF)
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
2 changes: 1 addition & 1 deletion pcsx2/GS/Renderers/Common/GSRenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -546,7 +546,7 @@ void GSRenderer::EndPresentFrame()

void GSRenderer::VSync(u32 field, bool registers_written, bool idle_frame)
{
if (GSConfig.DumpGSData && s_n >= GSConfig.SaveN)
if (GSConfig.ShouldDump(s_n, g_perfmon.GetFrame()))
{
DumpGSPrivRegs(*m_regs, GetDrawDumpPath("vsync_%05d_f%05lld_gs_reg.txt", s_n, g_perfmon.GetFrame()));
}
Expand Down
22 changes: 8 additions & 14 deletions pcsx2/GS/Renderers/HW/GSRendererHW.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1984,7 +1984,7 @@ void GSRendererHW::RoundSpriteOffset()

void GSRendererHW::Draw()
{
if (GSConfig.DumpGSData && (s_n >= GSConfig.SaveN) && g_perfmon.GetFrame() >= GSConfig.SaveNF)
if (GSConfig.ShouldDump(s_n, g_perfmon.GetFrame()))
{
std::string s;

Expand Down Expand Up @@ -3264,13 +3264,13 @@ void GSRendererHW::Draw()
src->m_texture = src->m_from_target->m_texture;
}

if (GSConfig.DumpGSData)
if (GSConfig.ShouldDump(s_n, g_perfmon.GetFrame()))
{
const u64 frame = g_perfmon.GetFrame();

std::string s;

if (GSConfig.SaveTexture && s_n >= GSConfig.SaveN && g_perfmon.GetFrame() >= GSConfig.SaveNF && src)
if (GSConfig.SaveTexture && src)
{
s = GetDrawDumpPath("%05d_f%05lld_itex_%05x_%s_%d%d_%02x_%02x_%02x_%02x.dds",
s_n, frame, static_cast<int>(m_cached_ctx.TEX0.TBP0), psm_str(m_cached_ctx.TEX0.PSM),
Expand All @@ -3288,15 +3288,15 @@ void GSRendererHW::Draw()
}
}

if (rt && GSConfig.SaveRT && s_n >= GSConfig.SaveN && g_perfmon.GetFrame() >= GSConfig.SaveNF)
if (rt && GSConfig.SaveRT)
{
s = GetDrawDumpPath("%05d_f%05lld_rt0_%05x_%s.bmp", s_n, frame, m_cached_ctx.FRAME.Block(), psm_str(m_cached_ctx.FRAME.PSM));

if (rt->m_texture)
rt->m_texture->Save(s);
}

if (ds && GSConfig.SaveDepth && s_n >= GSConfig.SaveN && g_perfmon.GetFrame() >= GSConfig.SaveNF)
if (ds && GSConfig.SaveDepth)
{
s = GetDrawDumpPath("%05d_f%05lld_rz0_%05x_%s.bmp", s_n, frame, m_cached_ctx.ZBUF.Block(), psm_str(m_cached_ctx.ZBUF.PSM));

Expand Down Expand Up @@ -3415,31 +3415,25 @@ void GSRendererHW::Draw()

//

if (GSConfig.DumpGSData)
if (GSConfig.ShouldDump(s_n, g_perfmon.GetFrame()))
{
const u64 frame = g_perfmon.GetFrame();

std::string s;

if (GSConfig.SaveRT && s_n >= GSConfig.SaveN && g_perfmon.GetFrame() >= GSConfig.SaveNF)
if (GSConfig.SaveRT)
{
s = GetDrawDumpPath("%05d_f%05lld_rt1_%05x_%s.bmp", s_n, frame, m_cached_ctx.FRAME.Block(), psm_str(m_cached_ctx.FRAME.PSM));

rt->m_texture->Save(s);
}

if (GSConfig.SaveDepth && s_n >= GSConfig.SaveN && g_perfmon.GetFrame() >= GSConfig.SaveNF)
if (GSConfig.SaveDepth)
{
s = GetDrawDumpPath("%05d_f%05lld_rz1_%05x_%s.bmp", s_n, frame, m_cached_ctx.ZBUF.Block(), psm_str(m_cached_ctx.ZBUF.PSM));

ds->m_texture->Save(s);
}

if ((GSConfig.SaveL > 0 && (s_n - GSConfig.SaveN) >= GSConfig.SaveL) ||
(GSConfig.SaveLF > 0 && ((int)g_perfmon.GetFrame() - GSConfig.SaveNF) >= GSConfig.SaveLF))
{
GSConfig.DumpGSData = 0;
}
}

if (rt)
Expand Down
75 changes: 26 additions & 49 deletions pcsx2/GS/Renderers/SW/GSRendererSW.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -179,12 +179,9 @@ GSTexture* GSRendererSW::GetOutput(int i, float& scale, int& y_offset)

m_texture[index]->Update(out_r, m_output, pitch);

if (GSConfig.DumpGSData)
if (GSConfig.ShouldDump(s_n, g_perfmon.GetFrame()) && GSConfig.SaveFrame)
{
if (GSConfig.SaveFrame && s_n >= GSConfig.SaveN && g_perfmon.GetFrame() >= GSConfig.SaveNF)
{
m_texture[index]->Save(GetDrawDumpPath("%05d_f%05lld_fr%d_%05x_%s.bmp", s_n, g_perfmon.GetFrame(), i, (int)curFramebuffer.Block(), psm_str(curFramebuffer.PSM)));
}
m_texture[index]->Save(GetDrawDumpPath("%05d_f%05lld_fr%d_%05x_%s.bmp", s_n, g_perfmon.GetFrame(), i, (int)curFramebuffer.Block(), psm_str(curFramebuffer.PSM)));
}
}

Expand Down Expand Up @@ -312,22 +309,17 @@ void GSRendererSW::Draw()
{
const GSDrawingContext* context = m_context;

if (GSConfig.DumpGSData)
if (GSConfig.ShouldDump(s_n, g_perfmon.GetFrame()))
{
std::string s;
// Dump Register state
std::string s = GetDrawDumpPath("%05d_context.txt", s_n);

if (s_n >= GSConfig.SaveN && g_perfmon.GetFrame() >= GSConfig.SaveNF)
{
// Dump Register state
s = GetDrawDumpPath("%05d_context.txt", s_n);

m_draw_env->Dump(s);
m_context->Dump(s);
m_draw_env->Dump(s);
m_context->Dump(s);

// Dump vertices
s = GetDrawDumpPath("%05d_vertex.txt", s_n);
DumpVertices(s);
}
// Dump vertices
s = GetDrawDumpPath("%05d_vertex.txt", s_n);
DumpVertices(s);
}

auto data = m_vertex_heap.make_shared<SharedData>().cast<GSRasterizerData>();
Expand Down Expand Up @@ -431,9 +423,7 @@ void GSRendererSW::Draw()

sd->UsePages(fb_pages, m_context->offset.fb.psm(), zb_pages, m_context->offset.zb.psm());

//

if (GSConfig.DumpGSData)
if (GSConfig.ShouldDump(s_n, g_perfmon.GetFrame()))
{
Sync(2);

Expand All @@ -444,7 +434,7 @@ void GSRendererSW::Draw()
// It will breaks the few games that really uses 16 bits RT
bool texture_shuffle = ((context->FRAME.PSM & 0x2) && ((context->TEX0.PSM & 3) == 2) && (m_vt.m_primclass == GS_SPRITE_CLASS));

if (GSConfig.SaveTexture && s_n >= GSConfig.SaveN && g_perfmon.GetFrame() >= GSConfig.SaveNF && PRIM->TME)
if (GSConfig.SaveTexture && PRIM->TME)
{
if (texture_shuffle)
{
Expand All @@ -457,7 +447,7 @@ void GSRendererSW::Draw()
m_mem.SaveBMP(s, m_context->TEX0.TBP0, m_context->TEX0.TBW, m_context->TEX0.PSM, 1 << m_context->TEX0.TW, 1 << m_context->TEX0.TH);
}

if (GSConfig.SaveRT && s_n >= GSConfig.SaveN && g_perfmon.GetFrame() >= GSConfig.SaveNF)
if (GSConfig.SaveRT)
{

if (texture_shuffle)
Expand All @@ -471,7 +461,7 @@ void GSRendererSW::Draw()
m_mem.SaveBMP(s, m_context->FRAME.Block(), m_context->FRAME.FBW, m_context->FRAME.PSM, r.z, r.w);
}

if (GSConfig.SaveDepth && s_n >= GSConfig.SaveN && g_perfmon.GetFrame() >= GSConfig.SaveNF)
if (GSConfig.SaveDepth)
{
s = GetDrawDumpPath("%05d_f%05lld_rz0_%05x_%s.bmp", s_n, frame, m_context->ZBUF.Block(), psm_str(m_context->ZBUF.PSM));

Expand All @@ -482,7 +472,7 @@ void GSRendererSW::Draw()

Sync(3);

if (GSConfig.SaveRT && s_n >= GSConfig.SaveN && g_perfmon.GetFrame() >= GSConfig.SaveNF)
if (GSConfig.SaveRT)
{
if (texture_shuffle)
{
Expand All @@ -495,18 +485,12 @@ void GSRendererSW::Draw()
m_mem.SaveBMP(s, m_context->FRAME.Block(), m_context->FRAME.FBW, m_context->FRAME.PSM, r.z, r.w);
}

if (GSConfig.SaveDepth && s_n >= GSConfig.SaveN && g_perfmon.GetFrame() >= GSConfig.SaveNF)
if (GSConfig.SaveDepth)
{
s = GetDrawDumpPath("%05d_f%05lld_rz1_%05x_%s.bmp", s_n, frame, m_context->ZBUF.Block(), psm_str(m_context->ZBUF.PSM));

m_mem.SaveBMP(s, m_context->ZBUF.Block(), m_context->FRAME.FBW, m_context->ZBUF.PSM, r.z, r.w);
}

if ((GSConfig.SaveL > 0 && (s_n - GSConfig.SaveN) >= GSConfig.SaveL) ||
(GSConfig.SaveLF > 0 && ((int)g_perfmon.GetFrame() - GSConfig.SaveNF) >= GSConfig.SaveLF))
{
GSConfig.DumpGSData = 0;
}
}
else
{
Expand Down Expand Up @@ -1547,28 +1531,21 @@ void GSRendererSW::SharedData::UpdateSource()
}
}

if (GSConfig.DumpGSData)
if (GSConfig.SaveTexture && GSConfig.ShouldDump(s_n, g_perfmon.GetFrame()))
{
const u64 frame = g_perfmon.GetFrame();

std::string s;

if (GSConfig.SaveTexture && g_gs_renderer->s_n >= GSConfig.SaveN && g_perfmon.GetFrame() >= GSConfig.SaveNF)
for (size_t i = 0; m_tex[i].t; i++)
{
for (size_t i = 0; m_tex[i].t; i++)
{
const GIFRegTEX0& TEX0 = g_gs_renderer->GetTex0Layer(i);
const GIFRegTEX0& TEX0 = g_gs_renderer->GetTex0Layer(i);

s = GetDrawDumpPath("%05d_f%05lld_itex%d_%05x_%s.bmp", g_gs_renderer->s_n, frame, i, TEX0.TBP0, psm_str(TEX0.PSM));
std::string s = GetDrawDumpPath("%05d_f%05lld_itex%d_%05x_%s.bmp", g_gs_renderer->s_n, g_perfmon.GetFrame(), i, TEX0.TBP0, psm_str(TEX0.PSM));

m_tex[i].t->Save(s);
}
m_tex[i].t->Save(s);
}

if (global.clut)
{
s = GetDrawDumpPath("%05d_f%05lld_itexp_%05x_%s.bmp", g_gs_renderer->s_n, frame, (int)g_gs_renderer->m_context->TEX0.CBP, psm_str(g_gs_renderer->m_context->TEX0.CPSM));
GSPng::Save((IsDevBuild || GSConfig.SaveAlpha) ? GSPng::RGB_A_PNG : GSPng::RGB_PNG, s, reinterpret_cast<const u8*>(global.clut), 256, 1, sizeof(u32) * 256, GSConfig.PNGCompressionLevel, false);
}
if (global.clut)
{
std::string s = GetDrawDumpPath("%05d_f%05lld_itexp_%05x_%s.bmp", g_gs_renderer->s_n, g_perfmon.GetFrame(), (int)g_gs_renderer->m_context->TEX0.CBP, psm_str(g_gs_renderer->m_context->TEX0.CPSM));
GSPng::Save((IsDevBuild || GSConfig.SaveAlpha) ? GSPng::RGB_A_PNG : GSPng::RGB_PNG, s, reinterpret_cast<const u8*>(global.clut), 256, 1, sizeof(u32) * 256, GSConfig.PNGCompressionLevel, false);
}
}
}
13 changes: 13 additions & 0 deletions pcsx2/Pcsx2Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -840,6 +840,10 @@ bool Pcsx2Config::GSOptions::OptionsAreEqual(const GSOptions& right) const
OpEqu(PNGCompressionLevel) &&
OpEqu(SaveN) &&
OpEqu(SaveL) &&
OpEqu(SaveB) &&
OpEqu(SaveNF) &&
OpEqu(SaveLF) &&
OpEqu(SaveBF) &&

OpEqu(ExclusiveFullscreenControl) &&
OpEqu(ScreenshotSize) &&
Expand Down Expand Up @@ -1027,8 +1031,10 @@ void Pcsx2Config::GSOptions::LoadSave(SettingsWrapper& wrap)
SettingsWrapBitfieldEx(PNGCompressionLevel, "png_compression_level");
SettingsWrapBitfieldEx(SaveN, "saven");
SettingsWrapBitfieldEx(SaveL, "savel");
SettingsWrapBitfieldEx(SaveL, "saveb");
SettingsWrapBitfieldEx(SaveNF, "savenf");
SettingsWrapBitfieldEx(SaveLF, "savelf");
SettingsWrapBitfieldEx(SaveLF, "savebf");

SettingsWrapEntryEx(CaptureContainer, "CaptureContainer");
SettingsWrapEntryEx(VideoCaptureCodec, "VideoCaptureCodec");
Expand Down Expand Up @@ -1113,6 +1119,13 @@ bool Pcsx2Config::GSOptions::UseHardwareRenderer() const
return (Renderer != GSRendererType::Null && Renderer != GSRendererType::SW);
}

bool Pcsx2Config::GSOptions::ShouldDump(int draw, int frame) const
{
return DumpGSData &&
(SaveN <= draw) && (draw < SaveN + SaveL) && (draw % SaveB == 0) &&
(SaveNF <= frame) && (frame < SaveNF + SaveLF) && (frame % SaveBF == 0);
}

static constexpr const std::array s_spu2_sync_mode_names = {
"Disabled",
"TimeStretch",
Expand Down

0 comments on commit b429b4e

Please sign in to comment.