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:
Pokechu22 2021-08-24 12:18:28 -07:00
parent d84d695fdf
commit e4605fa399
3 changed files with 30 additions and 20 deletions

View File

@ -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

View File

@ -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)
{

View File

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