mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-29 00:59:44 -06:00
Refactor object listing code
This also adds the commands after the last primitive data but before the next frame as a unique object; this is mainly just the XFB copy. It's nice to have these visible, though disabling the object does nothing since only primitive data is disabled and there is no primitive data in this case.
This commit is contained in:
@ -46,7 +46,9 @@ void FifoPlaybackAnalyzer::AnalyzeFrames(FifoDataFile* file,
|
||||
s_DrawingObject = false;
|
||||
|
||||
u32 cmdStart = 0;
|
||||
u32 nextMemUpdate = 0;
|
||||
|
||||
u32 part_start = 0;
|
||||
FifoAnalyzer::CPMemory cpmem;
|
||||
|
||||
#if LOG_FIFO_CMDS
|
||||
// Debugging
|
||||
@ -55,14 +57,6 @@ void FifoPlaybackAnalyzer::AnalyzeFrames(FifoDataFile* file,
|
||||
|
||||
while (cmdStart < frame.fifoData.size())
|
||||
{
|
||||
// Add memory updates that have occurred before this point in the frame
|
||||
while (nextMemUpdate < frame.memoryUpdates.size() &&
|
||||
frame.memoryUpdates[nextMemUpdate].fifoPosition <= cmdStart)
|
||||
{
|
||||
analyzed.memoryUpdates.push_back(frame.memoryUpdates[nextMemUpdate]);
|
||||
++nextMemUpdate;
|
||||
}
|
||||
|
||||
const bool wasDrawing = s_DrawingObject;
|
||||
const u32 cmdSize =
|
||||
FifoAnalyzer::AnalyzeCommand(&frame.fifoData[cmdStart], DecodeMode::Playback);
|
||||
@ -79,9 +73,7 @@ void FifoPlaybackAnalyzer::AnalyzeFrames(FifoDataFile* file,
|
||||
if (cmdSize == 0)
|
||||
{
|
||||
// Clean up frame analysis
|
||||
analyzed.objectStarts.clear();
|
||||
analyzed.objectCPStates.clear();
|
||||
analyzed.objectEnds.clear();
|
||||
analyzed.parts.clear();
|
||||
|
||||
return;
|
||||
}
|
||||
@ -90,22 +82,28 @@ void FifoPlaybackAnalyzer::AnalyzeFrames(FifoDataFile* file,
|
||||
{
|
||||
if (s_DrawingObject)
|
||||
{
|
||||
analyzed.objectStarts.push_back(cmdStart);
|
||||
analyzed.objectCPStates.push_back(s_CpMem);
|
||||
// Start of primitive data for an object
|
||||
analyzed.AddPart(FramePartType::Commands, part_start, cmdStart, s_CpMem);
|
||||
part_start = cmdStart;
|
||||
// Copy cpmem now, because end_of_primitives isn't triggered until the first opcode after
|
||||
// primitive data, and the first opcode might update cpmem
|
||||
std::memcpy(&cpmem, &s_CpMem, sizeof(FifoAnalyzer::CPMemory));
|
||||
}
|
||||
else
|
||||
{
|
||||
analyzed.objectEnds.push_back(cmdStart);
|
||||
// End of primitive data for an object, and thus end of the object
|
||||
analyzed.AddPart(FramePartType::PrimitiveData, part_start, cmdStart, cpmem);
|
||||
part_start = cmdStart;
|
||||
}
|
||||
}
|
||||
|
||||
cmdStart += cmdSize;
|
||||
}
|
||||
|
||||
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());
|
||||
if (part_start != cmdStart)
|
||||
{
|
||||
// Remaining data, usually without any primitives
|
||||
analyzed.AddPart(FramePartType::Commands, part_start, cmdStart, s_CpMem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,14 +9,35 @@
|
||||
#include "Core/FifoPlayer/FifoAnalyzer.h"
|
||||
#include "Core/FifoPlayer/FifoDataFile.h"
|
||||
|
||||
enum class FramePartType
|
||||
{
|
||||
Commands,
|
||||
PrimitiveData,
|
||||
};
|
||||
|
||||
struct FramePart
|
||||
{
|
||||
constexpr FramePart(FramePartType type, u32 start, u32 end, const FifoAnalyzer::CPMemory& cpmem)
|
||||
: m_type(type), m_start(start), m_end(end), m_cpmem(cpmem)
|
||||
{
|
||||
}
|
||||
|
||||
const FramePartType m_type;
|
||||
const u32 m_start;
|
||||
const u32 m_end;
|
||||
const FifoAnalyzer::CPMemory m_cpmem;
|
||||
};
|
||||
|
||||
struct AnalyzedFrameInfo
|
||||
{
|
||||
// Start of the primitives for the object (after previous update commands)
|
||||
std::vector<u32> objectStarts;
|
||||
std::vector<FifoAnalyzer::CPMemory> objectCPStates;
|
||||
// End of the primitives for the object
|
||||
std::vector<u32> objectEnds;
|
||||
std::vector<MemoryUpdate> memoryUpdates;
|
||||
std::vector<FramePart> parts;
|
||||
Common::EnumMap<u32, FramePartType::PrimitiveData> part_type_counts;
|
||||
|
||||
void AddPart(FramePartType type, u32 start, u32 end, const FifoAnalyzer::CPMemory& cpmem)
|
||||
{
|
||||
parts.emplace_back(type, start, end, cpmem);
|
||||
part_type_counts[type]++;
|
||||
}
|
||||
};
|
||||
|
||||
namespace FifoPlaybackAnalyzer
|
||||
|
@ -191,7 +191,7 @@ u32 FifoPlayer::GetMaxObjectCount() const
|
||||
u32 result = 0;
|
||||
for (auto& frame : m_FrameInfo)
|
||||
{
|
||||
const u32 count = static_cast<u32>(frame.objectStarts.size());
|
||||
const u32 count = frame.part_type_counts[FramePartType::PrimitiveData];
|
||||
if (count > result)
|
||||
result = count;
|
||||
}
|
||||
@ -202,7 +202,7 @@ u32 FifoPlayer::GetFrameObjectCount(u32 frame) const
|
||||
{
|
||||
if (frame < m_FrameInfo.size())
|
||||
{
|
||||
return static_cast<u32>(m_FrameInfo[frame].objectStarts.size());
|
||||
return m_FrameInfo[frame].part_type_counts[FramePartType::PrimitiveData];
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -262,55 +262,35 @@ void FifoPlayer::WriteFrame(const FifoFrameInfo& frame, const AnalyzedFrameInfo&
|
||||
m_ElapsedCycles = 0;
|
||||
m_FrameFifoSize = static_cast<u32>(frame.fifoData.size());
|
||||
|
||||
// Determine start and end objects
|
||||
u32 numObjects = (u32)(info.objectStarts.size());
|
||||
u32 drawStart = std::min(numObjects, m_ObjectRangeStart);
|
||||
u32 drawEnd = std::min(numObjects - 1, m_ObjectRangeEnd);
|
||||
u32 memory_update = 0;
|
||||
u32 object_num = 0;
|
||||
|
||||
u32 position = 0;
|
||||
u32 memoryUpdate = 0;
|
||||
|
||||
// Skip memory updates during frame if true
|
||||
// Skip all memory updates if early memory updates are enabled, as we already wrote them
|
||||
if (m_EarlyMemoryUpdates)
|
||||
{
|
||||
memoryUpdate = (u32)(frame.memoryUpdates.size());
|
||||
memory_update = (u32)(frame.memoryUpdates.size());
|
||||
}
|
||||
|
||||
if (numObjects > 0)
|
||||
for (const FramePart& part : info.parts)
|
||||
{
|
||||
u32 objectNum = 0;
|
||||
bool show_part;
|
||||
|
||||
// Write fifo data skipping objects before the draw range
|
||||
while (objectNum < drawStart)
|
||||
if (part.m_type == FramePartType::PrimitiveData)
|
||||
{
|
||||
WriteFramePart(position, info.objectStarts[objectNum], memoryUpdate, frame, info);
|
||||
|
||||
position = info.objectEnds[objectNum];
|
||||
++objectNum;
|
||||
show_part = m_ObjectRangeStart <= object_num && object_num <= m_ObjectRangeEnd;
|
||||
object_num++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We always include commands and EFB copies, as commands from earlier objects still apply to
|
||||
// later ones (games generally do not reconfigure everything for each object)
|
||||
show_part = true;
|
||||
}
|
||||
|
||||
// Write objects in draw range
|
||||
if (objectNum < numObjects && drawStart <= drawEnd)
|
||||
{
|
||||
objectNum = drawEnd;
|
||||
WriteFramePart(position, info.objectEnds[objectNum], memoryUpdate, frame, info);
|
||||
position = info.objectEnds[objectNum];
|
||||
++objectNum;
|
||||
}
|
||||
|
||||
// Write fifo data skipping objects after the draw range
|
||||
while (objectNum < numObjects)
|
||||
{
|
||||
WriteFramePart(position, info.objectStarts[objectNum], memoryUpdate, frame, info);
|
||||
|
||||
position = info.objectEnds[objectNum];
|
||||
++objectNum;
|
||||
}
|
||||
if (show_part)
|
||||
WriteFramePart(part, &memory_update, frame);
|
||||
}
|
||||
|
||||
// Write data after the last object
|
||||
WriteFramePart(position, static_cast<u32>(frame.fifoData.size()), memoryUpdate, frame, info);
|
||||
|
||||
FlushWGP();
|
||||
|
||||
// Sleep while the GPU is active
|
||||
@ -321,36 +301,39 @@ void FifoPlayer::WriteFrame(const FifoFrameInfo& frame, const AnalyzedFrameInfo&
|
||||
}
|
||||
}
|
||||
|
||||
void FifoPlayer::WriteFramePart(u32 dataStart, u32 dataEnd, u32& nextMemUpdate,
|
||||
const FifoFrameInfo& frame, const AnalyzedFrameInfo& info)
|
||||
void FifoPlayer::WriteFramePart(const FramePart& part, u32* next_mem_update,
|
||||
const FifoFrameInfo& frame)
|
||||
{
|
||||
const u8* const data = frame.fifoData.data();
|
||||
|
||||
while (nextMemUpdate < frame.memoryUpdates.size() && dataStart < dataEnd)
|
||||
{
|
||||
const MemoryUpdate& memUpdate = info.memoryUpdates[nextMemUpdate];
|
||||
u32 data_start = part.m_start;
|
||||
const u32 data_end = part.m_end;
|
||||
|
||||
if (memUpdate.fifoPosition < dataEnd)
|
||||
while (*next_mem_update < frame.memoryUpdates.size() && data_start < data_end)
|
||||
{
|
||||
const MemoryUpdate& memUpdate = frame.memoryUpdates[*next_mem_update];
|
||||
|
||||
if (memUpdate.fifoPosition < data_end)
|
||||
{
|
||||
if (dataStart < memUpdate.fifoPosition)
|
||||
if (data_start < memUpdate.fifoPosition)
|
||||
{
|
||||
WriteFifo(data, dataStart, memUpdate.fifoPosition);
|
||||
dataStart = memUpdate.fifoPosition;
|
||||
WriteFifo(data, data_start, memUpdate.fifoPosition);
|
||||
data_start = memUpdate.fifoPosition;
|
||||
}
|
||||
|
||||
WriteMemory(memUpdate);
|
||||
|
||||
++nextMemUpdate;
|
||||
++*next_mem_update;
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteFifo(data, dataStart, dataEnd);
|
||||
dataStart = dataEnd;
|
||||
WriteFifo(data, data_start, data_end);
|
||||
data_start = data_end;
|
||||
}
|
||||
}
|
||||
|
||||
if (dataStart < dataEnd)
|
||||
WriteFifo(data, dataStart, dataEnd);
|
||||
if (data_start < data_end)
|
||||
WriteFifo(data, data_start, data_end);
|
||||
}
|
||||
|
||||
void FifoPlayer::WriteAllMemoryUpdates()
|
||||
|
@ -108,8 +108,7 @@ private:
|
||||
CPU::State AdvanceFrame();
|
||||
|
||||
void WriteFrame(const FifoFrameInfo& frame, const AnalyzedFrameInfo& info);
|
||||
void WriteFramePart(u32 dataStart, u32 dataEnd, u32& nextMemUpdate, const FifoFrameInfo& frame,
|
||||
const AnalyzedFrameInfo& info);
|
||||
void WriteFramePart(const FramePart& part, u32* next_mem_update, const FifoFrameInfo& frame);
|
||||
|
||||
void WriteAllMemoryUpdates();
|
||||
void WriteMemory(const MemoryUpdate& memUpdate);
|
||||
|
Reference in New Issue
Block a user