summaryrefslogtreecommitdiff
path: root/Source/Core
diff options
context:
space:
mode:
Diffstat (limited to 'Source/Core')
-rw-r--r--Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp28
-rw-r--r--Source/Core/VideoCommon/BPMemory.h561
-rw-r--r--Source/Core/VideoCommon/BPStructs.cpp610
3 files changed, 821 insertions, 378 deletions
diff --git a/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp b/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp
index 8764e30b19..4b9020ab8f 100644
--- a/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp
+++ b/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp
@@ -287,11 +287,17 @@ void FIFOAnalyzer::UpdateDetails()
case OpcodeDecoder::GX_LOAD_BP_REG:
{
- u32 cmd2 = Common::swap32(objectdata);
- objectdata += 4;
- new_label = QStringLiteral("BP %1 %2")
- .arg(cmd2 >> 24, 2, 16, QLatin1Char('0'))
- .arg(cmd2 & 0xFFFFFF, 6, 16, QLatin1Char('0'));
+ const u8 cmd2 = *objectdata++;
+ const u32 cmddata = Common::swap24(objectdata);
+ objectdata += 3;
+
+ const auto [name, desc] = GetBPRegInfo(cmd2, cmddata);
+ ASSERT(!name.empty());
+
+ new_label = QStringLiteral("BP %1 %2 %3")
+ .arg(cmd2, 2, 16, QLatin1Char('0'))
+ .arg(cmddata, 6, 16, QLatin1Char('0'))
+ .arg(QString::fromStdString(name));
}
break;
@@ -476,14 +482,14 @@ void FIFOAnalyzer::UpdateDescription()
QString text;
if (*cmddata == OpcodeDecoder::GX_LOAD_BP_REG)
{
- std::string name;
- std::string desc;
- GetBPRegInfo(cmddata + 1, &name, &desc);
+ const u8 cmd = *(cmddata + 1);
+ const u32 value = Common::swap24(cmddata + 2);
+
+ const auto [name, desc] = GetBPRegInfo(cmd, value);
+ ASSERT(!name.empty());
text = tr("BP register ");
- text += name.empty() ?
- QStringLiteral("UNKNOWN_%1").arg(*(cmddata + 1), 2, 16, QLatin1Char('0')) :
- QString::fromStdString(name);
+ text += QString::fromStdString(name);
text += QLatin1Char{'\n'};
if (desc.empty())
diff --git a/Source/Core/VideoCommon/BPMemory.h b/Source/Core/VideoCommon/BPMemory.h
index 2a8d8ba0dd..035fa5531e 100644
--- a/Source/Core/VideoCommon/BPMemory.h
+++ b/Source/Core/VideoCommon/BPMemory.h
@@ -6,8 +6,10 @@
#include <array>
#include <string>
+#include <utility>
#include "Common/BitField.h"
+#include "Common/BitUtils.h"
#include "Common/CommonTypes.h"
#include "Common/EnumFormatter.h"
#include "Common/Inline.h"
@@ -411,6 +413,50 @@ struct TevStageCombiner
ColorCombiner colorC;
AlphaCombiner alphaC;
};
+template <>
+struct fmt::formatter<TevStageCombiner::ColorCombiner>
+{
+ constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
+ template <typename FormatContext>
+ auto format(const TevStageCombiner::ColorCombiner& cc, FormatContext& ctx)
+ {
+ return format_to(ctx.out(),
+ "a: {}\n"
+ "b: {}\n"
+ "c: {}\n"
+ "d: {}\n"
+ "Bias: {}\n"
+ "Op: {} / Comparison: {}\n"
+ "Clamp: {}\n"
+ "Scale factor: {} / Compare mode: {}\n"
+ "Dest: {}",
+ cc.a, cc.b, cc.c, cc.d, cc.bias, cc.op, cc.comparison, cc.clamp ? "Yes" : "No",
+ cc.scale, cc.compare_mode, cc.dest);
+ }
+};
+template <>
+struct fmt::formatter<TevStageCombiner::AlphaCombiner>
+{
+ constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
+ template <typename FormatContext>
+ auto format(const TevStageCombiner::AlphaCombiner& ac, FormatContext& ctx)
+ {
+ return format_to(ctx.out(),
+ "a: {}\n"
+ "b: {}\n"
+ "c: {}\n"
+ "d: {}\n"
+ "Bias: {}\n"
+ "Op: {} / Comparison: {}\n"
+ "Clamp: {}\n"
+ "Scale factor: {} / Compare mode: {}\n"
+ "Dest: {}\n"
+ "Ras sel: {}\n"
+ "Tex sel: {}",
+ ac.a, ac.b, ac.c, ac.d, ac.bias, ac.op, ac.comparison, ac.clamp ? "Yes" : "No",
+ ac.scale, ac.compare_mode, ac.dest, ac.rswap, ac.tswap);
+ }
+};
// several discoveries:
// GXSetTevIndBumpST(tevstage, indstage, matrixind)
@@ -444,10 +490,33 @@ union TevStageIndirect
u32 unused : 11;
};
+ u32 fullhex;
+
// If bs and mid are zero, the result of the stage is independent of
// the texture sample data, so we can skip sampling the texture.
bool IsActive() const { return bs != IndTexBumpAlpha::Off || mid != 0; }
};
+template <>
+struct fmt::formatter<TevStageIndirect>
+{
+ constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
+ template <typename FormatContext>
+ auto format(const TevStageIndirect& tevind, FormatContext& ctx)
+ {
+ return format_to(ctx.out(),
+ "Indirect tex stage ID: {}\n"
+ "Format: {}\n"
+ "Bias: {}\n"
+ "Bump alpha: {}\n"
+ "Offset matrix ID: {}\n"
+ "Regular coord S wrapping factor: {}\n"
+ "Regular coord T wrapping factor: {}\n"
+ "Use modified texture coordinates for LOD computation: {}\n"
+ "Add texture coordinates from previous TEV stage: {}",
+ tevind.bt, tevind.fmt, tevind.bias, tevind.bs, tevind.mid, tevind.sw,
+ tevind.tw, tevind.lb_utclod ? "Yes" : "No", tevind.fb_addprev ? "Yes" : "No");
+ }
+};
enum class RasColorChan : u32
{
@@ -485,6 +554,23 @@ union TwoTevStageOrders
u32 getEnable(int i) const { return i ? enable1.Value() : enable0.Value(); }
RasColorChan getColorChan(int i) const { return i ? colorchan1.Value() : colorchan0.Value(); }
};
+template <>
+struct fmt::formatter<TwoTevStageOrders>
+{
+ constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
+ template <typename FormatContext>
+ auto format(const TwoTevStageOrders& stages, FormatContext& ctx)
+ {
+ return format_to(ctx.out(),
+ "Stage 0 texmap: {}\nStage 0 tex coord: {}\n"
+ "Stage 0 enable texmap: {}\nStage 0 color channel: {}\n"
+ "Stage 1 texmap: {}\nStage 1 tex coord: {}\n"
+ "Stage 1 enable texmap: {}\nStage 1 color channel: {}\n",
+ stages.texmap0, stages.texcoord0, stages.enable0 ? "Yes" : "No",
+ stages.colorchan0, stages.texmap1, stages.texcoord1,
+ stages.enable1 ? "Yes" : "No", stages.colorchan1);
+ }
+};
union TEXSCALE
{
@@ -494,6 +580,22 @@ union TEXSCALE
BitField<12, 4, u32> ts1; // Indirect tex stage 1
u32 hex;
};
+template <>
+struct fmt::formatter<TEXSCALE>
+{
+ constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
+ template <typename FormatContext>
+ auto format(const TEXSCALE& scale, FormatContext& ctx)
+ {
+ return format_to(ctx.out(),
+ "Even stage S scale: {} ({})\n"
+ "Even stage T scale: {} ({})\n"
+ "Odd stage S scale: {} ({})\n"
+ "Odd stage T scale: {} ({})",
+ scale.ss0, 1.f / (1 << scale.ss0), scale.ts0, 1.f / (1 << scale.ts0),
+ scale.ss1, 1.f / (1 << scale.ss1), scale.ts1, 1.f / (1 << scale.ts1));
+ }
+};
union RAS1_IREF
{
@@ -510,6 +612,23 @@ union RAS1_IREF
u32 getTexCoord(int i) const { return (hex >> (6 * i + 3)) & 7; }
u32 getTexMap(int i) const { return (hex >> (6 * i)) & 7; }
};
+template <>
+struct fmt::formatter<RAS1_IREF>
+{
+ constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
+ template <typename FormatContext>
+ auto format(const RAS1_IREF& indref, FormatContext& ctx)
+ {
+ // The field names here are suspicious, since there is no bi3 or bc2
+ return format_to(ctx.out(),
+ "Stage 0 ntexmap: {}\nStage 0 ntexcoord: {}\n"
+ "Stage 1 ntexmap: {}\nStage 1 ntexcoord: {}\n"
+ "Stage 2 ntexmap: {}\nStage 2 ntexcoord: {}\n"
+ "Stage 3 ntexmap: {}\nStage 3 ntexcoord: {}",
+ indref.bi0, indref.bc0, indref.bi1, indref.bc1, indref.bi2, indref.bc3,
+ indref.bi4, indref.bc4);
+ }
+};
// Texture structs
enum class WrapMode : u32
@@ -583,12 +702,47 @@ union TexMode0
BitField<21, 1, bool, u32> lod_clamp;
u32 hex;
};
+template <>
+struct fmt::formatter<TexMode0>
+{
+ constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
+ template <typename FormatContext>
+ auto format(const TexMode0& mode, FormatContext& ctx)
+ {
+ return format_to(ctx.out(),
+ "Wrap S: {}\n"
+ "Wrap T: {}\n"
+ "Mag filter: {}\n"
+ "Mipmap filter: {}\n"
+ "Min filter: {}\n"
+ "LOD type: {}\n"
+ "LOD bias: {} ({})\n"
+ "Max aniso: {}\n"
+ "LOD/bias clamp: {}",
+ mode.wrap_s, mode.wrap_t, mode.mag_filter, mode.mipmap_filter, mode.min_filter,
+ mode.diag_lod, mode.lod_bias, mode.lod_bias / 32.f, mode.max_aniso,
+ mode.lod_clamp ? "Yes" : "No");
+ }
+};
+
union TexMode1
{
BitField<0, 8, u32> min_lod;
BitField<8, 8, u32> max_lod;
u32 hex;
};
+template <>
+struct fmt::formatter<TexMode1>
+{
+ constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
+ template <typename FormatContext>
+ auto format(const TexMode1& mode, FormatContext& ctx)
+ {
+ return format_to(ctx.out(), "Min LOD: {} ({})\nMax LOD: {} ({})", mode.min_lod,
+ mode.min_lod / 16.f, mode.max_lod, mode.max_lod / 16.f);
+ }
+};
+
union TexImage0
{
BitField<0, 10, u32> width; // Actually w-1
@@ -596,6 +750,21 @@ union TexImage0
BitField<20, 4, TextureFormat> format;
u32 hex;
};
+template <>
+struct fmt::formatter<TexImage0>
+{
+ constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
+ template <typename FormatContext>
+ auto format(const TexImage0& teximg, FormatContext& ctx)
+ {
+ return format_to(ctx.out(),
+ "Width: {}\n"
+ "Height: {}\n"
+ "Format: {}",
+ teximg.width + 1, teximg.height + 1, teximg.format);
+ }
+};
+
union TexImage1
{
BitField<0, 15, u32> tmem_even; // TMEM line index for even LODs
@@ -606,6 +775,22 @@ union TexImage1
BitField<21, 1, bool, u32> cache_manually_managed;
u32 hex;
};
+template <>
+struct fmt::formatter<TexImage1>
+{
+ constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
+ template <typename FormatContext>
+ auto format(const TexImage1& teximg, FormatContext& ctx)
+ {
+ return format_to(ctx.out(),
+ "Even TMEM Offset: {:x}\n"
+ "Even TMEM Width: {}\n"
+ "Even TMEM Height: {}\n"
+ "Cache is manually managed: {}",
+ teximg.tmem_even, teximg.cache_width, teximg.cache_height,
+ teximg.cache_manually_managed ? "Yes" : "No");
+ }
+};
union TexImage2
{
@@ -614,18 +799,55 @@ union TexImage2
BitField<18, 3, u32> cache_height;
u32 hex;
};
+template <>
+struct fmt::formatter<TexImage2>
+{
+ constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
+ template <typename FormatContext>
+ auto format(const TexImage2& teximg, FormatContext& ctx)
+ {
+ return format_to(ctx.out(),
+ "Odd TMEM Offset: {:x}\n"
+ "Odd TMEM Width: {}\n"
+ "Odd TMEM Height: {}",
+ teximg.tmem_odd, teximg.cache_width, teximg.cache_height);
+ }
+};
union TexImage3
{
BitField<0, 24, u32> image_base; // address in memory >> 5 (was 20 for GC)
u32 hex;
};
+template <>
+struct fmt::formatter<TexImage3>
+{
+ constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
+ template <typename FormatContext>
+ auto format(const TexImage3& teximg, FormatContext& ctx)
+ {
+ return format_to(ctx.out(), "Source address (32 byte aligned): 0x{:06X}",
+ teximg.image_base << 5);
+ }
+};
+
union TexTLUT
{
BitField<0, 10, u32> tmem_offset;
BitField<10, 2, TLUTFormat> tlut_format;
u32 hex;
};
+template <>
+struct fmt::formatter<TexTLUT>
+{
+ constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
+ template <typename FormatContext>
+ auto format(const TexTLUT& tlut, FormatContext& ctx)
+ {
+ return format_to(ctx.out(), "Address: {:08x}\nFormat: {}", tlut.tmem_offset << 9,
+ tlut.tlut_format);
+ }
+};
union ZTex1
{
@@ -639,6 +861,16 @@ union ZTex2
BitField<2, 2, ZTexOp> op;
u32 hex;
};
+template <>
+struct fmt::formatter<ZTex2>
+{
+ constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
+ template <typename FormatContext>
+ auto format(const ZTex2& ztex2, FormatContext& ctx)
+ {
+ return format_to(ctx.out(), "Type: {}\nOperation: {}", ztex2.type, ztex2.op);
+ }
+};
struct FourTexUnits
{
@@ -686,6 +918,29 @@ union GenMode
u32 hex;
};
+template <>
+struct fmt::formatter<GenMode>
+{
+ constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
+ template <typename FormatContext>
+ auto format(const GenMode& mode, FormatContext& ctx)
+ {
+ return format_to(ctx.out(),
+ "Num tex gens: {}\n"
+ "Num color channels: {}\n"
+ "Unused bit: {}\n"
+ "Flat shading (unconfirmed): {}\n"
+ "Multisampling: {}\n"
+ "Num TEV stages: {}\n"
+ "Cull mode: {}\n"
+ "Num indirect stages: {}\n"
+ "ZFreeze: {}",
+ mode.numtexgens, mode.numcolchans, mode.unused,
+ mode.flat_shading ? "Yes" : "No", mode.multisampling ? "Yes" : "No",
+ mode.numtevstages, mode.cullmode, mode.numindstages,
+ mode.zfreeze ? "Yes" : "No");
+ }
+};
enum class AspectRatioAdjustment
{
@@ -708,6 +963,23 @@ union LPSize
BitField<22, 1, AspectRatioAdjustment> adjust_for_aspect_ratio;
u32 hex;
};
+template <>
+struct fmt::formatter<LPSize>
+{
+ constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
+ template <typename FormatContext>
+ auto format(const LPSize& lp, FormatContext& ctx)
+ {
+ return format_to(ctx.out(),
+ "Line size: {} ({:.3} pixels)\n"
+ "Point size: {} ({:.3} pixels)\n"
+ "Line offset: {}\n"
+ "Point offset: {}\n"
+ "Adjust line aspect ratio: {}",
+ lp.linesize, lp.linesize / 6.f, lp.pointsize, lp.pointsize / 6.f, lp.lineoff,
+ lp.pointoff, lp.adjust_for_aspect_ratio);
+ }
+};
union X12Y12
{
@@ -820,6 +1092,29 @@ union BlendMode
bool UseLogicOp() const;
};
+template <>
+struct fmt::formatter<BlendMode>
+{
+ constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
+ template <typename FormatContext>
+ auto format(const BlendMode& mode, FormatContext& ctx)
+ {
+ static constexpr std::array<const char*, 2> no_yes = {"No", "Yes"};
+ return format_to(ctx.out(),
+ "Enable: {}\n"
+ "Logic ops: {}\n"
+ "Dither: {}\n"
+ "Color write: {}\n"
+ "Alpha write: {}\n"
+ "Dest factor: {}\n"
+ "Source factor: {}\n"
+ "Subtract: {}\n"
+ "Logic mode: {}",
+ no_yes[mode.blendenable], no_yes[mode.logicopenable], no_yes[mode.dither],
+ no_yes[mode.colorupdate], no_yes[mode.alphaupdate], mode.dstfactor,
+ mode.srcfactor, no_yes[mode.subtract], mode.logicmode);
+ }
+};
union FogParam0
{
@@ -830,6 +1125,17 @@ union FogParam0
u32 hex;
float FloatValue() const;
};
+template <>
+struct fmt::formatter<FogParam0>
+{
+ constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
+ template <typename FormatContext>
+ auto format(const FogParam0& param, FormatContext& ctx)
+ {
+ return format_to(ctx.out(), "A value: {}\nMantissa: {}\nExponent: {}\nSign: {}",
+ param.FloatValue(), param.mant, param.exp, param.sign ? '-' : '+');
+ }
+};
enum class FogProjection : u32
{
@@ -878,6 +1184,19 @@ union FogParam3
u32 hex;
float FloatValue() const;
};
+template <>
+struct fmt::formatter<FogParam3>
+{
+ constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
+ template <typename FormatContext>
+ auto format(const FogParam3& param, FormatContext& ctx)
+ {
+ return format_to(ctx.out(),
+ "C value: {}\nMantissa: {}\nExponent: {}\nSign: {}\nProjection: {}\nFsel: {}",
+ param.FloatValue(), param.c_mant, param.c_exp, param.c_sign ? '-' : '+',
+ param.proj, param.fsel);
+ }
+};
union FogRangeKElement
{
@@ -900,6 +1219,28 @@ struct FogRangeParams
RangeBase Base;
FogRangeKElement K[5];
};
+template <>
+struct fmt::formatter<FogRangeParams::RangeBase>
+{
+ constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
+ template <typename FormatContext>
+ auto format(const FogRangeParams::RangeBase& range, FormatContext& ctx)
+ {
+ return format_to(ctx.out(), "Center: {}\nEnabled: {}", range.Center,
+ range.Enabled ? "Yes" : "No");
+ }
+};
+template <>
+struct fmt::formatter<FogRangeKElement>
+{
+ constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
+ template <typename FormatContext>
+ auto format(const FogRangeKElement& range, FormatContext& ctx)
+ {
+ return format_to(ctx.out(), "High: {}\nLow: {}", range.HI, range.LO);
+ }
+};
+
// final eq: ze = A/(B_MAG - (Zs>>B_SHF));
struct FogParams
{
@@ -925,6 +1266,16 @@ struct FogParams
// amount to subtract from eyespacez after range adjustment
float GetC() const;
};
+template <>
+struct fmt::formatter<FogParams::FogColor>
+{
+ constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
+ template <typename FormatContext>
+ auto format(const FogParams::FogColor& color, FormatContext& ctx)
+ {
+ return format_to(ctx.out(), "Red: {}\nGreen: {}\nBlue: {}", color.r, color.g, color.b);
+ }
+};
enum class CompareMode : u32
{
@@ -953,6 +1304,20 @@ union ZMode
u32 hex;
};
+template <>
+struct fmt::formatter<ZMode>
+{
+ constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
+ template <typename FormatContext>
+ auto format(const ZMode& mode, FormatContext& ctx)
+ {
+ return format_to(ctx.out(),
+ "Enable test: {}\n"
+ "Compare function: {}\n"
+ "Enable updates: {}",
+ mode.testenable ? "Yes" : "No", mode.func, mode.updateenable ? "Yes" : "No");
+ }
+};
union ConstantAlpha
{
@@ -960,6 +1325,19 @@ union ConstantAlpha
BitField<8, 1, bool, u32> enable;
u32 hex;
};
+template <>
+struct fmt::formatter<ConstantAlpha>
+{
+ constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
+ template <typename FormatContext>
+ auto format(const ConstantAlpha& c, FormatContext& ctx)
+ {
+ return format_to(ctx.out(),
+ "Enable: {}\n"
+ "Alpha value: {:02x}",
+ c.enable ? "Yes" : "No", c.alpha);
+ }
+};
union FieldMode
{
@@ -967,6 +1345,17 @@ union FieldMode
BitField<0, 1, AspectRatioAdjustment> texLOD;
u32 hex;
};
+template <>
+struct fmt::formatter<FieldMode>
+{
+ constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
+ template <typename FormatContext>
+ auto format(const FieldMode& mode, FormatContext& ctx)
+ {
+ return format_to(ctx.out(), "Adjust vertex tex LOD computation to account for interlacing: {}",
+ mode.texLOD);
+ }
+};
enum class FieldMaskState : u32
{
@@ -986,6 +1375,16 @@ union FieldMask
BitField<1, 1, FieldMaskState> even;
u32 hex;
};
+template <>
+struct fmt::formatter<FieldMask>
+{
+ constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
+ template <typename FormatContext>
+ auto format(const FieldMask& mask, FormatContext& ctx)
+ {
+ return format_to(ctx.out(), "Odd field: {}\nEven field: {}", mask.odd, mask.even);
+ }
+};
enum class PixelFormat : u32
{
@@ -1038,6 +1437,20 @@ union PEControl
u32 hex;
};
+template <>
+struct fmt::formatter<PEControl>
+{
+ constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
+ template <typename FormatContext>
+ auto format(const PEControl& config, FormatContext& ctx)
+ {
+ return format_to(ctx.out(),
+ "EFB pixel format: {}\n"
+ "Depth format: {}\n"
+ "Early depth test: {}",
+ config.pixel_format, config.zformat, config.early_ztest ? "Yes" : "No");
+ }
+};
// Texture coordinate stuff
@@ -1051,6 +1464,25 @@ union TCInfo
BitField<19, 1, bool, u32> point_offset;
u32 hex;
};
+template <>
+struct fmt::formatter<TCInfo>
+{
+ constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
+ template <typename FormatContext>
+ auto format(const TCInfo& info, FormatContext& ctx)
+ {
+ return format_to(ctx.out(),
+ "Scale: {}\n"
+ "Range bias: {}\n"
+ "Cylindric wrap: {}\n"
+ "Use line offset: {} (s only)\n"
+ "Use point offset: {} (s only)",
+ info.scale_minus_1 + 1, info.range_bias ? "Yes" : "No",
+ info.cylindric_wrap ? "Yes" : "No", info.line_offset ? "Yes" : "No",
+ info.point_offset ? "Yes" : "No");
+ }
+};
+
struct TCoordInfo
{
TCInfo s;
@@ -1062,6 +1494,11 @@ enum class TevRegType : u32
Color = 0,
Constant = 1,
};
+template <>
+struct fmt::formatter<TevRegType> : EnumFormatter<TevRegType::Constant>
+{
+ formatter() : EnumFormatter({"Color", "Constant"}) {}
+};
struct TevReg
{
@@ -1086,6 +1523,37 @@ struct TevReg
RA ra;
BG bg;
};
+template <>
+struct fmt::formatter<TevReg::RA>
+{
+ constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
+ template <typename FormatContext>
+ auto format(const TevReg::RA& ra, FormatContext& ctx)
+ {
+ return format_to(ctx.out(), "Type: {}\nAlpha: {:03x}\nRed: {:03x}", ra.type, ra.alpha, ra.red);
+ }
+};
+template <>
+struct fmt::formatter<TevReg::BG>
+{
+ constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
+ template <typename FormatContext>
+ auto format(const TevReg::BG& bg, FormatContext& ctx)
+ {
+ return format_to(ctx.out(), "Type: {}\nGreen: {:03x}\nBlue: {:03x}", bg.type, bg.green,
+ bg.blue);
+ }
+};
+template <>
+struct fmt::formatter<TevReg>
+{
+ constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
+ template <typename FormatContext>
+ auto format(const TevReg& reg, FormatContext& ctx)
+ {
+ return format_to(ctx.out(), "{}\n{}", reg.ra, reg.bg);
+ }
+};
enum class KonstSel : u32
{
@@ -1172,6 +1640,19 @@ union TevKSel
KonstSel getKC(int i) const { return i ? kcsel1.Value() : kcsel0.Value(); }
KonstSel getKA(int i) const { return i ? kasel1.Value() : kasel0.Value(); }
};
+template <>
+struct fmt::formatter<TevKSel>
+{
+ constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
+ template <typename FormatContext>
+ auto format(const TevKSel& ksel, FormatContext& ctx)
+ {
+ return format_to(ctx.out(),
+ "Swap 1: {}\nSwap 2: {}\nColor sel 0: {}\nAlpha sel 0: {}\n"
+ "Color sel 1: {}\nAlpha sel 1: {}",
+ ksel.swap1, ksel.swap2, ksel.kcsel0, ksel.kasel0, ksel.kcsel1, ksel.kasel1);
+ }
+};
enum class AlphaTestOp : u32
{
@@ -1245,6 +1726,20 @@ union AlphaTest
return AlphaTestResult::Undetermined;
}
};
+template <>
+struct fmt::formatter<AlphaTest>
+{
+ constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
+ template <typename FormatContext>
+ auto format(const AlphaTest& test, FormatContext& ctx)
+ {
+ return format_to(ctx.out(),
+ "Test 1: {} (ref: 0x{:02x})\n"
+ "Test 2: {} (ref: 0x{:02x})\n"
+ "Logic: {}\n",
+ test.comp0, test.ref0, test.comp1, test.ref1, test.logic);
+ }
+};
enum class FrameToField : u32
{
@@ -1286,6 +1781,60 @@ union UPE_Copy
return static_cast<EFBCopyFormat>(target_pixel_format / 2 + (target_pixel_format & 1) * 8);
}
};
+template <>
+struct fmt::formatter<UPE_Copy>
+{
+ constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
+ template <typename FormatContext>
+ auto format(const UPE_Copy& copy, FormatContext& ctx)
+ {
+ static constexpr std::array<const char*, 2> no_yes = {"No", "Yes"};
+ std::string_view clamp;
+ if (copy.clamp_top)
+ {
+ if (copy.clamp_bottom)
+ clamp = "Top and Bottom";
+ else
+ clamp = "Top only";
+ }
+ else
+ {
+ if (copy.clamp_bottom)
+ clamp = "Bottom only";
+ else
+ clamp = "None";
+ }
+ std::string_view gamma = "Invalid";
+ switch (copy.gamma)
+ {
+ case 0:
+ gamma = "1.0";
+ break;
+ case 1:
+ gamma = "1.7";
+ break;
+ case 2:
+ gamma = "2.2";
+ break;
+ }
+
+ return format_to(ctx.out(),
+ "Clamping: {}\n"
+ "Converting from RGB to YUV: {}\n"
+ "Target pixel format: {}\n"
+ "Gamma correction: {}\n"
+ "Mipmap filter: {}\n"
+ "Vertical scaling: {}\n"
+ "Clear: {}\n"
+ "Frame to field: {}\n"
+ "Copy to XFB: {}\n"
+ "Intensity format: {}\n"
+ "Automatic color conversion: {}",
+ clamp, no_yes[copy.yuv], copy.tp_realFormat(), gamma, no_yes[copy.half_scale],
+ no_yes[copy.scale_invert], no_yes[copy.clear], copy.frame_to_field,
+ no_yes[copy.copy_to_xfb], no_yes[copy.intensity_fmt], no_yes[copy.auto_conv]);
+ }
+};
union CopyFilterCoefficients
{
@@ -1321,6 +1870,16 @@ union BPU_PreloadTileInfo
BitField<15, 2, u32> type;
u32 hex;
};
+template <>
+struct fmt::formatter<BPU_PreloadTileInfo>
+{
+ constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
+ template <typename FormatContext>
+ auto format(const BPU_PreloadTileInfo& info, FormatContext& ctx)
+ {
+ return format_to(ctx.out(), "Type: {}\nCount: {}", info.type, info.count);
+ }
+};
struct BPS_TmemConfig
{
@@ -1420,4 +1979,4 @@ extern BPMemory bpmem;
void LoadBPReg(u32 value0);
void LoadBPRegPreprocess(u32 value0);
-void GetBPRegInfo(const u8* data, std::string* name, std::string* desc);
+std::pair<std::string, std::string> GetBPRegInfo(u8 cmd, u32 cmddata);
diff --git a/Source/Core/VideoCommon/BPStructs.cpp b/Source/Core/VideoCommon/BPStructs.cpp
index d0418e9289..2ad90a350a 100644
--- a/Source/Core/VideoCommon/BPStructs.cpp
+++ b/Source/Core/VideoCommon/BPStructs.cpp
@@ -745,61 +745,59 @@ void LoadBPRegPreprocess(u32 value0)
}
}
-void GetBPRegInfo(const u8* data, std::string* name, std::string* desc)
+std::pair<std::string, std::string> GetBPRegInfo(u8 cmd, u32 cmddata)
{
- const char* no_yes[2] = {"No", "Yes"};
+// 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), "");
- u8 cmd = data[0];
- u32 cmddata = Common::swap32(data) & 0xFFFFFF;
switch (cmd)
{
-// Macro to set the register name and make sure it was written correctly via compile time assertion
-#define SetRegName(reg) \
- *name = #reg; \
- (void)(reg);
-
case BPMEM_GENMODE: // 0x00
- SetRegName(BPMEM_GENMODE);
- // TODO: Description
- break;
+ return std::make_pair(RegName(BPMEM_GENMODE), fmt::to_string(GenMode{.hex = cmddata}));
case BPMEM_DISPLAYCOPYFILTER: // 0x01
+ case BPMEM_DISPLAYCOPYFILTER + 1:
+ case BPMEM_DISPLAYCOPYFILTER + 2:
+ case BPMEM_DISPLAYCOPYFILTER + 3:
// TODO: This is actually the sample pattern used for copies from an antialiased EFB
- SetRegName(BPMEM_DISPLAYCOPYFILTER);
+ return DescriptionlessReg(BPMEM_DISPLAYCOPYFILTER);
// TODO: Description
- break;
-
- case 0x02: // 0x02
- case 0x03: // 0x03
- case 0x04: // 0x04
- // TODO: same as BPMEM_DISPLAYCOPYFILTER
- break;
case BPMEM_IND_MTXA: // 0x06
- case BPMEM_IND_MTXA + 3:
- case BPMEM_IND_MTXA + 6:
- SetRegName(BPMEM_IND_MTXA);
- // TODO: Description
- break;
-
case BPMEM_IND_MTXB: // 0x07
- case BPMEM_IND_MTXB + 3:
- case BPMEM_IND_MTXB + 6:
- SetRegName(BPMEM_IND_MTXB);
- // TODO: Descriptio
- break;
-
case BPMEM_IND_MTXC: // 0x08
+ case BPMEM_IND_MTXA + 3:
+ case BPMEM_IND_MTXB + 3:
case BPMEM_IND_MTXC + 3:
+ case BPMEM_IND_MTXA + 6:
+ case BPMEM_IND_MTXB + 6:
case BPMEM_IND_MTXC + 6:
- SetRegName(BPMEM_IND_MTXC);
- // TODO: Description
- break;
+ {
+ const u32 matrix_num = (cmd - BPMEM_IND_MTXA) / 3;
+ const u32 matrix_col = (cmd - BPMEM_IND_MTXA) % 3;
+ // These all use the same structure, though the meaning is *slightly* different;
+ // for conveninece implement it only once
+ const s32 row0 = cmddata & 0x0007ff; // ma or mc or me
+ const s32 row1 = (cmddata & 0x3ff800) >> 11; // mb or md or mf
+ const u32 scale = (cmddata & 0xc00000) >> 22; // 2 bits of a 6-bit field for each column
+
+ const float row0f = static_cast<float>(row0) / (1 << 10);
+ const float row1f = static_cast<float>(row0) / (1 << 10);
+
+ return std::make_pair(fmt::format("BPMEM_IND_MTX{} Matrix {}", "ABC"[matrix_col], matrix_num),
+ fmt::format("Matrix {} column {} ({})\n"
+ "Row 0 (m{}): {} ({})\n"
+ "Row 1 (m{}): {} ({})\n"
+ "Scale bits: {} (shifted: {})",
+ matrix_num, matrix_col, "ABC"[matrix_col], "ace"[matrix_col],
+ row0f, row0, "bdf"[matrix_col], row1f, row1, scale,
+ scale << (2 * matrix_col)));
+ }
case BPMEM_IND_IMASK: // 0x0F
- SetRegName(BPMEM_IND_IMASK);
+ return DescriptionlessReg(BPMEM_IND_IMASK);
// TODO: Description
- break;
case BPMEM_IND_CMD: // 0x10
case BPMEM_IND_CMD + 1:
@@ -817,49 +815,47 @@ void GetBPRegInfo(const u8* data, std::string* name, std::string* desc)
case BPMEM_IND_CMD + 13:
case BPMEM_IND_CMD + 14:
case BPMEM_IND_CMD + 15:
- SetRegName(BPMEM_IND_CMD);
- // TODO: Description
- break;
+ return std::make_pair(fmt::format("BPMEM_IND_CMD command {}", cmd - BPMEM_IND_CMD),
+ fmt::to_string(TevStageIndirect{.fullhex = cmddata}));
case BPMEM_SCISSORTL: // 0x20
- SetRegName(BPMEM_SCISSORTL);
- // TODO: Description
- break;
+ {
+ const X12Y12 top_left{.hex = cmddata};
+ return std::make_pair(RegName(BPMEM_SCISSORTL),
+ fmt::format("Scissor Top: {}\nScissor Left: {}", top_left.y, top_left.x));
+ }
case BPMEM_SCISSORBR: // 0x21
- SetRegName(BPMEM_SCISSORBR);
- // TODO: Description
- break;
+ {
+ const X12Y12 bottom_right{.hex = cmddata};
+ return std::make_pair(
+ RegName(BPMEM_SCISSORBR),
+ fmt::format("Scissor Bottom: {}\nScissor Right: {}", bottom_right.y, bottom_right.x));
+ }
case BPMEM_LINEPTWIDTH: // 0x22
- SetRegName(BPMEM_LINEPTWIDTH);
- // TODO: Description
- break;
+ return std::make_pair(RegName(BPMEM_LINEPTWIDTH), fmt::to_string(LPSize{.hex = cmddata}));
case BPMEM_PERF0_TRI: // 0x23
- SetRegName(BPMEM_PERF0_TRI);
+ return DescriptionlessReg(BPMEM_PERF0_TRI);
// TODO: Description
- break;
case BPMEM_PERF0_QUAD: // 0x24
- SetRegName(BPMEM_PERF0_QUAD);
+ return DescriptionlessReg(BPMEM_PERF0_QUAD);
// TODO: Description
- break;
case BPMEM_RAS1_SS0: // 0x25
- SetRegName(BPMEM_RAS1_SS0);
- // TODO: Description
- break;
+ return std::make_pair(
+ RegName(BPMEM_RAS1_SS0),
+ fmt::format("Indirect texture stages 0 and 1:\n{}", TEXSCALE{.hex = cmddata}));
case BPMEM_RAS1_SS1: // 0x26
- SetRegName(BPMEM_RAS1_SS1);
- // TODO: Description
- break;
+ return std::make_pair(
+ RegName(BPMEM_RAS1_SS1),
+ fmt::format("Indirect texture stages 2 and 3:\n{}", TEXSCALE{.hex = cmddata}));
case BPMEM_IREF: // 0x27
- SetRegName(BPMEM_IREF);
- // TODO: Description
- break;
+ return std::make_pair(RegName(BPMEM_IREF), fmt::to_string(RAS1_IREF{.hex = cmddata}));
case BPMEM_TREF: // 0x28
case BPMEM_TREF + 1:
@@ -869,9 +865,8 @@ void GetBPRegInfo(const u8* data, std::string* name, std::string* desc)
case BPMEM_TREF + 5:
case BPMEM_TREF + 6:
case BPMEM_TREF + 7:
- SetRegName(BPMEM_TREF);
- // TODO: Description
- break;
+ return std::make_pair(fmt::format("BPMEM_TREF number {}", cmd - BPMEM_TREF),
+ fmt::to_string(TwoTevStageOrders{.hex = cmddata}));
case BPMEM_SU_SSIZE: // 0x30
case BPMEM_SU_SSIZE + 2:
@@ -881,9 +876,8 @@ void GetBPRegInfo(const u8* data, std::string* name, std::string* desc)
case BPMEM_SU_SSIZE + 10:
case BPMEM_SU_SSIZE + 12:
case BPMEM_SU_SSIZE + 14:
- SetRegName(BPMEM_SU_SSIZE);
- // TODO: Description
- break;
+ return std::make_pair(fmt::format("BPMEM_SU_SSIZE number {}", (cmd - BPMEM_SU_SSIZE) / 2),
+ fmt::format("S size info:\n{}", TCInfo{.hex = cmddata}));
case BPMEM_SU_TSIZE: // 0x31
case BPMEM_SU_TSIZE + 2:
@@ -893,359 +887,283 @@ void GetBPRegInfo(const u8* data, std::string* name, std::string* desc)
case BPMEM_SU_TSIZE + 10:
case BPMEM_SU_TSIZE + 12:
case BPMEM_SU_TSIZE + 14:
- SetRegName(BPMEM_SU_TSIZE);
- // TODO: Description
- break;
+ return std::make_pair(fmt::format("BPMEM_SU_TSIZE number {}", (cmd - BPMEM_SU_TSIZE) / 2),
+ fmt::format("T size info:\n{}", TCInfo{.hex = cmddata}));
case BPMEM_ZMODE: // 0x40
- SetRegName(BPMEM_ZMODE);
- // TODO: Description
- break;
+ return std::make_pair(RegName(BPMEM_ZMODE), fmt::format("Z mode: {}", ZMode{.hex = cmddata}));
case BPMEM_BLENDMODE: // 0x41
- {
- SetRegName(BPMEM_BLENDMODE);
- BlendMode mode;
- mode.hex = cmddata;
- *desc = fmt::format("Enable: {}\n"
- "Logic ops: {}\n"
- "Dither: {}\n"
- "Color write: {}\n"
- "Alpha write: {}\n"
- "Dest factor: {}\n"
- "Source factor: {}\n"
- "Subtract: {}\n"
- "Logic mode: {}\n",
- no_yes[mode.blendenable], no_yes[mode.logicopenable], no_yes[mode.dither],
- no_yes[mode.colorupdate], no_yes[mode.alphaupdate], mode.dstfactor,
- mode.srcfactor, no_yes[mode.subtract], mode.logicmode);
- }
- break;
+ return std::make_pair(RegName(BPMEM_BLENDMODE), fmt::to_string(BlendMode{.hex = cmddata}));
case BPMEM_CONSTANTALPHA: // 0x42
- SetRegName(BPMEM_CONSTANTALPHA);
- // TODO: Description
- break;
+ return std::make_pair(RegName(BPMEM_CONSTANTALPHA),
+ fmt::to_string(ConstantAlpha{.hex = cmddata}));
case BPMEM_ZCOMPARE: // 0x43
- {
- SetRegName(BPMEM_ZCOMPARE);
- PEControl config;
- config.hex = cmddata;
- *desc = fmt::format("EFB pixel format: {}\n"
- "Depth format: {}\n"
- "Early depth test: {}\n",
- config.pixel_format, config.zformat, no_yes[config.early_ztest]);
- }
- break;
+ return std::make_pair(RegName(BPMEM_ZCOMPARE), fmt::to_string(PEControl{.hex = cmddata}));
case BPMEM_FIELDMASK: // 0x44
- SetRegName(BPMEM_FIELDMASK);
- // TODO: Description
- break;
+ return std::make_pair(RegName(BPMEM_FIELDMASK), fmt::to_string(FieldMask{.hex = cmddata}));
case BPMEM_SETDRAWDONE: // 0x45
- SetRegName(BPMEM_SETDRAWDONE);
+ return DescriptionlessReg(BPMEM_SETDRAWDONE);
// TODO: Description
- break;
case BPMEM_BUSCLOCK0: // 0x46
- SetRegName(BPMEM_BUSCLOCK0);
+ return DescriptionlessReg(BPMEM_BUSCLOCK0);
// TODO: Description
- break;
case BPMEM_PE_TOKEN_ID: // 0x47
- SetRegName(BPMEM_PE_TOKEN_ID);
+ return DescriptionlessReg(BPMEM_PE_TOKEN_ID);
// TODO: Description
- break;
case BPMEM_PE_TOKEN_INT_ID: // 0x48
- SetRegName(BPMEM_PE_TOKEN_INT_ID);
+ return DescriptionlessReg(BPMEM_PE_TOKEN_INT_ID);
// TODO: Description
- break;
case BPMEM_EFB_TL: // 0x49
{
- SetRegName(BPMEM_EFB_TL);
- X10Y10 left_top;
- left_top.hex = cmddata;
- *desc = fmt::format("Left: {}\nTop: {}", u32(left_top.x), u32(left_top.y));
+ const X10Y10 left_top{.hex = cmddata};
+ return std::make_pair(RegName(BPMEM_EFB_TL),
+ fmt::format("EFB Left: {}\nEFB Top: {}", left_top.x, left_top.y));
}
- break;
case BPMEM_EFB_WH: // 0x4A
{
- SetRegName(BPMEM_EFB_WH);
- X10Y10 width_height;
- width_height.hex = cmddata;
- *desc = fmt::format("Width: {}\nHeight: {}", width_height.x + 1, width_height.y + 1);
+ const X10Y10 width_height{.hex = cmddata};
+ return std::make_pair(
+ RegName(BPMEM_EFB_WH),
+ fmt::format("EFB Width: {}\nEFB Height: {}", width_height.x + 1, width_height.y + 1));
}
- break;
case BPMEM_EFB_ADDR: // 0x4B
- SetRegName(BPMEM_EFB_ADDR);
- *desc = fmt::format("Target address (32 byte aligned): 0x{:06X}", cmddata << 5);
- break;
+ return std::make_pair(
+ RegName(BPMEM_EFB_ADDR),
+ fmt::format("EFB Target address (32 byte aligned): 0x{:06X}", cmddata << 5));
case BPMEM_MIPMAP_STRIDE: // 0x4D
- SetRegName(BPMEM_MIPMAP_STRIDE);
+ return DescriptionlessReg(BPMEM_MIPMAP_STRIDE);
// TODO: Description
- break;
case BPMEM_COPYYSCALE: // 0x4E
- SetRegName(BPMEM_COPYYSCALE);
- *desc = fmt::format("Scaling factor (XFB copy only): 0x{:X} ({} or inverted {})", cmddata,
- static_cast<float>(cmddata) / 256.f, 256.f / static_cast<float>(cmddata));
- break;
+ return std::make_pair(
+ RegName(BPMEM_COPYYSCALE),
+ fmt::format("Y scaling factor (XFB copy only): 0x{:X} ({}, reciprocal {})", cmddata,
+ static_cast<float>(cmddata) / 256.f, 256.f / static_cast<float>(cmddata)));
case BPMEM_CLEAR_AR: // 0x4F
- SetRegName(BPMEM_CLEAR_AR);
- *desc = fmt::format("Alpha: 0x{:02X}\nRed: 0x{:02X}", (cmddata & 0xFF00) >> 8, cmddata & 0xFF);
- break;
+ return std::make_pair(RegName(BPMEM_CLEAR_AR),
+ fmt::format("Clear color alpha: 0x{:02X}\nClear color red: 0x{:02X}",
+ (cmddata & 0xFF00) >> 8, cmddata & 0xFF));
case BPMEM_CLEAR_GB: // 0x50
- SetRegName(BPMEM_CLEAR_GB);
- *desc = fmt::format("Green: 0x{:02X}\nBlue: 0x{:02X}", (cmddata & 0xFF00) >> 8, cmddata & 0xFF);
- break;
+ return std::make_pair(RegName(BPMEM_CLEAR_GB),
+ fmt::format("Clear color green: 0x{:02X}\nClear color blue: 0x{:02X}",
+ (cmddata & 0xFF00) >> 8, cmddata & 0xFF));
case BPMEM_CLEAR_Z: // 0x51
- SetRegName(BPMEM_CLEAR_Z);
- *desc = fmt::format("Z value: 0x{:06X}", cmddata);
- break;
+ return std::make_pair(RegName(BPMEM_CLEAR_Z), fmt::format("Clear Z value: 0x{:06X}", cmddata));
case BPMEM_TRIGGER_EFB_COPY: // 0x52
- {
- SetRegName(BPMEM_TRIGGER_EFB_COPY);
- UPE_Copy copy;
- copy.Hex = cmddata;
- *desc = fmt::format(
- "Clamping: {}\n"
- "Converting from RGB to YUV: {}\n"
- "Target pixel format: 0x{:X}\n"
- "Gamma correction: {}\n"
- "Mipmap filter: {}\n"
- "Vertical scaling: {}\n"
- "Clear: {}\n"
- "Frame to field: {}\n"
- "Copy to XFB: {}\n"
- "Intensity format: {}\n"
- "Automatic color conversion: {}",
- (copy.clamp_top && copy.clamp_bottom) ?
- "Top and Bottom" :
- (copy.clamp_top) ? "Top only" : (copy.clamp_bottom) ? "Bottom only" : "None",
- no_yes[copy.yuv], static_cast<int>(copy.tp_realFormat()),
- (copy.gamma == 0) ?
- "1.0" :
- (copy.gamma == 1) ? "1.7" : (copy.gamma == 2) ? "2.2" : "Invalid value 0x3?",
- no_yes[copy.half_scale], no_yes[copy.scale_invert], no_yes[copy.clear], copy.frame_to_field,
- no_yes[copy.copy_to_xfb], no_yes[copy.intensity_fmt], no_yes[copy.auto_conv]);
- }
- break;
+ return std::make_pair(RegName(BPMEM_TRIGGER_EFB_COPY),
+ fmt::to_string(UPE_Copy{.Hex = cmddata}));
case BPMEM_COPYFILTER0: // 0x53
- SetRegName(BPMEM_COPYFILTER0);
- // TODO: Description
- break;
+ {
+ const u32 w0 = (cmddata & 0x00003f);
+ const u32 w1 = (cmddata & 0x000fc0) >> 6;
+ const u32 w2 = (cmddata & 0x03f000) >> 12;
+ const u32 w3 = (cmddata & 0xfc0000) >> 18;
+ return std::make_pair(RegName(BPMEM_COPYFILTER0),
+ fmt::format("w0: {}\nw1: {}\nw2: {}\nw3: {}", w0, w1, w2, w3));
+ }
case BPMEM_COPYFILTER1: // 0x54
- SetRegName(BPMEM_COPYFILTER1);
- // TODO: Description
- break;
+ {
+ const u32 w4 = (cmddata & 0x00003f);
+ const u32 w5 = (cmddata & 0x000fc0) >> 6;
+ const u32 w6 = (cmddata & 0x03f000) >> 12;
+ // There is no w7
+ return std::make_pair(RegName(BPMEM_COPYFILTER1),
+ fmt::format("w4: {}\nw5: {}\nw6: {}", w4, w5, w6));
+ }
case BPMEM_CLEARBBOX1: // 0x55
- SetRegName(BPMEM_CLEARBBOX1);
+ return DescriptionlessReg(BPMEM_CLEARBBOX1);
// TODO: Description
- break;
case BPMEM_CLEARBBOX2: // 0x56
- SetRegName(BPMEM_CLEARBBOX2);
+ return DescriptionlessReg(BPMEM_CLEARBBOX2);
// TODO: Description
- break;
case BPMEM_CLEAR_PIXEL_PERF: // 0x57
- SetRegName(BPMEM_CLEAR_PIXEL_PERF);
+ return DescriptionlessReg(BPMEM_CLEAR_PIXEL_PERF);
// TODO: Description
- break;
case BPMEM_REVBITS: // 0x58
- SetRegName(BPMEM_REVBITS);
+ return DescriptionlessReg(BPMEM_REVBITS);
// TODO: Description
- break;
case BPMEM_SCISSOROFFSET: // 0x59
- SetRegName(BPMEM_SCISSOROFFSET);
- // TODO: Description
- break;
+ {
+ const X10Y10 xy{.hex = cmddata};
+ return std::make_pair(RegName(BPMEM_EFB_TL),
+ fmt::format("Scissor X offset: {}\nScissor Y offset: {}", xy.x, xy.y));
+ }
case BPMEM_PRELOAD_ADDR: // 0x60
- SetRegName(BPMEM_PRELOAD_ADDR);
+ return DescriptionlessReg(BPMEM_PRELOAD_ADDR);
// TODO: Description
- break;
case BPMEM_PRELOAD_TMEMEVEN: // 0x61
- SetRegName(BPMEM_PRELOAD_TMEMEVEN);
+ return DescriptionlessReg(BPMEM_PRELOAD_TMEMEVEN);
// TODO: Description
- break;
case BPMEM_PRELOAD_TMEMODD: // 0x62
- SetRegName(BPMEM_PRELOAD_TMEMODD);
+ return DescriptionlessReg(BPMEM_PRELOAD_TMEMODD);
// TODO: Description
- break;
case BPMEM_PRELOAD_MODE: // 0x63
- SetRegName(BPMEM_PRELOAD_MODE);
- // TODO: Description
- break;
+ return std::make_pair(RegName(BPMEM_PRELOAD_MODE),
+ fmt::to_string(BPU_PreloadTileInfo{.hex = cmddata}));
case BPMEM_LOADTLUT0: // 0x64
- SetRegName(BPMEM_LOADTLUT0);
+ return DescriptionlessReg(BPMEM_LOADTLUT0);
// TODO: Description
- break;
case BPMEM_LOADTLUT1: // 0x65
- SetRegName(BPMEM_LOADTLUT1);
+ return DescriptionlessReg(BPMEM_LOADTLUT1);
// TODO: Description
- break;
case BPMEM_TEXINVALIDATE: // 0x66
- SetRegName(BPMEM_TEXINVALIDATE);
+ return DescriptionlessReg(BPMEM_TEXINVALIDATE);
// TODO: Description
- break;
case BPMEM_PERF1: // 0x67
- SetRegName(BPMEM_PERF1);
+ return DescriptionlessReg(BPMEM_PERF1);
// TODO: Description
- break;
case BPMEM_FIELDMODE: // 0x68
- SetRegName(BPMEM_FIELDMODE);
- // TODO: Description
- break;
+ return std::make_pair(RegName(BPMEM_FIELDMODE), fmt::to_string(FieldMode{.hex = cmddata}));
case BPMEM_BUSCLOCK1: // 0x69
- SetRegName(BPMEM_BUSCLOCK1);
+ return DescriptionlessReg(BPMEM_BUSCLOCK1);
// TODO: Description
- break;
case BPMEM_TX_SETMODE0: // 0x80
case BPMEM_TX_SETMODE0 + 1:
case BPMEM_TX_SETMODE0 + 2:
case BPMEM_TX_SETMODE0 + 3:
- SetRegName(BPMEM_TX_SETMODE0);
- // TODO: Description
- break;
+ return std::make_pair(fmt::format("BPMEM_TX_SETMODE0 Texture Unit {}", cmd - BPMEM_TX_SETMODE0),
+ fmt::to_string(TexMode0{.hex = cmddata}));
case BPMEM_TX_SETMODE1: // 0x84
case BPMEM_TX_SETMODE1 + 1:
case BPMEM_TX_SETMODE1 + 2:
case BPMEM_TX_SETMODE1 + 3:
- SetRegName(BPMEM_TX_SETMODE1);
- // TODO: Description
- break;
+ return std::make_pair(fmt::format("BPMEM_TX_SETMODE1 Texture Unit {}", cmd - BPMEM_TX_SETMODE1),
+ fmt::to_string(TexMode1{.hex = cmddata}));
case BPMEM_TX_SETIMAGE0: // 0x88
case BPMEM_TX_SETIMAGE0 + 1:
case BPMEM_TX_SETIMAGE0 + 2:
case BPMEM_TX_SETIMAGE0 + 3:
- case BPMEM_TX_SETIMAGE0_4: // 0xA8
- case BPMEM_TX_SETIMAGE0_4 + 1:
- case BPMEM_TX_SETIMAGE0_4 + 2:
- case BPMEM_TX_SETIMAGE0_4 + 3:
- {
- SetRegName(BPMEM_TX_SETIMAGE0);
- int texnum =
- (cmd < BPMEM_TX_SETIMAGE0_4) ? cmd - BPMEM_TX_SETIMAGE0 : cmd - BPMEM_TX_SETIMAGE0_4 + 4;
- TexImage0 teximg;
- teximg.hex = cmddata;
- *desc = fmt::format("Texture Unit: {}\n"
- "Width: {}\n"
- "Height: {}\n"
- "Format: {}\n",
- texnum, u32(teximg.width) + 1, u32(teximg.height) + 1, teximg.format);
- }
- break;
+ return std::make_pair(
+ fmt::format("BPMEM_TX_SETIMAGE0 Texture Unit {}", cmd - BPMEM_TX_SETIMAGE0),
+ fmt::to_string(TexImage0{.hex = cmddata}));
case BPMEM_TX_SETIMAGE1: // 0x8C
case BPMEM_TX_SETIMAGE1 + 1:
case BPMEM_TX_SETIMAGE1 + 2:
case BPMEM_TX_SETIMAGE1 + 3:
- case BPMEM_TX_SETIMAGE1_4: // 0xAC
- case BPMEM_TX_SETIMAGE1_4 + 1:
- case BPMEM_TX_SETIMAGE1_4 + 2:
- case BPMEM_TX_SETIMAGE1_4 + 3:
- {
- SetRegName(BPMEM_TX_SETIMAGE1);
- int texnum =
- (cmd < BPMEM_TX_SETIMAGE1_4) ? cmd - BPMEM_TX_SETIMAGE1 : cmd - BPMEM_TX_SETIMAGE1_4 + 4;
- TexImage1 teximg;
- teximg.hex = cmddata;
- *desc = fmt::format("Texture Unit: {}\n"
- "Even TMEM Offset: {:x}\n"
- "Even TMEM Width: {}\n"
- "Even TMEM Height: {}\n"
- "Cache is manually managed: {}\n",
- texnum, u32(teximg.tmem_even), u32(teximg.cache_width),
- u32(teximg.cache_height), no_yes[teximg.cache_manually_managed]);
- }
- break;
+ return std::make_pair(
+ fmt::format("BPMEM_TX_SETIMAGE1 Texture Unit {}", cmd - BPMEM_TX_SETIMAGE1),
+ fmt::to_string(TexImage1{.hex = cmddata}));
case BPMEM_TX_SETIMAGE2: // 0x90
case BPMEM_TX_SETIMAGE2 + 1:
case BPMEM_TX_SETIMAGE2 + 2:
case BPMEM_TX_SETIMAGE2 + 3:
- case BPMEM_TX_SETIMAGE2_4: // 0xB0
- case BPMEM_TX_SETIMAGE2_4 + 1:
- case BPMEM_TX_SETIMAGE2_4 + 2:
- case BPMEM_TX_SETIMAGE2_4 + 3:
- {
- SetRegName(BPMEM_TX_SETIMAGE2);
- int texnum =
- (cmd < BPMEM_TX_SETIMAGE2_4) ? cmd - BPMEM_TX_SETIMAGE2 : cmd - BPMEM_TX_SETIMAGE2_4 + 4;
- TexImage2 teximg;
- teximg.hex = cmddata;
- *desc = fmt::format("Texture Unit: {}\n"
- "Odd TMEM Offset: {:x}\n"
- "Odd TMEM Width: {}\n"
- "Odd TMEM Height: {}\n",
- texnum, u32(teximg.tmem_odd), u32(teximg.cache_width),
- u32(teximg.cache_height));
- }
- break;
+ return std::make_pair(
+ fmt::format("BPMEM_TX_SETIMAGE2 Texture Unit {}", cmd - BPMEM_TX_SETIMAGE2),
+ fmt::to_string(TexImage2{.hex = cmddata}));
case BPMEM_TX_SETIMAGE3: // 0x94
case BPMEM_TX_SETIMAGE3 + 1:
case BPMEM_TX_SETIMAGE3 + 2:
case BPMEM_TX_SETIMAGE3 + 3:
- case BPMEM_TX_SETIMAGE3_4: // 0xB4
- case BPMEM_TX_SETIMAGE3_4 + 1:
- case BPMEM_TX_SETIMAGE3_4 + 2:
- case BPMEM_TX_SETIMAGE3_4 + 3:
- {
- SetRegName(BPMEM_TX_SETIMAGE3);
- int texnum =
- (cmd < BPMEM_TX_SETIMAGE3_4) ? cmd - BPMEM_TX_SETIMAGE3 : cmd - BPMEM_TX_SETIMAGE3_4 + 4;
- TexImage3 teximg;
- teximg.hex = cmddata;
- *desc = fmt::format("Texture {} source address (32 byte aligned): 0x{:06X}", texnum,
- teximg.image_base << 5);
- }
- break;
+ return std::make_pair(
+ fmt::format("BPMEM_TX_SETIMAGE3 Texture Unit {}", cmd - BPMEM_TX_SETIMAGE3),
+ fmt::to_string(TexImage3{.hex = cmddata}));
case BPMEM_TX_SETTLUT: // 0x98
case BPMEM_TX_SETTLUT + 1:
case BPMEM_TX_SETTLUT + 2:
case BPMEM_TX_SETTLUT + 3:
+ return std::make_pair(fmt::format("BPMEM_TX_SETTLUT Texture Unit {}", cmd - BPMEM_TX_SETTLUT),
+ fmt::to_string(TexTLUT{.hex = cmddata}));
+
+ case BPMEM_TX_SETMODE0_4: // 0xA0
+ case BPMEM_TX_SETMODE0_4 + 1:
+ case BPMEM_TX_SETMODE0_4 + 2:
+ case BPMEM_TX_SETMODE0_4 + 3:
+ return std::make_pair(
+ fmt::format("BPMEM_TX_SETMODE0_4 Texture Unit {}", cmd - BPMEM_TX_SETMODE0_4 + 4),
+ fmt::to_string(TexMode0{.hex = cmddata}));
+
+ case BPMEM_TX_SETMODE1_4: // 0xA4
+ case BPMEM_TX_SETMODE1_4 + 1:
+ case BPMEM_TX_SETMODE1_4 + 2:
+ case BPMEM_TX_SETMODE1_4 + 3:
+ return std::make_pair(
+ fmt::format("BPMEM_TX_SETMODE1_4 Texture Unit {}", cmd - BPMEM_TX_SETMODE1_4 + 4),
+ fmt::to_string(TexMode1{.hex = cmddata}));
+
+ case BPMEM_TX_SETIMAGE0_4: // 0xA8
+ case BPMEM_TX_SETIMAGE0_4 + 1:
+ case BPMEM_TX_SETIMAGE0_4 + 2:
+ case BPMEM_TX_SETIMAGE0_4 + 3:
+ return std::make_pair(
+ fmt::format("BPMEM_TX_SETIMAGE0_4 Texture Unit {}", cmd - BPMEM_TX_SETIMAGE0_4 + 4),
+ fmt::to_string(TexImage0{.hex = cmddata}));
+
+ case BPMEM_TX_SETIMAGE1_4: // 0xAC
+ case BPMEM_TX_SETIMAGE1_4 + 1:
+ case BPMEM_TX_SETIMAGE1_4 + 2:
+ case BPMEM_TX_SETIMAGE1_4 + 3:
+ return std::make_pair(
+ fmt::format("BPMEM_TX_SETIMAGE1_4 Texture Unit {}", cmd - BPMEM_TX_SETIMAGE1_4 + 4),
+ fmt::to_string(TexImage1{.hex = cmddata}));
+
+ case BPMEM_TX_SETIMAGE2_4: // 0xB0
+ case BPMEM_TX_SETIMAGE2_4 + 1:
+ case BPMEM_TX_SETIMAGE2_4 + 2:
+ case BPMEM_TX_SETIMAGE2_4 + 3:
+ return std::make_pair(
+ fmt::format("BPMEM_TX_SETIMAGE2_4 Texture Unit {}", cmd - BPMEM_TX_SETIMAGE2_4 + 4),
+ fmt::to_string(TexImage2{.hex = cmddata}));
+
+ case BPMEM_TX_SETIMAGE3_4: // 0xB4
+ case BPMEM_TX_SETIMAGE3_4 + 1:
+ case BPMEM_TX_SETIMAGE3_4 + 2:
+ case BPMEM_TX_SETIMAGE3_4 + 3:
+ return std::make_pair(
+ fmt::format("BPMEM_TX_SETIMAGE3_4 Texture Unit {}", cmd - BPMEM_TX_SETIMAGE3_4 + 4),
+ fmt::to_string(TexImage3{.hex = cmddata}));
+
case BPMEM_TX_SETTLUT_4: // 0xB8
case BPMEM_TX_SETTLUT_4 + 1:
case BPMEM_TX_SETTLUT_4 + 2:
case BPMEM_TX_SETTLUT_4 + 3:
- SetRegName(BPMEM_TX_SETTLUT);
- // TODO: Description
- break;
+ return std::make_pair(
+ fmt::format("BPMEM_TX_SETTLUT_4 Texture Unit {}", cmd - BPMEM_TX_SETTLUT_4 + 4),
+ fmt::to_string(TexTLUT{.hex = cmddata}));
case BPMEM_TEV_COLOR_ENV: // 0xC0
case BPMEM_TEV_COLOR_ENV + 2:
case BPMEM_TEV_COLOR_ENV + 4:
+ case BPMEM_TEV_COLOR_ENV + 6:
case BPMEM_TEV_COLOR_ENV + 8:
case BPMEM_TEV_COLOR_ENV + 10:
case BPMEM_TEV_COLOR_ENV + 12:
@@ -1258,24 +1176,9 @@ void GetBPRegInfo(const u8* data, std::string* name, std::string* desc)
case BPMEM_TEV_COLOR_ENV + 26:
case BPMEM_TEV_COLOR_ENV + 28:
case BPMEM_TEV_COLOR_ENV + 30:
- {
- SetRegName(BPMEM_TEV_COLOR_ENV);
- TevStageCombiner::ColorCombiner cc;
- cc.hex = cmddata;
- *desc = fmt::format("Tev stage: {}\n"
- "a: {}\n"
- "b: {}\n"
- "c: {}\n"
- "d: {}\n"
- "Bias: {}\n"
- "Op: {}\n"
- "Clamp: {}\n"
- "Scale factor: {}\n"
- "Dest: {}\n",
- (data[0] - BPMEM_TEV_COLOR_ENV) / 2, cc.a, cc.b, cc.c, cc.d, cc.bias, cc.op,
- no_yes[cc.clamp], cc.scale, cc.dest);
- break;
- }
+ return std::make_pair(
+ fmt::format("BPMEM_TEV_COLOR_ENV Tev stage {}", (cmd - BPMEM_TEV_COLOR_ENV) / 2),
+ fmt::to_string(TevStageCombiner::ColorCombiner{.hex = cmddata}));
case BPMEM_TEV_ALPHA_ENV: // 0xC1
case BPMEM_TEV_ALPHA_ENV + 2:
@@ -1293,99 +1196,65 @@ void GetBPRegInfo(const u8* data, std::string* name, std::string* desc)
case BPMEM_TEV_ALPHA_ENV + 26:
case BPMEM_TEV_ALPHA_ENV + 28:
case BPMEM_TEV_ALPHA_ENV + 30:
- {
- SetRegName(BPMEM_TEV_ALPHA_ENV);
- TevStageCombiner::AlphaCombiner ac;
- ac.hex = cmddata;
- *desc = fmt::format("Tev stage: {}\n"
- "a: {}\n"
- "b: {}\n"
- "c: {}\n"
- "d: {}\n"
- "Bias: {}\n"
- "Op: {}\n"
- "Clamp: {}\n"
- "Scale factor: {}\n"
- "Dest: {}\n"
- "Ras sel: {}\n"
- "Tex sel: {}\n",
- (data[0] - BPMEM_TEV_ALPHA_ENV) / 2, ac.a, ac.b, ac.c, ac.d, ac.bias, ac.op,
- no_yes[ac.clamp], ac.scale, ac.dest, ac.rswap.Value(), ac.tswap.Value());
- break;
- }
+ return std::make_pair(
+ fmt::format("BPMEM_TEV_ALPHA_ENV Tev stage {}", (cmd - BPMEM_TEV_ALPHA_ENV) / 2),
+ fmt::to_string(TevStageCombiner::AlphaCombiner{.hex = cmddata}));
case BPMEM_TEV_COLOR_RA: // 0xE0
case BPMEM_TEV_COLOR_RA + 2: // 0xE2
case BPMEM_TEV_COLOR_RA + 4: // 0xE4
case BPMEM_TEV_COLOR_RA + 6: // 0xE6
- SetRegName(BPMEM_TEV_COLOR_RA);
- // TODO: Description
- break;
+ return std::make_pair(
+ fmt::format("BPMEM_TEV_COLOR_RA Tev register {}", (cmd - BPMEM_TEV_COLOR_RA) / 2),
+ fmt::to_string(TevReg::RA{.hex = cmddata}));
case BPMEM_TEV_COLOR_BG: // 0xE1
case BPMEM_TEV_COLOR_BG + 2: // 0xE3
case BPMEM_TEV_COLOR_BG + 4: // 0xE5
case BPMEM_TEV_COLOR_BG + 6: // 0xE7
- SetRegName(BPMEM_TEV_COLOR_BG);
- // TODO: Description
- break;
+ return std::make_pair(
+ fmt::format("BPMEM_TEV_COLOR_BG Tev register {}", (cmd - BPMEM_TEV_COLOR_BG) / 2),
+ fmt::to_string(TevReg::BG{.hex = cmddata}));
case BPMEM_FOGRANGE: // 0xE8
+ return std::make_pair("BPMEM_FOGRANGE Base",
+ fmt::to_string(FogRangeParams::RangeBase{.hex = cmddata}));
+
case BPMEM_FOGRANGE + 1:
case BPMEM_FOGRANGE + 2:
case BPMEM_FOGRANGE + 3:
case BPMEM_FOGRANGE + 4:
case BPMEM_FOGRANGE + 5:
- SetRegName(BPMEM_FOGRANGE);
- // TODO: Description
- break;
+ return std::make_pair(fmt::format("BPMEM_FOGRANGE K element {}", cmd - BPMEM_FOGRANGE),
+ fmt::to_string(FogRangeKElement{.HEX = cmddata}));
case BPMEM_FOGPARAM0: // 0xEE
- SetRegName(BPMEM_FOGPARAM0);
- // TODO: Description
- break;
+ return std::make_pair(RegName(BPMEM_FOGPARAM0), fmt::to_string(FogParam0{.hex = cmddata}));
case BPMEM_FOGBMAGNITUDE: // 0xEF
- SetRegName(BPMEM_FOGBMAGNITUDE);
+ return DescriptionlessReg(BPMEM_FOGBMAGNITUDE);
// TODO: Description
- break;
case BPMEM_FOGBEXPONENT: // 0xF0
- SetRegName(BPMEM_FOGBEXPONENT);
+ return DescriptionlessReg(BPMEM_FOGBEXPONENT);
// TODO: Description
- break;
case BPMEM_FOGPARAM3: // 0xF1
- SetRegName(BPMEM_FOGPARAM3);
- // TODO: Description
- break;
+ return std::make_pair(RegName(BPMEM_FOGPARAM3), fmt::to_string(FogParam3{.hex = cmddata}));
case BPMEM_FOGCOLOR: // 0xF2
- SetRegName(BPMEM_FOGCOLOR);
- // TODO: Description
- break;
+ return std::make_pair(RegName(BPMEM_FOGCOLOR),
+ fmt::to_string(FogParams::FogColor{.hex = cmddata}));
case BPMEM_ALPHACOMPARE: // 0xF3
- {
- SetRegName(BPMEM_ALPHACOMPARE);
- AlphaTest test;
- test.hex = cmddata;
- *desc = fmt::format("Test 1: {} (ref: 0x{:02x})\n"
- "Test 2: {} (ref: 0x{:02x})\n"
- "Logic: {}\n",
- test.comp0, test.ref0.Value(), test.comp1, test.ref1.Value(), test.logic);
- break;
- }
+ return std::make_pair(RegName(BPMEM_ALPHACOMPARE), fmt::to_string(AlphaTest{.hex = cmddata}));
case BPMEM_BIAS: // 0xF4
- SetRegName(BPMEM_BIAS);
+ return DescriptionlessReg(BPMEM_BIAS);
// TODO: Description
- break;
case BPMEM_ZTEX2: // 0xF5
- SetRegName(BPMEM_ZTEX2);
- // TODO: Description
- break;
+ return std::make_pair(RegName(BPMEM_ZTEX2), fmt::to_string(ZTex2{.hex = cmddata}));
case BPMEM_TEV_KSEL: // 0xF6
case BPMEM_TEV_KSEL + 1:
@@ -1395,11 +1264,20 @@ void GetBPRegInfo(const u8* data, std::string* name, std::string* desc)
case BPMEM_TEV_KSEL + 5:
case BPMEM_TEV_KSEL + 6:
case BPMEM_TEV_KSEL + 7:
- SetRegName(BPMEM_TEV_KSEL);
- // TODO: Description
- break;
+ return std::make_pair(fmt::format("BPMEM_TEV_KSEL number {}", cmd - BPMEM_TEV_KSEL),
+ fmt::to_string(TevKSel{.hex = cmddata}));
+
+ case BPMEM_BP_MASK: // 0xFE
+ return std::make_pair(RegName(BPMEM_BP_MASK),
+ fmt::format("The next BP command will only update these bits; others "
+ "will retain their prior values: {:06x}",
+ cmddata));
+
+ default:
+ return std::make_pair(fmt::format("Unknown BP Reg: {:02x}={:06x}", cmd, cmddata), "");
-#undef SetRegName
+#undef DescriptionlessReg
+#undef RegName
}
}