diff --git a/pcsx2/GS/GSLzma.cpp b/pcsx2/GS/GSLzma.cpp index 39842170de..bdb90c96bf 100644 --- a/pcsx2/GS/GSLzma.cpp +++ b/pcsx2/GS/GSLzma.cpp @@ -14,28 +14,18 @@ */ #include "PrecompiledHeader.h" + +#include "common/FileSystem.h" +#include "common/StringUtil.h" + +#include "GSDump.h" #include "GSLzma.h" -GSDumpFile::GSDumpFile(char* filename, const char* repack_filename) -{ - m_fp = fopen(filename, "rb"); - if (m_fp == nullptr) - { - fprintf(stderr, "failed to open %s\n", filename); - throw "BAD"; // Just exit the program - } - - m_repack_fp = nullptr; - if (repack_filename) - { - m_repack_fp = fopen(repack_filename, "wb"); - if (m_repack_fp == nullptr) - fprintf(stderr, "failed to open %s for repack\n", repack_filename); - } -} +using namespace GSDumpTypes; GSDumpFile::GSDumpFile(FILE* file, FILE* repack_file) - : m_repack_fp(repack_file), m_fp(file) + : m_repack_fp(repack_file) + , m_fp(file) { } @@ -57,13 +47,161 @@ GSDumpFile::~GSDumpFile() fclose(m_repack_fp); } -/******************************************************************/ -GSDumpLzma::GSDumpLzma(char* filename, const char* repack_filename) - : GSDumpFile(filename, repack_filename) +std::unique_ptr GSDumpFile::OpenGSDump(const char* filename, const char* repack_filename /*= nullptr*/) { - Initialize(); + std::FILE* fp = FileSystem::OpenCFile(filename, "rb"); + if (!fp) + return nullptr; + + std::FILE* repack_fp = nullptr; + if (repack_filename && std::strlen(repack_filename) > 0) + { + repack_fp = FileSystem::OpenCFile(repack_filename, "wb"); + if (!repack_fp) + { + std::fclose(fp); + return nullptr; + } + } + + if (StringUtil::EndsWithNoCase(filename, ".xz")) + return std::make_unique(fp, nullptr); + else + return std::make_unique(fp, nullptr); } +bool GSDumpFile::GetPreviewImageFromDump(const char* filename, u32* width, u32* height, std::vector* pixels) +{ + std::unique_ptr dump = OpenGSDump(filename); + if (!dump) + return false; + + u32 crc; + if (!dump->Read(&crc, sizeof(crc)) || crc != 0xFFFFFFFFu) + { + // not new header dump, so no preview + return false; + } + + u32 header_size; + if (!dump->Read(&header_size, sizeof(header_size)) || header_size < sizeof(GSDumpHeader)) + { + // doesn't have the screenshot fields + return false; + } + + std::unique_ptr header_bits = std::make_unique(header_size); + if (!dump->Read(header_bits.get(), header_size)) + return false; + + GSDumpHeader header; + std::memcpy(&header, header_bits.get(), sizeof(header)); + if (header.screenshot_size == 0 || + header.screenshot_size < (header.screenshot_width * header.screenshot_height * sizeof(u32)) || + (static_cast(header.screenshot_offset) + header.screenshot_size) > header_size) + { + // doesn't have a screenshot + return false; + } + + *width = header.screenshot_width; + *height = header.screenshot_height; + pixels->resize(header.screenshot_width * header.screenshot_height); + std::memcpy(pixels->data(), header_bits.get() + header.screenshot_offset, header.screenshot_size); + return true; +} + +bool GSDumpFile::ReadFile() +{ + u32 ss; + if (!Read(&m_crc, 4) || !Read(&ss, 4)) + return false; + + m_state_data.resize(ss); + if (!Read(m_state_data.data(), ss)) + return false; + + // Pull serial out of new header, if present. + if (m_crc == 0xFFFFFFFFu) + { + GSDumpHeader header; + if (m_state_data.size() < sizeof(header)) + { + Console.Error("GSDump header is corrupted."); + return false; + } + + std::memcpy(&header, m_state_data.data(), sizeof(header)); + + m_crc = header.crc; + + if (header.serial_size > 0) + { + if (header.serial_offset > ss || (static_cast(header.serial_offset) + header.serial_size) > ss) + { + Console.Error("GSDump header is corrupted."); + return false; + } + + if (header.serial_size > 0) + m_serial.assign(reinterpret_cast(m_state_data.data()) + header.serial_offset, header.serial_size); + } + + // Read the real state data + m_state_data.resize(header.state_size); + if (!Read(m_state_data.data(), header.state_size)) + return false; + } + + m_regs_data.resize(8192); + if (!Read(m_regs_data.data(), m_regs_data.size())) + return false; + + for (;;) + { + GSData packet; + packet.path = GSTransferPath::Dummy; + if (!Read(&packet.id, 1)) + { + if (IsEof()) + break; + + return false; + } + + switch (packet.id) + { + case GSType::Transfer: + { + if (!Read(&packet.path, 1) || !Read(&packet.length, 4)) + return false; + } + break; + case GSType::VSync: + packet.length = 1; + break; + case GSType::ReadFIFO2: + packet.length = 4; + break; + case GSType::Registers: + packet.length = 8192; + break; + } + + if (packet.length > 0) + { + packet.data = std::unique_ptr(new u8[packet.length]); + if (!Read(packet.data.get(), packet.length)) + return false; + } + + m_dump_packets.push_back(std::move(packet)); + } + + return true; +} + +/******************************************************************/ GSDumpLzma::GSDumpLzma(FILE* file, FILE* repack_file) : GSDumpFile(file, repack_file) { @@ -178,11 +316,6 @@ GSDumpLzma::~GSDumpLzma() /******************************************************************/ -GSDumpRaw::GSDumpRaw(char* filename, const char* repack_filename) - : GSDumpFile(filename, repack_filename) -{ -} - GSDumpRaw::GSDumpRaw(FILE* file, FILE* repack_file) : GSDumpFile(file, repack_file) { @@ -199,7 +332,7 @@ bool GSDumpRaw::Read(void* ptr, size_t size) if (ret != size && ferror(m_fp)) { fprintf(stderr, "GSDumpRaw:: Read error (%zu/%zu)\n", ret, size); - throw "BAD"; // Just exit the program + return false; } if (ret == size) diff --git a/pcsx2/GS/GSLzma.h b/pcsx2/GS/GSLzma.h index 363999cfbd..bda8fdc404 100644 --- a/pcsx2/GS/GSLzma.h +++ b/pcsx2/GS/GSLzma.h @@ -13,24 +13,328 @@ * If not, see . */ +#pragma once + #include +#include +#include +#include + +#define GEN_REG_ENUM_CLASS_CONTENT(ClassName, EntryName, Value) \ + EntryName = Value, + +#define GEN_REG_GETNAME_CONTENT(ClassName, EntryName, Value) \ + case ClassName::EntryName: \ + return #EntryName; + +#define GEN_REG_ENUM_CLASS_AND_GETNAME(Macro, ClassName, Type, DefaultString) \ + enum class ClassName : Type \ + { \ + Macro(GEN_REG_ENUM_CLASS_CONTENT) \ + }; \ + static constexpr const char* GetName(ClassName reg) \ + { \ + switch (reg) \ + { \ + Macro(GEN_REG_GETNAME_CONTENT) default : return DefaultString; \ + } \ + } + +namespace GSDumpTypes +{ + // clang-format off +#define DEF_GSType(X) \ + X(GSType, Transfer, 0) \ + X(GSType, VSync, 1) \ + X(GSType, ReadFIFO2, 2) \ + X(GSType, Registers, 3) + GEN_REG_ENUM_CLASS_AND_GETNAME(DEF_GSType, GSType, u8, "UnknownType") +#undef DEF_GSType + +#define DEF_GSTransferPath(X) \ + X(GSTransferPath, Path1Old, 0) \ + X(GSTransferPath, Path2, 1) \ + X(GSTransferPath, Path3, 2) \ + X(GSTransferPath, Path1New, 3) \ + X(GSTransferPath, Dummy, 4) + GEN_REG_ENUM_CLASS_AND_GETNAME(DEF_GSTransferPath, GSTransferPath, u8, "UnknownPath") +#undef DEF_GSTransferPath + +#define DEF_GIFFlag(X) \ + X(GIFFlag, PACKED, 0) \ + X(GIFFlag, REGLIST, 1) \ + X(GIFFlag, IMAGE, 2) \ + X(GIFFlag, IMAGE2, 3) + GEN_REG_ENUM_CLASS_AND_GETNAME(DEF_GIFFlag, GIFFlag, u8, "UnknownFlag") +#undef DEF_GifFlag + +#define DEF_GIFReg(X) \ + X(GIFReg, PRIM, 0x00) \ + X(GIFReg, RGBAQ, 0x01) \ + X(GIFReg, ST, 0x02) \ + X(GIFReg, UV, 0x03) \ + X(GIFReg, XYZF2, 0x04) \ + X(GIFReg, XYZ2, 0x05) \ + X(GIFReg, TEX0_1, 0x06) \ + X(GIFReg, TEX0_2, 0x07) \ + X(GIFReg, CLAMP_1, 0x08) \ + X(GIFReg, CLAMP_2, 0x09) \ + X(GIFReg, FOG, 0x0a) \ + X(GIFReg, XYZF3, 0x0c) \ + X(GIFReg, XYZ3, 0x0d) \ + X(GIFReg, AD, 0x0e) \ + X(GIFReg, NOP, 0x0f) \ + X(GIFReg, TEX1_1, 0x14) \ + X(GIFReg, TEX1_2, 0x15) \ + X(GIFReg, TEX2_1, 0x16) \ + X(GIFReg, TEX2_2, 0x17) \ + X(GIFReg, XYOFFSET_1, 0x18) \ + X(GIFReg, XYOFFSET_2, 0x19) \ + X(GIFReg, PRMODECONT, 0x1a) \ + X(GIFReg, PRMODE, 0x1b) \ + X(GIFReg, TEXCLUT, 0x1c) \ + X(GIFReg, SCANMSK, 0x22) \ + X(GIFReg, MIPTBP1_1, 0x34) \ + X(GIFReg, MIPTBP1_2, 0x35) \ + X(GIFReg, MIPTBP2_1, 0x36) \ + X(GIFReg, MIPTBP2_2, 0x37) \ + X(GIFReg, TEXA, 0x3b) \ + X(GIFReg, FOGCOL, 0x3d) \ + X(GIFReg, TEXFLUSH, 0x3f) \ + X(GIFReg, SCISSOR_1, 0x40) \ + X(GIFReg, SCISSOR_2, 0x41) \ + X(GIFReg, ALPHA_1, 0x42) \ + X(GIFReg, ALPHA_2, 0x43) \ + X(GIFReg, DIMX, 0x44) \ + X(GIFReg, DTHE, 0x45) \ + X(GIFReg, COLCLAMP, 0x46) \ + X(GIFReg, TEST_1, 0x47) \ + X(GIFReg, TEST_2, 0x48) \ + X(GIFReg, PABE, 0x49) \ + X(GIFReg, FBA_1, 0x4a) \ + X(GIFReg, FBA_2, 0x4b) \ + X(GIFReg, FRAME_1, 0x4c) \ + X(GIFReg, FRAME_2, 0x4d) \ + X(GIFReg, ZBUF_1, 0x4e) \ + X(GIFReg, ZBUF_2, 0x4f) \ + X(GIFReg, BITBLTBUF, 0x50) \ + X(GIFReg, TRXPOS, 0x51) \ + X(GIFReg, TRXREG, 0x52) \ + X(GIFReg, TRXDIR, 0x53) \ + X(GIFReg, HWREG, 0x54) \ + X(GIFReg, SIGNAL, 0x60) \ + X(GIFReg, FINISH, 0x61) \ + X(GIFReg, LABEL, 0x62) + GEN_REG_ENUM_CLASS_AND_GETNAME(DEF_GIFReg, GIFReg, u8, "UnknownReg") +#undef DEF_GIFReg + // clang-format on + + template ::type = true> + static constexpr Output BitCast(Input input) + { + Output output; + memcpy(&output, &input, sizeof(input)); + return output; + } + template + static constexpr Output GetBits(u64 value, u32 shift, u32 numbits) + { + return static_cast((value >> shift) & ((1ull << numbits) - 1)); + } + + template + static constexpr Output GetBits(u128 value, u32 shift, u32 numbits) + { + u64 outval = 0; + if (shift == 0) + outval = value.lo; + else if (shift < 64) + outval = (value.lo >> shift) | (value.hi << (64 - shift)); + else + outval = value.hi >> (shift - 64); + return static_cast(outval & ((1ull << numbits) - 1)); + } + static constexpr const char* GetNameOneBit(u8 value, const char* zero, const char* one) + { + switch (value) + { + case 0: + return zero; + case 1: + return one; + default: + return "UNKNOWN"; + } + } + static constexpr const char* GetNameBool(bool value) + { + return value ? "True" : "False"; + } + + static constexpr const char* GetNamePRIMPRIM(u8 prim) + { + switch (prim) + { + case 0: + return "Point"; + case 1: + return "Line"; + case 2: + return "Line Strip"; + case 3: + return "Triangle"; + case 4: + return "Triangle Strip"; + case 5: + return "Triangle Fan"; + case 6: + return "Sprite"; + case 7: + return "Invalid"; + default: + return "UNKNOWN"; + } + } + static constexpr const char* GetNamePRIMIIP(u8 iip) + { + return GetNameOneBit(iip, "Flat Shading", "Gouraud Shading"); + } + static constexpr const char* GetNamePRIMFST(u8 fst) + { + return GetNameOneBit(fst, "STQ Value", "UV Value"); + } + static constexpr const char* GetNamePRIMCTXT(u8 ctxt) + { + return GetNameOneBit(ctxt, "Context 1", "Context 2"); + } + static constexpr const char* GetNamePRIMFIX(u8 fix) + { + return GetNameOneBit(fix, "Unfixed", "Fixed"); + } + static constexpr const char* GetNameTEXTCC(u8 tcc) + { + return GetNameOneBit(tcc, "RGB", "RGBA"); + } + static constexpr const char* GetNameTEXTFX(u8 tfx) + { + switch (tfx) + { + case 0: + return "Modulate"; + case 1: + return "Decal"; + case 2: + return "Highlight"; + case 3: + return "Highlight2"; + default: + return "UNKNOWN"; + } + } + static constexpr const char* GetNameTEXCSM(u8 csm) + { + return GetNameOneBit(csm, "CSM1", "CSM2"); + } + static constexpr const char* GetNameTEXPSM(u8 psm) + { + switch (psm) + { + case 000: + return "PSMCT32"; + case 001: + return "PSMCT24"; + case 002: + return "PSMCT16"; + case 012: + return "PSMCT16S"; + case 023: + return "PSMT8"; + case 024: + return "PSMT4"; + case 033: + return "PSMT8H"; + case 044: + return "PSMT4HL"; + case 054: + return "PSMT4HH"; + case 060: + return "PSMZ32"; + case 061: + return "PSMZ24"; + case 062: + return "PSMZ16"; + case 072: + return "PSMZ16S"; + default: + return "UNKNOWN"; + } + } + static constexpr const char* GetNameTEXCPSM(u8 psm) + { + switch (psm) + { + case 000: + return "PSMCT32"; + case 002: + return "PSMCT16"; + case 012: + return "PSMCT16S"; + default: + return "UNKNOWN"; + } + } +} // namespace GSDumpTypes class GSDumpFile { - FILE* m_repack_fp; +public: + struct GSData + { + GSDumpTypes::GSType id; + std::unique_ptr data; + s32 length; + GSDumpTypes::GSTransferPath path; + }; + + using ByteArray = std::vector; + using GSDataArray = std::vector; + + virtual ~GSDumpFile(); + + static std::unique_ptr OpenGSDump(const char* filename, const char* repack_filename = nullptr); + static bool GetPreviewImageFromDump(const char* filename, u32* width, u32* height, std::vector* pixels); + + __fi const std::string& GetSerial() const { return m_serial; } + __fi u32 GetCRC() const { return m_crc; } + + __fi const ByteArray& GetRegsData() const { return m_regs_data; } + __fi const ByteArray& GetStateData() const { return m_state_data; } + __fi const GSDataArray& GetPackets() const { return m_dump_packets; } + + bool ReadFile(); protected: - FILE* m_fp; + GSDumpFile(FILE* file, FILE* repack_file); - void Repack(void* ptr, size_t size); - -public: virtual bool IsEof() = 0; virtual bool Read(void* ptr, size_t size) = 0; - GSDumpFile(char* filename, const char* repack_filename); - GSDumpFile(FILE* file, FILE* repack_file); - virtual ~GSDumpFile(); + void Repack(void* ptr, size_t size); + + FILE* m_fp = nullptr; + +private: + FILE* m_repack_fp = nullptr; + + std::string m_serial; + u32 m_crc = 0; + + std::vector m_regs_data; + std::vector m_state_data; + + // TODO: Allocate a single, large buffer, and store pointers to + // each packet instead of a buffer per packet. + GSDataArray m_dump_packets; }; class GSDumpLzma : public GSDumpFile @@ -48,7 +352,6 @@ class GSDumpLzma : public GSDumpFile void Initialize(); public: - GSDumpLzma(char* filename, const char* repack_filename); GSDumpLzma(FILE* file, FILE* repack_file); virtual ~GSDumpLzma(); @@ -59,7 +362,6 @@ public: class GSDumpRaw : public GSDumpFile { public: - GSDumpRaw(char* filename, const char* repack_filename); GSDumpRaw(FILE* file, FILE* repack_file); virtual ~GSDumpRaw() = default; diff --git a/pcsx2/gui/Dialogs/GSDumpDialog.cpp b/pcsx2/gui/Dialogs/GSDumpDialog.cpp index c273af457a..24a05bfc89 100644 --- a/pcsx2/gui/Dialogs/GSDumpDialog.cpp +++ b/pcsx2/gui/Dialogs/GSDumpDialog.cpp @@ -25,8 +25,6 @@ #include "common/FileSystem.h" #include "common/StringUtil.h" #include "gui/Resources/NoIcon.h" -#include "GS.h" -#include "GS/GSDump.h" #include "HostDisplay.h" #include "PathDefs.h" @@ -51,192 +49,13 @@ #include #include -template ::type = true> -static constexpr Output BitCast(Input input) -{ - Output output; - memcpy(&output, &input, sizeof(input)); - return output; -} -template -static constexpr Output GetBits(u64 value, u32 shift, u32 numbits) -{ - return static_cast((value >> shift) & ((1ull << numbits) - 1)); -} - -template -static constexpr Output GetBits(u128 value, u32 shift, u32 numbits) -{ - u64 outval = 0; - if (shift == 0) - outval = value.lo; - else if (shift < 64) - outval = (value.lo >> shift) | (value.hi << (64 - shift)); - else - outval = value.hi >> (shift - 64); - return static_cast(outval & ((1ull << numbits) - 1)); -} -static constexpr const char* GetNameOneBit(u8 value, const char* zero, const char* one) -{ - switch (value) - { - case 0: return zero; - case 1: return one; - default: return "UNKNOWN"; - } -} -static constexpr const char* GetNameBool(bool value) -{ - return value ? "True" : "False"; -} - -static constexpr const char* GetNamePRIMPRIM(u8 prim) -{ - switch (prim) - { - case 0: return "Point"; - case 1: return "Line"; - case 2: return "Line Strip"; - case 3: return "Triangle"; - case 4: return "Triangle Strip"; - case 5: return "Triangle Fan"; - case 6: return "Sprite"; - case 7: return "Invalid"; - default: return "UNKNOWN"; - } -} -static constexpr const char* GetNamePRIMIIP(u8 iip) -{ - return GetNameOneBit(iip, "Flat Shading", "Gouraud Shading"); -} -static constexpr const char* GetNamePRIMFST(u8 fst) -{ - return GetNameOneBit(fst, "STQ Value", "UV Value"); -} -static constexpr const char* GetNamePRIMCTXT(u8 ctxt) -{ - return GetNameOneBit(ctxt, "Context 1", "Context 2"); -} -static constexpr const char* GetNamePRIMFIX(u8 fix) -{ - return GetNameOneBit(fix, "Unfixed", "Fixed"); -} -static constexpr const char* GetNameTEXTCC(u8 tcc) -{ - return GetNameOneBit(tcc, "RGB", "RGBA"); -} -static constexpr const char* GetNameTEXTFX(u8 tfx) -{ - switch (tfx) - { - case 0: return "Modulate"; - case 1: return "Decal"; - case 2: return "Highlight"; - case 3: return "Highlight2"; - default: return "UNKNOWN"; - } -} -static constexpr const char* GetNameTEXCSM(u8 csm) -{ - return GetNameOneBit(csm, "CSM1", "CSM2"); -} -static constexpr const char* GetNameTEXPSM(u8 psm) -{ - switch (psm) - { - case 000: return "PSMCT32"; - case 001: return "PSMCT24"; - case 002: return "PSMCT16"; - case 012: return "PSMCT16S"; - case 023: return "PSMT8"; - case 024: return "PSMT4"; - case 033: return "PSMT8H"; - case 044: return "PSMT4HL"; - case 054: return "PSMT4HH"; - case 060: return "PSMZ32"; - case 061: return "PSMZ24"; - case 062: return "PSMZ16"; - case 072: return "PSMZ16S"; - default: return "UNKNOWN"; - } -} -static constexpr const char* GetNameTEXCPSM(u8 psm) -{ - switch (psm) - { - case 000: return "PSMCT32"; - case 002: return "PSMCT16"; - case 012: return "PSMCT16S"; - default: return "UNKNOWN"; - } -} - -static std::unique_ptr GetDumpFile(const std::string& filename) -{ - std::FILE* fp = FileSystem::OpenCFile(filename.c_str(), "rb"); - if (!fp) - return nullptr; - - if (StringUtil::EndsWith(filename, ".xz")) - return std::make_unique(fp, nullptr); - else - return std::make_unique(fp, nullptr); -} - -static bool GetPreviewImageFromDump(const std::string& filename, u32* width, u32* height, std::vector* pixels) -{ - try - { - std::unique_ptr dump = GetDumpFile(filename); - if (!dump) - return false; - - u32 crc; - dump->Read(&crc, sizeof(crc)); - if (crc != 0xFFFFFFFFu) - { - // not new header dump, so no preview - return false; - } - - u32 header_size; - dump->Read(&header_size, sizeof(header_size)); - if (header_size < sizeof(GSDumpHeader)) - { - // doesn't have the screenshot fields - return false; - } - - std::unique_ptr header_bits = std::make_unique(header_size); - dump->Read(header_bits.get(), header_size); - - GSDumpHeader header; - std::memcpy(&header, header_bits.get(), sizeof(header)); - if (header.screenshot_size == 0 || - header.screenshot_size < (header.screenshot_width * header.screenshot_height * sizeof(u32)) || - (static_cast(header.screenshot_offset) + header.screenshot_size) > header_size) - { - // doesn't have a screenshot - return false; - } - - *width = header.screenshot_width; - *height = header.screenshot_height; - pixels->resize(header.screenshot_width * header.screenshot_height); - std::memcpy(pixels->data(), header_bits.get() + header.screenshot_offset, header.screenshot_size); - return true; - } - catch (...) - { - return false; - } -} +using namespace GSDumpTypes; static std::optional GetPreviewImageFromDump(const std::string& filename) { std::vector pixels; u32 width, height; - if (!GetPreviewImageFromDump(filename, &width, &height, &pixels)) + if (!GSDumpFile::GetPreviewImageFromDump(filename.c_str(), &width, &height, &pixels)) return std::nullopt; // strip alpha bytes because wx is dumb and stores on a separate plane @@ -471,7 +290,7 @@ void Dialogs::GSDumpDialog::RunDump(wxCommandEvent& event) if (!m_run->IsEnabled()) return; - m_thread->m_dump_file = GetDumpFile(StringUtil::wxStringToUTF8String(m_selected_dump)); + m_thread->m_dump_file = GSDumpFile::OpenGSDump(m_selected_dump.ToUTF8()); if (!m_thread->m_dump_file) { wxString s; @@ -583,11 +402,11 @@ void Dialogs::GSDumpDialog::GenPacketList() m_gif_items.clear(); wxTreeItemId mainrootId = m_gif_list->AddRoot("root"); wxTreeItemId rootId = m_gif_list->AppendItem(mainrootId, "0 - VSync"); - for (auto& element : m_dump_packets) + for (auto& element : m_thread->m_dump_file->GetPackets()) { wxString s, t; - element.id == GSType::Transfer ? t.Printf(" - %s", GetName(element.path)) : t.Printf(""); - s.Printf("%d - %s%s - %d byte", i, GetName(element.id), t, element.length); + element.id == GSType::Transfer ? t.Printf(" - %s", GSDumpTypes::GetName(element.path)) : t.Printf(""); + s.Printf("%d - %s%s - %d byte", i, GSDumpTypes::GetName(element.id), t, element.length); if (element.id == GSType::VSync) { m_gif_list->SetItemText(rootId, s); @@ -606,7 +425,7 @@ void Dialogs::GSDumpDialog::GenPacketList() m_gif_list->SelectItem(m_gif_items[0]); } -void Dialogs::GSDumpDialog::GenPacketInfo(GSData& dump) +void Dialogs::GSDumpDialog::GenPacketInfo(const GSDumpFile::GSData& dump) { m_gif_packet->DeleteAllItems(); wxTreeItemId rootId = m_gif_packet->AddRoot("root"); @@ -619,7 +438,7 @@ void Dialogs::GSDumpDialog::GenPacketInfo(GSData& dump) int idx = 0; while (remaining >= 16) { - wxTreeItemId trootId = m_gif_packet->AppendItem(rootId, wxString::Format("Transfer Path %s Packet %u", GetName(dump.path), idx)); + wxTreeItemId trootId = m_gif_packet->AppendItem(rootId, wxString::Format("Transfer Path %s Packet %u", GSDumpTypes::GetName(dump.path), idx)); ParseTransfer(trootId, data); m_gif_packet->Expand(trootId); u32 size = ReadPacketSize(data); @@ -667,7 +486,7 @@ void Dialogs::GSDumpDialog::ParseTransfer(wxTreeItemId& trootId, u8* data) m_gif_packet->AppendItem(trootId, wxString::Format("nloop = %u", nloop)); m_gif_packet->AppendItem(trootId, wxString::Format("eop = %u", eop)); - m_gif_packet->AppendItem(trootId, wxString::Format("flg = %s", GetName(flg))); + m_gif_packet->AppendItem(trootId, wxString::Format("flg = %s", GSDumpTypes::GetName(flg))); m_gif_packet->AppendItem(trootId, wxString::Format("pre = %u", pre)); if (pre) { @@ -719,12 +538,12 @@ void Dialogs::GSDumpDialog::ParseTransfer(wxTreeItemId& trootId, u8* data) void Dialogs::GSDumpDialog::ParsePacket(wxTreeEvent& event) { - GenPacketInfo(m_dump_packets[wxAtoi(m_gif_list->GetItemText(event.GetItem()).BeforeFirst('-'))]); + GenPacketInfo(m_thread->m_dump_file->GetPackets()[wxAtoi(m_gif_list->GetItemText(event.GetItem()).BeforeFirst('-'))]); } void Dialogs::GSDumpDialog::ParseTreeReg(wxTreeItemId& id, GIFReg reg, u128 data, bool packed) { - wxTreeItemId rootId = m_gif_packet->AppendItem(id, wxString(GetName(reg))); + wxTreeItemId rootId = m_gif_packet->AppendItem(id, wxString(GSDumpTypes::GetName(reg))); switch (reg) { case GIFReg::PRIM: @@ -752,7 +571,7 @@ void Dialogs::GSDumpDialog::ParseTreeReg(wxTreeItemId& id, GIFReg reg, u128 data q = BitCast(data._u32[1]); } - m_gif_packet->SetItemText(rootId, wxString::Format("%s - #%02x%02x%02x%02x, %g", GetName(reg), r, g, b, a, q)); + m_gif_packet->SetItemText(rootId, wxString::Format("%s - #%02x%02x%02x%02x, %g", GSDumpTypes::GetName(reg), r, g, b, a, q)); m_gif_packet->AppendItem(rootId, wxString::Format("R = %u", r)); m_gif_packet->AppendItem(rootId, wxString::Format("G = %u", g)); m_gif_packet->AppendItem(rootId, wxString::Format("B = %u", b)); @@ -770,11 +589,11 @@ void Dialogs::GSDumpDialog::ParseTreeReg(wxTreeItemId& id, GIFReg reg, u128 data { m_stored_q = BitCast(data._u32[2]); m_gif_packet->AppendItem(rootId, wxString::Format("Q = %g", m_stored_q)); - m_gif_packet->SetItemText(rootId, wxString::Format("%s - (%g, %g, %g)", GetName(reg), s, t, m_stored_q)); + m_gif_packet->SetItemText(rootId, wxString::Format("%s - (%g, %g, %g)", GSDumpTypes::GetName(reg), s, t, m_stored_q)); } else { - m_gif_packet->SetItemText(rootId, wxString::Format("%s - (%g, %g)", GetName(reg), s, t)); + m_gif_packet->SetItemText(rootId, wxString::Format("%s - (%g, %g)", GSDumpTypes::GetName(reg), s, t)); } break; } @@ -784,15 +603,15 @@ void Dialogs::GSDumpDialog::ParseTreeReg(wxTreeItemId& id, GIFReg reg, u128 data float v = static_cast(GetBits(data, packed ? 32 : 16, 14)) / 16.f; m_gif_packet->AppendItem(rootId, wxString::Format("U = %g", u)); m_gif_packet->AppendItem(rootId, wxString::Format("V = %g", v)); - m_gif_packet->SetItemText(rootId, wxString::Format("%s - (%g, %g)", GetName(reg), u, v)); + m_gif_packet->SetItemText(rootId, wxString::Format("%s - (%g, %g)", GSDumpTypes::GetName(reg), u, v)); break; } case GIFReg::XYZF2: case GIFReg::XYZF3: { - const char* name = GetName(reg); + const char* name = GSDumpTypes::GetName(reg); if (packed && (reg == GIFReg::XYZF2) && GetBits(data, 111, 1)) - name = GetName(GIFReg::XYZF3); + name = GSDumpTypes::GetName(GIFReg::XYZF3); float x, y; u32 z, f; @@ -822,9 +641,9 @@ void Dialogs::GSDumpDialog::ParseTreeReg(wxTreeItemId& id, GIFReg reg, u128 data case GIFReg::XYZ2: case GIFReg::XYZ3: { - const char* name = GetName(reg); + const char* name = GSDumpTypes::GetName(reg); if (packed && (reg == GIFReg::XYZ2) && GetBits(data, 111, 1)) - name = GetName(GIFReg::XYZ3); + name = GSDumpTypes::GetName(GIFReg::XYZ3); float x, y; u32 z; @@ -855,7 +674,7 @@ void Dialogs::GSDumpDialog::ParseTreeReg(wxTreeItemId& id, GIFReg reg, u128 data u32 tw = GetBits(data, 26, 4); u32 th = GetBits(data, 30, 4); - m_gif_packet->SetItemText(rootId, wxString::Format("%s - %ux%u %s", GetName(reg), 1 << tw, 1 << th, GetNameTEXPSM(psm))); + m_gif_packet->SetItemText(rootId, wxString::Format("%s - %ux%u %s", GSDumpTypes::GetName(reg), 1 << tw, 1 << th, GetNameTEXPSM(psm))); m_gif_packet->AppendItem(rootId, wxString::Format("TBP0 = %u", GetBits(data, 0, 14))); m_gif_packet->AppendItem(rootId, wxString::Format("TBW = %u", GetBits(data, 14, 6))); m_gif_packet->AppendItem(rootId, wxString::Format("PSM = %s", GetNameTEXPSM(psm))); @@ -874,7 +693,7 @@ void Dialogs::GSDumpDialog::ParseTreeReg(wxTreeItemId& id, GIFReg reg, u128 data { u32 f = GetBits(data, packed ? 100 : 56, 8); m_gif_packet->AppendItem(rootId, wxString::Format("F = %u", f)); - m_gif_packet->SetItemText(rootId, wxString::Format("%s - %u", GetName(reg), f)); + m_gif_packet->SetItemText(rootId, wxString::Format("%s - %u", GSDumpTypes::GetName(reg), f)); break; } case GIFReg::AD: @@ -915,7 +734,7 @@ void Dialogs::GSDumpDialog::ParseTreePrim(wxTreeItemId& id, u32 prim) m_gif_packet->Expand(id); } -void Dialogs::GSDumpDialog::ProcessDumpEvent(const GSData& event, u8* regs) +void Dialogs::GSDumpDialog::ProcessDumpEvent(const GSDumpFile::GSData& event, u8* regs) { switch (event.id) { @@ -993,8 +812,12 @@ void Dialogs::GSDumpDialog::GSThread::OnStop() void Dialogs::GSDumpDialog::GSThread::ExecuteTaskInThread() { - GSDump::isRunning = true; - u32 crc = 0, ss = 0; + if (!m_dump_file->ReadFile()) + { + OnStop(); + return; + } + GSRendererType renderer = g_Conf->EmuOptions.GS.Renderer; switch (m_renderer) { @@ -1021,79 +844,6 @@ void Dialogs::GSDumpDialog::GSThread::ExecuteTaskInThread() default: break; } - u8 regs[8192]; - - m_dump_file->Read(&crc, 4); - m_dump_file->Read(&ss, 4); - - std::unique_ptr state_data = std::make_unique(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(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(state_data.get()) + header.serial_offset, header.serial_size); - } - - // Read the real state data - ss = header.state_size; - state_data = std::make_unique(ss); - m_dump_file->Read(state_data.get(), ss); - } - - m_dump_file->Read(®s, 8192); - - freezeData fd = {(int)ss, (u8*)state_data.get()}; - m_root_window->m_dump_packets.clear(); - - while (!m_dump_file->IsEof()) - { - GSType id; - GSTransferPath id_transfer = GSTransferPath::Dummy; - m_dump_file->Read(&id, 1); - s32 size = 0; - switch (id) - { - case GSType::Transfer: - m_dump_file->Read(&id_transfer, 1); - m_dump_file->Read(&size, 4); - break; - case GSType::VSync: - size = 1; - break; - case GSType::ReadFIFO2: - size = 4; - break; - case GSType::Registers: - size = 8192; - break; - } - // 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 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}); - } GSinit(); sApp.OpenGsPanel(); @@ -1109,25 +859,35 @@ void Dialogs::GSDumpDialog::GSThread::ExecuteTaskInThread() } Pcsx2Config::GSOptions config(g_Conf->EmuOptions.GS); - if (!serial.empty()) + if (!m_dump_file->GetSerial().empty()) { - if (const GameDatabaseSchema::GameEntry* entry = GameDatabase::findGame(serial); entry) + if (const GameDatabaseSchema::GameEntry* entry = GameDatabase::findGame(m_dump_file->GetSerial()); entry) { // apply hardware fixes to config before opening (e.g. tex in rt) entry->applyGSHardwareFixes(config); } } + u8 regs[8192] = {}; + if (!m_dump_file->GetRegsData().empty()) + std::memcpy(regs, m_dump_file->GetRegsData().data(), std::min(m_dump_file->GetRegsData().size(), sizeof(regs))); + if (!GSopen(config, renderer, regs)) { OnStop(); return; } - GSsetGameCRC((int)crc, 0); + GSsetGameCRC((int)m_dump_file->GetCRC(), 0); + freezeData fd = {static_cast(m_dump_file->GetStateData().size()), + const_cast(m_dump_file->GetStateData().data())}; if (GSfreeze(FreezeAction::Load, &fd)) - GSDump::isRunning = false; + { + OnStop(); + return; + } + GSvsync(1, false); GSreset(); GSfreeze(FreezeAction::Load, &fd); @@ -1136,6 +896,7 @@ void Dialogs::GSDumpDialog::GSThread::ExecuteTaskInThread() m_debug_index = 0; size_t debug_idx = 0; + GSDump::isRunning = true; while (GSDump::isRunning) { if (m_debug) @@ -1145,7 +906,7 @@ void Dialogs::GSDumpDialog::GSThread::ExecuteTaskInThread() switch (m_root_window->m_button_events[0].btn) { case Step: - if (debug_idx >= m_root_window->m_dump_packets.size()) + if (debug_idx >= m_dump_file->GetPackets().size()) debug_idx = 0; m_debug_index = debug_idx; break; @@ -1155,13 +916,13 @@ void Dialogs::GSDumpDialog::GSThread::ExecuteTaskInThread() debug_idx = 0; break; case RunVSync: - if (debug_idx >= m_root_window->m_dump_packets.size()) + if (debug_idx >= m_dump_file->GetPackets().size()) debug_idx = 1; - if ((debug_idx + 1) < m_root_window->m_dump_packets.size()) + if ((debug_idx + 1) < m_dump_file->GetPackets().size()) { - auto it = std::find_if(m_root_window->m_dump_packets.begin() + debug_idx + 1, m_root_window->m_dump_packets.end(), [](const GSData& gs) { return gs.id == GSType::Registers; }); - if (it != std::end(m_root_window->m_dump_packets)) - m_debug_index = std::distance(m_root_window->m_dump_packets.begin(), it); + auto it = std::find_if(m_dump_file->GetPackets().begin() + debug_idx + 1, m_dump_file->GetPackets().end(), [](const GSDumpFile::GSData& gs) { return gs.id == GSType::Registers; }); + if (it != std::end(m_dump_file->GetPackets())) + m_debug_index = std::distance(m_dump_file->GetPackets().begin(), it); } break; } @@ -1171,12 +932,12 @@ void Dialogs::GSDumpDialog::GSThread::ExecuteTaskInThread() { while (debug_idx <= m_debug_index) { - m_root_window->ProcessDumpEvent(m_root_window->m_dump_packets[debug_idx++], regs); + m_root_window->ProcessDumpEvent(m_dump_file->GetPackets()[debug_idx++], regs); } - if ((debug_idx + 1) < m_root_window->m_dump_packets.size()) + if ((debug_idx + 1) < m_dump_file->GetPackets().size()) { - auto it = std::find_if(m_root_window->m_dump_packets.begin() + debug_idx + 1, m_root_window->m_dump_packets.end(), [](const GSData& gs) { return gs.id == GSType::Registers; }); - if (it != std::end(m_root_window->m_dump_packets)) + auto it = std::find_if(m_dump_file->GetPackets().begin() + debug_idx + 1, m_dump_file->GetPackets().end(), [](const GSDumpFile::GSData& gs) { return gs.id == GSType::Registers; }); + if (it != std::end(m_dump_file->GetPackets())) m_root_window->ProcessDumpEvent(*it, regs); } } @@ -1185,11 +946,11 @@ void Dialogs::GSDumpDialog::GSThread::ExecuteTaskInThread() m_root_window->ProcessDumpEvent({GSType::VSync, 0, 0, GSTransferPath::Dummy}, regs); } } - else if (m_root_window->m_dump_packets.size()) + else if (m_dump_file->GetPackets().size()) { - while (i < m_root_window->m_dump_packets.size()) + while (i < m_dump_file->GetPackets().size()) { - GSData& packet = m_root_window->m_dump_packets[i++]; + const GSDumpFile::GSData& packet = m_dump_file->GetPackets()[i++]; m_root_window->ProcessDumpEvent(packet, regs); if (packet.id == GSType::VSync) { @@ -1209,7 +970,7 @@ void Dialogs::GSDumpDialog::GSThread::ExecuteTaskInThread() } } - if (i >= m_root_window->m_dump_packets.size()) + if (i >= m_dump_file->GetPackets().size()) i = 0; } if (window) diff --git a/pcsx2/gui/Dialogs/ModalPopups.h b/pcsx2/gui/Dialogs/ModalPopups.h index a0b4615812..9de2d99016 100644 --- a/pcsx2/gui/Dialogs/ModalPopups.h +++ b/pcsx2/gui/Dialogs/ModalPopups.h @@ -25,28 +25,6 @@ #include #include -#define GEN_REG_ENUM_CLASS_CONTENT(ClassName, EntryName, Value) \ - EntryName = Value, - -#define GEN_REG_GETNAME_CONTENT(ClassName, EntryName, Value) \ - case ClassName::EntryName: \ - return #EntryName; - -#define GEN_REG_ENUM_CLASS_AND_GETNAME(Macro, ClassName, Type, DefaultString) \ - enum class ClassName : Type \ - { \ - Macro(GEN_REG_ENUM_CLASS_CONTENT) \ - }; \ - static constexpr const char* GetName(ClassName reg) \ - { \ - switch (reg) \ - { \ - Macro(GEN_REG_GETNAME_CONTENT) \ - default: \ - return DefaultString; \ - } \ - } - class FirstTimeWizard : public wxWizard { typedef wxWizard _parent; @@ -147,102 +125,6 @@ namespace Dialogs ID_FRAMERATE, }; - // clang-format off - -#define DEF_GSType(X) \ - X(GSType, Transfer, 0) \ - X(GSType, VSync, 1) \ - X(GSType, ReadFIFO2, 2) \ - X(GSType, Registers, 3) - GEN_REG_ENUM_CLASS_AND_GETNAME(DEF_GSType, GSType, u8, "UnknownType") -#undef DEF_GSType - -#define DEF_GSTransferPath(X) \ - X(GSTransferPath, Path1Old, 0) \ - X(GSTransferPath, Path2, 1) \ - X(GSTransferPath, Path3, 2) \ - X(GSTransferPath, Path1New, 3) \ - X(GSTransferPath, Dummy, 4) - GEN_REG_ENUM_CLASS_AND_GETNAME(DEF_GSTransferPath, GSTransferPath, u8, "UnknownPath") -#undef DEF_GSTransferPath - -#define DEF_GIFFlag(X) \ - X(GIFFlag, PACKED, 0) \ - X(GIFFlag, REGLIST, 1) \ - X(GIFFlag, IMAGE, 2) \ - X(GIFFlag, IMAGE2, 3) - GEN_REG_ENUM_CLASS_AND_GETNAME(DEF_GIFFlag, GIFFlag, u8, "UnknownFlag") -#undef DEF_GifFlag - -#define DEF_GIFReg(X) \ - X(GIFReg, PRIM, 0x00) \ - X(GIFReg, RGBAQ, 0x01) \ - X(GIFReg, ST, 0x02) \ - X(GIFReg, UV, 0x03) \ - X(GIFReg, XYZF2, 0x04) \ - X(GIFReg, XYZ2, 0x05) \ - X(GIFReg, TEX0_1, 0x06) \ - X(GIFReg, TEX0_2, 0x07) \ - X(GIFReg, CLAMP_1, 0x08) \ - X(GIFReg, CLAMP_2, 0x09) \ - X(GIFReg, FOG, 0x0a) \ - X(GIFReg, XYZF3, 0x0c) \ - X(GIFReg, XYZ3, 0x0d) \ - X(GIFReg, AD, 0x0e) \ - X(GIFReg, NOP, 0x0f) \ - X(GIFReg, TEX1_1, 0x14) \ - X(GIFReg, TEX1_2, 0x15) \ - X(GIFReg, TEX2_1, 0x16) \ - X(GIFReg, TEX2_2, 0x17) \ - X(GIFReg, XYOFFSET_1, 0x18) \ - X(GIFReg, XYOFFSET_2, 0x19) \ - X(GIFReg, PRMODECONT, 0x1a) \ - X(GIFReg, PRMODE, 0x1b) \ - X(GIFReg, TEXCLUT, 0x1c) \ - X(GIFReg, SCANMSK, 0x22) \ - X(GIFReg, MIPTBP1_1, 0x34) \ - X(GIFReg, MIPTBP1_2, 0x35) \ - X(GIFReg, MIPTBP2_1, 0x36) \ - X(GIFReg, MIPTBP2_2, 0x37) \ - X(GIFReg, TEXA, 0x3b) \ - X(GIFReg, FOGCOL, 0x3d) \ - X(GIFReg, TEXFLUSH, 0x3f) \ - X(GIFReg, SCISSOR_1, 0x40) \ - X(GIFReg, SCISSOR_2, 0x41) \ - X(GIFReg, ALPHA_1, 0x42) \ - X(GIFReg, ALPHA_2, 0x43) \ - X(GIFReg, DIMX, 0x44) \ - X(GIFReg, DTHE, 0x45) \ - X(GIFReg, COLCLAMP, 0x46) \ - X(GIFReg, TEST_1, 0x47) \ - X(GIFReg, TEST_2, 0x48) \ - X(GIFReg, PABE, 0x49) \ - X(GIFReg, FBA_1, 0x4a) \ - X(GIFReg, FBA_2, 0x4b) \ - X(GIFReg, FRAME_1, 0x4c) \ - X(GIFReg, FRAME_2, 0x4d) \ - X(GIFReg, ZBUF_1, 0x4e) \ - X(GIFReg, ZBUF_2, 0x4f) \ - X(GIFReg, BITBLTBUF, 0x50) \ - X(GIFReg, TRXPOS, 0x51) \ - X(GIFReg, TRXREG, 0x52) \ - X(GIFReg, TRXDIR, 0x53) \ - X(GIFReg, HWREG, 0x54) \ - X(GIFReg, SIGNAL, 0x60) \ - X(GIFReg, FINISH, 0x61) \ - X(GIFReg, LABEL, 0x62) - GEN_REG_ENUM_CLASS_AND_GETNAME(DEF_GIFReg, GIFReg, u8, "UnknownReg") -#undef DEF_GIFReg - - // clang-format on - - struct GSData - { - GSType id; - std::unique_ptr data; - int length; - GSTransferPath path; - }; enum ButtonState { Step, @@ -256,16 +138,15 @@ namespace Dialogs int index; }; std::vector m_button_events; - std::vector m_dump_packets; std::vector m_gif_items; float m_stored_q = 1.0; - void ProcessDumpEvent(const GSData& event, u8* regs); + void ProcessDumpEvent(const GSDumpFile::GSData& event, u8* regs); u32 ReadPacketSize(const void* packet); void GenPacketList(); - void GenPacketInfo(GSData& dump); + void GenPacketInfo(const GSDumpFile::GSData& dump); void ParseTransfer(wxTreeItemId& id, u8* data); - void ParseTreeReg(wxTreeItemId& id, GIFReg reg, u128 data, bool packed); + void ParseTreeReg(wxTreeItemId& id, GSDumpTypes::GIFReg reg, u128 data, bool packed); void ParseTreePrim(wxTreeItemId& id, u32 prim); void CloseDump(wxCommandEvent& event); class GSThread : public pxThread