mirror of https://github.com/PCSX2/pcsx2.git
GSDump: Add extensible header and serial
Serial is used to apply hw fixes.
This commit is contained in:
parent
5569e94f41
commit
4ed748fa30
|
@ -16,6 +16,7 @@
|
|||
#include "PrecompiledHeader.h"
|
||||
#include "GSDump.h"
|
||||
#include "GSExtra.h"
|
||||
#include "GSState.h"
|
||||
|
||||
GSDumpBase::GSDumpBase(const std::string& fn)
|
||||
: m_frames(0)
|
||||
|
@ -32,10 +33,29 @@ GSDumpBase::~GSDumpBase()
|
|||
fclose(m_gs);
|
||||
}
|
||||
|
||||
void GSDumpBase::AddHeader(u32 crc, const freezeData& fd, const GSPrivRegSet* regs)
|
||||
void GSDumpBase::AddHeader(const std::string& serial, u32 crc, const freezeData& fd, const GSPrivRegSet* regs)
|
||||
{
|
||||
AppendRawData(&crc, 4);
|
||||
AppendRawData(&fd.size, 4);
|
||||
// New header: CRC of FFFFFFFF, secondary header, full header follows.
|
||||
const u32 fake_crc = 0xFFFFFFFFu;
|
||||
AppendRawData(&fake_crc, 4);
|
||||
|
||||
// Compute full header size (with serial).
|
||||
// This acts as the state size for loading older dumps.
|
||||
const u32 header_size = sizeof(GSDumpHeader) + static_cast<u32>(serial.size());
|
||||
AppendRawData(&header_size, 4);
|
||||
|
||||
// Write hader.
|
||||
GSDumpHeader header = {};
|
||||
header.state_version = GSState::STATE_VERSION;
|
||||
header.state_size = fd.size;
|
||||
header.crc = crc;
|
||||
header.serial_offset = sizeof(header);
|
||||
header.serial_size = static_cast<u32>(serial.size());
|
||||
AppendRawData(&header, sizeof(header));
|
||||
if (!serial.empty())
|
||||
AppendRawData(serial.data(), serial.size());
|
||||
|
||||
// Then the real state data.
|
||||
AppendRawData(fd.data, fd.size);
|
||||
AppendRawData(regs, sizeof(*regs));
|
||||
}
|
||||
|
@ -92,18 +112,18 @@ void GSDumpBase::Write(const void* data, size_t size)
|
|||
// GSDump implementation
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
GSDump::GSDump(const std::string& fn, u32 crc, const freezeData& fd, const GSPrivRegSet* regs)
|
||||
GSDumpUncompressed::GSDumpUncompressed(const std::string& fn, const std::string& serial, u32 crc, const freezeData& fd, const GSPrivRegSet* regs)
|
||||
: GSDumpBase(fn + ".gs")
|
||||
{
|
||||
AddHeader(crc, fd, regs);
|
||||
AddHeader(serial, crc, fd, regs);
|
||||
}
|
||||
|
||||
void GSDump::AppendRawData(const void* data, size_t size)
|
||||
void GSDumpUncompressed::AppendRawData(const void* data, size_t size)
|
||||
{
|
||||
Write(data, size);
|
||||
}
|
||||
|
||||
void GSDump::AppendRawData(u8 c)
|
||||
void GSDumpUncompressed::AppendRawData(u8 c)
|
||||
{
|
||||
Write(&c, 1);
|
||||
}
|
||||
|
@ -112,7 +132,7 @@ void GSDump::AppendRawData(u8 c)
|
|||
// GSDumpXz implementation
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
GSDumpXz::GSDumpXz(const std::string& fn, u32 crc, const freezeData& fd, const GSPrivRegSet* regs)
|
||||
GSDumpXz::GSDumpXz(const std::string& fn, const std::string& serial, u32 crc, const freezeData& fd, const GSPrivRegSet* regs)
|
||||
: GSDumpBase(fn + ".gs.xz")
|
||||
{
|
||||
m_strm = LZMA_STREAM_INIT;
|
||||
|
@ -123,7 +143,7 @@ GSDumpXz::GSDumpXz(const std::string& fn, u32 crc, const freezeData& fd, const G
|
|||
return;
|
||||
}
|
||||
|
||||
AddHeader(crc, fd, regs);
|
||||
AddHeader(serial, crc, fd, regs);
|
||||
}
|
||||
|
||||
GSDumpXz::~GSDumpXz()
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
/*
|
||||
|
||||
Dump file format:
|
||||
- [crc/4] [state size/4] [state data/size] [PMODE/0x2000] [id/1] [data/?] .. [id/1] [data/?]
|
||||
- [0xFFFFFFFF] [Header] [state size/4] [state data/size] [PMODE/0x2000] [id/1] [data/?] .. [id/1] [data/?]
|
||||
|
||||
Transfer data (id == 0)
|
||||
- [0/1] [path index/1] [size/4] [data/size]
|
||||
|
@ -39,6 +39,17 @@ Regs data (id == 3)
|
|||
|
||||
*/
|
||||
|
||||
#pragma pack(push, 4)
|
||||
struct GSDumpHeader
|
||||
{
|
||||
u32 state_version; ///< Must always be first in struct to safely prevent old PCSX2 versions from crashing.
|
||||
u32 state_size;
|
||||
u32 serial_offset;
|
||||
u32 serial_size;
|
||||
u32 crc;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
class GSDumpBase
|
||||
{
|
||||
int m_frames;
|
||||
|
@ -46,7 +57,7 @@ class GSDumpBase
|
|||
FILE* m_gs;
|
||||
|
||||
protected:
|
||||
void AddHeader(u32 crc, const freezeData& fd, const GSPrivRegSet* regs);
|
||||
void AddHeader(const std::string& serial, u32 crc, const freezeData& fd, const GSPrivRegSet* regs);
|
||||
void Write(const void* data, size_t size);
|
||||
|
||||
virtual void AppendRawData(const void* data, size_t size) = 0;
|
||||
|
@ -61,14 +72,14 @@ public:
|
|||
bool VSync(int field, bool last, const GSPrivRegSet* regs);
|
||||
};
|
||||
|
||||
class GSDump final : public GSDumpBase
|
||||
class GSDumpUncompressed final : public GSDumpBase
|
||||
{
|
||||
void AppendRawData(const void* data, size_t size) final;
|
||||
void AppendRawData(u8 c) final;
|
||||
|
||||
public:
|
||||
GSDump(const std::string& fn, u32 crc, const freezeData& fd, const GSPrivRegSet* regs);
|
||||
virtual ~GSDump() = default;
|
||||
GSDumpUncompressed(const std::string& fn, const std::string& serial, u32 crc, const freezeData& fd, const GSPrivRegSet* regs);
|
||||
virtual ~GSDumpUncompressed() = default;
|
||||
};
|
||||
|
||||
class GSDumpXz final : public GSDumpBase
|
||||
|
@ -83,6 +94,6 @@ class GSDumpXz final : public GSDumpBase
|
|||
void AppendRawData(u8 c);
|
||||
|
||||
public:
|
||||
GSDumpXz(const std::string& fn, u32 crc, const freezeData& fd, const GSPrivRegSet* regs);
|
||||
GSDumpXz(const std::string& fn, const std::string& serial, u32 crc, const freezeData& fd, const GSPrivRegSet* regs);
|
||||
virtual ~GSDumpXz();
|
||||
};
|
||||
|
|
|
@ -29,7 +29,7 @@ static __fi bool IsAutoFlushEnabled()
|
|||
}
|
||||
|
||||
GSState::GSState()
|
||||
: m_version(7)
|
||||
: m_version(STATE_VERSION)
|
||||
, m_gsc(NULL)
|
||||
, m_skip(0)
|
||||
, m_skip_offset(0)
|
||||
|
@ -2173,7 +2173,7 @@ int GSState::Defrost(const freezeData* fd)
|
|||
|
||||
u8* data = fd->data;
|
||||
|
||||
int version;
|
||||
u32 version;
|
||||
|
||||
ReadState(&version, data);
|
||||
|
||||
|
|
|
@ -123,7 +123,7 @@ class GSState : public GSAlignedClass<32>
|
|||
template<bool auto_flush, bool index_swap>
|
||||
void SetPrimHandlers();
|
||||
|
||||
int m_version;
|
||||
u32 m_version;
|
||||
int m_sssize;
|
||||
|
||||
struct GSTransferBuffer
|
||||
|
@ -243,6 +243,8 @@ public:
|
|||
int s_savel;
|
||||
std::string m_dump_root;
|
||||
|
||||
static constexpr u32 STATE_VERSION = 8;
|
||||
|
||||
enum PRIM_OVERLAP
|
||||
{
|
||||
PRIM_OVERLAP_UNKNOW,
|
||||
|
|
|
@ -21,9 +21,15 @@
|
|||
#include "PerformanceMetrics.h"
|
||||
#include "pcsx2/Config.h"
|
||||
#include "common/StringUtil.h"
|
||||
|
||||
#ifndef PCSX2_CORE
|
||||
#include "gui/AppCoreThread.h"
|
||||
#if defined(__unix__)
|
||||
#include <X11/keysym.h>
|
||||
#endif
|
||||
#else
|
||||
#include "VMManager.h"
|
||||
#endif
|
||||
|
||||
GSRenderer::GSRenderer()
|
||||
: m_shift_key(false)
|
||||
|
@ -454,10 +460,16 @@ void GSRenderer::VSync(u32 field, bool registers_written)
|
|||
fd.data = new u8[fd.size];
|
||||
Freeze(&fd, false);
|
||||
|
||||
#ifndef PCSX2_CORE
|
||||
const std::string serial(StringUtil::wxStringToUTF8String(GameInfo::gameSerial));
|
||||
#else
|
||||
const std::string serial(VMManager::GetGameSerial());
|
||||
#endif
|
||||
|
||||
if (m_control_key)
|
||||
m_dump = std::unique_ptr<GSDumpBase>(new GSDump(m_snapshot, m_crc, fd, m_regs));
|
||||
m_dump = std::unique_ptr<GSDumpBase>(new GSDumpUncompressed(m_snapshot, serial, m_crc, fd, m_regs));
|
||||
else
|
||||
m_dump = std::unique_ptr<GSDumpBase>(new GSDumpXz(m_snapshot, m_crc, fd, m_regs));
|
||||
m_dump = std::unique_ptr<GSDumpBase>(new GSDumpXz(m_snapshot, serial, m_crc, fd, m_regs));
|
||||
|
||||
delete[] fd.data;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "common/EmbeddedImage.h"
|
||||
#include "gui/Resources/NoIcon.h"
|
||||
#include "GS.h"
|
||||
#include "GS/GSDump.h"
|
||||
#include "HostDisplay.h"
|
||||
|
||||
#include "PathDefs.h"
|
||||
|
@ -31,6 +32,7 @@
|
|||
#include "gui/GSFrame.h"
|
||||
#include "Counters.h"
|
||||
#include "PerformanceMetrics.h"
|
||||
#include "GameDatabase.h"
|
||||
|
||||
#include <wx/mstream.h>
|
||||
#include <wx/listctrl.h>
|
||||
|
@ -514,7 +516,7 @@ void Dialogs::GSDumpDialog::GenPacketInfo(GSData& dump)
|
|||
{
|
||||
case GSType::Transfer:
|
||||
{
|
||||
char* data = dump.data.get();
|
||||
u8* data = dump.data.get();
|
||||
u32 remaining = dump.length;
|
||||
int idx = 0;
|
||||
while (remaining >= 16)
|
||||
|
@ -532,7 +534,7 @@ void Dialogs::GSDumpDialog::GenPacketInfo(GSData& dump)
|
|||
case GSType::VSync:
|
||||
{
|
||||
wxString s;
|
||||
s.Printf("Field = %u", *(u8*)(dump.data.get()));
|
||||
s.Printf("Field = %u", dump.data[0]);
|
||||
m_gif_packet->AppendItem(rootId, s);
|
||||
break;
|
||||
}
|
||||
|
@ -549,7 +551,7 @@ void Dialogs::GSDumpDialog::GenPacketInfo(GSData& dump)
|
|||
}
|
||||
}
|
||||
|
||||
void Dialogs::GSDumpDialog::ParseTransfer(wxTreeItemId& trootId, char* data)
|
||||
void Dialogs::GSDumpDialog::ParseTransfer(wxTreeItemId& trootId, u8* data)
|
||||
{
|
||||
u64 tag = *(u64*)data;
|
||||
u64 regs = *(u64*)(data + 8);
|
||||
|
@ -815,7 +817,7 @@ void Dialogs::GSDumpDialog::ParseTreePrim(wxTreeItemId& id, u32 prim)
|
|||
m_gif_packet->Expand(id);
|
||||
}
|
||||
|
||||
void Dialogs::GSDumpDialog::ProcessDumpEvent(const GSData& event, char* regs)
|
||||
void Dialogs::GSDumpDialog::ProcessDumpEvent(const GSData& event, u8* regs)
|
||||
{
|
||||
switch (event.id)
|
||||
{
|
||||
|
@ -921,14 +923,46 @@ void Dialogs::GSDumpDialog::GSThread::ExecuteTaskInThread()
|
|||
default:
|
||||
break;
|
||||
}
|
||||
char regs[8192];
|
||||
u8 regs[8192];
|
||||
|
||||
m_dump_file->Read(&crc, 4);
|
||||
m_dump_file->Read(&ss, 4);
|
||||
|
||||
|
||||
std::unique_ptr<char[]> state_data(new char[ss]);
|
||||
std::unique_ptr<u8[]> state_data = std::make_unique<u8[]>(ss);
|
||||
m_dump_file->Read(state_data.get(), ss);
|
||||
|
||||
// Pull serial out of new header, if present.
|
||||
std::string serial;
|
||||
if (crc == 0xFFFFFFFFu)
|
||||
{
|
||||
GSDumpHeader header;
|
||||
if (ss < sizeof(header))
|
||||
{
|
||||
Console.Error("GSDump header is corrupted.");
|
||||
GSDump::isRunning = false;
|
||||
return;
|
||||
}
|
||||
|
||||
std::memcpy(&header, state_data.get(), sizeof(header));
|
||||
if (header.serial_size > 0)
|
||||
{
|
||||
if (header.serial_offset > ss || (static_cast<u64>(header.serial_offset) + header.serial_size) > ss)
|
||||
{
|
||||
Console.Error("GSDump header is corrupted.");
|
||||
GSDump::isRunning = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (header.serial_size > 0)
|
||||
serial.assign(reinterpret_cast<const char*>(state_data.get()) + header.serial_offset, header.serial_size);
|
||||
}
|
||||
|
||||
// Read the real state data
|
||||
ss = header.state_size;
|
||||
state_data = std::make_unique<u8[]>(ss);
|
||||
m_dump_file->Read(state_data.get(), ss);
|
||||
}
|
||||
|
||||
m_dump_file->Read(®s, 8192);
|
||||
|
||||
freezeData fd = {(int)ss, (u8*)state_data.get()};
|
||||
|
@ -956,7 +990,9 @@ void Dialogs::GSDumpDialog::GSThread::ExecuteTaskInThread()
|
|||
size = 8192;
|
||||
break;
|
||||
}
|
||||
std::unique_ptr<char[]> data(new char[size]);
|
||||
// make_unique would zero the data out, which is pointless since we're reading it anyway,
|
||||
// and this loop is executed a *ton* of times.
|
||||
std::unique_ptr<u8[]> data(new u8[size]);
|
||||
m_dump_file->Read(data.get(), size);
|
||||
m_root_window->m_dump_packets.push_back({id, std::move(data), size, id_transfer});
|
||||
}
|
||||
|
@ -974,7 +1010,17 @@ void Dialogs::GSDumpDialog::GSThread::ExecuteTaskInThread()
|
|||
g_FrameCount = 0;
|
||||
}
|
||||
|
||||
if (!GSopen(g_Conf->EmuOptions.GS, renderer, (u8*)regs))
|
||||
Pcsx2Config::GSOptions config(g_Conf->EmuOptions.GS);
|
||||
if (!serial.empty())
|
||||
{
|
||||
if (const GameDatabaseSchema::GameEntry* entry = GameDatabase::findGame(serial); entry)
|
||||
{
|
||||
// apply hardware fixes to config before opening (e.g. tex in rt)
|
||||
entry->applyGSHardwareFixes(config);
|
||||
}
|
||||
}
|
||||
|
||||
if (!GSopen(config, renderer, regs))
|
||||
{
|
||||
OnStop();
|
||||
return;
|
||||
|
|
|
@ -239,7 +239,7 @@ namespace Dialogs
|
|||
struct GSData
|
||||
{
|
||||
GSType id;
|
||||
std::unique_ptr<char[]> data;
|
||||
std::unique_ptr<u8[]> data;
|
||||
int length;
|
||||
GSTransferPath path;
|
||||
};
|
||||
|
@ -260,11 +260,11 @@ namespace Dialogs
|
|||
std::vector<wxTreeItemId> m_gif_items;
|
||||
|
||||
float m_stored_q = 1.0;
|
||||
void ProcessDumpEvent(const GSData& event, char* regs);
|
||||
void ProcessDumpEvent(const GSData& event, u8* regs);
|
||||
u32 ReadPacketSize(const void* packet);
|
||||
void GenPacketList();
|
||||
void GenPacketInfo(GSData& dump);
|
||||
void ParseTransfer(wxTreeItemId& id, char* data);
|
||||
void ParseTransfer(wxTreeItemId& id, u8* data);
|
||||
void ParseTreeReg(wxTreeItemId& id, GIFReg reg, u128 data, bool packed);
|
||||
void ParseTreePrim(wxTreeItemId& id, u32 prim);
|
||||
void CloseDump(wxCommandEvent& event);
|
||||
|
|
Loading…
Reference in New Issue