mirror of https://github.com/PCSX2/pcsx2.git
System: Remove/move out a bunch more leftover stuff from wx
The exceptions are particularly nasty, because there's nothing which catches them.
This commit is contained in:
parent
00bcb4cf02
commit
d446e40741
|
@ -201,84 +201,6 @@ Exception::RuntimeError::RuntimeError(const std::exception& ex, const char* pref
|
|||
ex.what()));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Exception::OutOfMemory (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
Exception::OutOfMemory::OutOfMemory(std::string allocdesc)
|
||||
: AllocDescription(std::move(allocdesc))
|
||||
{
|
||||
}
|
||||
|
||||
std::string Exception::OutOfMemory::FormatDiagnosticMessage() const
|
||||
{
|
||||
std::string retmsg;
|
||||
retmsg = "Out of memory";
|
||||
if (!AllocDescription.empty())
|
||||
fmt::format_to(std::back_inserter(retmsg), " while allocating '{}'", AllocDescription);
|
||||
|
||||
if (!m_message_diag.empty())
|
||||
fmt::format_to(std::back_inserter(retmsg), ":\n{}", m_message_diag);
|
||||
|
||||
return retmsg;
|
||||
}
|
||||
|
||||
std::string Exception::OutOfMemory::FormatDisplayMessage() const
|
||||
{
|
||||
std::string retmsg;
|
||||
retmsg = "Oh noes! Out of memory!";
|
||||
|
||||
if (!m_message_user.empty())
|
||||
fmt::format_to(std::back_inserter(retmsg), "\n\n{}", m_message_user);
|
||||
|
||||
return retmsg;
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Exception::VirtualMemoryMapConflict (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
Exception::VirtualMemoryMapConflict::VirtualMemoryMapConflict(std::string allocdesc)
|
||||
{
|
||||
AllocDescription = std::move(allocdesc);
|
||||
m_message_user = "Virtual memory mapping failure! Your system may have conflicting device drivers, services, or may simply have insufficient memory or resources to meet PCSX2's lofty needs.";
|
||||
}
|
||||
|
||||
std::string Exception::VirtualMemoryMapConflict::FormatDiagnosticMessage() const
|
||||
{
|
||||
std::string retmsg;
|
||||
retmsg = "Virtual memory map failed";
|
||||
if (!AllocDescription.empty())
|
||||
fmt::format_to(std::back_inserter(retmsg), " while reserving '{}'", AllocDescription);
|
||||
|
||||
if (!m_message_diag.empty())
|
||||
fmt::format_to(std::back_inserter(retmsg), ":\n{}", m_message_diag);
|
||||
|
||||
return retmsg;
|
||||
}
|
||||
|
||||
std::string Exception::VirtualMemoryMapConflict::FormatDisplayMessage() const
|
||||
{
|
||||
std::string retmsg;
|
||||
retmsg = "There is not enough virtual memory available, or necessary virtual memory mappings have already been reserved by other processes, services, or DLLs.";
|
||||
|
||||
if (!m_message_diag.empty())
|
||||
fmt::format_to(std::back_inserter(retmsg), "\n\n{}", m_message_diag);
|
||||
|
||||
return retmsg;
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
std::string Exception::CancelEvent::FormatDiagnosticMessage() const
|
||||
{
|
||||
return "Action canceled: " + m_message_diag;
|
||||
}
|
||||
|
||||
std::string Exception::CancelEvent::FormatDisplayMessage() const
|
||||
{
|
||||
return "Action canceled: " + m_message_diag;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Exception::BadStream (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -402,7 +324,7 @@ std::string Exception::EndOfStream::FormatDisplayMessage() const
|
|||
|
||||
// Translates an Errno code into an exception.
|
||||
// Throws an exception based on the given error code (usually taken from ANSI C's errno)
|
||||
BaseException* Exception::FromErrno(std::string streamname, int errcode)
|
||||
std::unique_ptr<BaseException> Exception::FromErrno(std::string streamname, int errcode)
|
||||
{
|
||||
pxAssumeDev(errcode != 0, "Invalid NULL error code? (errno)");
|
||||
|
||||
|
@ -410,27 +332,27 @@ BaseException* Exception::FromErrno(std::string streamname, int errcode)
|
|||
{
|
||||
case EINVAL:
|
||||
pxFailDev("Invalid argument");
|
||||
return &(new Exception::BadStream(streamname))->SetDiagMsg("Invalid argument? (likely caused by an unforgivable programmer error!)");
|
||||
return std::unique_ptr<BaseException>(&(new Exception::BadStream(streamname))->SetDiagMsg("Invalid argument? (likely caused by an unforgivable programmer error!)"));
|
||||
|
||||
case EACCES: // Access denied!
|
||||
return new Exception::AccessDenied(streamname);
|
||||
return std::unique_ptr<BaseException>(new Exception::AccessDenied(streamname));
|
||||
|
||||
case EMFILE: // Too many open files!
|
||||
return &(new Exception::CannotCreateStream(streamname))->SetDiagMsg("Too many open files"); // File handle allocation failure
|
||||
return std::unique_ptr<BaseException>(&(new Exception::CannotCreateStream(streamname))->SetDiagMsg("Too many open files")); // File handle allocation failure
|
||||
|
||||
case EEXIST:
|
||||
return &(new Exception::CannotCreateStream(streamname))->SetDiagMsg("File already exists");
|
||||
return std::unique_ptr<BaseException>(&(new Exception::CannotCreateStream(streamname))->SetDiagMsg("File already exists"));
|
||||
|
||||
case ENOENT: // File not found!
|
||||
return new Exception::FileNotFound(streamname);
|
||||
return std::unique_ptr<BaseException>(new Exception::FileNotFound(streamname));
|
||||
|
||||
case EPIPE:
|
||||
return &(new Exception::BadStream(streamname))->SetDiagMsg("Broken pipe");
|
||||
return std::unique_ptr<BaseException>(&(new Exception::BadStream(streamname))->SetDiagMsg("Broken pipe"));
|
||||
|
||||
case EBADF:
|
||||
return &(new Exception::BadStream(streamname))->SetDiagMsg("Bad file number");
|
||||
return std::unique_ptr<BaseException>(&(new Exception::BadStream(streamname))->SetDiagMsg("Bad file number"));
|
||||
|
||||
default:
|
||||
return &(new Exception::BadStream(streamname))->SetDiagMsg(fmt::format("General file/stream error [errno: {}]", errcode));
|
||||
return std::unique_ptr<BaseException>(&(new Exception::BadStream(streamname))->SetDiagMsg(fmt::format("General file/stream error [errno: {}]", errcode)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,53 +23,11 @@
|
|||
// Because wxTrap isn't available on Linux builds of wxWidgets (non-Debug, typically)
|
||||
void pxTrap();
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// DESTRUCTOR_CATCHALL - safe destructor helper
|
||||
// --------------------------------------------------------------------------------------
|
||||
// In C++ destructors *really* need to be "nothrow" garaunteed, otherwise you can have
|
||||
// disasterous nested exception throws during the unwinding process of an originating
|
||||
// exception. Use this macro to dispose of these dangerous exceptions, and generate a
|
||||
// friendly error log in their wake.
|
||||
//
|
||||
// Note: Console can also fire an Exception::OutOfMemory
|
||||
#define __DESTRUCTOR_CATCHALL(funcname) \
|
||||
catch (BaseException & ex) \
|
||||
{ \
|
||||
try \
|
||||
{ \
|
||||
Console.Error("Unhandled BaseException in %s (ignored!):", funcname); \
|
||||
Console.Error(ex.FormatDiagnosticMessage()); \
|
||||
} \
|
||||
catch (...) \
|
||||
{ \
|
||||
fprintf(stderr, "ERROR: (out of memory?)\n"); \
|
||||
} \
|
||||
} \
|
||||
catch (std::exception & ex) \
|
||||
{ \
|
||||
try \
|
||||
{ \
|
||||
Console.Error("Unhandled std::exception in %s (ignored!):", funcname); \
|
||||
Console.Error(ex.what()); \
|
||||
} \
|
||||
catch (...) \
|
||||
{ \
|
||||
fprintf(stderr, "ERROR: (out of memory?)\n"); \
|
||||
} \
|
||||
} \
|
||||
catch (...) \
|
||||
{ \
|
||||
/* Unreachable code */ \
|
||||
}
|
||||
|
||||
#define DESTRUCTOR_CATCHALL __DESTRUCTOR_CATCHALL(__pxFUNCTION__)
|
||||
|
||||
namespace Exception
|
||||
{
|
||||
class BaseException;
|
||||
|
||||
int MakeNewType();
|
||||
BaseException* FromErrno(std::string streamname, int errcode);
|
||||
std::unique_ptr<BaseException> FromErrno(std::string streamname, int errcode);
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// BaseException
|
||||
|
@ -119,8 +77,6 @@ namespace Exception
|
|||
virtual BaseException* Clone() const = 0;
|
||||
};
|
||||
|
||||
typedef std::unique_ptr<BaseException> ScopedExcept;
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Ps2Generic Exception
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -225,83 +181,6 @@ public: \
|
|||
RuntimeError(const std::exception& ex, const char* prefix = nullptr);
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// CancelAppEvent - Exception for canceling an event in a non-verbose fashion
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Typically the PCSX2 interface issues popup dialogs for runtime errors. This exception
|
||||
// instead issues a "silent" cancelation that is handled by the app gracefully (generates
|
||||
// log, and resumes messages queue processing).
|
||||
//
|
||||
// I chose to have this exception derive from RuntimeError, since if one is thrown from outside
|
||||
// an App message loop we'll still want it to be handled in a reasonably graceful manner.
|
||||
class CancelEvent : public RuntimeError
|
||||
{
|
||||
DEFINE_RUNTIME_EXCEPTION(CancelEvent, RuntimeError, "No reason given.")
|
||||
|
||||
public:
|
||||
explicit CancelEvent(std::string logmsg)
|
||||
{
|
||||
m_message_diag = std::move(logmsg);
|
||||
// overridden message formatters only use the diagnostic version...
|
||||
}
|
||||
|
||||
virtual std::string FormatDisplayMessage() const override;
|
||||
virtual std::string FormatDiagnosticMessage() const override;
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// OutOfMemory
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// This exception has a custom-formatted Diagnostic string. The parameter give when constructing
|
||||
// the exception is a block/alloc name, which is used as a formatting parameter in the diagnostic
|
||||
// output. The default diagnostic message is "Out of memory exception, while allocating the %s."
|
||||
// where %s is filled in with the block name.
|
||||
//
|
||||
// The user string is not custom-formatted, and should contain *NO* %s tags.
|
||||
//
|
||||
class OutOfMemory : public RuntimeError
|
||||
{
|
||||
DEFINE_RUNTIME_EXCEPTION(OutOfMemory, RuntimeError, "")
|
||||
|
||||
public:
|
||||
std::string AllocDescription;
|
||||
|
||||
public:
|
||||
OutOfMemory(std::string allocdesc);
|
||||
|
||||
virtual std::string FormatDisplayMessage() const override;
|
||||
virtual std::string FormatDiagnosticMessage() const override;
|
||||
};
|
||||
|
||||
class ParseError : public RuntimeError
|
||||
{
|
||||
DEFINE_RUNTIME_EXCEPTION(ParseError, RuntimeError, "Parse error");
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// Hardware/OS Exceptions:
|
||||
// HardwareDeficiency / VirtualMemoryMapConflict
|
||||
// ---------------------------------------------------------------------------------------
|
||||
|
||||
// This exception is a specific type of OutOfMemory error that isn't "really" an out of
|
||||
// memory error. More likely it's caused by a plugin or driver reserving a range of memory
|
||||
// we'd really like to have access to.
|
||||
class VirtualMemoryMapConflict : public OutOfMemory
|
||||
{
|
||||
DEFINE_RUNTIME_EXCEPTION(VirtualMemoryMapConflict, OutOfMemory, "")
|
||||
|
||||
VirtualMemoryMapConflict(std::string allocdesc);
|
||||
|
||||
virtual std::string FormatDisplayMessage() const override;
|
||||
virtual std::string FormatDiagnosticMessage() const override;
|
||||
};
|
||||
|
||||
class HardwareDeficiency : public RuntimeError
|
||||
{
|
||||
public:
|
||||
DEFINE_RUNTIME_EXCEPTION(HardwareDeficiency, RuntimeError, "Your machine's hardware is incapable of running PCSX2. Sorry dood.");
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// Streaming (file) Exceptions:
|
||||
// Stream / BadStream / CannotCreateStream / FileNotFound / AccessDenied / EndOfStream
|
||||
|
@ -401,28 +280,6 @@ public: \
|
|||
virtual std::string FormatDiagnosticMessage() const override;
|
||||
virtual std::string FormatDisplayMessage() const override;
|
||||
};
|
||||
|
||||
#ifdef _WIN32
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Exception::WinApiError
|
||||
// --------------------------------------------------------------------------------------
|
||||
class WinApiError : public RuntimeError
|
||||
{
|
||||
DEFINE_EXCEPTION_COPYTORS(WinApiError, RuntimeError)
|
||||
DEFINE_EXCEPTION_MESSAGES(WinApiError)
|
||||
|
||||
public:
|
||||
int ErrorId;
|
||||
|
||||
public:
|
||||
WinApiError();
|
||||
|
||||
std::string GetMsgFromWindows() const;
|
||||
virtual std::string FormatDisplayMessage() const override;
|
||||
virtual std::string FormatDiagnosticMessage() const override;
|
||||
};
|
||||
#endif
|
||||
} // namespace Exception
|
||||
|
||||
using Exception::BaseException;
|
||||
using Exception::ScopedExcept;
|
||||
|
|
|
@ -35,8 +35,7 @@ SafeArray<T>::SafeArray(std::string name, T* allocated_mem, int initSize)
|
|||
m_size = initSize;
|
||||
|
||||
if (m_ptr == NULL)
|
||||
throw Exception::OutOfMemory(name)
|
||||
.SetDiagMsg(fmt::format("Called from 'SafeArray::ctor' [size={}]", initSize));
|
||||
pxFailRel("SafeArray memory assignment failed");
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
@ -84,8 +83,7 @@ SafeArray<T>::SafeArray(int initialSize, std::string name)
|
|||
m_size = initialSize;
|
||||
|
||||
if ((initialSize != 0) && (m_ptr == NULL))
|
||||
throw Exception::OutOfMemory(name)
|
||||
.SetDiagMsg(fmt::format("Called from 'SafeArray::ctor' [size={}]", initialSize));
|
||||
pxFailRel("SafeArray memory allocation failed");
|
||||
}
|
||||
|
||||
// Clears the contents of the array to zero, and frees all memory allocations.
|
||||
|
@ -113,8 +111,7 @@ void SafeArray<T>::ExactAlloc(int newsize)
|
|||
|
||||
m_ptr = _virtual_realloc(newsize);
|
||||
if (m_ptr == NULL)
|
||||
throw Exception::OutOfMemory(Name)
|
||||
.SetDiagMsg(fmt::format("Called from 'SafeArray::ExactAlloc' [oldsize={}] [newsize={}]", m_size, newsize));
|
||||
pxFailRel("SafeArray exact alloc failed");
|
||||
|
||||
m_size = newsize;
|
||||
}
|
||||
|
@ -203,8 +200,7 @@ SafeList<T>::SafeList(int initialSize, const char* name)
|
|||
m_ptr = (T*)malloc(initialSize * sizeof(T));
|
||||
|
||||
if (m_ptr == NULL)
|
||||
throw Exception::OutOfMemory(Name)
|
||||
.SetDiagMsg(fmt::format("called from 'SafeList::ctor' [length={}]", m_length));
|
||||
pxFailRel("SafeList exact alloc failed");
|
||||
|
||||
for (int i = 0; i < m_allocsize; ++i)
|
||||
{
|
||||
|
@ -229,8 +225,7 @@ void SafeList<T>::MakeRoomFor(int blockSize)
|
|||
const int newalloc = blockSize + ChunkSize;
|
||||
m_ptr = _virtual_realloc(newalloc);
|
||||
if (m_ptr == NULL)
|
||||
throw Exception::OutOfMemory(Name)
|
||||
.SetDiagMsg(fmt::format("Called from 'SafeList::MakeRoomFor' [oldlen={}] [newlen={}]", m_length, blockSize));
|
||||
pxFailRel("SafeList MakeRoomFor failed");
|
||||
|
||||
for (; m_allocsize < newalloc; ++m_allocsize)
|
||||
{
|
||||
|
|
|
@ -81,38 +81,6 @@ std::string GetOSVersionString()
|
|||
return retval;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Exception::WinApiError (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
Exception::WinApiError::WinApiError()
|
||||
{
|
||||
ErrorId = GetLastError();
|
||||
m_message_diag = "Unspecified Windows API error.";
|
||||
}
|
||||
|
||||
std::string Exception::WinApiError::GetMsgFromWindows() const
|
||||
{
|
||||
if (!ErrorId)
|
||||
return "No valid error number was assigned to this exception!";
|
||||
|
||||
const DWORD BUF_LEN = 2048;
|
||||
wchar_t t_Msg[BUF_LEN];
|
||||
if (FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, 0, ErrorId, 0, t_Msg, BUF_LEN, 0))
|
||||
return fmt::format("Win32 Error #{}: {}", ErrorId, StringUtil::WideStringToUTF8String(t_Msg));
|
||||
|
||||
return fmt::format("Win32 Error #{} (no text msg available)", ErrorId);
|
||||
}
|
||||
|
||||
std::string Exception::WinApiError::FormatDisplayMessage() const
|
||||
{
|
||||
return m_message_user + "\n\n" + GetMsgFromWindows();
|
||||
}
|
||||
|
||||
std::string Exception::WinApiError::FormatDiagnosticMessage() const
|
||||
{
|
||||
return m_message_diag + "\n\t" + GetMsgFromWindows();
|
||||
}
|
||||
|
||||
bool WindowInfo::InhibitScreensaver(const WindowInfo& wi, bool inhibit)
|
||||
{
|
||||
EXECUTION_STATE flags = ES_CONTINUOUS;
|
||||
|
|
|
@ -58,8 +58,7 @@ void OutputIsoFile::Create(std::string filename, int version)
|
|||
if (!m_outstream)
|
||||
{
|
||||
Console.Error("(OutputIsoFile::Create) Unable to open the file '%s' for writing: %d", m_filename.c_str(), errno);
|
||||
ScopedExcept ex(Exception::FromErrno(filename, errno));
|
||||
ex->Rethrow();
|
||||
Exception::FromErrno(filename, errno)->Rethrow();
|
||||
}
|
||||
|
||||
Console.WriteLn("isoFile create ok: %s ", m_filename.c_str());
|
||||
|
@ -130,7 +129,7 @@ void OutputIsoFile::WriteBuffer(const void* src, size_t size)
|
|||
.SetDiagMsg(fmt::format("An error occurred while writing {} bytes to file", size));
|
||||
}
|
||||
|
||||
ScopedExcept ex(Exception::FromErrno(m_filename, err));
|
||||
std::unique_ptr<BaseException> ex(Exception::FromErrno(m_filename, err));
|
||||
ex->SetDiagMsg(fmt::format("An error occurred while writing {} bytes to file: {}", size, ex->DiagMsg()));
|
||||
ex->Rethrow();
|
||||
}
|
||||
|
|
|
@ -37,6 +37,8 @@
|
|||
|
||||
using namespace Threading;
|
||||
|
||||
class SysCoreThread;
|
||||
|
||||
class PINEServer : public pxThread
|
||||
{
|
||||
// parent thread
|
||||
|
|
|
@ -43,7 +43,3 @@
|
|||
#define PCSX2_DISCORD_URL "https://discord.com/invite/TCz3t9k"
|
||||
|
||||
static const bool PCSX2_isReleaseVersion = 0;
|
||||
|
||||
class SysCoreThread;
|
||||
|
||||
class CpuInitializerSet;
|
||||
|
|
163
pcsx2/System.cpp
163
pcsx2/System.cpp
|
@ -220,81 +220,6 @@ void SysLogMachineCaps()
|
|||
#endif
|
||||
}
|
||||
|
||||
template< typename CpuType >
|
||||
class CpuInitializer
|
||||
{
|
||||
public:
|
||||
std::unique_ptr<CpuType> MyCpu;
|
||||
ScopedExcept ExThrown;
|
||||
|
||||
CpuInitializer();
|
||||
virtual ~CpuInitializer();
|
||||
|
||||
bool IsAvailable() const
|
||||
{
|
||||
return !!MyCpu;
|
||||
}
|
||||
|
||||
CpuType* GetPtr() { return MyCpu.get(); }
|
||||
const CpuType* GetPtr() const { return MyCpu.get(); }
|
||||
|
||||
operator CpuType*() { return GetPtr(); }
|
||||
operator const CpuType*() const { return GetPtr(); }
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// CpuInitializer Template
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Helper for initializing various PCSX2 CPU providers, and handing errors and cleanup.
|
||||
//
|
||||
template< typename CpuType >
|
||||
CpuInitializer< CpuType >::CpuInitializer()
|
||||
{
|
||||
try {
|
||||
MyCpu = std::make_unique<CpuType>();
|
||||
MyCpu->Reserve();
|
||||
}
|
||||
catch( Exception::RuntimeError& ex )
|
||||
{
|
||||
Console.Error( "CPU provider error:\n\t%s", ex.FormatDiagnosticMessage().c_str() );
|
||||
MyCpu = nullptr;
|
||||
ExThrown = ScopedExcept(ex.Clone());
|
||||
}
|
||||
catch( std::runtime_error& ex )
|
||||
{
|
||||
Console.Error( "CPU provider error (STL Exception)\n\tDetails:%s", ex.what() );
|
||||
MyCpu = nullptr;
|
||||
ExThrown = ScopedExcept(new Exception::RuntimeError(ex));
|
||||
}
|
||||
}
|
||||
|
||||
template< typename CpuType >
|
||||
CpuInitializer< CpuType >::~CpuInitializer()
|
||||
{
|
||||
try {
|
||||
if (MyCpu)
|
||||
MyCpu->Shutdown();
|
||||
}
|
||||
DESTRUCTOR_CATCHALL
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// CpuInitializerSet
|
||||
// --------------------------------------------------------------------------------------
|
||||
class CpuInitializerSet
|
||||
{
|
||||
public:
|
||||
CpuInitializer<recMicroVU0> microVU0;
|
||||
CpuInitializer<recMicroVU1> microVU1;
|
||||
|
||||
CpuInitializer<InterpVU0> interpVU0;
|
||||
CpuInitializer<InterpVU1> interpVU1;
|
||||
|
||||
public:
|
||||
CpuInitializerSet() {}
|
||||
virtual ~CpuInitializerSet() = default;
|
||||
};
|
||||
|
||||
namespace HostMemoryMap {
|
||||
// For debuggers
|
||||
extern "C" {
|
||||
|
@ -419,90 +344,50 @@ SysCpuProviderPack::SysCpuProviderPack()
|
|||
Console.WriteLn( Color_StrongBlue, "Reserving memory for recompilers..." );
|
||||
ConsoleIndentScope indent(1);
|
||||
|
||||
CpuProviders = std::make_unique<CpuInitializerSet>();
|
||||
recCpu.Reserve();
|
||||
psxRec.Reserve();
|
||||
|
||||
try {
|
||||
recCpu.Reserve();
|
||||
}
|
||||
catch( Exception::RuntimeError& ex )
|
||||
{
|
||||
m_RecExceptionEE = ScopedExcept(ex.Clone());
|
||||
Console.Error( "EE Recompiler Reservation Failed:\n%s", ex.FormatDiagnosticMessage().c_str() );
|
||||
recCpu.Shutdown();
|
||||
}
|
||||
CpuMicroVU0.Reserve();
|
||||
CpuMicroVU1.Reserve();
|
||||
|
||||
try {
|
||||
psxRec.Reserve();
|
||||
}
|
||||
catch( Exception::RuntimeError& ex )
|
||||
{
|
||||
m_RecExceptionIOP = ScopedExcept(ex.Clone());
|
||||
Console.Error( "IOP Recompiler Reservation Failed:\n%s", ex.FormatDiagnosticMessage().c_str() );
|
||||
psxRec.Shutdown();
|
||||
}
|
||||
|
||||
// hmm! : VU0 and VU1 pre-allocations should do sVU and mVU separately? Sounds complicated. :(
|
||||
// TODO(Stenzek): error handling in this whole function...
|
||||
|
||||
if (newVifDynaRec)
|
||||
if constexpr (newVifDynaRec)
|
||||
{
|
||||
dVifReserve(0);
|
||||
dVifReserve(1);
|
||||
}
|
||||
}
|
||||
|
||||
bool SysCpuProviderPack::IsRecAvailable_MicroVU0() const { return CpuProviders->microVU0.IsAvailable(); }
|
||||
bool SysCpuProviderPack::IsRecAvailable_MicroVU1() const { return CpuProviders->microVU1.IsAvailable(); }
|
||||
BaseException* SysCpuProviderPack::GetException_MicroVU0() const { return CpuProviders->microVU0.ExThrown.get(); }
|
||||
BaseException* SysCpuProviderPack::GetException_MicroVU1() const { return CpuProviders->microVU1.ExThrown.get(); }
|
||||
|
||||
void SysCpuProviderPack::CleanupMess() noexcept
|
||||
{
|
||||
try
|
||||
{
|
||||
psxRec.Shutdown();
|
||||
recCpu.Shutdown();
|
||||
|
||||
if (newVifDynaRec)
|
||||
{
|
||||
dVifRelease(0);
|
||||
dVifRelease(1);
|
||||
}
|
||||
}
|
||||
DESTRUCTOR_CATCHALL
|
||||
}
|
||||
|
||||
SysCpuProviderPack::~SysCpuProviderPack()
|
||||
{
|
||||
CleanupMess();
|
||||
if (newVifDynaRec)
|
||||
{
|
||||
dVifRelease(1);
|
||||
dVifRelease(0);
|
||||
}
|
||||
|
||||
CpuMicroVU1.Shutdown();
|
||||
CpuMicroVU0.Shutdown();
|
||||
|
||||
psxRec.Shutdown();
|
||||
recCpu.Shutdown();
|
||||
}
|
||||
|
||||
bool SysCpuProviderPack::HadSomeFailures( const Pcsx2Config::RecompilerOptions& recOpts ) const
|
||||
{
|
||||
return (recOpts.EnableEE && !IsRecAvailable_EE()) ||
|
||||
(recOpts.EnableIOP && !IsRecAvailable_IOP()) ||
|
||||
(recOpts.EnableVU0 && !IsRecAvailable_MicroVU0()) ||
|
||||
(recOpts.EnableVU1 && !IsRecAvailable_MicroVU1())
|
||||
;
|
||||
|
||||
}
|
||||
|
||||
BaseVUmicroCPU* CpuVU0 = NULL;
|
||||
BaseVUmicroCPU* CpuVU1 = NULL;
|
||||
BaseVUmicroCPU* CpuVU0 = nullptr;
|
||||
BaseVUmicroCPU* CpuVU1 = nullptr;
|
||||
|
||||
void SysCpuProviderPack::ApplyConfig() const
|
||||
{
|
||||
Cpu = CHECK_EEREC ? &recCpu : &intCpu;
|
||||
psxCpu = CHECK_IOPREC ? &psxRec : &psxInt;
|
||||
|
||||
CpuVU0 = CpuProviders->interpVU0;
|
||||
CpuVU1 = CpuProviders->interpVU1;
|
||||
CpuVU0 = &CpuIntVU0;
|
||||
CpuVU1 = &CpuIntVU1;
|
||||
|
||||
if( EmuConfig.Cpu.Recompiler.EnableVU0 )
|
||||
CpuVU0 = (BaseVUmicroCPU*)CpuProviders->microVU0;
|
||||
CpuVU0 = &CpuMicroVU0;
|
||||
|
||||
if( EmuConfig.Cpu.Recompiler.EnableVU1 )
|
||||
CpuVU1 = (BaseVUmicroCPU*)CpuProviders->microVU1;
|
||||
CpuVU1 = &CpuMicroVU1;
|
||||
|
||||
#ifdef PCSX2_CORE
|
||||
if (GSDumpReplayer::IsReplayingDump())
|
||||
|
@ -526,8 +411,8 @@ void SysClearExecutionCache()
|
|||
psxCpu->Reset();
|
||||
|
||||
// mVU's VU0 needs to be properly initialized for macro mode even if it's not used for micro mode!
|
||||
if (CHECK_EEREC)
|
||||
((BaseVUmicroCPU*)GetCpuProviders().CpuProviders->microVU0)->Reset();
|
||||
if (CHECK_EEREC && !EmuConfig.Cpu.Recompiler.EnableVU0)
|
||||
CpuMicroVU0.Reset();
|
||||
|
||||
CpuVU0->Reset();
|
||||
CpuVU1->Reset();
|
||||
|
|
|
@ -136,33 +136,11 @@ protected:
|
|||
// --------------------------------------------------------------------------------------
|
||||
class SysCpuProviderPack
|
||||
{
|
||||
protected:
|
||||
ScopedExcept m_RecExceptionEE;
|
||||
ScopedExcept m_RecExceptionIOP;
|
||||
|
||||
public:
|
||||
std::unique_ptr<CpuInitializerSet> CpuProviders;
|
||||
|
||||
SysCpuProviderPack();
|
||||
virtual ~SysCpuProviderPack();
|
||||
~SysCpuProviderPack();
|
||||
|
||||
void ApplyConfig() const;
|
||||
|
||||
bool HadSomeFailures( const Pcsx2Config::RecompilerOptions& recOpts ) const;
|
||||
|
||||
bool IsRecAvailable_EE() const { return !m_RecExceptionEE; }
|
||||
bool IsRecAvailable_IOP() const { return !m_RecExceptionIOP; }
|
||||
|
||||
BaseException* GetException_EE() const { return m_RecExceptionEE.get(); }
|
||||
BaseException* GetException_IOP() const { return m_RecExceptionIOP.get(); }
|
||||
|
||||
bool IsRecAvailable_MicroVU0() const;
|
||||
bool IsRecAvailable_MicroVU1() const;
|
||||
BaseException* GetException_MicroVU0() const;
|
||||
BaseException* GetException_MicroVU1() const;
|
||||
|
||||
protected:
|
||||
void CleanupMess() noexcept;
|
||||
};
|
||||
|
||||
// GetCpuProviders - this function is not implemented by PCSX2 core -- it must be
|
||||
|
|
|
@ -236,6 +236,9 @@ void vu0Exec(VURegs* VU)
|
|||
// --------------------------------------------------------------------------------------
|
||||
// VU0microInterpreter
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
InterpVU0 CpuIntVU0;
|
||||
|
||||
InterpVU0::InterpVU0()
|
||||
{
|
||||
m_Idx = 0;
|
||||
|
|
|
@ -240,6 +240,8 @@ void vu1Exec(VURegs* VU)
|
|||
DbgCon.Error("VF[0].w != 1.0!!!!\n");
|
||||
}
|
||||
|
||||
InterpVU1 CpuIntVU1;
|
||||
|
||||
InterpVU1::InterpVU1()
|
||||
{
|
||||
m_Idx = 1;
|
||||
|
@ -255,12 +257,6 @@ void InterpVU1::Reset()
|
|||
VU1.ialuwritepos = 0;
|
||||
VU1.ialureadpos = 0;
|
||||
VU1.ialucount = 0;
|
||||
vu1Thread.WaitVU();
|
||||
}
|
||||
|
||||
void InterpVU1::Shutdown() noexcept
|
||||
{
|
||||
vu1Thread.WaitVU();
|
||||
}
|
||||
|
||||
void InterpVU1::SetStartPC(u32 startPC)
|
||||
|
|
184
pcsx2/VUmicro.h
184
pcsx2/VUmicro.h
|
@ -33,45 +33,30 @@ static const uint VU1_PROGMASK = VU1_PROGSIZE-1;
|
|||
|
||||
#define vu1RunCycles (3000000) // mVU1 uses this for inf loop detection on dev builds
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// BaseCpuProvider
|
||||
// --------------------------------------------------------------------------------------
|
||||
//
|
||||
// Design Note: This class is only partial C++ style. It still relies on Alloc and Shutdown
|
||||
// calls for memory and resource management. This is because the underlying implementations
|
||||
// of our CPU emulators don't have properly encapsulated objects yet -- if we allocate ram
|
||||
// in a constructor, it won't get free'd if an exception occurs during object construction.
|
||||
// Once we've resolved all the 'dangling pointers' and stuff in the recompilers, Alloc
|
||||
// and Shutdown can be removed in favor of constructor/destructor syntax.
|
||||
//
|
||||
class BaseCpuProvider
|
||||
{
|
||||
protected:
|
||||
// allocation counter for multiple calls to Reserve. Most implementations should utilize
|
||||
// this variable for sake of robustness.
|
||||
std::atomic<int> m_Reserved;
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// BaseVUmicroCPU
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Layer class for possible future implementation (currently is nothing more than a type-safe
|
||||
// type define).
|
||||
//
|
||||
class BaseVUmicroCPU
|
||||
{
|
||||
public:
|
||||
int m_Idx = 0;
|
||||
|
||||
// this boolean indicates to some generic logging facilities if the VU's registers
|
||||
// are valid for logging or not. (see DisVU1Micro.cpp, etc) [kinda hacky, might
|
||||
// be removed in the future]
|
||||
bool IsInterpreter;
|
||||
|
||||
public:
|
||||
BaseCpuProvider()
|
||||
BaseVUmicroCPU()
|
||||
{
|
||||
m_Reserved = 0;
|
||||
IsInterpreter = false;
|
||||
}
|
||||
|
||||
virtual ~BaseCpuProvider()
|
||||
{
|
||||
try {
|
||||
if( m_Reserved != 0 )
|
||||
Console.Warning( "Cleanup miscount detected on CPU provider. Count=%d", m_Reserved.load() );
|
||||
}
|
||||
DESTRUCTOR_CATCHALL
|
||||
}
|
||||
virtual ~BaseVUmicroCPU() = default;
|
||||
|
||||
virtual const char* GetShortName() const=0;
|
||||
virtual const char* GetLongName() const=0;
|
||||
|
@ -84,58 +69,20 @@ public:
|
|||
return 0;
|
||||
}
|
||||
|
||||
virtual void Reserve()=0;
|
||||
virtual void Shutdown()=0;
|
||||
virtual void Reset()=0;
|
||||
virtual void SetStartPC(u32 startPC)=0;
|
||||
virtual void Execute(u32 cycles)=0;
|
||||
virtual void ExecuteBlock(bool startUp)=0;
|
||||
|
||||
virtual void Step()=0;
|
||||
virtual void Clear(u32 Addr, u32 Size)=0;
|
||||
|
||||
// Executes a Block based on EE delta time (see VUmicro.cpp)
|
||||
void ExecuteBlock(bool startUp = 0);
|
||||
|
||||
// C++ Calling Conventions are unstable, and some compilers don't even allow us to take the
|
||||
// address of C++ methods. We need to use a wrapper function to invoke the ExecuteBlock from
|
||||
// recompiled code.
|
||||
static void ExecuteBlockJIT( BaseCpuProvider* cpu )
|
||||
{
|
||||
cpu->Execute(1024);
|
||||
}
|
||||
|
||||
// Gets the current cache reserve allocated to this CPU (value returned in megabytes)
|
||||
virtual uint GetCacheReserve() const=0;
|
||||
|
||||
// Specifies the maximum cache reserve amount for this CPU (value in megabytes).
|
||||
// CPU providers are allowed to reset their reserves (recompiler resets, etc) if such is
|
||||
// needed to conform to the new amount requested.
|
||||
virtual void SetCacheReserve( uint reserveInMegs ) const=0;
|
||||
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// BaseVUmicroCPU
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Layer class for possible future implementation (currently is nothing more than a type-safe
|
||||
// type define).
|
||||
//
|
||||
class BaseVUmicroCPU : public BaseCpuProvider {
|
||||
public:
|
||||
int m_Idx;
|
||||
|
||||
BaseVUmicroCPU() {
|
||||
m_Idx = 0;
|
||||
}
|
||||
virtual ~BaseVUmicroCPU() = default;
|
||||
|
||||
virtual void Step() {
|
||||
// Ideally this would fall back on interpretation for executing single instructions
|
||||
// for all CPU types, but due to VU complexities and large discrepancies between
|
||||
// clamping in recs and ints, it's not really worth bothering with yet.
|
||||
}
|
||||
|
||||
// Executes a Block based on EE delta time (see VUmicro.cpp)
|
||||
virtual void ExecuteBlock(bool startUp=0);
|
||||
|
||||
static void ExecuteBlockJIT(BaseVUmicroCPU* cpu, bool interlocked);
|
||||
|
||||
// VU1 sometimes needs to break execution on XGkick Path1 transfers if
|
||||
|
@ -144,100 +91,93 @@ public:
|
|||
virtual void ResumeXGkick() {}
|
||||
};
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// InterpVU0 / InterpVU1
|
||||
// --------------------------------------------------------------------------------------
|
||||
class InterpVU0 : public BaseVUmicroCPU
|
||||
class InterpVU0 final : public BaseVUmicroCPU
|
||||
{
|
||||
public:
|
||||
InterpVU0();
|
||||
virtual ~InterpVU0() { Shutdown(); }
|
||||
~InterpVU0() override { Shutdown(); }
|
||||
|
||||
const char* GetShortName() const { return "intVU0"; }
|
||||
const char* GetLongName() const { return "VU0 Interpreter"; }
|
||||
const char* GetShortName() const override { return "intVU0"; }
|
||||
const char* GetLongName() const override { return "VU0 Interpreter"; }
|
||||
|
||||
void Reserve() { }
|
||||
void Shutdown() noexcept { }
|
||||
void Reset();
|
||||
void Shutdown() override {}
|
||||
void Reset() override;
|
||||
|
||||
void Step();
|
||||
void SetStartPC(u32 startPC);
|
||||
void Execute(u32 cycles);
|
||||
void Clear(u32 addr, u32 size) {}
|
||||
|
||||
uint GetCacheReserve() const { return 0; }
|
||||
void SetCacheReserve( uint reserveInMegs ) const {}
|
||||
void Step() override;
|
||||
void SetStartPC(u32 startPC) override;
|
||||
void Execute(u32 cycles) override;
|
||||
void Clear(u32 addr, u32 size) override {}
|
||||
};
|
||||
|
||||
class InterpVU1 : public BaseVUmicroCPU
|
||||
class InterpVU1 final : public BaseVUmicroCPU
|
||||
{
|
||||
public:
|
||||
InterpVU1();
|
||||
virtual ~InterpVU1() { Shutdown(); }
|
||||
~InterpVU1() override { Shutdown(); }
|
||||
|
||||
const char* GetShortName() const { return "intVU1"; }
|
||||
const char* GetLongName() const { return "VU1 Interpreter"; }
|
||||
const char* GetShortName() const override { return "intVU1"; }
|
||||
const char* GetLongName() const override { return "VU1 Interpreter"; }
|
||||
|
||||
void Reserve() { }
|
||||
void Shutdown() noexcept;
|
||||
void Reset();
|
||||
void Shutdown() override {}
|
||||
void Reset() override;
|
||||
|
||||
void SetStartPC(u32 startPC);
|
||||
void Step();
|
||||
void Execute(u32 cycles);
|
||||
void Clear(u32 addr, u32 size) {}
|
||||
void ResumeXGkick() {}
|
||||
|
||||
uint GetCacheReserve() const { return 0; }
|
||||
void SetCacheReserve( uint reserveInMegs ) const {}
|
||||
void SetStartPC(u32 startPC) override;
|
||||
void Step() override;
|
||||
void Execute(u32 cycles) override;
|
||||
void Clear(u32 addr, u32 size) override {}
|
||||
void ResumeXGkick() override {}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// recMicroVU0 / recMicroVU1
|
||||
// --------------------------------------------------------------------------------------
|
||||
class recMicroVU0 : public BaseVUmicroCPU
|
||||
class recMicroVU0 final : public BaseVUmicroCPU
|
||||
{
|
||||
public:
|
||||
recMicroVU0();
|
||||
virtual ~recMicroVU0() { Shutdown(); }
|
||||
~recMicroVU0() override { Shutdown(); }
|
||||
|
||||
const char* GetShortName() const { return "mVU0"; }
|
||||
const char* GetLongName() const { return "microVU0 Recompiler"; }
|
||||
const char* GetShortName() const override { return "mVU0"; }
|
||||
const char* GetLongName() const override { return "microVU0 Recompiler"; }
|
||||
|
||||
void Reserve();
|
||||
void Shutdown() noexcept;
|
||||
void Shutdown() override;
|
||||
|
||||
void Reset();
|
||||
void SetStartPC(u32 startPC);
|
||||
void Execute(u32 cycles);
|
||||
void Clear(u32 addr, u32 size);
|
||||
|
||||
uint GetCacheReserve() const;
|
||||
void SetCacheReserve( uint reserveInMegs ) const;
|
||||
void Reset() override;
|
||||
void Step() override;
|
||||
void SetStartPC(u32 startPC) override;
|
||||
void Execute(u32 cycles) override;
|
||||
void Clear(u32 addr, u32 size) override;
|
||||
};
|
||||
|
||||
class recMicroVU1 : public BaseVUmicroCPU
|
||||
class recMicroVU1 final : public BaseVUmicroCPU
|
||||
{
|
||||
public:
|
||||
recMicroVU1();
|
||||
virtual ~recMicroVU1() { Shutdown(); }
|
||||
|
||||
const char* GetShortName() const { return "mVU1"; }
|
||||
const char* GetLongName() const { return "microVU1 Recompiler"; }
|
||||
const char* GetShortName() const override { return "mVU1"; }
|
||||
const char* GetLongName() const override { return "microVU1 Recompiler"; }
|
||||
|
||||
void Reserve();
|
||||
void Shutdown() noexcept;
|
||||
void Reset();
|
||||
void SetStartPC(u32 startPC);
|
||||
void Execute(u32 cycles);
|
||||
void Clear(u32 addr, u32 size);
|
||||
void ResumeXGkick();
|
||||
|
||||
uint GetCacheReserve() const;
|
||||
void SetCacheReserve( uint reserveInMegs ) const;
|
||||
void Shutdown() override;
|
||||
void Reset() override;
|
||||
void Step() override;
|
||||
void SetStartPC(u32 startPC) override;
|
||||
void Execute(u32 cycles) override;
|
||||
void Clear(u32 addr, u32 size) override;
|
||||
void ResumeXGkick() override;
|
||||
};
|
||||
|
||||
extern InterpVU0 CpuIntVU0;
|
||||
extern InterpVU1 CpuIntVU1;
|
||||
|
||||
extern recMicroVU0 CpuMicroVU0;
|
||||
extern recMicroVU1 CpuMicroVU1;
|
||||
|
||||
extern BaseVUmicroCPU* CpuVU0;
|
||||
extern BaseVUmicroCPU* CpuVU1;
|
||||
|
||||
|
|
|
@ -201,25 +201,6 @@ enum MenuIdentifiers
|
|||
|
||||
};
|
||||
|
||||
namespace Exception
|
||||
{
|
||||
// --------------------------------------------------------------------------
|
||||
// Exception used to perform an "errorless" termination of the app during OnInit
|
||||
// procedures. This happens when a user cancels out of startup prompts/wizards.
|
||||
//
|
||||
class StartupAborted : public CancelEvent
|
||||
{
|
||||
DEFINE_RUNTIME_EXCEPTION(StartupAborted, CancelEvent, "Startup initialization was aborted by the user.")
|
||||
|
||||
public:
|
||||
StartupAborted(std::string reason)
|
||||
{
|
||||
m_message_diag = "Startup aborted: " + reason;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Exception
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// AppImageIds - Config and Toolbar Images and Icons
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
|
|
@ -73,7 +73,7 @@ void Pcsx2App::DetectCpuAndUserMode()
|
|||
{
|
||||
// This code will probably never run if the binary was correctly compiled for SSE4
|
||||
// SSE4 is required for any decent speed and is supported by more than decade old x86 CPUs
|
||||
throw Exception::HardwareDeficiency()
|
||||
throw Exception::RuntimeError()
|
||||
.SetDiagMsg("Critical Failure: SSE4.1 Extensions not available.")
|
||||
.SetUserMsg("SSE4 extensions are not available. PCSX2 requires a cpu that supports the SSE4.1 instruction set.");
|
||||
}
|
||||
|
@ -171,55 +171,6 @@ void Pcsx2App::AllocateCoreStuffs()
|
|||
// so that the thread is safely blocked from being able to start emulation.
|
||||
|
||||
m_CpuProviders = std::make_unique<SysCpuProviderPack>();
|
||||
|
||||
if (m_CpuProviders->HadSomeFailures(g_Conf->EmuOptions.Cpu.Recompiler))
|
||||
{
|
||||
// HadSomeFailures only returns 'true' if an *enabled* cpu type fails to init. If
|
||||
// the user already has all interps configured, for example, then no point in
|
||||
// popping up this dialog.
|
||||
|
||||
wxDialogWithHelpers exconf(NULL, _("PCSX2 Recompiler Error(s)"));
|
||||
|
||||
wxTextCtrl* scrollableTextArea = new wxTextCtrl(
|
||||
&exconf, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
|
||||
wxTE_READONLY | wxTE_MULTILINE | wxTE_WORDWRAP);
|
||||
|
||||
exconf += 12;
|
||||
exconf += exconf.Heading(pxE(L"Warning: Some of the configured PS2 recompilers failed to initialize and have been disabled:"));
|
||||
|
||||
exconf += 6;
|
||||
exconf += scrollableTextArea | pxExpand.Border(wxALL, 16);
|
||||
|
||||
Pcsx2Config::RecompilerOptions& recOps = g_Conf->EmuOptions.Cpu.Recompiler;
|
||||
|
||||
if (BaseException* ex = m_CpuProviders->GetException_EE())
|
||||
{
|
||||
scrollableTextArea->AppendText(StringUtil::UTF8StringToWxString("* R5900 (EE)\n\t" + ex->FormatDisplayMessage() + "\n\n"));
|
||||
recOps.EnableEE = false;
|
||||
}
|
||||
|
||||
if (BaseException* ex = m_CpuProviders->GetException_IOP())
|
||||
{
|
||||
scrollableTextArea->AppendText(StringUtil::UTF8StringToWxString("* R3000A (IOP)\n\t" + ex->FormatDisplayMessage() + "\n\n"));
|
||||
recOps.EnableIOP = false;
|
||||
}
|
||||
|
||||
if (BaseException* ex = m_CpuProviders->GetException_MicroVU0())
|
||||
{
|
||||
scrollableTextArea->AppendText(StringUtil::UTF8StringToWxString("* microVU0\n\t" + ex->FormatDisplayMessage() + "\n\n"));
|
||||
recOps.EnableVU0 = false;
|
||||
}
|
||||
|
||||
if (BaseException* ex = m_CpuProviders->GetException_MicroVU1())
|
||||
{
|
||||
scrollableTextArea->AppendText(StringUtil::UTF8StringToWxString("* microVU1\n\t" + ex->FormatDisplayMessage() + "\n\n"));
|
||||
recOps.EnableVU1 = false;
|
||||
}
|
||||
|
||||
exconf += exconf.Heading(pxE(L"Note: Recompilers are not necessary for PCSX2 to run, however they typically improve emulation speed substantially. You may have to manually re-enable the recompilers listed above, if you resolve the errors."));
|
||||
|
||||
pxIssueConfirmation(exconf, MsgButtons().OK());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -517,12 +468,6 @@ bool Pcsx2App::OnInit()
|
|||
CleanupOnExit();
|
||||
return false;
|
||||
}
|
||||
catch (Exception::HardwareDeficiency& ex)
|
||||
{
|
||||
Msgbox::Alert(StringUtil::UTF8StringToWxString(ex.FormatDisplayMessage()) + L"\n\n" + AddAppName(_("Press OK to close %s.")), _("PCSX2 Error: Hardware Deficiency."));
|
||||
CleanupOnExit();
|
||||
return false;
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
// Failures on the core initialization procedure (typically OutOfMemory errors) are bad,
|
||||
// since it means the emulator is completely non-functional. Let's pop up an error and
|
||||
|
|
|
@ -98,6 +98,43 @@ void Pcsx2App::PostMenuAction( MenuIdentifiers menu_id ) const
|
|||
mainFrame->GetEventHandler()->AddPendingEvent( joe );
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Exception::WinApiError (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
Exception::WinApiError::WinApiError()
|
||||
{
|
||||
ErrorId = GetLastError();
|
||||
m_message_diag = "Unspecified Windows API error.";
|
||||
}
|
||||
|
||||
std::string Exception::WinApiError::GetMsgFromWindows() const
|
||||
{
|
||||
if (!ErrorId)
|
||||
return "No valid error number was assigned to this exception!";
|
||||
|
||||
const DWORD BUF_LEN = 2048;
|
||||
wchar_t t_Msg[BUF_LEN];
|
||||
if (FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, 0, ErrorId, 0, t_Msg, BUF_LEN, 0))
|
||||
return fmt::format("Win32 Error #{}: {}", ErrorId, StringUtil::WideStringToUTF8String(t_Msg));
|
||||
|
||||
return fmt::format("Win32 Error #{} (no text msg available)", ErrorId);
|
||||
}
|
||||
|
||||
std::string Exception::WinApiError::FormatDisplayMessage() const
|
||||
{
|
||||
return m_message_user + "\n\n" + GetMsgFromWindows();
|
||||
}
|
||||
|
||||
std::string Exception::WinApiError::FormatDiagnosticMessage() const
|
||||
{
|
||||
return m_message_diag + "\n\t" + GetMsgFromWindows();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Pcsx2AppMethodEvent
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
|
|
@ -126,7 +126,7 @@ Threading::MutexRecursive::MutexRecursive()
|
|||
if (++_attr_refcount == 1)
|
||||
{
|
||||
if (0 != pthread_mutexattr_init(&_attr_recursive))
|
||||
throw Exception::OutOfMemory("Recursive mutexing attributes");
|
||||
pxFailRel("pthread_mutexattr_init() failed");
|
||||
|
||||
pthread_mutexattr_settype(&_attr_recursive, PTHREAD_MUTEX_RECURSIVE);
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "common/Path.h"
|
||||
#include "common/Assertions.h"
|
||||
#include "common/Exceptions.h"
|
||||
#include "gui/PersistentThread.h"
|
||||
#include "wxDirName.h"
|
||||
|
||||
#include <wx/file.h>
|
||||
|
|
|
@ -95,9 +95,82 @@ extern ConsoleLogSource_Threading pxConLog_Thread;
|
|||
|
||||
#define pxThreadLog pxConLog_Thread.IsActive() && pxConLog_Thread
|
||||
|
||||
using ScopedExcept = std::unique_ptr<Exception::BaseException>;
|
||||
|
||||
namespace Exception
|
||||
{
|
||||
// --------------------------------------------------------------------------------------
|
||||
// CancelAppEvent - Exception for canceling an event in a non-verbose fashion
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Typically the PCSX2 interface issues popup dialogs for runtime errors. This exception
|
||||
// instead issues a "silent" cancelation that is handled by the app gracefully (generates
|
||||
// log, and resumes messages queue processing).
|
||||
//
|
||||
// I chose to have this exception derive from RuntimeError, since if one is thrown from outside
|
||||
// an App message loop we'll still want it to be handled in a reasonably graceful manner.
|
||||
class CancelEvent : public RuntimeError
|
||||
{
|
||||
DEFINE_RUNTIME_EXCEPTION(CancelEvent, RuntimeError, "No reason given.")
|
||||
|
||||
public:
|
||||
explicit CancelEvent(std::string logmsg)
|
||||
{
|
||||
m_message_diag = std::move(logmsg);
|
||||
// overridden message formatters only use the diagnostic version...
|
||||
}
|
||||
|
||||
virtual std::string FormatDisplayMessage() const override
|
||||
{
|
||||
return "Action canceled: " + m_message_diag;
|
||||
}
|
||||
|
||||
virtual std::string FormatDiagnosticMessage() const override
|
||||
{
|
||||
return "Action canceled: " + m_message_diag;
|
||||
}
|
||||
};
|
||||
|
||||
class ParseError : public RuntimeError
|
||||
{
|
||||
DEFINE_RUNTIME_EXCEPTION(ParseError, RuntimeError, "Parse error");
|
||||
};
|
||||
|
||||
#ifdef _WIN32
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Exception::WinApiError
|
||||
// --------------------------------------------------------------------------------------
|
||||
class WinApiError : public RuntimeError
|
||||
{
|
||||
DEFINE_EXCEPTION_COPYTORS(WinApiError, RuntimeError)
|
||||
DEFINE_EXCEPTION_MESSAGES(WinApiError)
|
||||
|
||||
public:
|
||||
int ErrorId;
|
||||
|
||||
public:
|
||||
WinApiError();
|
||||
|
||||
std::string GetMsgFromWindows() const;
|
||||
virtual std::string FormatDisplayMessage() const override;
|
||||
virtual std::string FormatDiagnosticMessage() const override;
|
||||
};
|
||||
#endif
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Exception used to perform an "errorless" termination of the app during OnInit
|
||||
// procedures. This happens when a user cancels out of startup prompts/wizards.
|
||||
//
|
||||
class StartupAborted : public CancelEvent
|
||||
{
|
||||
DEFINE_RUNTIME_EXCEPTION(StartupAborted, CancelEvent, "Startup initialization was aborted by the user.")
|
||||
|
||||
public:
|
||||
StartupAborted(std::string reason)
|
||||
{
|
||||
m_message_diag = "Startup aborted: " + reason;
|
||||
}
|
||||
};
|
||||
|
||||
class BaseThreadError : public RuntimeError
|
||||
{
|
||||
DEFINE_EXCEPTION_COPYTORS(BaseThreadError, RuntimeError)
|
||||
|
@ -125,8 +198,8 @@ namespace Exception
|
|||
m_message_diag = "An unspecified thread-related error occurred (thread=%s)";
|
||||
}
|
||||
|
||||
virtual std::string FormatDiagnosticMessage() const;
|
||||
virtual std::string FormatDisplayMessage() const;
|
||||
virtual std::string FormatDiagnosticMessage() const override;
|
||||
virtual std::string FormatDisplayMessage() const override;
|
||||
|
||||
Threading::pxThread& Thread();
|
||||
const Threading::pxThread& Thread() const;
|
||||
|
@ -151,6 +224,47 @@ namespace Exception
|
|||
};
|
||||
} // namespace Exception
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// DESTRUCTOR_CATCHALL - safe destructor helper
|
||||
// --------------------------------------------------------------------------------------
|
||||
// In C++ destructors *really* need to be "nothrow" garaunteed, otherwise you can have
|
||||
// disasterous nested exception throws during the unwinding process of an originating
|
||||
// exception. Use this macro to dispose of these dangerous exceptions, and generate a
|
||||
// friendly error log in their wake.
|
||||
//
|
||||
// Note: Console can also fire an Exception::OutOfMemory
|
||||
#define __DESTRUCTOR_CATCHALL(funcname) \
|
||||
catch (BaseException & ex) \
|
||||
{ \
|
||||
try \
|
||||
{ \
|
||||
Console.Error("Unhandled BaseException in %s (ignored!):", funcname); \
|
||||
Console.Error(ex.FormatDiagnosticMessage()); \
|
||||
} \
|
||||
catch (...) \
|
||||
{ \
|
||||
fprintf(stderr, "ERROR: (out of memory?)\n"); \
|
||||
} \
|
||||
} \
|
||||
catch (std::exception & ex) \
|
||||
{ \
|
||||
try \
|
||||
{ \
|
||||
Console.Error("Unhandled std::exception in %s (ignored!):", funcname); \
|
||||
Console.Error(ex.what()); \
|
||||
} \
|
||||
catch (...) \
|
||||
{ \
|
||||
fprintf(stderr, "ERROR: (out of memory?)\n"); \
|
||||
} \
|
||||
} \
|
||||
catch (...) \
|
||||
{ \
|
||||
/* Unreachable code */ \
|
||||
}
|
||||
|
||||
#define DESTRUCTOR_CATCHALL __DESTRUCTOR_CATCHALL(__pxFUNCTION__)
|
||||
|
||||
namespace Threading
|
||||
{
|
||||
extern void pxTestCancel();
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "common/Exceptions.h"
|
||||
#include "common/StringUtil.h"
|
||||
#include "common/Pcsx2Defs.h"
|
||||
#include "PersistentThread.h"
|
||||
#include "StringHelpers.h"
|
||||
|
||||
__fi wxString fromUTF8(const char* src)
|
||||
|
|
|
@ -693,7 +693,7 @@ static u8* m_recBlockAlloc = NULL;
|
|||
static const uint m_recBlockAllocSize =
|
||||
(((Ps2MemSize::IopRam + Ps2MemSize::Rom + Ps2MemSize::Rom1 + Ps2MemSize::Rom2) / 4) * sizeof(BASEBLOCK));
|
||||
|
||||
static void recReserveCache()
|
||||
static void recReserve()
|
||||
{
|
||||
if (recMem)
|
||||
return;
|
||||
|
@ -703,24 +703,19 @@ static void recReserveCache()
|
|||
recMem->Assign(GetVmMemory().CodeMemory(), HostMemoryMap::IOPrecOffset, 32 * _1mb);
|
||||
}
|
||||
|
||||
static void recReserve()
|
||||
{
|
||||
// IOP has no hardware requirements!
|
||||
|
||||
recReserveCache();
|
||||
}
|
||||
|
||||
static void recAlloc()
|
||||
{
|
||||
// Goal: Allocate BASEBLOCKs for every possible branch target in IOP memory.
|
||||
// Any 4-byte aligned address makes a valid branch target as per MIPS design (all instructions are
|
||||
// always 4 bytes long).
|
||||
|
||||
if (m_recBlockAlloc == NULL)
|
||||
if (!m_recBlockAlloc)
|
||||
{
|
||||
// We're on 64-bit, if these memory allocations fail, we're in real trouble.
|
||||
m_recBlockAlloc = (u8*)_aligned_malloc(m_recBlockAllocSize, 4096);
|
||||
|
||||
if (m_recBlockAlloc == NULL)
|
||||
throw Exception::OutOfMemory("R3000A BASEBLOCK lookup tables");
|
||||
if (!m_recBlockAlloc)
|
||||
pxFailRel("Failed to allocate R3000A BASEBLOCK lookup tables");
|
||||
}
|
||||
|
||||
u8* curpos = m_recBlockAlloc;
|
||||
recRAM = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::IopRam / 4) * sizeof(BASEBLOCK);
|
||||
|
@ -729,15 +724,14 @@ static void recAlloc()
|
|||
recROM2 = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::Rom2 / 4) * sizeof(BASEBLOCK);
|
||||
|
||||
|
||||
if (s_pInstCache == NULL)
|
||||
if (!s_pInstCache)
|
||||
{
|
||||
s_nInstCacheSize = 128;
|
||||
s_pInstCache = (EEINST*)malloc(sizeof(EEINST) * s_nInstCacheSize);
|
||||
if (!s_pInstCache)
|
||||
pxFailRel("Failed to allocate R3000 InstCache array.");
|
||||
}
|
||||
|
||||
if (s_pInstCache == NULL)
|
||||
throw Exception::OutOfMemory("R3000 InstCache.");
|
||||
|
||||
_DynGen_Dispatchers();
|
||||
}
|
||||
|
||||
|
|
|
@ -543,15 +543,7 @@ static __ri void ClearRecLUT(BASEBLOCK* base, int memsize)
|
|||
base[i].SetFnptr((uptr)JITCompile);
|
||||
}
|
||||
|
||||
|
||||
static void recThrowHardwareDeficiency(const char* extFail)
|
||||
{
|
||||
throw Exception::HardwareDeficiency()
|
||||
.SetDiagMsg(fmt::format("R5900-32 recompiler init failed: {} is not available.", extFail))
|
||||
.SetUserMsg(fmt::format("{} Extensions not found. The R5900-32 recompiler requires a host CPU with SSE2 extensions.", extFail));
|
||||
}
|
||||
|
||||
static void recReserveCache()
|
||||
static void recReserve()
|
||||
{
|
||||
if (recMem)
|
||||
return;
|
||||
|
@ -561,16 +553,6 @@ static void recReserveCache()
|
|||
recMem->Assign(GetVmMemory().CodeMemory(), HostMemoryMap::EErecOffset, 64 * _1mb);
|
||||
}
|
||||
|
||||
static void recReserve()
|
||||
{
|
||||
// Hardware Requirements Check...
|
||||
|
||||
if (!x86caps.hasStreamingSIMD4Extensions)
|
||||
recThrowHardwareDeficiency("SSE4");
|
||||
|
||||
recReserveCache();
|
||||
}
|
||||
|
||||
static void recAlloc()
|
||||
{
|
||||
if (!recRAMCopy)
|
||||
|
@ -629,11 +611,10 @@ static void recAlloc()
|
|||
{
|
||||
s_nInstCacheSize = 128;
|
||||
s_pInstCache = (EEINST*)malloc(sizeof(EEINST) * s_nInstCacheSize);
|
||||
if (!s_pInstCache)
|
||||
pxFailRel("Failed to allocate R5900-32 InstCache array");
|
||||
}
|
||||
|
||||
if (s_pInstCache == NULL)
|
||||
throw Exception::OutOfMemory("R5900-32 InstCache");
|
||||
|
||||
// No errors.. Proceed with initialization:
|
||||
|
||||
_DynGen_Dispatchers();
|
||||
|
@ -719,7 +700,7 @@ void recStep()
|
|||
|
||||
static fastjmp_buf m_SetJmp_StateCheck;
|
||||
static std::unique_ptr<BaseR5900Exception> m_cpuException;
|
||||
static ScopedExcept m_Exception;
|
||||
static std::unique_ptr<BaseException> m_Exception;
|
||||
|
||||
static void recExitExecution()
|
||||
{
|
||||
|
@ -2405,7 +2386,7 @@ static void recThrowException(const BaseException& ex)
|
|||
{
|
||||
if (!eeCpuExecuting)
|
||||
ex.Rethrow();
|
||||
m_Exception = ScopedExcept(ex.Clone());
|
||||
m_Exception = std::unique_ptr<BaseException>(ex.Clone());
|
||||
recExitExecution();
|
||||
}
|
||||
|
||||
|
|
|
@ -28,13 +28,6 @@
|
|||
alignas(__pagesize) static u8 vu0_RecDispatchers[mVUdispCacheSize];
|
||||
alignas(__pagesize) static u8 vu1_RecDispatchers[mVUdispCacheSize];
|
||||
|
||||
static __fi void mVUthrowHardwareDeficiency(const char* extFail, int vuIndex)
|
||||
{
|
||||
throw Exception::HardwareDeficiency()
|
||||
.SetDiagMsg(fmt::format("microVU{} recompiler init failed: %s is not available.", vuIndex, extFail))
|
||||
.SetUserMsg(fmt::format("{} Extensions not found. microVU requires a host CPU with SSE4 extensions.", extFail));
|
||||
}
|
||||
|
||||
void mVUreserveCache(microVU& mVU)
|
||||
{
|
||||
mVU.cache_reserve = new RecompiledCodeReserve(StringUtil::StdStringFromFormat("Micro VU%u Recompiler Cache", mVU.index));
|
||||
|
@ -48,10 +41,6 @@ void mVUreserveCache(microVU& mVU)
|
|||
// Only run this once per VU! ;)
|
||||
void mVUinit(microVU& mVU, uint vuIndex)
|
||||
{
|
||||
|
||||
if (!x86caps.hasStreamingSIMD4Extensions)
|
||||
mVUthrowHardwareDeficiency("SSE4", vuIndex);
|
||||
|
||||
memzero(mVU.prog);
|
||||
|
||||
mVU.index = vuIndex;
|
||||
|
@ -357,47 +346,44 @@ _mVUt __fi void* mVUsearchProg(u32 startPC, uptr pState)
|
|||
//------------------------------------------------------------------
|
||||
// recMicroVU0 / recMicroVU1
|
||||
//------------------------------------------------------------------
|
||||
|
||||
recMicroVU0 CpuMicroVU0;
|
||||
recMicroVU1 CpuMicroVU1;
|
||||
|
||||
recMicroVU0::recMicroVU0() { m_Idx = 0; IsInterpreter = false; }
|
||||
recMicroVU1::recMicroVU1() { m_Idx = 1; IsInterpreter = false; }
|
||||
|
||||
void recMicroVU0::Reserve()
|
||||
{
|
||||
if (m_Reserved.exchange(1) == 0)
|
||||
mVUinit(microVU0, 0);
|
||||
mVUinit(microVU0, 0);
|
||||
}
|
||||
void recMicroVU1::Reserve()
|
||||
{
|
||||
if (m_Reserved.exchange(1) == 0)
|
||||
{
|
||||
mVUinit(microVU1, 1);
|
||||
vu1Thread.Open();
|
||||
}
|
||||
mVUinit(microVU1, 1);
|
||||
vu1Thread.Open();
|
||||
}
|
||||
|
||||
void recMicroVU0::Shutdown() noexcept
|
||||
void recMicroVU0::Shutdown()
|
||||
{
|
||||
if (m_Reserved.exchange(0) == 1)
|
||||
mVUclose(microVU0);
|
||||
mVUclose(microVU0);
|
||||
}
|
||||
void recMicroVU1::Shutdown() noexcept
|
||||
void recMicroVU1::Shutdown()
|
||||
{
|
||||
if (m_Reserved.exchange(0) == 1)
|
||||
{
|
||||
vu1Thread.WaitVU();
|
||||
mVUclose(microVU1);
|
||||
}
|
||||
vu1Thread.WaitVU();
|
||||
mVUclose(microVU1);
|
||||
}
|
||||
|
||||
void recMicroVU0::Reset()
|
||||
{
|
||||
if (!pxAssertDev(m_Reserved, "MicroVU0 CPU Provider has not been reserved prior to reset!"))
|
||||
return;
|
||||
mVUreset(microVU0, true);
|
||||
}
|
||||
|
||||
void recMicroVU0::Step()
|
||||
{
|
||||
}
|
||||
|
||||
void recMicroVU1::Reset()
|
||||
{
|
||||
if (!pxAssertDev(m_Reserved, "MicroVU1 CPU Provider has not been reserved prior to reset!"))
|
||||
return;
|
||||
vu1Thread.WaitVU();
|
||||
vu1Thread.Get_MTVUChanges();
|
||||
mVUreset(microVU1, true);
|
||||
|
@ -410,8 +396,6 @@ void recMicroVU0::SetStartPC(u32 startPC)
|
|||
|
||||
void recMicroVU0::Execute(u32 cycles)
|
||||
{
|
||||
pxAssert(m_Reserved); // please allocate me first! :|
|
||||
|
||||
VU0.flags &= ~VUFLAG_MFLAGSET;
|
||||
|
||||
if (!(VU0.VI[REG_VPU_STAT].UL & 1))
|
||||
|
@ -432,10 +416,12 @@ void recMicroVU1::SetStartPC(u32 startPC)
|
|||
VU1.start_pc = startPC;
|
||||
}
|
||||
|
||||
void recMicroVU1::Step()
|
||||
{
|
||||
}
|
||||
|
||||
void recMicroVU1::Execute(u32 cycles)
|
||||
{
|
||||
pxAssert(m_Reserved); // please allocate me first! :|
|
||||
|
||||
if (!THREAD_VU1)
|
||||
{
|
||||
if (!(VU0.VI[REG_VPU_STAT].UL & 0x100))
|
||||
|
@ -453,43 +439,15 @@ void recMicroVU1::Execute(u32 cycles)
|
|||
|
||||
void recMicroVU0::Clear(u32 addr, u32 size)
|
||||
{
|
||||
pxAssert(m_Reserved); // please allocate me first! :|
|
||||
mVUclear(microVU0, addr, size);
|
||||
}
|
||||
void recMicroVU1::Clear(u32 addr, u32 size)
|
||||
{
|
||||
pxAssert(m_Reserved); // please allocate me first! :|
|
||||
mVUclear(microVU1, addr, size);
|
||||
}
|
||||
|
||||
uint recMicroVU0::GetCacheReserve() const
|
||||
{
|
||||
return microVU0.cacheSize;
|
||||
}
|
||||
uint recMicroVU1::GetCacheReserve() const
|
||||
{
|
||||
return microVU1.cacheSize;
|
||||
}
|
||||
|
||||
void recMicroVU0::SetCacheReserve(uint reserveInMegs) const
|
||||
{
|
||||
DevCon.WriteLn("microVU0: Changing cache size [%dmb]", reserveInMegs);
|
||||
microVU0.cacheSize = std::min(reserveInMegs, mVUcacheReserve);
|
||||
safe_delete(microVU0.cache_reserve); // I assume this unmaps the memory
|
||||
mVUreserveCache(microVU0); // Need rec-reset after this
|
||||
}
|
||||
void recMicroVU1::SetCacheReserve(uint reserveInMegs) const
|
||||
{
|
||||
DevCon.WriteLn("microVU1: Changing cache size [%dmb]", reserveInMegs);
|
||||
microVU1.cacheSize = std::min(reserveInMegs, mVUcacheReserve);
|
||||
safe_delete(microVU1.cache_reserve); // I assume this unmaps the memory
|
||||
mVUreserveCache(microVU1); // Need rec-reset after this
|
||||
}
|
||||
|
||||
void recMicroVU1::ResumeXGkick()
|
||||
{
|
||||
pxAssert(m_Reserved); // please allocate me first! :|
|
||||
|
||||
if (!(VU0.VI[REG_VPU_STAT].UL & 0x100))
|
||||
return;
|
||||
((mVUrecCallXG)microVU1.startFunctXG)();
|
||||
|
|
|
@ -79,4 +79,4 @@ alignas(16) extern nVifStruct nVif[2];
|
|||
alignas(16) extern nVifCall nVifUpk[(2 * 2 * 16) * 4]; // ([USN][Masking][Unpack Type]) [curCycle]
|
||||
alignas(16) extern u32 nVifMask[3][4][4]; // [MaskNumber][CycleNumber][Vector]
|
||||
|
||||
static const bool newVifDynaRec = 1; // Use code in newVif_Dynarec.inl
|
||||
static constexpr bool newVifDynaRec = 1; // Use code in newVif_Dynarec.inl
|
||||
|
|
|
@ -98,8 +98,7 @@ public:
|
|||
// Performance note: 64B align to reduce cache miss penalty in `find`
|
||||
if ((m_bucket[b] = (nVifBlock*)pcsx2_aligned_realloc(m_bucket[b], sizeof(nVifBlock) * (size + 2), 64, sizeof(nVifBlock) * (size + 1))) == NULL)
|
||||
{
|
||||
throw Exception::OutOfMemory(
|
||||
fmt::format("HashBucket Chain (bucket size={})", size + 2));
|
||||
pxFailRel("Failed to allocate HashBucket Chain");
|
||||
}
|
||||
|
||||
// Replace the empty cell by the new block and create a new empty cell
|
||||
|
@ -140,7 +139,7 @@ public:
|
|||
{
|
||||
if ((bucket = (nVifBlock*)_aligned_malloc(sizeof(nVifBlock), 64)) == nullptr)
|
||||
{
|
||||
throw Exception::OutOfMemory(fmt::format("HashBucket Chain (bucket size=%d)", 1));
|
||||
pxFailRel("Failed to allocate HashBucket Chain on reset");
|
||||
}
|
||||
|
||||
memset(bucket, 0, sizeof(nVifBlock));
|
||||
|
|
Loading…
Reference in New Issue