summaryrefslogtreecommitdiff
path: root/Source/Core/VideoCommon/XFStructs.cpp
diff options
context:
space:
mode:
authorJMC47 <JMC4789@gmail.com>2021-03-07 00:21:11 -0500
committerGitHub <noreply@github.com>2021-03-07 00:21:11 -0500
commit089250fde65c2e225681c0ef6917d28fa187e8de (patch)
treebcbb6db025c6003bd681e0028f0bc3b7b223bd07 /Source/Core/VideoCommon/XFStructs.cpp
parent5f7d935b0a40f5cece7341927bd92b6a8d5debbe (diff)
parentdf81210e96c6603d3aeb6c76f51b030d06cd06ac (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.cpp360
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));
+}