GE Debugger: Initial GE dump replay.

Doesn't work for a few reasons, mainly need existing matrix state/etc.
This commit is contained in:
Unknown W. Brackets
2017-06-03 14:14:43 -07:00
parent ea2c79d789
commit 73d21ab859
2 changed files with 221 additions and 3 deletions

View File

@@ -1671,10 +1671,13 @@ bool __KernelLoadGEDump(std::string *error_string) {
}
void __KernelGPUReplay() {
u64 destTicks = CoreTiming::GetTicks() + msToCycles(1001.0f / 60.0f);
if (!GPURecord::RunMountedReplay()) {
Core_Stop();
}
hleEatCycles(msToCycles(1001.0f / 60.0f));
if (destTicks < CoreTiming::GetTicks()) {
hleEatCycles(destTicks - CoreTiming::GetTicks());
}
}
int sceKernelLoadExec(const char *filename, u32 paramPtr)

View File

@@ -23,10 +23,15 @@
#include "Common/FileUtil.h"
#include "Common/Log.h"
#include "Core/Core.h"
#include "Core/CoreTiming.h"
#include "Core/ELF/ParamSFO.h"
#include "Core/FileSystems/MetaFileSystem.h"
#include "Core/HLE/sceDisplay.h"
#include "Core/HLE/sceKernelMemory.h"
#include "Core/MemMap.h"
#include "Core/MIPS/MIPS.h"
#include "Core/System.h"
#include "GPU/GPUInterface.h"
#include "GPU/GPUState.h"
#include "GPU/ge_constants.h"
#include "GPU/Common/TextureDecoder.h"
@@ -72,6 +77,15 @@ static std::vector<Command> commands;
static std::vector<u32> lastRegisters;
static std::vector<u32> lastTextures;
// TODO: Maybe move execute to another file?
static u32 execIndPtr;
static u32 execVertPtr;
static u32 execClutPtr;
static u32 execTransferPtr;
static u32 execMemcpyDest;
static u32 execTexturePtrs[8];
static std::vector<u32> execListQueue;
static void FlushRegisters() {
if (!lastRegisters.empty()) {
Command last{CommandType::REGISTERS};
@@ -419,6 +433,208 @@ void NotifyFrame() {
}
}
static bool ExecuteSubmitCmds(void *p, u32 sz) {
// TODO: Smarter memory allocation.
// Over allocate for the finish/end, and include execListQueue.
u32 pendingSize = (int)execListQueue.size() * sizeof(u32);
u32 allocSize = pendingSize + sz + 8;
u32 ptr = userMemory.Alloc(allocSize);
if (!ptr) {
ERROR_LOG(SYSTEM, "Unable to allocate for registers");
return false;
}
Memory::MemcpyUnchecked(ptr, execListQueue.data(), pendingSize);
Memory::MemcpyUnchecked(ptr + pendingSize, p, sz);
Memory::Write_U32(GE_CMD_FINISH << 24, ptr + pendingSize + sz + 0);
Memory::Write_U32(GE_CMD_END << 24, ptr + pendingSize + sz + 4);
auto optParam = PSPPointer<PspGeListArgs>::Create(0);
gpu->EnableInterrupts(false);
u32 listID = gpu->EnqueueList(ptr, 0, -1, optParam, false);
currentMIPS->downcount -= gpu->GetListTicks(listID) - CoreTiming::GetTicks();
gpu->ListSync(listID, 0);
gpu->EnableInterrupts(true);
userMemory.Free(ptr);
execListQueue.clear();
return true;
}
static void FreePSPPointer(u32 &p) {
if (p) {
userMemory.Free(p);
p = 0;
}
}
static void ExecuteRegisters(u32 ptr, u32 sz) {
ExecuteSubmitCmds(pushbuf.data() + ptr, sz);
}
static void ExecuteVertices(u32 ptr, u32 sz) {
FreePSPPointer(execVertPtr);
u32 allocSize = sz;
execVertPtr = userMemory.Alloc(allocSize);
if (!execVertPtr) {
ERROR_LOG(SYSTEM, "Unable to allocate for vertices");
return;
}
Memory::MemcpyUnchecked(execVertPtr, pushbuf.data() + ptr, sz);
execListQueue.push_back((GE_CMD_BASE << 24) | ((execVertPtr >> 8) & 0x00FF0000));
execListQueue.push_back((GE_CMD_VADDR << 24) | (execVertPtr & 0x00FFFFFF));
}
static void ExecuteIndices(u32 ptr, u32 sz) {
FreePSPPointer(execIndPtr);
u32 allocSize = sz;
execIndPtr = userMemory.Alloc(allocSize);
if (!execIndPtr) {
ERROR_LOG(SYSTEM, "Unable to allocate for indices");
return;
}
Memory::MemcpyUnchecked(execIndPtr, pushbuf.data() + ptr, sz);
execListQueue.push_back((GE_CMD_BASE << 24) | ((execIndPtr >> 8) & 0x00FF0000));
execListQueue.push_back((GE_CMD_IADDR << 24) | (execIndPtr & 0x00FFFFFF));
}
static void ExecuteClut(u32 ptr, u32 sz) {
FreePSPPointer(execClutPtr);
u32 allocSize = sz;
execClutPtr = userMemory.Alloc(allocSize);
if (!execClutPtr) {
ERROR_LOG(SYSTEM, "Unable to allocate for clut");
return;
}
Memory::MemcpyUnchecked(execClutPtr, pushbuf.data() + ptr, sz);
execListQueue.push_back((GE_CMD_CLUTADDRUPPER << 24) | ((execClutPtr >> 8) & 0x00FF0000));
execListQueue.push_back((GE_CMD_CLUTADDR << 24) | (execClutPtr & 0x00FFFFFF));
}
static void ExecuteTransferSrc(u32 ptr, u32 sz) {
FreePSPPointer(execTransferPtr);
u32 allocSize = sz;
execTransferPtr = userMemory.Alloc(allocSize);
if (!execClutPtr) {
ERROR_LOG(SYSTEM, "Unable to allocate for transfer");
return;
}
Memory::MemcpyUnchecked(execTransferPtr, pushbuf.data() + ptr, sz);
execListQueue.push_back((gstate.transfersrcw & 0xFF00FFFF) | ((execTransferPtr >> 8) & 0x00FF0000));
execListQueue.push_back(((GE_CMD_TRANSFERSRC) << 24) | (execTransferPtr & 0x00FFFFFF));
}
static void ExecuteMemset(u32 ptr, u32 sz) {
// TODO
}
static void ExecuteMemcpyDest(u32 ptr, u32 sz) {
// TODO
}
static void ExecuteMemcpy(u32 ptr, u32 sz) {
// TODO
}
static void ExecuteTexture(int level, u32 ptr, u32 sz) {
FreePSPPointer(execTexturePtrs[level]);
u32 allocSize = sz;
u32 pspPointer = userMemory.Alloc(allocSize);
if (!pspPointer) {
ERROR_LOG(SYSTEM, "Unable to allocate for texture");
return;
}
Memory::MemcpyUnchecked(pspPointer, pushbuf.data() + ptr, sz);
execTexturePtrs[level] = pspPointer;
execListQueue.push_back((gstate.texbufwidth[level] & 0xFF00FFFF) | ((pspPointer >> 8) & 0x00FF0000));
execListQueue.push_back(((GE_CMD_TEXADDR0 + level) << 24) | (pspPointer & 0x00FFFFFF));
}
static void ExecuteFree() {
FreePSPPointer(execIndPtr);
FreePSPPointer(execVertPtr);
FreePSPPointer(execClutPtr);
FreePSPPointer(execTransferPtr);
execMemcpyDest = 0;
for (int level = 0; level < 8; ++level) {
FreePSPPointer(execTexturePtrs[level]);
}
}
static bool ExecuteCommands() {
//for (const Command &cmd : commands) {
for (size_t i = 0; i < commands.size(); ++i) {
const Command &cmd = commands[i];
switch (cmd.type) {
case CommandType::REGISTERS:
ExecuteRegisters(cmd.ptr, cmd.sz);
break;
case CommandType::VERTICES:
ExecuteVertices(cmd.ptr, cmd.sz);
break;
case CommandType::INDICES:
ExecuteIndices(cmd.ptr, cmd.sz);
break;
case CommandType::CLUT:
ExecuteClut(cmd.ptr, cmd.sz);
break;
case CommandType::TRANSFERSRC:
ExecuteTransferSrc(cmd.ptr, cmd.sz);
break;
case CommandType::MEMSET:
ExecuteMemset(cmd.ptr, cmd.sz);
break;
case CommandType::MEMCPYDEST:
ExecuteMemcpyDest(cmd.ptr, cmd.sz);
break;
case CommandType::MEMCPYDATA:
ExecuteMemcpy(cmd.ptr, cmd.sz);
break;
case CommandType::TEXTURE0:
case CommandType::TEXTURE1:
case CommandType::TEXTURE2:
case CommandType::TEXTURE3:
case CommandType::TEXTURE4:
case CommandType::TEXTURE5:
case CommandType::TEXTURE6:
case CommandType::TEXTURE7:
ExecuteTexture((int)cmd.type - (int)CommandType::TEXTURE0, cmd.ptr, cmd.sz);
break;
default:
ERROR_LOG(SYSTEM, "Unsupported GE dump command: %d", cmd.type);
return false;
}
}
ExecuteFree();
return true;
}
bool RunMountedReplay() {
_assert_msg_(SYSTEM, !active && !nextFrame, "Cannot run replay while recording.");
@@ -458,8 +674,7 @@ bool RunMountedReplay() {
pspFileSystem.CloseFile(fp);
// TODO: Execute commands.
return true;
return ExecuteCommands();
}
};