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()));