mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-03-06 09:47:48 +01:00
284 lines
7.3 KiB
C++
284 lines
7.3 KiB
C++
// Copyright 2011 Dolphin Emulator Project
|
|
// Licensed under GPLv2+
|
|
// Refer to the license.txt file included.
|
|
|
|
#include <algorithm>
|
|
#include <cstring>
|
|
#include <string>
|
|
|
|
#include "Common/FileUtil.h"
|
|
|
|
#include "Core/FifoPlayer/FifoDataFile.h"
|
|
#include "Core/FifoPlayer/FifoFileStruct.h"
|
|
|
|
using namespace FifoFileStruct;
|
|
|
|
FifoDataFile::FifoDataFile() : m_Flags(0)
|
|
{
|
|
}
|
|
|
|
FifoDataFile::~FifoDataFile()
|
|
{
|
|
}
|
|
|
|
bool FifoDataFile::HasBrokenEFBCopies() const
|
|
{
|
|
return m_Version < 2;
|
|
}
|
|
|
|
void FifoDataFile::SetIsWii(bool isWii)
|
|
{
|
|
SetFlag(FLAG_IS_WII, isWii);
|
|
}
|
|
|
|
bool FifoDataFile::GetIsWii() const
|
|
{
|
|
return GetFlag(FLAG_IS_WII);
|
|
}
|
|
|
|
void FifoDataFile::AddFrame(const FifoFrameInfo& frameInfo)
|
|
{
|
|
m_Frames.push_back(frameInfo);
|
|
}
|
|
|
|
bool FifoDataFile::Save(const std::string& filename)
|
|
{
|
|
File::IOFile file;
|
|
if (!file.Open(filename, "wb"))
|
|
return false;
|
|
|
|
// Add space for header
|
|
PadFile(sizeof(FileHeader), file);
|
|
|
|
// Add space for frame list
|
|
u64 frameListOffset = file.Tell();
|
|
PadFile(m_Frames.size() * sizeof(FileFrameInfo), file);
|
|
|
|
u64 bpMemOffset = file.Tell();
|
|
file.WriteArray(m_BPMem, BP_MEM_SIZE);
|
|
|
|
u64 cpMemOffset = file.Tell();
|
|
file.WriteArray(m_CPMem, CP_MEM_SIZE);
|
|
|
|
u64 xfMemOffset = file.Tell();
|
|
file.WriteArray(m_XFMem, XF_MEM_SIZE);
|
|
|
|
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;
|
|
header.file_version = VERSION_NUMBER;
|
|
header.min_loader_version = MIN_LOADER_VERSION;
|
|
|
|
header.bpMemOffset = bpMemOffset;
|
|
header.bpMemSize = BP_MEM_SIZE;
|
|
|
|
header.cpMemOffset = cpMemOffset;
|
|
header.cpMemSize = CP_MEM_SIZE;
|
|
|
|
header.xfMemOffset = xfMemOffset;
|
|
header.xfMemSize = XF_MEM_SIZE;
|
|
|
|
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();
|
|
|
|
header.flags = m_Flags;
|
|
|
|
file.Seek(0, SEEK_SET);
|
|
file.WriteBytes(&header, sizeof(FileHeader));
|
|
|
|
// Write frames list
|
|
for (unsigned int i = 0; i < m_Frames.size(); ++i)
|
|
{
|
|
const FifoFrameInfo& srcFrame = m_Frames[i];
|
|
|
|
// Write FIFO data
|
|
file.Seek(0, SEEK_END);
|
|
u64 dataOffset = file.Tell();
|
|
file.WriteBytes(srcFrame.fifoData.data(), srcFrame.fifoData.size());
|
|
|
|
u64 memoryUpdatesOffset = WriteMemoryUpdates(srcFrame.memoryUpdates, file);
|
|
|
|
FileFrameInfo dstFrame;
|
|
dstFrame.fifoDataSize = static_cast<u32>(srcFrame.fifoData.size());
|
|
dstFrame.fifoDataOffset = dataOffset;
|
|
dstFrame.fifoStart = srcFrame.fifoStart;
|
|
dstFrame.fifoEnd = srcFrame.fifoEnd;
|
|
dstFrame.memoryUpdatesOffset = memoryUpdatesOffset;
|
|
dstFrame.numMemoryUpdates = static_cast<u32>(srcFrame.memoryUpdates.size());
|
|
|
|
// Write frame info
|
|
u64 frameOffset = frameListOffset + (i * sizeof(FileFrameInfo));
|
|
file.Seek(frameOffset, SEEK_SET);
|
|
file.WriteBytes(&dstFrame, sizeof(FileFrameInfo));
|
|
}
|
|
|
|
if (!file.Close())
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
std::unique_ptr<FifoDataFile> FifoDataFile::Load(const std::string& filename, bool flagsOnly)
|
|
{
|
|
File::IOFile file;
|
|
file.Open(filename, "rb");
|
|
if (!file)
|
|
return nullptr;
|
|
|
|
FileHeader header;
|
|
file.ReadBytes(&header, sizeof(header));
|
|
|
|
if (header.fileId != FILE_ID || header.min_loader_version > VERSION_NUMBER)
|
|
{
|
|
file.Close();
|
|
return nullptr;
|
|
}
|
|
|
|
auto dataFile = std::make_unique<FifoDataFile>();
|
|
|
|
dataFile->m_Flags = header.flags;
|
|
dataFile->m_Version = header.file_version;
|
|
|
|
if (flagsOnly)
|
|
{
|
|
file.Close();
|
|
return dataFile;
|
|
}
|
|
|
|
u32 size = std::min<u32>(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);
|
|
file.Seek(header.cpMemOffset, SEEK_SET);
|
|
file.ReadArray(dataFile->m_CPMem, size);
|
|
|
|
size = std::min<u32>(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);
|
|
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<u32>(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)
|
|
{
|
|
u64 frameOffset = header.frameListOffset + (i * sizeof(FileFrameInfo));
|
|
file.Seek(frameOffset, SEEK_SET);
|
|
FileFrameInfo srcFrame;
|
|
file.ReadBytes(&srcFrame, sizeof(FileFrameInfo));
|
|
|
|
FifoFrameInfo dstFrame;
|
|
dstFrame.fifoData.resize(srcFrame.fifoDataSize);
|
|
dstFrame.fifoStart = srcFrame.fifoStart;
|
|
dstFrame.fifoEnd = srcFrame.fifoEnd;
|
|
|
|
file.Seek(srcFrame.fifoDataOffset, SEEK_SET);
|
|
file.ReadBytes(dstFrame.fifoData.data(), srcFrame.fifoDataSize);
|
|
|
|
ReadMemoryUpdates(srcFrame.memoryUpdatesOffset, srcFrame.numMemoryUpdates,
|
|
dstFrame.memoryUpdates, file);
|
|
|
|
dataFile->AddFrame(dstFrame);
|
|
}
|
|
|
|
file.Close();
|
|
|
|
return dataFile;
|
|
}
|
|
|
|
void FifoDataFile::PadFile(size_t numBytes, File::IOFile& file)
|
|
{
|
|
for (size_t i = 0; i < numBytes; ++i)
|
|
fputc(0, file.GetHandle());
|
|
}
|
|
|
|
void FifoDataFile::SetFlag(u32 flag, bool set)
|
|
{
|
|
if (set)
|
|
m_Flags |= flag;
|
|
else
|
|
m_Flags &= ~flag;
|
|
}
|
|
|
|
bool FifoDataFile::GetFlag(u32 flag) const
|
|
{
|
|
return !!(m_Flags & flag);
|
|
}
|
|
|
|
u64 FifoDataFile::WriteMemoryUpdates(const std::vector<MemoryUpdate>& memUpdates,
|
|
File::IOFile& file)
|
|
{
|
|
// Add space for memory update list
|
|
u64 updateListOffset = file.Tell();
|
|
PadFile(memUpdates.size() * sizeof(FileMemoryUpdate), file);
|
|
|
|
for (unsigned int i = 0; i < memUpdates.size(); ++i)
|
|
{
|
|
const MemoryUpdate& srcUpdate = memUpdates[i];
|
|
|
|
// Write memory
|
|
file.Seek(0, SEEK_END);
|
|
u64 dataOffset = file.Tell();
|
|
file.WriteBytes(srcUpdate.data.data(), srcUpdate.data.size());
|
|
|
|
FileMemoryUpdate dstUpdate;
|
|
dstUpdate.address = srcUpdate.address;
|
|
dstUpdate.dataOffset = dataOffset;
|
|
dstUpdate.dataSize = static_cast<u32>(srcUpdate.data.size());
|
|
dstUpdate.fifoPosition = srcUpdate.fifoPosition;
|
|
dstUpdate.type = srcUpdate.type;
|
|
|
|
u64 updateOffset = updateListOffset + (i * sizeof(FileMemoryUpdate));
|
|
file.Seek(updateOffset, SEEK_SET);
|
|
file.WriteBytes(&dstUpdate, sizeof(FileMemoryUpdate));
|
|
}
|
|
|
|
return updateListOffset;
|
|
}
|
|
|
|
void FifoDataFile::ReadMemoryUpdates(u64 fileOffset, u32 numUpdates,
|
|
std::vector<MemoryUpdate>& memUpdates, File::IOFile& file)
|
|
{
|
|
memUpdates.resize(numUpdates);
|
|
|
|
for (u32 i = 0; i < numUpdates; ++i)
|
|
{
|
|
u64 updateOffset = fileOffset + (i * sizeof(FileMemoryUpdate));
|
|
file.Seek(updateOffset, SEEK_SET);
|
|
FileMemoryUpdate srcUpdate;
|
|
file.ReadBytes(&srcUpdate, sizeof(FileMemoryUpdate));
|
|
|
|
MemoryUpdate& dstUpdate = memUpdates[i];
|
|
dstUpdate.address = srcUpdate.address;
|
|
dstUpdate.fifoPosition = srcUpdate.fifoPosition;
|
|
dstUpdate.data.resize(srcUpdate.dataSize);
|
|
dstUpdate.type = static_cast<MemoryUpdate::Type>(srcUpdate.type);
|
|
|
|
file.Seek(srcUpdate.dataOffset, SEEK_SET);
|
|
file.ReadBytes(dstUpdate.data.data(), srcUpdate.dataSize);
|
|
}
|
|
}
|