From 5b315b7bb4a30044af66c1a34e0d686aaa7692d0 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Tue, 3 Jan 2017 17:10:22 +1000 Subject: [PATCH 1/4] FifoPlayer: Reload initial state when looping back to first frame This should ensure that when playing with loop enabled, the first frame is in the same state each time. There is potentially still issues when the start frame is set to something other than zero, but I'm not sure how we could work around this without capturing the entire state on each frame. --- Source/Core/Core/FifoPlayer/FifoPlayer.cpp | 12 ++++++++++-- Source/Core/Core/FifoPlayer/FifoPlayer.h | 1 + 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/Source/Core/Core/FifoPlayer/FifoPlayer.cpp b/Source/Core/Core/FifoPlayer/FifoPlayer.cpp index e8dbad863d..346743ed4a 100644 --- a/Source/Core/Core/FifoPlayer/FifoPlayer.cpp +++ b/Source/Core/Core/FifoPlayer/FifoPlayer.cpp @@ -122,7 +122,12 @@ 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(); + FlushWGP(); } if (m_FrameWrittenCb) @@ -414,7 +419,12 @@ void FifoPlayer::LoadMemory() PowerPC::IBATUpdated(); SetupFifo(); + LoadRegisters(); + FlushWGP(); +} +void FifoPlayer::LoadRegisters() +{ const u32* regs = m_File->GetBPMem(); for (int i = 0; i < FifoDataFile::BP_MEM_SIZE; ++i) { @@ -448,8 +458,6 @@ void FifoPlayer::LoadMemory() regs = m_File->GetXFRegs(); for (int i = 0; i < FifoDataFile::XF_REGS_SIZE; ++i) LoadXFReg(i, regs[i]); - - FlushWGP(); } void FifoPlayer::WriteCP(u32 address, u16 value) diff --git a/Source/Core/Core/FifoPlayer/FifoPlayer.h b/Source/Core/Core/FifoPlayer/FifoPlayer.h index e1c285ff43..819c62dda0 100644 --- a/Source/Core/Core/FifoPlayer/FifoPlayer.h +++ b/Source/Core/Core/FifoPlayer/FifoPlayer.h @@ -110,6 +110,7 @@ private: void SetupFifo(); void LoadMemory(); + void LoadRegisters(); void WriteCP(u32 address, u16 value); void WritePI(u32 address, u32 value); From 438989668ebcdf04ded58672f45884cf28558e79 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Tue, 3 Jan 2017 17:30:50 +1000 Subject: [PATCH 2/4] FifoDataFile: Add support for storing texture memory state This bumps the file version to 4. --- Source/Core/Core/FifoPlayer/FifoDataFile.cpp | 23 ++++++++++++++++---- Source/Core/Core/FifoPlayer/FifoDataFile.h | 3 +++ Source/Core/Core/FifoPlayer/FifoFileStruct.h | 4 +++- 3 files changed, 25 insertions(+), 5 deletions(-) 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]; }; From 5f3c878ba2037efbb9ac20de379451c9b9c298db Mon Sep 17 00:00:00 2001 From: Stenzek Date: Tue, 3 Jan 2017 17:31:16 +1000 Subject: [PATCH 3/4] FifoPlayer: Save/restore texture memory state for fifo logs --- Source/Core/Core/FifoPlayer/FifoPlayer.cpp | 13 +++++++++++++ Source/Core/Core/FifoPlayer/FifoPlayer.h | 1 + Source/Core/Core/FifoPlayer/FifoRecorder.cpp | 4 +++- Source/Core/Core/FifoPlayer/FifoRecorder.h | 2 +- Source/Core/VideoCommon/RenderBase.cpp | 4 +++- 5 files changed, 21 insertions(+), 3 deletions(-) diff --git a/Source/Core/Core/FifoPlayer/FifoPlayer.cpp b/Source/Core/Core/FifoPlayer/FifoPlayer.cpp index 346743ed4a..f42cfd00c1 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() @@ -127,6 +131,7 @@ int FifoPlayer::AdvanceFrame() // GPU is the same for each playback loop. m_CurrentFrame = m_FrameRangeStart; LoadRegisters(); + LoadTextureMemory(); FlushWGP(); } @@ -420,6 +425,7 @@ void FifoPlayer::LoadMemory() SetupFifo(); LoadRegisters(); + LoadTextureMemory(); FlushWGP(); } @@ -460,6 +466,13 @@ void FifoPlayer::LoadRegisters() LoadXFReg(i, regs[i]); } +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) { PowerPC::Write_U16(value, 0xCC000000 | address); diff --git a/Source/Core/Core/FifoPlayer/FifoPlayer.h b/Source/Core/Core/FifoPlayer/FifoPlayer.h index 819c62dda0..cdbb72669d 100644 --- a/Source/Core/Core/FifoPlayer/FifoPlayer.h +++ b/Source/Core/Core/FifoPlayer/FifoPlayer.h @@ -111,6 +111,7 @@ private: 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, From 18792b232880869c7e1ae2a6ff3b8500d3a6d6f2 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Tue, 3 Jan 2017 17:49:45 +1000 Subject: [PATCH 4/4] FifoPlayer: Don't set BPMEM_PRELOAD_MODE on load Since in this case we're setting it based on the state at record start time, not when a register is loaded, UseMemory would not be called, so this could potentially wipe out texture memory that was valid. --- Source/Core/Core/FifoPlayer/FifoPlayer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/Core/Core/FifoPlayer/FifoPlayer.cpp b/Source/Core/Core/FifoPlayer/FifoPlayer.cpp index f42cfd00c1..036e2581c2 100644 --- a/Source/Core/Core/FifoPlayer/FifoPlayer.cpp +++ b/Source/Core/Core/FifoPlayer/FifoPlayer.cpp @@ -535,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: