mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-23 21:39:52 +00:00
Merge pull request #16321 from unknownbrackets/gedebugger-record
GE Debugger: Try harder to identify unchanged VRAM
This commit is contained in:
commit
03a90b1bbf
@ -46,6 +46,7 @@
|
||||
namespace GPURecord {
|
||||
|
||||
static std::string lastExecFilename;
|
||||
static uint32_t lastExecVersion;
|
||||
static std::vector<Command> lastExecCommands;
|
||||
static std::vector<u8> lastExecPushbuf;
|
||||
static std::mutex executeLock;
|
||||
@ -761,6 +762,7 @@ static void ReplayStop() {
|
||||
lastExecFilename.clear();
|
||||
lastExecCommands.clear();
|
||||
lastExecPushbuf.clear();
|
||||
lastExecVersion = 0;
|
||||
}
|
||||
|
||||
bool RunMountedReplay(const std::string &filename) {
|
||||
@ -769,7 +771,7 @@ bool RunMountedReplay(const std::string &filename) {
|
||||
std::lock_guard<std::mutex> guard(executeLock);
|
||||
Core_ListenStopRequest(&ReplayStop);
|
||||
|
||||
uint32_t version = 0;
|
||||
uint32_t version = lastExecVersion;
|
||||
if (lastExecFilename != filename) {
|
||||
PROFILE_THIS_SCOPE("ReplayLoad");
|
||||
u32 fp = pspFileSystem.OpenFile(filename, FILEACCESS_READ);
|
||||
@ -812,6 +814,7 @@ bool RunMountedReplay(const std::string &filename) {
|
||||
}
|
||||
|
||||
lastExecFilename = filename;
|
||||
lastExecVersion = version;
|
||||
}
|
||||
|
||||
DumpExecute executor(lastExecPushbuf, lastExecCommands, version);
|
||||
|
@ -60,11 +60,13 @@ static std::vector<Command> commands;
|
||||
static std::vector<u32> lastRegisters;
|
||||
static std::vector<u32> lastTextures;
|
||||
static std::set<u32> lastRenderTargets;
|
||||
static std::vector<u8> lastVRAM;
|
||||
|
||||
enum class DirtyVRAMFlag : uint8_t {
|
||||
CLEAN = 0,
|
||||
DIRTY = 1,
|
||||
DRAWN = 2,
|
||||
UNKNOWN = 1,
|
||||
DIRTY = 2,
|
||||
DRAWN = 3,
|
||||
};
|
||||
static constexpr uint32_t DIRTY_VRAM_SHIFT = 8;
|
||||
static constexpr uint32_t DIRTY_VRAM_ROUND = (1 << DIRTY_VRAM_SHIFT) - 1;
|
||||
@ -106,8 +108,15 @@ static Path GenRecordingFilename() {
|
||||
}
|
||||
|
||||
static void DirtyAllVRAM(DirtyVRAMFlag flag) {
|
||||
for (uint32_t i = 0; i < DIRTY_VRAM_SIZE; ++i)
|
||||
dirtyVRAM[i] = flag;
|
||||
if (flag == DirtyVRAMFlag::UNKNOWN) {
|
||||
for (uint32_t i = 0; i < DIRTY_VRAM_SIZE; ++i) {
|
||||
if (dirtyVRAM[i] == DirtyVRAMFlag::CLEAN)
|
||||
dirtyVRAM[i] = DirtyVRAMFlag::UNKNOWN;
|
||||
}
|
||||
} else {
|
||||
for (uint32_t i = 0; i < DIRTY_VRAM_SIZE; ++i)
|
||||
dirtyVRAM[i] = flag;
|
||||
}
|
||||
}
|
||||
|
||||
static void DirtyVRAM(u32 start, u32 sz, DirtyVRAMFlag flag) {
|
||||
@ -123,10 +132,10 @@ static void DirtyVRAM(u32 start, u32 sz, DirtyVRAMFlag flag) {
|
||||
}
|
||||
|
||||
static void DirtyDrawnVRAM() {
|
||||
int w = std::max(gstate.getScissorX2(), gstate.getRegionX2()) + 1;
|
||||
int h = std::max(gstate.getScissorY2(), gstate.getRegionY2()) + 1;
|
||||
int w = std::min(gstate.getScissorX2(), gstate.getRegionX2()) + 1;
|
||||
int h = std::min(gstate.getScissorY2(), gstate.getRegionY2()) + 1;
|
||||
|
||||
bool drawZ = gstate.isDepthWriteEnabled() && gstate.isDepthTestEnabled();
|
||||
bool drawZ = !gstate.isModeClear() && gstate.isDepthWriteEnabled() && gstate.isDepthTestEnabled();
|
||||
bool clearZ = gstate.isModeClear() && gstate.isClearModeDepthMask();
|
||||
if (drawZ || clearZ) {
|
||||
int bytes = 2 * gstate.DepthBufStride() * h;
|
||||
@ -155,6 +164,7 @@ static void BeginRecording() {
|
||||
pushbuf.resize(pushbuf.size() + sz);
|
||||
gstate.Save((u32_le *)(pushbuf.data() + ptr));
|
||||
commands.push_back({CommandType::INIT, sz, ptr});
|
||||
lastVRAM.resize(2 * 1024 * 1024);
|
||||
|
||||
// Also save the initial CLUT.
|
||||
GPUDebugBuffer clut;
|
||||
@ -325,6 +335,7 @@ static u32 GetTargetFlags(u32 addr, u32 sizeInRAM) {
|
||||
addr &= 0x041FFFFF;
|
||||
const bool isTarget = lastRenderTargets.find(addr) != lastRenderTargets.end();
|
||||
|
||||
bool isUnknownVRAM = false;
|
||||
bool isDirtyVRAM = false;
|
||||
bool isDrawnVRAM = false;
|
||||
uint32_t start = (addr >> DIRTY_VRAM_SHIFT) & DIRTY_VRAM_MASK;
|
||||
@ -333,16 +344,25 @@ static u32 GetTargetFlags(u32 addr, u32 sizeInRAM) {
|
||||
bool endEven = ((addr + sizeInRAM) & DIRTY_VRAM_ROUND) == 0;
|
||||
for (uint32_t i = 0; i < blocks; ++i) {
|
||||
DirtyVRAMFlag flag = dirtyVRAM[start + i];
|
||||
isUnknownVRAM = (isUnknownVRAM || flag == DirtyVRAMFlag::UNKNOWN) && flag != DirtyVRAMFlag::DIRTY && flag != DirtyVRAMFlag::DRAWN;
|
||||
isDirtyVRAM = isDirtyVRAM || flag != DirtyVRAMFlag::CLEAN;
|
||||
isDrawnVRAM = isDrawnVRAM || flag == DirtyVRAMFlag::DRAWN;
|
||||
|
||||
// Mark the VRAM clean now that it's been copied to VRAM.
|
||||
if (flag == DirtyVRAMFlag::DIRTY) {
|
||||
if (flag == DirtyVRAMFlag::UNKNOWN || flag == DirtyVRAMFlag::DIRTY) {
|
||||
if ((i > 0 || startEven) && (i < blocks || endEven))
|
||||
dirtyVRAM[start + i] = DirtyVRAMFlag::CLEAN;
|
||||
}
|
||||
}
|
||||
|
||||
if (isUnknownVRAM && isDirtyVRAM) {
|
||||
// This means it's only UNKNOWN/CLEAN and not known to be actually dirty.
|
||||
// Let's check our shadow copy of what we last sent for this VRAM.
|
||||
int diff = memcmp(&lastVRAM[addr & 0x001FFFFF], Memory::GetPointerUnchecked(addr), sizeInRAM);
|
||||
if (diff == 0)
|
||||
isDirtyVRAM = false;
|
||||
}
|
||||
|
||||
// The isTarget flag is mostly used for replay of dumps on a PSP.
|
||||
u32 flags = isTarget ? 1 : 0;
|
||||
// The unchangedVRAM flag tells us we can skip recopying.
|
||||
@ -376,13 +396,16 @@ static void EmitTextureData(int level, u32 texaddr) {
|
||||
u32 pad;
|
||||
};
|
||||
|
||||
u32 flags = GetTargetFlags(texaddr, sizeInRAM);
|
||||
u32 flags = GetTargetFlags(texaddr, bytes);
|
||||
FramebufData framebuf{ texaddr, bufw, flags };
|
||||
framebufData.resize(sizeof(framebuf) + bytes);
|
||||
memcpy(&framebufData[0], &framebuf, sizeof(framebuf));
|
||||
memcpy(&framebufData[sizeof(framebuf)], p, bytes);
|
||||
p = &framebufData[0];
|
||||
|
||||
if ((flags & 2) == 0)
|
||||
memcpy(&lastVRAM[texaddr & 0x001FFFFF], Memory::GetPointerUnchecked(texaddr), bytes);
|
||||
|
||||
// Okay, now we'll just emit this instead.
|
||||
type = CommandType((int)CommandType::FRAMEBUF0 + level);
|
||||
bytes += (u32)sizeof(framebuf);
|
||||
@ -418,11 +441,12 @@ static void FlushPrimState(int vcount) {
|
||||
lastRenderTargets.insert(PSP_GetVidMemBase() | gstate.getDepthBufRawAddress());
|
||||
|
||||
// We re-flush textures always in case the game changed them... kinda expensive.
|
||||
// TODO: Dirty textures on transfer/stall/etc. somehow?
|
||||
// TODO: Or maybe de-dup by validating if it has changed?
|
||||
bool textureEnabled = gstate.isTextureMapEnabled() || gstate.isAntiAliasEnabled();
|
||||
// Play it safe and allow texture coords to emit data too.
|
||||
bool textureCoords = (gstate.vertType & GE_VTYPE_TC_MASK) != 0;
|
||||
for (int level = 0; level < 8; ++level) {
|
||||
u32 texaddr = gstate.getTextureAddress(level);
|
||||
if (texaddr) {
|
||||
if (texaddr && (textureEnabled || textureCoords)) {
|
||||
EmitTextureData(level, texaddr);
|
||||
}
|
||||
}
|
||||
@ -508,6 +532,9 @@ static void EmitClut(u32 op) {
|
||||
pushbuf.resize(pushbuf.size() + sizeof(data));
|
||||
memcpy(pushbuf.data() + cmd.ptr, &data, sizeof(data));
|
||||
commands.push_back(cmd);
|
||||
|
||||
if ((flags & 2) == 0)
|
||||
memcpy(&lastVRAM[addr & 0x001FFFFF], Memory::GetPointerUnchecked(addr), bytes);
|
||||
}
|
||||
EmitCommandWithRAM(CommandType::CLUT, Memory::GetPointerUnchecked(addr), bytes, 16);
|
||||
}
|
||||
@ -558,6 +585,7 @@ static void FinishRecording() {
|
||||
Path filename = WriteRecording();
|
||||
commands.clear();
|
||||
pushbuf.clear();
|
||||
lastVRAM.clear();
|
||||
|
||||
NOTICE_LOG(SYSTEM, "Recording finished");
|
||||
active = false;
|
||||
@ -655,8 +683,9 @@ void NotifyMemcpy(u32 dest, u32 src, u32 sz) {
|
||||
|
||||
sz = Memory::ValidSize(dest, sz);
|
||||
if (sz != 0) {
|
||||
EmitCommandWithRAM(CommandType::MEMCPYDATA, Memory::GetPointer(dest), sz, 1);
|
||||
DirtyVRAM(dest, sz, DirtyVRAMFlag::DIRTY);
|
||||
EmitCommandWithRAM(CommandType::MEMCPYDATA, Memory::GetPointerUnchecked(dest), sz, 1);
|
||||
memcpy(&lastVRAM[dest & 0x001FFFFF], Memory::GetPointerUnchecked(dest), sz);
|
||||
DirtyVRAM(dest, sz, DirtyVRAMFlag::CLEAN);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -682,20 +711,14 @@ void NotifyMemset(u32 dest, int v, u32 sz) {
|
||||
pushbuf.resize(pushbuf.size() + sizeof(data));
|
||||
memcpy(pushbuf.data() + cmd.ptr, &data, sizeof(data));
|
||||
commands.push_back(cmd);
|
||||
DirtyVRAM(dest, sz, DirtyVRAMFlag::DIRTY);
|
||||
memset(&lastVRAM[dest & 0x001FFFFF], v, sz);
|
||||
DirtyVRAM(dest, sz, DirtyVRAMFlag::CLEAN);
|
||||
}
|
||||
}
|
||||
|
||||
void NotifyUpload(u32 dest, u32 sz) {
|
||||
if (!active) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Memory::IsVRAMAddress(dest)) {
|
||||
// This also checks the edram translation value.
|
||||
NotifyMemcpy(dest, dest, sz);
|
||||
DirtyVRAM(dest, sz, DirtyVRAMFlag::DIRTY);
|
||||
}
|
||||
// This also checks the edram translation value and dirties VRAM.
|
||||
NotifyMemcpy(dest, dest, sz);
|
||||
}
|
||||
|
||||
static bool HasDrawCommands() {
|
||||
@ -790,7 +813,7 @@ void NotifyCPU() {
|
||||
return;
|
||||
}
|
||||
|
||||
DirtyAllVRAM(DirtyVRAMFlag::DIRTY);
|
||||
DirtyAllVRAM(DirtyVRAMFlag::UNKNOWN);
|
||||
}
|
||||
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user