diff --git a/Source/Core/Core/FifoPlayer/FifoDataFile.cpp b/Source/Core/Core/FifoPlayer/FifoDataFile.cpp index 92e3769327..9d25ba81f2 100644 --- a/Source/Core/Core/FifoPlayer/FifoDataFile.cpp +++ b/Source/Core/Core/FifoPlayer/FifoDataFile.cpp @@ -65,6 +65,9 @@ bool FifoDataFile::Save(const std::string& filename) u64 xfRegsOffset = file.Tell(); file.WriteArray(m_XFRegs, XF_REGS_SIZE); + u64 texMemOffset = file.Tell(); + file.WriteArray(m_TexMem, TEX_MEM_SIZE); + // Write header FileHeader header; header.fileId = FILE_ID; @@ -83,6 +86,9 @@ bool FifoDataFile::Save(const std::string& filename) header.xfRegsOffset = xfRegsOffset; header.xfRegsSize = XF_REGS_SIZE; + header.texMemOffset = texMemOffset; + header.texMemSize = TEX_MEM_SIZE; + header.frameListOffset = frameListOffset; header.frameCount = (u32)m_Frames.size(); @@ -150,22 +156,31 @@ std::unique_ptr FifoDataFile::Load(const std::string& filename, bo return dataFile; } - u32 size = std::min((u32)BP_MEM_SIZE, header.bpMemSize); + u32 size = std::min(BP_MEM_SIZE, header.bpMemSize); file.Seek(header.bpMemOffset, SEEK_SET); file.ReadArray(dataFile->m_BPMem, size); - size = std::min((u32)CP_MEM_SIZE, header.cpMemSize); + size = std::min(CP_MEM_SIZE, header.cpMemSize); file.Seek(header.cpMemOffset, SEEK_SET); file.ReadArray(dataFile->m_CPMem, size); - size = std::min((u32)XF_MEM_SIZE, header.xfMemSize); + size = std::min(XF_MEM_SIZE, header.xfMemSize); file.Seek(header.xfMemOffset, SEEK_SET); file.ReadArray(dataFile->m_XFMem, size); - size = std::min((u32)XF_REGS_SIZE, header.xfRegsSize); + size = std::min(XF_REGS_SIZE, header.xfRegsSize); file.Seek(header.xfRegsOffset, SEEK_SET); file.ReadArray(dataFile->m_XFRegs, size); + // Texture memory saving was added in version 4. + std::memset(dataFile->m_TexMem, 0, TEX_MEM_SIZE); + if (dataFile->m_Version >= 4) + { + size = std::min(TEX_MEM_SIZE, header.texMemSize); + file.Seek(header.texMemOffset, SEEK_SET); + file.ReadArray(dataFile->m_TexMem, size); + } + // Read frames for (u32 i = 0; i < header.frameCount; ++i) { diff --git a/Source/Core/Core/FifoPlayer/FifoDataFile.h b/Source/Core/Core/FifoPlayer/FifoDataFile.h index 45dee96dba..f3c8e92eb3 100644 --- a/Source/Core/Core/FifoPlayer/FifoDataFile.h +++ b/Source/Core/Core/FifoPlayer/FifoDataFile.h @@ -51,6 +51,7 @@ public: CP_MEM_SIZE = 256, XF_MEM_SIZE = 4096, XF_REGS_SIZE = 96, + TEX_MEM_SIZE = 1024 * 1024, }; FifoDataFile(); @@ -64,6 +65,7 @@ public: u32* GetCPMem() { return m_CPMem; } u32* GetXFMem() { return m_XFMem; } u32* GetXFRegs() { return m_XFRegs; } + u8* GetTexMem() { return m_TexMem; } void AddFrame(const FifoFrameInfo& frameInfo); const FifoFrameInfo& GetFrame(u32 frame) const { return m_Frames[frame]; } u32 GetFrameCount() const { return static_cast(m_Frames.size()); } @@ -90,6 +92,7 @@ private: u32 m_CPMem[CP_MEM_SIZE]; u32 m_XFMem[XF_MEM_SIZE]; u32 m_XFRegs[XF_REGS_SIZE]; + u8 m_TexMem[TEX_MEM_SIZE]; u32 m_Flags; u32 m_Version; diff --git a/Source/Core/Core/FifoPlayer/FifoFileStruct.h b/Source/Core/Core/FifoPlayer/FifoFileStruct.h index 5dd2329ee5..78914674d4 100644 --- a/Source/Core/Core/FifoPlayer/FifoFileStruct.h +++ b/Source/Core/Core/FifoPlayer/FifoFileStruct.h @@ -11,7 +11,7 @@ namespace FifoFileStruct enum { FILE_ID = 0x0d01f1f0, - VERSION_NUMBER = 3, + VERSION_NUMBER = 4, MIN_LOADER_VERSION = 1, }; @@ -34,6 +34,8 @@ union FileHeader { u64 frameListOffset; u32 frameCount; u32 flags; + u64 texMemOffset; + u32 texMemSize; }; u32 rawData[32]; }; diff --git a/Source/Core/Core/FifoPlayer/FifoPlayer.cpp b/Source/Core/Core/FifoPlayer/FifoPlayer.cpp index e8dbad863d..036e2581c2 100644 --- a/Source/Core/Core/FifoPlayer/FifoPlayer.cpp +++ b/Source/Core/Core/FifoPlayer/FifoPlayer.cpp @@ -25,6 +25,10 @@ #include "VideoCommon/BPMemory.h" #include "VideoCommon/CommandProcessor.h" +// We need to include TextureDecoder.h for the texMem array. +// TODO: Move texMem somewhere else so this isn't an issue. +#include "VideoCommon/TextureDecoder.h" + bool IsPlayingBackFifologWithBrokenEFBCopies = false; FifoPlayer::~FifoPlayer() @@ -122,7 +126,13 @@ int FifoPlayer::AdvanceFrame() if (m_FrameRangeStart >= m_FrameRangeEnd) return CPU::CPU_STEPPING; + // When looping, reload the contents of all the BP/CP/CF registers. + // This ensures that each time the first frame is played back, the state of the + // GPU is the same for each playback loop. m_CurrentFrame = m_FrameRangeStart; + LoadRegisters(); + LoadTextureMemory(); + FlushWGP(); } if (m_FrameWrittenCb) @@ -414,7 +424,13 @@ void FifoPlayer::LoadMemory() PowerPC::IBATUpdated(); SetupFifo(); + LoadRegisters(); + LoadTextureMemory(); + FlushWGP(); +} +void FifoPlayer::LoadRegisters() +{ const u32* regs = m_File->GetBPMem(); for (int i = 0; i < FifoDataFile::BP_MEM_SIZE; ++i) { @@ -448,8 +464,13 @@ void FifoPlayer::LoadMemory() regs = m_File->GetXFRegs(); for (int i = 0; i < FifoDataFile::XF_REGS_SIZE; ++i) LoadXFReg(i, regs[i]); +} - FlushWGP(); +void FifoPlayer::LoadTextureMemory() +{ + static_assert(static_cast(TMEM_SIZE) == static_cast(FifoDataFile::TEX_MEM_SIZE), + "TMEM_SIZE matches the size of texture memory in FifoDataFile"); + std::memcpy(texMem, m_File->GetTexMem(), FifoDataFile::TEX_MEM_SIZE); } void FifoPlayer::WriteCP(u32 address, u16 value) @@ -514,6 +535,7 @@ bool FifoPlayer::ShouldLoadBP(u8 address) case BPMEM_PE_TOKEN_INT_ID: case BPMEM_TRIGGER_EFB_COPY: case BPMEM_LOADTLUT1: + case BPMEM_PRELOAD_MODE: case BPMEM_PERF1: return false; default: diff --git a/Source/Core/Core/FifoPlayer/FifoPlayer.h b/Source/Core/Core/FifoPlayer/FifoPlayer.h index e1c285ff43..cdbb72669d 100644 --- a/Source/Core/Core/FifoPlayer/FifoPlayer.h +++ b/Source/Core/Core/FifoPlayer/FifoPlayer.h @@ -110,6 +110,8 @@ private: void SetupFifo(); void LoadMemory(); + void LoadRegisters(); + void LoadTextureMemory(); void WriteCP(u32 address, u16 value); void WritePI(u32 address, u32 value); diff --git a/Source/Core/Core/FifoPlayer/FifoRecorder.cpp b/Source/Core/Core/FifoPlayer/FifoRecorder.cpp index eb229bafad..5a55b9f459 100644 --- a/Source/Core/Core/FifoPlayer/FifoRecorder.cpp +++ b/Source/Core/Core/FifoPlayer/FifoRecorder.cpp @@ -183,7 +183,7 @@ void FifoRecorder::EndFrame(u32 fifoStart, u32 fifoEnd) } void FifoRecorder::SetVideoMemory(const u32* bpMem, const u32* cpMem, const u32* xfMem, - const u32* xfRegs, u32 xfRegsSize) + const u32* xfRegs, u32 xfRegsSize, const u8* texMem) { std::lock_guard lk(sMutex); @@ -195,6 +195,8 @@ void FifoRecorder::SetVideoMemory(const u32* bpMem, const u32* cpMem, const u32* u32 xfRegsCopySize = std::min((u32)FifoDataFile::XF_REGS_SIZE, xfRegsSize); memcpy(m_File->GetXFRegs(), xfRegs, xfRegsCopySize * 4); + + memcpy(m_File->GetTexMem(), texMem, FifoDataFile::TEX_MEM_SIZE); } FifoRecordAnalyzer::Initialize(cpMem); diff --git a/Source/Core/Core/FifoPlayer/FifoRecorder.h b/Source/Core/Core/FifoPlayer/FifoRecorder.h index 49ef79dae5..63ce93eaf7 100644 --- a/Source/Core/Core/FifoPlayer/FifoRecorder.h +++ b/Source/Core/Core/FifoPlayer/FifoRecorder.h @@ -37,7 +37,7 @@ public: // bpMem must point to the actual bp mem array used by the plugin because it will be read as fifo // data is recorded void SetVideoMemory(const u32* bpMem, const u32* cpMem, const u32* xfMem, const u32* xfRegs, - u32 xfRegsSize); + u32 xfRegsSize, const u8* texMem); // Checked once per frame prior to callng EndFrame() bool IsRecording() const { return m_IsRecording; } diff --git a/Source/Core/VideoCommon/RenderBase.cpp b/Source/Core/VideoCommon/RenderBase.cpp index e3096a770f..0456d46530 100644 --- a/Source/Core/VideoCommon/RenderBase.cpp +++ b/Source/Core/VideoCommon/RenderBase.cpp @@ -51,6 +51,7 @@ #include "VideoCommon/RenderBase.h" #include "VideoCommon/Statistics.h" #include "VideoCommon/TextureCacheBase.h" +#include "VideoCommon/TextureDecoder.h" #include "VideoCommon/VideoConfig.h" #include "VideoCommon/XFMemory.h" @@ -678,7 +679,8 @@ void Renderer::RecordVideoMemory() FillCPMemoryArray(cpmem); - FifoRecorder::GetInstance().SetVideoMemory(bpmem_ptr, cpmem, xfmem_ptr, xfregs_ptr, xfregs_size); + FifoRecorder::GetInstance().SetVideoMemory(bpmem_ptr, cpmem, xfmem_ptr, xfregs_ptr, xfregs_size, + texMem); } void Renderer::Swap(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const EFBRectangle& rc,