From 4cc442d7cd3af4ddc0f887d2b701036ac5354e9b Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Wed, 10 Mar 2021 12:48:52 -0800 Subject: [PATCH 01/24] Use CP constants in FifoAnalyzer --- Source/Core/Core/FifoPlayer/FifoAnalyzer.cpp | 32 +++++++++---------- Source/Core/Core/FifoPlayer/FifoAnalyzer.h | 6 ++-- .../Core/FifoPlayer/FifoPlaybackAnalyzer.cpp | 12 +++---- .../Core/FifoPlayer/FifoRecordAnalyzer.cpp | 12 +++---- 4 files changed, 31 insertions(+), 31 deletions(-) diff --git a/Source/Core/Core/FifoPlayer/FifoAnalyzer.cpp b/Source/Core/Core/FifoPlayer/FifoAnalyzer.cpp index e19bc22139..27936506e5 100644 --- a/Source/Core/Core/FifoPlayer/FifoAnalyzer.cpp +++ b/Source/Core/Core/FifoPlayer/FifoAnalyzer.cpp @@ -258,37 +258,37 @@ u32 AnalyzeCommand(const u8* data, DecodeMode mode) void LoadCPReg(u32 subCmd, u32 value, CPMemory& cpMem) { - switch (subCmd & 0xF0) + switch (subCmd & CP_COMMAND_MASK) { - case 0x50: + case VCD_LO: cpMem.vtxDesc.low.Hex = value; break; - case 0x60: + case VCD_HI: cpMem.vtxDesc.high.Hex = value; break; - case 0x70: - ASSERT((subCmd & 0x0F) < 8); - cpMem.vtxAttr[subCmd & 7].g0.Hex = value; + case CP_VAT_REG_A: + ASSERT(subCmd - CP_VAT_REG_A < CP_NUM_VAT_REG); + cpMem.vtxAttr[subCmd & CP_VAT_MASK].g0.Hex = value; break; - case 0x80: - ASSERT((subCmd & 0x0F) < 8); - cpMem.vtxAttr[subCmd & 7].g1.Hex = value; + case CP_VAT_REG_B: + ASSERT(subCmd - CP_VAT_REG_B < CP_NUM_VAT_REG); + cpMem.vtxAttr[subCmd & CP_VAT_MASK].g1.Hex = value; break; - case 0x90: - ASSERT((subCmd & 0x0F) < 8); - cpMem.vtxAttr[subCmd & 7].g2.Hex = value; + case CP_VAT_REG_C: + ASSERT(subCmd - CP_VAT_REG_C < CP_NUM_VAT_REG); + cpMem.vtxAttr[subCmd & CP_VAT_MASK].g2.Hex = value; break; - case 0xA0: - cpMem.arrayBases[subCmd & 0xF] = value; + case ARRAY_BASE: + cpMem.arrayBases[subCmd & CP_ARRAY_MASK] = value; break; - case 0xB0: - cpMem.arrayStrides[subCmd & 0xF] = value & 0xFF; + case ARRAY_STRIDE: + cpMem.arrayStrides[subCmd & CP_ARRAY_MASK] = value & 0xFF; break; } } diff --git a/Source/Core/Core/FifoPlayer/FifoAnalyzer.h b/Source/Core/Core/FifoPlayer/FifoAnalyzer.h index 5f1d883ba2..4adfc4e259 100644 --- a/Source/Core/Core/FifoPlayer/FifoAnalyzer.h +++ b/Source/Core/Core/FifoPlayer/FifoAnalyzer.h @@ -22,9 +22,9 @@ u32 AnalyzeCommand(const u8* data, DecodeMode mode); struct CPMemory { TVtxDesc vtxDesc; - std::array vtxAttr; - std::array arrayBases; - std::array arrayStrides; + std::array vtxAttr; + std::array arrayBases; + std::array arrayStrides; }; void LoadCPReg(u32 subCmd, u32 value, CPMemory& cpMem); diff --git a/Source/Core/Core/FifoPlayer/FifoPlaybackAnalyzer.cpp b/Source/Core/Core/FifoPlayer/FifoPlaybackAnalyzer.cpp index 4b8da762bc..84dda8d8c5 100644 --- a/Source/Core/Core/FifoPlayer/FifoPlaybackAnalyzer.cpp +++ b/Source/Core/Core/FifoPlayer/FifoPlaybackAnalyzer.cpp @@ -25,14 +25,14 @@ void FifoPlaybackAnalyzer::AnalyzeFrames(FifoDataFile* file, std::vector& frameInfo) { u32* cpMem = file->GetCPMem(); - FifoAnalyzer::LoadCPReg(0x50, cpMem[0x50], s_CpMem); - FifoAnalyzer::LoadCPReg(0x60, cpMem[0x60], s_CpMem); + FifoAnalyzer::LoadCPReg(VCD_LO, cpMem[VCD_LO], s_CpMem); + FifoAnalyzer::LoadCPReg(VCD_HI, cpMem[VCD_HI], s_CpMem); - for (int i = 0; i < 8; ++i) + for (u32 i = 0; i < CP_NUM_VAT_REG; ++i) { - FifoAnalyzer::LoadCPReg(0x70 + i, cpMem[0x70 + i], s_CpMem); - FifoAnalyzer::LoadCPReg(0x80 + i, cpMem[0x80 + i], s_CpMem); - FifoAnalyzer::LoadCPReg(0x90 + i, cpMem[0x90 + i], s_CpMem); + FifoAnalyzer::LoadCPReg(CP_VAT_REG_A + i, cpMem[CP_VAT_REG_A + i], s_CpMem); + FifoAnalyzer::LoadCPReg(CP_VAT_REG_B + i, cpMem[CP_VAT_REG_B + i], s_CpMem); + FifoAnalyzer::LoadCPReg(CP_VAT_REG_C + i, cpMem[CP_VAT_REG_C + i], s_CpMem); } frameInfo.clear(); diff --git a/Source/Core/Core/FifoPlayer/FifoRecordAnalyzer.cpp b/Source/Core/Core/FifoPlayer/FifoRecordAnalyzer.cpp index c9c88c6bb8..9f8a3266ac 100644 --- a/Source/Core/Core/FifoPlayer/FifoRecordAnalyzer.cpp +++ b/Source/Core/Core/FifoPlayer/FifoRecordAnalyzer.cpp @@ -17,16 +17,16 @@ void FifoRecordAnalyzer::Initialize(const u32* cpMem) { s_DrawingObject = false; - FifoAnalyzer::LoadCPReg(0x50, *(cpMem + 0x50), s_CpMem); - FifoAnalyzer::LoadCPReg(0x60, *(cpMem + 0x60), s_CpMem); - for (int i = 0; i < 8; ++i) - FifoAnalyzer::LoadCPReg(0x70 + i, *(cpMem + 0x70 + i), s_CpMem); + FifoAnalyzer::LoadCPReg(VCD_LO, cpMem[VCD_LO], s_CpMem); + FifoAnalyzer::LoadCPReg(VCD_HI, cpMem[VCD_HI], s_CpMem); + for (u32 i = 0; i < CP_NUM_VAT_REG; ++i) + FifoAnalyzer::LoadCPReg(CP_VAT_REG_A + i, cpMem[CP_VAT_REG_A + i], s_CpMem); - const u32* const bases_start = cpMem + 0xA0; + const u32* const bases_start = cpMem + ARRAY_BASE; const u32* const bases_end = bases_start + s_CpMem.arrayBases.size(); std::copy(bases_start, bases_end, s_CpMem.arrayBases.begin()); - const u32* const strides_start = cpMem + 0xB0; + const u32* const strides_start = cpMem + ARRAY_STRIDE; const u32* const strides_end = strides_start + s_CpMem.arrayStrides.size(); std::copy(strides_start, strides_end, s_CpMem.arrayStrides.begin()); } From bc7da726a5b8cc8e9c229a62796993a9e1119362 Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Wed, 10 Mar 2021 17:11:45 -0800 Subject: [PATCH 02/24] Convert VertexLoader_Color to a table --- Source/Core/VideoCommon/VertexLoader.cpp | 102 ++---------------- .../Core/VideoCommon/VertexLoader_Color.cpp | 82 +++++++------- Source/Core/VideoCommon/VertexLoader_Color.h | 30 ++---- 3 files changed, 57 insertions(+), 157 deletions(-) diff --git a/Source/Core/VideoCommon/VertexLoader.cpp b/Source/Core/VideoCommon/VertexLoader.cpp index f06b60a430..f51b27518f 100644 --- a/Source/Core/VideoCommon/VertexLoader.cpp +++ b/Source/Core/VideoCommon/VertexLoader.cpp @@ -205,98 +205,16 @@ void VertexLoader::CompileVertexTranslator() m_native_vtx_decl.colors[i].components = 4; m_native_vtx_decl.colors[i].type = VAR_UNSIGNED_BYTE; m_native_vtx_decl.colors[i].integer = false; - switch (m_VtxDesc.low.Color[i]) - { - case VertexComponentFormat::NotPresent: - break; - case VertexComponentFormat::Direct: - switch (m_VtxAttr.color[i].Comp) - { - case ColorFormat::RGB565: - m_VertexSize += 2; - WriteCall(Color_ReadDirect_16b_565); - break; - case ColorFormat::RGB888: - m_VertexSize += 3; - WriteCall(Color_ReadDirect_24b_888); - break; - case ColorFormat::RGB888x: - m_VertexSize += 4; - WriteCall(Color_ReadDirect_32b_888x); - break; - case ColorFormat::RGBA4444: - m_VertexSize += 2; - WriteCall(Color_ReadDirect_16b_4444); - break; - case ColorFormat::RGBA6666: - m_VertexSize += 3; - WriteCall(Color_ReadDirect_24b_6666); - break; - case ColorFormat::RGBA8888: - m_VertexSize += 4; - WriteCall(Color_ReadDirect_32b_8888); - break; - default: - ASSERT(0); - break; - } - break; - case VertexComponentFormat::Index8: - m_VertexSize += 1; - switch (m_VtxAttr.color[i].Comp) - { - case ColorFormat::RGB565: - WriteCall(Color_ReadIndex8_16b_565); - break; - case ColorFormat::RGB888: - WriteCall(Color_ReadIndex8_24b_888); - break; - case ColorFormat::RGB888x: - WriteCall(Color_ReadIndex8_32b_888x); - break; - case ColorFormat::RGBA4444: - WriteCall(Color_ReadIndex8_16b_4444); - break; - case ColorFormat::RGBA6666: - WriteCall(Color_ReadIndex8_24b_6666); - break; - case ColorFormat::RGBA8888: - WriteCall(Color_ReadIndex8_32b_8888); - break; - default: - ASSERT(0); - break; - } - break; - case VertexComponentFormat::Index16: - m_VertexSize += 2; - switch (m_VtxAttr.color[i].Comp) - { - case ColorFormat::RGB565: - WriteCall(Color_ReadIndex16_16b_565); - break; - case ColorFormat::RGB888: - WriteCall(Color_ReadIndex16_24b_888); - break; - case ColorFormat::RGB888x: - WriteCall(Color_ReadIndex16_32b_888x); - break; - case ColorFormat::RGBA4444: - WriteCall(Color_ReadIndex16_16b_4444); - break; - case ColorFormat::RGBA6666: - WriteCall(Color_ReadIndex16_24b_6666); - break; - case ColorFormat::RGBA8888: - WriteCall(Color_ReadIndex16_32b_8888); - break; - default: - ASSERT(0); - break; - } - break; - } - // Common for the three bottom cases + + m_VertexSize += VertexLoader_Color::GetSize(m_VtxDesc.low.Color[i], m_VtxAttr.color[i].Comp); + TPipelineFunction pFunc = + VertexLoader_Color::GetFunction(m_VtxDesc.low.Color[i], m_VtxAttr.color[i].Comp); + + if (pFunc != nullptr) + WriteCall(pFunc); + else + ASSERT(m_VtxDesc.low.Color[i] == VertexComponentFormat::NotPresent); + if (m_VtxDesc.low.Color[i] != VertexComponentFormat::NotPresent) { components |= VB_HAS_COL0 << i; diff --git a/Source/Core/VideoCommon/VertexLoader_Color.cpp b/Source/Core/VideoCommon/VertexLoader_Color.cpp index cef347346d..75d16ee458 100644 --- a/Source/Core/VideoCommon/VertexLoader_Color.cpp +++ b/Source/Core/VideoCommon/VertexLoader_Color.cpp @@ -5,6 +5,7 @@ #include #include "Common/CommonTypes.h" +#include "Common/MsgHandler.h" #include "Common/Swap.h" #include "VideoCommon/VertexLoader.h" @@ -136,7 +137,6 @@ void Color_ReadIndex_32b_8888(VertexLoader* loader) (index * g_main_cp_state.array_strides[ARRAY_COLOR0 + loader->m_colIndex]); SetCol(loader, Read32(address)); } -} // Anonymous namespace void Color_ReadDirect_24b_888(VertexLoader* loader) { @@ -149,10 +149,12 @@ void Color_ReadDirect_32b_888x(VertexLoader* loader) SetCol(loader, Read24(DataGetPosition())); DataSkip(4); } + void Color_ReadDirect_16b_565(VertexLoader* loader) { SetCol565(loader, DataRead()); } + void Color_ReadDirect_16b_4444(VertexLoader* loader) { u16 value; @@ -161,62 +163,52 @@ void Color_ReadDirect_16b_4444(VertexLoader* loader) SetCol4444(loader, value); DataSkip(2); } + void Color_ReadDirect_24b_6666(VertexLoader* loader) { SetCol6666(loader, Common::swap32(DataGetPosition() - 1)); DataSkip(3); } + void Color_ReadDirect_32b_8888(VertexLoader* loader) { SetCol(loader, DataReadU32Unswapped()); } -void Color_ReadIndex8_16b_565(VertexLoader* loader) +constexpr TPipelineFunction s_table_read_color[4][6] = { + {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}, + {Color_ReadDirect_16b_565, Color_ReadDirect_24b_888, Color_ReadDirect_32b_888x, + Color_ReadDirect_16b_4444, Color_ReadDirect_24b_6666, Color_ReadDirect_32b_8888}, + {Color_ReadIndex_16b_565, Color_ReadIndex_24b_888, Color_ReadIndex_32b_888x, + Color_ReadIndex_16b_4444, Color_ReadIndex_24b_6666, Color_ReadIndex_32b_8888}, + {Color_ReadIndex_16b_565, Color_ReadIndex_24b_888, Color_ReadIndex_32b_888x, + Color_ReadIndex_16b_4444, Color_ReadIndex_24b_6666, Color_ReadIndex_32b_8888}, +}; + +constexpr u32 s_table_read_color_vertex_size[4][6] = { + {0, 0, 0, 0, 0, 0}, + {2, 3, 4, 2, 3, 4}, + {1, 1, 1, 1, 1, 1}, + {2, 2, 2, 2, 2, 2}, +}; +} // Anonymous namespace + +u32 VertexLoader_Color::GetSize(VertexComponentFormat type, ColorFormat format) { - Color_ReadIndex_16b_565(loader); -} -void Color_ReadIndex8_24b_888(VertexLoader* loader) -{ - Color_ReadIndex_24b_888(loader); -} -void Color_ReadIndex8_32b_888x(VertexLoader* loader) -{ - Color_ReadIndex_32b_888x(loader); -} -void Color_ReadIndex8_16b_4444(VertexLoader* loader) -{ - Color_ReadIndex_16b_4444(loader); -} -void Color_ReadIndex8_24b_6666(VertexLoader* loader) -{ - Color_ReadIndex_24b_6666(loader); -} -void Color_ReadIndex8_32b_8888(VertexLoader* loader) -{ - Color_ReadIndex_32b_8888(loader); + if (format > ColorFormat::RGBA8888) + { + PanicAlertFmt("Invalid color format {}", format); + return 0; + } + return s_table_read_color_vertex_size[u32(type)][u32(format)]; } -void Color_ReadIndex16_16b_565(VertexLoader* loader) +TPipelineFunction VertexLoader_Color::GetFunction(VertexComponentFormat type, ColorFormat format) { - Color_ReadIndex_16b_565(loader); -} -void Color_ReadIndex16_24b_888(VertexLoader* loader) -{ - Color_ReadIndex_24b_888(loader); -} -void Color_ReadIndex16_32b_888x(VertexLoader* loader) -{ - Color_ReadIndex_32b_888x(loader); -} -void Color_ReadIndex16_16b_4444(VertexLoader* loader) -{ - Color_ReadIndex_16b_4444(loader); -} -void Color_ReadIndex16_24b_6666(VertexLoader* loader) -{ - Color_ReadIndex_24b_6666(loader); -} -void Color_ReadIndex16_32b_8888(VertexLoader* loader) -{ - Color_ReadIndex_32b_8888(loader); + if (format > ColorFormat::RGBA8888) + { + PanicAlertFmt("Invalid color format {}", format); + return nullptr; + } + return s_table_read_color[u32(type)][u32(format)]; } diff --git a/Source/Core/VideoCommon/VertexLoader_Color.h b/Source/Core/VideoCommon/VertexLoader_Color.h index 0f83dc4b29..3fd8b078ea 100644 --- a/Source/Core/VideoCommon/VertexLoader_Color.h +++ b/Source/Core/VideoCommon/VertexLoader_Color.h @@ -4,25 +4,15 @@ #pragma once -class VertexLoader; +#include "Common/CommonTypes.h" +#include "VideoCommon/VertexLoader.h" -void Color_ReadDirect_24b_888(VertexLoader* loader); -void Color_ReadDirect_32b_888x(VertexLoader* loader); -void Color_ReadDirect_16b_565(VertexLoader* loader); -void Color_ReadDirect_16b_4444(VertexLoader* loader); -void Color_ReadDirect_24b_6666(VertexLoader* loader); -void Color_ReadDirect_32b_8888(VertexLoader* loader); +enum class VertexComponentFormat; +enum class ColorFormat; -void Color_ReadIndex8_16b_565(VertexLoader* loader); -void Color_ReadIndex8_24b_888(VertexLoader* loader); -void Color_ReadIndex8_32b_888x(VertexLoader* loader); -void Color_ReadIndex8_16b_4444(VertexLoader* loader); -void Color_ReadIndex8_24b_6666(VertexLoader* loader); -void Color_ReadIndex8_32b_8888(VertexLoader* loader); - -void Color_ReadIndex16_16b_565(VertexLoader* loader); -void Color_ReadIndex16_24b_888(VertexLoader* loader); -void Color_ReadIndex16_32b_888x(VertexLoader* loader); -void Color_ReadIndex16_16b_4444(VertexLoader* loader); -void Color_ReadIndex16_24b_6666(VertexLoader* loader); -void Color_ReadIndex16_32b_8888(VertexLoader* loader); +class VertexLoader_Color +{ +public: + static u32 GetSize(VertexComponentFormat type, ColorFormat format); + static TPipelineFunction GetFunction(VertexComponentFormat type, ColorFormat format); +}; From b6149623aae83ff278b7c3de9afd8d2e9bda94a3 Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Wed, 10 Mar 2021 18:48:26 -0800 Subject: [PATCH 03/24] Remove VertexLoader::ToString --- Source/Core/VideoCommon/CPMemory.h | 10 +++++ Source/Core/VideoCommon/VertexLoader.h | 1 - Source/Core/VideoCommon/VertexLoaderARM64.h | 1 - Source/Core/VideoCommon/VertexLoaderBase.cpp | 41 ------------------- Source/Core/VideoCommon/VertexLoaderBase.h | 5 --- .../Core/VideoCommon/VertexLoaderManager.cpp | 28 ------------- Source/Core/VideoCommon/VertexLoaderManager.h | 3 -- Source/Core/VideoCommon/VertexLoaderX64.cpp | 3 +- Source/Core/VideoCommon/VertexLoaderX64.h | 1 - 9 files changed, 12 insertions(+), 81 deletions(-) diff --git a/Source/Core/VideoCommon/CPMemory.h b/Source/Core/VideoCommon/CPMemory.h index f54445940f..5c50d30a85 100644 --- a/Source/Core/VideoCommon/CPMemory.h +++ b/Source/Core/VideoCommon/CPMemory.h @@ -524,6 +524,16 @@ struct VAT UVAT_group1 g1; UVAT_group2 g2; }; +template <> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const VAT& vat, FormatContext& ctx) + { + return format_to(ctx.out(), "{}\n{}\n{}", vat.g0, vat.g1, vat.g2); + } +}; class VertexLoaderBase; diff --git a/Source/Core/VideoCommon/VertexLoader.h b/Source/Core/VideoCommon/VertexLoader.h index 2caae086d3..73738c86b8 100644 --- a/Source/Core/VideoCommon/VertexLoader.h +++ b/Source/Core/VideoCommon/VertexLoader.h @@ -22,7 +22,6 @@ public: VertexLoader(const TVtxDesc& vtx_desc, const VAT& vtx_attr); int RunVertices(DataReader src, DataReader dst, int count) override; - std::string GetName() const override { return "OldLoader"; } bool IsInitialized() override { return true; } // This vertex loader supports all formats // They are used for the communication with the loader functions float m_posScale; diff --git a/Source/Core/VideoCommon/VertexLoaderARM64.h b/Source/Core/VideoCommon/VertexLoaderARM64.h index b7faec0239..6b18b59c0e 100644 --- a/Source/Core/VideoCommon/VertexLoaderARM64.h +++ b/Source/Core/VideoCommon/VertexLoaderARM64.h @@ -19,7 +19,6 @@ public: VertexLoaderARM64(const TVtxDesc& vtx_desc, const VAT& vtx_att); protected: - std::string GetName() const override { return "VertexLoaderARM64"; } bool IsInitialized() override { return true; } int RunVertices(DataReader src, DataReader dst, int count) override; diff --git a/Source/Core/VideoCommon/VertexLoaderBase.cpp b/Source/Core/VideoCommon/VertexLoaderBase.cpp index 483d46dd08..604ad1f04b 100644 --- a/Source/Core/VideoCommon/VertexLoaderBase.cpp +++ b/Source/Core/VideoCommon/VertexLoaderBase.cpp @@ -73,46 +73,6 @@ void VertexLoaderBase::SetVAT(const VAT& vat) m_VtxAttr.texCoord[7].Frac = vat.g2.Tex7Frac; }; -std::string VertexLoaderBase::ToString() const -{ - std::string dest; - dest.reserve(250); - - dest += GetName(); - dest += ": "; - - dest += fmt::format("{}b skin: {} P: {} {}-{} ", m_VertexSize, m_VtxDesc.low.PosMatIdx, - m_VtxAttr.PosElements, m_VtxDesc.low.Position, m_VtxAttr.PosFormat); - - if (m_VtxDesc.low.Normal != VertexComponentFormat::NotPresent) - { - dest += fmt::format("Nrm: {} {}-{} ", m_VtxAttr.NormalElements, m_VtxDesc.low.Normal, - m_VtxAttr.NormalFormat); - } - - for (size_t i = 0; i < g_main_cp_state.vtx_desc.low.Color.Size(); i++) - { - if (g_main_cp_state.vtx_desc.low.Color[i] == VertexComponentFormat::NotPresent) - continue; - - const auto& color = m_VtxAttr.color[i]; - dest += fmt::format("C{}: {} {}-{} ", i, color.Elements, g_main_cp_state.vtx_desc.low.Color[i], - color.Comp); - } - - for (size_t i = 0; i < g_main_cp_state.vtx_desc.high.TexCoord.Size(); i++) - { - if (g_main_cp_state.vtx_desc.high.TexCoord[i] == VertexComponentFormat::NotPresent) - continue; - - const auto& tex_coord = m_VtxAttr.texCoord[i]; - dest += fmt::format("T{}: {} {}-{} ", i, tex_coord.Elements, - g_main_cp_state.vtx_desc.high.TexCoord[i], tex_coord.Format); - } - dest += fmt::format(" - {} v", m_numLoadedVertices); - return dest; -} - // a hacky implementation to compare two vertex loaders class VertexLoaderTester : public VertexLoaderBase { @@ -178,7 +138,6 @@ public: m_numLoadedVertices += count; return count_a; } - std::string GetName() const override { return "CompareLoader"; } bool IsInitialized() override { return m_initialized; } private: diff --git a/Source/Core/VideoCommon/VertexLoaderBase.h b/Source/Core/VideoCommon/VertexLoaderBase.h index 77b66f629b..cf100fb4c6 100644 --- a/Source/Core/VideoCommon/VertexLoaderBase.h +++ b/Source/Core/VideoCommon/VertexLoaderBase.h @@ -67,11 +67,6 @@ public: virtual bool IsInitialized() = 0; - // For debugging / profiling - std::string ToString() const; - - virtual std::string GetName() const = 0; - // per loader public state int m_VertexSize = 0; // number of bytes of a raw GC vertex PortableVertexDeclaration m_native_vtx_decl{}; diff --git a/Source/Core/VideoCommon/VertexLoaderManager.cpp b/Source/Core/VideoCommon/VertexLoaderManager.cpp index 94a331a0d2..ab362fc29c 100644 --- a/Source/Core/VideoCommon/VertexLoaderManager.cpp +++ b/Source/Core/VideoCommon/VertexLoaderManager.cpp @@ -114,34 +114,6 @@ struct entry }; } // namespace -std::string VertexLoadersToString() -{ - std::lock_guard lk(s_vertex_loader_map_lock); - std::vector entries; - - size_t total_size = 0; - for (const auto& map_entry : s_vertex_loader_map) - { - entry e = {map_entry.second->ToString(), - static_cast(map_entry.second->m_numLoadedVertices)}; - - total_size += e.text.size() + 1; - entries.push_back(std::move(e)); - } - - sort(entries.begin(), entries.end()); - - std::string dest; - dest.reserve(total_size); - for (const entry& entry : entries) - { - dest += entry.text; - dest += '\n'; - } - - return dest; -} - void MarkAllDirty() { g_main_cp_state.attr_dirty = BitSet32::AllTrue(8); diff --git a/Source/Core/VideoCommon/VertexLoaderManager.h b/Source/Core/VideoCommon/VertexLoaderManager.h index 71188cca6b..74856a4d28 100644 --- a/Source/Core/VideoCommon/VertexLoaderManager.h +++ b/Source/Core/VideoCommon/VertexLoaderManager.h @@ -38,9 +38,6 @@ NativeVertexFormat* GetUberVertexFormat(const PortableVertexDeclaration& decl); // Returns -1 if buf_size is insufficient, else the amount of bytes consumed int RunVertices(int vtx_attr_group, int primitive, int count, DataReader src, bool is_preprocess); -// For debugging -std::string VertexLoadersToString(); - NativeVertexFormat* GetCurrentVertexFormat(); // Resolved pointers to array bases. Used by vertex loaders. diff --git a/Source/Core/VideoCommon/VertexLoaderX64.cpp b/Source/Core/VideoCommon/VertexLoaderX64.cpp index 2c0a97b54b..27ccad71b5 100644 --- a/Source/Core/VideoCommon/VertexLoaderX64.cpp +++ b/Source/Core/VideoCommon/VertexLoaderX64.cpp @@ -53,7 +53,8 @@ VertexLoaderX64::VertexLoaderX64(const TVtxDesc& vtx_desc, const VAT& vtx_att) GenerateVertexLoader(); WriteProtect(); - const std::string name = ToString(); + const std::string name = + fmt::format("VertexLoaderX64\nVtx desc: \n{}\nVAT:\n{}", vtx_desc, vtx_att); JitRegister::Register(region, GetCodePtr(), name.c_str()); } diff --git a/Source/Core/VideoCommon/VertexLoaderX64.h b/Source/Core/VideoCommon/VertexLoaderX64.h index 0344d7f1c9..4b3029066c 100644 --- a/Source/Core/VideoCommon/VertexLoaderX64.h +++ b/Source/Core/VideoCommon/VertexLoaderX64.h @@ -18,7 +18,6 @@ public: VertexLoaderX64(const TVtxDesc& vtx_desc, const VAT& vtx_att); protected: - std::string GetName() const override { return "VertexLoaderX64"; } bool IsInitialized() override { return true; } int RunVertices(DataReader src, DataReader dst, int count) override; From 252ef6bb3432a4fef363acf41c2d36b0899f8ec9 Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Wed, 10 Mar 2021 21:14:58 -0800 Subject: [PATCH 04/24] Use bool bitfields in VAT --- Source/Core/VideoCommon/CPMemory.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/Core/VideoCommon/CPMemory.h b/Source/Core/VideoCommon/CPMemory.h index 5c50d30a85..931cb587e5 100644 --- a/Source/Core/VideoCommon/CPMemory.h +++ b/Source/Core/VideoCommon/CPMemory.h @@ -319,8 +319,8 @@ union UVAT_group0 BitField<22, 3, ComponentFormat> Tex0CoordFormat; BitField<25, 5, u32> Tex0Frac; // 30:31 - BitField<30, 1, u32> ByteDequant; - BitField<31, 1, u32> NormalIndex3; + BitField<30, 1, bool, u32> ByteDequant; + BitField<31, 1, bool, u32> NormalIndex3; }; template <> struct fmt::formatter @@ -376,7 +376,7 @@ union UVAT_group1 BitField<27, 1, TexComponentCount> Tex4CoordElements; BitField<28, 3, ComponentFormat> Tex4CoordFormat; // 31 - BitField<31, 1, u32> VCacheEnhance; + BitField<31, 1, bool, u32> VCacheEnhance; }; template <> struct fmt::formatter From 0a71ce143a946e0ef3a1dc4ceb8390c250cab8a0 Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Thu, 11 Mar 2021 15:57:54 -0800 Subject: [PATCH 05/24] Extract VertexLoaderARM64::GetLoadSize into a new function --- Source/Core/VideoCommon/VertexLoaderARM64.cpp | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/Source/Core/VideoCommon/VertexLoaderARM64.cpp b/Source/Core/VideoCommon/VertexLoaderARM64.cpp index 94c821a26b..9fae16c59e 100644 --- a/Source/Core/VideoCommon/VertexLoaderARM64.cpp +++ b/Source/Core/VideoCommon/VertexLoaderARM64.cpp @@ -25,6 +25,20 @@ constexpr ARM64Reg stride_reg = ARM64Reg::X11; constexpr ARM64Reg arraybase_reg = ARM64Reg::X10; constexpr ARM64Reg scale_reg = ARM64Reg::X9; +static constexpr int GetLoadSize(int load_bytes) +{ + if (load_bytes == 1) + return 1; + else if (load_bytes <= 2) + return 2; + else if (load_bytes <= 4) + return 4; + else if (load_bytes <= 8) + return 8; + else + return 16; +} + alignas(16) static const float scale_factors[] = { 1.0 / (1ULL << 0), 1.0 / (1ULL << 1), 1.0 / (1ULL << 2), 1.0 / (1ULL << 3), 1.0 / (1ULL << 4), 1.0 / (1ULL << 5), 1.0 / (1ULL << 6), 1.0 / (1ULL << 7), @@ -120,8 +134,7 @@ int VertexLoaderARM64::ReadVertex(VertexComponentFormat attribute, ComponentForm int elem_size = GetElementSize(format); int load_bytes = elem_size * count_in; - int load_size = - load_bytes == 1 ? 1 : load_bytes <= 2 ? 2 : load_bytes <= 4 ? 4 : load_bytes <= 8 ? 8 : 16; + int load_size = GetLoadSize(load_bytes); load_size <<= 3; elem_size <<= 3; @@ -434,8 +447,7 @@ void VertexLoaderARM64::GenerateVertexLoader() int elem_size = GetElementSize(m_VtxAttr.PosFormat); int pos_elements = m_VtxAttr.PosElements == CoordComponentCount::XY ? 2 : 3; int load_bytes = elem_size * pos_elements; - int load_size = - load_bytes == 1 ? 1 : load_bytes <= 2 ? 2 : load_bytes <= 4 ? 4 : load_bytes <= 8 ? 8 : 16; + int load_size = GetLoadSize(load_bytes); load_size <<= 3; s32 offset = GetAddressImm(ARRAY_POSITION, m_VtxDesc.low.Position, EncodeRegTo64(scratch1_reg), @@ -458,9 +470,7 @@ void VertexLoaderARM64::GenerateVertexLoader() int elem_size = GetElementSize(m_VtxAttr.NormalFormat); int load_bytes = elem_size * 3; - int load_size = load_bytes == 1 ? - 1 : - load_bytes <= 2 ? 2 : load_bytes <= 4 ? 4 : load_bytes <= 8 ? 8 : 16; + int load_size = GetLoadSize(load_bytes); offset = GetAddressImm(ARRAY_NORMAL, m_VtxDesc.low.Normal, EncodeRegTo64(scratch1_reg), load_size << 3); @@ -523,9 +533,7 @@ void VertexLoaderARM64::GenerateVertexLoader() int elem_size = GetElementSize(m_VtxAttr.texCoord[i].Format); int load_bytes = elem_size * (elements + 2); - int load_size = load_bytes == 1 ? - 1 : - load_bytes <= 2 ? 2 : load_bytes <= 4 ? 4 : load_bytes <= 8 ? 8 : 16; + int load_size = GetLoadSize(load_bytes); load_size <<= 3; s32 offset = GetAddressImm(ARRAY_TEXCOORD0 + int(i), m_VtxDesc.high.TexCoord[i], From cafffff75ea4fc42c401b87370e94efe17309cad Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Wed, 10 Mar 2021 22:15:43 -0800 Subject: [PATCH 06/24] Eliminate TVtxAttr --- Source/Core/VideoCommon/CPMemory.h | 166 +++++++++++++----- Source/Core/VideoCommon/VertexLoader.cpp | 51 +++--- Source/Core/VideoCommon/VertexLoaderARM64.cpp | 45 ++--- Source/Core/VideoCommon/VertexLoaderBase.cpp | 51 +----- Source/Core/VideoCommon/VertexLoaderBase.h | 9 +- Source/Core/VideoCommon/VertexLoaderX64.cpp | 32 ++-- 6 files changed, 191 insertions(+), 163 deletions(-) diff --git a/Source/Core/VideoCommon/CPMemory.h b/Source/Core/VideoCommon/CPMemory.h index 931cb587e5..c82521ebb4 100644 --- a/Source/Core/VideoCommon/CPMemory.h +++ b/Source/Core/VideoCommon/CPMemory.h @@ -317,7 +317,7 @@ union UVAT_group0 // 21:29 BitField<21, 1, TexComponentCount> Tex0CoordElements; BitField<22, 3, ComponentFormat> Tex0CoordFormat; - BitField<25, 5, u32> Tex0Frac; + BitField<25, 5, u8, u32> Tex0Frac; // 30:31 BitField<30, 1, bool, u32> ByteDequant; BitField<31, 1, bool, u32> NormalIndex3; @@ -363,15 +363,15 @@ union UVAT_group1 // 0:8 BitField<0, 1, TexComponentCount> Tex1CoordElements; BitField<1, 3, ComponentFormat> Tex1CoordFormat; - BitField<4, 5, u32> Tex1Frac; + BitField<4, 5, u8, u32> Tex1Frac; // 9:17 BitField<9, 1, TexComponentCount> Tex2CoordElements; BitField<10, 3, ComponentFormat> Tex2CoordFormat; - BitField<13, 5, u32> Tex2Frac; + BitField<13, 5, u8, u32> Tex2Frac; // 18:26 BitField<18, 1, TexComponentCount> Tex3CoordElements; BitField<19, 3, ComponentFormat> Tex3CoordFormat; - BitField<22, 5, u32> Tex3Frac; + BitField<22, 5, u8, u32> Tex3Frac; // 27:30 BitField<27, 1, TexComponentCount> Tex4CoordElements; BitField<28, 3, ComponentFormat> Tex4CoordFormat; @@ -410,19 +410,19 @@ union UVAT_group2 { u32 Hex; // 0:4 - BitField<0, 5, u32> Tex4Frac; + BitField<0, 5, u8, u32> Tex4Frac; // 5:13 BitField<5, 1, TexComponentCount> Tex5CoordElements; BitField<6, 3, ComponentFormat> Tex5CoordFormat; - BitField<9, 5, u32> Tex5Frac; + BitField<9, 5, u8, u32> Tex5Frac; // 14:22 BitField<14, 1, TexComponentCount> Tex6CoordElements; BitField<15, 3, ComponentFormat> Tex6CoordFormat; - BitField<18, 5, u32> Tex6Frac; + BitField<18, 5, u8, u32> Tex6Frac; // 23:31 BitField<23, 1, TexComponentCount> Tex7CoordElements; BitField<24, 3, ComponentFormat> Tex7CoordFormat; - BitField<27, 5, u32> Tex7Frac; + BitField<27, 5, u8, u32> Tex7Frac; }; template <> struct fmt::formatter @@ -450,30 +450,123 @@ struct fmt::formatter } }; -struct ColorAttr +struct VAT { - ColorComponentCount Elements; - ColorFormat Comp; -}; + UVAT_group0 g0; + UVAT_group1 g1; + UVAT_group2 g2; -struct TexAttr -{ - TexComponentCount Elements; - ComponentFormat Format; - u8 Frac; + constexpr ColorComponentCount GetColorElements(size_t idx) const + { + switch (idx) + { + case 0: + return g0.Color0Elements; + case 1: + return g0.Color1Elements; + default: + PanicAlertFmt("Invalid color index {}", idx); + return ColorComponentCount::RGB; + } + } + constexpr ColorFormat GetColorFormat(size_t idx) const + { + switch (idx) + { + case 0: + return g0.Color0Comp; + case 1: + return g0.Color1Comp; + default: + PanicAlertFmt("Invalid color index {}", idx); + return ColorFormat::RGB565; + } + } + constexpr TexComponentCount GetTexElements(size_t idx) const + { + switch (idx) + { + case 0: + return g0.Tex0CoordElements; + case 1: + return g1.Tex1CoordElements; + case 2: + return g1.Tex2CoordElements; + case 3: + return g1.Tex3CoordElements; + case 4: + return g1.Tex4CoordElements; + case 5: + return g2.Tex5CoordElements; + case 6: + return g2.Tex6CoordElements; + case 7: + return g2.Tex7CoordElements; + default: + PanicAlertFmt("Invalid tex coord index {}", idx); + return TexComponentCount::S; + } + } + constexpr ComponentFormat GetTexFormat(size_t idx) const + { + switch (idx) + { + case 0: + return g0.Tex0CoordFormat; + case 1: + return g1.Tex1CoordFormat; + case 2: + return g1.Tex2CoordFormat; + case 3: + return g1.Tex3CoordFormat; + case 4: + return g1.Tex4CoordFormat; + case 5: + return g2.Tex5CoordFormat; + case 6: + return g2.Tex6CoordFormat; + case 7: + return g2.Tex7CoordFormat; + default: + PanicAlertFmt("Invalid tex coord index {}", idx); + return ComponentFormat::UByte; + } + } + constexpr u8 GetTexFrac(size_t idx) const + { + switch (idx) + { + case 0: + return g0.Tex0Frac; + case 1: + return g1.Tex1Frac; + case 2: + return g1.Tex2Frac; + case 3: + return g1.Tex3Frac; + case 4: + return g2.Tex4Frac; + case 5: + return g2.Tex5Frac; + case 6: + return g2.Tex6Frac; + case 7: + return g2.Tex7Frac; + default: + PanicAlertFmt("Invalid tex coord index {}", idx); + return 0; + } + } }; - -struct TVtxAttr +template <> +struct fmt::formatter { - CoordComponentCount PosElements; - ComponentFormat PosFormat; - u8 PosFrac; - NormalComponentCount NormalElements; - ComponentFormat NormalFormat; - ColorAttr color[2]; - TexAttr texCoord[8]; - bool ByteDequant; - u8 NormalIndex3; + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + template + auto format(const VAT& vat, FormatContext& ctx) + { + return format_to(ctx.out(), "{}\n{}\n{}", vat.g0, vat.g1, vat.g2); + } }; // Matrix indices @@ -518,23 +611,6 @@ struct fmt::formatter } }; -struct VAT -{ - UVAT_group0 g0; - UVAT_group1 g1; - UVAT_group2 g2; -}; -template <> -struct fmt::formatter -{ - constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } - template - auto format(const VAT& vat, FormatContext& ctx) - { - return format_to(ctx.out(), "{}\n{}\n{}", vat.g0, vat.g1, vat.g2); - } -}; - class VertexLoaderBase; // STATE_TO_SAVE diff --git a/Source/Core/VideoCommon/VertexLoader.cpp b/Source/Core/VideoCommon/VertexLoader.cpp index f51b27518f..da8e0d2e05 100644 --- a/Source/Core/VideoCommon/VertexLoader.cpp +++ b/Source/Core/VideoCommon/VertexLoader.cpp @@ -72,15 +72,14 @@ VertexLoader::VertexLoader(const TVtxDesc& vtx_desc, const VAT& vtx_attr) CompileVertexTranslator(); // generate frac factors - m_posScale = 1.0f / (1U << m_VtxAttr.PosFrac); - for (int i = 0; i < 8; i++) - m_tcScale[i] = 1.0f / (1U << m_VtxAttr.texCoord[i].Frac); + m_posScale = 1.0f / (1U << m_VtxAttr.g0.PosFrac); + for (u32 i = 0; i < 8; i++) + m_tcScale[i] = 1.0f / (1U << m_VtxAttr.GetTexFrac(i)); } void VertexLoader::CompileVertexTranslator() { m_VertexSize = 0; - const TVtxAttr& vtx_attr = m_VtxAttr; // Reset pipeline m_numPipelineStages = 0; @@ -154,12 +153,12 @@ void VertexLoader::CompileVertexTranslator() } // Write vertex position loader - WriteCall(VertexLoader_Position::GetFunction(m_VtxDesc.low.Position, m_VtxAttr.PosFormat, - m_VtxAttr.PosElements)); + WriteCall(VertexLoader_Position::GetFunction(m_VtxDesc.low.Position, m_VtxAttr.g0.PosFormat, + m_VtxAttr.g0.PosElements)); - m_VertexSize += VertexLoader_Position::GetSize(m_VtxDesc.low.Position, m_VtxAttr.PosFormat, - m_VtxAttr.PosElements); - int pos_elements = m_VtxAttr.PosElements == CoordComponentCount::XY ? 2 : 3; + m_VertexSize += VertexLoader_Position::GetSize(m_VtxDesc.low.Position, m_VtxAttr.g0.PosFormat, + m_VtxAttr.g0.PosElements); + int pos_elements = m_VtxAttr.g0.PosElements == CoordComponentCount::XY ? 2 : 3; m_native_vtx_decl.position.components = pos_elements; m_native_vtx_decl.position.enable = true; m_native_vtx_decl.position.offset = nat_offset; @@ -170,22 +169,23 @@ void VertexLoader::CompileVertexTranslator() // Normals if (m_VtxDesc.low.Normal != VertexComponentFormat::NotPresent) { - m_VertexSize += VertexLoader_Normal::GetSize(m_VtxDesc.low.Normal, m_VtxAttr.NormalFormat, - m_VtxAttr.NormalElements, m_VtxAttr.NormalIndex3); + m_VertexSize += + VertexLoader_Normal::GetSize(m_VtxDesc.low.Normal, m_VtxAttr.g0.NormalFormat, + m_VtxAttr.g0.NormalElements, m_VtxAttr.g0.NormalIndex3); TPipelineFunction pFunc = - VertexLoader_Normal::GetFunction(m_VtxDesc.low.Normal, m_VtxAttr.NormalFormat, - m_VtxAttr.NormalElements, m_VtxAttr.NormalIndex3); + VertexLoader_Normal::GetFunction(m_VtxDesc.low.Normal, m_VtxAttr.g0.NormalFormat, + m_VtxAttr.g0.NormalElements, m_VtxAttr.g0.NormalIndex3); if (pFunc == nullptr) { PanicAlertFmt("VertexLoader_Normal::GetFunction({} {} {} {}) returned zero!", - m_VtxDesc.low.Normal, m_VtxAttr.NormalFormat, m_VtxAttr.NormalElements, - m_VtxAttr.NormalIndex3); + m_VtxDesc.low.Normal, m_VtxAttr.g0.NormalFormat, m_VtxAttr.g0.NormalElements, + m_VtxAttr.g0.NormalIndex3); } WriteCall(pFunc); - for (int i = 0; i < (vtx_attr.NormalElements == NormalComponentCount::NBT ? 3 : 1); i++) + for (int i = 0; i < (m_VtxAttr.g0.NormalElements == NormalComponentCount::NBT ? 3 : 1); i++) { m_native_vtx_decl.normals[i].components = 3; m_native_vtx_decl.normals[i].enable = true; @@ -196,7 +196,7 @@ void VertexLoader::CompileVertexTranslator() } components |= VB_HAS_NRM0; - if (m_VtxAttr.NormalElements == NormalComponentCount::NBT) + if (m_VtxAttr.g0.NormalElements == NormalComponentCount::NBT) components |= VB_HAS_NRM1 | VB_HAS_NRM2; } @@ -206,9 +206,10 @@ void VertexLoader::CompileVertexTranslator() m_native_vtx_decl.colors[i].type = VAR_UNSIGNED_BYTE; m_native_vtx_decl.colors[i].integer = false; - m_VertexSize += VertexLoader_Color::GetSize(m_VtxDesc.low.Color[i], m_VtxAttr.color[i].Comp); + m_VertexSize += + VertexLoader_Color::GetSize(m_VtxDesc.low.Color[i], m_VtxAttr.GetColorFormat(i)); TPipelineFunction pFunc = - VertexLoader_Color::GetFunction(m_VtxDesc.low.Color[i], m_VtxAttr.color[i].Comp); + VertexLoader_Color::GetFunction(m_VtxDesc.low.Color[i], m_VtxAttr.GetColorFormat(i)); if (pFunc != nullptr) WriteCall(pFunc); @@ -232,8 +233,8 @@ void VertexLoader::CompileVertexTranslator() m_native_vtx_decl.texcoords[i].integer = false; const auto tc = m_VtxDesc.high.TexCoord[i].Value(); - const auto format = m_VtxAttr.texCoord[i].Format; - const auto elements = m_VtxAttr.texCoord[i].Elements; + const auto format = m_VtxAttr.GetTexFormat(i); + const auto elements = m_VtxAttr.GetTexElements(i); if (tc != VertexComponentFormat::NotPresent) { @@ -257,8 +258,7 @@ void VertexLoader::CompileVertexTranslator() // if texmtx is included, texcoord will always be 3 floats, z will be the texmtx index m_native_vtx_decl.texcoords[i].components = 3; nat_offset += 12; - WriteCall(m_VtxAttr.texCoord[i].Elements == TexComponentCount::ST ? TexMtx_Write_Float : - TexMtx_Write_Float2); + WriteCall(elements == TexComponentCount::ST ? TexMtx_Write_Float : TexMtx_Write_Float2); } else { @@ -272,9 +272,8 @@ void VertexLoader::CompileVertexTranslator() if (tc != VertexComponentFormat::NotPresent) { m_native_vtx_decl.texcoords[i].enable = true; - m_native_vtx_decl.texcoords[i].components = - vtx_attr.texCoord[i].Elements == TexComponentCount::ST ? 2 : 1; - nat_offset += 4 * (vtx_attr.texCoord[i].Elements == TexComponentCount::ST ? 2 : 1); + m_native_vtx_decl.texcoords[i].components = elements == TexComponentCount::ST ? 2 : 1; + nat_offset += 4 * (elements == TexComponentCount::ST ? 2 : 1); } } diff --git a/Source/Core/VideoCommon/VertexLoaderARM64.cpp b/Source/Core/VideoCommon/VertexLoaderARM64.cpp index 9fae16c59e..8dc396b47c 100644 --- a/Source/Core/VideoCommon/VertexLoaderARM64.cpp +++ b/Source/Core/VideoCommon/VertexLoaderARM64.cpp @@ -393,10 +393,11 @@ void VertexLoaderARM64::GenerateVertexLoader() for (size_t i = 0; i < m_VtxDesc.high.TexCoord.Size(); i++) { has_tc |= m_VtxDesc.high.TexCoord[i] != VertexComponentFormat::NotPresent; - has_tc_scale |= !!m_VtxAttr.texCoord[i].Frac; + has_tc_scale |= (m_VtxAttr.GetTexFrac(i) != 0); } - bool need_scale = (m_VtxAttr.ByteDequant && m_VtxAttr.PosFrac) || (has_tc && has_tc_scale) || + bool need_scale = (m_VtxAttr.g0.ByteDequant && m_VtxAttr.g0.PosFrac) || + (has_tc && has_tc_scale) || (m_VtxDesc.low.Normal != VertexComponentFormat::NotPresent); AlignCode16(); @@ -444,30 +445,30 @@ void VertexLoaderARM64::GenerateVertexLoader() // Position { - int elem_size = GetElementSize(m_VtxAttr.PosFormat); - int pos_elements = m_VtxAttr.PosElements == CoordComponentCount::XY ? 2 : 3; + int elem_size = GetElementSize(m_VtxAttr.g0.PosFormat); + int pos_elements = m_VtxAttr.g0.PosElements == CoordComponentCount::XY ? 2 : 3; int load_bytes = elem_size * pos_elements; int load_size = GetLoadSize(load_bytes); load_size <<= 3; s32 offset = GetAddressImm(ARRAY_POSITION, m_VtxDesc.low.Position, EncodeRegTo64(scratch1_reg), load_size); - ReadVertex(m_VtxDesc.low.Position, m_VtxAttr.PosFormat, pos_elements, pos_elements, - m_VtxAttr.ByteDequant, m_VtxAttr.PosFrac, &m_native_vtx_decl.position, offset); + ReadVertex(m_VtxDesc.low.Position, m_VtxAttr.g0.PosFormat, pos_elements, pos_elements, + m_VtxAttr.g0.ByteDequant, m_VtxAttr.g0.PosFrac, &m_native_vtx_decl.position, offset); } if (m_VtxDesc.low.Normal != VertexComponentFormat::NotPresent) { static const u8 map[8] = {7, 6, 15, 14}; - const u8 scaling_exponent = map[u32(m_VtxAttr.NormalFormat)]; - const int limit = m_VtxAttr.NormalElements == NormalComponentCount::NBT ? 3 : 1; + const u8 scaling_exponent = map[u32(m_VtxAttr.g0.NormalFormat.Value())]; + const int limit = m_VtxAttr.g0.NormalElements == NormalComponentCount::NBT ? 3 : 1; s32 offset = -1; - for (int i = 0; i < (m_VtxAttr.NormalElements == NormalComponentCount::NBT ? 3 : 1); i++) + for (int i = 0; i < (m_VtxAttr.g0.NormalElements == NormalComponentCount::NBT ? 3 : 1); i++) { - if (!i || m_VtxAttr.NormalIndex3) + if (!i || m_VtxAttr.g0.NormalIndex3) { - int elem_size = GetElementSize(m_VtxAttr.NormalFormat); + int elem_size = GetElementSize(m_VtxAttr.g0.NormalFormat); int load_bytes = elem_size * 3; int load_size = GetLoadSize(load_bytes); @@ -480,7 +481,7 @@ void VertexLoaderARM64::GenerateVertexLoader() else offset += i * elem_size * 3; } - int bytes_read = ReadVertex(m_VtxDesc.low.Normal, m_VtxAttr.NormalFormat, 3, 3, true, + int bytes_read = ReadVertex(m_VtxDesc.low.Normal, m_VtxAttr.g0.NormalFormat, 3, 3, true, scaling_exponent, &m_native_vtx_decl.normals[i], offset); if (offset == -1) @@ -490,7 +491,7 @@ void VertexLoaderARM64::GenerateVertexLoader() } m_native_components |= VB_HAS_NRM0; - if (m_VtxAttr.NormalElements == NormalComponentCount::NBT) + if (m_VtxAttr.g0.NormalElements == NormalComponentCount::NBT) m_native_components |= VB_HAS_NRM1 | VB_HAS_NRM2; } @@ -503,13 +504,13 @@ void VertexLoaderARM64::GenerateVertexLoader() if (m_VtxDesc.low.Color[i] != VertexComponentFormat::NotPresent) { u32 align = 4; - if (m_VtxAttr.color[i].Comp == ColorFormat::RGB565 || - m_VtxAttr.color[i].Comp == ColorFormat::RGBA4444) + if (m_VtxAttr.GetColorFormat(i) == ColorFormat::RGB565 || + m_VtxAttr.GetColorFormat(i) == ColorFormat::RGBA4444) align = 2; s32 offset = GetAddressImm(ARRAY_COLOR0 + int(i), m_VtxDesc.low.Color[i], EncodeRegTo64(scratch1_reg), align); - ReadColor(m_VtxDesc.low.Color[i], m_VtxAttr.color[i].Comp, offset); + ReadColor(m_VtxDesc.low.Color[i], m_VtxAttr.GetColorFormat(i), offset); m_native_components |= VB_HAS_COL0 << i; m_native_vtx_decl.colors[i].components = 4; m_native_vtx_decl.colors[i].enable = true; @@ -526,22 +527,22 @@ void VertexLoaderARM64::GenerateVertexLoader() m_native_vtx_decl.texcoords[i].type = VAR_FLOAT; m_native_vtx_decl.texcoords[i].integer = false; - int elements = m_VtxAttr.texCoord[i].Elements == TexComponentCount::S ? 1 : 2; + int elements = m_VtxAttr.GetTexElements(i) == TexComponentCount::S ? 1 : 2; if (m_VtxDesc.high.TexCoord[i] != VertexComponentFormat::NotPresent) { m_native_components |= VB_HAS_UV0 << i; - int elem_size = GetElementSize(m_VtxAttr.texCoord[i].Format); + int elem_size = GetElementSize(m_VtxAttr.GetTexFormat(i)); int load_bytes = elem_size * (elements + 2); int load_size = GetLoadSize(load_bytes); load_size <<= 3; s32 offset = GetAddressImm(ARRAY_TEXCOORD0 + int(i), m_VtxDesc.high.TexCoord[i], EncodeRegTo64(scratch1_reg), load_size); - u8 scaling_exponent = m_VtxAttr.texCoord[i].Frac; - ReadVertex(m_VtxDesc.high.TexCoord[i], m_VtxAttr.texCoord[i].Format, elements, - m_VtxDesc.low.TexMatIdx[i] ? 2 : elements, m_VtxAttr.ByteDequant, scaling_exponent, - &m_native_vtx_decl.texcoords[i], offset); + u8 scaling_exponent = m_VtxAttr.GetTexFrac(i); + ReadVertex(m_VtxDesc.high.TexCoord[i], m_VtxAttr.GetTexFormat(i), elements, + m_VtxDesc.low.TexMatIdx[i] ? 2 : elements, m_VtxAttr.g0.ByteDequant, + scaling_exponent, &m_native_vtx_decl.texcoords[i], offset); } if (m_VtxDesc.low.TexMatIdx[i]) { diff --git a/Source/Core/VideoCommon/VertexLoaderBase.cpp b/Source/Core/VideoCommon/VertexLoaderBase.cpp index 604ad1f04b..6a8c6498c0 100644 --- a/Source/Core/VideoCommon/VertexLoaderBase.cpp +++ b/Source/Core/VideoCommon/VertexLoaderBase.cpp @@ -26,53 +26,6 @@ #include "VideoCommon/VertexLoaderARM64.h" #endif -VertexLoaderBase::VertexLoaderBase(const TVtxDesc& vtx_desc, const VAT& vtx_attr) - : m_VtxDesc{vtx_desc}, m_vat{vtx_attr} -{ - SetVAT(vtx_attr); -} - -void VertexLoaderBase::SetVAT(const VAT& vat) -{ - m_VtxAttr.PosElements = vat.g0.PosElements; - m_VtxAttr.PosFormat = vat.g0.PosFormat; - m_VtxAttr.PosFrac = vat.g0.PosFrac; - m_VtxAttr.NormalElements = vat.g0.NormalElements; - m_VtxAttr.NormalFormat = vat.g0.NormalFormat; - m_VtxAttr.color[0].Elements = vat.g0.Color0Elements; - m_VtxAttr.color[0].Comp = vat.g0.Color0Comp; - m_VtxAttr.color[1].Elements = vat.g0.Color1Elements; - m_VtxAttr.color[1].Comp = vat.g0.Color1Comp; - m_VtxAttr.texCoord[0].Elements = vat.g0.Tex0CoordElements; - m_VtxAttr.texCoord[0].Format = vat.g0.Tex0CoordFormat; - m_VtxAttr.texCoord[0].Frac = vat.g0.Tex0Frac; - m_VtxAttr.ByteDequant = vat.g0.ByteDequant; - m_VtxAttr.NormalIndex3 = vat.g0.NormalIndex3; - - m_VtxAttr.texCoord[1].Elements = vat.g1.Tex1CoordElements; - m_VtxAttr.texCoord[1].Format = vat.g1.Tex1CoordFormat; - m_VtxAttr.texCoord[1].Frac = vat.g1.Tex1Frac; - m_VtxAttr.texCoord[2].Elements = vat.g1.Tex2CoordElements; - m_VtxAttr.texCoord[2].Format = vat.g1.Tex2CoordFormat; - m_VtxAttr.texCoord[2].Frac = vat.g1.Tex2Frac; - m_VtxAttr.texCoord[3].Elements = vat.g1.Tex3CoordElements; - m_VtxAttr.texCoord[3].Format = vat.g1.Tex3CoordFormat; - m_VtxAttr.texCoord[3].Frac = vat.g1.Tex3Frac; - m_VtxAttr.texCoord[4].Elements = vat.g1.Tex4CoordElements; - m_VtxAttr.texCoord[4].Format = vat.g1.Tex4CoordFormat; - - m_VtxAttr.texCoord[4].Frac = vat.g2.Tex4Frac; - m_VtxAttr.texCoord[5].Elements = vat.g2.Tex5CoordElements; - m_VtxAttr.texCoord[5].Format = vat.g2.Tex5CoordFormat; - m_VtxAttr.texCoord[5].Frac = vat.g2.Tex5Frac; - m_VtxAttr.texCoord[6].Elements = vat.g2.Tex6CoordElements; - m_VtxAttr.texCoord[6].Format = vat.g2.Tex6CoordFormat; - m_VtxAttr.texCoord[6].Frac = vat.g2.Tex6Frac; - m_VtxAttr.texCoord[7].Elements = vat.g2.Tex7CoordElements; - m_VtxAttr.texCoord[7].Format = vat.g2.Tex7CoordFormat; - m_VtxAttr.texCoord[7].Frac = vat.g2.Tex7Frac; -}; - // a hacky implementation to compare two vertex loaders class VertexLoaderTester : public VertexLoaderBase { @@ -130,8 +83,8 @@ public: ERROR_LOG_FMT(VIDEO, "The two vertex loaders have loaded different data " "(guru meditation {:#010x}, {:#010x}, {:#010x}, {:#010x}, {:#010x}).", - m_VtxDesc.low.Hex, m_VtxDesc.high.Hex, m_vat.g0.Hex, m_vat.g1.Hex, - m_vat.g2.Hex); + m_VtxDesc.low.Hex, m_VtxDesc.high.Hex, m_VtxAttr.g0.Hex, m_VtxAttr.g1.Hex, + m_VtxAttr.g2.Hex); } memcpy(dst.GetPointer(), buffer_a.data(), count_a * m_native_vtx_decl.stride); diff --git a/Source/Core/VideoCommon/VertexLoaderBase.h b/Source/Core/VideoCommon/VertexLoaderBase.h index cf100fb4c6..bc57d34b4f 100644 --- a/Source/Core/VideoCommon/VertexLoaderBase.h +++ b/Source/Core/VideoCommon/VertexLoaderBase.h @@ -77,11 +77,10 @@ public: int m_numLoadedVertices = 0; protected: - VertexLoaderBase(const TVtxDesc& vtx_desc, const VAT& vtx_attr); - void SetVAT(const VAT& vat); + VertexLoaderBase(const TVtxDesc& vtx_desc, const VAT& vtx_attr) + : m_VtxDesc{vtx_desc}, m_VtxAttr{vtx_attr} {}; // GC vertex format - TVtxAttr m_VtxAttr; // VAT decoded into easy format - TVtxDesc m_VtxDesc; // Not really used currently - or well it is, but could be easily avoided. - VAT m_vat; + const VAT m_VtxAttr; + const TVtxDesc m_VtxDesc; }; diff --git a/Source/Core/VideoCommon/VertexLoaderX64.cpp b/Source/Core/VideoCommon/VertexLoaderX64.cpp index 27ccad71b5..9e1b056b97 100644 --- a/Source/Core/VideoCommon/VertexLoaderX64.cpp +++ b/Source/Core/VideoCommon/VertexLoaderX64.cpp @@ -439,30 +439,30 @@ void VertexLoaderX64::GenerateVertexLoader() } OpArg data = GetVertexAddr(ARRAY_POSITION, m_VtxDesc.low.Position); - int pos_elements = m_VtxAttr.PosElements == CoordComponentCount::XY ? 2 : 3; - ReadVertex(data, m_VtxDesc.low.Position, m_VtxAttr.PosFormat, pos_elements, pos_elements, - m_VtxAttr.ByteDequant, m_VtxAttr.PosFrac, &m_native_vtx_decl.position); + int pos_elements = m_VtxAttr.g0.PosElements == CoordComponentCount::XY ? 2 : 3; + ReadVertex(data, m_VtxDesc.low.Position, m_VtxAttr.g0.PosFormat, pos_elements, pos_elements, + m_VtxAttr.g0.ByteDequant, m_VtxAttr.g0.PosFrac, &m_native_vtx_decl.position); if (m_VtxDesc.low.Normal != VertexComponentFormat::NotPresent) { static const u8 map[8] = {7, 6, 15, 14}; - const u8 scaling_exponent = map[u32(m_VtxAttr.NormalFormat)]; - const int limit = m_VtxAttr.NormalElements == NormalComponentCount::NBT ? 3 : 1; + const u8 scaling_exponent = map[u32(m_VtxAttr.g0.NormalFormat.Value())]; + const int limit = m_VtxAttr.g0.NormalElements == NormalComponentCount::NBT ? 3 : 1; for (int i = 0; i < limit; i++) { - if (!i || m_VtxAttr.NormalIndex3) + if (!i || m_VtxAttr.g0.NormalIndex3) { data = GetVertexAddr(ARRAY_NORMAL, m_VtxDesc.low.Normal); - int elem_size = GetElementSize(m_VtxAttr.NormalFormat); + int elem_size = GetElementSize(m_VtxAttr.g0.NormalFormat); data.AddMemOffset(i * elem_size * 3); } - data.AddMemOffset(ReadVertex(data, m_VtxDesc.low.Normal, m_VtxAttr.NormalFormat, 3, 3, true, - scaling_exponent, &m_native_vtx_decl.normals[i])); + data.AddMemOffset(ReadVertex(data, m_VtxDesc.low.Normal, m_VtxAttr.g0.NormalFormat, 3, 3, + true, scaling_exponent, &m_native_vtx_decl.normals[i])); } m_native_components |= VB_HAS_NRM0; - if (m_VtxAttr.NormalElements == NormalComponentCount::NBT) + if (m_VtxAttr.g0.NormalElements == NormalComponentCount::NBT) m_native_components |= VB_HAS_NRM1 | VB_HAS_NRM2; } @@ -471,7 +471,7 @@ void VertexLoaderX64::GenerateVertexLoader() if (m_VtxDesc.low.Color[i] != VertexComponentFormat::NotPresent) { data = GetVertexAddr(ARRAY_COLOR0 + int(i), m_VtxDesc.low.Color[i]); - ReadColor(data, m_VtxDesc.low.Color[i], m_VtxAttr.color[i].Comp); + ReadColor(data, m_VtxDesc.low.Color[i], m_VtxAttr.GetColorFormat(i)); m_native_components |= VB_HAS_COL0 << i; m_native_vtx_decl.colors[i].components = 4; m_native_vtx_decl.colors[i].enable = true; @@ -484,14 +484,14 @@ void VertexLoaderX64::GenerateVertexLoader() for (size_t i = 0; i < m_VtxDesc.high.TexCoord.Size(); i++) { - int elements = m_VtxAttr.texCoord[i].Elements == TexComponentCount::ST ? 2 : 1; + int elements = m_VtxAttr.GetTexElements(i) == TexComponentCount::ST ? 2 : 1; if (m_VtxDesc.high.TexCoord[i] != VertexComponentFormat::NotPresent) { data = GetVertexAddr(ARRAY_TEXCOORD0 + int(i), m_VtxDesc.high.TexCoord[i]); - u8 scaling_exponent = m_VtxAttr.texCoord[i].Frac; - ReadVertex(data, m_VtxDesc.high.TexCoord[i], m_VtxAttr.texCoord[i].Format, elements, - m_VtxDesc.low.TexMatIdx[i] ? 2 : elements, m_VtxAttr.ByteDequant, scaling_exponent, - &m_native_vtx_decl.texcoords[i]); + u8 scaling_exponent = m_VtxAttr.GetTexFrac(i); + ReadVertex(data, m_VtxDesc.high.TexCoord[i], m_VtxAttr.GetTexFormat(i), elements, + m_VtxDesc.low.TexMatIdx[i] ? 2 : elements, m_VtxAttr.g0.ByteDequant, + scaling_exponent, &m_native_vtx_decl.texcoords[i]); m_native_components |= VB_HAS_UV0 << i; } if (m_VtxDesc.low.TexMatIdx[i]) From fa7077763f91980e372d502b4357f3dda971ffbe Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Thu, 11 Mar 2021 11:23:13 -0800 Subject: [PATCH 07/24] Remove VertexLoaderBase::IsInitialized It is no longer relevant for the current set of loaders after 70305425462843af192489da00389559cd6f5834. If it becomes relevant again, a static function named IsUsable or IsCompatibleWithCurrentMachine or something would be a better approach. --- Source/Core/VideoCommon/VertexLoader.h | 1 - Source/Core/VideoCommon/VertexLoaderARM64.cpp | 3 - Source/Core/VideoCommon/VertexLoaderARM64.h | 1 - Source/Core/VideoCommon/VertexLoaderBase.cpp | 82 ++++++++----------- Source/Core/VideoCommon/VertexLoaderBase.h | 2 - Source/Core/VideoCommon/VertexLoaderX64.cpp | 3 - Source/Core/VideoCommon/VertexLoaderX64.h | 1 - 7 files changed, 33 insertions(+), 60 deletions(-) diff --git a/Source/Core/VideoCommon/VertexLoader.h b/Source/Core/VideoCommon/VertexLoader.h index 73738c86b8..4be2f41a65 100644 --- a/Source/Core/VideoCommon/VertexLoader.h +++ b/Source/Core/VideoCommon/VertexLoader.h @@ -22,7 +22,6 @@ public: VertexLoader(const TVtxDesc& vtx_desc, const VAT& vtx_attr); int RunVertices(DataReader src, DataReader dst, int count) override; - bool IsInitialized() override { return true; } // This vertex loader supports all formats // They are used for the communication with the loader functions float m_posScale; float m_tcScale[8]; diff --git a/Source/Core/VideoCommon/VertexLoaderARM64.cpp b/Source/Core/VideoCommon/VertexLoaderARM64.cpp index 8dc396b47c..4030a50808 100644 --- a/Source/Core/VideoCommon/VertexLoaderARM64.cpp +++ b/Source/Core/VideoCommon/VertexLoaderARM64.cpp @@ -53,9 +53,6 @@ alignas(16) static const float scale_factors[] = { VertexLoaderARM64::VertexLoaderARM64(const TVtxDesc& vtx_desc, const VAT& vtx_att) : VertexLoaderBase(vtx_desc, vtx_att), m_float_emit(this) { - if (!IsInitialized()) - return; - AllocCodeSpace(4096); ClearCodeSpace(); GenerateVertexLoader(); diff --git a/Source/Core/VideoCommon/VertexLoaderARM64.h b/Source/Core/VideoCommon/VertexLoaderARM64.h index 6b18b59c0e..2b2787709b 100644 --- a/Source/Core/VideoCommon/VertexLoaderARM64.h +++ b/Source/Core/VideoCommon/VertexLoaderARM64.h @@ -19,7 +19,6 @@ public: VertexLoaderARM64(const TVtxDesc& vtx_desc, const VAT& vtx_att); protected: - bool IsInitialized() override { return true; } int RunVertices(DataReader src, DataReader dst, int count) override; private: diff --git a/Source/Core/VideoCommon/VertexLoaderBase.cpp b/Source/Core/VideoCommon/VertexLoaderBase.cpp index 6a8c6498c0..84d7eb43c0 100644 --- a/Source/Core/VideoCommon/VertexLoaderBase.cpp +++ b/Source/Core/VideoCommon/VertexLoaderBase.cpp @@ -34,31 +34,23 @@ public: const TVtxDesc& vtx_desc, const VAT& vtx_attr) : VertexLoaderBase(vtx_desc, vtx_attr), a(std::move(a_)), b(std::move(b_)) { - m_initialized = a && b && a->IsInitialized() && b->IsInitialized(); - - if (m_initialized) + ASSERT(a && b); + if (a->m_VertexSize == b->m_VertexSize && a->m_native_components == b->m_native_components && + a->m_native_vtx_decl.stride == b->m_native_vtx_decl.stride) { - m_initialized = a->m_VertexSize == b->m_VertexSize && - a->m_native_components == b->m_native_components && - a->m_native_vtx_decl.stride == b->m_native_vtx_decl.stride; - - if (m_initialized) - { - m_VertexSize = a->m_VertexSize; - m_native_components = a->m_native_components; - memcpy(&m_native_vtx_decl, &a->m_native_vtx_decl, sizeof(PortableVertexDeclaration)); - } - else - { - ERROR_LOG_FMT(VIDEO, "Can't compare vertex loaders that expect different vertex formats!"); - ERROR_LOG_FMT(VIDEO, "a: m_VertexSize {}, m_native_components {:#010x}, stride {}", - a->m_VertexSize, a->m_native_components, a->m_native_vtx_decl.stride); - ERROR_LOG_FMT(VIDEO, "b: m_VertexSize {}, m_native_components {:#010x}, stride {}", - b->m_VertexSize, b->m_native_components, b->m_native_vtx_decl.stride); - } + m_VertexSize = a->m_VertexSize; + m_native_components = a->m_native_components; + memcpy(&m_native_vtx_decl, &a->m_native_vtx_decl, sizeof(PortableVertexDeclaration)); + } + else + { + ERROR_LOG_FMT(VIDEO, "Can't compare vertex loaders that expect different vertex formats!"); + ERROR_LOG_FMT(VIDEO, "a: m_VertexSize {}, m_native_components {:#010x}, stride {}", + a->m_VertexSize, a->m_native_components, a->m_native_vtx_decl.stride); + ERROR_LOG_FMT(VIDEO, "b: m_VertexSize {}, m_native_components {:#010x}, stride {}", + b->m_VertexSize, b->m_native_components, b->m_native_vtx_decl.stride); } } - ~VertexLoaderTester() override {} int RunVertices(DataReader src, DataReader dst, int count) override { buffer_a.resize(count * a->m_native_vtx_decl.stride + 4); @@ -81,21 +73,17 @@ public: std::min(count_a, count_b) * m_native_vtx_decl.stride)) { ERROR_LOG_FMT(VIDEO, - "The two vertex loaders have loaded different data " - "(guru meditation {:#010x}, {:#010x}, {:#010x}, {:#010x}, {:#010x}).", - m_VtxDesc.low.Hex, m_VtxDesc.high.Hex, m_VtxAttr.g0.Hex, m_VtxAttr.g1.Hex, - m_VtxAttr.g2.Hex); + "The two vertex loaders have loaded different data. Configuration:" + "\nVertex desc:\n{}\n\nVertex attr:\n{}", + m_VtxDesc, m_VtxAttr); } memcpy(dst.GetPointer(), buffer_a.data(), count_a * m_native_vtx_decl.stride); m_numLoadedVertices += count; return count_a; } - bool IsInitialized() override { return m_initialized; } private: - bool m_initialized; - std::unique_ptr a; std::unique_ptr b; @@ -106,33 +94,29 @@ private: std::unique_ptr VertexLoaderBase::CreateVertexLoader(const TVtxDesc& vtx_desc, const VAT& vtx_attr) { - std::unique_ptr loader; + std::unique_ptr loader = nullptr; //#define COMPARE_VERTEXLOADERS -#if defined(COMPARE_VERTEXLOADERS) && defined(_M_X86_64) - // first try: Any new VertexLoader vs the old one - loader = std::make_unique( - std::make_unique(vtx_desc, vtx_attr), // the software one - std::make_unique(vtx_desc, vtx_attr), // the new one to compare - vtx_desc, vtx_attr); - if (loader->IsInitialized()) - return loader; -#elif defined(_M_X86_64) +#if defined(_M_X86_64) loader = std::make_unique(vtx_desc, vtx_attr); - if (loader->IsInitialized()) - return loader; #elif defined(_M_ARM_64) loader = std::make_unique(vtx_desc, vtx_attr); - if (loader->IsInitialized()) - return loader; #endif - // last try: The old VertexLoader - loader = std::make_unique(vtx_desc, vtx_attr); - if (loader->IsInitialized()) - return loader; + // Use the software loader as a fallback + // (not currently applicable, as both VertexLoaderX64 and VertexLoaderARM64 + // are always usable, but if a loader that only works on some CPUs is created + // then this fallback would be used) + if (!loader) + loader = std::make_unique(vtx_desc, vtx_attr); - PanicAlertFmt("No Vertex Loader found."); - return nullptr; +#if defined(COMPARE_VERTEXLOADERS) + return std::make_unique( + std::make_unique(vtx_desc, vtx_attr), // the software one + std::move(loader), // the new one to compare + vtx_desc, vtx_attr); +#else + return loader; +#endif } diff --git a/Source/Core/VideoCommon/VertexLoaderBase.h b/Source/Core/VideoCommon/VertexLoaderBase.h index bc57d34b4f..2c787479b6 100644 --- a/Source/Core/VideoCommon/VertexLoaderBase.h +++ b/Source/Core/VideoCommon/VertexLoaderBase.h @@ -65,8 +65,6 @@ public: virtual ~VertexLoaderBase() {} virtual int RunVertices(DataReader src, DataReader dst, int count) = 0; - virtual bool IsInitialized() = 0; - // per loader public state int m_VertexSize = 0; // number of bytes of a raw GC vertex PortableVertexDeclaration m_native_vtx_decl{}; diff --git a/Source/Core/VideoCommon/VertexLoaderX64.cpp b/Source/Core/VideoCommon/VertexLoaderX64.cpp index 9e1b056b97..e6d94693b8 100644 --- a/Source/Core/VideoCommon/VertexLoaderX64.cpp +++ b/Source/Core/VideoCommon/VertexLoaderX64.cpp @@ -45,9 +45,6 @@ static OpArg MPIC(const void* ptr) VertexLoaderX64::VertexLoaderX64(const TVtxDesc& vtx_desc, const VAT& vtx_att) : VertexLoaderBase(vtx_desc, vtx_att) { - if (!IsInitialized()) - return; - AllocCodeSpace(4096); ClearCodeSpace(); GenerateVertexLoader(); diff --git a/Source/Core/VideoCommon/VertexLoaderX64.h b/Source/Core/VideoCommon/VertexLoaderX64.h index 4b3029066c..7b91ad6cf8 100644 --- a/Source/Core/VideoCommon/VertexLoaderX64.h +++ b/Source/Core/VideoCommon/VertexLoaderX64.h @@ -18,7 +18,6 @@ public: VertexLoaderX64(const TVtxDesc& vtx_desc, const VAT& vtx_att); protected: - bool IsInitialized() override { return true; } int RunVertices(DataReader src, DataReader dst, int count) override; private: From 0a906f553fe7699d1c863a464211f74b6c306a0f Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Thu, 11 Mar 2021 12:55:25 -0800 Subject: [PATCH 08/24] Move vertex size and component calculation to VertexLoaderBase --- Source/Core/VideoCommon/VertexLoader.cpp | 91 +++---------------- Source/Core/VideoCommon/VertexLoaderARM64.cpp | 11 +-- Source/Core/VideoCommon/VertexLoaderBase.cpp | 78 ++++++++++++++-- Source/Core/VideoCommon/VertexLoaderBase.h | 11 ++- .../Core/VideoCommon/VertexLoaderManager.cpp | 2 +- Source/Core/VideoCommon/VertexLoaderX64.cpp | 10 +- .../VideoCommon/VertexLoaderTest.cpp | 2 +- 7 files changed, 96 insertions(+), 109 deletions(-) diff --git a/Source/Core/VideoCommon/VertexLoader.cpp b/Source/Core/VideoCommon/VertexLoader.cpp index da8e0d2e05..0d49ef1a4b 100644 --- a/Source/Core/VideoCommon/VertexLoader.cpp +++ b/Source/Core/VideoCommon/VertexLoader.cpp @@ -79,13 +79,9 @@ VertexLoader::VertexLoader(const TVtxDesc& vtx_desc, const VAT& vtx_attr) void VertexLoader::CompileVertexTranslator() { - m_VertexSize = 0; - // Reset pipeline m_numPipelineStages = 0; - u32 components = 0; - // Position in pc vertex format. int nat_offset = 0; @@ -93,71 +89,24 @@ void VertexLoader::CompileVertexTranslator() if (m_VtxDesc.low.PosMatIdx) { WriteCall(PosMtx_ReadDirect_UByte); - components |= VB_HAS_POSMTXIDX; m_native_vtx_decl.posmtx.components = 4; m_native_vtx_decl.posmtx.enable = true; m_native_vtx_decl.posmtx.offset = nat_offset; m_native_vtx_decl.posmtx.type = VAR_UNSIGNED_BYTE; m_native_vtx_decl.posmtx.integer = true; nat_offset += 4; - m_VertexSize += 1; } - if (m_VtxDesc.low.Tex0MatIdx) + for (auto texmtxidx : m_VtxDesc.low.TexMatIdx) { - m_VertexSize += 1; - components |= VB_HAS_TEXMTXIDX0; - WriteCall(TexMtx_ReadDirect_UByte); - } - if (m_VtxDesc.low.Tex1MatIdx) - { - m_VertexSize += 1; - components |= VB_HAS_TEXMTXIDX1; - WriteCall(TexMtx_ReadDirect_UByte); - } - if (m_VtxDesc.low.Tex2MatIdx) - { - m_VertexSize += 1; - components |= VB_HAS_TEXMTXIDX2; - WriteCall(TexMtx_ReadDirect_UByte); - } - if (m_VtxDesc.low.Tex3MatIdx) - { - m_VertexSize += 1; - components |= VB_HAS_TEXMTXIDX3; - WriteCall(TexMtx_ReadDirect_UByte); - } - if (m_VtxDesc.low.Tex4MatIdx) - { - m_VertexSize += 1; - components |= VB_HAS_TEXMTXIDX4; - WriteCall(TexMtx_ReadDirect_UByte); - } - if (m_VtxDesc.low.Tex5MatIdx) - { - m_VertexSize += 1; - components |= VB_HAS_TEXMTXIDX5; - WriteCall(TexMtx_ReadDirect_UByte); - } - if (m_VtxDesc.low.Tex6MatIdx) - { - m_VertexSize += 1; - components |= VB_HAS_TEXMTXIDX6; - WriteCall(TexMtx_ReadDirect_UByte); - } - if (m_VtxDesc.low.Tex7MatIdx) - { - m_VertexSize += 1; - components |= VB_HAS_TEXMTXIDX7; - WriteCall(TexMtx_ReadDirect_UByte); + if (texmtxidx) + WriteCall(TexMtx_ReadDirect_UByte); } // Write vertex position loader WriteCall(VertexLoader_Position::GetFunction(m_VtxDesc.low.Position, m_VtxAttr.g0.PosFormat, m_VtxAttr.g0.PosElements)); - m_VertexSize += VertexLoader_Position::GetSize(m_VtxDesc.low.Position, m_VtxAttr.g0.PosFormat, - m_VtxAttr.g0.PosElements); int pos_elements = m_VtxAttr.g0.PosElements == CoordComponentCount::XY ? 2 : 3; m_native_vtx_decl.position.components = pos_elements; m_native_vtx_decl.position.enable = true; @@ -169,10 +118,6 @@ void VertexLoader::CompileVertexTranslator() // Normals if (m_VtxDesc.low.Normal != VertexComponentFormat::NotPresent) { - m_VertexSize += - VertexLoader_Normal::GetSize(m_VtxDesc.low.Normal, m_VtxAttr.g0.NormalFormat, - m_VtxAttr.g0.NormalElements, m_VtxAttr.g0.NormalIndex3); - TPipelineFunction pFunc = VertexLoader_Normal::GetFunction(m_VtxDesc.low.Normal, m_VtxAttr.g0.NormalFormat, m_VtxAttr.g0.NormalElements, m_VtxAttr.g0.NormalIndex3); @@ -194,10 +139,6 @@ void VertexLoader::CompileVertexTranslator() m_native_vtx_decl.normals[i].integer = false; nat_offset += 12; } - - components |= VB_HAS_NRM0; - if (m_VtxAttr.g0.NormalElements == NormalComponentCount::NBT) - components |= VB_HAS_NRM1 | VB_HAS_NRM2; } for (size_t i = 0; i < m_VtxDesc.low.Color.Size(); i++) @@ -206,8 +147,6 @@ void VertexLoader::CompileVertexTranslator() m_native_vtx_decl.colors[i].type = VAR_UNSIGNED_BYTE; m_native_vtx_decl.colors[i].integer = false; - m_VertexSize += - VertexLoader_Color::GetSize(m_VtxDesc.low.Color[i], m_VtxAttr.GetColorFormat(i)); TPipelineFunction pFunc = VertexLoader_Color::GetFunction(m_VtxDesc.low.Color[i], m_VtxAttr.GetColorFormat(i)); @@ -218,7 +157,6 @@ void VertexLoader::CompileVertexTranslator() if (m_VtxDesc.low.Color[i] != VertexComponentFormat::NotPresent) { - components |= VB_HAS_COL0 << i; m_native_vtx_decl.colors[i].offset = nat_offset; m_native_vtx_decl.colors[i].enable = true; nat_offset += 4; @@ -245,25 +183,21 @@ void VertexLoader::CompileVertexTranslator() ASSERT_MSG(VIDEO, elements == TexComponentCount::S || elements == TexComponentCount::ST, "Invalid number of texture coordinates elements!\n(elements = %d)", (u32)elements); - components |= VB_HAS_UV0 << i; WriteCall(VertexLoader_TextCoord::GetFunction(tc, format, elements)); - m_VertexSize += VertexLoader_TextCoord::GetSize(tc, format, elements); } - if (components & (VB_HAS_TEXMTXIDX0 << i)) + if (m_VtxDesc.low.TexMatIdx[i]) { m_native_vtx_decl.texcoords[i].enable = true; + m_native_vtx_decl.texcoords[i].components = 3; + nat_offset += 12; if (tc != VertexComponentFormat::NotPresent) { // if texmtx is included, texcoord will always be 3 floats, z will be the texmtx index - m_native_vtx_decl.texcoords[i].components = 3; - nat_offset += 12; WriteCall(elements == TexComponentCount::ST ? TexMtx_Write_Float : TexMtx_Write_Float2); } else { - m_native_vtx_decl.texcoords[i].components = 3; - nat_offset += 12; WriteCall(TexMtx_Write_Float3); } } @@ -280,17 +214,21 @@ void VertexLoader::CompileVertexTranslator() if (tc == VertexComponentFormat::NotPresent) { // if there's more tex coords later, have to write a dummy call - size_t j = i + 1; - for (; j < m_VtxDesc.high.TexCoord.Size(); ++j) + bool has_more = false; + for (size_t j = 0; j < m_VtxDesc.high.TexCoord.Size(); ++j) { if (m_VtxDesc.high.TexCoord[j] != VertexComponentFormat::NotPresent) { + has_more = true; WriteCall(VertexLoader_TextCoord::GetDummyFunction()); // important to get indices right! break; } + else if (m_VtxDesc.low.TexMatIdx[i]) + { + has_more = true; + } } - // tricky! - if (j == 8 && !((components & VB_HAS_TEXMTXIDXALL) & (VB_HAS_TEXMTXIDXALL << (i + 1)))) + if (!has_more) { // no more tex coords and tex matrices, so exit loop break; @@ -304,7 +242,6 @@ void VertexLoader::CompileVertexTranslator() WriteCall(SkipVertex); } - m_native_components = components; m_native_vtx_decl.stride = nat_offset; } diff --git a/Source/Core/VideoCommon/VertexLoaderARM64.cpp b/Source/Core/VideoCommon/VertexLoaderARM64.cpp index 4030a50808..e546c42be8 100644 --- a/Source/Core/VideoCommon/VertexLoaderARM64.cpp +++ b/Source/Core/VideoCommon/VertexLoaderARM64.cpp @@ -423,7 +423,6 @@ void VertexLoaderARM64::GenerateVertexLoader() STR(IndexType::Unsigned, scratch1_reg, EncodeRegTo64(scratch2_reg), 0); SetJumpTarget(dont_store); - m_native_components |= VB_HAS_POSMTXIDX; m_native_vtx_decl.posmtx.components = 4; m_native_vtx_decl.posmtx.enable = true; m_native_vtx_decl.posmtx.offset = m_dst_ofs; @@ -486,10 +485,6 @@ void VertexLoaderARM64::GenerateVertexLoader() else offset += bytes_read; } - - m_native_components |= VB_HAS_NRM0; - if (m_VtxAttr.g0.NormalElements == NormalComponentCount::NBT) - m_native_components |= VB_HAS_NRM1 | VB_HAS_NRM2; } for (size_t i = 0; i < m_VtxDesc.low.Color.Size(); i++) @@ -508,7 +503,6 @@ void VertexLoaderARM64::GenerateVertexLoader() s32 offset = GetAddressImm(ARRAY_COLOR0 + int(i), m_VtxDesc.low.Color[i], EncodeRegTo64(scratch1_reg), align); ReadColor(m_VtxDesc.low.Color[i], m_VtxAttr.GetColorFormat(i), offset); - m_native_components |= VB_HAS_COL0 << i; m_native_vtx_decl.colors[i].components = 4; m_native_vtx_decl.colors[i].enable = true; m_native_vtx_decl.colors[i].offset = m_dst_ofs; @@ -527,8 +521,6 @@ void VertexLoaderARM64::GenerateVertexLoader() int elements = m_VtxAttr.GetTexElements(i) == TexComponentCount::S ? 1 : 2; if (m_VtxDesc.high.TexCoord[i] != VertexComponentFormat::NotPresent) { - m_native_components |= VB_HAS_UV0 << i; - int elem_size = GetElementSize(m_VtxAttr.GetTexFormat(i)); int load_bytes = elem_size * (elements + 2); int load_size = GetLoadSize(load_bytes); @@ -543,7 +535,6 @@ void VertexLoaderARM64::GenerateVertexLoader() } if (m_VtxDesc.low.TexMatIdx[i]) { - m_native_components |= VB_HAS_TEXMTXIDX0 << i; m_native_vtx_decl.texcoords[i].components = 3; m_native_vtx_decl.texcoords[i].enable = true; m_native_vtx_decl.texcoords[i].type = VAR_FLOAT; @@ -609,7 +600,7 @@ void VertexLoaderARM64::GenerateVertexLoader() FlushIcache(); - m_VertexSize = m_src_ofs; + ASSERT(m_vertex_size == m_src_ofs); m_native_vtx_decl.stride = m_dst_ofs; } diff --git a/Source/Core/VideoCommon/VertexLoaderBase.cpp b/Source/Core/VideoCommon/VertexLoaderBase.cpp index 84d7eb43c0..51f9fda359 100644 --- a/Source/Core/VideoCommon/VertexLoaderBase.cpp +++ b/Source/Core/VideoCommon/VertexLoaderBase.cpp @@ -19,6 +19,10 @@ #include "VideoCommon/DataReader.h" #include "VideoCommon/VertexLoader.h" +#include "VideoCommon/VertexLoader_Color.h" +#include "VideoCommon/VertexLoader_Normal.h" +#include "VideoCommon/VertexLoader_Position.h" +#include "VideoCommon/VertexLoader_TextCoord.h" #ifdef _M_X86_64 #include "VideoCommon/VertexLoaderX64.h" @@ -35,20 +39,22 @@ public: : VertexLoaderBase(vtx_desc, vtx_attr), a(std::move(a_)), b(std::move(b_)) { ASSERT(a && b); - if (a->m_VertexSize == b->m_VertexSize && a->m_native_components == b->m_native_components && + if (a->m_vertex_size == b->m_vertex_size && a->m_native_components == b->m_native_components && a->m_native_vtx_decl.stride == b->m_native_vtx_decl.stride) { - m_VertexSize = a->m_VertexSize; - m_native_components = a->m_native_components; + // These are generated from the VAT and vertex desc, so they should match. + // m_native_vtx_decl.stride isn't set yet, though. + ASSERT(m_vertex_size == a->m_vertex_size && m_native_components == a->m_native_components); + memcpy(&m_native_vtx_decl, &a->m_native_vtx_decl, sizeof(PortableVertexDeclaration)); } else { - ERROR_LOG_FMT(VIDEO, "Can't compare vertex loaders that expect different vertex formats!"); - ERROR_LOG_FMT(VIDEO, "a: m_VertexSize {}, m_native_components {:#010x}, stride {}", - a->m_VertexSize, a->m_native_components, a->m_native_vtx_decl.stride); - ERROR_LOG_FMT(VIDEO, "b: m_VertexSize {}, m_native_components {:#010x}, stride {}", - b->m_VertexSize, b->m_native_components, b->m_native_vtx_decl.stride); + PanicAlertFmt("Can't compare vertex loaders that expect different vertex formats!\n" + "a: m_vertex_size {}, m_native_components {:#010x}, stride {}\n" + "b: m_vertex_size {}, m_native_components {:#010x}, stride {}", + a->m_vertex_size, a->m_native_components, a->m_native_vtx_decl.stride, + b->m_vertex_size, b->m_native_components, b->m_native_vtx_decl.stride); } } int RunVertices(DataReader src, DataReader dst, int count) override @@ -91,6 +97,62 @@ private: std::vector buffer_b; }; +u32 VertexLoaderBase::GetVertexSize(const TVtxDesc& vtx_desc, const VAT& vtx_attr) +{ + u32 size = 0; + if (vtx_desc.low.PosMatIdx) + size++; + for (auto texmtxidx : vtx_desc.low.TexMatIdx) + { + if (texmtxidx) + size++; + } + size += VertexLoader_Position::GetSize(vtx_desc.low.Position, vtx_attr.g0.PosFormat, + vtx_attr.g0.PosElements); + size += VertexLoader_Normal::GetSize(vtx_desc.low.Normal, vtx_attr.g0.NormalFormat, + vtx_attr.g0.NormalElements, vtx_attr.g0.NormalIndex3); + for (u32 i = 0; i < vtx_desc.low.Color.Size(); i++) + { + size += VertexLoader_Color::GetSize(vtx_desc.low.Color[i], vtx_attr.GetColorFormat(i)); + } + for (u32 i = 0; i < vtx_desc.high.TexCoord.Size(); i++) + { + size += VertexLoader_TextCoord::GetSize(vtx_desc.high.TexCoord[i], vtx_attr.GetTexFormat(i), + vtx_attr.GetTexElements(i)); + } + return size; +} + +u32 VertexLoaderBase::GetVertexComponents(const TVtxDesc& vtx_desc, const VAT& vtx_attr) +{ + u32 components = 0; + if (vtx_desc.low.PosMatIdx) + components |= VB_HAS_POSMTXIDX; + for (u32 i = 0; i < vtx_desc.low.TexMatIdx.Size(); i++) + { + if (vtx_desc.low.TexMatIdx[i]) + components |= VB_HAS_TEXMTXIDX0 << i; + } + // Vertices always have positions; thus there is no VB_HAS_POS as it would always be set + if (vtx_desc.low.Normal != VertexComponentFormat::NotPresent) + { + components |= VB_HAS_NRM0; + if (vtx_attr.g0.NormalElements == NormalComponentCount::NBT) + components |= VB_HAS_NRM1 | VB_HAS_NRM2; + } + for (u32 i = 0; i < vtx_desc.low.Color.Size(); i++) + { + if (vtx_desc.low.Color[i] != VertexComponentFormat::NotPresent) + components |= VB_HAS_COL0 << i; + } + for (u32 i = 0; i < vtx_desc.high.TexCoord.Size(); i++) + { + if (vtx_desc.high.TexCoord[i] != VertexComponentFormat::NotPresent) + components |= VB_HAS_UV0 << i; + } + return components; +} + std::unique_ptr VertexLoaderBase::CreateVertexLoader(const TVtxDesc& vtx_desc, const VAT& vtx_attr) { diff --git a/Source/Core/VideoCommon/VertexLoaderBase.h b/Source/Core/VideoCommon/VertexLoaderBase.h index 2c787479b6..2e73fbad1d 100644 --- a/Source/Core/VideoCommon/VertexLoaderBase.h +++ b/Source/Core/VideoCommon/VertexLoaderBase.h @@ -60,15 +60,17 @@ struct hash class VertexLoaderBase { public: + static u32 GetVertexSize(const TVtxDesc& vtx_desc, const VAT& vtx_attr); + static u32 GetVertexComponents(const TVtxDesc& vtx_desc, const VAT& vtx_attr); static std::unique_ptr CreateVertexLoader(const TVtxDesc& vtx_desc, const VAT& vtx_attr); virtual ~VertexLoaderBase() {} virtual int RunVertices(DataReader src, DataReader dst, int count) = 0; // per loader public state - int m_VertexSize = 0; // number of bytes of a raw GC vertex PortableVertexDeclaration m_native_vtx_decl{}; - u32 m_native_components = 0; + const u32 m_vertex_size; // number of bytes of a raw GC vertex + const u32 m_native_components; // used by VertexLoaderManager NativeVertexFormat* m_native_vertex_format = nullptr; @@ -76,7 +78,10 @@ public: protected: VertexLoaderBase(const TVtxDesc& vtx_desc, const VAT& vtx_attr) - : m_VtxDesc{vtx_desc}, m_VtxAttr{vtx_attr} {}; + : m_VtxDesc{vtx_desc}, m_VtxAttr{vtx_attr}, m_vertex_size{GetVertexSize(vtx_desc, vtx_attr)}, + m_native_components{GetVertexComponents(vtx_desc, vtx_attr)} + { + } // GC vertex format const VAT m_VtxAttr; diff --git a/Source/Core/VideoCommon/VertexLoaderManager.cpp b/Source/Core/VideoCommon/VertexLoaderManager.cpp index ab362fc29c..c657ed7989 100644 --- a/Source/Core/VideoCommon/VertexLoaderManager.cpp +++ b/Source/Core/VideoCommon/VertexLoaderManager.cpp @@ -247,7 +247,7 @@ int RunVertices(int vtx_attr_group, int primitive, int count, DataReader src, bo VertexLoaderBase* loader = RefreshLoader(vtx_attr_group, is_preprocess); - int size = count * loader->m_VertexSize; + int size = count * loader->m_vertex_size; if ((int)src.size() < size) return -1; diff --git a/Source/Core/VideoCommon/VertexLoaderX64.cpp b/Source/Core/VideoCommon/VertexLoaderX64.cpp index e6d94693b8..89eb841f5e 100644 --- a/Source/Core/VideoCommon/VertexLoaderX64.cpp +++ b/Source/Core/VideoCommon/VertexLoaderX64.cpp @@ -418,7 +418,6 @@ void VertexLoaderX64::GenerateVertexLoader() MOV(32, MPIC(VertexLoaderManager::position_matrix_index, count_reg, SCALE_4), R(scratch1)); SetJumpTarget(dont_store); - m_native_components |= VB_HAS_POSMTXIDX; m_native_vtx_decl.posmtx.components = 4; m_native_vtx_decl.posmtx.enable = true; m_native_vtx_decl.posmtx.offset = m_dst_ofs; @@ -457,10 +456,6 @@ void VertexLoaderX64::GenerateVertexLoader() data.AddMemOffset(ReadVertex(data, m_VtxDesc.low.Normal, m_VtxAttr.g0.NormalFormat, 3, 3, true, scaling_exponent, &m_native_vtx_decl.normals[i])); } - - m_native_components |= VB_HAS_NRM0; - if (m_VtxAttr.g0.NormalElements == NormalComponentCount::NBT) - m_native_components |= VB_HAS_NRM1 | VB_HAS_NRM2; } for (size_t i = 0; i < m_VtxDesc.low.Color.Size(); i++) @@ -469,7 +464,6 @@ void VertexLoaderX64::GenerateVertexLoader() { data = GetVertexAddr(ARRAY_COLOR0 + int(i), m_VtxDesc.low.Color[i]); ReadColor(data, m_VtxDesc.low.Color[i], m_VtxAttr.GetColorFormat(i)); - m_native_components |= VB_HAS_COL0 << i; m_native_vtx_decl.colors[i].components = 4; m_native_vtx_decl.colors[i].enable = true; m_native_vtx_decl.colors[i].offset = m_dst_ofs; @@ -489,11 +483,9 @@ void VertexLoaderX64::GenerateVertexLoader() ReadVertex(data, m_VtxDesc.high.TexCoord[i], m_VtxAttr.GetTexFormat(i), elements, m_VtxDesc.low.TexMatIdx[i] ? 2 : elements, m_VtxAttr.g0.ByteDequant, scaling_exponent, &m_native_vtx_decl.texcoords[i]); - m_native_components |= VB_HAS_UV0 << i; } if (m_VtxDesc.low.TexMatIdx[i]) { - m_native_components |= VB_HAS_TEXMTXIDX0 << i; m_native_vtx_decl.texcoords[i].components = 3; m_native_vtx_decl.texcoords[i].enable = true; m_native_vtx_decl.texcoords[i].type = VAR_FLOAT; @@ -544,7 +536,7 @@ void VertexLoaderX64::GenerateVertexLoader() RET(); } - m_VertexSize = m_src_ofs; + ASSERT(m_vertex_size == m_src_ofs); m_native_vtx_decl.stride = m_dst_ofs; } diff --git a/Source/UnitTests/VideoCommon/VertexLoaderTest.cpp b/Source/UnitTests/VideoCommon/VertexLoaderTest.cpp index 7f9dbdec84..925a13114a 100644 --- a/Source/UnitTests/VideoCommon/VertexLoaderTest.cpp +++ b/Source/UnitTests/VideoCommon/VertexLoaderTest.cpp @@ -62,7 +62,7 @@ protected: void CreateAndCheckSizes(size_t input_size, size_t output_size) { m_loader = VertexLoaderBase::CreateVertexLoader(m_vtx_desc, m_vtx_attr); - ASSERT_EQ((int)input_size, m_loader->m_VertexSize); + ASSERT_EQ(input_size, m_loader->m_vertex_size); ASSERT_EQ((int)output_size, m_loader->m_native_vtx_decl.stride); } From 3436a92ea5daeffce1936ae658c0922644d1123a Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Mon, 15 Mar 2021 21:02:25 -0700 Subject: [PATCH 09/24] Don't reset the FIFO frame/object limit when unpausing --- Source/Core/DolphinQt/FIFO/FIFOPlayerWindow.cpp | 3 ++- Source/Core/DolphinQt/FIFO/FIFOPlayerWindow.h | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Source/Core/DolphinQt/FIFO/FIFOPlayerWindow.cpp b/Source/Core/DolphinQt/FIFO/FIFOPlayerWindow.cpp index ae351792fe..d2132f3cd6 100644 --- a/Source/Core/DolphinQt/FIFO/FIFOPlayerWindow.cpp +++ b/Source/Core/DolphinQt/FIFO/FIFOPlayerWindow.cpp @@ -50,10 +50,11 @@ FIFOPlayerWindow::FIFOPlayerWindow(QWidget* parent) : QDialog(parent) }); connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, [this](Core::State state) { - if (state == Core::State::Running) + if (state == Core::State::Running && m_emu_state != Core::State::Paused) OnEmulationStarted(); else if (state == Core::State::Uninitialized) OnEmulationStopped(); + m_emu_state = state; }); } diff --git a/Source/Core/DolphinQt/FIFO/FIFOPlayerWindow.h b/Source/Core/DolphinQt/FIFO/FIFOPlayerWindow.h index 5441b38aba..10df9b0b96 100644 --- a/Source/Core/DolphinQt/FIFO/FIFOPlayerWindow.h +++ b/Source/Core/DolphinQt/FIFO/FIFOPlayerWindow.h @@ -6,6 +6,8 @@ #include +#include "Core/Core.h" + class QCheckBox; class QDialogButtonBox; class QLabel; @@ -62,4 +64,5 @@ private: QDialogButtonBox* m_button_box; FIFOAnalyzer* m_analyzer; + Core::State m_emu_state = Core::State::Uninitialized; }; From 5ebe63b1752c02f762985f166422e7d1da4a6353 Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Wed, 17 Mar 2021 12:08:11 -0700 Subject: [PATCH 10/24] Reset the from frame/object to 0 on starting FIFO playback Now that this is only called when playback actually starts (and not on unpausing), this change makes the experience a bit better (no more missing objects from not having reset the from object after changing FIFOs). --- Source/Core/DolphinQt/FIFO/FIFOPlayerWindow.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/Core/DolphinQt/FIFO/FIFOPlayerWindow.cpp b/Source/Core/DolphinQt/FIFO/FIFOPlayerWindow.cpp index d2132f3cd6..d88581b6f5 100644 --- a/Source/Core/DolphinQt/FIFO/FIFOPlayerWindow.cpp +++ b/Source/Core/DolphinQt/FIFO/FIFOPlayerWindow.cpp @@ -304,6 +304,8 @@ void FIFOPlayerWindow::OnFIFOLoaded() m_frame_range_to->setMaximum(frame_count); m_object_range_to->setMaximum(object_count); + m_frame_range_from->setValue(0); + m_object_range_from->setValue(0); m_frame_range_to->setValue(frame_count); m_object_range_to->setValue(object_count); From 263ca79aaeef9d768a779738b7ce3bf2b3e610c7 Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Mon, 8 Feb 2021 16:10:57 -0800 Subject: [PATCH 11/24] Adjust FIFO player object ranges A single object can be selected instead of 2 (it was already inclusive internally), and the maximum value is the highest number of objects in any frame (minus 1) to reduce jank when multiple frames are being played back. --- Source/Core/Core/FifoPlayer/FifoPlayer.cpp | 12 ++++++++++++ Source/Core/Core/FifoPlayer/FifoPlayer.h | 1 + Source/Core/DolphinQt/FIFO/FIFOPlayerWindow.cpp | 10 +++++----- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/Source/Core/Core/FifoPlayer/FifoPlayer.cpp b/Source/Core/Core/FifoPlayer/FifoPlayer.cpp index 880ef791a5..48b6b581d5 100644 --- a/Source/Core/Core/FifoPlayer/FifoPlayer.cpp +++ b/Source/Core/Core/FifoPlayer/FifoPlayer.cpp @@ -189,6 +189,18 @@ bool FifoPlayer::IsRunningWithFakeVideoInterfaceUpdates() const return m_File->ShouldGenerateFakeVIUpdates(); } +u32 FifoPlayer::GetMaxObjectCount() const +{ + u32 result = 0; + for (auto& frame : m_FrameInfo) + { + const u32 count = static_cast(frame.objectStarts.size()); + if (count > result) + result = count; + } + return result; +} + u32 FifoPlayer::GetFrameObjectCount() const { if (m_CurrentFrame < m_FrameInfo.size()) diff --git a/Source/Core/Core/FifoPlayer/FifoPlayer.h b/Source/Core/Core/FifoPlayer/FifoPlayer.h index 5302e8cfcb..0f326c3cdb 100644 --- a/Source/Core/Core/FifoPlayer/FifoPlayer.h +++ b/Source/Core/Core/FifoPlayer/FifoPlayer.h @@ -74,6 +74,7 @@ public: bool IsPlaying() const; FifoDataFile* GetFile() const { return m_File.get(); } + u32 GetMaxObjectCount() const; u32 GetFrameObjectCount() const; u32 GetCurrentFrameNum() const { return m_CurrentFrame; } const AnalyzedFrameInfo& GetAnalyzedFrameInfo(u32 frame) const { return m_FrameInfo[frame]; } diff --git a/Source/Core/DolphinQt/FIFO/FIFOPlayerWindow.cpp b/Source/Core/DolphinQt/FIFO/FIFOPlayerWindow.cpp index d88581b6f5..f888bb255d 100644 --- a/Source/Core/DolphinQt/FIFO/FIFOPlayerWindow.cpp +++ b/Source/Core/DolphinQt/FIFO/FIFOPlayerWindow.cpp @@ -298,16 +298,16 @@ void FIFOPlayerWindow::OnFIFOLoaded() { FifoDataFile* file = FifoPlayer::GetInstance().GetFile(); - auto object_count = FifoPlayer::GetInstance().GetFrameObjectCount(); + auto object_count = FifoPlayer::GetInstance().GetMaxObjectCount(); auto frame_count = file->GetFrameCount(); m_frame_range_to->setMaximum(frame_count); - m_object_range_to->setMaximum(object_count); + m_object_range_to->setMaximum(object_count - 1); m_frame_range_from->setValue(0); m_object_range_from->setValue(0); m_frame_range_to->setValue(frame_count); - m_object_range_to->setValue(object_count); + m_object_range_to->setValue(object_count - 1); UpdateInfo(); UpdateLimits(); @@ -336,8 +336,8 @@ void FIFOPlayerWindow::UpdateLimits() { m_frame_range_from->setMaximum(std::max(m_frame_range_to->value() - 1, 0)); m_frame_range_to->setMinimum(m_frame_range_from->value() + 1); - m_object_range_from->setMaximum(std::max(m_object_range_to->value() - 1, 0)); - m_object_range_to->setMinimum(m_object_range_from->value() + 1); + m_object_range_from->setMaximum(m_object_range_to->value()); + m_object_range_to->setMinimum(m_object_range_from->value()); } void FIFOPlayerWindow::UpdateControls() From 58333d6feb7eb9bb6d9c5026124345a29a1cc255 Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Mon, 8 Feb 2021 16:25:57 -0800 Subject: [PATCH 12/24] Make FIFO frame count inclusive The 'zero frames in the range' check can be removed because now there is always at least 1 frame; of course that might be the same frame over and over again, but that's still useful for e.g. Free Look (and the 1 frame repeating effect already occurred when frame count was exclusive). --- Source/Core/Core/FifoPlayer/FifoPlayer.cpp | 19 ++++++++----------- .../Core/DolphinQt/FIFO/FIFOPlayerWindow.cpp | 8 ++++---- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/Source/Core/Core/FifoPlayer/FifoPlayer.cpp b/Source/Core/Core/FifoPlayer/FifoPlayer.cpp index 48b6b581d5..ef8b81e8b1 100644 --- a/Source/Core/Core/FifoPlayer/FifoPlayer.cpp +++ b/Source/Core/Core/FifoPlayer/FifoPlayer.cpp @@ -51,7 +51,7 @@ bool FifoPlayer::Open(const std::string& filename) { FifoPlaybackAnalyzer::AnalyzeFrames(m_File.get(), m_FrameInfo); - m_FrameRangeEnd = m_File->GetFrameCount(); + m_FrameRangeEnd = m_File->GetFrameCount() - 1; } if (m_FileLoadedCb) @@ -131,13 +131,10 @@ private: CPU::State FifoPlayer::AdvanceFrame() { - if (m_CurrentFrame >= m_FrameRangeEnd) + if (m_CurrentFrame > m_FrameRangeEnd) { if (!m_Loop) return CPU::State::PowerDown; - // If there are zero frames in the range then sleep instead of busy spinning - if (m_FrameRangeStart >= m_FrameRangeEnd) - return CPU::State::Stepping; // When looping, reload the contents of all the BP/CP/CF registers. // This ensures that each time the first frame is played back, the state of the @@ -215,9 +212,9 @@ void FifoPlayer::SetFrameRangeStart(u32 start) { if (m_File) { - u32 frameCount = m_File->GetFrameCount(); - if (start > frameCount) - start = frameCount; + const u32 lastFrame = m_File->GetFrameCount() - 1; + if (start > lastFrame) + start = lastFrame; m_FrameRangeStart = start; if (m_FrameRangeEnd < start) @@ -232,9 +229,9 @@ void FifoPlayer::SetFrameRangeEnd(u32 end) { if (m_File) { - u32 frameCount = m_File->GetFrameCount(); - if (end > frameCount) - end = frameCount; + const u32 lastFrame = m_File->GetFrameCount() - 1; + if (end > lastFrame) + end = lastFrame; m_FrameRangeEnd = end; if (m_FrameRangeStart > end) diff --git a/Source/Core/DolphinQt/FIFO/FIFOPlayerWindow.cpp b/Source/Core/DolphinQt/FIFO/FIFOPlayerWindow.cpp index f888bb255d..0b76a9e72c 100644 --- a/Source/Core/DolphinQt/FIFO/FIFOPlayerWindow.cpp +++ b/Source/Core/DolphinQt/FIFO/FIFOPlayerWindow.cpp @@ -301,12 +301,12 @@ void FIFOPlayerWindow::OnFIFOLoaded() auto object_count = FifoPlayer::GetInstance().GetMaxObjectCount(); auto frame_count = file->GetFrameCount(); - m_frame_range_to->setMaximum(frame_count); + m_frame_range_to->setMaximum(frame_count - 1); m_object_range_to->setMaximum(object_count - 1); m_frame_range_from->setValue(0); m_object_range_from->setValue(0); - m_frame_range_to->setValue(frame_count); + m_frame_range_to->setValue(frame_count - 1); m_object_range_to->setValue(object_count - 1); UpdateInfo(); @@ -334,8 +334,8 @@ void FIFOPlayerWindow::OnLimitsChanged() void FIFOPlayerWindow::UpdateLimits() { - m_frame_range_from->setMaximum(std::max(m_frame_range_to->value() - 1, 0)); - m_frame_range_to->setMinimum(m_frame_range_from->value() + 1); + m_frame_range_from->setMaximum(m_frame_range_to->value()); + m_frame_range_to->setMinimum(m_frame_range_from->value()); m_object_range_from->setMaximum(m_object_range_to->value()); m_object_range_to->setMinimum(m_object_range_from->value()); } From a557230dea09d09e87517f0fd4b8d8b518df4913 Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Fri, 12 Feb 2021 18:49:23 -0800 Subject: [PATCH 13/24] Fix crash when attempting to analyze a FIFO after stopping playback --- Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp | 9 +++++++++ Source/Core/DolphinQt/FIFO/FIFOPlayerWindow.cpp | 1 + 2 files changed, 10 insertions(+) diff --git a/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp b/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp index 4b9020ab8f..db0ff42488 100644 --- a/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp +++ b/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp @@ -165,6 +165,9 @@ void FIFOAnalyzer::UpdateDetails() m_detail_list->clear(); m_object_data_offsets.clear(); + if (!FifoPlayer::GetInstance().IsPlaying()) + return; + auto items = m_tree_widget->selectedItems(); if (items.isEmpty() || items[0]->data(0, OBJECT_ROLE).isNull()) @@ -316,6 +319,9 @@ void FIFOAnalyzer::BeginSearch() { QString search_str = m_search_edit->text(); + if (!FifoPlayer::GetInstance().IsPlaying()) + return; + auto items = m_tree_widget->selectedItems(); if (items.isEmpty() || items[0]->data(0, FRAME_ROLE).isNull()) @@ -462,6 +468,9 @@ void FIFOAnalyzer::UpdateDescription() { m_entry_detail_browser->clear(); + if (!FifoPlayer::GetInstance().IsPlaying()) + return; + auto items = m_tree_widget->selectedItems(); if (items.isEmpty()) diff --git a/Source/Core/DolphinQt/FIFO/FIFOPlayerWindow.cpp b/Source/Core/DolphinQt/FIFO/FIFOPlayerWindow.cpp index 0b76a9e72c..c4d29b1165 100644 --- a/Source/Core/DolphinQt/FIFO/FIFOPlayerWindow.cpp +++ b/Source/Core/DolphinQt/FIFO/FIFOPlayerWindow.cpp @@ -245,6 +245,7 @@ void FIFOPlayerWindow::OnEmulationStopped() StopRecording(); UpdateControls(); + m_analyzer->Update(); } void FIFOPlayerWindow::OnRecordingDone() From ef75381a84dbd10b240d65b19fd18b6db5ed354f Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Fri, 12 Feb 2021 18:50:33 -0800 Subject: [PATCH 14/24] Fix occasional deadlock when stopping FIFO playback --- Source/Core/Core/FifoPlayer/FifoPlayer.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/Core/Core/FifoPlayer/FifoPlayer.cpp b/Source/Core/Core/FifoPlayer/FifoPlayer.cpp index ef8b81e8b1..8ed4481032 100644 --- a/Source/Core/Core/FifoPlayer/FifoPlayer.cpp +++ b/Source/Core/Core/FifoPlayer/FifoPlayer.cpp @@ -384,6 +384,8 @@ void FifoPlayer::WriteFifo(const u8* data, u32 start, u32 end) { while (IsHighWatermarkSet()) { + if (CPU::GetState() != CPU::State::Running) + break; CoreTiming::Idle(); CoreTiming::Advance(); } From 28b71c65afb49b41639c26eb21c3f8e01138015b Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Wed, 31 Mar 2021 22:43:21 -0700 Subject: [PATCH 15/24] Fix same object count being used for all frames in the FIFO analyzer If the number of objects varied, this would result in either missing objects on some frames, or too many objects on some frames; the latter case could cause crashes. Since it used the current frame to get the count, if the FIFO is started before the FIFO analyzer is opened, then the current frame is effectively random, making it hard to reproduce consistently. This issue has existed since the FIFO analyzer was implemented for Qt. --- Source/Core/Core/FifoPlayer/FifoPlayer.cpp | 11 ++++++++--- Source/Core/Core/FifoPlayer/FifoPlayer.h | 3 ++- Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp | 17 ++++++++--------- Source/Core/DolphinQt/FIFO/FIFOPlayerWindow.cpp | 2 +- 4 files changed, 19 insertions(+), 14 deletions(-) diff --git a/Source/Core/Core/FifoPlayer/FifoPlayer.cpp b/Source/Core/Core/FifoPlayer/FifoPlayer.cpp index 8ed4481032..da35c44646 100644 --- a/Source/Core/Core/FifoPlayer/FifoPlayer.cpp +++ b/Source/Core/Core/FifoPlayer/FifoPlayer.cpp @@ -198,16 +198,21 @@ u32 FifoPlayer::GetMaxObjectCount() const return result; } -u32 FifoPlayer::GetFrameObjectCount() const +u32 FifoPlayer::GetFrameObjectCount(u32 frame) const { - if (m_CurrentFrame < m_FrameInfo.size()) + if (frame < m_FrameInfo.size()) { - return (u32)(m_FrameInfo[m_CurrentFrame].objectStarts.size()); + return static_cast(m_FrameInfo[frame].objectStarts.size()); } return 0; } +u32 FifoPlayer::GetCurrentFrameObjectCount() const +{ + return GetFrameObjectCount(m_CurrentFrame); +} + void FifoPlayer::SetFrameRangeStart(u32 start) { if (m_File) diff --git a/Source/Core/Core/FifoPlayer/FifoPlayer.h b/Source/Core/Core/FifoPlayer/FifoPlayer.h index 0f326c3cdb..2b9b8947d9 100644 --- a/Source/Core/Core/FifoPlayer/FifoPlayer.h +++ b/Source/Core/Core/FifoPlayer/FifoPlayer.h @@ -75,7 +75,8 @@ public: FifoDataFile* GetFile() const { return m_File.get(); } u32 GetMaxObjectCount() const; - u32 GetFrameObjectCount() const; + u32 GetFrameObjectCount(u32 frame) const; + u32 GetCurrentFrameObjectCount() const; u32 GetCurrentFrameNum() const { return m_CurrentFrame; } const AnalyzedFrameInfo& GetAnalyzedFrameInfo(u32 frame) const { return m_FrameInfo[frame]; } // Frame range diff --git a/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp b/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp index db0ff42488..7cf804f899 100644 --- a/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp +++ b/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp @@ -139,23 +139,22 @@ void FIFOAnalyzer::UpdateTree() auto* file = FifoPlayer::GetInstance().GetFile(); - int object_count = FifoPlayer::GetInstance().GetFrameObjectCount(); - int frame_count = file->GetFrameCount(); - - for (int i = 0; i < frame_count; i++) + const u32 frame_count = file->GetFrameCount(); + for (u32 frame = 0; frame < frame_count; frame++) { - auto* frame_item = new QTreeWidgetItem({tr("Frame %1").arg(i)}); + auto* frame_item = new QTreeWidgetItem({tr("Frame %1").arg(frame)}); recording_item->addChild(frame_item); - for (int j = 0; j < object_count; j++) + const u32 object_count = FifoPlayer::GetInstance().GetFrameObjectCount(frame); + for (u32 object = 0; object < object_count; object++) { - auto* object_item = new QTreeWidgetItem({tr("Object %1").arg(j)}); + auto* object_item = new QTreeWidgetItem({tr("Object %1").arg(object)}); frame_item->addChild(object_item); - object_item->setData(0, FRAME_ROLE, i); - object_item->setData(0, OBJECT_ROLE, j); + object_item->setData(0, FRAME_ROLE, frame); + object_item->setData(0, OBJECT_ROLE, object); } } } diff --git a/Source/Core/DolphinQt/FIFO/FIFOPlayerWindow.cpp b/Source/Core/DolphinQt/FIFO/FIFOPlayerWindow.cpp index c4d29b1165..e4154b6b6c 100644 --- a/Source/Core/DolphinQt/FIFO/FIFOPlayerWindow.cpp +++ b/Source/Core/DolphinQt/FIFO/FIFOPlayerWindow.cpp @@ -262,7 +262,7 @@ void FIFOPlayerWindow::UpdateInfo() m_info_label->setText( tr("%1 frame(s)\n%2 object(s)\nCurrent Frame: %3") .arg(QString::number(file->GetFrameCount()), - QString::number(FifoPlayer::GetInstance().GetFrameObjectCount()), + QString::number(FifoPlayer::GetInstance().GetCurrentFrameObjectCount()), QString::number(FifoPlayer::GetInstance().GetCurrentFrameNum()))); return; } From 05bd15a928a6e9d81653812829d569789ee72718 Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Fri, 19 Feb 2021 20:03:31 -0800 Subject: [PATCH 16/24] Clear m_object_data_offsets first and require it before UpdateDescription It still tries to update the description on clearing, potentially with bad data. --- Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp b/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp index 7cf804f899..baff4512b8 100644 --- a/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp +++ b/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp @@ -161,8 +161,12 @@ void FIFOAnalyzer::UpdateTree() void FIFOAnalyzer::UpdateDetails() { - m_detail_list->clear(); + // Clearing the detail list can update the selection, which causes UpdateDescription to be called + // immediately. However, the object data offsets have not been recalculated yet, which can cause + // the wrong data to be used, potentially leading to out of bounds data or other bad things. + // Clear m_object_data_offsets first, so that UpdateDescription exits immediately. m_object_data_offsets.clear(); + m_detail_list->clear(); if (!FifoPlayer::GetInstance().IsPlaying()) return; @@ -472,7 +476,7 @@ void FIFOAnalyzer::UpdateDescription() auto items = m_tree_widget->selectedItems(); - if (items.isEmpty()) + if (items.isEmpty() || m_object_data_offsets.empty()) return; int frame_nr = items[0]->data(0, FRAME_ROLE).toInt(); From 83f7c41e318be983879eb18bbce3f7d5585bdcfd Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Tue, 16 Feb 2021 11:24:57 -0800 Subject: [PATCH 17/24] Make the FIFO Player a separate window This way, it can be focused with the render window behind it, instead of having the main window show up and cover the render window. This is useful for adjusting the object range, among other things. --- .../Core/DolphinQt/FIFO/FIFOPlayerWindow.cpp | 25 ++++++++++++++++--- Source/Core/DolphinQt/FIFO/FIFOPlayerWindow.h | 6 +++-- Source/Core/DolphinQt/MainWindow.cpp | 2 +- 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/Source/Core/DolphinQt/FIFO/FIFOPlayerWindow.cpp b/Source/Core/DolphinQt/FIFO/FIFOPlayerWindow.cpp index e4154b6b6c..dc1b4f44b7 100644 --- a/Source/Core/DolphinQt/FIFO/FIFOPlayerWindow.cpp +++ b/Source/Core/DolphinQt/FIFO/FIFOPlayerWindow.cpp @@ -6,9 +6,13 @@ #include #include +#include #include #include #include +#include +#include +#include #include #include #include @@ -26,12 +30,13 @@ #include "DolphinQt/FIFO/FIFOAnalyzer.h" #include "DolphinQt/QtUtils/ModalMessageBox.h" #include "DolphinQt/QtUtils/QueueOnObject.h" +#include "DolphinQt/Resources.h" #include "DolphinQt/Settings.h" -FIFOPlayerWindow::FIFOPlayerWindow(QWidget* parent) : QDialog(parent) +FIFOPlayerWindow::FIFOPlayerWindow(QWidget* parent) : QWidget(parent) { setWindowTitle(tr("FIFO Player")); - setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + setWindowIcon(Resources::GetAppIcon()); CreateWidgets(); ConnectWidgets(); @@ -56,6 +61,8 @@ FIFOPlayerWindow::FIFOPlayerWindow(QWidget* parent) : QDialog(parent) OnEmulationStopped(); m_emu_state = state; }); + + installEventFilter(this); } FIFOPlayerWindow::~FIFOPlayerWindow() @@ -167,7 +174,7 @@ void FIFOPlayerWindow::ConnectWidgets() connect(m_save, &QPushButton::clicked, this, &FIFOPlayerWindow::SaveRecording); connect(m_record, &QPushButton::clicked, this, &FIFOPlayerWindow::StartRecording); connect(m_stop, &QPushButton::clicked, this, &FIFOPlayerWindow::StopRecording); - connect(m_button_box, &QDialogButtonBox::rejected, this, &FIFOPlayerWindow::reject); + connect(m_button_box, &QDialogButtonBox::rejected, this, &FIFOPlayerWindow::hide); connect(m_early_memory_updates, &QCheckBox::toggled, this, &FIFOPlayerWindow::OnEarlyMemoryUpdatesChanged); connect(m_frame_range_from, qOverload(&QSpinBox::valueChanged), this, @@ -371,3 +378,15 @@ void FIFOPlayerWindow::UpdateControls() m_save->setEnabled(FifoRecorder::GetInstance().IsRecordingDone()); } + +bool FIFOPlayerWindow::eventFilter(QObject* object, QEvent* event) +{ + // Close when escape is pressed + if (event->type() == QEvent::KeyPress) + { + if (static_cast(event)->matches(QKeySequence::Cancel)) + hide(); + } + + return false; +} diff --git a/Source/Core/DolphinQt/FIFO/FIFOPlayerWindow.h b/Source/Core/DolphinQt/FIFO/FIFOPlayerWindow.h index 10df9b0b96..d6bc8b3600 100644 --- a/Source/Core/DolphinQt/FIFO/FIFOPlayerWindow.h +++ b/Source/Core/DolphinQt/FIFO/FIFOPlayerWindow.h @@ -4,7 +4,7 @@ #pragma once -#include +#include #include "Core/Core.h" @@ -15,7 +15,7 @@ class QPushButton; class QSpinBox; class FIFOAnalyzer; -class FIFOPlayerWindow : public QDialog +class FIFOPlayerWindow : public QWidget { Q_OBJECT public: @@ -45,6 +45,8 @@ private: void UpdateInfo(); void UpdateLimits(); + bool eventFilter(QObject* object, QEvent* event) final override; + QLabel* m_info_label; QPushButton* m_load; QPushButton* m_save; diff --git a/Source/Core/DolphinQt/MainWindow.cpp b/Source/Core/DolphinQt/MainWindow.cpp index 3261a4b740..61e58eb19f 100644 --- a/Source/Core/DolphinQt/MainWindow.cpp +++ b/Source/Core/DolphinQt/MainWindow.cpp @@ -1214,7 +1214,7 @@ void MainWindow::ShowFIFOPlayer() { if (!m_fifo_window) { - m_fifo_window = new FIFOPlayerWindow(this); + m_fifo_window = new FIFOPlayerWindow; connect(m_fifo_window, &FIFOPlayerWindow::LoadFIFORequested, this, [this](const QString& path) { StartGame(path, ScanForSecondDisc::No); }); } From 1dc3ff58794900f9988e403c34e8b212c0aa8f01 Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Wed, 3 Mar 2021 17:13:33 -0800 Subject: [PATCH 18/24] Show register updates before primitive updates This also shows the register updates for object 0, which were previously not visible(!) --- Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp | 291 ++++++++++---------- 1 file changed, 153 insertions(+), 138 deletions(-) diff --git a/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp b/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp index baff4512b8..a388b04661 100644 --- a/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp +++ b/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp @@ -171,151 +171,166 @@ void FIFOAnalyzer::UpdateDetails() if (!FifoPlayer::GetInstance().IsPlaying()) return; - auto items = m_tree_widget->selectedItems(); + const auto items = m_tree_widget->selectedItems(); if (items.isEmpty() || items[0]->data(0, OBJECT_ROLE).isNull()) return; - int frame_nr = items[0]->data(0, FRAME_ROLE).toInt(); - int object_nr = items[0]->data(0, OBJECT_ROLE).toInt(); + const u32 frame_nr = items[0]->data(0, FRAME_ROLE).toUInt(); + const u32 object_nr = items[0]->data(0, OBJECT_ROLE).toUInt(); const auto& frame_info = FifoPlayer::GetInstance().GetAnalyzedFrameInfo(frame_nr); const auto& fifo_frame = FifoPlayer::GetInstance().GetFile()->GetFrame(frame_nr); - const u8* objectdata_start = &fifo_frame.fifoData[frame_info.objectStarts[object_nr]]; - const u8* objectdata_end = &fifo_frame.fifoData[frame_info.objectEnds[object_nr]]; - const u8* objectdata = objectdata_start; - const std::ptrdiff_t obj_offset = - objectdata_start - &fifo_frame.fifoData[frame_info.objectStarts[0]]; + // Note that frame_info.objectStarts[object_nr] is the start of the primitive data, + // but we want to start with the register updates which happen before that. + const u32 object_start = (object_nr == 0 ? 0 : frame_info.objectEnds[object_nr - 1]); + const u32 object_nonprim_size = frame_info.objectStarts[object_nr] - object_start; + const u32 object_size = frame_info.objectEnds[object_nr] - object_start; + + const u8* const object = &fifo_frame.fifoData[object_start]; + + u32 object_offset = 0; + while (object_offset < object_nonprim_size) + { + QString new_label; + const u32 start_offset = object_offset; + m_object_data_offsets.push_back(start_offset); + + const u8 command = object[object_offset++]; + switch (command) + { + case OpcodeDecoder::GX_NOP: + new_label = QStringLiteral("NOP"); + break; + + case OpcodeDecoder::GX_CMD_UNKNOWN_METRICS: + new_label = QStringLiteral("GX_CMD_UNKNOWN_METRICS"); + break; + + case OpcodeDecoder::GX_CMD_INVL_VC: + new_label = QStringLiteral("GX_CMD_INVL_VC"); + break; + + case OpcodeDecoder::GX_LOAD_CP_REG: + { + const u8 cmd2 = object[object_offset++]; + const u32 value = Common::swap32(&object[object_offset]); + object_offset += 4; + + const auto [name, desc] = GetCPRegInfo(cmd2, value); + ASSERT(!name.empty()); + + new_label = QStringLiteral("CP %1 %2 %3") + .arg(cmd2, 2, 16, QLatin1Char('0')) + .arg(value, 8, 16, QLatin1Char('0')) + .arg(QString::fromStdString(name)); + } + break; + + case OpcodeDecoder::GX_LOAD_XF_REG: + { + const auto [name, desc] = GetXFTransferInfo(&object[object_offset]); + const u32 cmd2 = Common::swap32(&object[object_offset]); + object_offset += 4; + ASSERT(!name.empty()); + + const u8 stream_size = ((cmd2 >> 16) & 15) + 1; + + new_label = QStringLiteral("XF %1 ").arg(cmd2, 8, 16, QLatin1Char('0')); + + for (u8 i = 0; i < stream_size; i++) + { + const u32 value = Common::swap32(&object[object_offset]); + object_offset += 4; + + new_label += QStringLiteral("%1 ").arg(value, 8, 16, QLatin1Char('0')); + } + + new_label += QStringLiteral(" ") + QString::fromStdString(name); + } + break; + + case OpcodeDecoder::GX_LOAD_INDX_A: + new_label = QStringLiteral("LOAD INDX A"); + object_offset += 4; + break; + case OpcodeDecoder::GX_LOAD_INDX_B: + new_label = QStringLiteral("LOAD INDX B"); + object_offset += 4; + break; + case OpcodeDecoder::GX_LOAD_INDX_C: + new_label = QStringLiteral("LOAD INDX C"); + object_offset += 4; + break; + case OpcodeDecoder::GX_LOAD_INDX_D: + new_label = QStringLiteral("LOAD INDX D"); + object_offset += 4; + break; + + case OpcodeDecoder::GX_CMD_CALL_DL: + // The recorder should have expanded display lists into the fifo stream and skipped the + // call to start them + // That is done to make it easier to track where memory is updated + ASSERT(false); + object_offset += 8; + new_label = QStringLiteral("CALL DL"); + break; + + case OpcodeDecoder::GX_LOAD_BP_REG: + { + const u8 cmd2 = object[object_offset++]; + const u32 cmddata = Common::swap24(&object[object_offset]); + object_offset += 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; + + default: + new_label = tr("Unexpected 0x80 call? Aborting..."); + object_offset = object_nonprim_size; + break; + } + new_label = QStringLiteral("%1: ").arg(object_start + start_offset, 8, 16, QLatin1Char('0')) + + new_label; + m_detail_list->addItem(new_label); + } + + // Object primitive data + ASSERT(object_offset == object_nonprim_size); + m_object_data_offsets.push_back(object_offset); + + const u8 cmd = object[object_offset++]; + const u16 vertex_count = Common::swap16(&object[object_offset]); + object_offset += 2; + + const u32 object_prim_size = object_size - object_offset; - int cmd = *objectdata++; - int stream_size = Common::swap16(objectdata); - objectdata += 2; QString new_label = QStringLiteral("%1: %2 %3 ") - .arg(obj_offset, 8, 16, QLatin1Char('0')) + .arg(object_start + object_offset, 8, 16, QLatin1Char('0')) .arg(cmd, 2, 16, QLatin1Char('0')) - .arg(stream_size, 4, 16, QLatin1Char('0')); - if (stream_size && ((objectdata_end - objectdata) % stream_size)) - new_label += tr("NOTE: Stream size doesn't match actual data length\n"); + .arg(vertex_count, 4, 16, QLatin1Char('0')); - while (objectdata < objectdata_end) - new_label += QStringLiteral("%1").arg(*objectdata++, 2, 16, QLatin1Char('0')); + while (object_offset < object_size) + { + u32 byte = object[object_offset++]; + new_label += QStringLiteral("%1").arg(byte, 2, 16, QLatin1Char('0')); + } + + if (vertex_count != 0 && (object_prim_size % vertex_count) != 0) + { + new_label += QLatin1Char{'\n'}; + new_label += tr("NOTE: Stream size doesn't match actual data length"); + } m_detail_list->addItem(new_label); - m_object_data_offsets.push_back(0); - - // Between objectdata_end and next_objdata_start, there are register setting commands - if (object_nr + 1 < static_cast(frame_info.objectStarts.size())) - { - const u8* next_objdata_start = &fifo_frame.fifoData[frame_info.objectStarts[object_nr + 1]]; - while (objectdata < next_objdata_start) - { - m_object_data_offsets.push_back(objectdata - objectdata_start); - int new_offset = objectdata - &fifo_frame.fifoData[frame_info.objectStarts[0]]; - int command = *objectdata++; - switch (command) - { - case OpcodeDecoder::GX_NOP: - new_label = QStringLiteral("NOP"); - break; - - case OpcodeDecoder::GX_CMD_UNKNOWN_METRICS: - new_label = QStringLiteral("GX_CMD_UNKNOWN_METRICS"); - break; - - case OpcodeDecoder::GX_CMD_INVL_VC: - new_label = QStringLiteral("GX_CMD_INVL_VC"); - break; - - case OpcodeDecoder::GX_LOAD_CP_REG: - { - u32 cmd2 = *objectdata++; - u32 value = Common::swap32(objectdata); - objectdata += 4; - const auto [name, desc] = GetCPRegInfo(cmd2, value); - ASSERT(!name.empty()); - - new_label = QStringLiteral("CP %1 %2 %3") - .arg(cmd2, 2, 16, QLatin1Char('0')) - .arg(value, 8, 16, QLatin1Char('0')) - .arg(QString::fromStdString(name)); - } - break; - - case OpcodeDecoder::GX_LOAD_XF_REG: - { - const auto [name, desc] = GetXFTransferInfo(objectdata); - u32 cmd2 = Common::swap32(objectdata); - objectdata += 4; - ASSERT(!name.empty()); - - u8 streamSize = ((cmd2 >> 16) & 15) + 1; - - const u8* stream_start = objectdata; - const u8* stream_end = stream_start + streamSize * 4; - - new_label = QStringLiteral("XF %1 ").arg(cmd2, 8, 16, QLatin1Char('0')); - while (objectdata < stream_end) - { - new_label += QStringLiteral("%1").arg(*objectdata++, 2, 16, QLatin1Char('0')); - - if (((objectdata - stream_start) % 4) == 0) - new_label += QLatin1Char(' '); - } - - new_label += QStringLiteral(" ") + QString::fromStdString(name); - } - break; - - case OpcodeDecoder::GX_LOAD_INDX_A: - case OpcodeDecoder::GX_LOAD_INDX_B: - case OpcodeDecoder::GX_LOAD_INDX_C: - case OpcodeDecoder::GX_LOAD_INDX_D: - { - objectdata += 4; - new_label = (command == OpcodeDecoder::GX_LOAD_INDX_A) ? - QStringLiteral("LOAD INDX A") : - (command == OpcodeDecoder::GX_LOAD_INDX_B) ? - QStringLiteral("LOAD INDX B") : - (command == OpcodeDecoder::GX_LOAD_INDX_C) ? QStringLiteral("LOAD INDX C") : - QStringLiteral("LOAD INDX D"); - } - break; - - case OpcodeDecoder::GX_CMD_CALL_DL: - // The recorder should have expanded display lists into the fifo stream and skipped the - // call to start them - // That is done to make it easier to track where memory is updated - ASSERT(false); - objectdata += 8; - new_label = QStringLiteral("CALL DL"); - break; - - case OpcodeDecoder::GX_LOAD_BP_REG: - { - 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; - - default: - new_label = tr("Unexpected 0x80 call? Aborting..."); - objectdata = static_cast(next_objdata_start); - break; - } - new_label = QStringLiteral("%1: ").arg(new_offset, 8, 16, QLatin1Char('0')) + new_label; - m_detail_list->addItem(new_label); - } - } } void FIFOAnalyzer::BeginSearch() @@ -474,20 +489,20 @@ void FIFOAnalyzer::UpdateDescription() if (!FifoPlayer::GetInstance().IsPlaying()) return; - auto items = m_tree_widget->selectedItems(); + const auto items = m_tree_widget->selectedItems(); if (items.isEmpty() || m_object_data_offsets.empty()) return; - int frame_nr = items[0]->data(0, FRAME_ROLE).toInt(); - int object_nr = items[0]->data(0, OBJECT_ROLE).toInt(); - int entry_nr = m_detail_list->currentRow(); + const u32 frame_nr = items[0]->data(0, FRAME_ROLE).toUInt(); + const u32 object_nr = items[0]->data(0, OBJECT_ROLE).toUInt(); + const u32 entry_nr = m_detail_list->currentRow(); - const AnalyzedFrameInfo& frame = FifoPlayer::GetInstance().GetAnalyzedFrameInfo(frame_nr); + const AnalyzedFrameInfo& frame_info = FifoPlayer::GetInstance().GetAnalyzedFrameInfo(frame_nr); const FifoFrameInfo& fifo_frame = FifoPlayer::GetInstance().GetFile()->GetFrame(frame_nr); - const u8* cmddata = - &fifo_frame.fifoData[frame.objectStarts[object_nr]] + m_object_data_offsets[entry_nr]; + const u32 object_start = (object_nr == 0 ? 0 : frame_info.objectEnds[object_nr - 1]); + const u8* cmddata = &fifo_frame.fifoData[object_start + m_object_data_offsets[entry_nr]]; // TODO: Not sure whether we should bother translating the descriptions From dbacf68b793206e48bc1c3950dc93350986b7606 Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Fri, 19 Feb 2021 14:02:59 -0800 Subject: [PATCH 19/24] Improve FIFO analyzer search function - Only one search result is generated per command/line, even if there are multiple matches in that line. - Pressing enter on the edit field begins a search, just like clicking the begin button. - The next and previous buttons are disabled until a search is begun. - The search results are cleared when changing objects or frames. - The previous button once again works (a regression from the previous commit), and the register updates and graphics data for the correct object are searched. - currentRow() never returns -1, so checking that is unnecessary (and misleading). - The 'Invalid search parameters (no object selected)' previously never showed up before because FRAME_ROLE is present if and only if OBJECT_ROLE is present. --- Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp | 105 +++++++++----------- Source/Core/DolphinQt/FIFO/FIFOAnalyzer.h | 12 ++- 2 files changed, 58 insertions(+), 59 deletions(-) diff --git a/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp b/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp index a388b04661..c04b01e40a 100644 --- a/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp +++ b/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp @@ -81,6 +81,9 @@ void FIFOAnalyzer::CreateWidgets() m_search_previous = new QPushButton(tr("Previous Match")); m_search_label = new QLabel; + m_search_next->setEnabled(false); + m_search_previous->setEnabled(false); + auto* box_layout = new QHBoxLayout; box_layout->addWidget(m_search_edit); @@ -111,6 +114,7 @@ void FIFOAnalyzer::ConnectWidgets() connect(m_detail_list, &QListWidget::itemSelectionChanged, this, &FIFOAnalyzer::UpdateDescription); + connect(m_search_edit, &QLineEdit::returnPressed, this, &FIFOAnalyzer::BeginSearch); connect(m_search_new, &QPushButton::clicked, this, &FIFOAnalyzer::BeginSearch); connect(m_search_next, &QPushButton::clicked, this, &FIFOAnalyzer::FindNext); connect(m_search_previous, &QPushButton::clicked, this, &FIFOAnalyzer::FindPrevious); @@ -167,6 +171,10 @@ void FIFOAnalyzer::UpdateDetails() // Clear m_object_data_offsets first, so that UpdateDescription exits immediately. m_object_data_offsets.clear(); m_detail_list->clear(); + m_search_results.clear(); + m_search_next->setEnabled(false); + m_search_previous->setEnabled(false); + m_search_label->clear(); if (!FifoPlayer::GetInstance().IsPlaying()) return; @@ -335,17 +343,15 @@ void FIFOAnalyzer::UpdateDetails() void FIFOAnalyzer::BeginSearch() { - QString search_str = m_search_edit->text(); + const QString search_str = m_search_edit->text(); if (!FifoPlayer::GetInstance().IsPlaying()) return; - auto items = m_tree_widget->selectedItems(); + const auto items = m_tree_widget->selectedItems(); - if (items.isEmpty() || items[0]->data(0, FRAME_ROLE).isNull()) - return; - - if (items[0]->data(0, OBJECT_ROLE).isNull()) + if (items.isEmpty() || items[0]->data(0, FRAME_ROLE).isNull() || + items[0]->data(0, OBJECT_ROLE).isNull()) { m_search_label->setText(tr("Invalid search parameters (no object selected)")); return; @@ -380,36 +386,35 @@ void FIFOAnalyzer::BeginSearch() m_search_results.clear(); - int frame_nr = items[0]->data(0, FRAME_ROLE).toInt(); - int object_nr = items[0]->data(0, OBJECT_ROLE).toInt(); + const u32 frame_nr = items[0]->data(0, FRAME_ROLE).toUInt(); + const u32 object_nr = items[0]->data(0, OBJECT_ROLE).toUInt(); const AnalyzedFrameInfo& frame_info = FifoPlayer::GetInstance().GetAnalyzedFrameInfo(frame_nr); const FifoFrameInfo& fifo_frame = FifoPlayer::GetInstance().GetFile()->GetFrame(frame_nr); - // TODO: Support searching through the last object...how do we know where the cmd data ends? + const u32 object_start = (object_nr == 0 ? 0 : frame_info.objectEnds[object_nr - 1]); + const u32 object_size = frame_info.objectEnds[object_nr] - object_start; + + const u8* const object = &fifo_frame.fifoData[object_start]; + // TODO: Support searching for bit patterns - - const auto* start_ptr = &fifo_frame.fifoData[frame_info.objectStarts[object_nr]]; - const auto* end_ptr = &fifo_frame.fifoData[frame_info.objectStarts[object_nr + 1]]; - - for (const u8* ptr = start_ptr; ptr < end_ptr - length + 1; ++ptr) + for (u32 cmd_nr = 0; cmd_nr < m_object_data_offsets.size(); cmd_nr++) { - if (std::equal(search_val.begin(), search_val.end(), ptr)) - { - SearchResult result; - result.frame = frame_nr; + const u32 cmd_start = m_object_data_offsets[cmd_nr]; + const u32 cmd_end = (cmd_nr + 1 == m_object_data_offsets.size()) ? + object_size : + m_object_data_offsets[cmd_nr + 1]; - result.object = object_nr; - result.cmd = 0; - for (unsigned int cmd_nr = 1; cmd_nr < m_object_data_offsets.size(); ++cmd_nr) + const u8* const cmd_start_ptr = &object[cmd_start]; + const u8* const cmd_end_ptr = &object[cmd_end]; + + for (const u8* ptr = cmd_start_ptr; ptr < cmd_end_ptr - length + 1; ptr++) + { + if (std::equal(search_val.begin(), search_val.end(), ptr)) { - if (ptr < start_ptr + m_object_data_offsets[cmd_nr]) - { - result.cmd = cmd_nr - 1; - break; - } + m_search_results.emplace_back(frame_nr, object_nr, cmd_nr); + break; } - m_search_results.push_back(result); } } @@ -421,41 +426,29 @@ void FIFOAnalyzer::BeginSearch() void FIFOAnalyzer::FindNext() { - int index = m_detail_list->currentRow(); + const int index = m_detail_list->currentRow(); + ASSERT(index >= 0); - if (index == -1) + auto next_result = + std::find_if(m_search_results.begin(), m_search_results.end(), + [index](auto& result) { return result.m_cmd > static_cast(index); }); + if (next_result != m_search_results.end()) { - ShowSearchResult(0); - return; - } - - for (auto it = m_search_results.begin(); it != m_search_results.end(); ++it) - { - if (it->cmd > index) - { - ShowSearchResult(it - m_search_results.begin()); - return; - } + ShowSearchResult(next_result - m_search_results.begin()); } } void FIFOAnalyzer::FindPrevious() { - int index = m_detail_list->currentRow(); + const int index = m_detail_list->currentRow(); + ASSERT(index >= 0); - if (index == -1) + auto prev_result = + std::find_if(m_search_results.rbegin(), m_search_results.rend(), + [index](auto& result) { return result.m_cmd < static_cast(index); }); + if (prev_result != m_search_results.rend()) { - ShowSearchResult(m_search_results.size() - 1); - return; - } - - for (auto it = m_search_results.rbegin(); it != m_search_results.rend(); ++it) - { - if (it->cmd < index) - { - ShowSearchResult(m_search_results.size() - 1 - (it - m_search_results.rbegin())); - return; - } + ShowSearchResult((m_search_results.rend() - prev_result) - 1); } } @@ -464,7 +457,7 @@ void FIFOAnalyzer::ShowSearchResult(size_t index) if (m_search_results.empty()) return; - if (index > m_search_results.size()) + if (index >= m_search_results.size()) { ShowSearchResult(m_search_results.size() - 1); return; @@ -473,10 +466,10 @@ void FIFOAnalyzer::ShowSearchResult(size_t index) const auto& result = m_search_results[index]; QTreeWidgetItem* object_item = - m_tree_widget->topLevelItem(0)->child(result.frame)->child(result.object); + m_tree_widget->topLevelItem(0)->child(result.m_frame)->child(result.m_object); m_tree_widget->setCurrentItem(object_item); - m_detail_list->setCurrentRow(result.cmd); + m_detail_list->setCurrentRow(result.m_cmd); m_search_next->setEnabled(index + 1 < m_search_results.size()); m_search_previous->setEnabled(index > 0); diff --git a/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.h b/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.h index f31ddde2a9..dba746cdb6 100644 --- a/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.h +++ b/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.h @@ -8,6 +8,8 @@ #include +#include "Common/CommonTypes.h" + class QGroupBox; class QLabel; class QLineEdit; @@ -57,9 +59,13 @@ private: struct SearchResult { - int frame; - int object; - int cmd; + constexpr SearchResult(u32 frame, u32 object, u32 cmd) + : m_frame(frame), m_object(object), m_cmd(cmd) + { + } + const u32 m_frame; + const u32 m_object; + const u32 m_cmd; }; std::vector m_object_data_offsets; From 2ddf2c3ba2a0b0abffd0a8a922d1d63a8dc5f0da Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Fri, 19 Feb 2021 19:12:06 -0800 Subject: [PATCH 20/24] Update and clear the description on each object change Since the description updating is tied to the selection changing on the detail list, and the detail list is recreated on each object change, behavior was somewhat broken. Clearing the list changed the current row to zero, but nothing else (particularly m_object_data_offsets) had been updated, so the description was not necessarily correct (this is easier to observe now since the vertex data is at the end, so it's easier to get different lengths of register updates). Furthermore, subsequent clears did not update the current row since there was no visible selection, so it only changed the description once. The current row is now always set to zero, which forces an update (and also scrolls the list back to the top). The presence of FRAME_ROLE and OBJECT_ROLE are also checked so that the description is cleared if no object is selected. --- Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp b/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp index c04b01e40a..e532ba72ca 100644 --- a/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp +++ b/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp @@ -339,6 +339,9 @@ void FIFOAnalyzer::UpdateDetails() } m_detail_list->addItem(new_label); + + // Needed to ensure the description updates when changing objects + m_detail_list->setCurrentRow(0); } void FIFOAnalyzer::BeginSearch() @@ -487,6 +490,9 @@ void FIFOAnalyzer::UpdateDescription() if (items.isEmpty() || m_object_data_offsets.empty()) return; + if (items[0]->data(0, FRAME_ROLE).isNull() || items[0]->data(0, OBJECT_ROLE).isNull()) + return; + const u32 frame_nr = items[0]->data(0, FRAME_ROLE).toUInt(); const u32 object_nr = items[0]->data(0, OBJECT_ROLE).toUInt(); const u32 entry_nr = m_detail_list->currentRow(); From 1a3d2c32119e15d64008a94624e592cda70b734e Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Fri, 19 Feb 2021 20:53:24 -0800 Subject: [PATCH 21/24] Coalesce NOPs --- Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp b/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp index e532ba72ca..5511fe0dfe 100644 --- a/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp +++ b/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp @@ -209,7 +209,18 @@ void FIFOAnalyzer::UpdateDetails() switch (command) { case OpcodeDecoder::GX_NOP: - new_label = QStringLiteral("NOP"); + if (object[object_offset] == OpcodeDecoder::GX_NOP) + { + u32 nop_count = 2; + while (object[++object_offset] == OpcodeDecoder::GX_NOP) + nop_count++; + + new_label = QStringLiteral("NOP (%1x)").arg(nop_count); + } + else + { + new_label = QStringLiteral("NOP"); + } break; case OpcodeDecoder::GX_CMD_UNKNOWN_METRICS: From df77a687e891efdca38223c353da0d06bc666359 Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Sat, 20 Feb 2021 13:17:42 -0800 Subject: [PATCH 22/24] Add descriptions for GX_LOAD_INDX_A/B/C/D --- Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp | 72 ++++++++++++++++++--- Source/Core/VideoCommon/CPMemory.h | 5 ++ Source/Core/VideoCommon/XFStructs.cpp | 35 ++++++++-- Source/Core/VideoCommon/XFStructs.h | 1 + 4 files changed, 98 insertions(+), 15 deletions(-) diff --git a/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp b/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp index 5511fe0dfe..676288f442 100644 --- a/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp +++ b/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp @@ -271,21 +271,37 @@ void FIFOAnalyzer::UpdateDetails() break; case OpcodeDecoder::GX_LOAD_INDX_A: - new_label = QStringLiteral("LOAD INDX A"); + { + const auto [desc, written] = + GetXFIndexedLoadInfo(ARRAY_XF_A, Common::swap32(&object[object_offset])); object_offset += 4; - break; + new_label = QStringLiteral("LOAD INDX A %1").arg(QString::fromStdString(desc)); + } + break; case OpcodeDecoder::GX_LOAD_INDX_B: - new_label = QStringLiteral("LOAD INDX B"); + { + const auto [desc, written] = + GetXFIndexedLoadInfo(ARRAY_XF_B, Common::swap32(&object[object_offset])); object_offset += 4; - break; + new_label = QStringLiteral("LOAD INDX B %1").arg(QString::fromStdString(desc)); + } + break; case OpcodeDecoder::GX_LOAD_INDX_C: - new_label = QStringLiteral("LOAD INDX C"); + { + const auto [desc, written] = + GetXFIndexedLoadInfo(ARRAY_XF_C, Common::swap32(&object[object_offset])); object_offset += 4; - break; + new_label = QStringLiteral("LOAD INDX C %1").arg(QString::fromStdString(desc)); + } + break; case OpcodeDecoder::GX_LOAD_INDX_D: - new_label = QStringLiteral("LOAD INDX D"); + { + const auto [desc, written] = + GetXFIndexedLoadInfo(ARRAY_XF_D, Common::swap32(&object[object_offset])); object_offset += 4; - break; + new_label = QStringLiteral("LOAD INDX D %1").arg(QString::fromStdString(desc)); + } + break; case OpcodeDecoder::GX_CMD_CALL_DL: // The recorder should have expanded display lists into the fifo stream and skipped the @@ -565,6 +581,46 @@ void FIFOAnalyzer::UpdateDescription() else text += QString::fromStdString(desc); } + else if (*cmddata == OpcodeDecoder::GX_LOAD_INDX_A) + { + const auto [desc, written] = GetXFIndexedLoadInfo(ARRAY_XF_A, Common::swap32(cmddata + 1)); + + text = QString::fromStdString(desc); + text += QLatin1Char{'\n'}; + text += tr("Usually used for position matrices"); + text += QLatin1Char{'\n'}; + text += QString::fromStdString(written); + } + else if (*cmddata == OpcodeDecoder::GX_LOAD_INDX_B) + { + const auto [desc, written] = GetXFIndexedLoadInfo(ARRAY_XF_B, Common::swap32(cmddata + 1)); + + text = QString::fromStdString(desc); + text += QLatin1Char{'\n'}; + text += tr("Usually used for normal matrices"); + text += QLatin1Char{'\n'}; + text += QString::fromStdString(written); + } + else if (*cmddata == OpcodeDecoder::GX_LOAD_INDX_C) + { + const auto [desc, written] = GetXFIndexedLoadInfo(ARRAY_XF_C, Common::swap32(cmddata + 1)); + + text = QString::fromStdString(desc); + text += QLatin1Char{'\n'}; + text += tr("Usually used for tex coord matrices"); + text += QLatin1Char{'\n'}; + text += QString::fromStdString(written); + } + else if (*cmddata == OpcodeDecoder::GX_LOAD_INDX_D) + { + const auto [desc, written] = GetXFIndexedLoadInfo(ARRAY_XF_D, Common::swap32(cmddata + 1)); + + text = QString::fromStdString(desc); + text += QLatin1Char{'\n'}; + text += tr("Usually used for light objects"); + text += QLatin1Char{'\n'}; + text += QString::fromStdString(written); + } else { text = tr("No description available"); diff --git a/Source/Core/VideoCommon/CPMemory.h b/Source/Core/VideoCommon/CPMemory.h index c82521ebb4..488d210129 100644 --- a/Source/Core/VideoCommon/CPMemory.h +++ b/Source/Core/VideoCommon/CPMemory.h @@ -63,6 +63,11 @@ enum ARRAY_TEXCOORD0 = 4, NUM_TEXCOORD_ARRAYS = 8, + ARRAY_XF_A = 12, // Usually used for position matrices + ARRAY_XF_B = 13, // Usually used for normal matrices + ARRAY_XF_C = 14, // Usually used for tex coord matrices + ARRAY_XF_D = 15, // Usually used for light objects + // Number of arrays related to vertex components (position, normal, color, tex coord) // Excludes the 4 arrays used for indexed XF loads NUM_VERTEX_COMPONENT_ARRAYS = 12, diff --git a/Source/Core/VideoCommon/XFStructs.cpp b/Source/Core/VideoCommon/XFStructs.cpp index 9ceaf2edc1..4da229c422 100644 --- a/Source/Core/VideoCommon/XFStructs.cpp +++ b/Source/Core/VideoCommon/XFStructs.cpp @@ -259,12 +259,19 @@ void LoadXFReg(u32 transferSize, u32 baseAddress, DataReader src) } } +constexpr std::tuple ExtractIndexedXF(u32 val) +{ + const u32 index = val >> 16; + const u32 address = val & 0xFFF; // check mask + const u32 size = ((val >> 12) & 0xF) + 1; + + return {index, address, size}; +} + // TODO - verify that it is correct. Seems to work, though. void LoadIndexedXF(u32 val, int refarray) { - int index = val >> 16; - int address = val & 0xFFF; // check mask - int size = ((val >> 12) & 0xF) + 1; + const auto [index, address, size] = ExtractIndexedXF(val); // load stuff from array to address in xf mem u32* currData = (u32*)(&xfmem) + address; @@ -279,7 +286,7 @@ void LoadIndexedXF(u32 val, int refarray) g_main_cp_state.array_strides[refarray] * index); } bool changed = false; - for (int i = 0; i < size; ++i) + for (u32 i = 0; i < size; ++i) { if (currData[i] != Common::swap32(newData[i])) { @@ -290,15 +297,14 @@ void LoadIndexedXF(u32 val, int refarray) } if (changed) { - for (int i = 0; i < size; ++i) + for (u32 i = 0; i < size; ++i) currData[i] = Common::swap32(newData[i]); } } void PreprocessIndexedXF(u32 val, int refarray) { - const u32 index = val >> 16; - const u32 size = ((val >> 12) & 0xF) + 1; + const auto [index, address, size] = ExtractIndexedXF(val); const u8* new_data = Memory::GetPointer(g_preprocess_cp_state.array_bases[refarray] + g_preprocess_cp_state.array_strides[refarray] * index); @@ -643,3 +649,18 @@ std::pair GetXFTransferInfo(const u8* data) return std::make_pair(fmt::to_string(name), fmt::to_string(desc)); } + +std::pair GetXFIndexedLoadInfo(u8 array, u32 value) +{ + const auto [index, address, size] = ExtractIndexedXF(value); + + const auto desc = fmt::format("Load {} bytes to XF address {:03x} from CP array {} row {}", size, + address, array, index); + fmt::memory_buffer written; + for (u32 i = 0; i < size; i++) + { + fmt::format_to(written, "{}\n", GetXFMemName(address + i)); + } + + return std::make_pair(desc, fmt::to_string(written)); +} diff --git a/Source/Core/VideoCommon/XFStructs.h b/Source/Core/VideoCommon/XFStructs.h index 5aac1f059b..d73f47c722 100644 --- a/Source/Core/VideoCommon/XFStructs.h +++ b/Source/Core/VideoCommon/XFStructs.h @@ -13,3 +13,4 @@ std::pair GetXFRegInfo(u32 address, u32 value); std::string GetXFMemName(u32 address); std::string GetXFMemDescription(u32 address, u32 value); std::pair GetXFTransferInfo(const u8* data); +std::pair GetXFIndexedLoadInfo(u8 array, u32 value); From 73f4e57006d3bf2dc58835a940c6d85998e09a1b Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Fri, 19 Feb 2021 20:01:50 -0800 Subject: [PATCH 23/24] Add name and description for primitives --- .../Core/FifoPlayer/FifoPlaybackAnalyzer.cpp | 10 ++ .../Core/FifoPlayer/FifoPlaybackAnalyzer.h | 4 + Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp | 124 +++++++++++++----- 3 files changed, 105 insertions(+), 33 deletions(-) diff --git a/Source/Core/Core/FifoPlayer/FifoPlaybackAnalyzer.cpp b/Source/Core/Core/FifoPlayer/FifoPlaybackAnalyzer.cpp index 84dda8d8c5..9eb589491b 100644 --- a/Source/Core/Core/FifoPlayer/FifoPlaybackAnalyzer.cpp +++ b/Source/Core/Core/FifoPlayer/FifoPlaybackAnalyzer.cpp @@ -6,6 +6,7 @@ #include +#include "Common/Assert.h" #include "Common/CommonTypes.h" #include "Core/FifoPlayer/FifoAnalyzer.h" #include "Core/FifoPlayer/FifoDataFile.h" @@ -80,6 +81,7 @@ void FifoPlaybackAnalyzer::AnalyzeFrames(FifoDataFile* file, { // Clean up frame analysis analyzed.objectStarts.clear(); + analyzed.objectCPStates.clear(); analyzed.objectEnds.clear(); return; @@ -88,9 +90,14 @@ void FifoPlaybackAnalyzer::AnalyzeFrames(FifoDataFile* file, if (wasDrawing != s_DrawingObject) { if (s_DrawingObject) + { analyzed.objectStarts.push_back(cmdStart); + analyzed.objectCPStates.push_back(s_CpMem); + } else + { analyzed.objectEnds.push_back(cmdStart); + } } cmdStart += cmdSize; @@ -98,5 +105,8 @@ void FifoPlaybackAnalyzer::AnalyzeFrames(FifoDataFile* file, if (analyzed.objectEnds.size() < analyzed.objectStarts.size()) analyzed.objectEnds.push_back(cmdStart); + + ASSERT(analyzed.objectStarts.size() == analyzed.objectCPStates.size()); + ASSERT(analyzed.objectStarts.size() == analyzed.objectEnds.size()); } } diff --git a/Source/Core/Core/FifoPlayer/FifoPlaybackAnalyzer.h b/Source/Core/Core/FifoPlayer/FifoPlaybackAnalyzer.h index 47cbfa6ae8..f7847a3a2b 100644 --- a/Source/Core/Core/FifoPlayer/FifoPlaybackAnalyzer.h +++ b/Source/Core/Core/FifoPlayer/FifoPlaybackAnalyzer.h @@ -7,11 +7,15 @@ #include #include +#include "Core/FifoPlayer/FifoAnalyzer.h" #include "Core/FifoPlayer/FifoDataFile.h" struct AnalyzedFrameInfo { + // Start of the primitives for the object (after previous update commands) std::vector objectStarts; + std::vector objectCPStates; + // End of the primitives for the object std::vector objectEnds; std::vector memoryUpdates; }; diff --git a/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp b/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp index 676288f442..70bb7821c6 100644 --- a/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp +++ b/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp @@ -25,6 +25,7 @@ #include "VideoCommon/BPMemory.h" #include "VideoCommon/CPMemory.h" #include "VideoCommon/OpcodeDecoding.h" +#include "VideoCommon/VertexLoaderBase.h" #include "VideoCommon/XFStructs.h" constexpr int FRAME_ROLE = Qt::UserRole; @@ -163,6 +164,25 @@ void FIFOAnalyzer::UpdateTree() } } +static std::string GetPrimitiveName(u8 cmd) +{ + if ((cmd & 0xC0) != 0x80) + { + PanicAlertFmt("Not a primitive command: {:#04x}", cmd); + return ""; + } + const u8 vat = cmd & OpcodeDecoder::GX_VAT_MASK; // Vertex loader index (0 - 7) + const u8 primitive = + (cmd & OpcodeDecoder::GX_PRIMITIVE_MASK) >> OpcodeDecoder::GX_PRIMITIVE_SHIFT; + static constexpr std::array names = { + "GX_DRAW_QUADS", "GX_DRAW_QUADS_2 (nonstandard)", + "GX_DRAW_TRIANGLES", "GX_DRAW_TRIANGLE_STRIP", + "GX_DRAW_TRIANGLE_FAN", "GX_DRAW_LINES", + "GX_DRAW_LINE_STRIP", "GX_DRAW_POINTS", + }; + return fmt::format("{} VAT {}", names[primitive], vat); +} + void FIFOAnalyzer::UpdateDetails() { // Clearing the detail list can update the selection, which causes UpdateDescription to be called @@ -193,13 +213,12 @@ void FIFOAnalyzer::UpdateDetails() // Note that frame_info.objectStarts[object_nr] is the start of the primitive data, // but we want to start with the register updates which happen before that. const u32 object_start = (object_nr == 0 ? 0 : frame_info.objectEnds[object_nr - 1]); - const u32 object_nonprim_size = frame_info.objectStarts[object_nr] - object_start; const u32 object_size = frame_info.objectEnds[object_nr] - object_start; const u8* const object = &fifo_frame.fifoData[object_start]; u32 object_offset = 0; - while (object_offset < object_nonprim_size) + while (object_offset < object_size) { QString new_label; const u32 start_offset = object_offset; @@ -329,8 +348,49 @@ void FIFOAnalyzer::UpdateDetails() break; default: - new_label = tr("Unexpected 0x80 call? Aborting..."); - object_offset = object_nonprim_size; + if ((command & 0xC0) == 0x80) + { + // Object primitive data + + const u8 vat = command & OpcodeDecoder::GX_VAT_MASK; + const auto& vtx_desc = frame_info.objectCPStates[object_nr].vtxDesc; + const auto& vtx_attr = frame_info.objectCPStates[object_nr].vtxAttr[vat]; + + const auto name = GetPrimitiveName(command); + + const u16 vertex_count = Common::swap16(&object[object_offset]); + object_offset += 2; + const u32 vertex_size = VertexLoaderBase::GetVertexSize(vtx_desc, vtx_attr); + + // Note that vertex_count is allowed to be 0, with no special treatment + // (another command just comes right after the current command, with no vertices in between) + const u32 object_prim_size = vertex_count * vertex_size; + + new_label = QStringLiteral("PRIMITIVE %1 (%2) %3 vertices %4 bytes/vertex %5 total bytes") + .arg(QString::fromStdString(name)) + .arg(command, 2, 16, QLatin1Char('0')) + .arg(vertex_count) + .arg(vertex_size) + .arg(object_prim_size); + + // It's not really useful to have a massive unreadable hex string for the object primitives. + // Put it in the description instead. + +// #define INCLUDE_HEX_IN_PRIMITIVES +#ifdef INCLUDE_HEX_IN_PRIMITIVES + new_label += QStringLiteral(" "); + for (u32 i = 0; i < object_prim_size; i++) + { + new_label += QStringLiteral("%1").arg(object[object_offset++], 2, 16, QLatin1Char('0')); + } +#else + object_offset += object_prim_size; +#endif + } + else + { + new_label = QStringLiteral("Unknown opcode %1").arg(command, 2, 16); + } break; } new_label = QStringLiteral("%1: ").arg(object_start + start_offset, 8, 16, QLatin1Char('0')) + @@ -338,34 +398,7 @@ void FIFOAnalyzer::UpdateDetails() m_detail_list->addItem(new_label); } - // Object primitive data - ASSERT(object_offset == object_nonprim_size); - m_object_data_offsets.push_back(object_offset); - - const u8 cmd = object[object_offset++]; - const u16 vertex_count = Common::swap16(&object[object_offset]); - object_offset += 2; - - const u32 object_prim_size = object_size - object_offset; - - QString new_label = QStringLiteral("%1: %2 %3 ") - .arg(object_start + object_offset, 8, 16, QLatin1Char('0')) - .arg(cmd, 2, 16, QLatin1Char('0')) - .arg(vertex_count, 4, 16, QLatin1Char('0')); - - while (object_offset < object_size) - { - u32 byte = object[object_offset++]; - new_label += QStringLiteral("%1").arg(byte, 2, 16, QLatin1Char('0')); - } - - if (vertex_count != 0 && (object_prim_size % vertex_count) != 0) - { - new_label += QLatin1Char{'\n'}; - new_label += tr("NOTE: Stream size doesn't match actual data length"); - } - - m_detail_list->addItem(new_label); + ASSERT(object_offset == object_size); // Needed to ensure the description updates when changing objects m_detail_list->setCurrentRow(0); @@ -528,7 +561,9 @@ void FIFOAnalyzer::UpdateDescription() const FifoFrameInfo& fifo_frame = FifoPlayer::GetInstance().GetFile()->GetFrame(frame_nr); const u32 object_start = (object_nr == 0 ? 0 : frame_info.objectEnds[object_nr - 1]); - const u8* cmddata = &fifo_frame.fifoData[object_start + m_object_data_offsets[entry_nr]]; + const u32 entry_start = m_object_data_offsets[entry_nr]; + + const u8* cmddata = &fifo_frame.fifoData[object_start + entry_start]; // TODO: Not sure whether we should bother translating the descriptions @@ -621,6 +656,29 @@ void FIFOAnalyzer::UpdateDescription() text += QLatin1Char{'\n'}; text += QString::fromStdString(written); } + else if ((*cmddata & 0xC0) == 0x80) + { + const u8 vat = *cmddata & OpcodeDecoder::GX_VAT_MASK; + const auto name = GetPrimitiveName(*cmddata); + const u16 vertex_count = Common::swap16(cmddata + 1); + + text = tr("Primitive "); + text += QString::fromStdString(name); + text += QLatin1Char{'\n'}; + + const auto& vtx_desc = frame_info.objectCPStates[object_nr].vtxDesc; + const auto& vtx_attr = frame_info.objectCPStates[object_nr].vtxAttr[vat]; + const u32 vertex_size = VertexLoaderBase::GetVertexSize(vtx_desc, vtx_attr); + + u32 i = 3; + for (u32 vertex_num = 0; vertex_num < vertex_count; vertex_num++) + { + text += QLatin1Char{'\n'}; + // TODO: format each vertex nicely + for (u32 vertex_off = 0; vertex_off < vertex_size; vertex_off++) + text += QStringLiteral("%1").arg(cmddata[i++], 2, 16, QLatin1Char('0')); + } + } else { text = tr("No description available"); From 77b1cca987974c8e6e322989e19e406b58dd0fcb Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Thu, 11 Mar 2021 15:43:00 -0800 Subject: [PATCH 24/24] Separate vertex components by spaces --- Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp | 13 ++++-- Source/Core/VideoCommon/VertexLoaderBase.cpp | 46 +++++++++++++++----- Source/Core/VideoCommon/VertexLoaderBase.h | 2 + 3 files changed, 46 insertions(+), 15 deletions(-) diff --git a/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp b/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp index 70bb7821c6..453a01bf81 100644 --- a/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp +++ b/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp @@ -668,15 +668,20 @@ void FIFOAnalyzer::UpdateDescription() const auto& vtx_desc = frame_info.objectCPStates[object_nr].vtxDesc; const auto& vtx_attr = frame_info.objectCPStates[object_nr].vtxAttr[vat]; - const u32 vertex_size = VertexLoaderBase::GetVertexSize(vtx_desc, vtx_attr); + const auto component_sizes = VertexLoaderBase::GetVertexComponentSizes(vtx_desc, vtx_attr); u32 i = 3; for (u32 vertex_num = 0; vertex_num < vertex_count; vertex_num++) { text += QLatin1Char{'\n'}; - // TODO: format each vertex nicely - for (u32 vertex_off = 0; vertex_off < vertex_size; vertex_off++) - text += QStringLiteral("%1").arg(cmddata[i++], 2, 16, QLatin1Char('0')); + for (u32 comp_size : component_sizes) + { + for (u32 comp_off = 0; comp_off < comp_size; comp_off++) + { + text += QStringLiteral("%1").arg(cmddata[i++], 2, 16, QLatin1Char('0')); + } + text += QLatin1Char{' '}; + } } } else diff --git a/Source/Core/VideoCommon/VertexLoaderBase.cpp b/Source/Core/VideoCommon/VertexLoaderBase.cpp index 51f9fda359..b920b16a9d 100644 --- a/Source/Core/VideoCommon/VertexLoaderBase.cpp +++ b/Source/Core/VideoCommon/VertexLoaderBase.cpp @@ -97,29 +97,45 @@ private: std::vector buffer_b; }; -u32 VertexLoaderBase::GetVertexSize(const TVtxDesc& vtx_desc, const VAT& vtx_attr) +template +static void GetComponentSizes(const TVtxDesc& vtx_desc, const VAT& vtx_attr, Function f) { - u32 size = 0; if (vtx_desc.low.PosMatIdx) - size++; + f(1); for (auto texmtxidx : vtx_desc.low.TexMatIdx) { if (texmtxidx) - size++; + f(1); } - size += VertexLoader_Position::GetSize(vtx_desc.low.Position, vtx_attr.g0.PosFormat, - vtx_attr.g0.PosElements); - size += VertexLoader_Normal::GetSize(vtx_desc.low.Normal, vtx_attr.g0.NormalFormat, - vtx_attr.g0.NormalElements, vtx_attr.g0.NormalIndex3); + const u32 pos_size = VertexLoader_Position::GetSize(vtx_desc.low.Position, vtx_attr.g0.PosFormat, + vtx_attr.g0.PosElements); + if (pos_size != 0) + f(pos_size); + const u32 norm_size = + VertexLoader_Normal::GetSize(vtx_desc.low.Normal, vtx_attr.g0.NormalFormat, + vtx_attr.g0.NormalElements, vtx_attr.g0.NormalIndex3); + if (norm_size != 0) + f(norm_size); for (u32 i = 0; i < vtx_desc.low.Color.Size(); i++) { - size += VertexLoader_Color::GetSize(vtx_desc.low.Color[i], vtx_attr.GetColorFormat(i)); + const u32 color_size = + VertexLoader_Color::GetSize(vtx_desc.low.Color[i], vtx_attr.GetColorFormat(i)); + if (color_size != 0) + f(color_size); } for (u32 i = 0; i < vtx_desc.high.TexCoord.Size(); i++) { - size += VertexLoader_TextCoord::GetSize(vtx_desc.high.TexCoord[i], vtx_attr.GetTexFormat(i), - vtx_attr.GetTexElements(i)); + const u32 tc_size = VertexLoader_TextCoord::GetSize( + vtx_desc.high.TexCoord[i], vtx_attr.GetTexFormat(i), vtx_attr.GetTexElements(i)); + if (tc_size != 0) + f(tc_size); } +} + +u32 VertexLoaderBase::GetVertexSize(const TVtxDesc& vtx_desc, const VAT& vtx_attr) +{ + u32 size = 0; + GetComponentSizes(vtx_desc, vtx_attr, [&size](u32 s) { size += s; }); return size; } @@ -153,6 +169,14 @@ u32 VertexLoaderBase::GetVertexComponents(const TVtxDesc& vtx_desc, const VAT& v return components; } +std::vector VertexLoaderBase::GetVertexComponentSizes(const TVtxDesc& vtx_desc, + const VAT& vtx_attr) +{ + std::vector sizes; + GetComponentSizes(vtx_desc, vtx_attr, [&sizes](u32 s) { sizes.push_back(s); }); + return sizes; +} + std::unique_ptr VertexLoaderBase::CreateVertexLoader(const TVtxDesc& vtx_desc, const VAT& vtx_attr) { diff --git a/Source/Core/VideoCommon/VertexLoaderBase.h b/Source/Core/VideoCommon/VertexLoaderBase.h index 2e73fbad1d..3dc03b5ce5 100644 --- a/Source/Core/VideoCommon/VertexLoaderBase.h +++ b/Source/Core/VideoCommon/VertexLoaderBase.h @@ -7,6 +7,7 @@ #include #include #include +#include #include "Common/CommonTypes.h" #include "VideoCommon/CPMemory.h" @@ -62,6 +63,7 @@ class VertexLoaderBase public: static u32 GetVertexSize(const TVtxDesc& vtx_desc, const VAT& vtx_attr); static u32 GetVertexComponents(const TVtxDesc& vtx_desc, const VAT& vtx_attr); + static std::vector GetVertexComponentSizes(const TVtxDesc& vtx_desc, const VAT& vtx_attr); static std::unique_ptr CreateVertexLoader(const TVtxDesc& vtx_desc, const VAT& vtx_attr); virtual ~VertexLoaderBase() {}