diff options
| author | JMC47 <JMC4789@gmail.com> | 2021-03-07 00:21:11 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-03-07 00:21:11 -0500 |
| commit | 089250fde65c2e225681c0ef6917d28fa187e8de (patch) | |
| tree | bcbb6db025c6003bd681e0028f0bc3b7b223bd07 /Source/Core/VideoCommon/XFStructs.cpp | |
| parent | 5f7d935b0a40f5cece7341927bd92b6a8d5debbe (diff) | |
| parent | df81210e96c6603d3aeb6c76f51b030d06cd06ac (diff) | |
Merge pull request #9497 from Pokechu22/better-fifo-analyzer
Graphics refactoring + add names and descriptions in FIFO analyzer
Diffstat (limited to 'Source/Core/VideoCommon/XFStructs.cpp')
| -rw-r--r-- | Source/Core/VideoCommon/XFStructs.cpp | 360 |
1 files changed, 350 insertions, 10 deletions
diff --git a/Source/Core/VideoCommon/XFStructs.cpp b/Source/Core/VideoCommon/XFStructs.cpp index 4fda86a8e0..741680b826 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" @@ -28,7 +31,7 @@ static void XFRegWritten(int transferSize, u32 baseAddress, DataReader src) u32 address = baseAddress; u32 dataIndex = 0; - while (transferSize > 0 && address < 0x1058) + while (transferSize > 0 && address < XFMEM_REGISTERS_END) { u32 newValue = src.Peek<u32>(dataIndex * sizeof(u32)); u32 nextAddress = address + 1; @@ -93,7 +96,7 @@ static void XFRegWritten(int transferSize, u32 baseAddress, DataReader src) break; case XFMEM_DUALTEX: - if (xfmem.dualTexTrans.enabled != (newValue & 1)) + if (xfmem.dualTexTrans.enabled != bool(newValue & 1)) g_vertex_manager->Flush(); VertexShaderManager::SetTexMatrixInfoChanged(-1); break; @@ -205,30 +208,30 @@ static void XFRegWritten(int transferSize, u32 baseAddress, DataReader src) void LoadXFReg(u32 transferSize, u32 baseAddress, DataReader src) { // do not allow writes past registers - if (baseAddress + transferSize > 0x1058) + if (baseAddress + transferSize > XFMEM_REGISTERS_END) { WARN_LOG_FMT(VIDEO, "XF load exceeds address space: {:x} {} bytes", baseAddress, transferSize); - if (baseAddress >= 0x1058) + if (baseAddress >= XFMEM_REGISTERS_END) transferSize = 0; else - transferSize = 0x1058 - baseAddress; + transferSize = XFMEM_REGISTERS_END - baseAddress; } // write to XF mem - if (baseAddress < 0x1000 && transferSize > 0) + if (baseAddress < XFMEM_REGISTERS_START && transferSize > 0) { u32 end = baseAddress + transferSize; u32 xfMemBase = baseAddress; u32 xfMemTransferSize = transferSize; - if (end >= 0x1000) + if (end >= XFMEM_REGISTERS_START) { - xfMemTransferSize = 0x1000 - baseAddress; + xfMemTransferSize = XFMEM_REGISTERS_START - baseAddress; - baseAddress = 0x1000; - transferSize = end - 0x1000; + baseAddress = XFMEM_REGISTERS_START; + transferSize = end - XFMEM_REGISTERS_START; } else { @@ -300,3 +303,340 @@ void PreprocessIndexedXF(u32 val, int refarray) const size_t buf_size = size * sizeof(u32); Fifo::PushFifoAuxBuffer(new_data, buf_size); } + +std::pair<std::string, std::string> 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<float>(value))); + case XFMEM_SETVIEWPORT + 1: + return std::make_pair(RegName(XFMEM_SETVIEWPORT + 1), + fmt::format("Viewport height: {}", Common::BitCast<float>(value))); + case XFMEM_SETVIEWPORT + 2: + return std::make_pair(RegName(XFMEM_SETVIEWPORT + 2), + fmt::format("Viewport z range: {}", Common::BitCast<float>(value))); + case XFMEM_SETVIEWPORT + 3: + return std::make_pair(RegName(XFMEM_SETVIEWPORT + 3), + fmt::format("Viewport x origin: {}", Common::BitCast<float>(value))); + case XFMEM_SETVIEWPORT + 4: + return std::make_pair(RegName(XFMEM_SETVIEWPORT + 4), + fmt::format("Viewport y origin: {}", Common::BitCast<float>(value))); + case XFMEM_SETVIEWPORT + 5: + return std::make_pair(RegName(XFMEM_SETVIEWPORT + 5), + fmt::format("Viewport far z: {}", Common::BitCast<float>(value))); + break; + + case XFMEM_SETPROJECTION: + return std::make_pair(RegName(XFMEM_SETPROJECTION + 0), + fmt::format("Projection[0]: {}", Common::BitCast<float>(value))); + case XFMEM_SETPROJECTION + 1: + return std::make_pair(RegName(XFMEM_SETPROJECTION + 1), + fmt::format("Projection[1]: {}", Common::BitCast<float>(value))); + case XFMEM_SETPROJECTION + 2: + return std::make_pair(RegName(XFMEM_SETPROJECTION + 2), + fmt::format("Projection[2]: {}", Common::BitCast<float>(value))); + case XFMEM_SETPROJECTION + 3: + return std::make_pair(RegName(XFMEM_SETPROJECTION + 3), + fmt::format("Projection[3]: {}", Common::BitCast<float>(value))); + case XFMEM_SETPROJECTION + 4: + return std::make_pair(RegName(XFMEM_SETPROJECTION + 4), + fmt::format("Projection[4]: {}", Common::BitCast<float>(value))); + case XFMEM_SETPROJECTION + 5: + return std::make_pair(RegName(XFMEM_SETPROJECTION + 5), + fmt::format("Projection[5]: {}", Common::BitCast<float>(value))); + case XFMEM_SETPROJECTION + 6: + return std::make_pair(RegName(XFMEM_SETPROJECTION + 6), + fmt::to_string(static_cast<ProjectionType>(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::string GetXFMemName(u32 address) +{ + if (address >= XFMEM_POSMATRICES && address < XFMEM_POSMATRICES_END) + { + const u32 row = (address - XFMEM_POSMATRICES) / 4; + const u32 col = (address - XFMEM_POSMATRICES) % 4; + return fmt::format("Position matrix row {:2d} col {:2d}", row, col); + } + else if (address >= XFMEM_NORMALMATRICES && address < XFMEM_NORMALMATRICES_END) + { + const u32 row = (address - XFMEM_NORMALMATRICES) / 3; + const u32 col = (address - XFMEM_NORMALMATRICES) % 3; + return fmt::format("Normal matrix row {:2d} col {:2d}", row, col); + } + else if (address >= XFMEM_POSTMATRICES && address < XFMEM_POSTMATRICES_END) + { + const u32 row = (address - XFMEM_POSMATRICES) / 4; + const u32 col = (address - XFMEM_POSMATRICES) % 4; + return fmt::format("Post matrix row {:2d} col {:2d}", row, col); + } + else if (address >= XFMEM_LIGHTS && address < XFMEM_LIGHTS_END) + { + const u32 light = (address - XFMEM_LIGHTS) / 16; + const u32 offset = (address - XFMEM_LIGHTS) % 16; + switch (offset) + { + default: + return fmt::format("Light {} unused param {}", light, offset); + case 3: + return fmt::format("Light {} color", light); + case 4: + case 5: + case 6: + return fmt::format("Light {} cosine attenuation {}", light, offset - 4); + case 7: + case 8: + case 9: + return fmt::format("Light {} distance attenuation {}", light, offset - 7); + case 10: + case 11: + case 12: + // Yagcd says light pos or "inf ldir", while dolphin has a union for dpos and sdir with only + // dpos being used nowadays. As far as I can tell only the DX9 engine once at + // Source/Plugins/Plugin_VideoDX9/Src/TransformEngine.cpp used sdir directly... + return fmt::format("Light {0} {1} position or inf ldir {1}", light, "xyz"[offset - 10]); + case 13: + case 14: + case 15: + // Yagcd says light dir or "1/2 angle", dolphin has union for ddir or shalfangle. + // It would make sense if d stood for direction and s for specular, but it's ddir and + // shalfhangle that have the comment "specular lights only", both at the same offset, + // while dpos and sdir have none... + return fmt::format("Light {0} {1} direction or half hangle {1}", light, "xyz"[offset - 13]); + } + } + else + { + return fmt::format("Unknown memory {:04x}", address); + } +} + +std::string GetXFMemDescription(u32 address, u32 value) +{ + if ((address >= XFMEM_POSMATRICES && address < XFMEM_POSMATRICES_END) || + (address >= XFMEM_NORMALMATRICES && address < XFMEM_NORMALMATRICES_END) || + (address >= XFMEM_POSTMATRICES && address < XFMEM_POSTMATRICES_END)) + { + // The matrices all use floats + return fmt::format("{} = {}", GetXFMemName(address), Common::BitCast<float>(value)); + } + else if (address >= XFMEM_LIGHTS && address < XFMEM_LIGHTS_END) + { + // Each light is 16 words; for this function we don't care which light it is + const u32 offset = (address - XFMEM_LIGHTS) % 16; + if (offset <= 3) + { + // The unused parameters (0, 1, 2) and the color (3) should be hex-formatted + return fmt::format("{} = {:08x}", GetXFMemName(address), value); + } + else + { + // Everything else is a float + return fmt::format("{} = {}", GetXFMemName(address), Common::BitCast<float>(value)); + } + } + else + { + // Unknown address + return fmt::format("{} = {:08x}", GetXFMemName(address), value); + } +} + +std::pair<std::string, std::string> 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; + } + + fmt::format_to(name, "Write {} XF mem words at {:04x}", xf_mem_transfer_size, xf_mem_base); + + for (u32 i = 0; i < xf_mem_transfer_size; i++) + { + const auto mem_desc = GetXFMemDescription(xf_mem_base + i, Common::swap32(data)); + fmt::format_to(desc, i == 0 ? "{}" : "\n{}", mem_desc); + data += 4; + } + + 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)); +} |
