-
Notifications
You must be signed in to change notification settings - Fork 2.6k
/
FifoPlayer.h
162 lines (124 loc) · 5.32 KB
/
FifoPlayer.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
// Copyright 2011 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <functional>
#include <memory>
#include <string>
#include <vector>
#include "Core/FifoPlayer/FifoDataFile.h"
#include "Core/FifoPlayer/FifoPlaybackAnalyzer.h"
#include "Core/PowerPC/CPUCoreBase.h"
class FifoDataFile;
struct MemoryUpdate;
struct AnalyzedFrameInfo;
namespace CPU
{
enum class State;
}
// Story time:
// When FifoRecorder was created, efb copies weren't really used or they used efb2tex which ignored
// the underlying memory, so FifoRecorder didn't do anything special about the memory backing efb
// copies. This means the memory underlying efb copies go treated like regular textures and was
// baked into the fifo log. If you recorded with efb2ram on, the result of efb2ram would be baked
// into the fifo. If you recorded with efb2tex or efb off, random data would be included in the fifo
// log.
// Later the behaviour of efb2tex was changed to zero the underlying memory and check the hash of
// that.
// But this broke a whole lot of fifologs due to the following sequence of events:
// 1. fifoplayer would trigger the efb copy
// 2. Texture cache would zero the memory backing the texture and hash it.
// 3. Time passes.
// 4. fifoplayer would encounter the drawcall using the efb copy
// 5. fifoplayer would overwrite the memory backing the efb copy back to it's state when
// recording.
// 6. Texture cache would hash the memory and see that the hash no-longer matches
// 7. Texture cache would load whatever data was now in memory as a texture either a baked in
// efb2ram copy from recording time or just random data.
// 8. The output of fifoplayer would be wrong.
// To keep compatibility with old fifologs, we have this flag which signals texture cache to not
// bother
// hashing the memory and just assume the hash matched.
// At a later point proper efb copy support should be added to fiforecorder and this flag will
// change
// based on the version of the .dff file, but until then it will always be true when a fifolog is
// playing.
// Shitty global to fix a shitty problem
extern bool IsPlayingBackFifologWithBrokenEFBCopies;
class FifoPlayer
{
public:
using CallbackFunc = std::function<void()>;
~FifoPlayer();
bool Open(const std::string& filename);
void Close();
// Returns a CPUCoreBase instance that can be injected into PowerPC as a
// pseudo-CPU. The instance is only valid while the FifoPlayer is Open().
// Returns nullptr if the FifoPlayer is not initialized correctly.
// Play/Pause/Stop of the FifoLog can be controlled normally via the
// PowerPC state.
std::unique_ptr<CPUCoreBase> GetCPUCore();
bool IsPlaying() const;
FifoDataFile* GetFile() const { return m_File.get(); }
u32 GetFrameObjectCount() const;
u32 GetCurrentFrameNum() const { return m_CurrentFrame; }
const AnalyzedFrameInfo& GetAnalyzedFrameInfo(u32 frame) const { return m_FrameInfo[frame]; }
// Frame range
u32 GetFrameRangeStart() const { return m_FrameRangeStart; }
void SetFrameRangeStart(u32 start);
u32 GetFrameRangeEnd() const { return m_FrameRangeEnd; }
void SetFrameRangeEnd(u32 end);
// Object range
u32 GetObjectRangeStart() const { return m_ObjectRangeStart; }
void SetObjectRangeStart(u32 start) { m_ObjectRangeStart = start; }
u32 GetObjectRangeEnd() const { return m_ObjectRangeEnd; }
void SetObjectRangeEnd(u32 end) { m_ObjectRangeEnd = end; }
// If enabled then all memory updates happen at once before the first frame
// Default is disabled
void SetEarlyMemoryUpdates(bool enabled) { m_EarlyMemoryUpdates = enabled; }
// Callbacks
void SetFileLoadedCallback(CallbackFunc callback);
void SetFrameWrittenCallback(CallbackFunc callback) { m_FrameWrittenCb = std::move(callback); }
static FifoPlayer& GetInstance();
bool IsRunningWithFakeVideoInterfaceUpdates() const;
private:
class CPUCore;
FifoPlayer();
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 WriteAllMemoryUpdates();
void WriteMemory(const MemoryUpdate& memUpdate);
// writes a range of data to the fifo
// start and end must be relative to frame's fifo data so elapsed cycles are figured correctly
void WriteFifo(const u8* data, u32 start, u32 end);
void SetupFifo();
void LoadMemory();
void LoadRegisters();
void LoadTextureMemory();
void WriteCP(u32 address, u16 value);
void WritePI(u32 address, u32 value);
void FlushWGP();
void LoadBPReg(u8 reg, u32 value);
void LoadCPReg(u8 reg, u32 value);
void LoadXFReg(u16 reg, u32 value);
void LoadXFMem16(u16 address, const u32* data);
bool ShouldLoadBP(u8 address);
static bool IsIdleSet();
static bool IsHighWatermarkSet();
bool m_Loop;
u32 m_CurrentFrame = 0;
u32 m_FrameRangeStart = 0;
u32 m_FrameRangeEnd = 0;
u32 m_ObjectRangeStart = 0;
u32 m_ObjectRangeEnd = 10000;
bool m_EarlyMemoryUpdates = false;
u64 m_CyclesPerFrame = 0;
u32 m_ElapsedCycles = 0;
u32 m_FrameFifoSize = 0;
CallbackFunc m_FileLoadedCb = nullptr;
CallbackFunc m_FrameWrittenCb = nullptr;
std::unique_ptr<FifoDataFile> m_File;
std::vector<AnalyzedFrameInfo> m_FrameInfo;
};