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:
Connor McLaughlin 2022-10-13 01:42:36 +10:00 committed by refractionpcsx2
parent 00bcb4cf02
commit d446e40741
24 changed files with 307 additions and 755 deletions

View File

@ -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)));
}
}

View File

@ -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;

View File

@ -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)
{

View File

@ -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;

View File

@ -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();
}

View File

@ -37,6 +37,8 @@
using namespace Threading;
class SysCoreThread;
class PINEServer : public pxThread
{
// parent thread

View File

@ -43,7 +43,3 @@
#define PCSX2_DISCORD_URL "https://discord.com/invite/TCz3t9k"
static const bool PCSX2_isReleaseVersion = 0;
class SysCoreThread;
class CpuInitializerSet;

View File

@ -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();

View File

@ -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

View File

@ -236,6 +236,9 @@ void vu0Exec(VURegs* VU)
// --------------------------------------------------------------------------------------
// VU0microInterpreter
// --------------------------------------------------------------------------------------
InterpVU0 CpuIntVU0;
InterpVU0::InterpVU0()
{
m_Idx = 0;

View File

@ -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)

View File

@ -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;

View File

@ -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
// --------------------------------------------------------------------------------------

View File

@ -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

View File

@ -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
// --------------------------------------------------------------------------------------

View File

@ -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);
}

View File

@ -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>

View File

@ -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();

View File

@ -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)

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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)();

View File

@ -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

View File

@ -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));