GS-Debug: Dump verticles with draws

- Move context dumping to the top so we see it as the game set, not after we've messed with it.
Thanks to tadanokojin for these changes
This commit is contained in:
refractionpcsx2 2022-03-13 03:46:16 +00:00
parent 3e7d32c807
commit bbe3af7f61
4 changed files with 135 additions and 20 deletions

View File

@ -20,6 +20,7 @@
#include <algorithm> // clamp
#include <cfloat> // FLT_MAX
#include <iomanip> // Dump Verticles
int GSState::s_n = 0;
@ -551,6 +552,100 @@ float GSState::GetTvRefreshRate()
__assume(0); // unreachable
}
void GSState::DumpVertices(std::string& filename)
{
std::ofstream file(filename);
if (!file.is_open())
return;
size_t count = m_index.tail;
GSVertex* buffer = &m_vertex.buff[0];
const char* DEL = ", ";
file << "VERTEX COORDS (XYZ)" << std::endl;
file << std::fixed << std::setprecision(4);
for (size_t i = 0; i < count; ++i)
{
file << "\t" << "v" << i << ": ";
GSVertex v = buffer[m_index.buff[i]];
float x = (v.XYZ.X - (int)m_context->XYOFFSET.OFX) / 16.0f;
float y = (v.XYZ.Y - (int)m_context->XYOFFSET.OFY) / 16.0f;
file << x << DEL;
file << y << DEL;
file << v.XYZ.Z;
file << std::endl;
}
file << std::endl;
file << "VERTEX COLOR (RGBA)" << std::endl;
file << std::fixed << std::setprecision(6);
for (size_t i = 0; i < count; ++i)
{
file << "\t" << "v" << i << ": ";
GSVertex v = buffer[m_index.buff[i]];
file << std::setfill('0') << std::setw(3) << unsigned(v.RGBAQ.R) << DEL;
file << std::setfill('0') << std::setw(3) << unsigned(v.RGBAQ.G) << DEL;
file << std::setfill('0') << std::setw(3) << unsigned(v.RGBAQ.B) << DEL;
file << std::setfill('0') << std::setw(3) << unsigned(v.RGBAQ.A);
file << std::endl;
}
file << std::endl;
bool use_uv = PRIM->FST;
std::string qualifier = use_uv ? "UV" : "STQ";
file << "TEXTURE COORDS (" << qualifier << ")" << std::endl;;
for (size_t i = 0; i < count; ++i)
{
file << "\t" << "v" << i << ": ";
GSVertex v = buffer[m_index.buff[i]];
// note
// Yes, technically as far as the GS is concerned Q belongs
// to RGBAQ. However, the purpose of this dump is to print
// our data in a more human readable format and typically Q
// is associated with STQ.
if (use_uv)
{
float uv_U = v.U / 16.0f;
float uv_V = v.V / 16.0f;
file << uv_U << DEL << uv_V;
}
else
file << v.ST.S << DEL << v.ST.T << DEL << v.RGBAQ.Q;
file << std::endl;
}
file << std::endl;
file << "TRACER" << std::endl;
GSVector4i v = m_vt.m_min.c;
file << "\tmin c (x,y,z,w): " << v.x << DEL << v.y << DEL << v.z << DEL << v.w << std::endl;
v = m_vt.m_max.c;
file << "\tmax c (x,y,z,w): " << v.x << DEL << v.y << DEL << v.z << DEL << v.w << std::endl;
GSVector4 v2 = m_vt.m_min.p;
file << "\tmin p (x,y,z,w): " << v2.x << DEL << v2.y << DEL << v2.z << DEL << v2.w << std::endl;
v2 = m_vt.m_max.p;
file << "\tmax p (x,y,z,w): " << v2.x << DEL << v2.y << DEL << v2.z << DEL << v2.w << std::endl;
v2 = m_vt.m_min.t;
file << "\tmin t (x,y,z,w): " << v2.x << DEL << v2.y << DEL << v2.z << DEL << v2.w << std::endl;
v2 = m_vt.m_max.t;
file << "\tmax t (x,y,z,w): " << v2.x << DEL << v2.y << DEL << v2.z << DEL << v2.w << std::endl;
file.close();
}
void GSState::GIFPackedRegHandlerNull(const GIFPackedReg* RESTRICT r)
{
}

View File

@ -303,6 +303,7 @@ public:
void SetRegsMem(u8* basemem) { m_regs = reinterpret_cast<GSPrivRegSet*>(basemem); }
void SetFrameSkip(int skip);
void DumpVertices(std::string& filename);
PRIM_OVERLAP PrimitiveOverlap();
GIFRegTEX0 GetTex0Layer(u32 lod);

View File

@ -1196,6 +1196,25 @@ void GSRendererHW::RoundSpriteOffset()
void GSRendererHW::Draw()
{
if (s_dump)
{
const u64 frame = g_perfmon.GetFrame();
std::string s;
if (s_n >= s_saven)
{
// Dump Register state
s = format("%05d_context.txt", s_n);
m_env.Dump(m_dump_root + s);
m_context->Dump(m_dump_root + s);
// Dump vertices
s = format("%05d_vertex.txt", s_n);
DumpVertices(m_dump_root + s);
}
}
if (IsBadFrame())
{
GL_INS("Warning skipping a draw call (%d)", s_n);
@ -1602,15 +1621,6 @@ void GSRendererHW::Draw()
std::string s;
if (s_n >= s_saven)
{
// Dump Register state
s = format("%05d_context.txt", s_n);
m_env.Dump(m_dump_root + s);
m_context->Dump(m_dump_root + s);
}
if (s_savet && s_n >= s_saven && m_src)
{
s = format("%05d_f%lld_itex_%05x_%s_%d%d_%02x_%02x_%02x_%02x.dds",

View File

@ -317,6 +317,24 @@ void GSRendererSW::Draw()
{
const GSDrawingContext* context = m_context;
if (s_dump)
{
std::string s;
if (s_n >= s_saven)
{
// Dump Register state
s = format("%05d_context.txt", s_n);
m_env.Dump(m_dump_root + s);
m_context->Dump(m_dump_root + s);
// Dump vertices
s = format("%05d_vertex.txt", s_n);
DumpVertices(m_dump_root + s);
}
}
auto data = m_vertex_heap.make_shared<SharedData>(this).cast<GSRasterizerData>();
SharedData* sd = static_cast<SharedData*>(data.get());
@ -426,22 +444,13 @@ void GSRendererSW::Draw()
{
Sync(2);
std::string s;
u64 frame = g_perfmon.GetFrame();
// Dump the texture in 32 bits format. It helps to debug texture shuffle effect
// 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));
std::string s;
if (s_n >= s_saven)
{
// Dump Register state
s = format("%05d_context.txt", s_n);
m_env.Dump(m_dump_root + s);
m_context->Dump(m_dump_root + s);
}
if (s_savet && s_n >= s_saven && PRIM->TME)
{
if (texture_shuffle)