mirror of
https://github.com/OpenEmu/PCSX2-Core.git
synced 2025-11-01 11:07:36 +00:00
Almost got it linking...
This commit is contained in:
+18
-29
@@ -38,10 +38,10 @@
|
||||
#include "VMManager.h"
|
||||
//#include "AppConfig.h"
|
||||
#include "Frontend/InputManager.h"
|
||||
#include "Frontend/INISettingsInterface.h"
|
||||
#include "pcsx2/INISettingsInterface.h"
|
||||
#include "Frontend/OpenGLHostDisplay.h"
|
||||
#include "common/SettingsWrapper.h"
|
||||
#include "CDVD/CDVDaccess.h"
|
||||
#include "CDVD/CDVD.h"
|
||||
#include "SPU2/Global.h"
|
||||
#include "SPU2/SndOut.h"
|
||||
#include "PAD/Host/KeyStatus.h"
|
||||
@@ -84,7 +84,6 @@ PCSX2GameCore *_current;
|
||||
NSString* DiscSubRegion;
|
||||
|
||||
std::unique_ptr<INISettingsInterface> s_base_settings_interface;
|
||||
std::unique_ptr<HostDisplay> hostDisplay;
|
||||
|
||||
VMBootParameters params;
|
||||
|
||||
@@ -186,10 +185,10 @@ static NSString *binCueFix(NSString *path)
|
||||
s_base_settings_interface = std::make_unique<INISettingsInterface>(std::move(pcsx2ini));
|
||||
Host::Internal::SetBaseSettingsLayer(s_base_settings_interface.get());
|
||||
|
||||
EmuConfig = Pcsx2Config();
|
||||
EmuFolders::SetDefaults();
|
||||
|
||||
SettingsInterface& si = *s_base_settings_interface.get();
|
||||
EmuConfig = Pcsx2Config();
|
||||
EmuFolders::SetDefaults(si);
|
||||
|
||||
si.SetUIntValue("UI", "SettingsVersion", 1);
|
||||
|
||||
{
|
||||
@@ -301,16 +300,12 @@ static NSString *binCueFix(NSString *path)
|
||||
params.fullscreen = false;
|
||||
|
||||
if(!hasInitialized){
|
||||
hostDisplay = HostDisplay::CreateDisplayForAPI(OpenGLHostDisplay::RenderAPI::OpenGL);
|
||||
g_host_display = HostDisplay::CreateForAPI(RenderAPI::OpenGL);
|
||||
WindowInfo wi;
|
||||
wi.type = WindowInfo::Type::MacOS;
|
||||
wi.surface_width = screenRect.size.width ;
|
||||
wi.surface_height = screenRect.size.height ;
|
||||
hostDisplay->CreateRenderDevice(wi,
|
||||
Host::GetStringSettingValue("EmuCore/GS", "Adapter", ""),
|
||||
VsyncMode::Adaptive,
|
||||
Host::GetBoolSettingValue("EmuCore/GS", "ThreadedPresentation", false),
|
||||
Host::GetBoolSettingValue("EmuCore/GS", "UseDebugDevice", false));
|
||||
g_host_display->CreateDevice(wi, VsyncMode::Adaptive);
|
||||
|
||||
|
||||
if(VMManager::Initialize(params)){
|
||||
@@ -731,11 +726,12 @@ void Host::OnSaveStateSaved(const std::string_view& filename)
|
||||
{
|
||||
}
|
||||
|
||||
void Host::OnGameChanged(const std::string& disc_path, const std::string& game_serial, const std::string& game_name, u32 game_crc)
|
||||
void Host::OnGameChanged(const std::string& disc_path, const std::string& elf_override, const std::string& game_serial,
|
||||
const std::string& game_name, u32 game_crc)
|
||||
{
|
||||
}
|
||||
|
||||
void Host::PumpMessagesOnCPUThread()
|
||||
void Host::CPUThreadVSync()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -753,41 +749,34 @@ void Host::RunOnCPUThread(std::function<void()> function, bool block)
|
||||
|
||||
#pragma mark Host Display
|
||||
|
||||
HostDisplay* Host::AcquireHostDisplay(HostDisplay::RenderAPI api)
|
||||
bool Host::AcquireHostDisplay(RenderAPI api, bool clear_state_on_fail)
|
||||
{
|
||||
GET_CURRENT_OR_RETURN(nullptr);
|
||||
GET_CURRENT_OR_RETURN(false);
|
||||
|
||||
[current.renderDelegate willRenderFrameOnAlternateThread];
|
||||
return current->hostDisplay.get();
|
||||
return g_host_display.get();
|
||||
}
|
||||
|
||||
void Host::ReleaseHostDisplay()
|
||||
void Host::ReleaseHostDisplay(bool clear_state)
|
||||
{
|
||||
GET_CURRENT_OR_RETURN();
|
||||
if(current->hostDisplay.get()){
|
||||
current->hostDisplay.reset();
|
||||
if(g_host_display.get()){
|
||||
g_host_display.reset();
|
||||
}
|
||||
}
|
||||
|
||||
HostDisplay* Host::GetHostDisplay()
|
||||
{
|
||||
GET_CURRENT_OR_RETURN(nullptr);
|
||||
|
||||
return current->hostDisplay.get();
|
||||
}
|
||||
|
||||
bool Host::BeginPresentFrame(bool frame_skip)
|
||||
{
|
||||
GET_CURRENT_OR_RETURN(false);
|
||||
|
||||
return current->hostDisplay.get()->BeginPresent(frame_skip);
|
||||
return g_host_display.get()->BeginPresent(frame_skip);
|
||||
}
|
||||
|
||||
void Host::EndPresentFrame()
|
||||
{
|
||||
GET_CURRENT_OR_RETURN();
|
||||
|
||||
current->hostDisplay.get()->EndPresent();
|
||||
g_host_display.get()->EndPresent();
|
||||
}
|
||||
|
||||
int Host::PresentFrameBuffer()
|
||||
|
||||
+145
-101
@@ -40,15 +40,13 @@
|
||||
#include "GS.h"
|
||||
#include "GS/GS.h"
|
||||
#include "SPU2/spu2.h"
|
||||
#include "USB/USB.h"
|
||||
#include "StateWrapper.h"
|
||||
#include "PAD/Gamepad.h"
|
||||
|
||||
#ifndef PCSX2_CORE
|
||||
#include "gui/App.h"
|
||||
#include "gui/ConsoleLogger.h"
|
||||
#include "gui/SysThreads.h"
|
||||
#else
|
||||
#include "USB/USB.h"
|
||||
#include "VMManager.h"
|
||||
|
||||
#ifdef ENABLE_ACHIEVEMENTS
|
||||
#include "Frontend/Achievements.h"
|
||||
#endif
|
||||
|
||||
#include "fmt/core.h"
|
||||
@@ -58,23 +56,37 @@
|
||||
|
||||
using namespace R5900;
|
||||
|
||||
static tlbs s_tlb_backup[std::size(tlb)];
|
||||
|
||||
static void PreLoadPrep()
|
||||
{
|
||||
// ensure everything is in sync before we start overwriting stuff.
|
||||
if (THREAD_VU1)
|
||||
vu1Thread.WaitVU();
|
||||
GetMTGS().WaitGS(false);
|
||||
|
||||
// backup current TLBs, since we're going to overwrite them all
|
||||
std::memcpy(s_tlb_backup, tlb, sizeof(s_tlb_backup));
|
||||
|
||||
// clear protected pages, since we don't want to fault loading EE memory
|
||||
mmap_ResetBlockTracking();
|
||||
|
||||
SysClearExecutionCache();
|
||||
#ifndef PCSX2_CORE
|
||||
PatchesVerboseReset();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void PostLoadPrep()
|
||||
{
|
||||
resetCache();
|
||||
// WriteCP0Status(cpuRegs.CP0.n.Status.val);
|
||||
for(int i=0; i<48; i++) MapTLB(i);
|
||||
for (int i = 0; i < 48; i++)
|
||||
{
|
||||
if (std::memcmp(&s_tlb_backup[i], &tlb[i], sizeof(tlbs)) != 0)
|
||||
{
|
||||
UnmapTLB(s_tlb_backup[i], i);
|
||||
MapTLB(tlb[i], i);
|
||||
}
|
||||
}
|
||||
|
||||
if (EmuConfig.Gamefixes.GoemonTlbHack) GoemonPreloadTlb();
|
||||
CBreakPoints::SetSkipFirst(BREAKPOINT_EE, 0);
|
||||
CBreakPoints::SetSkipFirst(BREAKPOINT_IOP, 0);
|
||||
@@ -85,55 +97,6 @@ static void PostLoadPrep()
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SaveStateBase (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
#ifndef PCSX2_CORE
|
||||
std::string SaveStateBase::GetSavestateFolder(int slot, bool isSavingOrLoading)
|
||||
{
|
||||
std::string CRCvalue(StringUtil::StdStringFromFormat("%08X", ElfCRC));
|
||||
std::string serialName;
|
||||
|
||||
if (g_GameStarted || g_GameLoading)
|
||||
{
|
||||
if (DiscSerial.empty())
|
||||
{
|
||||
// Running homebrew/standalone ELF, return only the ELF name.
|
||||
// can't use FileSystem here because it's DOS paths
|
||||
const std::string::size_type pos = std::min(DiscSerial.rfind('/'), DiscSerial.rfind('\\'));
|
||||
if (pos != std::string::npos)
|
||||
serialName = DiscSerial.substr(pos + 1);
|
||||
else
|
||||
serialName = DiscSerial;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Running a normal retail game
|
||||
// Folder format is "SLXX-XXXX - (00000000)"
|
||||
serialName = DiscSerial;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Still inside the BIOS/not running a game (why would anyone want to do this?)
|
||||
serialName = StringUtil::StdStringFromFormat("BIOS (%s v%u.%u)", BiosZone.c_str(), (BiosVersion >> 8), BiosVersion & 0xff);
|
||||
CRCvalue = "None";
|
||||
}
|
||||
|
||||
const std::string dir(StringUtil::StdStringFromFormat("%s" FS_OSPATH_SEPARATOR_STR "%s - (%s)",
|
||||
g_Conf->Folders.Savestates.ToUTF8().data(), serialName.c_str(), CRCvalue.c_str()));
|
||||
|
||||
if (isSavingOrLoading)
|
||||
{
|
||||
if (!FileSystem::DirectoryExists(dir.c_str()))
|
||||
{
|
||||
// sstates should exist, no need to create it
|
||||
FileSystem::CreateDirectoryPath(dir.c_str(), false);
|
||||
}
|
||||
}
|
||||
|
||||
return Path::Combine(dir, StringUtil::StdStringFromFormat("%s (%s).%02d.p2s",
|
||||
serialName.c_str(), CRCvalue.c_str(), slot));
|
||||
}
|
||||
#endif
|
||||
|
||||
SaveStateBase::SaveStateBase( SafeArray<u8>& memblock )
|
||||
{
|
||||
Init( &memblock );
|
||||
@@ -189,12 +152,12 @@ SaveStateBase& SaveStateBase::FreezeBios()
|
||||
// Check the BIOS, and issue a warning if the bios for this state
|
||||
// doesn't match the bios currently being used (chances are it'll still
|
||||
// work fine, but some games are very picky).
|
||||
|
||||
|
||||
u32 bioscheck = BiosChecksum;
|
||||
char biosdesc[256];
|
||||
memzero( biosdesc );
|
||||
memcpy( biosdesc, BiosDescription.c_str(), std::min( sizeof(biosdesc), BiosDescription.length() ) );
|
||||
|
||||
|
||||
Freeze( bioscheck );
|
||||
Freeze( biosdesc );
|
||||
|
||||
@@ -209,15 +172,17 @@ SaveStateBase& SaveStateBase::FreezeBios()
|
||||
biosdesc, bioscheck
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
SaveStateBase& SaveStateBase::FreezeInternals()
|
||||
{
|
||||
const u32 previousCRC = ElfCRC;
|
||||
|
||||
// Print this until the MTVU problem in gifPathFreeze is taken care of (rama)
|
||||
if (THREAD_VU1) Console.Warning("MTVU speedhack is enabled, saved states may not be stable");
|
||||
|
||||
|
||||
// Second Block - Various CPU Registers and States
|
||||
// -----------------------------------------------
|
||||
FreezeTag( "cpuRegs" );
|
||||
@@ -235,19 +200,27 @@ SaveStateBase& SaveStateBase::FreezeInternals()
|
||||
StringUtil::Strlcpy(localDiscSerial, DiscSerial.c_str(), sizeof(localDiscSerial));
|
||||
Freeze(localDiscSerial);
|
||||
if (IsLoading())
|
||||
{
|
||||
DiscSerial = localDiscSerial;
|
||||
|
||||
if (ElfCRC != previousCRC)
|
||||
{
|
||||
// HACK: LastELF isn't in the save state... Load it before we go too far into restoring state.
|
||||
// When we next bump save states, we should include it. We need this for achievements, because
|
||||
// we want to load and activate achievements before restoring any of their tracked state.
|
||||
if (const std::string& elf_override = VMManager::Internal::GetElfOverride(); !elf_override.empty())
|
||||
cdvdReloadElfInfo(fmt::format("host:{}", elf_override));
|
||||
else
|
||||
cdvdReloadElfInfo();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Third Block - Cycle Timers and Events
|
||||
// -------------------------------------
|
||||
FreezeTag( "Cycles" );
|
||||
Freeze(EEsCycle);
|
||||
Freeze(EEoCycle);
|
||||
Freeze(iopCycleEE);
|
||||
Freeze(iopBreak);
|
||||
Freeze(g_nextEventCycle);
|
||||
Freeze(g_iopNextEventCycle);
|
||||
Freeze(s_iLastCOP0Cycle);
|
||||
Freeze(s_iLastPERFCycle);
|
||||
Freeze(nextCounter);
|
||||
Freeze(nextsCounter);
|
||||
Freeze(psxNextsCounter);
|
||||
@@ -376,20 +349,13 @@ struct SysState_Component
|
||||
|
||||
static int SysState_MTGSFreeze(FreezeAction mode, freezeData* fP)
|
||||
{
|
||||
#ifndef PCSX2_CORE
|
||||
ScopedCoreThreadPause paused_core;
|
||||
#endif
|
||||
MTGS_FreezeData sstate = { fP, 0 };
|
||||
GetMTGS().Freeze(mode, sstate);
|
||||
#ifndef PCSX2_CORE
|
||||
paused_core.AllowResume();
|
||||
#endif
|
||||
return sstate.retval;
|
||||
}
|
||||
|
||||
static constexpr SysState_Component SPU2{ "SPU2", SPU2freeze };
|
||||
static constexpr SysState_Component PAD_{ "PAD", PADfreeze };
|
||||
static constexpr SysState_Component USB{ "USB", USBfreeze };
|
||||
static constexpr SysState_Component GS{ "GS", SysState_MTGSFreeze };
|
||||
|
||||
|
||||
@@ -409,6 +375,9 @@ static void SysState_ComponentFreezeOutRoot(void* dest, SysState_Component comp)
|
||||
|
||||
static void SysState_ComponentFreezeIn(zip_file_t* zf, SysState_Component comp)
|
||||
{
|
||||
if (!zf)
|
||||
return;
|
||||
|
||||
freezeData fP = { 0, nullptr };
|
||||
if (comp.freeze(FreezeAction::Size, &fP) != 0)
|
||||
fP.size = 0;
|
||||
@@ -435,6 +404,43 @@ static void SysState_ComponentFreezeOut(SaveStateBase& writer, SysState_Componen
|
||||
return;
|
||||
}
|
||||
|
||||
static void SysState_ComponentFreezeInNew(zip_file_t* zf, const char* name, bool(*do_state_func)(StateWrapper&))
|
||||
{
|
||||
// TODO: We could decompress on the fly here for a little bit more speed.
|
||||
std::vector<u8> data;
|
||||
if (zf)
|
||||
{
|
||||
std::optional<std::vector<u8>> optdata(ReadBinaryFileInZip(zf));
|
||||
if (optdata.has_value())
|
||||
data = std::move(optdata.value());
|
||||
}
|
||||
|
||||
StateWrapper::ReadOnlyMemoryStream stream(data.empty() ? nullptr : data.data(), data.size());
|
||||
StateWrapper sw(&stream, StateWrapper::Mode::Read, g_SaveVersion);
|
||||
|
||||
// TODO: Get rid of the bloody exceptions.
|
||||
if (!do_state_func(sw))
|
||||
throw std::runtime_error(fmt::format(" * {}: Error loading state!", name));
|
||||
}
|
||||
|
||||
static void SysState_ComponentFreezeOutNew(SaveStateBase& writer, const char* name, u32 reserve, bool (*do_state_func)(StateWrapper&))
|
||||
{
|
||||
StateWrapper::VectorMemoryStream stream(reserve);
|
||||
StateWrapper sw(&stream, StateWrapper::Mode::Write, g_SaveVersion);
|
||||
|
||||
// TODO: Get rid of the bloody exceptions.
|
||||
if (!do_state_func(sw))
|
||||
throw std::runtime_error(fmt::format(" * {}: Error saving state!", name));
|
||||
|
||||
const int size = static_cast<int>(stream.GetBuffer().size());
|
||||
if (size > 0)
|
||||
{
|
||||
writer.PrepBlock(size);
|
||||
std::memcpy(writer.GetBlockPtr(), stream.GetBuffer().data(), size);
|
||||
writer.CommitBlock(size);
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// BaseSavestateEntry
|
||||
// --------------------------------------------------------------------------------------
|
||||
@@ -606,8 +612,8 @@ public:
|
||||
virtual ~SavestateEntry_USB() = default;
|
||||
|
||||
const char* GetFilename() const { return "USB.bin"; }
|
||||
void FreezeIn(zip_file_t* zf) const { return SysState_ComponentFreezeIn(zf, USB); }
|
||||
void FreezeOut(SaveStateBase& writer) const { return SysState_ComponentFreezeOut(writer, USB); }
|
||||
void FreezeIn(zip_file_t* zf) const { return SysState_ComponentFreezeInNew(zf, "USB", &USB::DoState); }
|
||||
void FreezeOut(SaveStateBase& writer) const { return SysState_ComponentFreezeOutNew(writer, "USB", 16 * 1024, &USB::DoState); }
|
||||
bool IsRequired() const { return false; }
|
||||
};
|
||||
|
||||
@@ -633,7 +639,44 @@ public:
|
||||
bool IsRequired() const { return true; }
|
||||
};
|
||||
|
||||
#ifdef ENABLE_ACHIEVEMENTS
|
||||
class SaveStateEntry_Achievements : public BaseSavestateEntry
|
||||
{
|
||||
virtual ~SaveStateEntry_Achievements() override = default;
|
||||
|
||||
const char* GetFilename() const override { return "Achievements.bin"; }
|
||||
void FreezeIn(zip_file_t* zf) const override
|
||||
{
|
||||
if (!Achievements::IsActive())
|
||||
return;
|
||||
|
||||
std::optional<std::vector<u8>> data;
|
||||
if (zf)
|
||||
data = ReadBinaryFileInZip(zf);
|
||||
|
||||
if (data.has_value() && !data->empty())
|
||||
Achievements::LoadState(data->data(), data->size());
|
||||
else
|
||||
Achievements::LoadState(nullptr, 0);
|
||||
}
|
||||
|
||||
void FreezeOut(SaveStateBase& writer) const override
|
||||
{
|
||||
if (!Achievements::IsActive())
|
||||
return;
|
||||
|
||||
std::vector<u8> data(Achievements::SaveState());
|
||||
if (!data.empty())
|
||||
{
|
||||
writer.PrepBlock(static_cast<int>(data.size()));
|
||||
std::memcpy(writer.GetBlockPtr(), data.data(), data.size());
|
||||
writer.CommitBlock(static_cast<int>(data.size()));
|
||||
}
|
||||
}
|
||||
|
||||
bool IsRequired() const override { return false; }
|
||||
};
|
||||
#endif
|
||||
|
||||
// (cpuRegs, iopRegs, VPU/GIF/DMAC structures should all remain as part of a larger unified
|
||||
// block, since they're all PCSX2-dependent and having separate files in the archie for them
|
||||
@@ -651,22 +694,16 @@ static const std::unique_ptr<BaseSavestateEntry> SavestateEntries[] = {
|
||||
std::unique_ptr<BaseSavestateEntry>(new SavestateEntry_VU0prog),
|
||||
std::unique_ptr<BaseSavestateEntry>(new SavestateEntry_VU1prog),
|
||||
std::unique_ptr<BaseSavestateEntry>(new SavestateEntry_SPU2),
|
||||
#ifndef PCSX2_CORE
|
||||
std::unique_ptr<BaseSavestateEntry>(new SavestateEntry_USB),
|
||||
#endif
|
||||
std::unique_ptr<BaseSavestateEntry>(new SavestateEntry_PAD),
|
||||
std::unique_ptr<BaseSavestateEntry>(new SavestateEntry_GS),
|
||||
#ifdef ENABLE_ACHIEVEMENTS
|
||||
std::unique_ptr<BaseSavestateEntry>(new SaveStateEntry_Achievements),
|
||||
#endif
|
||||
};
|
||||
|
||||
std::unique_ptr<ArchiveEntryList> SaveState_DownloadState()
|
||||
{
|
||||
#ifndef PCSX2_CORE
|
||||
if (!GetCoreThread().HasActiveMachine())
|
||||
throw Exception::RuntimeError()
|
||||
.SetDiagMsg("SysExecEvent_DownloadState: Cannot freeze/download an invalid VM state!")
|
||||
.SetUserMsg("There is no active virtual machine state to download or save.");
|
||||
#endif
|
||||
|
||||
std::unique_ptr<ArchiveEntryList> destlist = std::make_unique<ArchiveEntryList>(new VmStateBuffer("Zippable Savestate"));
|
||||
|
||||
memSavingState saveme(destlist->GetBuffer());
|
||||
@@ -697,16 +734,17 @@ std::unique_ptr<SaveStateScreenshotData> SaveState_SaveScreenshot()
|
||||
static constexpr u32 SCREENSHOT_WIDTH = 640;
|
||||
static constexpr u32 SCREENSHOT_HEIGHT = 480;
|
||||
|
||||
std::vector<u32> pixels(SCREENSHOT_WIDTH * SCREENSHOT_HEIGHT);
|
||||
if (!GetMTGS().SaveMemorySnapshot(SCREENSHOT_WIDTH, SCREENSHOT_HEIGHT, &pixels))
|
||||
u32 width, height;
|
||||
std::vector<u32> pixels;
|
||||
if (!GetMTGS().SaveMemorySnapshot(SCREENSHOT_WIDTH, SCREENSHOT_HEIGHT, true, false, &width, &height, &pixels))
|
||||
{
|
||||
// saving failed for some reason, device lost?
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<SaveStateScreenshotData> data = std::make_unique<SaveStateScreenshotData>();
|
||||
data->width = SCREENSHOT_WIDTH;
|
||||
data->height = SCREENSHOT_HEIGHT;
|
||||
data->width = width;
|
||||
data->height = height;
|
||||
data->pixels = std::move(pixels);
|
||||
return data;
|
||||
}
|
||||
@@ -970,17 +1008,15 @@ static void CheckVersion(const std::string& filename, zip_t* zf)
|
||||
if (savever > g_SaveVersion)
|
||||
throw Exception::SaveStateLoadError(filename)
|
||||
.SetDiagMsg(fmt::format("Savestate uses an unsupported or unknown savestate version.\n(PCSX2 ver={:x}, state ver={:x})", g_SaveVersion, savever))
|
||||
.SetUserMsg("Cannot load this savestate. The state is an unsupported version.");
|
||||
|
||||
.SetUserMsg("Cannot load this savestate. The state is an unsupported version.\nOption 1: Download an older PCSX2 version from pcsx2.net and make a memcard save like on the physical PS2.\nOption 2: Delete the savestates.");
|
||||
// check for a "minor" version incompatibility; which happens if the savestate being loaded is a newer version
|
||||
// than the emulator recognizes. 99% chance that trying to load it will just corrupt emulation or crash.
|
||||
if ((savever >> 16) != (g_SaveVersion >> 16))
|
||||
throw Exception::SaveStateLoadError(filename)
|
||||
.SetDiagMsg(fmt::format("Savestate uses an unknown savestate version.\n(PCSX2 ver={:x}, state ver={:x})", g_SaveVersion, savever))
|
||||
.SetUserMsg("Cannot load this savestate. The state is an unsupported version.");
|
||||
}
|
||||
.SetUserMsg("Cannot load this savestate. The state is an unsupported version.\nOption 1: Download an older PCSX2 version from pcsx2.net and make a memcard save like on the physical PS2.\nOption 2: Delete the savestates.");}
|
||||
|
||||
static zip_int64_t CheckFileExistsInState(zip_t* zf, const char* name)
|
||||
static zip_int64_t CheckFileExistsInState(zip_t* zf, const char* name, bool required)
|
||||
{
|
||||
zip_int64_t index = zip_name_locate(zf, name, /*ZIP_FL_NOCASE*/ 0);
|
||||
if (index >= 0)
|
||||
@@ -989,7 +1025,11 @@ static zip_int64_t CheckFileExistsInState(zip_t* zf, const char* name)
|
||||
return index;
|
||||
}
|
||||
|
||||
Console.WriteLn(Color_Red, " ... not found '%s'!", name);
|
||||
if (required)
|
||||
Console.WriteLn(Color_Red, " ... not found '%s'!", name);
|
||||
else
|
||||
DevCon.WriteLn(Color_Red, " ... not found '%s'!", name);
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
@@ -1028,15 +1068,16 @@ void SaveState_UnzipFromDisk(const std::string& filename)
|
||||
CheckVersion(filename, zf.get());
|
||||
|
||||
// check that all parts are included
|
||||
const s64 internal_index = CheckFileExistsInState(zf.get(), EntryFilename_InternalStructures);
|
||||
const s64 internal_index = CheckFileExistsInState(zf.get(), EntryFilename_InternalStructures, true);
|
||||
s64 entryIndices[std::size(SavestateEntries)];
|
||||
|
||||
// Log any parts and pieces that are missing, and then generate an exception.
|
||||
bool throwIt = (internal_index < 0);
|
||||
for (u32 i = 0; i < std::size(SavestateEntries); i++)
|
||||
{
|
||||
entryIndices[i] = CheckFileExistsInState(zf.get(), SavestateEntries[i]->GetFilename());
|
||||
if (entryIndices[i] < 0 && SavestateEntries[i]->IsRequired())
|
||||
const bool required = SavestateEntries[i]->IsRequired();
|
||||
entryIndices[i] = CheckFileExistsInState(zf.get(), SavestateEntries[i]->GetFilename(), required);
|
||||
if (entryIndices[i] < 0 && required)
|
||||
throwIt = true;
|
||||
}
|
||||
|
||||
@@ -1051,7 +1092,10 @@ void SaveState_UnzipFromDisk(const std::string& filename)
|
||||
for (u32 i = 0; i < std::size(SavestateEntries); ++i)
|
||||
{
|
||||
if (entryIndices[i] < 0)
|
||||
{
|
||||
SavestateEntries[i]->FreezeIn(nullptr);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto zff = zip_fopen_index_managed(zf.get(), entryIndices[i], 0);
|
||||
if (!zff)
|
||||
|
||||
+30
-10
@@ -36,25 +36,25 @@ namespace GL
|
||||
|
||||
ContextAGL::~ContextAGL()
|
||||
{
|
||||
CleanupView();
|
||||
|
||||
if (m_opengl_module_handle)
|
||||
dlclose(m_opengl_module_handle);
|
||||
}
|
||||
|
||||
std::unique_ptr<Context> ContextAGL::Create(const WindowInfo& wi, const Version* versions_to_try,
|
||||
size_t num_versions_to_try)
|
||||
std::unique_ptr<Context> ContextAGL::Create(const WindowInfo& wi, gsl::span<const Version> versions_to_try)
|
||||
{
|
||||
std::unique_ptr<ContextAGL> context = std::make_unique<ContextAGL>(wi);
|
||||
if (!context->Initialize(versions_to_try, num_versions_to_try))
|
||||
if (!context->Initialize(versions_to_try))
|
||||
return nullptr;
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
bool ContextAGL::Initialize(const Version* versions_to_try, size_t num_versions_to_try)
|
||||
bool ContextAGL::Initialize(gsl::span<const Version> versions_to_try)
|
||||
{
|
||||
MakeCurrent();
|
||||
|
||||
for (size_t i = 0; i < num_versions_to_try; i++)
|
||||
for (const Version& cv : versions_to_try)
|
||||
{
|
||||
const Version& cv = versions_to_try[i];
|
||||
if (cv.profile == Profile::NoProfile && CreateContext(nullptr, NSOpenGLProfileVersionLegacy, true))
|
||||
{
|
||||
// we already have the dummy context, so just use that
|
||||
@@ -89,8 +89,8 @@ namespace GL
|
||||
|
||||
bool ContextAGL::ChangeSurface(const WindowInfo& new_wi)
|
||||
{
|
||||
m_wi.surface_width = new_wi.surface_width;
|
||||
m_wi.surface_height = new_wi.surface_height;
|
||||
m_wi = new_wi;
|
||||
BindContextToView();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -101,6 +101,26 @@ namespace GL
|
||||
|
||||
bool ContextAGL::UpdateDimensions()
|
||||
{
|
||||
if (![NSThread isMainThread])
|
||||
{
|
||||
bool ret;
|
||||
dispatch_sync(dispatch_get_main_queue(), [this, &ret]{ ret = UpdateDimensions(); });
|
||||
return ret;
|
||||
}
|
||||
|
||||
const NSSize window_size = [m_view frame].size;
|
||||
const CGFloat window_scale = [[m_view window] backingScaleFactor];
|
||||
const u32 new_width = static_cast<u32>(window_size.width * window_scale);
|
||||
const u32 new_height = static_cast<u32>(window_size.height * window_scale);
|
||||
|
||||
if (m_wi.surface_width == new_width && m_wi.surface_height == new_height)
|
||||
return false;
|
||||
|
||||
m_wi.surface_width = new_width;
|
||||
m_wi.surface_height = new_height;
|
||||
|
||||
[m_context update];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#include "common/ScopedGuard.h"
|
||||
#include "common/StringUtil.h"
|
||||
#include "common/GL/Program.h"
|
||||
|
||||
#include <array>
|
||||
#include <tuple>
|
||||
|
||||
@@ -62,22 +61,22 @@ OpenGLHostDisplay::~OpenGLHostDisplay()
|
||||
}
|
||||
}
|
||||
|
||||
HostDisplay::RenderAPI OpenGLHostDisplay::GetRenderAPI() const
|
||||
RenderAPI OpenGLHostDisplay::GetRenderAPI() const
|
||||
{
|
||||
return m_gl_context->IsGLES() ? RenderAPI::OpenGLES : RenderAPI::OpenGL;
|
||||
}
|
||||
|
||||
void* OpenGLHostDisplay::GetRenderDevice() const
|
||||
void* OpenGLHostDisplay::GetDevice() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void* OpenGLHostDisplay::GetRenderContext() const
|
||||
void* OpenGLHostDisplay::GetContext() const
|
||||
{
|
||||
return m_gl_context.get();
|
||||
}
|
||||
|
||||
void* OpenGLHostDisplay::GetRenderSurface() const
|
||||
void* OpenGLHostDisplay::GetSurface() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
@@ -87,6 +86,9 @@ std::unique_ptr<HostDisplayTexture> OpenGLHostDisplay::CreateTexture(u32 width,
|
||||
// clear error
|
||||
glGetError();
|
||||
|
||||
// don't worry, I'm planning on removing this eventually - we'll use GSTexture instead.
|
||||
glActiveTexture(GL_TEXTURE7);
|
||||
|
||||
GLuint id;
|
||||
glGenTextures(1, &id);
|
||||
glBindTexture(GL_TEXTURE_2D, id);
|
||||
@@ -102,6 +104,8 @@ std::unique_ptr<HostDisplayTexture> OpenGLHostDisplay::CreateTexture(u32 width,
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
||||
}
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
GLenum error = glGetError();
|
||||
if (error != GL_NO_ERROR)
|
||||
{
|
||||
@@ -115,37 +119,20 @@ std::unique_ptr<HostDisplayTexture> OpenGLHostDisplay::CreateTexture(u32 width,
|
||||
|
||||
void OpenGLHostDisplay::UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* texture_data, u32 texture_data_stride)
|
||||
{
|
||||
OpenGLHostDisplayTexture* tex = static_cast<OpenGLHostDisplayTexture*>(texture);
|
||||
glActiveTexture(GL_TEXTURE7);
|
||||
|
||||
GLint alignment;
|
||||
if (texture_data_stride & 1)
|
||||
alignment = 1;
|
||||
else if (texture_data_stride & 2)
|
||||
alignment = 2;
|
||||
else
|
||||
alignment = 4;
|
||||
|
||||
GLint old_texture_binding = 0, old_alignment = 0, old_row_length = 0;
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_texture_binding);
|
||||
glBindTexture(GL_TEXTURE_2D, tex->GetGLID());
|
||||
|
||||
glGetIntegerv(GL_UNPACK_ALIGNMENT, &old_alignment);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, alignment);
|
||||
|
||||
glGetIntegerv(GL_UNPACK_ROW_LENGTH, &old_row_length);
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, texture_data_stride / sizeof(u32));
|
||||
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, GL_RGBA8, GL_UNSIGNED_BYTE, texture_data);
|
||||
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, old_row_length);
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, old_alignment);
|
||||
glBindTexture(GL_TEXTURE_2D, old_texture_binding);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
}
|
||||
|
||||
void OpenGLHostDisplay::SetVSync(VsyncMode mode)
|
||||
{
|
||||
if (m_gl_context->GetWindowInfo().type == WindowInfo::Type::Surfaceless)
|
||||
if (m_vsync_mode == mode || m_gl_context->GetWindowInfo().type == WindowInfo::Type::Surfaceless)
|
||||
return;
|
||||
|
||||
// Window framebuffer has to be bound to call SetSwapInterval.
|
||||
@@ -157,6 +144,7 @@ void OpenGLHostDisplay::SetVSync(VsyncMode mode)
|
||||
m_gl_context->SetSwapInterval(static_cast<s32>(mode != VsyncMode::Off));
|
||||
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, current_fbo);
|
||||
m_vsync_mode = mode;
|
||||
}
|
||||
|
||||
const char* OpenGLHostDisplay::GetGLSLVersionString() const
|
||||
@@ -190,17 +178,17 @@ std::string OpenGLHostDisplay::GetGLSLVersionHeader() const
|
||||
return header;
|
||||
}
|
||||
|
||||
bool OpenGLHostDisplay::HasRenderDevice() const
|
||||
bool OpenGLHostDisplay::HasDevice() const
|
||||
{
|
||||
return static_cast<bool>(m_gl_context);
|
||||
}
|
||||
|
||||
bool OpenGLHostDisplay::HasRenderSurface() const
|
||||
bool OpenGLHostDisplay::HasSurface() const
|
||||
{
|
||||
return m_window_info.type != WindowInfo::Type::Surfaceless;
|
||||
}
|
||||
|
||||
bool OpenGLHostDisplay::CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, VsyncMode vsync, bool threaded_presentation, bool debug_device)
|
||||
bool OpenGLHostDisplay::CreateDevice(const WindowInfo& wi, VsyncMode vsync)
|
||||
{
|
||||
m_gl_context = GL::Context::Create(wi);
|
||||
if (!m_gl_context)
|
||||
@@ -217,8 +205,11 @@ bool OpenGLHostDisplay::CreateRenderDevice(const WindowInfo& wi, std::string_vie
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OpenGLHostDisplay::InitializeRenderDevice(std::string_view shader_cache_directory, bool debug_device)
|
||||
bool OpenGLHostDisplay::SetupDevice()
|
||||
{
|
||||
// We do use 8-bit formats, and higher alignment for 32-bit formats won't hurt anything.
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
|
||||
SetSwapInterval();
|
||||
GL::Program::ResetLastProgram();
|
||||
return true;
|
||||
@@ -230,7 +221,7 @@ void OpenGLHostDisplay::SetSwapInterval()
|
||||
m_gl_context->SetSwapInterval(interval);
|
||||
}
|
||||
|
||||
bool OpenGLHostDisplay::MakeRenderContextCurrent()
|
||||
bool OpenGLHostDisplay::MakeCurrent()
|
||||
{
|
||||
if (!m_gl_context->MakeCurrent())
|
||||
{
|
||||
@@ -242,12 +233,12 @@ bool OpenGLHostDisplay::MakeRenderContextCurrent()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OpenGLHostDisplay::DoneRenderContextCurrent()
|
||||
bool OpenGLHostDisplay::DoneCurrent()
|
||||
{
|
||||
return m_gl_context->DoneCurrent();
|
||||
}
|
||||
|
||||
bool OpenGLHostDisplay::ChangeRenderWindow(const WindowInfo& new_wi)
|
||||
bool OpenGLHostDisplay::ChangeWindow(const WindowInfo& new_wi)
|
||||
{
|
||||
pxAssert(m_gl_context);
|
||||
|
||||
@@ -269,7 +260,7 @@ bool OpenGLHostDisplay::ChangeRenderWindow(const WindowInfo& new_wi)
|
||||
return true;
|
||||
}
|
||||
|
||||
void OpenGLHostDisplay::ResizeRenderWindow(s32 new_window_width, s32 new_window_height, float new_window_scale)
|
||||
void OpenGLHostDisplay::ResizeWindow(s32 new_window_width, s32 new_window_height, float new_window_scale)
|
||||
{
|
||||
if (!m_gl_context)
|
||||
return;
|
||||
@@ -313,7 +304,7 @@ HostDisplay::AdapterAndModeList OpenGLHostDisplay::GetAdapterAndModeList()
|
||||
return aml;
|
||||
}
|
||||
|
||||
void OpenGLHostDisplay::DestroyRenderSurface()
|
||||
void OpenGLHostDisplay::DestroySurface()
|
||||
{
|
||||
if (!m_gl_context)
|
||||
return;
|
||||
@@ -364,11 +355,8 @@ bool OpenGLHostDisplay::BeginPresent(bool frame_skip)
|
||||
|
||||
void OpenGLHostDisplay::EndPresent()
|
||||
{
|
||||
// clear out pipeline bindings, since imgui doesn't use them
|
||||
glBindProgramPipeline(0);
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
GL::Program::ResetLastProgram();
|
||||
|
||||
@@ -401,7 +389,7 @@ void OpenGLHostDisplay::DestroyTimestampQueries()
|
||||
if (m_timestamp_query_started)
|
||||
{
|
||||
const auto EndQuery = gles ? glEndQueryEXT : glEndQuery;
|
||||
EndQuery(m_timestamp_queries[m_write_timestamp_query]);
|
||||
EndQuery(GL_TIME_ELAPSED);
|
||||
}
|
||||
|
||||
DeleteQueries(static_cast<u32>(m_timestamp_queries.size()), m_timestamp_queries.data());
|
||||
@@ -440,7 +428,6 @@ void OpenGLHostDisplay::PopTimestampQuery()
|
||||
|
||||
GLint available = 0;
|
||||
GetQueryObjectiv(m_timestamp_queries[m_read_timestamp_query], GL_QUERY_RESULT_AVAILABLE, &available);
|
||||
pxAssert(m_read_timestamp_query != m_write_timestamp_query);
|
||||
|
||||
if (!available)
|
||||
break;
|
||||
@@ -452,8 +439,7 @@ void OpenGLHostDisplay::PopTimestampQuery()
|
||||
m_waiting_timestamp_queries--;
|
||||
}
|
||||
|
||||
// delay ending the current query until we've read back some
|
||||
if (m_timestamp_query_started && m_waiting_timestamp_queries < (NUM_TIMESTAMP_QUERIES - 1))
|
||||
if (m_timestamp_query_started)
|
||||
{
|
||||
const auto EndQuery = gles ? glEndQueryEXT : glEndQuery;
|
||||
EndQuery(GL_TIME_ELAPSED);
|
||||
@@ -466,7 +452,7 @@ void OpenGLHostDisplay::PopTimestampQuery()
|
||||
|
||||
void OpenGLHostDisplay::KickTimestampQuery()
|
||||
{
|
||||
if (m_timestamp_query_started)
|
||||
if (m_timestamp_query_started || m_waiting_timestamp_queries == NUM_TIMESTAMP_QUERIES)
|
||||
return;
|
||||
|
||||
const bool gles = m_gl_context->IsGLES();
|
||||
@@ -499,3 +485,4 @@ float OpenGLHostDisplay::GetAndResetAccumulatedGPUTime()
|
||||
m_accumulated_gpu_time = 0.0f;
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
+457
-129
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user