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).
This commit is contained in:
parent
d84d695fdf
commit
e4605fa399
|
@ -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 (part_start != offset)
|
||||
if (analyzer.m_efb_copy)
|
||||
{
|
||||
// Remaining data, usually without any primitives
|
||||
analyzed.AddPart(FramePartType::Commands, part_start, offset, analyzer.m_cpmem);
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
@ -56,6 +57,7 @@ enum class FramePartType
|
|||
{
|
||||
Commands,
|
||||
PrimitiveData,
|
||||
EFBCopy,
|
||||
};
|
||||
|
||||
struct FramePart
|
||||
|
@ -74,7 +76,7 @@ struct FramePart
|
|||
struct AnalyzedFrameInfo
|
||||
{
|
||||
std::vector<FramePart> parts;
|
||||
Common::EnumMap<u32, FramePartType::PrimitiveData> part_type_counts;
|
||||
Common::EnumMap<u32, FramePartType::EFBCopy> part_type_counts;
|
||||
|
||||
void AddPart(FramePartType type, u32 start, u32 end, const CPState& cpmem)
|
||||
{
|
||||
|
|
|
@ -160,7 +160,7 @@ void FIFOAnalyzer::UpdateTree()
|
|||
const AnalyzedFrameInfo& frame_info = FifoPlayer::GetInstance().GetAnalyzedFrameInfo(frame);
|
||||
ASSERT(frame_info.parts.size() != 0);
|
||||
|
||||
Common::EnumMap<u32, FramePartType::PrimitiveData> part_counts;
|
||||
Common::EnumMap<u32, FramePartType::EFBCopy> 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()));
|
||||
|
|
Loading…
Reference in New Issue