FifoRecorder: Use Video Common to record efb2ram correctly.

Texture updates have been moved into TextureCache, while
TMEM updates where moved into bpmem. Code for handling
efb2ram updates was added to TextureCache.

There was a bug for preloaded RGBA8 textures, it only copied
half the texture. The TODO was wrong too.
This commit is contained in:
Scott Mansell
2015-09-08 03:05:47 +12:00
parent 3df83e5717
commit a355d9868e
13 changed files with 77 additions and 144 deletions

View File

@ -68,18 +68,6 @@ void LoadBPReg(const BPCmd &bp, BPMemory &bpMem)
bpMem.bpMask = 0xFFFFFF;
}
void GetTlutLoadData(u32 &tlutAddr, u32 &memAddr, u32 &tlutXferCount, BPMemory &bpMem)
{
tlutAddr = (bpMem.tmem_config.tlut_dest & 0x3FF) << 9;
tlutXferCount = (bpMem.tmem_config.tlut_dest & 0x1FFC00) >> 5;
// TODO - figure out a cleaner way.
if (SConfig::GetInstance().bWii)
memAddr = bpMem.tmem_config.tlut_src << 5;
else
memAddr = (bpMem.tmem_config.tlut_src & 0xFFFFF) << 5;
}
void LoadCPReg(u32 subCmd, u32 value, CPMemory &cpMem)
{
switch (subCmd & 0xF0)

View File

@ -28,6 +28,11 @@ FifoDataFile::~FifoDataFile()
}
}
bool FifoDataFile::HasBrokenEFBCopies() const
{
return version < 2;
}
void FifoDataFile::SetIsWii(bool isWii)
{
SetFlag(FLAG_IS_WII, isWii);

View File

@ -59,6 +59,7 @@ public:
void SetIsWii(bool isWii);
bool GetIsWii() const;
bool HasBrokenEFBCopies() const;
u32 *GetBPMem() { return m_BPMem; }
u32 *GetCPMem() { return m_CPMem; }
@ -93,6 +94,7 @@ private:
u32 m_XFRegs[XF_REGS_SIZE];
u32 m_Flags;
u32 version;
std::vector<FifoFrameInfo> m_Frames;
};

View File

@ -12,7 +12,7 @@ namespace FifoFileStruct
enum
{
FILE_ID = 0x0d01f1f0,
VERSION_NUMBER = 1,
VERSION_NUMBER = 2,
MIN_LOADER_VERSION = 1,
};

View File

@ -63,8 +63,7 @@ bool FifoPlayer::Play()
if (m_File->GetFrameCount() == 0)
return false;
// Currently these is no such thing as a Fifolog without broken EFB copies.
IsPlayingBackFifologWithBrokenEFBCopies = true;
IsPlayingBackFifologWithBrokenEFBCopies = m_File->HasBrokenEFBCopies();
m_CurrentFrame = m_FrameRangeStart;

View File

@ -99,11 +99,6 @@ void FifoRecordAnalyzer::DecodeOpcode(u8 *data)
u32 cmd2 = ReadFifo32(data);
BPCmd bp = FifoAnalyzer::DecodeBPCmd(cmd2, *m_BpMem);
if (bp.address == BPMEM_LOADTLUT1)
ProcessLoadTlut1();
if (bp.address == BPMEM_PRELOAD_MODE)
ProcessPreloadTexture();
}
break;
@ -113,7 +108,6 @@ void FifoRecordAnalyzer::DecodeOpcode(u8 *data)
if (!m_DrawingObject)
{
m_DrawingObject = true;
ProcessTexMaps();
}
ProcessVertexArrays(data, cmd & GX_VAT_MASK);
@ -125,26 +119,6 @@ void FifoRecordAnalyzer::DecodeOpcode(u8 *data)
}
}
void FifoRecordAnalyzer::ProcessLoadTlut1()
{
u32 tlutXferCount;
u32 tlutMemAddr;
u32 memAddr;
GetTlutLoadData(tlutMemAddr, memAddr, tlutXferCount, *m_BpMem);
FifoRecorder::GetInstance().WriteMemory(memAddr, tlutXferCount, MemoryUpdate::TMEM);
}
void FifoRecordAnalyzer::ProcessPreloadTexture()
{
BPS_TmemConfig& tmem_cfg = m_BpMem->tmem_config;
//u32 tmem_addr = tmem_cfg.preload_tmem_even * TMEM_LINE_SIZE;
u32 size = tmem_cfg.preload_tile_info.count * TMEM_LINE_SIZE; // TODO: Should this be half size for RGBA8 preloads?
FifoRecorder::GetInstance().WriteMemory(tmem_cfg.preload_addr << 5, size, MemoryUpdate::TMEM);
}
void FifoRecordAnalyzer::ProcessLoadIndexedXf(u32 val, int array)
{
int index = val >> 16;
@ -152,7 +126,7 @@ void FifoRecordAnalyzer::ProcessLoadIndexedXf(u32 val, int array)
u32 address = m_CpMem.arrayBases[array] + m_CpMem.arrayStrides[array] * index;
FifoRecorder::GetInstance().WriteMemory(address, size * 4, MemoryUpdate::XF_DATA);
FifoRecorder::GetInstance().UseMemory(address, size * 4, MemoryUpdate::XF_DATA);
}
void FifoRecordAnalyzer::ProcessVertexArrays(u8 *data, u8 vtxAttrGroup)
@ -225,80 +199,5 @@ void FifoRecordAnalyzer::WriteVertexArray(int arrayIndex, u8 *vertexData, int ve
u32 arrayStart = m_CpMem.arrayBases[arrayIndex];
u32 arraySize = m_CpMem.arrayStrides[arrayIndex] * (maxIndex + 1);
FifoRecorder::GetInstance().WriteMemory(arrayStart, arraySize, MemoryUpdate::VERTEX_STREAM);
}
void FifoRecordAnalyzer::ProcessTexMaps()
{
u32 writtenTexMaps = 0;
// Texture maps used in TEV indirect stages
for (u32 i = 0; i < m_BpMem->genMode.numindstages; ++i)
{
u32 texMap = m_BpMem->tevindref.getTexMap(i);
WriteTexMapMemory(texMap, writtenTexMaps);
}
// Texture maps used in TEV direct stages
for (u32 i = 0; i <= m_BpMem->genMode.numtevstages; ++i)
{
int stageNum2 = i >> 1;
int stageOdd = i & 1;
TwoTevStageOrders &order = m_BpMem->tevorders[stageNum2];
int texMap = order.getTexMap(stageOdd);
if (order.getEnable(stageOdd))
WriteTexMapMemory(texMap, writtenTexMaps);
}
}
void FifoRecordAnalyzer::WriteTexMapMemory(int texMap, u32 &writtenTexMaps)
{
// Avoid rechecking the same texture map
u32 texMapMask = 1 << texMap;
if (writtenTexMaps & texMapMask)
return;
writtenTexMaps |= texMapMask;
FourTexUnits& texUnit = m_BpMem->tex[(texMap >> 2) & 1];
u8 subTexmap = texMap & 3;
TexImage0& ti0 = texUnit.texImage0[subTexmap];
u32 width = ti0.width + 1;
u32 height = ti0.height + 1;
u32 imageBase = texUnit.texImage3[subTexmap].image_base << 5;
u32 fmtWidth = TexDecoder_GetBlockWidthInTexels(ti0.format) - 1;
u32 fmtHeight = TexDecoder_GetBlockHeightInTexels(ti0.format) - 1;
int fmtDepth = TexDecoder_GetTexelSizeInNibbles(ti0.format);
// Round width and height up to the next block
width = (width + fmtWidth) & (~fmtWidth);
height = (height + fmtHeight) & (~fmtHeight);
u32 textureSize = (width * height * fmtDepth) / 2;
// TODO: mip maps
int mip = texUnit.texMode1[subTexmap].max_lod;
if ((texUnit.texMode0[subTexmap].min_filter & 3) == 0)
mip = 0;
while (mip)
{
width >>= 1;
height >>= 1;
width = std::max(width, fmtWidth);
height = std::max(height, fmtHeight);
u32 size = (width * height * fmtDepth) >> 1;
textureSize += size;
mip--;
}
FifoRecorder::GetInstance().WriteMemory(imageBase, textureSize, MemoryUpdate::TEXTURE_MAP);
FifoRecorder::GetInstance().UseMemory(arrayStart, arraySize, MemoryUpdate::VERTEX_STREAM);
}

View File

@ -19,20 +19,16 @@ public:
void Initialize(u32 *bpMem, u32 *cpMem);
// Assumes data contains all information for the command
// Calls FifoRecorder::WriteMemory
// Calls FifoRecorder::UseMemory
void AnalyzeGPCommand(u8 *data);
private:
void DecodeOpcode(u8 *data);
void ProcessLoadTlut1();
void ProcessPreloadTexture();
void ProcessLoadIndexedXf(u32 val, int array);
void ProcessVertexArrays(u8 *data, u8 vtxAttrGroup);
void ProcessTexMaps();
void WriteVertexArray(int arrayIndex, u8 *vertexData, int vertexSize, int numVertices);
void WriteTexMapMemory(int texMap, u32 &writtenTexMaps);
bool m_DrawingObject;

View File

@ -102,7 +102,7 @@ void FifoRecorder::WriteGPCommand(u8 *data, u32 size)
m_SkipNextData = m_SkipFutureData;
}
void FifoRecorder::WriteMemory(u32 address, u32 size, MemoryUpdate::Type type)
void FifoRecorder::UseMemory(u32 address, u32 size, MemoryUpdate::Type type, bool dynamicUpdate)
{
u8 *curData;
u8 *newData;
@ -117,7 +117,7 @@ void FifoRecorder::WriteMemory(u32 address, u32 size, MemoryUpdate::Type type)
newData = &Memory::m_pRAM[address & Memory::RAM_MASK];
}
if (memcmp(curData, newData, size) != 0)
if (!dynamicUpdate && memcmp(curData, newData, size) != 0)
{
// Update current memory
memcpy(curData, newData, size);
@ -133,6 +133,11 @@ void FifoRecorder::WriteMemory(u32 address, u32 size, MemoryUpdate::Type type)
m_CurrentFrame.memoryUpdates.push_back(memUpdate);
}
else if (dynamicUpdate)
{
// Shadow the data so it won't be recorded as changed by a future UseMemory
memcpy(curData, newData, size);
}
}
void FifoRecorder::EndFrame(u32 fifoStart, u32 fifoEnd)

View File

@ -27,7 +27,10 @@ public:
// Must write one full GP command at a time
void WriteGPCommand(u8 *data, u32 size);
void WriteMemory(u32 address, u32 size, MemoryUpdate::Type type);
// Track memory that has been used and write it to the fifolog if it has changed.
// If memory is updated by the video backend (dynamicUpdate == true) take special care to make sure the data
// isn't baked into the fifolog.
void UseMemory(u32 address, u32 size, MemoryUpdate::Type type, bool dynamicUpdate = false);
void EndFrame(u32 fifoStart, u32 fifoEnd);