From e4605fa39955845145457aaa1f6ef227b7c6f78a Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Tue, 24 Aug 2021 12:18:28 -0700 Subject: [PATCH] Fifo analyzer: Create a new object for each EFB copy Previously, EFB copies would be in the middle of other objects, as objects were only split on primitive data. A distinct object for each EFB copy makes them easier to spot, but does also mean there are more objects that do nothing when disabled (as disabling an object only skips primitive data, and there is no primitive data for EFB copies). --- Source/Core/Core/FifoPlayer/FifoPlayer.cpp | 29 ++++++++++++++++----- Source/Core/Core/FifoPlayer/FifoPlayer.h | 4 ++- Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp | 17 ++++-------- 3 files changed, 30 insertions(+), 20 deletions(-) diff --git a/Source/Core/Core/FifoPlayer/FifoPlayer.cpp b/Source/Core/Core/FifoPlayer/FifoPlayer.cpp index bbb08a7ddd..58add3faaa 100644 --- a/Source/Core/Core/FifoPlayer/FifoPlayer.cpp +++ b/Source/Core/Core/FifoPlayer/FifoPlayer.cpp @@ -42,7 +42,7 @@ public: OPCODE_CALLBACK(void OnXF(u16 address, u8 count, const u8* data)) {} OPCODE_CALLBACK(void OnCP(u8 command, u32 value)) { GetCPState().LoadCPReg(command, value); } - OPCODE_CALLBACK(void OnBP(u8 command, u32 value)) {} + OPCODE_CALLBACK(void OnBP(u8 command, u32 value)); OPCODE_CALLBACK(void OnIndexedLoad(CPArray array, u32 index, u16 address, u8 size)) {} OPCODE_CALLBACK(void OnPrimitiveCommand(OpcodeDecoder::Primitive primitive, u8 vat, u32 vertex_size, u16 num_vertices, @@ -57,9 +57,11 @@ public: bool m_start_of_primitives = false; bool m_end_of_primitives = false; + bool m_efb_copy = false; // Internal state, copied to above in OnCommand bool m_was_primitive = false; bool m_is_primitive = false; + bool m_is_copy = false; bool m_is_nop = false; CPState m_cpmem; }; @@ -103,18 +105,27 @@ void FifoPlaybackAnalyzer::AnalyzeFrames(FifoDataFile* file, } offset += cmd_size; + + if (analyzer.m_efb_copy) + { + // We increase the offset beforehand, so that the trigger EFB copy command is included. + analyzed.AddPart(FramePartType::EFBCopy, part_start, offset, analyzer.m_cpmem); + part_start = offset; + } } - if (part_start != offset) - { - // Remaining data, usually without any primitives - analyzed.AddPart(FramePartType::Commands, part_start, offset, analyzer.m_cpmem); - } - + // The frame should end with an EFB copy, so part_start should have been updated to the end. + ASSERT(part_start == frame.fifoData.size()); ASSERT(offset == frame.fifoData.size()); } } +void FifoPlaybackAnalyzer::OnBP(u8 command, u32 value) +{ + if (command == BPMEM_TRIGGER_EFB_COPY) + m_is_copy = true; +} + void FifoPlaybackAnalyzer::OnPrimitiveCommand(OpcodeDecoder::Primitive primitive, u8 vat, u32 vertex_size, u16 num_vertices, const u8* vertex_data) @@ -131,6 +142,7 @@ void FifoPlaybackAnalyzer::OnCommand(const u8* data, u32 size) { m_start_of_primitives = false; m_end_of_primitives = false; + m_efb_copy = false; if (!m_is_nop) { @@ -138,10 +150,13 @@ void FifoPlaybackAnalyzer::OnCommand(const u8* data, u32 size) m_start_of_primitives = true; else if (m_was_primitive && !m_is_primitive) m_end_of_primitives = true; + else if (m_is_copy) + m_efb_copy = true; m_was_primitive = m_is_primitive; } m_is_primitive = false; + m_is_copy = false; m_is_nop = false; } } // namespace diff --git a/Source/Core/Core/FifoPlayer/FifoPlayer.h b/Source/Core/Core/FifoPlayer/FifoPlayer.h index ffae2e92d4..4e2e0ffed7 100644 --- a/Source/Core/Core/FifoPlayer/FifoPlayer.h +++ b/Source/Core/Core/FifoPlayer/FifoPlayer.h @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -56,6 +57,7 @@ enum class FramePartType { Commands, PrimitiveData, + EFBCopy, }; struct FramePart @@ -74,7 +76,7 @@ struct FramePart struct AnalyzedFrameInfo { std::vector parts; - Common::EnumMap part_type_counts; + Common::EnumMap part_type_counts; void AddPart(FramePartType type, u32 start, u32 end, const CPState& cpmem) { diff --git a/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp b/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp index 9135d70e09..4f76f2d263 100644 --- a/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp +++ b/Source/Core/DolphinQt/FIFO/FIFOAnalyzer.cpp @@ -160,7 +160,7 @@ void FIFOAnalyzer::UpdateTree() const AnalyzedFrameInfo& frame_info = FifoPlayer::GetInstance().GetAnalyzedFrameInfo(frame); ASSERT(frame_info.parts.size() != 0); - Common::EnumMap part_counts; + Common::EnumMap part_counts; u32 part_start = 0; for (u32 part_nr = 0; part_nr < frame_info.parts.size(); part_nr++) @@ -173,6 +173,8 @@ void FIFOAnalyzer::UpdateTree() QTreeWidgetItem* object_item = nullptr; if (part.m_type == FramePartType::PrimitiveData) object_item = new QTreeWidgetItem({tr("Object %1").arg(part_type_nr)}); + else if (part.m_type == FramePartType::EFBCopy) + object_item = new QTreeWidgetItem({tr("EFB copy %1").arg(part_type_nr)}); // We don't create dedicated labels for FramePartType::Command; // those are grouped with the primitive @@ -188,17 +190,8 @@ void FIFOAnalyzer::UpdateTree() } } - // Final data (the XFB copy) - if (part_start != frame_info.parts.size()) - { - QTreeWidgetItem* object_item = new QTreeWidgetItem({tr("Final Data")}); - frame_item->addChild(object_item); - - object_item->setData(0, FRAME_ROLE, frame); - object_item->setData(0, PART_START_ROLE, part_start); - object_item->setData(0, PART_END_ROLE, u32(frame_info.parts.size() - 1)); - } - + // We shouldn't end on a Command (it should end with an EFB copy) + ASSERT(part_start == frame_info.parts.size()); // The counts we computed should match the frame's counts ASSERT(std::equal(frame_info.part_type_counts.begin(), frame_info.part_type_counts.end(), part_counts.begin()));