From 2d6ec7457dc4540ab539c585d004dedb676bf455 Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Sat, 6 Feb 2021 21:14:21 -0800 Subject: [PATCH] Add names and descriptions for XF registers to the FIFO analyzer --- Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp | 15 ++ Source/Core/VideoCommon/XFMemory.h | 69 ++++++ Source/Core/VideoCommon/XFStructs.cpp | 242 ++++++++++++++++++++ Source/Core/VideoCommon/XFStructs.h | 6 + 4 files changed, 332 insertions(+) diff --git a/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp b/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp index 4db865b069..8764e30b19 100644 --- a/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp +++ b/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp @@ -25,6 +25,7 @@ #include "VideoCommon/BPMemory.h" #include "VideoCommon/CPMemory.h" #include "VideoCommon/OpcodeDecoding.h" +#include "VideoCommon/XFStructs.h" constexpr int FRAME_ROLE = Qt::UserRole; constexpr int OBJECT_ROLE = Qt::UserRole + 1; @@ -237,8 +238,10 @@ void FIFOAnalyzer::UpdateDetails() case OpcodeDecoder::GX_LOAD_XF_REG: { + const auto [name, desc] = GetXFTransferInfo(objectdata); u32 cmd2 = Common::swap32(objectdata); objectdata += 4; + ASSERT(!name.empty()); u8 streamSize = ((cmd2 >> 16) & 15) + 1; @@ -253,6 +256,8 @@ void FIFOAnalyzer::UpdateDetails() if (((objectdata - stream_start) % 4) == 0) new_label += QLatin1Char(' '); } + + new_label += QStringLiteral(" ") + QString::fromStdString(name); } break; @@ -505,7 +510,17 @@ void FIFOAnalyzer::UpdateDescription() } else if (*cmddata == OpcodeDecoder::GX_LOAD_XF_REG) { + const auto [name, desc] = GetXFTransferInfo(cmddata + 1); + ASSERT(!name.empty()); + text = tr("XF register "); + text += QString::fromStdString(name); + text += QLatin1Char{'\n'}; + + if (desc.empty()) + text += tr("No description available"); + else + text += QString::fromStdString(desc); } else { diff --git a/Source/Core/VideoCommon/XFMemory.h b/Source/Core/VideoCommon/XFMemory.h index 8dc94937f1..7efd3d2209 100644 --- a/Source/Core/VideoCommon/XFMemory.h +++ b/Source/Core/VideoCommon/XFMemory.h @@ -192,6 +192,7 @@ enum XFMEM_POSTMATRICES_END = 0x600, XFMEM_LIGHTS = 0x600, XFMEM_LIGHTS_END = 0x680, + XFMEM_REGISTERS_START = 0x1000, XFMEM_ERROR = 0x1000, XFMEM_DIAG = 0x1001, XFMEM_STATE0 = 0x1002, @@ -226,6 +227,7 @@ enum XFMEM_SETNUMTEXGENS = 0x103f, XFMEM_SETTEXMTXINFO = 0x1040, XFMEM_SETPOSTMTXINFO = 0x1050, + XFMEM_REGISTERS_END = 0x1058, }; union LitChannel @@ -244,6 +246,20 @@ union LitChannel return enablelighting ? (lightMask0_3 | (lightMask4_7 << 4)) : 0; } }; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const LitChannel& chan, FormatContext& ctx) + { + return format_to(ctx.out(), + "Material source: {0}\nEnable lighting: {1}\nLight mask: {2:x} ({2:08b})\n" + "Ambient source: {3}\nDiffuse function: {4}\nAttenuation function: {5}", + chan.matsource, chan.enablelighting ? "Yes" : "No", chan.GetFullLightMask(), + chan.ambsource, chan.diffusefunc, chan.attnfunc); + } +}; union ClipDisable { @@ -252,6 +268,22 @@ union ClipDisable BitField<2, 1, bool, u32> disable_cpoly_clipping_acceleration; u32 hex; }; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const ClipDisable& cd, FormatContext& ctx) + { + return format_to(ctx.out(), + "Disable clipping detection: {}\n" + "Disable trivial rejection: {}\n" + "Disable cpoly clipping acceleration: {}", + cd.disable_clipping_detection ? "Yes" : "No", + cd.disable_trivial_rejection ? "Yes" : "No", + cd.disable_cpoly_clipping_acceleration ? "Yes" : "No"); + } +}; union INVTXSPEC { @@ -260,6 +292,17 @@ union INVTXSPEC BitField<4, 4, u32> numtextures; u32 hex; }; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const INVTXSPEC& spec, FormatContext& ctx) + { + return format_to(ctx.out(), "Num colors: {}\nNum normals: {}\nNum textures: {}", spec.numcolors, + spec.numnormals, spec.numtextures); + } +}; union TexMtxInfo { @@ -273,6 +316,20 @@ union TexMtxInfo BitField<15, 3, u32> embosslightshift; // light index that is used u32 hex; }; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const TexMtxInfo& i, FormatContext& ctx) + { + return format_to(ctx.out(), + "Projection: {}\nInput form: {}\nTex gen type: {}\n" + "Source row: {}\nEmboss source shift: {}\nEmboss light shift: {}", + i.projection, i.inputform, i.texgentype, i.sourcerow, i.embosssourceshift, + i.embosslightshift); + } +}; union PostMtxInfo { @@ -282,6 +339,18 @@ union PostMtxInfo u32 hex; }; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const PostMtxInfo& i, FormatContext& ctx) + { + return format_to(ctx.out(), "Index: {}\nNormalize before send operation: {}", i.index, + i.normalize ? "Yes" : "No"); + } +}; + union NumColorChannel { BitField<0, 2, u32> numColorChans; diff --git a/Source/Core/VideoCommon/XFStructs.cpp b/Source/Core/VideoCommon/XFStructs.cpp index 3d02ca19bf..0e9667c509 100644 --- a/Source/Core/VideoCommon/XFStructs.cpp +++ b/Source/Core/VideoCommon/XFStructs.cpp @@ -2,6 +2,9 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "VideoCommon/XFStructs.h" + +#include "Common/BitUtils.h" #include "Common/CommonTypes.h" #include "Common/Logging/Log.h" #include "Common/Swap.h" @@ -300,3 +303,242 @@ void PreprocessIndexedXF(u32 val, int refarray) const size_t buf_size = size * sizeof(u32); Fifo::PushFifoAuxBuffer(new_data, buf_size); } + +std::pair GetXFRegInfo(u32 address, u32 value) +{ +// Macro to set the register name and make sure it was written correctly via compile time assertion +#define RegName(reg) ((void)(reg), #reg) +#define DescriptionlessReg(reg) std::make_pair(RegName(reg), ""); + + switch (address) + { + case XFMEM_ERROR: + return DescriptionlessReg(XFMEM_ERROR); + case XFMEM_DIAG: + return DescriptionlessReg(XFMEM_DIAG); + case XFMEM_STATE0: // internal state 0 + return std::make_pair(RegName(XFMEM_STATE0), "internal state 0"); + case XFMEM_STATE1: // internal state 1 + return std::make_pair(RegName(XFMEM_STATE1), "internal state 1"); + case XFMEM_CLOCK: + return DescriptionlessReg(XFMEM_CLOCK); + case XFMEM_SETGPMETRIC: + return DescriptionlessReg(XFMEM_SETGPMETRIC); + + case XFMEM_CLIPDISABLE: + return std::make_pair(RegName(XFMEM_CLIPDISABLE), fmt::to_string(ClipDisable{.hex = value})); + + case XFMEM_VTXSPECS: + return std::make_pair(RegName(XFMEM_VTXSPECS), fmt::to_string(INVTXSPEC{.hex = value})); + + case XFMEM_SETNUMCHAN: + return std::make_pair(RegName(XFMEM_SETNUMCHAN), + fmt::format("Number of color channels: {}", value & 3)); + break; + + case XFMEM_SETCHAN0_AMBCOLOR: + return std::make_pair(RegName(XFMEM_SETCHAN0_AMBCOLOR), + fmt::format("Channel 0 Ambient Color: {:06x}", value)); + case XFMEM_SETCHAN1_AMBCOLOR: + return std::make_pair(RegName(XFMEM_SETCHAN1_AMBCOLOR), + fmt::format("Channel 1 Ambient Color: {:06x}", value)); + + case XFMEM_SETCHAN0_MATCOLOR: + return std::make_pair(RegName(XFMEM_SETCHAN0_MATCOLOR), + fmt::format("Channel 0 Material Color: {:06x}", value)); + case XFMEM_SETCHAN1_MATCOLOR: + return std::make_pair(RegName(XFMEM_SETCHAN1_MATCOLOR), + fmt::format("Channel 1 Material Color: {:06x}", value)); + + case XFMEM_SETCHAN0_COLOR: // Channel Color + return std::make_pair(RegName(XFMEM_SETCHAN0_COLOR), + fmt::format("Channel 0 Color config:\n{}", LitChannel{.hex = value})); + case XFMEM_SETCHAN1_COLOR: + return std::make_pair(RegName(XFMEM_SETCHAN1_COLOR), + fmt::format("Channel 1 Color config:\n{}", LitChannel{.hex = value})); + case XFMEM_SETCHAN0_ALPHA: // Channel Alpha + return std::make_pair(RegName(XFMEM_SETCHAN0_ALPHA), + fmt::format("Channel 0 Alpha config:\n{}", LitChannel{.hex = value})); + case XFMEM_SETCHAN1_ALPHA: + return std::make_pair(RegName(XFMEM_SETCHAN1_ALPHA), + fmt::format("Channel 1 Alpha config:\n{}", LitChannel{.hex = value})); + + case XFMEM_DUALTEX: + return std::make_pair(RegName(XFMEM_DUALTEX), + fmt::format("Dual Tex Trans {}", (value & 1) ? "enabled" : "disabled")); + + case XFMEM_SETMATRIXINDA: + return std::make_pair(RegName(XFMEM_SETMATRIXINDA), + fmt::format("Matrix index A:\n{}", TMatrixIndexA{.Hex = value})); + case XFMEM_SETMATRIXINDB: + return std::make_pair(RegName(XFMEM_SETMATRIXINDB), + fmt::format("Matrix index B:\n{}", TMatrixIndexB{.Hex = value})); + + case XFMEM_SETVIEWPORT: + return std::make_pair(RegName(XFMEM_SETVIEWPORT + 0), + fmt::format("Viewport width: {}", Common::BitCast(value))); + case XFMEM_SETVIEWPORT + 1: + return std::make_pair(RegName(XFMEM_SETVIEWPORT + 1), + fmt::format("Viewport height: {}", Common::BitCast(value))); + case XFMEM_SETVIEWPORT + 2: + return std::make_pair(RegName(XFMEM_SETVIEWPORT + 2), + fmt::format("Viewport z range: {}", Common::BitCast(value))); + case XFMEM_SETVIEWPORT + 3: + return std::make_pair(RegName(XFMEM_SETVIEWPORT + 3), + fmt::format("Viewport x origin: {}", Common::BitCast(value))); + case XFMEM_SETVIEWPORT + 4: + return std::make_pair(RegName(XFMEM_SETVIEWPORT + 4), + fmt::format("Viewport y origin: {}", Common::BitCast(value))); + case XFMEM_SETVIEWPORT + 5: + return std::make_pair(RegName(XFMEM_SETVIEWPORT + 5), + fmt::format("Viewport far z: {}", Common::BitCast(value))); + break; + + case XFMEM_SETPROJECTION: + return std::make_pair(RegName(XFMEM_SETPROJECTION + 0), + fmt::format("Projection[0]: {}", Common::BitCast(value))); + case XFMEM_SETPROJECTION + 1: + return std::make_pair(RegName(XFMEM_SETPROJECTION + 1), + fmt::format("Projection[1]: {}", Common::BitCast(value))); + case XFMEM_SETPROJECTION + 2: + return std::make_pair(RegName(XFMEM_SETPROJECTION + 2), + fmt::format("Projection[2]: {}", Common::BitCast(value))); + case XFMEM_SETPROJECTION + 3: + return std::make_pair(RegName(XFMEM_SETPROJECTION + 3), + fmt::format("Projection[3]: {}", Common::BitCast(value))); + case XFMEM_SETPROJECTION + 4: + return std::make_pair(RegName(XFMEM_SETPROJECTION + 4), + fmt::format("Projection[4]: {}", Common::BitCast(value))); + case XFMEM_SETPROJECTION + 5: + return std::make_pair(RegName(XFMEM_SETPROJECTION + 5), + fmt::format("Projection[5]: {}", Common::BitCast(value))); + case XFMEM_SETPROJECTION + 6: + return std::make_pair(RegName(XFMEM_SETPROJECTION + 6), + fmt::to_string(static_cast(value))); + + case XFMEM_SETNUMTEXGENS: + return std::make_pair(RegName(XFMEM_SETNUMTEXGENS), + fmt::format("Number of tex gens: {}", value & 15)); + + case XFMEM_SETTEXMTXINFO: + case XFMEM_SETTEXMTXINFO + 1: + case XFMEM_SETTEXMTXINFO + 2: + case XFMEM_SETTEXMTXINFO + 3: + case XFMEM_SETTEXMTXINFO + 4: + case XFMEM_SETTEXMTXINFO + 5: + case XFMEM_SETTEXMTXINFO + 6: + case XFMEM_SETTEXMTXINFO + 7: + return std::make_pair( + fmt::format("XFMEM_SETTEXMTXINFO Matrix {}", address - XFMEM_SETTEXMTXINFO), + fmt::to_string(TexMtxInfo{.hex = value})); + + case XFMEM_SETPOSTMTXINFO: + case XFMEM_SETPOSTMTXINFO + 1: + case XFMEM_SETPOSTMTXINFO + 2: + case XFMEM_SETPOSTMTXINFO + 3: + case XFMEM_SETPOSTMTXINFO + 4: + case XFMEM_SETPOSTMTXINFO + 5: + case XFMEM_SETPOSTMTXINFO + 6: + case XFMEM_SETPOSTMTXINFO + 7: + return std::make_pair( + fmt::format("XFMEM_SETPOSTMTXINFO Matrix {}", address - XFMEM_SETPOSTMTXINFO), + fmt::to_string(PostMtxInfo{.hex = value})); + + // -------------- + // Unknown Regs + // -------------- + + // Maybe these are for Normals? + case 0x1048: // xfmem.texcoords[0].nrmmtxinfo.hex = data; break; ?? + case 0x1049: + case 0x104a: + case 0x104b: + case 0x104c: + case 0x104d: + case 0x104e: + case 0x104f: + return std::make_pair( + fmt::format("Possible Normal Mtx XF reg?: {:x}={:x}", address, value), + "Maybe these are for Normals? xfmem.texcoords[0].nrmmtxinfo.hex = data; break; ??"); + break; + + case 0x1013: + case 0x1014: + case 0x1015: + case 0x1016: + case 0x1017: + + default: + return std::make_pair(fmt::format("Unknown XF Reg: {:x}={:x}", address, value), ""); + } +#undef RegName +#undef DescriptionlessReg +} + +std::pair GetXFTransferInfo(const u8* data) +{ + const u32 cmd = Common::swap32(data); + data += 4; + u32 base_address = cmd & 0xFFFF; + const u32 transfer_size = ((cmd >> 16) & 15) + 1; + + if (base_address > XFMEM_REGISTERS_END) + { + return std::make_pair("Invalid XF Transfer", "Base address past end of address space"); + } + else if (transfer_size == 1 && base_address >= XFMEM_REGISTERS_START) + { + // Write directly to a single register + const u32 value = Common::swap32(data); + return GetXFRegInfo(base_address, value); + } + + // More complicated cases + fmt::memory_buffer name, desc; + u32 end_address = base_address + transfer_size; // exclusive + + // do not allow writes past registers + if (end_address > XFMEM_REGISTERS_END) + { + fmt::format_to(name, "Invalid XF Transfer "); + fmt::format_to(desc, "Transfer ends past end of address space\n\n"); + end_address = XFMEM_REGISTERS_END; + } + + // write to XF mem + if (base_address < XFMEM_REGISTERS_START) + { + const u32 xf_mem_base = base_address; + u32 xf_mem_transfer_size = transfer_size; + + if (end_address > XFMEM_REGISTERS_START) + { + xf_mem_transfer_size = XFMEM_REGISTERS_START - base_address; + base_address = XFMEM_REGISTERS_START; + data += 4 * xf_mem_transfer_size; + } + + fmt::format_to(name, "Write {} XF mem words at {:04x}", xf_mem_transfer_size, xf_mem_base); + + if (end_address > XFMEM_REGISTERS_START) + fmt::format_to(name, "; "); + } + + // write to XF regs + if (base_address >= XFMEM_REGISTERS_START) + { + fmt::format_to(name, "Write {} XF regs at {:04x}", end_address - base_address, base_address); + + for (u32 address = base_address; address < end_address; address++) + { + const u32 value = Common::swap32(data); + + const auto [regname, regdesc] = GetXFRegInfo(address, value); + fmt::format_to(desc, "{}\n{}\n", regname, regdesc); + + data += 4; + } + } + + return std::make_pair(fmt::to_string(name), fmt::to_string(desc)); +} diff --git a/Source/Core/VideoCommon/XFStructs.h b/Source/Core/VideoCommon/XFStructs.h index d6f8d48d46..25b2e5fccc 100644 --- a/Source/Core/VideoCommon/XFStructs.h +++ b/Source/Core/VideoCommon/XFStructs.h @@ -4,4 +4,10 @@ #pragma once +#include +#include + #include "VideoCommon/XFMemory.h" + +std::pair GetXFRegInfo(u32 address, u32 value); +std::pair GetXFTransferInfo(const u8* data);