mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-01 14:58:14 +00:00
Merge pull request #21148 from hrydgard/more-misc
Add workaround for infamous GoW crash
This commit is contained in:
8 files changed
+97
-54
No files matched your search
@@ -154,6 +154,7 @@ void Compatibility::CheckSettings(IniFile &iniFile, const std::string &gameID) {
|
||||
CheckSetting(iniFile, gameID, "SaveStatesNotRecommended", &flags_.SaveStatesNotRecommended);
|
||||
CheckSetting(iniFile, gameID, "IgnoreEnqueue", &flags_.IgnoreEnqueue);
|
||||
CheckSetting(iniFile, gameID, "MsgDialogAutoStatus", &flags_.MsgDialogAutoStatus);
|
||||
CheckSetting(iniFile, gameID, "NullPageValid", &flags_.NullPageValid);
|
||||
}
|
||||
|
||||
void Compatibility::CheckVRSettings(IniFile &iniFile, const std::string &gameID) {
|
||||
|
||||
@@ -117,6 +117,7 @@ struct CompatFlags {
|
||||
bool SaveStatesNotRecommended;
|
||||
bool IgnoreEnqueue;
|
||||
bool MsgDialogAutoStatus;
|
||||
bool NullPageValid;
|
||||
};
|
||||
|
||||
struct VRCompat {
|
||||
|
||||
+42
-30
@@ -50,6 +50,7 @@ u8* base = nullptr;
|
||||
MemArena g_arena;
|
||||
// ==============
|
||||
|
||||
u8 *m_pNullPage;
|
||||
u8 *m_pPhysicalScratchPad;
|
||||
u8 *m_pUncachedScratchPad;
|
||||
// 64-bit: Pointers to high-mem mirrors
|
||||
@@ -67,8 +68,8 @@ u8 *m_pUncachedKernelRAM[3];
|
||||
// since when we write to the depth buffer (like with the depth rasterizer or the software renderer)
|
||||
// we write unswizzled data anyway. There are some exceptions, Silent Hill abuses the swizzling in ways that break
|
||||
// our software renderer.
|
||||
u8 *m_pPhysicalVRAM[4];
|
||||
u8 *m_pUncachedVRAM[4];
|
||||
static u8 *m_pPhysicalVRAM[4];
|
||||
static u8 *m_pUncachedVRAM[4];
|
||||
|
||||
// Holds the ending address of the PSP's user space.
|
||||
// Required for HD Remasters to work properly.
|
||||
@@ -77,11 +78,13 @@ u32 g_MemorySize;
|
||||
// Used to store the PSP model on game startup.
|
||||
u32 g_PSPModel;
|
||||
|
||||
static MemMapSetupFlags g_setupFlags;
|
||||
|
||||
std::recursive_mutex g_shutdownLock;
|
||||
|
||||
// We don't declare the IO region in here since its handled by other means.
|
||||
static MemoryView views[] =
|
||||
{
|
||||
static MemoryView views[] = {
|
||||
{&m_pNullPage, 0x00000000, 0x00010000, MV_NULL_PAGE}, // Null page, usually not enabled. Only used for working around some race condition bugs.
|
||||
{&m_pPhysicalScratchPad, 0x00010000, SCRATCHPAD_SIZE, 0},
|
||||
{&m_pUncachedScratchPad, 0x40010000, SCRATCHPAD_SIZE, MV_MIRROR_PREVIOUS},
|
||||
{&m_pPhysicalVRAM[0], 0x04000000, 0x00200000, 0},
|
||||
@@ -111,8 +114,6 @@ static MemoryView views[] =
|
||||
// implement those.
|
||||
};
|
||||
|
||||
static const int num_views = sizeof(views) / sizeof(MemoryView);
|
||||
|
||||
inline static bool CanIgnoreView(const MemoryView &view) {
|
||||
#ifdef MASKED_PSP_MEMORY
|
||||
// Basically, 32-bit platforms can ignore views that are masked out anyway.
|
||||
@@ -122,16 +123,19 @@ inline static bool CanIgnoreView(const MemoryView &view) {
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool SkipView(MemMapSetupFlags flags, u32 viewFlags) {
|
||||
#if PPSSPP_PLATFORM(IOS) && PPSSPP_ARCH(64BIT)
|
||||
#define SKIP(a_flags, b_flags) \
|
||||
if ((b_flags) & MV_KERNEL) \
|
||||
continue;
|
||||
#else
|
||||
#define SKIP(a_flags, b_flags) \
|
||||
;
|
||||
// We use a limited memory map on iOS with masking, we don't need to allocate the kernel space views.
|
||||
if (viewFlags & MV_KERNEL) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
if ((viewFlags & MV_NULL_PAGE) && !(flags & MemMapSetupFlags::AllocNullPage))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool Memory_TryBase(u32 flags) {
|
||||
static bool Memory_TryBase(MemMapSetupFlags flags) {
|
||||
// OK, we know where to find free space. Now grab it!
|
||||
// We just mimic the popular BAT setup.
|
||||
|
||||
@@ -139,17 +143,19 @@ static bool Memory_TryBase(u32 flags) {
|
||||
size_t last_position = 0;
|
||||
|
||||
// Zero all the pointers to be sure.
|
||||
for (int i = 0; i < num_views; i++) {
|
||||
if (views[i].out_ptr)
|
||||
for (int i = 0; i < ARRAY_SIZE(views); i++) {
|
||||
if (views[i].out_ptr) {
|
||||
*views[i].out_ptr = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int i;
|
||||
for (i = 0; i < num_views; i++) {
|
||||
int i; // the final values is used in the next loop
|
||||
for (i = 0; i < ARRAY_SIZE(views); i++) {
|
||||
const MemoryView &view = views[i];
|
||||
if (view.size == 0)
|
||||
continue;
|
||||
SKIP(flags, view.flags);
|
||||
if (SkipView(flags, view.flags))
|
||||
continue;
|
||||
|
||||
if (view.flags & MV_MIRROR_PREVIOUS) {
|
||||
position = last_position;
|
||||
@@ -184,7 +190,8 @@ bail:
|
||||
for (int j = 0; j <= i; j++) {
|
||||
if (views[i].size == 0)
|
||||
continue;
|
||||
SKIP(flags, views[i].flags);
|
||||
if (SkipView(flags, views[i].flags))
|
||||
continue;
|
||||
if (views[j].out_ptr && *views[j].out_ptr) {
|
||||
if (!CanIgnoreView(views[j])) {
|
||||
g_arena.ReleaseView(0, *views[j].out_ptr, views[j].size);
|
||||
@@ -195,7 +202,8 @@ bail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MemoryMap_Setup(u32 flags) {
|
||||
bool MemoryMap_Setup(MemMapSetupFlags flags) {
|
||||
g_setupFlags = flags;
|
||||
#if PPSSPP_PLATFORM(UWP)
|
||||
// We reserve the memory, then simply commit in TryBase.
|
||||
base = (u8*)VirtualAllocFromApp(0, 0x10000000, MEM_RESERVE, PAGE_READWRITE);
|
||||
@@ -203,10 +211,11 @@ bool MemoryMap_Setup(u32 flags) {
|
||||
|
||||
// Figure out how much memory we need to allocate in total.
|
||||
size_t total_mem = 0;
|
||||
for (int i = 0; i < num_views; i++) {
|
||||
for (int i = 0; i < ARRAY_SIZE(views); i++) {
|
||||
if (views[i].size == 0)
|
||||
continue;
|
||||
SKIP(flags, views[i].flags);
|
||||
if (SkipView(flags, views[i].flags))
|
||||
continue;
|
||||
if (!CanIgnoreView(views[i]))
|
||||
total_mem += g_arena.roundup(views[i].size);
|
||||
}
|
||||
@@ -264,15 +273,18 @@ bool MemoryMap_Setup(u32 flags) {
|
||||
return Memory_TryBase(flags);
|
||||
}
|
||||
|
||||
void MemoryMap_Shutdown(u32 flags) {
|
||||
void MemoryMap_Shutdown() {
|
||||
size_t position = 0;
|
||||
size_t last_position = 0;
|
||||
const MemMapSetupFlags flags = g_setupFlags;
|
||||
g_setupFlags = MemMapSetupFlags::Default;
|
||||
|
||||
for (int i = 0; i < num_views; i++) {
|
||||
for (int i = 0; i < ARRAY_SIZE(views); i++) {
|
||||
if (views[i].size == 0)
|
||||
continue;
|
||||
SKIP(flags, views[i].flags);
|
||||
|
||||
if (SkipView(flags, views[i].flags))
|
||||
continue;
|
||||
|
||||
if (views[i].flags & MV_MIRROR_PREVIOUS) {
|
||||
position = last_position;
|
||||
}
|
||||
@@ -291,7 +303,7 @@ void MemoryMap_Shutdown(u32 flags) {
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Init() {
|
||||
bool Init(MemMapSetupFlags flags) {
|
||||
// On some 32 bit platforms (like Android, iOS, etc.), you can only map < 32 megs at a time.
|
||||
const static int MAX_MMAP_SIZE = 31 * 1024 * 1024;
|
||||
_dbg_assert_msg_(g_MemorySize <= MAX_MMAP_SIZE * 3, "ACK - too much memory for three mmap views.");
|
||||
@@ -304,7 +316,6 @@ bool Init() {
|
||||
views[i].size = std::min(std::max((int)g_MemorySize - MAX_MMAP_SIZE * 2, 0), MAX_MMAP_SIZE);
|
||||
}
|
||||
|
||||
int flags = 0;
|
||||
if (!MemoryMap_Setup(flags)) {
|
||||
return false;
|
||||
}
|
||||
@@ -319,8 +330,9 @@ bool Init() {
|
||||
void Reinit() {
|
||||
_assert_msg_(PSP_GetBootState() == BootState::Complete, "Cannot reinit during startup/shutdown");
|
||||
Core_NotifyLifecycle(CoreLifecycle::MEMORY_REINITING);
|
||||
MemMapSetupFlags flags = g_setupFlags;
|
||||
Shutdown();
|
||||
Init();
|
||||
Init(flags);
|
||||
Core_NotifyLifecycle(CoreLifecycle::MEMORY_REINITED);
|
||||
}
|
||||
|
||||
@@ -398,7 +410,7 @@ void DoState(PointerWrap &p) {
|
||||
void Shutdown() {
|
||||
std::lock_guard<std::recursive_mutex> guard(g_shutdownLock);
|
||||
u32 flags = 0;
|
||||
MemoryMap_Shutdown(flags);
|
||||
MemoryMap_Shutdown();
|
||||
base = nullptr;
|
||||
DEBUG_LOG(Log::MemMap, "Memory system shut down.");
|
||||
}
|
||||
|
||||
+12
-10
@@ -25,6 +25,7 @@
|
||||
#include <stddef.h>
|
||||
#endif
|
||||
|
||||
#include "Common/Common.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/Swap.h"
|
||||
#include "Core/Opcode.h"
|
||||
@@ -71,8 +72,7 @@ extern u32 g_PSPModel;
|
||||
#define MASKED_PSP_MEMORY
|
||||
#endif
|
||||
|
||||
enum
|
||||
{
|
||||
enum {
|
||||
// This may be adjusted by remaster games.
|
||||
RAM_NORMAL_SIZE = 0x02000000,
|
||||
// Used if the PSP model is PSP-2000 (Slim).
|
||||
@@ -93,26 +93,28 @@ enum {
|
||||
MV_IS_PRIMARY_RAM = 0x100,
|
||||
MV_IS_EXTRA1_RAM = 0x200,
|
||||
MV_IS_EXTRA2_RAM = 0x400,
|
||||
MV_KERNEL = 0x800 // Can be skipped on platforms where memory is tight.
|
||||
MV_KERNEL = 0x800, // Can be skipped on platforms where memory is tight.
|
||||
MV_NULL_PAGE = 0x1000,
|
||||
};
|
||||
|
||||
struct MemoryView
|
||||
{
|
||||
struct MemoryView {
|
||||
u8 **out_ptr;
|
||||
u32 virtual_address;
|
||||
u32 size;
|
||||
u32 flags;
|
||||
};
|
||||
|
||||
// Uses a memory arena to set up an emulator-friendly memory map
|
||||
bool MemoryMap_Setup(u32 flags);
|
||||
void MemoryMap_Shutdown(u32 flags);
|
||||
enum class MemMapSetupFlags {
|
||||
Default = 0,
|
||||
AllocNullPage = 1,
|
||||
};
|
||||
ENUM_CLASS_BITOPS(MemMapSetupFlags);
|
||||
|
||||
// Init and Shutdown
|
||||
bool Init();
|
||||
bool Init(MemMapSetupFlags flags);
|
||||
void Shutdown();
|
||||
void DoState(PointerWrap &p);
|
||||
void Clear();
|
||||
|
||||
// False when shutdown has already been called.
|
||||
bool IsActive();
|
||||
|
||||
|
||||
+6
-1
@@ -365,8 +365,13 @@ static bool CPU_Init(FileLoader *fileLoader, IdentifiedFileType type, std::strin
|
||||
HLEPlugins::Init();
|
||||
}
|
||||
|
||||
Memory::MemMapSetupFlags memMapFlags = Memory::MemMapSetupFlags::Default;
|
||||
if (g_CoreParameter.compat.flags().NullPageValid) {
|
||||
memMapFlags = Memory::MemMapSetupFlags::AllocNullPage;
|
||||
}
|
||||
|
||||
// Initialize the memory map as early as possible (now that we've read the PARAM.SFO).
|
||||
if (!Memory::Init()) {
|
||||
if (!Memory::Init(memMapFlags)) {
|
||||
// We're screwed.
|
||||
*errorString = "Memory init failed";
|
||||
return false;
|
||||
|
||||
+16
-12
@@ -179,7 +179,7 @@ void ScreenshotViewScreen::OnDeleteState(UI::EventParams &e) {
|
||||
|
||||
// TODO: Also show the screenshot on the confirmation screen?
|
||||
|
||||
screenManager()->push(new UI::MessagePopupScreen(title, message, di->T("Delete"), di->T("Cancel"), [=](bool result) {
|
||||
screenManager()->push(new UI::MessagePopupScreen(title, message, di->T("Delete"), di->T("Cancel"), [this](bool result) {
|
||||
if (result) {
|
||||
SaveState::DeleteSlot(saveStatePrefix_, slot_);
|
||||
TriggerFinish(DR_CANCEL);
|
||||
@@ -588,7 +588,7 @@ void GamePauseScreen::CreateViews() {
|
||||
|
||||
rightColumnItems->SetSpacing(0.0f);
|
||||
if (getUMDReplacePermit()) {
|
||||
rightColumnItems->Add(new Choice(pa->T("Switch UMD"), ImageID("I_UMD")))->OnClick.Add([=](UI::EventParams &) {
|
||||
rightColumnItems->Add(new Choice(pa->T("Switch UMD"), ImageID("I_UMD")))->OnClick.Add([this](UI::EventParams &) {
|
||||
screenManager()->push(new UmdReplaceScreen());
|
||||
});
|
||||
}
|
||||
@@ -616,22 +616,22 @@ void GamePauseScreen::CreateViews() {
|
||||
}
|
||||
|
||||
if (g_Config.bAchievementsEnable && Achievements::HasAchievementsOrLeaderboards()) {
|
||||
rightColumnItems->Add(new Choice(ac->T("Achievements"), ImageID("I_ACHIEVEMENT")))->OnClick.Add([&](UI::EventParams &e) {
|
||||
rightColumnItems->Add(new Choice(ac->T("Achievements"), ImageID("I_ACHIEVEMENT")))->OnClick.Add([this](UI::EventParams &e) {
|
||||
screenManager()->push(new RetroAchievementsListScreen(gamePath_));
|
||||
});
|
||||
}
|
||||
|
||||
rightColumnItems->Add(new Choice(gr->T("Display layout & effects"), ImageID("I_DISPLAY")))->OnClick.Add([&](UI::EventParams &) -> void {
|
||||
rightColumnItems->Add(new Choice(gr->T("Display layout & effects"), ImageID("I_DISPLAY")))->OnClick.Add([this](UI::EventParams &) -> void {
|
||||
screenManager()->push(new DisplayLayoutScreen(gamePath_));
|
||||
});
|
||||
if (g_Config.bShowTouchControls) {
|
||||
rightColumnItems->Add(new Choice(co->T("Edit touch control layout..."), ImageID("I_CONTROLLER")))->OnClick.Add([&](UI::EventParams &) -> void {
|
||||
rightColumnItems->Add(new Choice(co->T("Edit touch control layout..."), ImageID("I_CONTROLLER")))->OnClick.Add([this](UI::EventParams &) -> void {
|
||||
screenManager()->push(new TouchControlLayoutScreen(gamePath_));
|
||||
});
|
||||
}
|
||||
|
||||
if (g_Config.bEnableCheats && PSP_CoreParameter().fileType != IdentifiedFileType::PPSSPP_GE_DUMP) {
|
||||
rightColumnItems->Add(new Choice(pa->T("Cheats"), ImageID("I_CHEAT")))->OnClick.Add([&](UI::EventParams &e) {
|
||||
rightColumnItems->Add(new Choice(pa->T("Cheats"), ImageID("I_CHEAT")))->OnClick.Add([this](UI::EventParams &e) {
|
||||
screenManager()->push(new CwCheatScreen(gamePath_));
|
||||
});
|
||||
}
|
||||
@@ -668,9 +668,9 @@ void GamePauseScreen::CreateViews() {
|
||||
exit->SetEnabled(!bootPending_);
|
||||
|
||||
if (middleColumn) {
|
||||
middleColumn->SetSpacing(portrait ? 8.0f : 20.0f);
|
||||
middleColumn->SetSpacing(portrait ? 8.0f : 0.0f);
|
||||
playButton_ = middleColumn->Add(new Choice(g_Config.bRunBehindPauseMenu ? ImageID("I_PAUSE") : ImageID("I_PLAY"), new LinearLayoutParams(64, 64)));
|
||||
playButton_->OnClick.Add([=](UI::EventParams &e) {
|
||||
playButton_->OnClick.Add([this](UI::EventParams &e) {
|
||||
g_Config.bRunBehindPauseMenu = !g_Config.bRunBehindPauseMenu;
|
||||
playButton_->SetIconLeft(g_Config.bRunBehindPauseMenu ? ImageID("I_PAUSE") : ImageID("I_PLAY"));
|
||||
});
|
||||
@@ -678,12 +678,16 @@ void GamePauseScreen::CreateViews() {
|
||||
bool mustRunBehind = MustRunBehind();
|
||||
playButton_->SetVisibility(mustRunBehind ? UI::V_GONE : UI::V_VISIBLE);
|
||||
|
||||
if (!portrait) {
|
||||
middleColumn->Add(new Spacer(20.0f));
|
||||
}
|
||||
|
||||
Choice *infoButton = middleColumn->Add(new Choice(ImageID("I_INFO"), new LinearLayoutParams(64, 64)));
|
||||
infoButton->OnClick.Add([=](UI::EventParams &e) {
|
||||
infoButton->OnClick.Add([this](UI::EventParams &e) {
|
||||
screenManager()->push(new GameScreen(gamePath_, true));
|
||||
});
|
||||
|
||||
if (true || System_GetPropertyInt(SYSPROP_DEVICE_TYPE) == DEVICE_TYPE_MOBILE) {
|
||||
if (System_GetPropertyInt(SYSPROP_DEVICE_TYPE) == DEVICE_TYPE_MOBILE) {
|
||||
AddRotationPicker(screenManager(), middleColumn, false);
|
||||
}
|
||||
|
||||
@@ -706,7 +710,7 @@ void GamePauseScreen::ShowContextMenu(UI::View *menuButton, bool portrait) {
|
||||
std::string confirmMessage = GetConfirmExitMessage();
|
||||
if (!confirmMessage.empty()) {
|
||||
auto di = GetI18NCategory(I18NCat::DIALOG);
|
||||
screenManager()->push(new UI::MessagePopupScreen(di->T("Reset"), confirmMessage, di->T("Reset"), di->T("Cancel"), [=](bool result) {
|
||||
screenManager()->push(new UI::MessagePopupScreen(di->T("Reset"), confirmMessage, di->T("Reset"), di->T("Cancel"), [this](bool result) {
|
||||
if (result) {
|
||||
System_PostUIMessage(UIMessage::REQUEST_GAME_RESET);
|
||||
}
|
||||
@@ -802,7 +806,7 @@ void GamePauseScreen::OnExit(UI::EventParams &e) {
|
||||
if (!confirmExitMessage.empty()) {
|
||||
auto di = GetI18NCategory(I18NCat::DIALOG);
|
||||
std::string_view title = di->T("Are you sure you want to exit?");
|
||||
screenManager()->push(new UI::MessagePopupScreen(title, confirmExitMessage, di->T("Exit"), di->T("Cancel"), [=](bool result) {
|
||||
screenManager()->push(new UI::MessagePopupScreen(title, confirmExitMessage, di->T("Exit"), di->T("Cancel"), [this](bool result) {
|
||||
if (result) {
|
||||
if (g_Config.bPauseMenuExitsEmulator) {
|
||||
System_ExitApp();
|
||||
|
||||
@@ -2088,3 +2088,21 @@ ULUS10077 = true
|
||||
# Ghost Recon - Predator. See #20856
|
||||
ULUS10445 = true
|
||||
ULES01350 = True
|
||||
|
||||
[NullPageValid]
|
||||
# Works around crashes in some games (such as GoW: GoS, see issue #14958) that access invalid memory pages, by mapping some extra memory at address 0.
|
||||
# GOW : Ghost of Sparta
|
||||
UCUS98737 = true
|
||||
UCAS40323 = true
|
||||
NPHG00092 = true
|
||||
NPEG00044 = true
|
||||
NPEG00045 = true
|
||||
NPJG00120 = true
|
||||
NPUG80508 = true
|
||||
UCJS10114 = true
|
||||
UCES01401 = true
|
||||
UCES01473 = true
|
||||
# GOW : Ghost of Sparta Demo
|
||||
NPJG90095 = true
|
||||
NPEG90035 = true
|
||||
NPUG70125 = true
|
||||
@@ -107,7 +107,7 @@ static void SetupJitHarness() {
|
||||
PSP_CoreParameter().cpuCore = CPUCore::INTERPRETER;
|
||||
PSP_CoreParameter().fastForward = true;
|
||||
|
||||
Memory::Init();
|
||||
Memory::Init(Memory::MemMapSetupFlags::Default);
|
||||
mipsr4k.Reset();
|
||||
CoreTiming::Init();
|
||||
InitVFPU();
|
||||
|
||||
Reference in new issue
Block a user