Merge pull request #9780 from unknownbrackets/ge-record

GE recorder and replay
This commit is contained in:
Henrik Rydgård 2017-06-05 10:08:55 +02:00 committed by GitHub
commit c5ebeb4273
53 changed files with 1663 additions and 243 deletions

View file

@ -1268,6 +1268,8 @@ set(GPU_SOURCES
GPU/Common/SplineCommon.h
GPU/Debugger/Breakpoints.cpp
GPU/Debugger/Breakpoints.h
GPU/Debugger/Record.cpp
GPU/Debugger/Record.h
GPU/Debugger/Stepping.cpp
GPU/Debugger/Stepping.h
GPU/GPUInterface.h
@ -1350,6 +1352,8 @@ add_library(${CoreLibName} ${CoreLinkType}
Core/ELF/ParamSFO.cpp
Core/ELF/ParamSFO.h
Core/FileSystems/tlzrc.cpp
Core/FileSystems/BlobFileSystem.cpp
Core/FileSystems/BlobFileSystem.h
Core/FileSystems/BlockDevices.cpp
Core/FileSystems/BlockDevices.h
Core/FileSystems/DirectoryFileSystem.cpp

View file

@ -21,7 +21,8 @@
<PropertyGroup Label="Globals">
<ProjectGuid>{533F1D30-D04D-47CC-AD71-20F658907E36}</ProjectGuid>
<RootNamespace>Core</RootNamespace>
<WindowsTargetPlatformVersion></WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>
</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
@ -183,6 +184,7 @@
<ClCompile Include="..\ext\udis86\syn.c" />
<ClCompile Include="..\ext\udis86\udis86.c" />
<ClCompile Include="AVIDump.cpp" />
<ClCompile Include="FileSystems\BlobFileSystem.cpp" />
<ClCompile Include="HLE\KUBridge.cpp" />
<ClCompile Include="MIPS\IR\IRAsm.cpp" />
<ClCompile Include="MIPS\IR\IRCompALU.cpp" />
@ -524,6 +526,7 @@
<ClInclude Include="..\ext\udis86\udint.h" />
<ClInclude Include="..\ext\udis86\udis86.h" />
<ClInclude Include="AVIDump.h" />
<ClInclude Include="FileSystems\BlobFileSystem.h" />
<ClInclude Include="HLE\KUBridge.h" />
<ClInclude Include="MIPS\IR\IRFrontend.h" />
<ClInclude Include="MIPS\IR\IRInst.h" />

View file

@ -680,6 +680,9 @@
<ClCompile Include="HLE\KUBridge.cpp">
<Filter>HLE\Libraries</Filter>
</ClCompile>
<ClCompile Include="FileSystems\BlobFileSystem.cpp">
<Filter>FileSystems</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="ELF\ElfReader.h">
@ -1250,10 +1253,13 @@
<ClInclude Include="HLE\KUBridge.h">
<Filter>HLE\Libraries</Filter>
</ClInclude>
<ClInclude Include="FileSystems\BlobFileSystem.h">
<Filter>FileSystems</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="CMakeLists.txt" />
<None Include="..\LICENSE.TXT" />
<None Include="..\android\jni\Android.mk" />
</ItemGroup>
</Project>
</Project>

View file

@ -573,6 +573,10 @@ void ForceCheck()
currentMIPS->downcount = -1;
// But let's not eat a bunch more time in Advance() because of this.
slicelength = -1;
#ifdef _DEBUG
_dbg_assert_msg_(CPU, cyclesExecuted >= 0, "Shouldn't have a negative cyclesExecuted");
#endif
}
void Advance()
@ -613,7 +617,7 @@ void LogPendingEvents()
Event *ptr = first;
while (ptr)
{
//INFO_LOG(TIMER, "PENDING: Now: %lld Pending: %lld Type: %d", globalTimer, ptr->time, ptr->type);
//INFO_LOG(CPU, "PENDING: Now: %lld Pending: %lld Type: %d", globalTimer, ptr->time, ptr->type);
ptr = ptr->next;
}
}

View file

@ -37,6 +37,14 @@ public:
std::vector<std::string> GetKeys();
std::string GenerateFakeID(std::string filename = "");
std::string GetDiscID() {
const std::string discID = GetValueString("DISC_ID");
if (discID.empty()) {
return GenerateFakeID();
}
return discID;
}
bool ReadSFO(const u8 *paramsfo, size_t size);
bool WriteSFO(u8 **paramsfo, size_t *size);

View file

@ -0,0 +1,137 @@
// Copyright (c) 2017- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include "Core/FileSystems/BlobFileSystem.h"
BlobFileSystem::BlobFileSystem(IHandleAllocator *hAlloc, FileLoader *fileLoader, std::string alias)
: alloc_(hAlloc), fileLoader_(fileLoader), alias_(alias) {
}
BlobFileSystem::~BlobFileSystem() {
// TODO: Who deletes fileLoader?
}
void BlobFileSystem::DoState(PointerWrap &p) {
// Not used in real emulation.
}
std::vector<PSPFileInfo> BlobFileSystem::GetDirListing(std::string path) {
std::vector<PSPFileInfo> listing;
listing.push_back(GetFileInfo(alias_));
return listing;
}
u32 BlobFileSystem::OpenFile(std::string filename, FileAccess access, const char *devicename) {
u32 newHandle = alloc_->GetNewHandle();
entries_[newHandle] = 0;
return newHandle;
}
void BlobFileSystem::CloseFile(u32 handle) {
alloc_->FreeHandle(handle);
entries_.erase(handle);
}
size_t BlobFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size) {
auto entry = entries_.find(handle);
if (entry != entries_.end()) {
size_t readSize = fileLoader_->ReadAt(entry->second, size, pointer);
entry->second += readSize;
return readSize;
}
return 0;
}
size_t BlobFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size, int &usec) {
usec = 0;
return ReadFile(handle, pointer, size);
}
size_t BlobFileSystem::WriteFile(u32 handle, const u8 *pointer, s64 size) {
return 0;
}
size_t BlobFileSystem::WriteFile(u32 handle, const u8 *pointer, s64 size, int &usec) {
return 0;
}
size_t BlobFileSystem::SeekFile(u32 handle, s32 position, FileMove type) {
auto entry = entries_.find(handle);
if (entry != entries_.end()) {
switch (type) {
case FILEMOVE_BEGIN:
entry->second = position;
break;
case FILEMOVE_CURRENT:
entry->second += position;
break;
case FILEMOVE_END:
entry->second = fileLoader_->FileSize() + position;
break;
}
return (size_t)entry->second;
}
return 0;
}
PSPFileInfo BlobFileSystem::GetFileInfo(std::string filename) {
PSPFileInfo info{};
info.name = alias_;
info.size = fileLoader_->FileSize();
info.access = 0666;
info.exists = true;
info.type = FILETYPE_NORMAL;
return info;
}
bool BlobFileSystem::OwnsHandle(u32 handle) {
auto entry = entries_.find(handle);
return entry != entries_.end();
}
int BlobFileSystem::Ioctl(u32 handle, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, u32 outlen, int &usec) {
return -1;
}
int BlobFileSystem::DevType(u32 handle) {
return -1;
}
bool BlobFileSystem::MkDir(const std::string &dirname) {
return false;
}
bool BlobFileSystem::RmDir(const std::string &dirname) {
return false;
}
int BlobFileSystem::RenameFile(const std::string &from, const std::string &to) {
return -1;
}
bool BlobFileSystem::RemoveFile(const std::string &filename) {
return false;
}
bool BlobFileSystem::GetHostPath(const std::string &inpath, std::string &outpath) {
outpath = fileLoader_->Path();
return true;
}
u64 BlobFileSystem::FreeSpace(const std::string &path) {
return 0;
}

View file

@ -0,0 +1,63 @@
// Copyright (c) 2017- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#pragma once
// This is used for opening a debug file as a blob, and mounting it.
// Importantly, uses a fileLoader for all access, so http:// URLs are supported.
// As of writing, only used by GE dump replay.
#include <map>
#include <string>
#include "Core/Loaders.h"
#include "Core/FileSystems/FileSystem.h"
class BlobFileSystem : public IFileSystem {
public:
BlobFileSystem(IHandleAllocator *hAlloc, FileLoader *fileLoader, std::string alias);
~BlobFileSystem();
void DoState(PointerWrap &p) override;
std::vector<PSPFileInfo> GetDirListing(std::string path) override;
u32 OpenFile(std::string filename, FileAccess access, const char *devicename = nullptr) override;
void CloseFile(u32 handle) override;
size_t ReadFile(u32 handle, u8 *pointer, s64 size) override;
size_t ReadFile(u32 handle, u8 *pointer, s64 size, int &usec) override;
size_t WriteFile(u32 handle, const u8 *pointer, s64 size) override;
size_t WriteFile(u32 handle, const u8 *pointer, s64 size, int &usec) override;
size_t SeekFile(u32 handle, s32 position, FileMove type) override;
PSPFileInfo GetFileInfo(std::string filename) override;
bool OwnsHandle(u32 handle) override;
int Ioctl(u32 handle, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, u32 outlen, int &usec) override;
int DevType(u32 handle) override;
int Flags() override { return 0; }
bool MkDir(const std::string &dirname) override;
bool RmDir(const std::string &dirname) override;
int RenameFile(const std::string &from, const std::string &to) override;
bool RemoveFile(const std::string &filename) override;
bool GetHostPath(const std::string &inpath, std::string &outpath) override;
u64 FreeSpace(const std::string &path) override;
private:
// File positions.
std::map<u32, s64> entries_;
IHandleAllocator *alloc_;
FileLoader *fileLoader_;
std::string alias_;
};

View file

@ -92,6 +92,7 @@ const HLEFunction FakeSysCalls[] = {
{NID_EXTENDRETURN, __KernelReturnFromExtendStack, "__KernelReturnFromExtendStack"},
{NID_MODULERETURN, __KernelReturnFromModuleFunc, "__KernelReturnFromModuleFunc"},
{NID_IDLE, __KernelIdle, "_sceKernelIdle"},
{NID_GPUREPLAY, __KernelGPUReplay, "__KernelGPUReplay"},
};
const HLEFunction UtilsForUser[] =

View file

@ -23,5 +23,6 @@
#define NID_EXTENDRETURN 0xbad0b0c9
#define NID_MODULERETURN 0xbad0d318
#define NID_IDLE 0x1d7e1d7e
#define NID_GPUREPLAY 0x9e45bd95
void RegisterAllModules();

View file

@ -825,13 +825,29 @@ static u32 sceDisplaySetMode(int displayMode, int displayWidth, int displayHeigh
return DisplayWaitForVblanks("display mode", 1);
}
// Some games (GTA) never call this during gameplay, so bad place to put a framerate counter.
static u32 sceDisplaySetFramebuf(u32 topaddr, int linesize, int pixelformat, int sync) {
void __DisplaySetFramebuf(u32 topaddr, int linesize, int pixelFormat, int sync) {
FrameBufferState fbstate = {0};
fbstate.topaddr = topaddr;
fbstate.fmt = (GEBufferFormat)pixelformat;
fbstate.fmt = (GEBufferFormat)pixelFormat;
fbstate.stride = linesize;
if (sync == PSP_DISPLAY_SETBUF_IMMEDIATE) {
// Write immediately to the current framebuffer parameters
framebuf = fbstate;
gpu->SetDisplayFramebuffer(framebuf.topaddr, framebuf.stride, framebuf.fmt);
} else {
// Delay the write until vblank
latchedFramebuf = fbstate;
framebufIsLatched = true;
// If we update the format or stride, this affects the current framebuf immediately.
framebuf.fmt = latchedFramebuf.fmt;
framebuf.stride = latchedFramebuf.stride;
}
}
// Some games (GTA) never call this during gameplay, so bad place to put a framerate counter.
u32 sceDisplaySetFramebuf(u32 topaddr, int linesize, int pixelformat, int sync) {
if (sync != PSP_DISPLAY_SETBUF_IMMEDIATE && sync != PSP_DISPLAY_SETBUF_NEXTFRAME) {
return hleLogError(SCEDISPLAY, SCE_KERNEL_ERROR_INVALID_MODE, "invalid sync mode");
}
@ -849,7 +865,7 @@ static u32 sceDisplaySetFramebuf(u32 topaddr, int linesize, int pixelformat, int
}
if (sync == PSP_DISPLAY_SETBUF_IMMEDIATE) {
if (fbstate.fmt != latchedFramebuf.fmt || fbstate.stride != latchedFramebuf.stride) {
if ((GEBufferFormat)pixelformat != latchedFramebuf.fmt || linesize != latchedFramebuf.stride) {
return hleReportError(SCEDISPLAY, SCE_KERNEL_ERROR_INVALID_MODE, "must change latched framebuf first");
}
}
@ -882,19 +898,7 @@ static u32 sceDisplaySetFramebuf(u32 topaddr, int linesize, int pixelformat, int
lastFlipCycles = CoreTiming::GetTicks();
}
if (sync == PSP_DISPLAY_SETBUF_IMMEDIATE) {
// Write immediately to the current framebuffer parameters
framebuf = fbstate;
gpu->SetDisplayFramebuffer(framebuf.topaddr, framebuf.stride, framebuf.fmt);
} else {
// Delay the write until vblank
latchedFramebuf = fbstate;
framebufIsLatched = true;
// If we update the format or stride, this affects the current framebuf immediately.
framebuf.fmt = latchedFramebuf.fmt;
framebuf.stride = latchedFramebuf.stride;
}
__DisplaySetFramebuf(topaddr, linesize, pixelformat, sync);
if (delayCycles > 0) {
// Okay, the game is going at too high a frame rate. God of War and Fat Princess both do this.
@ -910,10 +914,10 @@ static u32 sceDisplaySetFramebuf(u32 topaddr, int linesize, int pixelformat, int
}
}
bool __DisplayGetFramebuf(u8 **topaddr, u32 *linesize, u32 *pixelFormat, int latchedMode) {
bool __DisplayGetFramebuf(PSPPointer<u8> *topaddr, u32 *linesize, u32 *pixelFormat, int latchedMode) {
const FrameBufferState &fbState = latchedMode == PSP_DISPLAY_SETBUF_NEXTFRAME ? latchedFramebuf : framebuf;
if (topaddr != nullptr)
*topaddr = Memory::GetPointer(fbState.topaddr);
(*topaddr).ptr = fbState.topaddr;
if (linesize != nullptr)
*linesize = fbState.stride;
if (pixelFormat != nullptr)

View file

@ -17,6 +17,8 @@
#pragma once
#include "Core/MemMap.h"
void __DisplayInit();
void __DisplayDoState(PointerWrap &p);
void __DisplayShutdown();
@ -27,7 +29,8 @@ void Register_sceDisplay();
bool __DisplayFrameDone();
// Get information about the current framebuffer.
bool __DisplayGetFramebuf(u8 **topaddr, u32 *linesize, u32 *pixelFormat, int mode);
bool __DisplayGetFramebuf(PSPPointer<u8> *topaddr, u32 *linesize, u32 *pixelFormat, int mode);
void __DisplaySetFramebuf(u32 topaddr, int linesize, int pixelformat, int sync);
typedef void (*VblankCallback)();
// Listen for vblank events. Only register during init.
@ -44,4 +47,4 @@ int __DisplayGetFlipCount();
// Call this when resuming to avoid a small speedup burst
void __DisplaySetWasPaused();
void Register_sceDisplay_driver();
void Register_sceDisplay_driver();

View file

@ -1825,7 +1825,8 @@ static u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 o
return 0;
case 0x20: // EMULATOR_DEVCTL__EMIT_SCREENSHOT
u8 *topaddr;
{
PSPPointer<u8> topaddr;
u32 linesize, pixelFormat;
__DisplayGetFramebuf(&topaddr, &linesize, &pixelFormat, 0);
@ -1833,6 +1834,7 @@ static u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 o
host->SendDebugScreenshot(topaddr, linesize, 272);
return 0;
}
}
ERROR_LOG(SCEIO, "sceIoDevCtl: UNKNOWN PARAMETERS");

View file

@ -24,6 +24,7 @@
#include "Common/FileUtil.h"
#include "Common/StringUtils.h"
#include "Core/Config.h"
#include "Core/Core.h"
#include "Core/HLE/HLE.h"
#include "Core/HLE/FunctionWrappers.h"
#include "Core/HLE/HLETables.h"
@ -57,6 +58,7 @@
#include "Core/HLE/KernelWaitHelpers.h"
#include "Core/ELF/ParamSFO.h"
#include "GPU/Debugger/Record.h"
#include "GPU/GPU.h"
#include "GPU/GPUInterface.h"
#include "GPU/GPUState.h"
@ -1513,8 +1515,36 @@ u32 __KernelGetModuleGP(SceUID uid)
}
}
bool __KernelLoadExec(const char *filename, u32 paramPtr, std::string *error_string)
{
void __KernelLoadReset() {
// Wipe kernel here, loadexec should reset the entire system
if (__KernelIsRunning()) {
u32 error;
while (!loadedModules.empty()) {
SceUID moduleID = *loadedModules.begin();
Module *module = kernelObjects.Get<Module>(moduleID, error);
if (module) {
module->Cleanup();
} else {
// An invalid module. We need to remove it or we'll loop forever.
WARN_LOG(LOADER, "Invalid module still marked as loaded on loadexec");
loadedModules.erase(moduleID);
}
}
Replacement_Shutdown();
__KernelShutdown();
// HLE needs to be reset here
HLEShutdown();
Replacement_Init();
HLEInit();
gpu->Reinitialize();
}
__KernelModuleInit();
__KernelInit();
}
bool __KernelLoadExec(const char *filename, u32 paramPtr, std::string *error_string) {
SceKernelLoadExecParam param;
if (paramPtr)
@ -1536,33 +1566,7 @@ bool __KernelLoadExec(const char *filename, u32 paramPtr, std::string *error_str
Memory::Memcpy(param_key, keyAddr, (u32)keylen);
}
// Wipe kernel here, loadexec should reset the entire system
if (__KernelIsRunning())
{
u32 error;
while (!loadedModules.empty()) {
SceUID moduleID = *loadedModules.begin();
Module *module = kernelObjects.Get<Module>(moduleID, error);
if (module) {
module->Cleanup();
} else {
// An invalid module. We need to remove it or we'll loop forever.
WARN_LOG(LOADER, "Invalid module still marked as loaded on loadexec");
loadedModules.erase(moduleID);
}
}
Replacement_Shutdown();
__KernelShutdown();
//HLE needs to be reset here
HLEShutdown();
Replacement_Init();
HLEInit();
gpu->Reinitialize();
}
__KernelModuleInit();
__KernelInit();
__KernelLoadReset();
PSPFileInfo info = pspFileSystem.GetFileInfo(filename);
if (!info.exists) {
@ -1635,6 +1639,64 @@ bool __KernelLoadExec(const char *filename, u32 paramPtr, std::string *error_str
return true;
}
bool __KernelLoadGEDump(const std::string &base_filename, std::string *error_string) {
__KernelLoadReset();
mipsr4k.pc = PSP_GetUserMemoryBase();
const static u32_le runDumpCode[] = {
// Save the filename.
MIPS_MAKE_ORI(MIPS_REG_S0, MIPS_REG_A0, 0),
MIPS_MAKE_ORI(MIPS_REG_S1, MIPS_REG_A1, 0),
// Call the actual render.
MIPS_MAKE_SYSCALL("FakeSysCalls", "__KernelGPUReplay"),
// Make sure we don't get out of sync.
MIPS_MAKE_LUI(MIPS_REG_A0, 0),
MIPS_MAKE_SYSCALL("sceGe_user", "sceGeDrawSync"),
// Set the return address after the entry which saved the filename.
MIPS_MAKE_LUI(MIPS_REG_RA, mipsr4k.pc >> 16),
MIPS_MAKE_ADDIU(MIPS_REG_RA, MIPS_REG_RA, 8),
// Wait for the next vblank to render again.
MIPS_MAKE_JR_RA(),
MIPS_MAKE_SYSCALL("sceDisplay", "sceDisplayWaitVblankStart"),
// This never gets reached, just here to be safe.
MIPS_MAKE_BREAK(0),
};
for (size_t i = 0; i < ARRAY_SIZE(runDumpCode); ++i) {
Memory::WriteUnchecked_U32(runDumpCode[i], mipsr4k.pc + (int)i * sizeof(u32_le));
}
Module *module = new Module;
kernelObjects.Create(module);
loadedModules.insert(module->GetUID());
memset(&module->nm, 0, sizeof(module->nm));
module->isFake = true;
module->nm.entry_addr = mipsr4k.pc;
module->nm.gp_value = -1;
SceUID threadID = __KernelSetupRootThread(module->GetUID(), (int)base_filename.size(), base_filename.data(), 0x20, 0x1000, 0);
__KernelSetThreadRA(threadID, NID_MODULERETURN);
__KernelStartIdleThreads(module->GetUID());
return true;
}
void __KernelGPUReplay() {
// Special ABI: s0 and s1 are the "args". Not null terminated.
const char *filenamep = Memory::GetCharPointer(currentMIPS->r[MIPS_REG_S1]);
if (!filenamep) {
ERROR_LOG(SYSTEM, "Failed to load dump filename");
Core_Stop();
return;
}
std::string filename(filenamep, currentMIPS->r[MIPS_REG_S0]);
if (!GPURecord::RunMountedReplay(filename)) {
Core_Stop();
}
}
int sceKernelLoadExec(const char *filename, u32 paramPtr)
{
std::string exec_filename = filename;

View file

@ -39,7 +39,9 @@ void __KernelModuleDoState(PointerWrap &p);
void __KernelModuleShutdown();
u32 __KernelGetModuleGP(SceUID module);
bool __KernelLoadGEDump(const std::string &base_filename, std::string *error_string);
bool __KernelLoadExec(const char *filename, u32 paramPtr, std::string *error_string);
void __KernelGPUReplay();
void __KernelReturnFromModuleFunc();
u32 hleKernelStopUnloadSelfModuleWithOrWithoutStatus(u32 exitCode, u32 argSize, u32 argp, u32 statusAddr, u32 optionAddr, bool WithStatus);

View file

@ -69,31 +69,30 @@ IdentifiedFileType Identify_File(FileLoader *fileLoader) {
}
std::string extension = fileLoader->Extension();
if (!strcasecmp(extension.c_str(), ".iso"))
{
if (!strcasecmp(extension.c_str(), ".iso")) {
// may be a psx iso, they have 2352 byte sectors. You never know what some people try to open
if ((fileLoader->FileSize() % 2352) == 0)
{
if ((fileLoader->FileSize() % 2352) == 0) {
unsigned char sync[12];
fileLoader->ReadAt(0, 12, sync);
// each sector in a mode2 image starts with these 12 bytes
if (memcmp(sync,"\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00",12) == 0)
{
if (memcmp(sync,"\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00", 12) == 0) {
return IdentifiedFileType::ISO_MODE2;
}
// maybe it also just happened to have that size,
}
return IdentifiedFileType::PSP_ISO;
}
else if (!strcasecmp(extension.c_str(),".cso"))
{
} else if (!strcasecmp(extension.c_str(), ".cso")) {
return IdentifiedFileType::PSP_ISO;
}
else if (!strcasecmp(extension.c_str(),".ppst"))
{
} else if (!strcasecmp(extension.c_str(), ".ppst")) {
return IdentifiedFileType::PPSSPP_SAVESTATE;
} else if (!strcasecmp(extension.c_str(), ".ppdmp")) {
char data[8]{};
fileLoader->ReadAt(0, 8, data);
if (memcmp(data, "PPSSPPGE", 8) == 0) {
return IdentifiedFileType::PPSSPP_GE_DUMP;
}
}
// First, check if it's a directory with an EBOOT.PBP in it.
@ -337,6 +336,9 @@ bool LoadFile(FileLoader **fileLoaderPtr, std::string *error_string) {
*error_string = "This is save data, not a game."; // Actually, we could make it load it...
break;
case IdentifiedFileType::PPSSPP_GE_DUMP:
return Load_PSP_GE_Dump(fileLoader, error_string);
case IdentifiedFileType::UNKNOWN_BIN:
case IdentifiedFileType::UNKNOWN_ELF:
case IdentifiedFileType::UNKNOWN:

View file

@ -49,6 +49,8 @@ enum class IdentifiedFileType {
PSP_SAVEDATA_DIRECTORY,
PPSSPP_SAVESTATE,
PPSSPP_GE_DUMP,
UNKNOWN,
};

View file

@ -612,6 +612,11 @@ void ArmJit::Comp_Syscall(MIPSOpcode op)
RestoreRoundingMode();
js.downcountAmount = -offset;
if (!js.inDelaySlot) {
gpr.SetRegImm(SCRATCHREG1, GetCompilerPC() + 4);
MovToPC(SCRATCHREG1);
}
FlushAll();
SaveDowncount();

View file

@ -594,6 +594,11 @@ void Arm64Jit::Comp_Syscall(MIPSOpcode op)
RestoreRoundingMode();
js.downcountAmount = -offset;
if (!js.inDelaySlot) {
gpr.SetRegImm(SCRATCH1, GetCompilerPC() + 4);
MovToPC(SCRATCH1);
}
FlushAll();
SaveStaticRegisters();

View file

@ -380,6 +380,11 @@ void IRFrontend::Comp_Syscall(MIPSOpcode op) {
ir.Write(IROp::Downcount, 0, dcAmount & 0xFF, dcAmount >> 8);
js.downcountAmount = 0;
// If not in a delay slot, we need to update PC.
if (!js.inDelaySlot) {
ir.Write(IROp::SetPCConst, 0, ir.AddConstant(GetCompilerPC() + 4));
}
FlushAll();
RestoreRoundingMode();

View file

@ -787,6 +787,10 @@ void Jit::Comp_Syscall(MIPSOpcode op)
RestoreRoundingMode();
js.downcountAmount = -offset;
if (!js.inDelaySlot) {
MOV(32, M(&mips_->pc), Imm32(GetCompilerPC() + 4));
}
#ifdef USE_PROFILER
// When profiling, we can't skip CallSyscall, since it times syscalls.
ABI_CallFunctionC(&CallSyscall, op.encoding);

View file

@ -27,11 +27,12 @@
#include "Core/ELF/ElfReader.h"
#include "Core/ELF/ParamSFO.h"
#include "FileSystems/BlockDevices.h"
#include "FileSystems/DirectoryFileSystem.h"
#include "FileSystems/ISOFileSystem.h"
#include "FileSystems/MetaFileSystem.h"
#include "FileSystems/VirtualDiscFileSystem.h"
#include "Core/FileSystems/BlockDevices.h"
#include "Core/FileSystems/BlobFileSystem.h"
#include "Core/FileSystems/DirectoryFileSystem.h"
#include "Core/FileSystems/ISOFileSystem.h"
#include "Core/FileSystems/MetaFileSystem.h"
#include "Core/FileSystems/VirtualDiscFileSystem.h"
#include "Core/Loaders.h"
#include "Core/MemMap.h"
@ -355,3 +356,11 @@ bool Load_PSP_ELF_PBP(FileLoader *fileLoader, std::string *error_string) {
return __KernelLoadExec(finalName.c_str(), 0, error_string);
}
bool Load_PSP_GE_Dump(FileLoader *fileLoader, std::string *error_string) {
BlobFileSystem *umd = new BlobFileSystem(&pspFileSystem, fileLoader, "data.ppdmp");
pspFileSystem.Mount("disc0:", umd);
__KernelLoadGEDump("disc0:/data.ppdmp", error_string);
return true;
}

View file

@ -23,5 +23,6 @@ class FileLoader;
bool Load_PSP_ISO(FileLoader *fileLoader, std::string *error_string);
bool Load_PSP_ELF_PBP(FileLoader *fileLoader, std::string *error_string);
bool Load_PSP_GE_Dump(FileLoader *fileLoader, std::string *error_string);
void InitMemoryForGameISO(FileLoader *fileLoader);
void InitMemoryForGamePBP(FileLoader *fileLoader);

View file

@ -242,10 +242,7 @@ void CPU_Init() {
// Here we have read the PARAM.SFO, let's see if we need any compatibility overrides.
// Homebrew usually has an empty discID, and even if they do have a disc id, it's not
// likely to collide with any commercial ones.
std::string discID = g_paramSFO.GetValueString("DISC_ID");
if (discID.empty()) {
discID = g_paramSFO.GenerateFakeID();
}
std::string discID = g_paramSFO.GetDiscID();
coreParameter.compat.Load(discID);
Memory::Init();

View file

@ -47,10 +47,7 @@ void TextureReplacer::Init() {
}
void TextureReplacer::NotifyConfigChanged() {
gameID_ = g_paramSFO.GetValueString("DISC_ID");
if (gameID_.empty()) {
gameID_ = g_paramSFO.GenerateFakeID();
}
gameID_ = g_paramSFO.GetDiscID();
enabled_ = g_Config.bReplaceTextures || g_Config.bSaveNewTextures;
if (enabled_) {

View file

@ -119,10 +119,6 @@ FramebufferManagerCommon::~FramebufferManagerCommon() {
}
void FramebufferManagerCommon::Init() {
std::string gameId = g_paramSFO.GetValueString("DISC_ID");
if (gameId.empty()) {
gameId = g_paramSFO.GenerateFakeID();
}
BeginFrame();
}

View file

@ -480,8 +480,8 @@ class VertexDecoder {
public:
VertexDecoder();
// A jit cache is not mandatory, we don't use it in the sw renderer
void SetVertexType(u32 vtype, const VertexDecoderOptions &options, VertexDecoderJitCache *jitCache = 0);
// A jit cache is not mandatory.
void SetVertexType(u32 vtype, const VertexDecoderOptions &options, VertexDecoderJitCache *jitCache = nullptr);
u32 VertexType() const { return fmt_; }

View file

@ -293,10 +293,6 @@ void GPU_D3D11::InitClearInternal() {
}
}
void GPU_D3D11::DumpNextFrame() {
dumpNextFrame_ = true;
}
void GPU_D3D11::BeginHostFrame() {
GPUCommon::BeginHostFrame();
UpdateCmdInfo();
@ -309,11 +305,6 @@ void GPU_D3D11::BeginHostFrame() {
}
}
void GPU_D3D11::BeginFrame() {
ScheduleEvent(GPU_EVENT_BEGIN_FRAME);
gstate_c.Dirty(DIRTY_PROJTHROUGHMATRIX);
}
void GPU_D3D11::ReapplyGfxStateInternal() {
GPUCommon::ReapplyGfxStateInternal();
@ -331,16 +322,11 @@ void GPU_D3D11::BeginFrameInternal() {
depalShaderCache_->Decimate();
// fragmentTestCache_.Decimate();
if (dumpNextFrame_) {
NOTICE_LOG(G3D, "DUMPING THIS FRAME");
dumpThisFrame_ = true;
dumpNextFrame_ = false;
} else if (dumpThisFrame_) {
dumpThisFrame_ = false;
}
GPUCommon::BeginFrameInternal();
shaderManagerD3D11_->DirtyLastShader();
framebufferManagerD3D11_->BeginFrame();
gstate_c.Dirty(DIRTY_PROJTHROUGHMATRIX);
}
void GPU_D3D11::SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format) {

View file

@ -42,13 +42,11 @@ public:
void ReapplyGfxStateInternal() override;
void SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format) override;
void BeginFrame() override;
void GetStats(char *buffer, size_t bufsize) override;
void ClearCacheNextFrame() override;
void DeviceLost() override; // Only happens on Android. Drop all textures and shaders.
void DeviceRestore() override;
void DumpNextFrame() override;
void DoState(PointerWrap &p) override;
void ClearShaderCache() override;
@ -122,4 +120,4 @@ private:
std::string reportingPrimaryInfo_;
std::string reportingFullInfo_;
};
};

1037
GPU/Debugger/Record.cpp Normal file

File diff suppressed because it is too large Load diff

36
GPU/Debugger/Record.h Normal file
View file

@ -0,0 +1,36 @@
// Copyright (c) 2017- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#pragma once
#include <string>
#include "Common/CommonTypes.h"
namespace GPURecord {
bool IsActive();
void Activate();
void NotifyCommand(u32 pc);
void NotifyMemcpy(u32 dest, u32 src, u32 sz);
void NotifyMemset(u32 dest, int v, u32 sz);
void NotifyUpload(u32 dest, u32 sz);
void NotifyFrame();
bool RunMountedReplay(const std::string &filename);
};

View file

@ -260,10 +260,6 @@ void GPU_DX9::InitClearInternal() {
}
}
void GPU_DX9::DumpNextFrame() {
dumpNextFrame_ = true;
}
void GPU_DX9::BeginHostFrame() {
GPUCommon::BeginHostFrame();
UpdateCmdInfo();
@ -276,10 +272,6 @@ void GPU_DX9::BeginHostFrame() {
}
}
void GPU_DX9::BeginFrame() {
ScheduleEvent(GPU_EVENT_BEGIN_FRAME);
}
void GPU_DX9::ReapplyGfxStateInternal() {
dxstate.Restore();
GPUCommon::ReapplyGfxStateInternal();
@ -300,13 +292,7 @@ void GPU_DX9::BeginFrameInternal() {
depalShaderCache_.Decimate();
// fragmentTestCache_.Decimate();
if (dumpNextFrame_) {
NOTICE_LOG(G3D, "DUMPING THIS FRAME");
dumpThisFrame_ = true;
dumpNextFrame_ = false;
} else if (dumpThisFrame_) {
dumpThisFrame_ = false;
}
GPUCommon::BeginFrameInternal();
shaderManagerDX9_->DirtyShader();
framebufferManagerDX9_->BeginFrame();

View file

@ -43,13 +43,11 @@ public:
void ReapplyGfxStateInternal() override;
void SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format) override;
void BeginFrame() override;
void GetStats(char *buffer, size_t bufsize) override;
void ClearCacheNextFrame() override;
void DeviceLost() override; // Only happens on Android. Drop all textures and shaders.
void DeviceRestore() override;
void DumpNextFrame() override;
void DoState(PointerWrap &p) override;
void ClearShaderCache() override;

View file

@ -168,10 +168,7 @@ GPU_GLES::GPU_GLES(GraphicsContext *gfxCtx, Draw::DrawContext *draw)
textureCacheGL_->NotifyConfigChanged();
// Load shader cache.
std::string discID = g_paramSFO.GetValueString("DISC_ID");
if (discID.empty()) {
discID = g_paramSFO.GenerateFakeID();
}
std::string discID = g_paramSFO.GetDiscID();
if (discID.size()) {
File::CreateFullPath(GetSysDirectory(DIRECTORY_APP_CACHE));
shaderCachePath_ = GetSysDirectory(DIRECTORY_APP_CACHE) + "/" + discID + ".glshadercache";
@ -422,10 +419,6 @@ void GPU_GLES::InitClearInternal() {
glstate.viewport.set(0, 0, PSP_CoreParameter().pixelWidth, PSP_CoreParameter().pixelHeight);
}
void GPU_GLES::DumpNextFrame() {
dumpNextFrame_ = true;
}
void GPU_GLES::BeginHostFrame() {
GPUCommon::BeginHostFrame();
UpdateCmdInfo();
@ -438,10 +431,6 @@ void GPU_GLES::BeginHostFrame() {
}
}
void GPU_GLES::BeginFrame() {
ScheduleEvent(GPU_EVENT_BEGIN_FRAME);
}
inline void GPU_GLES::UpdateVsyncInterval(bool force) {
#ifdef _WIN32
int desiredVSyncInterval = g_Config.bVSync ? 1 : 0;
@ -495,13 +484,7 @@ void GPU_GLES::BeginFrameInternal() {
depalShaderCache_.Decimate();
fragmentTestCache_.Decimate();
if (dumpNextFrame_) {
NOTICE_LOG(G3D, "DUMPING THIS FRAME");
dumpThisFrame_ = true;
dumpNextFrame_ = false;
} else if (dumpThisFrame_) {
dumpThisFrame_ = false;
}
GPUCommon::BeginFrameInternal();
// Save the cache from time to time. TODO: How often?
if (!shaderCachePath_.empty() && (gpuStats.numFlips & 1023) == 0) {

View file

@ -43,14 +43,12 @@ public:
void ReapplyGfxStateInternal() override;
void SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format) override;
void BeginFrame() override;
void GetStats(char *buffer, size_t bufsize) override;
void ClearCacheNextFrame() override;
void DeviceLost() override; // Only happens on Android. Drop all textures and shaders.
void DeviceRestore() override;
void DumpNextFrame() override;
void DoState(PointerWrap &p) override;
void ClearShaderCache() override;

View file

@ -218,6 +218,7 @@
<ClInclude Include="D3D11\TextureScalerD3D11.h" />
<ClInclude Include="D3D11\VertexShaderGeneratorD3D11.h" />
<ClInclude Include="Debugger\Breakpoints.h" />
<ClInclude Include="Debugger\Record.h" />
<ClInclude Include="Debugger\Stepping.h" />
<ClInclude Include="Directx9\DepalettizeShaderDX9.h" />
<ClInclude Include="Directx9\GPU_DX9.h" />
@ -318,6 +319,7 @@
<ClCompile Include="D3D11\TextureScalerD3D11.cpp" />
<ClCompile Include="D3D11\VertexShaderGeneratorD3D11.cpp" />
<ClCompile Include="Debugger\Breakpoints.cpp" />
<ClCompile Include="Debugger\Record.cpp" />
<ClCompile Include="Debugger\Stepping.cpp" />
<ClCompile Include="Directx9\DepalettizeShaderDX9.cpp" />
<ClCompile Include="Directx9\GPU_DX9.cpp" />

View file

@ -262,6 +262,9 @@
<ClInclude Include="Software\Sampler.h">
<Filter>Software</Filter>
</ClInclude>
<ClInclude Include="Debugger\Record.h">
<Filter>Debugger</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Math3D.cpp">
@ -519,5 +522,8 @@
<ClCompile Include="Software\SamplerX86.cpp">
<Filter>Software</Filter>
</ClCompile>
<ClCompile Include="Debugger\Record.cpp">
<Filter>Debugger</Filter>
</ClCompile>
</ItemGroup>
</Project>

View file

@ -25,6 +25,7 @@
#include "GPU/Common/FramebufferCommon.h"
#include "GPU/Common/TextureCacheCommon.h"
#include "GPU/Common/DrawEngineCommon.h"
#include "GPU/Debugger/Record.h"
const CommonCommandTableEntry commonCommandTable[] = {
// From Common. No flushing but definitely need execute.
@ -461,6 +462,10 @@ void GPUCommon::Resized() {
resized_ = true;
}
void GPUCommon::DumpNextFrame() {
dumpNextFrame_ = true;
}
u32 GPUCommon::DrawSync(int mode) {
if (ThreadEnabled()) {
// Sync first, because the CPU is usually faster than the emulated GPU.
@ -898,7 +903,8 @@ bool GPUCommon::InterpretList(DisplayList &list) {
gpuState = list.pc == list.stall ? GPUSTATE_STALL : GPUSTATE_RUNNING;
guard.unlock();
const bool useDebugger = host->GPUDebuggingActive();
debugRecording_ = GPURecord::IsActive();
const bool useDebugger = host->GPUDebuggingActive() || debugRecording_;
const bool useFastRunLoop = !dumpThisFrame_ && !useDebugger;
while (gpuState == GPUSTATE_RUNNING) {
{
@ -945,12 +951,28 @@ bool GPUCommon::InterpretList(DisplayList &list) {
return gpuState == GPUSTATE_DONE || gpuState == GPUSTATE_ERROR;
}
void GPUCommon::BeginFrame() {
ScheduleEvent(GPU_EVENT_BEGIN_FRAME);
}
void GPUCommon::BeginFrameInternal() {
if (dumpNextFrame_) {
NOTICE_LOG(G3D, "DUMPING THIS FRAME");
dumpThisFrame_ = true;
dumpNextFrame_ = false;
} else if (dumpThisFrame_) {
dumpThisFrame_ = false;
}
GPURecord::NotifyFrame();
}
void GPUCommon::SlowRunLoop(DisplayList &list)
{
const bool dumpThisFrame = dumpThisFrame_;
while (downcount > 0)
{
host->GPUNotifyCommand(list.pc);
GPURecord::NotifyCommand(list.pc);
u32 op = Memory::ReadUnchecked_U32(list.pc);
u32 cmd = op >> 24;
@ -1197,13 +1219,16 @@ void GPUCommon::Execute_Call(u32 op, u32 diff) {
#endif
// Bone matrix optimization - many games will CALL a bone matrix (!).
if ((Memory::ReadUnchecked_U32(target) >> 24) == GE_CMD_BONEMATRIXDATA) {
// We don't optimize during recording - so the matrix data gets recorded.
if (!debugRecording_ && (Memory::ReadUnchecked_U32(target) >> 24) == GE_CMD_BONEMATRIXDATA) {
// Check for the end
if ((Memory::ReadUnchecked_U32(target + 11 * 4) >> 24) == GE_CMD_BONEMATRIXDATA &&
(Memory::ReadUnchecked_U32(target + 12 * 4) >> 24) == GE_CMD_RET) {
// Yep, pretty sure this is a bone matrix call.
FastLoadBoneMatrix(target);
return;
// Yep, pretty sure this is a bone matrix call. Double check stall first.
if (target > currentList->stall || target + 12 * 4 < currentList->stall) {
FastLoadBoneMatrix(target);
return;
}
}
}
@ -1553,15 +1578,23 @@ void GPUCommon::Execute_WorldMtxNum(u32 op, u32 diff) {
const int end = 12 - (op & 0xF);
int i = 0;
while ((src[i] >> 24) == GE_CMD_WORLDMATRIXDATA) {
const u32 newVal = src[i] << 8;
if (dst[i] != newVal) {
Flush();
dst[i] = newVal;
gstate_c.Dirty(DIRTY_WORLDMATRIX);
}
if (++i >= end) {
break;
// We must record the individual data commands while debugRecording_.
bool fastLoad = !debugRecording_;
if (currentList->pc < currentList->stall && currentList->pc + end * 4 >= currentList->stall) {
fastLoad = false;
}
if (fastLoad) {
while ((src[i] >> 24) == GE_CMD_WORLDMATRIXDATA) {
const u32 newVal = src[i] << 8;
if (dst[i] != newVal) {
Flush();
dst[i] = newVal;
gstate_c.Dirty(DIRTY_WORLDMATRIX);
}
if (++i >= end) {
break;
}
}
}
@ -1594,15 +1627,22 @@ void GPUCommon::Execute_ViewMtxNum(u32 op, u32 diff) {
const int end = 12 - (op & 0xF);
int i = 0;
while ((src[i] >> 24) == GE_CMD_VIEWMATRIXDATA) {
const u32 newVal = src[i] << 8;
if (dst[i] != newVal) {
Flush();
dst[i] = newVal;
gstate_c.Dirty(DIRTY_VIEWMATRIX);
}
if (++i >= end) {
break;
bool fastLoad = !debugRecording_;
if (currentList->pc < currentList->stall && currentList->pc + end * 4 >= currentList->stall) {
fastLoad = false;
}
if (fastLoad) {
while ((src[i] >> 24) == GE_CMD_VIEWMATRIXDATA) {
const u32 newVal = src[i] << 8;
if (dst[i] != newVal) {
Flush();
dst[i] = newVal;
gstate_c.Dirty(DIRTY_VIEWMATRIX);
}
if (++i >= end) {
break;
}
}
}
@ -1635,15 +1675,22 @@ void GPUCommon::Execute_ProjMtxNum(u32 op, u32 diff) {
const int end = 16 - (op & 0xF);
int i = 0;
while ((src[i] >> 24) == GE_CMD_PROJMATRIXDATA) {
const u32 newVal = src[i] << 8;
if (dst[i] != newVal) {
Flush();
dst[i] = newVal;
gstate_c.Dirty(DIRTY_PROJMATRIX);
}
if (++i >= end) {
break;
bool fastLoad = !debugRecording_;
if (currentList->pc < currentList->stall && currentList->pc + end * 4 >= currentList->stall) {
fastLoad = false;
}
if (fastLoad) {
while ((src[i] >> 24) == GE_CMD_PROJMATRIXDATA) {
const u32 newVal = src[i] << 8;
if (dst[i] != newVal) {
Flush();
dst[i] = newVal;
gstate_c.Dirty(DIRTY_PROJMATRIX);
}
if (++i >= end) {
break;
}
}
}
@ -1677,15 +1724,22 @@ void GPUCommon::Execute_TgenMtxNum(u32 op, u32 diff) {
const int end = 12 - (op & 0xF);
int i = 0;
while ((src[i] >> 24) == GE_CMD_TGENMATRIXDATA) {
const u32 newVal = src[i] << 8;
if (dst[i] != newVal) {
Flush();
dst[i] = newVal;
gstate_c.Dirty(DIRTY_TEXMATRIX);
}
if (++i >= end) {
break;
bool fastLoad = !debugRecording_;
if (currentList->pc < currentList->stall && currentList->pc + end * 4 >= currentList->stall) {
fastLoad = false;
}
if (fastLoad) {
while ((src[i] >> 24) == GE_CMD_TGENMATRIXDATA) {
const u32 newVal = src[i] << 8;
if (dst[i] != newVal) {
Flush();
dst[i] = newVal;
gstate_c.Dirty(DIRTY_TEXMATRIX);
}
if (++i >= end) {
break;
}
}
}
@ -1718,34 +1772,41 @@ void GPUCommon::Execute_BoneMtxNum(u32 op, u32 diff) {
const int end = 12 * 8 - (op & 0x7F);
int i = 0;
// If we can't use software skinning, we have to flush and dirty.
if (!g_Config.bSoftwareSkinning || (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) != 0) {
while ((src[i] >> 24) == GE_CMD_BONEMATRIXDATA) {
const u32 newVal = src[i] << 8;
if (dst[i] != newVal) {
Flush();
dst[i] = newVal;
}
if (++i >= end) {
break;
}
}
bool fastLoad = !debugRecording_;
if (currentList->pc < currentList->stall && currentList->pc + end * 4 >= currentList->stall) {
fastLoad = false;
}
const int numPlusCount = (op & 0x7F) + i;
for (int num = op & 0x7F; num < numPlusCount; num += 12) {
gstate_c.Dirty(DIRTY_BONEMATRIX0 << (num / 12));
}
} else {
while ((src[i] >> 24) == GE_CMD_BONEMATRIXDATA) {
dst[i] = src[i] << 8;
if (++i >= end) {
break;
if (fastLoad) {
// If we can't use software skinning, we have to flush and dirty.
if (!g_Config.bSoftwareSkinning || (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) != 0) {
while ((src[i] >> 24) == GE_CMD_BONEMATRIXDATA) {
const u32 newVal = src[i] << 8;
if (dst[i] != newVal) {
Flush();
dst[i] = newVal;
}
if (++i >= end) {
break;
}
}
}
const int numPlusCount = (op & 0x7F) + i;
for (int num = op & 0x7F; num < numPlusCount; num += 12) {
gstate_c.deferredVertTypeDirty |= DIRTY_BONEMATRIX0 << (num / 12);
const int numPlusCount = (op & 0x7F) + i;
for (int num = op & 0x7F; num < numPlusCount; num += 12) {
gstate_c.Dirty(DIRTY_BONEMATRIX0 << (num / 12));
}
} else {
while ((src[i] >> 24) == GE_CMD_BONEMATRIXDATA) {
dst[i] = src[i] << 8;
if (++i >= end) {
break;
}
}
const int numPlusCount = (op & 0x7F) + i;
for (int num = op & 0x7F; num < numPlusCount; num += 12) {
gstate_c.deferredVertTypeDirty |= DIRTY_BONEMATRIX0 << (num / 12);
}
}
}
@ -2330,6 +2391,7 @@ bool GPUCommon::PerformMemoryCopy(u32 dest, u32 src, int size) {
}
InvalidateCache(dest, size, GPU_INVALIDATE_HINT);
GPURecord::NotifyMemcpy(dest, src, size);
return false;
}
@ -2354,6 +2416,7 @@ bool GPUCommon::PerformMemorySet(u32 dest, u8 v, int size) {
// Or perhaps a texture, let's invalidate.
InvalidateCache(dest, size, GPU_INVALIDATE_HINT);
GPURecord::NotifyMemset(dest, v, size);
return false;
}
@ -2370,6 +2433,7 @@ bool GPUCommon::PerformMemoryUpload(u32 dest, int size) {
// Cheat a bit to force an upload of the framebuffer.
// VRAM + 0x00400000 is simply a VRAM mirror.
if (Memory::IsVRAMAddress(dest)) {
GPURecord::NotifyUpload(dest, size);
return PerformMemoryCopy(dest, dest ^ 0x00400000, size);
}
return false;

View file

@ -61,6 +61,7 @@ public:
}
void Resized() override;
void DumpNextFrame() override;
void ExecuteOp(u32 op, u32 diff) override;
void PreExecuteOp(u32 op, u32 diff) override;
@ -202,7 +203,7 @@ public:
const std::list<int>& GetDisplayLists() override {
return dlQueue;
}
virtual bool DecodeTexture(u8* dest, const GPUgstate &state) override {
bool DecodeTexture(u8* dest, const GPUgstate &state) override {
return false;
}
std::vector<FramebufferInfo> GetFramebufferList() override {
@ -211,6 +212,13 @@ public:
void ClearShaderCache() override {}
void CleanupBeforeUI() override {}
s64 GetListTicks(int listid) override {
if (listid >= 0 && listid < DisplayListMaxCount) {
return dls[listid].waitTicks;
}
return -1;
}
std::vector<std::string> DebugGetShaderIDs(DebugShaderType shader) override { return std::vector<std::string>(); };
std::string DebugGetShaderString(std::string id, DebugShaderType shader, DebugShaderStringType stringType) override {
return "N/A";
@ -227,7 +235,8 @@ protected:
}
virtual void InitClearInternal() {}
virtual void BeginFrameInternal() {}
void BeginFrame() override;
virtual void BeginFrameInternal();
virtual void CopyDisplayToOutputInternal() {}
virtual void ReinitializeInternal() {}
@ -329,6 +338,7 @@ protected:
bool dumpNextFrame_;
bool dumpThisFrame_;
bool debugRecording_;
bool interruptsEnabled_;
bool resized_;
DrawType lastDraw_;

View file

@ -299,6 +299,7 @@ public:
virtual const std::list<int>& GetDisplayLists() = 0;
virtual bool DecodeTexture(u8* dest, const GPUgstate &state) = 0;
virtual std::vector<FramebufferInfo> GetFramebufferList() = 0;
virtual s64 GetListTicks(int listid) = 0;
// For debugging. The IDs returned are opaque, do not poke in them or display them in any way.
virtual std::vector<std::string> DebugGetShaderIDs(DebugShaderType type) = 0;

View file

@ -29,7 +29,6 @@ public:
void InitClear() override {}
void ExecuteOp(u32 op, u32 diff) override;
void BeginFrame() override {}
void SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format) override {}
void CopyDisplayToOutput() override {}
void GetStats(char *buffer, size_t bufsize) override;

View file

@ -37,6 +37,7 @@
#include "GPU/Software/TransformUnit.h"
#include "GPU/Common/DrawEngineCommon.h"
#include "GPU/Common/FramebufferCommon.h"
#include "GPU/Debugger/Record.h"
const int FB_WIDTH = 480;
const int FB_HEIGHT = 272;
@ -876,6 +877,7 @@ bool SoftGPU::PerformMemoryCopy(u32 dest, u32 src, int size)
{
// Nothing to update.
InvalidateCache(dest, size, GPU_INVALIDATE_HINT);
GPURecord::NotifyMemcpy(dest, src, size);
// Let's just be safe.
framebufferDirty_ = true;
return false;
@ -885,6 +887,7 @@ bool SoftGPU::PerformMemorySet(u32 dest, u8 v, int size)
{
// Nothing to update.
InvalidateCache(dest, size, GPU_INVALIDATE_HINT);
GPURecord::NotifyMemset(dest, v, size);
// Let's just be safe.
framebufferDirty_ = true;
return false;
@ -901,6 +904,7 @@ bool SoftGPU::PerformMemoryUpload(u32 dest, int size)
{
// Nothing to update.
InvalidateCache(dest, size, GPU_INVALIDATE_HINT);
GPURecord::NotifyUpload(dest, size);
return false;
}

View file

@ -55,7 +55,6 @@ public:
void InitClear() override {}
void ExecuteOp(u32 op, u32 diff) override;
void BeginFrame() override {}
void SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format) override;
void CopyDisplayToOutput() override;
void GetStats(char *buffer, size_t bufsize) override;
@ -70,7 +69,6 @@ public:
void DeviceLost() override;
void DeviceRestore() override;
void DumpNextFrame() override {}
void Resized() override {}
void GetReportingInfo(std::string &primaryInfo, std::string &fullInfo) override {

View file

@ -329,14 +329,6 @@ void GPU_Vulkan::InitClearInternal() {
}
}
void GPU_Vulkan::DumpNextFrame() {
dumpNextFrame_ = true;
}
void GPU_Vulkan::BeginFrame() {
ScheduleEvent(GPU_EVENT_BEGIN_FRAME);
}
void GPU_Vulkan::UpdateVsyncInterval(bool force) {
// TODO
}
@ -351,9 +343,6 @@ void GPU_Vulkan::UpdateCmdInfo() {
}
}
void GPU_Vulkan::BeginFrameInternal() {
}
void GPU_Vulkan::SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format) {
host->GPUNotifyDisplay(framebuf, stride, format);
framebufferManager_->SetDisplayFramebuffer(framebuf, stride, format);

View file

@ -46,13 +46,11 @@ public:
void ExecuteOp(u32 op, u32 diff) override;
void SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format) override;
void BeginFrame() override;
void GetStats(char *buffer, size_t bufsize) override;
void ClearCacheNextFrame() override;
void DeviceLost() override; // Only happens on Android. Drop all textures and shaders.
void DeviceRestore() override;
void DumpNextFrame() override;
void DoState(PointerWrap &p) override;
void ClearShaderCache() override;
@ -102,7 +100,6 @@ private:
void CheckFlushOp(int cmd, u32 diff);
void BuildReportingInfo();
void InitClearInternal() override;
void BeginFrameInternal() override;
void CopyDisplayToOutputInternal() override;
void ReinitializeInternal() override;
inline void UpdateVsyncInterval(bool force);

View file

@ -1336,10 +1336,7 @@ UI::EventReturn DeveloperToolsScreen::OnLoadLanguageIni(UI::EventParams &e) {
}
UI::EventReturn DeveloperToolsScreen::OnOpenTexturesIniFile(UI::EventParams &e) {
std::string gameID = g_paramSFO.GetValueString("DISC_ID");
if (gameID.empty()) {
gameID = g_paramSFO.GenerateFakeID();
}
std::string gameID = g_paramSFO.GetDiscID();
std::string texturesDirectory = GetSysDirectory(DIRECTORY_TEXTURES) + gameID + "/";
bool enabled_ = !gameID.empty();
if (enabled_) {

View file

@ -713,10 +713,7 @@ void TakeScreenshot() {
// First, find a free filename.
int i = 0;
std::string gameId = g_paramSFO.GetValueString("DISC_ID");
if (gameId.empty()) {
gameId = g_paramSFO.GenerateFakeID();
}
std::string gameId = g_paramSFO.GetDiscID();
char filename[2048];
while (i < 10000){

View file

@ -320,10 +320,7 @@ void GamePauseScreen::CreateViews() {
root_->SetDefaultFocusView(continueChoice);
continueChoice->OnClick.Handle<UIScreen>(this, &UIScreen::OnBack);
std::string gameId = g_paramSFO.GetValueString("DISC_ID");
if (gameId.empty()) {
gameId = g_paramSFO.GenerateFakeID();
}
std::string gameId = g_paramSFO.GetDiscID();
if (g_Config.hasGameConfig(gameId)) {
rightColumnItems->Add(new Choice(pa->T("Game Settings")))->OnClick.Handle(this, &GamePauseScreen::OnGameSettings);
rightColumnItems->Add(new Choice(pa->T("Delete Game Config")))->OnClick.Handle(this, &GamePauseScreen::OnDeleteConfig);
@ -424,10 +421,7 @@ void GamePauseScreen::CallbackDeleteConfig(bool yes)
UI::EventReturn GamePauseScreen::OnCreateConfig(UI::EventParams &e)
{
std::string gameId = g_paramSFO.GetValueString("DISC_ID");
if (gameId.empty()) {
gameId = g_paramSFO.GenerateFakeID();
}
std::string gameId = g_paramSFO.GetDiscID();
g_Config.createGameConfig(gameId);
g_Config.changeGameSpecific(gameId);
g_Config.saveGameConfig(gameId);

View file

@ -330,6 +330,7 @@
<ClInclude Include="..\..\Core\FileLoaders\LocalFileLoader.h" />
<ClInclude Include="..\..\Core\FileLoaders\RamCachingFileLoader.h" />
<ClInclude Include="..\..\Core\FileLoaders\RetryingFileLoader.h" />
<ClInclude Include="..\..\Core\FileSystems\BlobFileSystem.h" />
<ClInclude Include="..\..\Core\FileSystems\BlockDevices.h" />
<ClInclude Include="..\..\Core\FileSystems\DirectoryFileSystem.h" />
<ClInclude Include="..\..\Core\FileSystems\FileSystem.h" />
@ -521,6 +522,7 @@
<ClCompile Include="..\..\Core\FileLoaders\LocalFileLoader.cpp" />
<ClCompile Include="..\..\Core\FileLoaders\RamCachingFileLoader.cpp" />
<ClCompile Include="..\..\Core\FileLoaders\RetryingFileLoader.cpp" />
<ClCompile Include="..\..\Core\FileSystems\BlobFileSystem.cpp" />
<ClCompile Include="..\..\Core\FileSystems\BlockDevices.cpp" />
<ClCompile Include="..\..\Core\FileSystems\DirectoryFileSystem.cpp" />
<ClCompile Include="..\..\Core\FileSystems\FileSystem.cpp" />

View file

@ -166,6 +166,9 @@
<ClCompile Include="..\..\Core\MIPS\x86\RegCacheFPU.cpp">
<Filter>MIPS\x86</Filter>
</ClCompile>
<ClCompile Include="..\..\Core\FileSystems\BlobFileSystem.cpp">
<Filter>FileSystems</Filter>
</ClCompile>
<ClCompile Include="..\..\Core\FileSystems\BlockDevices.cpp">
<Filter>FileSystems</Filter>
</ClCompile>
@ -674,6 +677,9 @@
<ClInclude Include="..\..\Core\MIPS\x86\RegCacheFPU.h">
<Filter>MIPS\x86</Filter>
</ClInclude>
<ClInclude Include="..\..\Core\FileSystems\BlobFileSystem.h">
<Filter>FileSystems</Filter>
</ClInclude>
<ClInclude Include="..\..\Core\FileSystems\BlockDevices.h">
<Filter>FileSystems</Filter>
</ClInclude>

View file

@ -36,6 +36,7 @@
#include "GPU/Common/GPUStateUtils.h"
#include "GPU/GPUState.h"
#include "GPU/Debugger/Breakpoints.h"
#include "GPU/Debugger/Record.h"
#include "GPU/Debugger/Stepping.h"
#include "Core/Config.h"
#include <windowsx.h>
@ -706,6 +707,10 @@ BOOL CGEDebugger::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) {
breakNext = BREAK_NONE;
break;
case IDC_GEDBG_RECORD:
GPURecord::Activate();
break;
case IDC_GEDBG_FORCEOPAQUE:
if (attached && gpuDebug != nullptr) {
forceOpaque_ = SendMessage(GetDlgItem(m_hDlg, IDC_GEDBG_FORCEOPAQUE), BM_GETCHECK, 0, 0) != 0;

View file

@ -176,6 +176,7 @@ BEGIN
PUSHBUTTON "Step &Prim",IDC_GEDBG_STEPPRIM,166,2,48,14
PUSHBUTTON "Step &Into",IDC_GEDBG_STEP,218,2,48,14
PUSHBUTTON "&Resume",IDC_GEDBG_RESUME,270,2,48,14
PUSHBUTTON "Rec&ord",IDC_GEDBG_RECORD,440,2,48,14
CONTROL "",IDC_GEDBG_TEX,"SimpleGLWindow",WS_CHILD | WS_VISIBLE,10,20,128,128
CONTROL "",IDC_GEDBG_FRAME,"SimpleGLWindow",WS_CHILD | WS_VISIBLE,148,20,256,136
CONTROL "",IDC_GEDBG_MAINTAB,"SysTabControl32",TCS_TABS | TCS_FOCUSNEVER,10,216,480,180

View file

@ -333,6 +333,7 @@
#define ID_FILE_USEFFV1 40166
#define ID_FILE_DUMPAUDIO 40167
#define ID_HELP_GITHUB 40168
#define IDC_GEDBG_RECORD 40169
// Dummy option to let the buffered rendering hotkey cycle through all the options.
#define ID_OPTIONS_BUFFEREDRENDERINGDUMMY 40500

View file

@ -229,6 +229,7 @@ EXEC_AND_LIB_FILES := \
$(SRC)/GPU/Common/PostShader.cpp \
$(SRC)/GPU/Common/ShaderUniforms.cpp \
$(SRC)/GPU/Debugger/Breakpoints.cpp \
$(SRC)/GPU/Debugger/Record.cpp \
$(SRC)/GPU/Debugger/Stepping.cpp \
$(SRC)/GPU/GLES/FramebufferManagerGLES.cpp \
$(SRC)/GPU/GLES/DepalettizeShaderGLES.cpp \
@ -363,6 +364,7 @@ EXEC_AND_LIB_FILES := \
$(SRC)/Core/HLE/sceGameUpdate.cpp \
$(SRC)/Core/HLE/sceNp.cpp \
$(SRC)/Core/HLE/scePauth.cpp \
$(SRC)/Core/FileSystems/BlobFileSystem.cpp \
$(SRC)/Core/FileSystems/BlockDevices.cpp \
$(SRC)/Core/FileSystems/ISOFileSystem.cpp \
$(SRC)/Core/FileSystems/FileSystem.cpp \