From 1fe94ffe813d70287ee91f78b283976c2519fd80 Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Sun, 7 Feb 2021 15:25:11 -0800 Subject: [PATCH] Use formatters in GetBPRegInfo; add missing commands BPMEM_TEV_COLOR_ENV + 6 (0xC6) was missing due to a typo. BPMEM_BP_MASK (0xFE) does not lend itself well to documentation with the current FIFO analyzer implementation (since it requires remembering the values in BP memory) but still shouldn't be treated as unknown. BPMEM_TX_SETMODE0_4 and BPMEM_TX_SETMODE1_4 (0xA4-0xAB) were missing entirely. --- Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp | 28 +- Source/Core/VideoCommon/BPMemory.h | 561 +++++++++++++++++- Source/Core/VideoCommon/BPStructs.cpp | 610 ++++++++------------ 3 files changed, 821 insertions(+), 378 deletions(-) diff --git a/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp b/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp index 8764e30b1993..4b9020ab8f59 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 2a8d8ba0dd39..035fa5531ef1 100644 --- a/Source/Core/VideoCommon/BPMemory.h +++ b/Source/Core/VideoCommon/BPMemory.h @@ -6,8 +6,10 @@ #include #include +#include #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 +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + 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 +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + 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 +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + 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 +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + 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 +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + 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 +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + 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 +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + 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 +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + 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 +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + 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 +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + 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 +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + 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 +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + 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 +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + 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 +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + 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 +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + 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 +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + 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 +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const BlendMode& mode, FormatContext& ctx) + { + static constexpr std::array 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 +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + 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 +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + 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 +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + 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 +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + 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 +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + 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 +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + 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 +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + 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 +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + 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 +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + 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 +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + 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 +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + 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 : EnumFormatter +{ + formatter() : EnumFormatter({"Color", "Constant"}) {} +}; struct TevReg { @@ -1086,6 +1523,37 @@ struct TevReg RA ra; BG bg; }; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + 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 +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + 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 +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + 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 +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + 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 +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + 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(target_pixel_format / 2 + (target_pixel_format & 1) * 8); } }; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const UPE_Copy& copy, FormatContext& ctx) + { + static constexpr std::array 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 +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + 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 GetBPRegInfo(u8 cmd, u32 cmddata); diff --git a/Source/Core/VideoCommon/BPStructs.cpp b/Source/Core/VideoCommon/BPStructs.cpp index d0418e928944..2ad90a350a3c 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 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(row0) / (1 << 10); + const float row1f = static_cast(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(cmddata) / 256.f, 256.f / static_cast(cmddata)); - break; + return std::make_pair( + RegName(BPMEM_COPYYSCALE), + fmt::format("Y scaling factor (XFB copy only): 0x{:X} ({}, reciprocal {})", cmddata, + static_cast(cmddata) / 256.f, 256.f / static_cast(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(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 } }