Add names and descriptions for XF registers to the FIFO analyzer

This commit is contained in:
Pokechu22 2021-02-06 21:14:21 -08:00
parent aab81d5aa0
commit 2d6ec7457d
4 changed files with 332 additions and 0 deletions

View File

@ -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
{

View File

@ -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<LitChannel>
{
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
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<ClipDisable>
{
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
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<INVTXSPEC>
{
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
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<TexMtxInfo>
{
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
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<PostMtxInfo>
{
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
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;

View File

@ -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<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::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;
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));
}

View File

@ -4,4 +4,10 @@
#pragma once
#include <string>
#include <utility>
#include "VideoCommon/XFMemory.h"
std::pair<std::string, std::string> GetXFRegInfo(u32 address, u32 value);
std::pair<std::string, std::string> GetXFTransferInfo(const u8* data);