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 #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 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 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})); -#undef SetRegName + 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 DescriptionlessReg +#undef RegName } }