mirror of https://github.com/PCSX2/pcsx2.git
Common: reformat (#4720)
* common: format AlignedMalloc.cpp * common: format AppTrait.h * common: format Assertions.h * common: format CheckedStaticBox * common: format Console * common: format Dependencies.h * common: format EmbeddedImage * common: format EventSource * common: format Exceptions * common: format FastFormatString.cpp * common: format General.h * common: format InitInterface * common: format MathUtils.h * common: format MemsetFast/MemcpyFast * common: format Mutex.cpp * common: format PageFaultSource.h * common: format Path.h * common: format PathUtils.cpp * common: format Pcsx2Types.h * common: format Perf * common: format PersistentThread.h * common: format RwMutex * common: format SafeArray * common: format ScopedAlloc.h * common: format ScopedPtrMT.h * common: format Semaphore.cpp * common: format StringHelpers * common: format ThreadTools.cpp * common: format Threading.h * common: format ThreadingDialogs * common: format ThreadingInternal.h * common: format TraceLog.h * common: format VirtualMemory.cpp * common: format pxCheckBox * common: format pxEvents.h * common: format pxForwardDefs.h * common: format pxRadioPanel * common: format pxStaticText * common: format pxStreams * common: format pxTranslate.cpp * common: format pxWindowTextWriter.cpp * common: format wxAppWithHelpers * common: format wxBaseTools.h * common: format wxGuiTools * common: format wxHelpers.cpp * common: format Darwin directory * common: format Linux directory * common: format Windows directory * common: format LnxCpuDetect.cpp * common: format WinCpuDetect.cpp * common: format bmi.cpp * common: format cpudetect.cpp * common: format cpu_detect_internal.h * common: format fpu.cpp * common: format groups.cpp * common: format instructions.h * common: format internal.h * common: format jmp.cpp * common: format legacy.cpp * common: format legacy_instructions.h * common: format legacy_internal.h * common: format movs.cpp * common: format simd.cpp * common: format tools.h * common: format x86emitter.cpp * common: format x86types.h * common: format bmi.h * common: format dwshift.h * common: format group1.h group2.h group3.h * common: format incdec.h * common: format jmpcall.h * common: format movs.h * common: format simd_arithmetic.h * common: format simd_comparisons.h * common: format simd_helpers.h * common: format simd_moremovs.h * common: format simd_shufflepack.h * common: format simd_templated_helpers.h * common: format test.h
This commit is contained in:
parent
f9bf87f50d
commit
13dfceff48
|
@ -21,33 +21,34 @@
|
|||
#include "common/Assertions.h"
|
||||
#include "common/ScopedAlloc.h"
|
||||
|
||||
void *__fastcall _aligned_malloc(size_t size, size_t align)
|
||||
void* __fastcall _aligned_malloc(size_t size, size_t align)
|
||||
{
|
||||
pxAssert(align < 0x10000);
|
||||
pxAssert(align < 0x10000);
|
||||
#if defined(__USE_ISOC11) && !defined(ASAN_WORKAROUND) // not supported yet on gcc 4.9
|
||||
return aligned_alloc(align, size);
|
||||
return aligned_alloc(align, size);
|
||||
#else
|
||||
void *result = 0;
|
||||
posix_memalign(&result, align, size);
|
||||
return result;
|
||||
void* result = 0;
|
||||
posix_memalign(&result, align, size);
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
void *__fastcall pcsx2_aligned_realloc(void *handle, size_t new_size, size_t align, size_t old_size)
|
||||
void* __fastcall pcsx2_aligned_realloc(void* handle, size_t new_size, size_t align, size_t old_size)
|
||||
{
|
||||
pxAssert(align < 0x10000);
|
||||
pxAssert(align < 0x10000);
|
||||
|
||||
void *newbuf = _aligned_malloc(new_size, align);
|
||||
void* newbuf = _aligned_malloc(new_size, align);
|
||||
|
||||
if (newbuf != NULL && handle != NULL) {
|
||||
memcpy(newbuf, handle, std::min(old_size, new_size));
|
||||
_aligned_free(handle);
|
||||
}
|
||||
return newbuf;
|
||||
if (newbuf != NULL && handle != NULL)
|
||||
{
|
||||
memcpy(newbuf, handle, std::min(old_size, new_size));
|
||||
_aligned_free(handle);
|
||||
}
|
||||
return newbuf;
|
||||
}
|
||||
|
||||
__fi void _aligned_free(void *pmem)
|
||||
__fi void _aligned_free(void* pmem)
|
||||
{
|
||||
free(pmem);
|
||||
free(pmem);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -27,13 +27,13 @@
|
|||
//
|
||||
class Pcsx2AppTraits : public wxGUIAppTraits
|
||||
{
|
||||
typedef wxGUIAppTraits _parent;
|
||||
typedef wxGUIAppTraits _parent;
|
||||
|
||||
public:
|
||||
virtual ~Pcsx2AppTraits() {}
|
||||
wxMessageOutput *CreateMessageOutput();
|
||||
virtual ~Pcsx2AppTraits() {}
|
||||
wxMessageOutput* CreateMessageOutput();
|
||||
|
||||
#ifdef wxUSE_STDPATHS
|
||||
wxStandardPaths &GetStandardPaths();
|
||||
wxStandardPaths& GetStandardPaths();
|
||||
#endif
|
||||
};
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
#endif
|
||||
|
||||
#ifndef wxNullChar
|
||||
#define wxNullChar ((wxChar *)NULL)
|
||||
#define wxNullChar ((wxChar*)NULL)
|
||||
#endif
|
||||
|
||||
// FnChar_t - function name char type; typedef'd in case it ever changes between compilers
|
||||
|
@ -39,29 +39,29 @@ typedef char FnChar_t;
|
|||
// --------------------------------------------------------------------------------------
|
||||
struct DiagnosticOrigin
|
||||
{
|
||||
const wxChar *srcfile;
|
||||
const FnChar_t *function;
|
||||
const wxChar *condition;
|
||||
int line;
|
||||
const wxChar* srcfile;
|
||||
const FnChar_t* function;
|
||||
const wxChar* condition;
|
||||
int line;
|
||||
|
||||
DiagnosticOrigin(const wxChar *_file, int _line, const FnChar_t *_func, const wxChar *_cond = NULL)
|
||||
: srcfile(_file)
|
||||
, function(_func)
|
||||
, condition(_cond)
|
||||
, line(_line)
|
||||
{
|
||||
}
|
||||
DiagnosticOrigin(const wxChar* _file, int _line, const FnChar_t* _func, const wxChar* _cond = NULL)
|
||||
: srcfile(_file)
|
||||
, function(_func)
|
||||
, condition(_cond)
|
||||
, line(_line)
|
||||
{
|
||||
}
|
||||
|
||||
wxString ToString(const wxChar *msg = NULL) const;
|
||||
wxString ToString(const wxChar* msg = NULL) const;
|
||||
};
|
||||
|
||||
// Returns ture if the assertion is to trap into the debugger, or false if execution
|
||||
// of the program should continue unimpeded.
|
||||
typedef bool pxDoAssertFnType(const DiagnosticOrigin &origin, const wxChar *msg);
|
||||
typedef bool pxDoAssertFnType(const DiagnosticOrigin& origin, const wxChar* msg);
|
||||
|
||||
extern pxDoAssertFnType pxAssertImpl_LogIt;
|
||||
|
||||
extern pxDoAssertFnType *pxDoAssert;
|
||||
extern pxDoAssertFnType* pxDoAssert;
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// pxAssert / pxAssertDev
|
||||
|
@ -159,11 +159,14 @@ extern pxDoAssertFnType *pxDoAssert;
|
|||
#define pxAssumeDev(cond, msg) (__assume(cond))
|
||||
|
||||
#define pxFail(msg) \
|
||||
do { \
|
||||
} while (0)
|
||||
do \
|
||||
{ \
|
||||
} while (0)
|
||||
|
||||
#define pxFailDev(msg) \
|
||||
do { \
|
||||
} while (0)
|
||||
do \
|
||||
{ \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -177,18 +180,18 @@ extern pxDoAssertFnType *pxDoAssert;
|
|||
// IndexBoundsCheckDev.
|
||||
|
||||
#define IndexBoundsCheck(objname, idx, sze) pxAssertMsg((uint)(idx) < (uint)(sze), \
|
||||
pxsFmt(L"Array index out of bounds accessing object '%s' (index=%d, size=%d)", objname, (idx), (sze)))
|
||||
pxsFmt(L"Array index out of bounds accessing object '%s' (index=%d, size=%d)", objname, (idx), (sze)))
|
||||
|
||||
#define IndexBoundsCheckDev(objname, idx, sze) pxAssertDev((uint)(idx) < (uint)(sze), \
|
||||
pxsFmt(L"Array index out of bounds accessing object '%s' (index=%d, size=%d)", objname, (idx), (sze)))
|
||||
pxsFmt(L"Array index out of bounds accessing object '%s' (index=%d, size=%d)", objname, (idx), (sze)))
|
||||
|
||||
#define IndexBoundsAssume(objname, idx, sze) pxAssumeMsg((uint)(idx) < (uint)(sze), \
|
||||
pxsFmt(L"Array index out of bounds accessing object '%s' (index=%d, size=%d)", objname, (idx), (sze)))
|
||||
pxsFmt(L"Array index out of bounds accessing object '%s' (index=%d, size=%d)", objname, (idx), (sze)))
|
||||
|
||||
#define IndexBoundsAssumeDev(objname, idx, sze) pxAssumeDev((uint)(idx) < (uint)(sze), \
|
||||
pxsFmt(L"Array index out of bounds accessing object '%s' (index=%d, size=%d)", objname, (idx), (sze)))
|
||||
pxsFmt(L"Array index out of bounds accessing object '%s' (index=%d, size=%d)", objname, (idx), (sze)))
|
||||
|
||||
extern void pxOnAssert(const DiagnosticOrigin &origin, const wxString &msg);
|
||||
extern void pxOnAssert(const DiagnosticOrigin& origin, const wxString& msg);
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// jNO_DEFAULT -- disables the default case in a switch, which improves switch optimization
|
||||
|
@ -201,9 +204,10 @@ extern void pxOnAssert(const DiagnosticOrigin &origin, const wxString &msg);
|
|||
// * In debug/devel builds the default case will cause an assertion.
|
||||
//
|
||||
#ifndef jNO_DEFAULT
|
||||
#define jNO_DEFAULT \
|
||||
default: { \
|
||||
pxAssumeDev(0, "Incorrect usage of jNO_DEFAULT detected (default case is not unreachable!)"); \
|
||||
break; \
|
||||
}
|
||||
#define jNO_DEFAULT \
|
||||
default: \
|
||||
{ \
|
||||
pxAssumeDev(0, "Incorrect usage of jNO_DEFAULT detected (default case is not unreachable!)"); \
|
||||
break; \
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -15,62 +15,64 @@
|
|||
|
||||
#include "common/CheckedStaticBox.h"
|
||||
|
||||
CheckedStaticBox::CheckedStaticBox(wxWindow *parent, int orientation, const wxString &title)
|
||||
: wxPanelWithHelpers(parent, wxVERTICAL)
|
||||
, ThisSizer(*new wxStaticBoxSizer(orientation, this))
|
||||
, ThisToggle(*new wxCheckBox(this, wxID_ANY, title, wxPoint(8, 0)))
|
||||
CheckedStaticBox::CheckedStaticBox(wxWindow* parent, int orientation, const wxString& title)
|
||||
: wxPanelWithHelpers(parent, wxVERTICAL)
|
||||
, ThisSizer(*new wxStaticBoxSizer(orientation, this))
|
||||
, ThisToggle(*new wxCheckBox(this, wxID_ANY, title, wxPoint(8, 0)))
|
||||
{
|
||||
*this += ThisToggle;
|
||||
*this += ThisSizer | pxExpand;
|
||||
*this += ThisToggle;
|
||||
*this += ThisSizer | pxExpand;
|
||||
|
||||
// Ensure that the right-side of the static group box isn't too cozy:
|
||||
SetMinWidth(ThisToggle.GetSize().GetWidth() + 32);
|
||||
// Ensure that the right-side of the static group box isn't too cozy:
|
||||
SetMinWidth(ThisToggle.GetSize().GetWidth() + 32);
|
||||
|
||||
Bind(wxEVT_CHECKBOX, &CheckedStaticBox::MainToggle_Click, this, ThisToggle.GetId());
|
||||
Bind(wxEVT_CHECKBOX, &CheckedStaticBox::MainToggle_Click, this, ThisToggle.GetId());
|
||||
}
|
||||
|
||||
// Event handler for click events for the main checkbox (default behavior: enables/disables all child controls)
|
||||
// This function can be overridden to implement custom handling of check enable/disable behavior.
|
||||
void CheckedStaticBox::MainToggle_Click(wxCommandEvent &evt)
|
||||
void CheckedStaticBox::MainToggle_Click(wxCommandEvent& evt)
|
||||
{
|
||||
SetValue(evt.IsChecked());
|
||||
evt.Skip();
|
||||
SetValue(evt.IsChecked());
|
||||
evt.Skip();
|
||||
}
|
||||
|
||||
// Sets the main checkbox status, and enables/disables all child controls
|
||||
// bound to the StaticBox accordingly.
|
||||
void CheckedStaticBox::SetValue(bool val)
|
||||
{
|
||||
wxWindowList &list = GetChildren();
|
||||
wxWindowList& list = GetChildren();
|
||||
|
||||
for (wxWindowList::iterator iter = list.begin(); iter != list.end(); ++iter) {
|
||||
wxWindow *current = *iter;
|
||||
if (current != &ThisToggle)
|
||||
current->Enable(IsEnabled() && val);
|
||||
}
|
||||
ThisToggle.SetValue(val);
|
||||
for (wxWindowList::iterator iter = list.begin(); iter != list.end(); ++iter)
|
||||
{
|
||||
wxWindow* current = *iter;
|
||||
if (current != &ThisToggle)
|
||||
current->Enable(IsEnabled() && val);
|
||||
}
|
||||
ThisToggle.SetValue(val);
|
||||
}
|
||||
|
||||
bool CheckedStaticBox::GetValue() const
|
||||
{
|
||||
return ThisToggle.GetValue();
|
||||
return ThisToggle.GetValue();
|
||||
}
|
||||
|
||||
// This override is here so to only enable the children if both the main toggle and
|
||||
// the enable request are true. If not, disable them!
|
||||
bool CheckedStaticBox::Enable(bool enable)
|
||||
{
|
||||
if (!_parent::Enable(enable))
|
||||
return false;
|
||||
if (!_parent::Enable(enable))
|
||||
return false;
|
||||
|
||||
bool val = enable && ThisToggle.GetValue();
|
||||
wxWindowList &list = GetChildren();
|
||||
bool val = enable && ThisToggle.GetValue();
|
||||
wxWindowList& list = GetChildren();
|
||||
|
||||
for (wxWindowList::iterator iter = list.begin(); iter != list.end(); ++iter) {
|
||||
wxWindow *current = *iter;
|
||||
if (current != &ThisToggle)
|
||||
current->Enable(val);
|
||||
}
|
||||
for (wxWindowList::iterator iter = list.begin(); iter != list.end(); ++iter)
|
||||
{
|
||||
wxWindow* current = *iter;
|
||||
if (current != &ThisToggle)
|
||||
current->Enable(val);
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -19,19 +19,19 @@
|
|||
|
||||
class CheckedStaticBox : public wxPanelWithHelpers
|
||||
{
|
||||
typedef wxPanelWithHelpers _parent;
|
||||
typedef wxPanelWithHelpers _parent;
|
||||
|
||||
public:
|
||||
wxBoxSizer &ThisSizer; // Boxsizer which holds all child items.
|
||||
wxCheckBox &ThisToggle; // toggle which can enable/disable all child controls
|
||||
wxBoxSizer& ThisSizer; // Boxsizer which holds all child items.
|
||||
wxCheckBox& ThisToggle; // toggle which can enable/disable all child controls
|
||||
|
||||
public:
|
||||
CheckedStaticBox(wxWindow *parent, int orientation, const wxString &title = wxEmptyString);
|
||||
CheckedStaticBox(wxWindow* parent, int orientation, const wxString& title = wxEmptyString);
|
||||
|
||||
void SetValue(bool val);
|
||||
bool GetValue() const;
|
||||
bool Enable(bool enable = true);
|
||||
void SetValue(bool val);
|
||||
bool GetValue() const;
|
||||
bool Enable(bool enable = true);
|
||||
|
||||
public:
|
||||
virtual void MainToggle_Click(wxCommandEvent &evt);
|
||||
virtual void MainToggle_Click(wxCommandEvent& evt);
|
||||
};
|
||||
|
|
|
@ -26,11 +26,11 @@ static DeclareTls(int) conlog_Indent(0);
|
|||
static DeclareTls(ConsoleColors) conlog_Color(DefaultConsoleColor);
|
||||
|
||||
#ifdef __POSIX__
|
||||
static FILE *stdout_fp = stdout;
|
||||
static FILE* stdout_fp = stdout;
|
||||
|
||||
void Console_SetStdout(FILE *fp)
|
||||
void Console_SetStdout(FILE* fp)
|
||||
{
|
||||
stdout_fp = fp;
|
||||
stdout_fp = fp;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -41,33 +41,33 @@ void Console_SetStdout(FILE *fp)
|
|||
// Important! Only Assert and Null console loggers are allowed during C++ startup init (when
|
||||
// the program or DLL first loads). Other log targets rely on the static buffer and a
|
||||
// threaded mutex lock, which are only valid after C++ initialization has finished.
|
||||
void Console_SetActiveHandler(const IConsoleWriter &writer, FILE *flushfp)
|
||||
void Console_SetActiveHandler(const IConsoleWriter& writer, FILE* flushfp)
|
||||
{
|
||||
pxAssertDev(
|
||||
(writer.WriteRaw != NULL) && (writer.DoWriteLn != NULL) &&
|
||||
(writer.Newline != NULL) && (writer.SetTitle != NULL) &&
|
||||
(writer.DoSetColor != NULL),
|
||||
"Invalid IConsoleWriter object! All function pointer interfaces must be implemented.");
|
||||
pxAssertDev(
|
||||
(writer.WriteRaw != NULL) && (writer.DoWriteLn != NULL) &&
|
||||
(writer.Newline != NULL) && (writer.SetTitle != NULL) &&
|
||||
(writer.DoSetColor != NULL),
|
||||
"Invalid IConsoleWriter object! All function pointer interfaces must be implemented.");
|
||||
|
||||
Console = writer;
|
||||
DevConWriter = writer;
|
||||
Console = writer;
|
||||
DevConWriter = writer;
|
||||
|
||||
#ifdef PCSX2_DEBUG
|
||||
DbgCon = writer;
|
||||
DbgCon = writer;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Writes text to the Visual Studio Output window (Microsoft Windows only).
|
||||
// On all other platforms this pipes to Stdout instead.
|
||||
void MSW_OutputDebugString(const wxString &text)
|
||||
void MSW_OutputDebugString(const wxString& text)
|
||||
{
|
||||
#if defined(__WXMSW__) && !defined(__WXMICROWIN__)
|
||||
static bool hasDebugger = wxIsDebuggerRunning();
|
||||
if (hasDebugger)
|
||||
OutputDebugString(text);
|
||||
static bool hasDebugger = wxIsDebuggerRunning();
|
||||
if (hasDebugger)
|
||||
OutputDebugString(text);
|
||||
#else
|
||||
fputs(text.utf8_str(), stdout_fp);
|
||||
fflush(stdout_fp);
|
||||
fputs(text.utf8_str(), stdout_fp);
|
||||
fflush(stdout_fp);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -76,23 +76,23 @@ void MSW_OutputDebugString(const wxString &text)
|
|||
// ConsoleNull
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
static void __concall ConsoleNull_SetTitle(const wxString &title) {}
|
||||
static void __concall ConsoleNull_SetTitle(const wxString& title) {}
|
||||
static void __concall ConsoleNull_DoSetColor(ConsoleColors color) {}
|
||||
static void __concall ConsoleNull_Newline() {}
|
||||
static void __concall ConsoleNull_DoWrite(const wxString &fmt) {}
|
||||
static void __concall ConsoleNull_DoWriteLn(const wxString &fmt) {}
|
||||
static void __concall ConsoleNull_DoWrite(const wxString& fmt) {}
|
||||
static void __concall ConsoleNull_DoWriteLn(const wxString& fmt) {}
|
||||
|
||||
const IConsoleWriter ConsoleWriter_Null =
|
||||
{
|
||||
ConsoleNull_DoWrite,
|
||||
ConsoleNull_DoWriteLn,
|
||||
ConsoleNull_DoSetColor,
|
||||
{
|
||||
ConsoleNull_DoWrite,
|
||||
ConsoleNull_DoWriteLn,
|
||||
ConsoleNull_DoSetColor,
|
||||
|
||||
ConsoleNull_DoWrite,
|
||||
ConsoleNull_Newline,
|
||||
ConsoleNull_SetTitle,
|
||||
ConsoleNull_DoWrite,
|
||||
ConsoleNull_Newline,
|
||||
ConsoleNull_SetTitle,
|
||||
|
||||
0, // instance-level indentation (should always be 0)
|
||||
0, // instance-level indentation (should always be 0)
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -100,133 +100,134 @@ const IConsoleWriter ConsoleWriter_Null =
|
|||
// --------------------------------------------------------------------------------------
|
||||
|
||||
#if defined(__unix__)
|
||||
static __fi const char *GetLinuxConsoleColor(ConsoleColors color)
|
||||
static __fi const char* GetLinuxConsoleColor(ConsoleColors color)
|
||||
{
|
||||
switch (color) {
|
||||
case Color_Black:
|
||||
case Color_StrongBlack:
|
||||
return "\033[30m\033[1m";
|
||||
switch (color)
|
||||
{
|
||||
case Color_Black:
|
||||
case Color_StrongBlack:
|
||||
return "\033[30m\033[1m";
|
||||
|
||||
case Color_Red:
|
||||
return "\033[31m";
|
||||
case Color_StrongRed:
|
||||
return "\033[31m\033[1m";
|
||||
case Color_Red:
|
||||
return "\033[31m";
|
||||
case Color_StrongRed:
|
||||
return "\033[31m\033[1m";
|
||||
|
||||
case Color_Green:
|
||||
return "\033[32m";
|
||||
case Color_StrongGreen:
|
||||
return "\033[32m\033[1m";
|
||||
case Color_Green:
|
||||
return "\033[32m";
|
||||
case Color_StrongGreen:
|
||||
return "\033[32m\033[1m";
|
||||
|
||||
case Color_Yellow:
|
||||
return "\033[33m";
|
||||
case Color_StrongYellow:
|
||||
return "\033[33m\033[1m";
|
||||
case Color_Yellow:
|
||||
return "\033[33m";
|
||||
case Color_StrongYellow:
|
||||
return "\033[33m\033[1m";
|
||||
|
||||
case Color_Blue:
|
||||
return "\033[34m";
|
||||
case Color_StrongBlue:
|
||||
return "\033[34m\033[1m";
|
||||
case Color_Blue:
|
||||
return "\033[34m";
|
||||
case Color_StrongBlue:
|
||||
return "\033[34m\033[1m";
|
||||
|
||||
// No orange, so use magenta.
|
||||
case Color_Orange:
|
||||
case Color_Magenta:
|
||||
return "\033[35m";
|
||||
case Color_StrongOrange:
|
||||
case Color_StrongMagenta:
|
||||
return "\033[35m\033[1m";
|
||||
// No orange, so use magenta.
|
||||
case Color_Orange:
|
||||
case Color_Magenta:
|
||||
return "\033[35m";
|
||||
case Color_StrongOrange:
|
||||
case Color_StrongMagenta:
|
||||
return "\033[35m\033[1m";
|
||||
|
||||
case Color_Cyan:
|
||||
return "\033[36m";
|
||||
case Color_StrongCyan:
|
||||
return "\033[36m\033[1m";
|
||||
case Color_Cyan:
|
||||
return "\033[36m";
|
||||
case Color_StrongCyan:
|
||||
return "\033[36m\033[1m";
|
||||
|
||||
// Use 'white' instead of grey.
|
||||
case Color_Gray:
|
||||
case Color_White:
|
||||
return "\033[37m";
|
||||
case Color_StrongGray:
|
||||
case Color_StrongWhite:
|
||||
return "\033[37m\033[1m";
|
||||
// Use 'white' instead of grey.
|
||||
case Color_Gray:
|
||||
case Color_White:
|
||||
return "\033[37m";
|
||||
case Color_StrongGray:
|
||||
case Color_StrongWhite:
|
||||
return "\033[37m\033[1m";
|
||||
|
||||
// On some other value being passed, clear any formatting.
|
||||
case Color_Default:
|
||||
default:
|
||||
return "\033[0m";
|
||||
}
|
||||
// On some other value being passed, clear any formatting.
|
||||
case Color_Default:
|
||||
default:
|
||||
return "\033[0m";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// One possible default write action at startup and shutdown is to use the stdout.
|
||||
static void __concall ConsoleStdout_DoWrite(const wxString &fmt)
|
||||
static void __concall ConsoleStdout_DoWrite(const wxString& fmt)
|
||||
{
|
||||
MSW_OutputDebugString(fmt);
|
||||
MSW_OutputDebugString(fmt);
|
||||
}
|
||||
|
||||
// Default write action at startup and shutdown is to use the stdout.
|
||||
static void __concall ConsoleStdout_DoWriteLn(const wxString &fmt)
|
||||
static void __concall ConsoleStdout_DoWriteLn(const wxString& fmt)
|
||||
{
|
||||
MSW_OutputDebugString(fmt + L"\n");
|
||||
MSW_OutputDebugString(fmt + L"\n");
|
||||
}
|
||||
|
||||
static void __concall ConsoleStdout_Newline()
|
||||
{
|
||||
MSW_OutputDebugString(L"\n");
|
||||
MSW_OutputDebugString(L"\n");
|
||||
}
|
||||
|
||||
static void __concall ConsoleStdout_DoSetColor(ConsoleColors color)
|
||||
{
|
||||
#if defined(__unix__)
|
||||
fprintf(stdout_fp, "\033[0m%s", GetLinuxConsoleColor(color));
|
||||
fflush(stdout_fp);
|
||||
fprintf(stdout_fp, "\033[0m%s", GetLinuxConsoleColor(color));
|
||||
fflush(stdout_fp);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void __concall ConsoleStdout_SetTitle(const wxString &title)
|
||||
static void __concall ConsoleStdout_SetTitle(const wxString& title)
|
||||
{
|
||||
#if defined(__unix__)
|
||||
fputs("\033]0;", stdout_fp);
|
||||
fputs(title.utf8_str(), stdout_fp);
|
||||
fputs("\007", stdout_fp);
|
||||
fputs("\033]0;", stdout_fp);
|
||||
fputs(title.utf8_str(), stdout_fp);
|
||||
fputs("\007", stdout_fp);
|
||||
#endif
|
||||
}
|
||||
|
||||
const IConsoleWriter ConsoleWriter_Stdout =
|
||||
{
|
||||
ConsoleStdout_DoWrite, // Writes without newlines go to buffer to avoid error log spam.
|
||||
ConsoleStdout_DoWriteLn,
|
||||
ConsoleStdout_DoSetColor,
|
||||
{
|
||||
ConsoleStdout_DoWrite, // Writes without newlines go to buffer to avoid error log spam.
|
||||
ConsoleStdout_DoWriteLn,
|
||||
ConsoleStdout_DoSetColor,
|
||||
|
||||
ConsoleNull_DoWrite, // writes from re-piped stdout are ignored here, lest we create infinite loop hell >_<
|
||||
ConsoleStdout_Newline,
|
||||
ConsoleStdout_SetTitle,
|
||||
0, // instance-level indentation (should always be 0)
|
||||
ConsoleNull_DoWrite, // writes from re-piped stdout are ignored here, lest we create infinite loop hell >_<
|
||||
ConsoleStdout_Newline,
|
||||
ConsoleStdout_SetTitle,
|
||||
0, // instance-level indentation (should always be 0)
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// ConsoleAssert
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
static void __concall ConsoleAssert_DoWrite(const wxString &fmt)
|
||||
static void __concall ConsoleAssert_DoWrite(const wxString& fmt)
|
||||
{
|
||||
pxFail(L"Console class has not been initialized; Message written:\n\t" + fmt);
|
||||
pxFail(L"Console class has not been initialized; Message written:\n\t" + fmt);
|
||||
}
|
||||
|
||||
static void __concall ConsoleAssert_DoWriteLn(const wxString &fmt)
|
||||
static void __concall ConsoleAssert_DoWriteLn(const wxString& fmt)
|
||||
{
|
||||
pxFail(L"Console class has not been initialized; Message written:\n\t" + fmt);
|
||||
pxFail(L"Console class has not been initialized; Message written:\n\t" + fmt);
|
||||
}
|
||||
|
||||
const IConsoleWriter ConsoleWriter_Assert =
|
||||
{
|
||||
ConsoleAssert_DoWrite,
|
||||
ConsoleAssert_DoWriteLn,
|
||||
ConsoleNull_DoSetColor,
|
||||
{
|
||||
ConsoleAssert_DoWrite,
|
||||
ConsoleAssert_DoWriteLn,
|
||||
ConsoleNull_DoSetColor,
|
||||
|
||||
ConsoleNull_DoWrite,
|
||||
ConsoleNull_Newline,
|
||||
ConsoleNull_SetTitle,
|
||||
ConsoleNull_DoWrite,
|
||||
ConsoleNull_Newline,
|
||||
ConsoleNull_SetTitle,
|
||||
|
||||
0, // instance-level indentation (should always be 0)
|
||||
0, // instance-level indentation (should always be 0)
|
||||
};
|
||||
|
||||
// =====================================================================================================
|
||||
|
@ -239,170 +240,170 @@ const IConsoleWriter ConsoleWriter_Assert =
|
|||
// glob_indent - this parameter is used to specify a global indentation setting. It is used by
|
||||
// WriteLn function, but defaults to 0 for Warning and Error calls. Local indentation always
|
||||
// applies to all writes.
|
||||
wxString IConsoleWriter::_addIndentation(const wxString &src, int glob_indent = 0) const
|
||||
wxString IConsoleWriter::_addIndentation(const wxString& src, int glob_indent = 0) const
|
||||
{
|
||||
const int indent = glob_indent + _imm_indentation;
|
||||
if (indent == 0)
|
||||
return src;
|
||||
const int indent = glob_indent + _imm_indentation;
|
||||
if (indent == 0)
|
||||
return src;
|
||||
|
||||
wxString result(src);
|
||||
const wxString indentStr(L'\t', indent);
|
||||
result.Replace(L"\n", L"\n" + indentStr);
|
||||
return indentStr + result;
|
||||
wxString result(src);
|
||||
const wxString indentStr(L'\t', indent);
|
||||
result.Replace(L"\n", L"\n" + indentStr);
|
||||
return indentStr + result;
|
||||
}
|
||||
|
||||
// Sets the indentation to be applied to all WriteLn's. The indentation is added to the
|
||||
// primary write, and to any newlines specified within the write. Note that this applies
|
||||
// to calls to WriteLn *only* -- calls to Write bypass the indentation parser.
|
||||
const IConsoleWriter &IConsoleWriter::SetIndent(int tabcount) const
|
||||
const IConsoleWriter& IConsoleWriter::SetIndent(int tabcount) const
|
||||
{
|
||||
conlog_Indent += tabcount;
|
||||
pxAssert(conlog_Indent >= 0);
|
||||
return *this;
|
||||
conlog_Indent += tabcount;
|
||||
pxAssert(conlog_Indent >= 0);
|
||||
return *this;
|
||||
}
|
||||
|
||||
IConsoleWriter IConsoleWriter::Indent(int tabcount) const
|
||||
{
|
||||
IConsoleWriter retval = *this;
|
||||
retval._imm_indentation = tabcount;
|
||||
return retval;
|
||||
IConsoleWriter retval = *this;
|
||||
retval._imm_indentation = tabcount;
|
||||
return retval;
|
||||
}
|
||||
|
||||
// Changes the active console color.
|
||||
// This color will be unset by calls to colored text methods
|
||||
// such as ErrorMsg and Notice.
|
||||
const IConsoleWriter &IConsoleWriter::SetColor(ConsoleColors color) const
|
||||
const IConsoleWriter& IConsoleWriter::SetColor(ConsoleColors color) const
|
||||
{
|
||||
// Ignore current color requests since, well, the current color is already set. ;)
|
||||
if (color == Color_Current)
|
||||
return *this;
|
||||
// Ignore current color requests since, well, the current color is already set. ;)
|
||||
if (color == Color_Current)
|
||||
return *this;
|
||||
|
||||
pxAssertMsg((color > Color_Current) && (color < ConsoleColors_Count), "Invalid ConsoleColor specified.");
|
||||
pxAssertMsg((color > Color_Current) && (color < ConsoleColors_Count), "Invalid ConsoleColor specified.");
|
||||
|
||||
if (conlog_Color != color)
|
||||
DoSetColor(conlog_Color = color);
|
||||
if (conlog_Color != color)
|
||||
DoSetColor(conlog_Color = color);
|
||||
|
||||
return *this;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ConsoleColors IConsoleWriter::GetColor() const
|
||||
{
|
||||
return conlog_Color;
|
||||
return conlog_Color;
|
||||
}
|
||||
|
||||
// Restores the console color to default (usually black, or low-intensity white if the console uses a black background)
|
||||
const IConsoleWriter &IConsoleWriter::ClearColor() const
|
||||
const IConsoleWriter& IConsoleWriter::ClearColor() const
|
||||
{
|
||||
if (conlog_Color != DefaultConsoleColor)
|
||||
DoSetColor(conlog_Color = DefaultConsoleColor);
|
||||
if (conlog_Color != DefaultConsoleColor)
|
||||
DoSetColor(conlog_Color = DefaultConsoleColor);
|
||||
|
||||
return *this;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// ASCII/UTF8 (char*)
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
bool IConsoleWriter::FormatV(const char *fmt, va_list args) const
|
||||
bool IConsoleWriter::FormatV(const char* fmt, va_list args) const
|
||||
{
|
||||
DoWriteLn(_addIndentation(pxsFmtV(fmt, args), conlog_Indent));
|
||||
return false;
|
||||
DoWriteLn(_addIndentation(pxsFmtV(fmt, args), conlog_Indent));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IConsoleWriter::WriteLn(const char *fmt, ...) const
|
||||
bool IConsoleWriter::WriteLn(const char* fmt, ...) const
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
FormatV(fmt, args);
|
||||
va_end(args);
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
FormatV(fmt, args);
|
||||
va_end(args);
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IConsoleWriter::WriteLn(ConsoleColors color, const char *fmt, ...) const
|
||||
bool IConsoleWriter::WriteLn(ConsoleColors color, const char* fmt, ...) const
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
ConsoleColorScope cs(color);
|
||||
FormatV(fmt, args);
|
||||
va_end(args);
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
ConsoleColorScope cs(color);
|
||||
FormatV(fmt, args);
|
||||
va_end(args);
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IConsoleWriter::Error(const char *fmt, ...) const
|
||||
bool IConsoleWriter::Error(const char* fmt, ...) const
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
ConsoleColorScope cs(Color_StrongRed);
|
||||
FormatV(fmt, args);
|
||||
va_end(args);
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
ConsoleColorScope cs(Color_StrongRed);
|
||||
FormatV(fmt, args);
|
||||
va_end(args);
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IConsoleWriter::Warning(const char *fmt, ...) const
|
||||
bool IConsoleWriter::Warning(const char* fmt, ...) const
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
ConsoleColorScope cs(Color_StrongOrange);
|
||||
FormatV(fmt, args);
|
||||
va_end(args);
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
ConsoleColorScope cs(Color_StrongOrange);
|
||||
FormatV(fmt, args);
|
||||
va_end(args);
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Write Variants - Unicode/UTF16 style
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
bool IConsoleWriter::FormatV(const wxChar *fmt, va_list args) const
|
||||
bool IConsoleWriter::FormatV(const wxChar* fmt, va_list args) const
|
||||
{
|
||||
DoWriteLn(_addIndentation(pxsFmtV(fmt, args), conlog_Indent));
|
||||
return false;
|
||||
DoWriteLn(_addIndentation(pxsFmtV(fmt, args), conlog_Indent));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IConsoleWriter::WriteLn(const wxChar *fmt, ...) const
|
||||
bool IConsoleWriter::WriteLn(const wxChar* fmt, ...) const
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
FormatV(fmt, args);
|
||||
va_end(args);
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
FormatV(fmt, args);
|
||||
va_end(args);
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IConsoleWriter::WriteLn(ConsoleColors color, const wxChar *fmt, ...) const
|
||||
bool IConsoleWriter::WriteLn(ConsoleColors color, const wxChar* fmt, ...) const
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
ConsoleColorScope cs(color);
|
||||
FormatV(fmt, args);
|
||||
va_end(args);
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
ConsoleColorScope cs(color);
|
||||
FormatV(fmt, args);
|
||||
va_end(args);
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IConsoleWriter::Error(const wxChar *fmt, ...) const
|
||||
bool IConsoleWriter::Error(const wxChar* fmt, ...) const
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
ConsoleColorScope cs(Color_StrongRed);
|
||||
FormatV(fmt, args);
|
||||
va_end(args);
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
ConsoleColorScope cs(Color_StrongRed);
|
||||
FormatV(fmt, args);
|
||||
va_end(args);
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IConsoleWriter::Warning(const wxChar *fmt, ...) const
|
||||
bool IConsoleWriter::Warning(const wxChar* fmt, ...) const
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
ConsoleColorScope cs(Color_StrongOrange);
|
||||
FormatV(fmt, args);
|
||||
va_end(args);
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
ConsoleColorScope cs(Color_StrongOrange);
|
||||
FormatV(fmt, args);
|
||||
va_end(args);
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -410,45 +411,45 @@ bool IConsoleWriter::Warning(const wxChar *fmt, ...) const
|
|||
// --------------------------------------------------------------------------------------
|
||||
bool IConsoleWriter::WriteLn(const wxString fmt, ...) const
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
FormatV(fmt.wx_str(), args);
|
||||
va_end(args);
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
FormatV(fmt.wx_str(), args);
|
||||
va_end(args);
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IConsoleWriter::WriteLn(ConsoleColors color, const wxString fmt, ...) const
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
ConsoleColorScope cs(color);
|
||||
FormatV(fmt.wx_str(), args);
|
||||
va_end(args);
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
ConsoleColorScope cs(color);
|
||||
FormatV(fmt.wx_str(), args);
|
||||
va_end(args);
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IConsoleWriter::Error(const wxString fmt, ...) const
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
ConsoleColorScope cs(Color_StrongRed);
|
||||
FormatV(fmt.wx_str(), args);
|
||||
va_end(args);
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
ConsoleColorScope cs(Color_StrongRed);
|
||||
FormatV(fmt.wx_str(), args);
|
||||
va_end(args);
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IConsoleWriter::Warning(const wxString fmt, ...) const
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
ConsoleColorScope cs(Color_StrongOrange);
|
||||
FormatV(fmt.wx_str(), args);
|
||||
va_end(args);
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
ConsoleColorScope cs(Color_StrongOrange);
|
||||
FormatV(fmt.wx_str(), args);
|
||||
va_end(args);
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -458,70 +459,73 @@ bool IConsoleWriter::Warning(const wxString fmt, ...) const
|
|||
|
||||
ConsoleColorScope::ConsoleColorScope(ConsoleColors newcolor)
|
||||
{
|
||||
m_IsScoped = false;
|
||||
m_newcolor = newcolor;
|
||||
EnterScope();
|
||||
m_IsScoped = false;
|
||||
m_newcolor = newcolor;
|
||||
EnterScope();
|
||||
}
|
||||
|
||||
ConsoleColorScope::~ConsoleColorScope()
|
||||
{
|
||||
LeaveScope();
|
||||
LeaveScope();
|
||||
}
|
||||
|
||||
void ConsoleColorScope::EnterScope()
|
||||
{
|
||||
if (!m_IsScoped) {
|
||||
m_old_color = Console.GetColor();
|
||||
Console.SetColor(m_newcolor);
|
||||
m_IsScoped = true;
|
||||
}
|
||||
if (!m_IsScoped)
|
||||
{
|
||||
m_old_color = Console.GetColor();
|
||||
Console.SetColor(m_newcolor);
|
||||
m_IsScoped = true;
|
||||
}
|
||||
}
|
||||
|
||||
void ConsoleColorScope::LeaveScope()
|
||||
{
|
||||
m_IsScoped = m_IsScoped && (Console.SetColor(m_old_color), false);
|
||||
m_IsScoped = m_IsScoped && (Console.SetColor(m_old_color), false);
|
||||
}
|
||||
|
||||
ConsoleIndentScope::ConsoleIndentScope(int tabs)
|
||||
{
|
||||
m_IsScoped = false;
|
||||
m_amount = tabs;
|
||||
EnterScope();
|
||||
m_IsScoped = false;
|
||||
m_amount = tabs;
|
||||
EnterScope();
|
||||
}
|
||||
|
||||
ConsoleIndentScope::~ConsoleIndentScope()
|
||||
{
|
||||
try {
|
||||
LeaveScope();
|
||||
}
|
||||
DESTRUCTOR_CATCHALL
|
||||
try
|
||||
{
|
||||
LeaveScope();
|
||||
}
|
||||
DESTRUCTOR_CATCHALL
|
||||
}
|
||||
|
||||
void ConsoleIndentScope::EnterScope()
|
||||
{
|
||||
m_IsScoped = m_IsScoped || (Console.SetIndent(m_amount), true);
|
||||
m_IsScoped = m_IsScoped || (Console.SetIndent(m_amount), true);
|
||||
}
|
||||
|
||||
void ConsoleIndentScope::LeaveScope()
|
||||
{
|
||||
m_IsScoped = m_IsScoped && (Console.SetIndent(-m_amount), false);
|
||||
m_IsScoped = m_IsScoped && (Console.SetIndent(-m_amount), false);
|
||||
}
|
||||
|
||||
|
||||
ConsoleAttrScope::ConsoleAttrScope(ConsoleColors newcolor, int indent)
|
||||
{
|
||||
m_old_color = Console.GetColor();
|
||||
Console.SetIndent(m_tabsize = indent);
|
||||
Console.SetColor(newcolor);
|
||||
m_old_color = Console.GetColor();
|
||||
Console.SetIndent(m_tabsize = indent);
|
||||
Console.SetColor(newcolor);
|
||||
}
|
||||
|
||||
ConsoleAttrScope::~ConsoleAttrScope()
|
||||
{
|
||||
try {
|
||||
Console.SetColor(m_old_color);
|
||||
Console.SetIndent(-m_tabsize);
|
||||
}
|
||||
DESTRUCTOR_CATCHALL
|
||||
try
|
||||
{
|
||||
Console.SetColor(m_old_color);
|
||||
Console.SetIndent(-m_tabsize);
|
||||
}
|
||||
DESTRUCTOR_CATCHALL
|
||||
}
|
||||
|
||||
|
||||
|
@ -552,31 +556,31 @@ NullConsoleWriter NullCon = {};
|
|||
|
||||
// Writes to the console using the specified color. This overrides the default color setting
|
||||
// for this log.
|
||||
bool ConsoleLogSource::WriteV(ConsoleColors color, const char *fmt, va_list list) const
|
||||
bool ConsoleLogSource::WriteV(ConsoleColors color, const char* fmt, va_list list) const
|
||||
{
|
||||
ConsoleColorScope cs(color);
|
||||
DoWrite(pxsFmtV(fmt, list).c_str());
|
||||
return false;
|
||||
ConsoleColorScope cs(color);
|
||||
DoWrite(pxsFmtV(fmt, list).c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ConsoleLogSource::WriteV(ConsoleColors color, const wxChar *fmt, va_list list) const
|
||||
bool ConsoleLogSource::WriteV(ConsoleColors color, const wxChar* fmt, va_list list) const
|
||||
{
|
||||
ConsoleColorScope cs(color);
|
||||
DoWrite(pxsFmtV(fmt, list).c_str());
|
||||
return false;
|
||||
ConsoleColorScope cs(color);
|
||||
DoWrite(pxsFmtV(fmt, list).c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Writes to the console using the source's default color. Note that the source's default
|
||||
// color will always be used, thus ConsoleColorScope() will not be effectual unless the
|
||||
// console's default color is Color_Default.
|
||||
bool ConsoleLogSource::WriteV(const char *fmt, va_list list) const
|
||||
bool ConsoleLogSource::WriteV(const char* fmt, va_list list) const
|
||||
{
|
||||
WriteV(DefaultColor, fmt, list);
|
||||
return false;
|
||||
WriteV(DefaultColor, fmt, list);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ConsoleLogSource::WriteV(const wxChar *fmt, va_list list) const
|
||||
bool ConsoleLogSource::WriteV(const wxChar* fmt, va_list list) const
|
||||
{
|
||||
WriteV(DefaultColor, fmt, list);
|
||||
return false;
|
||||
WriteV(DefaultColor, fmt, list);
|
||||
return false;
|
||||
}
|
||||
|
|
239
common/Console.h
239
common/Console.h
|
@ -15,40 +15,41 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "StringHelpers.h"
|
||||
#include "common/StringHelpers.h"
|
||||
|
||||
enum ConsoleColors {
|
||||
Color_Current = -1,
|
||||
enum ConsoleColors
|
||||
{
|
||||
Color_Current = -1,
|
||||
|
||||
Color_Default = 0,
|
||||
Color_Default = 0,
|
||||
|
||||
Color_Black,
|
||||
Color_Green,
|
||||
Color_Red,
|
||||
Color_Blue,
|
||||
Color_Magenta,
|
||||
Color_Orange,
|
||||
Color_Gray,
|
||||
Color_Black,
|
||||
Color_Green,
|
||||
Color_Red,
|
||||
Color_Blue,
|
||||
Color_Magenta,
|
||||
Color_Orange,
|
||||
Color_Gray,
|
||||
|
||||
Color_Cyan, // faint visibility, intended for logging PS2/IOP output
|
||||
Color_Yellow, // faint visibility, intended for logging PS2/IOP output
|
||||
Color_White, // faint visibility, intended for logging PS2/IOP output
|
||||
Color_Cyan, // faint visibility, intended for logging PS2/IOP output
|
||||
Color_Yellow, // faint visibility, intended for logging PS2/IOP output
|
||||
Color_White, // faint visibility, intended for logging PS2/IOP output
|
||||
|
||||
// Strong text *may* result in mis-aligned text in the console, depending on the
|
||||
// font and the platform, so use these with caution.
|
||||
Color_StrongBlack,
|
||||
Color_StrongRed, // intended for errors
|
||||
Color_StrongGreen, // intended for infrequent state information
|
||||
Color_StrongBlue, // intended for block headings
|
||||
Color_StrongMagenta,
|
||||
Color_StrongOrange, // intended for warnings
|
||||
Color_StrongGray,
|
||||
// Strong text *may* result in mis-aligned text in the console, depending on the
|
||||
// font and the platform, so use these with caution.
|
||||
Color_StrongBlack,
|
||||
Color_StrongRed, // intended for errors
|
||||
Color_StrongGreen, // intended for infrequent state information
|
||||
Color_StrongBlue, // intended for block headings
|
||||
Color_StrongMagenta,
|
||||
Color_StrongOrange, // intended for warnings
|
||||
Color_StrongGray,
|
||||
|
||||
Color_StrongCyan,
|
||||
Color_StrongYellow,
|
||||
Color_StrongWhite,
|
||||
Color_StrongCyan,
|
||||
Color_StrongYellow,
|
||||
Color_StrongWhite,
|
||||
|
||||
ConsoleColors_Count
|
||||
ConsoleColors_Count
|
||||
};
|
||||
|
||||
static const ConsoleColors DefaultConsoleColor = Color_Default;
|
||||
|
@ -70,60 +71,60 @@ static const ConsoleColors DefaultConsoleColor = Color_Default;
|
|||
//
|
||||
struct IConsoleWriter
|
||||
{
|
||||
// A direct console write, without tabbing or newlines. Useful to devs who want to do quick
|
||||
// logging of various junk; but should *not* be used in production code due.
|
||||
void(__concall *WriteRaw)(const wxString &fmt);
|
||||
// A direct console write, without tabbing or newlines. Useful to devs who want to do quick
|
||||
// logging of various junk; but should *not* be used in production code due.
|
||||
void(__concall* WriteRaw)(const wxString& fmt);
|
||||
|
||||
// WriteLn implementation for internal use only. Bypasses tabbing, prefixing, and other
|
||||
// formatting.
|
||||
void(__concall *DoWriteLn)(const wxString &fmt);
|
||||
// WriteLn implementation for internal use only. Bypasses tabbing, prefixing, and other
|
||||
// formatting.
|
||||
void(__concall* DoWriteLn)(const wxString& fmt);
|
||||
|
||||
// SetColor implementation for internal use only.
|
||||
void(__concall *DoSetColor)(ConsoleColors color);
|
||||
// SetColor implementation for internal use only.
|
||||
void(__concall* DoSetColor)(ConsoleColors color);
|
||||
|
||||
// Special implementation of DoWrite that's pretty much for MSVC use only.
|
||||
// All implementations should map to DoWrite, except Stdio which should map to Null.
|
||||
// (This avoids circular/recursive stdio output)
|
||||
void(__concall *DoWriteFromStdout)(const wxString &fmt);
|
||||
// Special implementation of DoWrite that's pretty much for MSVC use only.
|
||||
// All implementations should map to DoWrite, except Stdio which should map to Null.
|
||||
// (This avoids circular/recursive stdio output)
|
||||
void(__concall* DoWriteFromStdout)(const wxString& fmt);
|
||||
|
||||
void(__concall *Newline)();
|
||||
void(__concall *SetTitle)(const wxString &title);
|
||||
void(__concall* Newline)();
|
||||
void(__concall* SetTitle)(const wxString& title);
|
||||
|
||||
// internal value for indentation of individual lines. Use the Indent() member to invoke.
|
||||
int _imm_indentation;
|
||||
// internal value for indentation of individual lines. Use the Indent() member to invoke.
|
||||
int _imm_indentation;
|
||||
|
||||
// For internal use only.
|
||||
wxString _addIndentation(const wxString &src, int glob_indent) const;
|
||||
// For internal use only.
|
||||
wxString _addIndentation(const wxString& src, int glob_indent) const;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Public members; call these to print stuff to console!
|
||||
//
|
||||
// All functions always return false. Return value is provided only so that we can easily
|
||||
// disable logs at compile time using the "0&&action" macro trick.
|
||||
// ----------------------------------------------------------------------------
|
||||
// Public members; call these to print stuff to console!
|
||||
//
|
||||
// All functions always return false. Return value is provided only so that we can easily
|
||||
// disable logs at compile time using the "0&&action" macro trick.
|
||||
|
||||
ConsoleColors GetColor() const;
|
||||
const IConsoleWriter &SetColor(ConsoleColors color) const;
|
||||
const IConsoleWriter &ClearColor() const;
|
||||
const IConsoleWriter &SetIndent(int tabcount = 1) const;
|
||||
ConsoleColors GetColor() const;
|
||||
const IConsoleWriter& SetColor(ConsoleColors color) const;
|
||||
const IConsoleWriter& ClearColor() const;
|
||||
const IConsoleWriter& SetIndent(int tabcount = 1) const;
|
||||
|
||||
IConsoleWriter Indent(int tabcount = 1) const;
|
||||
IConsoleWriter Indent(int tabcount = 1) const;
|
||||
|
||||
bool FormatV(const char *fmt, va_list args) const;
|
||||
bool WriteLn(ConsoleColors color, const char *fmt, ...) const;
|
||||
bool WriteLn(const char *fmt, ...) const;
|
||||
bool Error(const char *fmt, ...) const;
|
||||
bool Warning(const char *fmt, ...) const;
|
||||
bool FormatV(const char* fmt, va_list args) const;
|
||||
bool WriteLn(ConsoleColors color, const char* fmt, ...) const;
|
||||
bool WriteLn(const char* fmt, ...) const;
|
||||
bool Error(const char* fmt, ...) const;
|
||||
bool Warning(const char* fmt, ...) const;
|
||||
|
||||
bool FormatV(const wxChar *fmt, va_list args) const;
|
||||
bool WriteLn(ConsoleColors color, const wxChar *fmt, ...) const;
|
||||
bool WriteLn(const wxChar *fmt, ...) const;
|
||||
bool Error(const wxChar *fmt, ...) const;
|
||||
bool Warning(const wxChar *fmt, ...) const;
|
||||
bool FormatV(const wxChar* fmt, va_list args) const;
|
||||
bool WriteLn(ConsoleColors color, const wxChar* fmt, ...) const;
|
||||
bool WriteLn(const wxChar* fmt, ...) const;
|
||||
bool Error(const wxChar* fmt, ...) const;
|
||||
bool Warning(const wxChar* fmt, ...) const;
|
||||
|
||||
bool WriteLn(ConsoleColors color, const wxString fmt, ...) const;
|
||||
bool WriteLn(const wxString fmt, ...) const;
|
||||
bool Error(const wxString fmt, ...) const;
|
||||
bool Warning(const wxString fmt, ...) const;
|
||||
bool WriteLn(ConsoleColors color, const wxString fmt, ...) const;
|
||||
bool WriteLn(const wxString fmt, ...) const;
|
||||
bool Error(const wxString fmt, ...) const;
|
||||
bool Warning(const wxString fmt, ...) const;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -133,37 +134,37 @@ struct IConsoleWriter
|
|||
//
|
||||
struct NullConsoleWriter
|
||||
{
|
||||
void WriteRaw(const wxString &fmt) {}
|
||||
void DoWriteLn(const wxString &fmt) {}
|
||||
void DoSetColor(ConsoleColors color) {}
|
||||
void DoWriteFromStdout(const wxString &fmt) {}
|
||||
void Newline() {}
|
||||
void SetTitle(const wxString &title) {}
|
||||
void WriteRaw(const wxString& fmt) {}
|
||||
void DoWriteLn(const wxString& fmt) {}
|
||||
void DoSetColor(ConsoleColors color) {}
|
||||
void DoWriteFromStdout(const wxString& fmt) {}
|
||||
void Newline() {}
|
||||
void SetTitle(const wxString& title) {}
|
||||
|
||||
|
||||
ConsoleColors GetColor() const { return Color_Current; }
|
||||
const NullConsoleWriter &SetColor(ConsoleColors color) const { return *this; }
|
||||
const NullConsoleWriter &ClearColor() const { return *this; }
|
||||
const NullConsoleWriter &SetIndent(int tabcount = 1) const { return *this; }
|
||||
ConsoleColors GetColor() const { return Color_Current; }
|
||||
const NullConsoleWriter& SetColor(ConsoleColors color) const { return *this; }
|
||||
const NullConsoleWriter& ClearColor() const { return *this; }
|
||||
const NullConsoleWriter& SetIndent(int tabcount = 1) const { return *this; }
|
||||
|
||||
NullConsoleWriter Indent(int tabcount = 1) const { return NullConsoleWriter(); }
|
||||
NullConsoleWriter Indent(int tabcount = 1) const { return NullConsoleWriter(); }
|
||||
|
||||
bool FormatV(const char *fmt, va_list args) const { return false; }
|
||||
bool WriteLn(ConsoleColors color, const char *fmt, ...) const { return false; }
|
||||
bool WriteLn(const char *fmt, ...) const { return false; }
|
||||
bool Error(const char *fmt, ...) const { return false; }
|
||||
bool Warning(const char *fmt, ...) const { return false; }
|
||||
bool FormatV(const char* fmt, va_list args) const { return false; }
|
||||
bool WriteLn(ConsoleColors color, const char* fmt, ...) const { return false; }
|
||||
bool WriteLn(const char* fmt, ...) const { return false; }
|
||||
bool Error(const char* fmt, ...) const { return false; }
|
||||
bool Warning(const char* fmt, ...) const { return false; }
|
||||
|
||||
bool FormatV(const wxChar *fmt, va_list args) const { return false; }
|
||||
bool WriteLn(ConsoleColors color, const wxChar *fmt, ...) const { return false; }
|
||||
bool WriteLn(const wxChar *fmt, ...) const { return false; }
|
||||
bool Error(const wxChar *fmt, ...) const { return false; }
|
||||
bool Warning(const wxChar *fmt, ...) const { return false; }
|
||||
bool FormatV(const wxChar* fmt, va_list args) const { return false; }
|
||||
bool WriteLn(ConsoleColors color, const wxChar* fmt, ...) const { return false; }
|
||||
bool WriteLn(const wxChar* fmt, ...) const { return false; }
|
||||
bool Error(const wxChar* fmt, ...) const { return false; }
|
||||
bool Warning(const wxChar* fmt, ...) const { return false; }
|
||||
|
||||
bool WriteLn(ConsoleColors color, const wxString fmt, ...) const { return false; }
|
||||
bool WriteLn(const wxString fmt, ...) const { return false; }
|
||||
bool Error(const wxString fmt, ...) const { return false; }
|
||||
bool Warning(const wxString fmt, ...) const { return false; }
|
||||
bool WriteLn(ConsoleColors color, const wxString fmt, ...) const { return false; }
|
||||
bool WriteLn(const wxString fmt, ...) const { return false; }
|
||||
bool Error(const wxString fmt, ...) const { return false; }
|
||||
bool Warning(const wxString fmt, ...) const { return false; }
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -179,19 +180,19 @@ struct NullConsoleWriter
|
|||
//
|
||||
class ConsoleIndentScope
|
||||
{
|
||||
DeclareNoncopyableObject(ConsoleIndentScope);
|
||||
DeclareNoncopyableObject(ConsoleIndentScope);
|
||||
|
||||
protected:
|
||||
int m_amount;
|
||||
bool m_IsScoped;
|
||||
int m_amount;
|
||||
bool m_IsScoped;
|
||||
|
||||
public:
|
||||
// Constructor: The specified number of tabs will be appended to the current indentation
|
||||
// setting. The tabs will be unrolled when the object leaves scope or is destroyed.
|
||||
ConsoleIndentScope(int tabs = 1);
|
||||
virtual ~ConsoleIndentScope();
|
||||
void EnterScope();
|
||||
void LeaveScope();
|
||||
// Constructor: The specified number of tabs will be appended to the current indentation
|
||||
// setting. The tabs will be unrolled when the object leaves scope or is destroyed.
|
||||
ConsoleIndentScope(int tabs = 1);
|
||||
virtual ~ConsoleIndentScope();
|
||||
void EnterScope();
|
||||
void LeaveScope();
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -199,18 +200,18 @@ public:
|
|||
// --------------------------------------------------------------------------------------
|
||||
class ConsoleColorScope
|
||||
{
|
||||
DeclareNoncopyableObject(ConsoleColorScope);
|
||||
DeclareNoncopyableObject(ConsoleColorScope);
|
||||
|
||||
protected:
|
||||
ConsoleColors m_newcolor;
|
||||
ConsoleColors m_old_color;
|
||||
bool m_IsScoped;
|
||||
ConsoleColors m_newcolor;
|
||||
ConsoleColors m_old_color;
|
||||
bool m_IsScoped;
|
||||
|
||||
public:
|
||||
ConsoleColorScope(ConsoleColors newcolor);
|
||||
virtual ~ConsoleColorScope();
|
||||
void EnterScope();
|
||||
void LeaveScope();
|
||||
ConsoleColorScope(ConsoleColors newcolor);
|
||||
virtual ~ConsoleColorScope();
|
||||
void EnterScope();
|
||||
void LeaveScope();
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -220,23 +221,23 @@ public:
|
|||
//
|
||||
class ConsoleAttrScope
|
||||
{
|
||||
DeclareNoncopyableObject(ConsoleAttrScope);
|
||||
DeclareNoncopyableObject(ConsoleAttrScope);
|
||||
|
||||
protected:
|
||||
ConsoleColors m_old_color;
|
||||
int m_tabsize;
|
||||
ConsoleColors m_old_color;
|
||||
int m_tabsize;
|
||||
|
||||
public:
|
||||
ConsoleAttrScope(ConsoleColors newcolor, int indent = 0);
|
||||
virtual ~ConsoleAttrScope();
|
||||
ConsoleAttrScope(ConsoleColors newcolor, int indent = 0);
|
||||
virtual ~ConsoleAttrScope();
|
||||
};
|
||||
|
||||
extern IConsoleWriter Console;
|
||||
|
||||
#if defined(__unix__) || defined(__APPLE__)
|
||||
extern void Console_SetStdout(FILE *fp);
|
||||
extern void Console_SetStdout(FILE* fp);
|
||||
#endif
|
||||
extern void Console_SetActiveHandler(const IConsoleWriter &writer, FILE *flushfp = NULL);
|
||||
extern void Console_SetActiveHandler(const IConsoleWriter& writer, FILE* flushfp = NULL);
|
||||
|
||||
extern const IConsoleWriter ConsoleWriter_Null;
|
||||
extern const IConsoleWriter ConsoleWriter_Stdout;
|
||||
|
@ -250,7 +251,7 @@ extern bool DevConWriterEnabled;
|
|||
#ifdef PCSX2_DEVBUILD
|
||||
#define DevCon DevConWriter
|
||||
#else
|
||||
#define DevCon DevConWriterEnabled &&DevConWriter
|
||||
#define DevCon DevConWriterEnabled&& DevConWriter
|
||||
#endif
|
||||
|
||||
#ifdef PCSX2_DEBUG
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
#include "common/Pcsx2Types.h"
|
||||
|
||||
#define NELEM(x) \
|
||||
((sizeof(x) / sizeof(0 [x])) / ((size_t)(!(sizeof(x) % sizeof(0 [x])))))
|
||||
((sizeof(x) / sizeof(0 [x])) / ((size_t)(!(sizeof(x) % sizeof(0 [x])))))
|
||||
|
||||
// Darwin (OSX) is a bit different from Linux when requesting properties of
|
||||
// the OS because of its BSD/Mach heritage. Helpfully, most of this code
|
||||
|
@ -39,23 +39,25 @@
|
|||
// failure (not supported by the operating system).
|
||||
u64 GetPhysicalMemory()
|
||||
{
|
||||
static u64 mem = 0;
|
||||
static u64 mem = 0;
|
||||
|
||||
// fetch the total memory only once, as its an expensive system call and
|
||||
// doesn't change during the course of the program. Thread-safety is
|
||||
// ensured by atomic operations with full-barriers (usually compiled
|
||||
// down to XCHG on x86).
|
||||
if (__atomic_load_n(&mem, __ATOMIC_SEQ_CST) == 0) {
|
||||
u64 getmem = 0;
|
||||
size_t len = sizeof(getmem);
|
||||
int mib[] = {CTL_HW, HW_MEMSIZE};
|
||||
if (sysctl(mib, NELEM(mib), &getmem, &len, NULL, 0) < 0) {
|
||||
perror("sysctl:");
|
||||
}
|
||||
__atomic_store_n(&mem, getmem, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
// fetch the total memory only once, as its an expensive system call and
|
||||
// doesn't change during the course of the program. Thread-safety is
|
||||
// ensured by atomic operations with full-barriers (usually compiled
|
||||
// down to XCHG on x86).
|
||||
if (__atomic_load_n(&mem, __ATOMIC_SEQ_CST) == 0)
|
||||
{
|
||||
u64 getmem = 0;
|
||||
size_t len = sizeof(getmem);
|
||||
int mib[] = {CTL_HW, HW_MEMSIZE};
|
||||
if (sysctl(mib, NELEM(mib), &getmem, &len, NULL, 0) < 0)
|
||||
{
|
||||
perror("sysctl:");
|
||||
}
|
||||
__atomic_store_n(&mem, getmem, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
|
||||
return mem;
|
||||
return mem;
|
||||
}
|
||||
|
||||
void InitCPUTicks()
|
||||
|
@ -72,26 +74,28 @@ void InitCPUTicks()
|
|||
// GetTickFrequency() to maintain good precision.
|
||||
u64 GetTickFrequency()
|
||||
{
|
||||
static u64 freq = 0;
|
||||
static u64 freq = 0;
|
||||
|
||||
// by the time denom is not 0, the structure will have been fully
|
||||
// updated and no more atomic accesses are necessary.
|
||||
if (__atomic_load_n(&freq, __ATOMIC_SEQ_CST) == 0) {
|
||||
mach_timebase_info_data_t info;
|
||||
// by the time denom is not 0, the structure will have been fully
|
||||
// updated and no more atomic accesses are necessary.
|
||||
if (__atomic_load_n(&freq, __ATOMIC_SEQ_CST) == 0)
|
||||
{
|
||||
mach_timebase_info_data_t info;
|
||||
|
||||
// mach_timebase_info() is a syscall, very slow, that's why we take
|
||||
// pains to only do it once. On x86(-64), the result is guaranteed
|
||||
// to be info.denom == info.numer == 1 (i.e.: the frequency is 1e9,
|
||||
// which means GetCPUTicks is just nanoseconds).
|
||||
if (mach_timebase_info(&info) != KERN_SUCCESS) {
|
||||
abort();
|
||||
}
|
||||
// mach_timebase_info() is a syscall, very slow, that's why we take
|
||||
// pains to only do it once. On x86(-64), the result is guaranteed
|
||||
// to be info.denom == info.numer == 1 (i.e.: the frequency is 1e9,
|
||||
// which means GetCPUTicks is just nanoseconds).
|
||||
if (mach_timebase_info(&info) != KERN_SUCCESS)
|
||||
{
|
||||
abort();
|
||||
}
|
||||
|
||||
// store the calculated value atomically
|
||||
__atomic_store_n(&freq, (u64)1e9 * (u64)info.denom / (u64)info.numer, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
// store the calculated value atomically
|
||||
__atomic_store_n(&freq, (u64)1e9 * (u64)info.denom / (u64)info.numer, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
|
||||
return freq;
|
||||
return freq;
|
||||
}
|
||||
|
||||
// return the number of "ticks" since some arbitrary, fixed time in the
|
||||
|
@ -100,53 +104,55 @@ u64 GetTickFrequency()
|
|||
// nanoseconds.
|
||||
u64 GetCPUTicks()
|
||||
{
|
||||
return mach_absolute_time();
|
||||
return mach_absolute_time();
|
||||
}
|
||||
|
||||
wxString GetOSVersionString()
|
||||
{
|
||||
wxString version;
|
||||
static int initialized = 0;
|
||||
wxString version;
|
||||
static int initialized = 0;
|
||||
|
||||
// fetch the OS description only once (thread-safely)
|
||||
if (__atomic_load_n(&initialized, __ATOMIC_SEQ_CST) == 0) {
|
||||
char type[32] = {0};
|
||||
char release[32] = {0};
|
||||
char arch[32] = {0};
|
||||
// fetch the OS description only once (thread-safely)
|
||||
if (__atomic_load_n(&initialized, __ATOMIC_SEQ_CST) == 0)
|
||||
{
|
||||
char type[32] = {0};
|
||||
char release[32] = {0};
|
||||
char arch[32] = {0};
|
||||
|
||||
#define SYSCTL_GET(var, base, name) \
|
||||
do { \
|
||||
int mib[] = {base, name}; \
|
||||
size_t len = sizeof(var); \
|
||||
sysctl(mib, NELEM(mib), NULL, &len, NULL, 0); \
|
||||
sysctl(mib, NELEM(mib), var, &len, NULL, 0); \
|
||||
} while (0)
|
||||
#define SYSCTL_GET(var, base, name) \
|
||||
do \
|
||||
{ \
|
||||
int mib[] = {base, name}; \
|
||||
size_t len = sizeof(var); \
|
||||
sysctl(mib, NELEM(mib), NULL, &len, NULL, 0); \
|
||||
sysctl(mib, NELEM(mib), var, &len, NULL, 0); \
|
||||
} while (0)
|
||||
|
||||
SYSCTL_GET(release, CTL_KERN, KERN_OSRELEASE);
|
||||
SYSCTL_GET(type, CTL_KERN, KERN_OSTYPE);
|
||||
SYSCTL_GET(arch, CTL_HW, HW_MACHINE);
|
||||
SYSCTL_GET(release, CTL_KERN, KERN_OSRELEASE);
|
||||
SYSCTL_GET(type, CTL_KERN, KERN_OSTYPE);
|
||||
SYSCTL_GET(arch, CTL_HW, HW_MACHINE);
|
||||
|
||||
#undef SYSCTL_KERN
|
||||
|
||||
// I know strcat is not good, but stpcpy is not universally
|
||||
// available yet.
|
||||
char buf[128] = {0};
|
||||
strcat(buf, type);
|
||||
strcat(buf, " ");
|
||||
strcat(buf, release);
|
||||
strcat(buf, " ");
|
||||
strcat(buf, arch);
|
||||
// I know strcat is not good, but stpcpy is not universally
|
||||
// available yet.
|
||||
char buf[128] = {0};
|
||||
strcat(buf, type);
|
||||
strcat(buf, " ");
|
||||
strcat(buf, release);
|
||||
strcat(buf, " ");
|
||||
strcat(buf, arch);
|
||||
|
||||
version = buf;
|
||||
version = buf;
|
||||
|
||||
__atomic_store_n(&initialized, 1, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
__atomic_store_n(&initialized, 1, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
|
||||
return version;
|
||||
return version;
|
||||
}
|
||||
|
||||
void ScreensaverAllow(bool allow)
|
||||
{
|
||||
// no-op
|
||||
// no-op
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -20,10 +20,10 @@
|
|||
#include <pthread.h> // pthread_setcancelstate()
|
||||
#include <sys/time.h> // gettimeofday()
|
||||
#include <mach/mach.h>
|
||||
#include <mach/task.h> // semaphore_create() and semaphore_destroy()
|
||||
#include <mach/semaphore.h> // semaphore_*()
|
||||
#include <mach/task.h> // semaphore_create() and semaphore_destroy()
|
||||
#include <mach/semaphore.h> // semaphore_*()
|
||||
#include <mach/mach_error.h> // mach_error_string()
|
||||
#include <mach/mach_time.h> // mach_absolute_time()
|
||||
#include <mach/mach_time.h> // mach_absolute_time()
|
||||
|
||||
#include "common/Threading.h"
|
||||
#include "common/ThreadingInternal.h"
|
||||
|
@ -45,107 +45,113 @@
|
|||
|
||||
static void MACH_CHECK(kern_return_t mach_retval)
|
||||
{
|
||||
switch (mach_retval) {
|
||||
case KERN_SUCCESS: break;
|
||||
case KERN_ABORTED: // Awoken due reason unrelated to semaphore (e.g. pthread_cancel)
|
||||
pthread_testcancel(); // Unlike sem_wait, mach semaphore ops aren't cancellation points
|
||||
// fallthrough
|
||||
default:
|
||||
fprintf(stderr, "mach error: %s", mach_error_string(mach_retval));
|
||||
assert(mach_retval == KERN_SUCCESS);
|
||||
}
|
||||
switch (mach_retval)
|
||||
{
|
||||
case KERN_SUCCESS:
|
||||
break;
|
||||
case KERN_ABORTED: // Awoken due reason unrelated to semaphore (e.g. pthread_cancel)
|
||||
pthread_testcancel(); // Unlike sem_wait, mach semaphore ops aren't cancellation points
|
||||
// fallthrough
|
||||
default:
|
||||
fprintf(stderr, "mach error: %s", mach_error_string(mach_retval));
|
||||
assert(mach_retval == KERN_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
Threading::Semaphore::Semaphore()
|
||||
{
|
||||
// other platforms explicitly make a thread-private (unshared) semaphore
|
||||
// here. But it seems Mach doesn't support that.
|
||||
MACH_CHECK(semaphore_create(mach_task_self(), (semaphore_t *)&m_sema, SYNC_POLICY_FIFO, 0));
|
||||
__atomic_store_n(&m_counter, 0, __ATOMIC_SEQ_CST);
|
||||
// other platforms explicitly make a thread-private (unshared) semaphore
|
||||
// here. But it seems Mach doesn't support that.
|
||||
MACH_CHECK(semaphore_create(mach_task_self(), (semaphore_t*)&m_sema, SYNC_POLICY_FIFO, 0));
|
||||
__atomic_store_n(&m_counter, 0, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
|
||||
Threading::Semaphore::~Semaphore()
|
||||
{
|
||||
MACH_CHECK(semaphore_destroy(mach_task_self(), (semaphore_t)m_sema));
|
||||
__atomic_store_n(&m_counter, 0, __ATOMIC_SEQ_CST);
|
||||
MACH_CHECK(semaphore_destroy(mach_task_self(), (semaphore_t)m_sema));
|
||||
__atomic_store_n(&m_counter, 0, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
|
||||
void Threading::Semaphore::Reset()
|
||||
{
|
||||
MACH_CHECK(semaphore_destroy(mach_task_self(), (semaphore_t)m_sema));
|
||||
MACH_CHECK(semaphore_create(mach_task_self(), (semaphore_t *)&m_sema, SYNC_POLICY_FIFO, 0));
|
||||
__atomic_store_n(&m_counter, 0, __ATOMIC_SEQ_CST);
|
||||
MACH_CHECK(semaphore_destroy(mach_task_self(), (semaphore_t)m_sema));
|
||||
MACH_CHECK(semaphore_create(mach_task_self(), (semaphore_t*)&m_sema, SYNC_POLICY_FIFO, 0));
|
||||
__atomic_store_n(&m_counter, 0, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
|
||||
void Threading::Semaphore::Post()
|
||||
{
|
||||
MACH_CHECK(semaphore_signal(m_sema));
|
||||
__atomic_add_fetch(&m_counter, 1, __ATOMIC_SEQ_CST);
|
||||
MACH_CHECK(semaphore_signal(m_sema));
|
||||
__atomic_add_fetch(&m_counter, 1, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
|
||||
void Threading::Semaphore::Post(int multiple)
|
||||
{
|
||||
for (int i = 0; i < multiple; ++i) {
|
||||
MACH_CHECK(semaphore_signal(m_sema));
|
||||
}
|
||||
__atomic_add_fetch(&m_counter, multiple, __ATOMIC_SEQ_CST);
|
||||
for (int i = 0; i < multiple; ++i)
|
||||
{
|
||||
MACH_CHECK(semaphore_signal(m_sema));
|
||||
}
|
||||
__atomic_add_fetch(&m_counter, multiple, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
|
||||
void Threading::Semaphore::WaitWithoutYield()
|
||||
{
|
||||
pxAssertMsg(!wxThread::IsMain(), "Unyielding semaphore wait issued from the main/gui thread. Please use Wait() instead.");
|
||||
MACH_CHECK(semaphore_wait(m_sema));
|
||||
__atomic_sub_fetch(&m_counter, 1, __ATOMIC_SEQ_CST);
|
||||
pxAssertMsg(!wxThread::IsMain(), "Unyielding semaphore wait issued from the main/gui thread. Please use Wait() instead.");
|
||||
MACH_CHECK(semaphore_wait(m_sema));
|
||||
__atomic_sub_fetch(&m_counter, 1, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
|
||||
bool Threading::Semaphore::WaitWithoutYield(const wxTimeSpan &timeout)
|
||||
bool Threading::Semaphore::WaitWithoutYield(const wxTimeSpan& timeout)
|
||||
{
|
||||
// This method is the reason why there has to be a special Darwin
|
||||
// implementation of Semaphore. Note that semaphore_timedwait() is prone
|
||||
// to returning with KERN_ABORTED, which basically signifies that some
|
||||
// signal has worken it up. The best official "documentation" for
|
||||
// semaphore_timedwait() is the way it's used in Grand Central Dispatch,
|
||||
// which is open-source.
|
||||
// This method is the reason why there has to be a special Darwin
|
||||
// implementation of Semaphore. Note that semaphore_timedwait() is prone
|
||||
// to returning with KERN_ABORTED, which basically signifies that some
|
||||
// signal has worken it up. The best official "documentation" for
|
||||
// semaphore_timedwait() is the way it's used in Grand Central Dispatch,
|
||||
// which is open-source.
|
||||
|
||||
// on x86 platforms, mach_absolute_time() returns nanoseconds
|
||||
// TODO(aktau): on iOS a scale value from mach_timebase_info will be necessary
|
||||
u64 const kOneThousand = 1000;
|
||||
u64 const kOneBillion = kOneThousand * kOneThousand * kOneThousand;
|
||||
u64 const delta = timeout.GetMilliseconds().GetValue() * (kOneThousand * kOneThousand);
|
||||
mach_timespec_t ts;
|
||||
kern_return_t kr = KERN_ABORTED;
|
||||
for (u64 now = mach_absolute_time(), deadline = now + delta;
|
||||
kr == KERN_ABORTED; now = mach_absolute_time()) {
|
||||
if (now > deadline) {
|
||||
// timed out by definition
|
||||
return false;
|
||||
}
|
||||
// on x86 platforms, mach_absolute_time() returns nanoseconds
|
||||
// TODO(aktau): on iOS a scale value from mach_timebase_info will be necessary
|
||||
u64 const kOneThousand = 1000;
|
||||
u64 const kOneBillion = kOneThousand * kOneThousand * kOneThousand;
|
||||
u64 const delta = timeout.GetMilliseconds().GetValue() * (kOneThousand * kOneThousand);
|
||||
mach_timespec_t ts;
|
||||
kern_return_t kr = KERN_ABORTED;
|
||||
for (u64 now = mach_absolute_time(), deadline = now + delta;
|
||||
kr == KERN_ABORTED; now = mach_absolute_time())
|
||||
{
|
||||
if (now > deadline)
|
||||
{
|
||||
// timed out by definition
|
||||
return false;
|
||||
}
|
||||
|
||||
u64 timeleft = deadline - now;
|
||||
ts.tv_sec = timeleft / kOneBillion;
|
||||
ts.tv_nsec = timeleft % kOneBillion;
|
||||
u64 timeleft = deadline - now;
|
||||
ts.tv_sec = timeleft / kOneBillion;
|
||||
ts.tv_nsec = timeleft % kOneBillion;
|
||||
|
||||
// possible return values of semaphore_timedwait() (from XNU sources):
|
||||
// internal kernel val -> return value
|
||||
// THREAD_INTERRUPTED -> KERN_ABORTED
|
||||
// THREAD_TIMED_OUT -> KERN_OPERATION_TIMED_OUT
|
||||
// THREAD_AWAKENED -> KERN_SUCCESS
|
||||
// THREAD_RESTART -> KERN_TERMINATED
|
||||
// default -> KERN_FAILURE
|
||||
kr = semaphore_timedwait(m_sema, ts);
|
||||
}
|
||||
// possible return values of semaphore_timedwait() (from XNU sources):
|
||||
// internal kernel val -> return value
|
||||
// THREAD_INTERRUPTED -> KERN_ABORTED
|
||||
// THREAD_TIMED_OUT -> KERN_OPERATION_TIMED_OUT
|
||||
// THREAD_AWAKENED -> KERN_SUCCESS
|
||||
// THREAD_RESTART -> KERN_TERMINATED
|
||||
// default -> KERN_FAILURE
|
||||
kr = semaphore_timedwait(m_sema, ts);
|
||||
}
|
||||
|
||||
if (kr == KERN_OPERATION_TIMED_OUT) {
|
||||
return false;
|
||||
}
|
||||
if (kr == KERN_OPERATION_TIMED_OUT)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// while it's entirely possible to have KERN_FAILURE here, we should
|
||||
// probably assert so we can study and correct the actual error here
|
||||
// (the thread dying while someone is wainting for it).
|
||||
MACH_CHECK(kr);
|
||||
// while it's entirely possible to have KERN_FAILURE here, we should
|
||||
// probably assert so we can study and correct the actual error here
|
||||
// (the thread dying while someone is wainting for it).
|
||||
MACH_CHECK(kr);
|
||||
|
||||
__atomic_sub_fetch(&m_counter, 1, __ATOMIC_SEQ_CST);
|
||||
return true;
|
||||
__atomic_sub_fetch(&m_counter, 1, __ATOMIC_SEQ_CST);
|
||||
return true;
|
||||
}
|
||||
|
||||
// This is a wxApp-safe implementation of Wait, which makes sure and executes the App's
|
||||
|
@ -155,18 +161,24 @@ bool Threading::Semaphore::WaitWithoutYield(const wxTimeSpan &timeout)
|
|||
void Threading::Semaphore::Wait()
|
||||
{
|
||||
#if wxUSE_GUI
|
||||
if (!wxThread::IsMain() || (wxTheApp == NULL)) {
|
||||
WaitWithoutYield();
|
||||
} else if (_WaitGui_RecursionGuard(L"Semaphore::Wait")) {
|
||||
ScopedBusyCursor hourglass(Cursor_ReallyBusy);
|
||||
WaitWithoutYield();
|
||||
} else {
|
||||
while (!WaitWithoutYield(def_yieldgui_interval)) {
|
||||
YieldToMain();
|
||||
}
|
||||
}
|
||||
if (!wxThread::IsMain() || (wxTheApp == NULL))
|
||||
{
|
||||
WaitWithoutYield();
|
||||
}
|
||||
else if (_WaitGui_RecursionGuard(L"Semaphore::Wait"))
|
||||
{
|
||||
ScopedBusyCursor hourglass(Cursor_ReallyBusy);
|
||||
WaitWithoutYield();
|
||||
}
|
||||
else
|
||||
{
|
||||
while (!WaitWithoutYield(def_yieldgui_interval))
|
||||
{
|
||||
YieldToMain();
|
||||
}
|
||||
}
|
||||
#else
|
||||
WaitWithoutYield();
|
||||
WaitWithoutYield();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -179,29 +191,35 @@ void Threading::Semaphore::Wait()
|
|||
// false if the wait timed out before the semaphore was signaled, or true if the signal was
|
||||
// reached prior to timeout.
|
||||
//
|
||||
bool Threading::Semaphore::Wait(const wxTimeSpan &timeout)
|
||||
bool Threading::Semaphore::Wait(const wxTimeSpan& timeout)
|
||||
{
|
||||
#if wxUSE_GUI
|
||||
if (!wxThread::IsMain() || (wxTheApp == NULL)) {
|
||||
return WaitWithoutYield(timeout);
|
||||
} else if (_WaitGui_RecursionGuard(L"Semaphore::TimedWait")) {
|
||||
ScopedBusyCursor hourglass(Cursor_ReallyBusy);
|
||||
return WaitWithoutYield(timeout);
|
||||
} else {
|
||||
//ScopedBusyCursor hourglass( Cursor_KindaBusy );
|
||||
wxTimeSpan countdown((timeout));
|
||||
if (!wxThread::IsMain() || (wxTheApp == NULL))
|
||||
{
|
||||
return WaitWithoutYield(timeout);
|
||||
}
|
||||
else if (_WaitGui_RecursionGuard(L"Semaphore::TimedWait"))
|
||||
{
|
||||
ScopedBusyCursor hourglass(Cursor_ReallyBusy);
|
||||
return WaitWithoutYield(timeout);
|
||||
}
|
||||
else
|
||||
{
|
||||
//ScopedBusyCursor hourglass( Cursor_KindaBusy );
|
||||
wxTimeSpan countdown((timeout));
|
||||
|
||||
do {
|
||||
if (WaitWithoutYield(def_yieldgui_interval))
|
||||
break;
|
||||
YieldToMain();
|
||||
countdown -= def_yieldgui_interval;
|
||||
} while (countdown.GetMilliseconds() > 0);
|
||||
do
|
||||
{
|
||||
if (WaitWithoutYield(def_yieldgui_interval))
|
||||
break;
|
||||
YieldToMain();
|
||||
countdown -= def_yieldgui_interval;
|
||||
} while (countdown.GetMilliseconds() > 0);
|
||||
|
||||
return countdown.GetMilliseconds() > 0;
|
||||
}
|
||||
return countdown.GetMilliseconds() > 0;
|
||||
}
|
||||
#else
|
||||
return WaitWithoutYield(timeout);
|
||||
return WaitWithoutYield(timeout);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -220,22 +238,22 @@ bool Threading::Semaphore::Wait(const wxTimeSpan &timeout)
|
|||
// POSIX threads), this should work. -- aktau
|
||||
void Threading::Semaphore::WaitNoCancel()
|
||||
{
|
||||
int oldstate;
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
|
||||
Wait();
|
||||
pthread_setcancelstate(oldstate, NULL);
|
||||
int oldstate;
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
|
||||
Wait();
|
||||
pthread_setcancelstate(oldstate, NULL);
|
||||
}
|
||||
|
||||
void Threading::Semaphore::WaitNoCancel(const wxTimeSpan &timeout)
|
||||
void Threading::Semaphore::WaitNoCancel(const wxTimeSpan& timeout)
|
||||
{
|
||||
int oldstate;
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
|
||||
Wait(timeout);
|
||||
pthread_setcancelstate(oldstate, NULL);
|
||||
int oldstate;
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
|
||||
Wait(timeout);
|
||||
pthread_setcancelstate(oldstate, NULL);
|
||||
}
|
||||
|
||||
int Threading::Semaphore::Count()
|
||||
{
|
||||
return __atomic_load_n(&m_counter, __ATOMIC_SEQ_CST);
|
||||
return __atomic_load_n(&m_counter, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -29,27 +29,27 @@
|
|||
|
||||
__forceinline void Threading::Sleep(int ms)
|
||||
{
|
||||
usleep(1000 * ms);
|
||||
usleep(1000 * ms);
|
||||
}
|
||||
|
||||
// For use in spin/wait loops, acts as a hint to Intel CPUs and should, in theory
|
||||
// improve performance and reduce cpu power consumption.
|
||||
__forceinline void Threading::SpinWait()
|
||||
{
|
||||
// If this doesn't compile you can just comment it out (it only serves as a
|
||||
// performance hint and isn't required).
|
||||
__asm__("pause");
|
||||
// If this doesn't compile you can just comment it out (it only serves as a
|
||||
// performance hint and isn't required).
|
||||
__asm__("pause");
|
||||
}
|
||||
|
||||
__forceinline void Threading::EnableHiresScheduler()
|
||||
{
|
||||
// Darwin has customizable schedulers, see xnu/osfmk/man. Not
|
||||
// implemented yet though (and not sure if useful for pcsx2).
|
||||
// Darwin has customizable schedulers, see xnu/osfmk/man. Not
|
||||
// implemented yet though (and not sure if useful for pcsx2).
|
||||
}
|
||||
|
||||
__forceinline void Threading::DisableHiresScheduler()
|
||||
{
|
||||
// see EnableHiresScheduler()
|
||||
// see EnableHiresScheduler()
|
||||
}
|
||||
|
||||
// Just like on Windows, this is not really the number of ticks per second,
|
||||
|
@ -58,27 +58,28 @@ __forceinline void Threading::DisableHiresScheduler()
|
|||
// doing this will of course yield precision loss.
|
||||
u64 Threading::GetThreadTicksPerSecond()
|
||||
{
|
||||
return 1000000; // the *CpuTime() functions return values in microseconds
|
||||
return 1000000; // the *CpuTime() functions return values in microseconds
|
||||
}
|
||||
|
||||
// gets the CPU time used by the current thread (both system and user), in
|
||||
// microseconds, returns 0 on failure
|
||||
static u64 getthreadtime(thread_port_t thread)
|
||||
{
|
||||
mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT;
|
||||
thread_basic_info_data_t info;
|
||||
mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT;
|
||||
thread_basic_info_data_t info;
|
||||
|
||||
kern_return_t kr = thread_info(thread, THREAD_BASIC_INFO,
|
||||
(thread_info_t)&info, &count);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
return 0;
|
||||
}
|
||||
kern_return_t kr = thread_info(thread, THREAD_BASIC_INFO,
|
||||
(thread_info_t)&info, &count);
|
||||
if (kr != KERN_SUCCESS)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// add system and user time
|
||||
return (u64)info.user_time.seconds * (u64)1e6 +
|
||||
(u64)info.user_time.microseconds +
|
||||
(u64)info.system_time.seconds * (u64)1e6 +
|
||||
(u64)info.system_time.microseconds;
|
||||
// add system and user time
|
||||
return (u64)info.user_time.seconds * (u64)1e6 +
|
||||
(u64)info.user_time.microseconds +
|
||||
(u64)info.system_time.seconds * (u64)1e6 +
|
||||
(u64)info.system_time.microseconds;
|
||||
}
|
||||
|
||||
// Returns the current timestamp (not relative to a real world clock) in
|
||||
|
@ -88,44 +89,45 @@ static u64 getthreadtime(thread_port_t thread)
|
|||
// not very good.
|
||||
u64 Threading::GetThreadCpuTime()
|
||||
{
|
||||
// we could also use mach_thread_self() and mach_port_deallocate(), but
|
||||
// that calls upon mach traps (kinda like system calls). Unless I missed
|
||||
// something in the COMMPAGE (like Linux vDSO) which makes overrides it
|
||||
// to be user-space instead. In contract,
|
||||
// pthread_mach_thread_np(pthread_self()) is entirely in user-space.
|
||||
u64 us = getthreadtime(pthread_mach_thread_np(pthread_self()));
|
||||
return us * 10ULL;
|
||||
// we could also use mach_thread_self() and mach_port_deallocate(), but
|
||||
// that calls upon mach traps (kinda like system calls). Unless I missed
|
||||
// something in the COMMPAGE (like Linux vDSO) which makes overrides it
|
||||
// to be user-space instead. In contract,
|
||||
// pthread_mach_thread_np(pthread_self()) is entirely in user-space.
|
||||
u64 us = getthreadtime(pthread_mach_thread_np(pthread_self()));
|
||||
return us * 10ULL;
|
||||
}
|
||||
|
||||
u64 Threading::pxThread::GetCpuTime() const
|
||||
{
|
||||
// Get the cpu time for the thread belonging to this object. Use m_native_id and/or
|
||||
// m_native_handle to implement it. Return value should be a measure of total time the
|
||||
// thread has used on the CPU (scaled by the value returned by GetThreadTicksPerSecond(),
|
||||
// which typically would be an OS-provided scalar or some sort).
|
||||
if (!m_native_id) {
|
||||
return 0;
|
||||
}
|
||||
// Get the cpu time for the thread belonging to this object. Use m_native_id and/or
|
||||
// m_native_handle to implement it. Return value should be a measure of total time the
|
||||
// thread has used on the CPU (scaled by the value returned by GetThreadTicksPerSecond(),
|
||||
// which typically would be an OS-provided scalar or some sort).
|
||||
if (!m_native_id)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return getthreadtime((thread_port_t)m_native_id) * 10ULL;
|
||||
return getthreadtime((thread_port_t)m_native_id) * 10ULL;
|
||||
}
|
||||
|
||||
void Threading::pxThread::_platform_specific_OnStartInThread()
|
||||
{
|
||||
m_native_id = (uptr)mach_thread_self();
|
||||
m_native_id = (uptr)mach_thread_self();
|
||||
}
|
||||
|
||||
void Threading::pxThread::_platform_specific_OnCleanupInThread()
|
||||
{
|
||||
// cleanup of handles that were upened in
|
||||
// _platform_specific_OnStartInThread
|
||||
mach_port_deallocate(mach_task_self(), (thread_port_t)m_native_id);
|
||||
// cleanup of handles that were upened in
|
||||
// _platform_specific_OnStartInThread
|
||||
mach_port_deallocate(mach_task_self(), (thread_port_t)m_native_id);
|
||||
}
|
||||
|
||||
// name can be up to 16 bytes
|
||||
void Threading::SetNameOfCurrentThread(const char *name)
|
||||
void Threading::SetNameOfCurrentThread(const char* name)
|
||||
{
|
||||
pthread_setname_np(name);
|
||||
pthread_setname_np(name);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -61,44 +61,48 @@
|
|||
// method is not implemented! You must implement it yourself if you want to use it:
|
||||
// EnumToString(value);
|
||||
//
|
||||
#define ImplementEnumOperators(enumName) \
|
||||
static __fi enumName &operator++(enumName &src) \
|
||||
{ \
|
||||
src = (enumName)((int)src + 1); \
|
||||
return src; \
|
||||
} \
|
||||
static __fi enumName &operator--(enumName &src) \
|
||||
{ \
|
||||
src = (enumName)((int)src - 1); \
|
||||
return src; \
|
||||
} \
|
||||
static __fi enumName operator++(enumName &src, int) \
|
||||
{ \
|
||||
enumName orig = src; \
|
||||
src = (enumName)((int)src + 1); \
|
||||
return orig; \
|
||||
} \
|
||||
static __fi enumName operator--(enumName &src, int) \
|
||||
{ \
|
||||
enumName orig = src; \
|
||||
src = (enumName)((int)src - 1); \
|
||||
return orig; \
|
||||
} \
|
||||
\
|
||||
static __fi bool operator<(const enumName &left, const pxEnumEnd_t &) { return (int)left < enumName##_COUNT; } \
|
||||
static __fi bool operator!=(const enumName &left, const pxEnumEnd_t &) { return (int)left != enumName##_COUNT; } \
|
||||
static __fi bool operator==(const enumName &left, const pxEnumEnd_t &) { return (int)left == enumName##_COUNT; } \
|
||||
\
|
||||
static __fi bool EnumIsValid(enumName id) \
|
||||
{ \
|
||||
return ((int)id >= enumName##_FIRST) && ((int)id < enumName##_COUNT); \
|
||||
} \
|
||||
static __fi void EnumAssert(enumName id) \
|
||||
{ \
|
||||
pxAssert(EnumIsValid(id)); \
|
||||
} \
|
||||
\
|
||||
extern const wxChar *EnumToString(enumName id)
|
||||
#define ImplementEnumOperators(enumName) \
|
||||
static __fi enumName& operator++(enumName& src) \
|
||||
{ \
|
||||
src = (enumName)((int)src + 1); \
|
||||
return src; \
|
||||
} \
|
||||
\
|
||||
static __fi enumName& operator--(enumName& src) \
|
||||
{ \
|
||||
src = (enumName)((int)src - 1); \
|
||||
return src; \
|
||||
} \
|
||||
\
|
||||
static __fi enumName operator++(enumName& src, int) \
|
||||
{ \
|
||||
enumName orig = src; \
|
||||
src = (enumName)((int)src + 1); \
|
||||
return orig; \
|
||||
} \
|
||||
\
|
||||
static __fi enumName operator--(enumName& src, int) \
|
||||
{ \
|
||||
enumName orig = src; \
|
||||
src = (enumName)((int)src - 1); \
|
||||
return orig; \
|
||||
} \
|
||||
\
|
||||
static __fi bool operator<(const enumName& left, const pxEnumEnd_t&) { return (int)left < enumName##_COUNT; } \
|
||||
static __fi bool operator!=(const enumName& left, const pxEnumEnd_t&) { return (int)left != enumName##_COUNT; } \
|
||||
static __fi bool operator==(const enumName& left, const pxEnumEnd_t&) { return (int)left == enumName##_COUNT; } \
|
||||
\
|
||||
static __fi bool EnumIsValid(enumName id) \
|
||||
{ \
|
||||
return ((int)id >= enumName##_FIRST) && ((int)id < enumName##_COUNT); \
|
||||
} \
|
||||
\
|
||||
static __fi void EnumAssert(enumName id) \
|
||||
{ \
|
||||
pxAssert(EnumIsValid(id)); \
|
||||
} \
|
||||
\
|
||||
extern const wxChar* EnumToString(enumName id)
|
||||
|
||||
class pxEnumEnd_t
|
||||
{
|
||||
|
@ -130,9 +134,9 @@ static const pxEnumEnd_t pxEnumEnd = {};
|
|||
//
|
||||
#ifndef DeclareNoncopyableObject
|
||||
#define DeclareNoncopyableObject(classname) \
|
||||
private: \
|
||||
explicit classname(const classname &); \
|
||||
classname &operator=(const classname &)
|
||||
private: \
|
||||
explicit classname(const classname&); \
|
||||
classname& operator=(const classname&)
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -144,19 +148,19 @@ private: \
|
|||
class ScopedBool
|
||||
{
|
||||
protected:
|
||||
bool *m_boolme;
|
||||
bool* m_boolme;
|
||||
|
||||
public:
|
||||
ScopedBool(bool &boolme)
|
||||
{
|
||||
boolme = true;
|
||||
m_boolme = &boolme;
|
||||
}
|
||||
ScopedBool(bool& boolme)
|
||||
{
|
||||
boolme = true;
|
||||
m_boolme = &boolme;
|
||||
}
|
||||
|
||||
~ScopedBool()
|
||||
{
|
||||
*m_boolme = false;
|
||||
}
|
||||
~ScopedBool()
|
||||
{
|
||||
*m_boolme = false;
|
||||
}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -218,7 +222,7 @@ public:
|
|||
|
||||
#include <stdexcept>
|
||||
#include <cstring> // string.h under c++
|
||||
#include <cstdio> // stdio.h under c++
|
||||
#include <cstdio> // stdio.h under c++
|
||||
#include <cstdlib>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
|
@ -262,12 +266,12 @@ static const s64 _4gb = _1gb * 4;
|
|||
#define pxE_dev(english) pxExpandMsg((english))
|
||||
|
||||
|
||||
extern const wxChar *__fastcall pxExpandMsg(const wxChar *message);
|
||||
extern const wxChar *__fastcall pxGetTranslation(const wxChar *message);
|
||||
extern const wxChar* __fastcall pxExpandMsg(const wxChar* message);
|
||||
extern const wxChar* __fastcall pxGetTranslation(const wxChar* message);
|
||||
extern bool pxIsEnglish(int id);
|
||||
|
||||
extern wxString fromUTF8(const char *src);
|
||||
extern wxString fromAscii(const char *src);
|
||||
extern wxString fromUTF8(const char* src);
|
||||
extern wxString fromAscii(const char* src);
|
||||
|
||||
|
||||
#include "common/Assertions.h"
|
||||
|
|
|
@ -25,8 +25,8 @@
|
|||
class IEmbeddedImage
|
||||
{
|
||||
public:
|
||||
virtual const wxImage &Get() = 0;
|
||||
virtual wxImage Scale(int width, int height) = 0;
|
||||
virtual const wxImage& Get() = 0;
|
||||
virtual wxImage Scale(int width, int height) = 0;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -42,79 +42,80 @@ template <typename ImageType>
|
|||
class EmbeddedImage : public IEmbeddedImage
|
||||
{
|
||||
protected:
|
||||
wxImage m_Image;
|
||||
const wxSize m_ResampleTo;
|
||||
wxImage m_Image;
|
||||
const wxSize m_ResampleTo;
|
||||
|
||||
protected:
|
||||
// ------------------------------------------------------------------------
|
||||
// Internal function used to ensure the image is loaded before returning the image
|
||||
// handle (called from all methods that return an image handle).
|
||||
//
|
||||
void _loadImage()
|
||||
{
|
||||
if (!m_Image.Ok()) {
|
||||
wxMemoryInputStream joe(ImageType::Data, ImageType::Length);
|
||||
m_Image.LoadFile(joe, ImageType::GetFormat());
|
||||
// ------------------------------------------------------------------------
|
||||
// Internal function used to ensure the image is loaded before returning the image
|
||||
// handle (called from all methods that return an image handle).
|
||||
//
|
||||
void _loadImage()
|
||||
{
|
||||
if (!m_Image.Ok())
|
||||
{
|
||||
wxMemoryInputStream joe(ImageType::Data, ImageType::Length);
|
||||
m_Image.LoadFile(joe, ImageType::GetFormat());
|
||||
|
||||
if (m_ResampleTo.IsFullySpecified() && (m_ResampleTo.GetWidth() != m_Image.GetWidth() || m_ResampleTo.GetHeight() != m_Image.GetHeight()))
|
||||
m_Image.Rescale(m_ResampleTo.GetWidth(), m_ResampleTo.GetHeight(), wxIMAGE_QUALITY_HIGH);
|
||||
}
|
||||
}
|
||||
if (m_ResampleTo.IsFullySpecified() && (m_ResampleTo.GetWidth() != m_Image.GetWidth() || m_ResampleTo.GetHeight() != m_Image.GetHeight()))
|
||||
m_Image.Rescale(m_ResampleTo.GetWidth(), m_ResampleTo.GetHeight(), wxIMAGE_QUALITY_HIGH);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
EmbeddedImage()
|
||||
: m_Image()
|
||||
, m_ResampleTo(wxDefaultSize)
|
||||
{
|
||||
}
|
||||
EmbeddedImage()
|
||||
: m_Image()
|
||||
, m_ResampleTo(wxDefaultSize)
|
||||
{
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Constructor for creating an embedded image that gets resampled to the specified size when
|
||||
// loaded.
|
||||
//
|
||||
// Implementation Note: This function uses wxWidgets ResamplBox method to resize the image.
|
||||
// wxWidgets ResampleBicubic appears to be buggy and produces fairly poor results when down-
|
||||
// sampling images (basically resembles a pixel resize). ResampleBox produces much cleaner
|
||||
// results.
|
||||
//
|
||||
EmbeddedImage(int newWidth, int newHeight)
|
||||
: m_Image()
|
||||
, m_ResampleTo(newWidth, newHeight)
|
||||
{
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
// Constructor for creating an embedded image that gets resampled to the specified size when
|
||||
// loaded.
|
||||
//
|
||||
// Implementation Note: This function uses wxWidgets ResamplBox method to resize the image.
|
||||
// wxWidgets ResampleBicubic appears to be buggy and produces fairly poor results when down-
|
||||
// sampling images (basically resembles a pixel resize). ResampleBox produces much cleaner
|
||||
// results.
|
||||
//
|
||||
EmbeddedImage(int newWidth, int newHeight)
|
||||
: m_Image()
|
||||
, m_ResampleTo(newWidth, newHeight)
|
||||
{
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Loads and retrieves the embedded image. The embedded image is only loaded from its em-
|
||||
// bedded format once. Any subsequent calls to Get(), Rescale(), or Resample() will use
|
||||
// the pre-loaded copy. Translation: the png/jpeg decoding overhead happens only once,
|
||||
// and only happens when the image is actually fetched. Simply creating an instance
|
||||
// of an EmbeddedImage object uses no excess memory nor cpu overhead. :)
|
||||
//
|
||||
const wxImage &Get()
|
||||
{
|
||||
_loadImage();
|
||||
return m_Image;
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
// Loads and retrieves the embedded image. The embedded image is only loaded from its em-
|
||||
// bedded format once. Any subsequent calls to Get(), Rescale(), or Resample() will use
|
||||
// the pre-loaded copy. Translation: the png/jpeg decoding overhead happens only once,
|
||||
// and only happens when the image is actually fetched. Simply creating an instance
|
||||
// of an EmbeddedImage object uses no excess memory nor cpu overhead. :)
|
||||
//
|
||||
const wxImage& Get()
|
||||
{
|
||||
_loadImage();
|
||||
return m_Image;
|
||||
}
|
||||
|
||||
wxIcon GetIcon()
|
||||
{
|
||||
wxIcon retval;
|
||||
retval.CopyFromBitmap(Get());
|
||||
return retval;
|
||||
}
|
||||
wxIcon GetIcon()
|
||||
{
|
||||
wxIcon retval;
|
||||
retval.CopyFromBitmap(Get());
|
||||
return retval;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Performs a pixel resize of the loaded image and returns a new image handle (EmbeddedImage
|
||||
// is left unmodified).
|
||||
//
|
||||
// ------------------------------------------------------------------------
|
||||
// Performs a pixel resize of the loaded image and returns a new image handle (EmbeddedImage
|
||||
// is left unmodified).
|
||||
//
|
||||
|
||||
wxImage Scale(int width, int height)
|
||||
{
|
||||
_loadImage();
|
||||
// Not strictly necessary - wxWidgets does the dimensions check anyway.
|
||||
if (width != m_Image.GetWidth() || height != m_Image.GetHeight())
|
||||
return m_Image.Scale(width, height, wxIMAGE_QUALITY_HIGH);
|
||||
else
|
||||
return m_Image;
|
||||
}
|
||||
wxImage Scale(int width, int height)
|
||||
{
|
||||
_loadImage();
|
||||
// Not strictly necessary - wxWidgets does the dimensions check anyway.
|
||||
if (width != m_Image.GetWidth() || height != m_Image.GetHeight())
|
||||
return m_Image.Scale(width, height, wxIMAGE_QUALITY_HIGH);
|
||||
else
|
||||
return m_Image;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -26,54 +26,54 @@ template <typename ListenerType>
|
|||
class EventSource
|
||||
{
|
||||
public:
|
||||
typedef typename ListenerType::EvtParams EvtParams;
|
||||
typedef typename std::list<ListenerType *> ListenerList;
|
||||
typedef typename ListenerList::iterator ListenerIterator;
|
||||
typedef typename ListenerType::EvtParams EvtParams;
|
||||
typedef typename std::list<ListenerType*> ListenerList;
|
||||
typedef typename ListenerList::iterator ListenerIterator;
|
||||
|
||||
protected:
|
||||
typedef typename ListenerList::const_iterator ConstIterator;
|
||||
typedef typename ListenerList::const_iterator ConstIterator;
|
||||
|
||||
ListenerList m_listeners;
|
||||
ListenerList m_listeners;
|
||||
|
||||
// This is a cached copy of the listener list used to handle standard dispatching, which
|
||||
// allows for self-modification of the EventSource's listener list by the listeners.
|
||||
// Translation: The dispatcher uses this copy instead, to avoid iterator invalidation.
|
||||
ListenerList m_cache_copy;
|
||||
bool m_cache_valid;
|
||||
// This is a cached copy of the listener list used to handle standard dispatching, which
|
||||
// allows for self-modification of the EventSource's listener list by the listeners.
|
||||
// Translation: The dispatcher uses this copy instead, to avoid iterator invalidation.
|
||||
ListenerList m_cache_copy;
|
||||
bool m_cache_valid;
|
||||
|
||||
Threading::Mutex m_listeners_lock;
|
||||
Threading::Mutex m_listeners_lock;
|
||||
|
||||
public:
|
||||
EventSource()
|
||||
{
|
||||
m_cache_valid = false;
|
||||
}
|
||||
EventSource()
|
||||
{
|
||||
m_cache_valid = false;
|
||||
}
|
||||
|
||||
virtual ~EventSource() = default;
|
||||
virtual ~EventSource() = default;
|
||||
|
||||
virtual ListenerIterator Add(ListenerType &listener);
|
||||
virtual void Remove(ListenerType &listener);
|
||||
virtual void Remove(const ListenerIterator &listenerHandle);
|
||||
virtual ListenerIterator Add(ListenerType& listener);
|
||||
virtual void Remove(ListenerType& listener);
|
||||
virtual void Remove(const ListenerIterator& listenerHandle);
|
||||
|
||||
void Add(ListenerType *listener)
|
||||
{
|
||||
if (listener == NULL)
|
||||
return;
|
||||
Add(*listener);
|
||||
}
|
||||
void Add(ListenerType* listener)
|
||||
{
|
||||
if (listener == NULL)
|
||||
return;
|
||||
Add(*listener);
|
||||
}
|
||||
|
||||
void Remove(ListenerType *listener)
|
||||
{
|
||||
if (listener == NULL)
|
||||
return;
|
||||
Remove(*listener);
|
||||
}
|
||||
void Remove(ListenerType* listener)
|
||||
{
|
||||
if (listener == NULL)
|
||||
return;
|
||||
Remove(*listener);
|
||||
}
|
||||
|
||||
void Dispatch(const EvtParams ¶ms);
|
||||
void Dispatch(const EvtParams& params);
|
||||
|
||||
protected:
|
||||
virtual ListenerIterator _AddFast_without_lock(ListenerType &listener);
|
||||
virtual void _DispatchRaw(ListenerIterator iter, const ListenerIterator &iend, const EvtParams ¶ms);
|
||||
virtual ListenerIterator _AddFast_without_lock(ListenerType& listener);
|
||||
virtual void _DispatchRaw(ListenerIterator iter, const ListenerIterator& iend, const EvtParams& params);
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -86,9 +86,9 @@ template <typename EvtParams>
|
|||
class IEventDispatcher
|
||||
{
|
||||
protected:
|
||||
IEventDispatcher() {}
|
||||
IEventDispatcher() {}
|
||||
|
||||
public:
|
||||
virtual ~IEventDispatcher() = default;
|
||||
virtual void DispatchEvent(const EvtParams ¶ms) = 0;
|
||||
virtual ~IEventDispatcher() = default;
|
||||
virtual void DispatchEvent(const EvtParams& params) = 0;
|
||||
};
|
||||
|
|
|
@ -20,79 +20,92 @@
|
|||
using Threading::ScopedLock;
|
||||
|
||||
template <typename ListenerType>
|
||||
typename EventSource<ListenerType>::ListenerIterator EventSource<ListenerType>::Add(ListenerType &listener)
|
||||
typename EventSource<ListenerType>::ListenerIterator EventSource<ListenerType>::Add(ListenerType& listener)
|
||||
{
|
||||
ScopedLock locker(m_listeners_lock);
|
||||
ScopedLock locker(m_listeners_lock);
|
||||
|
||||
// Check for duplicates before adding the event.
|
||||
if (IsDebugBuild) {
|
||||
ListenerIterator iter = m_listeners.begin();
|
||||
while (iter != m_listeners.end()) {
|
||||
if ((*iter) == &listener)
|
||||
return iter;
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
return _AddFast_without_lock(listener);
|
||||
// Check for duplicates before adding the event.
|
||||
if (IsDebugBuild)
|
||||
{
|
||||
ListenerIterator iter = m_listeners.begin();
|
||||
while (iter != m_listeners.end())
|
||||
{
|
||||
if ((*iter) == &listener)
|
||||
return iter;
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
return _AddFast_without_lock(listener);
|
||||
}
|
||||
|
||||
template <typename ListenerType>
|
||||
void EventSource<ListenerType>::Remove(ListenerType &listener)
|
||||
void EventSource<ListenerType>::Remove(ListenerType& listener)
|
||||
{
|
||||
ScopedLock locker(m_listeners_lock);
|
||||
m_cache_valid = false;
|
||||
m_listeners.remove(&listener);
|
||||
ScopedLock locker(m_listeners_lock);
|
||||
m_cache_valid = false;
|
||||
m_listeners.remove(&listener);
|
||||
}
|
||||
|
||||
template <typename ListenerType>
|
||||
void EventSource<ListenerType>::Remove(const ListenerIterator &listenerHandle)
|
||||
void EventSource<ListenerType>::Remove(const ListenerIterator& listenerHandle)
|
||||
{
|
||||
ScopedLock locker(m_listeners_lock);
|
||||
m_cache_valid = false;
|
||||
m_listeners.erase(listenerHandle);
|
||||
ScopedLock locker(m_listeners_lock);
|
||||
m_cache_valid = false;
|
||||
m_listeners.erase(listenerHandle);
|
||||
}
|
||||
|
||||
template <typename ListenerType>
|
||||
typename EventSource<ListenerType>::ListenerIterator EventSource<ListenerType>::_AddFast_without_lock(ListenerType &listener)
|
||||
typename EventSource<ListenerType>::ListenerIterator EventSource<ListenerType>::_AddFast_without_lock(ListenerType& listener)
|
||||
{
|
||||
m_cache_valid = false;
|
||||
m_listeners.push_front(&listener);
|
||||
return m_listeners.begin();
|
||||
m_cache_valid = false;
|
||||
m_listeners.push_front(&listener);
|
||||
return m_listeners.begin();
|
||||
}
|
||||
|
||||
|
||||
template <typename ListenerType>
|
||||
__fi void EventSource<ListenerType>::_DispatchRaw(ListenerIterator iter, const ListenerIterator &iend, const EvtParams &evtparams)
|
||||
__fi void EventSource<ListenerType>::_DispatchRaw(ListenerIterator iter, const ListenerIterator& iend, const EvtParams& evtparams)
|
||||
{
|
||||
while (iter != iend) {
|
||||
try {
|
||||
(*iter)->DispatchEvent(evtparams);
|
||||
} catch (Exception::RuntimeError &ex) {
|
||||
if (IsDevBuild) {
|
||||
pxFailDev(L"Ignoring runtime error thrown from event listener (event listeners should not throw exceptions!): " + ex.FormatDiagnosticMessage());
|
||||
} else {
|
||||
Console.Error(L"Ignoring runtime error thrown from event listener: " + ex.FormatDiagnosticMessage());
|
||||
}
|
||||
} catch (BaseException &ex) {
|
||||
if (IsDevBuild) {
|
||||
ex.DiagMsg() = L"Non-runtime BaseException thrown from event listener .. " + ex.DiagMsg();
|
||||
throw;
|
||||
}
|
||||
Console.Error(L"Ignoring non-runtime BaseException thrown from event listener: " + ex.FormatDiagnosticMessage());
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
while (iter != iend)
|
||||
{
|
||||
try
|
||||
{
|
||||
(*iter)->DispatchEvent(evtparams);
|
||||
}
|
||||
catch (Exception::RuntimeError& ex)
|
||||
{
|
||||
if (IsDevBuild)
|
||||
{
|
||||
pxFailDev(L"Ignoring runtime error thrown from event listener (event listeners should not throw exceptions!): " + ex.FormatDiagnosticMessage());
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Error(L"Ignoring runtime error thrown from event listener: " + ex.FormatDiagnosticMessage());
|
||||
}
|
||||
}
|
||||
catch (BaseException& ex)
|
||||
{
|
||||
if (IsDevBuild)
|
||||
{
|
||||
ex.DiagMsg() = L"Non-runtime BaseException thrown from event listener .. " + ex.DiagMsg();
|
||||
throw;
|
||||
}
|
||||
Console.Error(L"Ignoring non-runtime BaseException thrown from event listener: " + ex.FormatDiagnosticMessage());
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ListenerType>
|
||||
void EventSource<ListenerType>::Dispatch(const EvtParams &evtparams)
|
||||
void EventSource<ListenerType>::Dispatch(const EvtParams& evtparams)
|
||||
{
|
||||
if (!m_cache_valid) {
|
||||
m_cache_copy = m_listeners;
|
||||
m_cache_valid = true;
|
||||
}
|
||||
if (!m_cache_valid)
|
||||
{
|
||||
m_cache_copy = m_listeners;
|
||||
m_cache_valid = true;
|
||||
}
|
||||
|
||||
if (m_cache_copy.empty())
|
||||
return;
|
||||
_DispatchRaw(m_cache_copy.begin(), m_cache_copy.end(), evtparams);
|
||||
if (m_cache_copy.empty())
|
||||
return;
|
||||
_DispatchRaw(m_cache_copy.begin(), m_cache_copy.end(), evtparams);
|
||||
}
|
||||
|
|
|
@ -42,28 +42,28 @@ Fnptr_OutOfMemory pxDoOutOfMemory = NULL;
|
|||
// That's ok. What we don't want is the *same* thread recurse-asserting.
|
||||
static DeclareTls(int) s_assert_guard(0);
|
||||
|
||||
pxDoAssertFnType *pxDoAssert = pxAssertImpl_LogIt;
|
||||
pxDoAssertFnType* pxDoAssert = pxAssertImpl_LogIt;
|
||||
|
||||
// make life easier for people using VC++ IDE by using this format, which allows double-click
|
||||
// response times from the Output window...
|
||||
wxString DiagnosticOrigin::ToString(const wxChar *msg) const
|
||||
wxString DiagnosticOrigin::ToString(const wxChar* msg) const
|
||||
{
|
||||
FastFormatUnicode message;
|
||||
FastFormatUnicode message;
|
||||
|
||||
message.Write(L"%ls(%d) : assertion failed:\n", srcfile, line);
|
||||
message.Write(L"%ls(%d) : assertion failed:\n", srcfile, line);
|
||||
|
||||
if (function != NULL)
|
||||
message.Write(" Function: %s\n", function);
|
||||
if (function != NULL)
|
||||
message.Write(" Function: %s\n", function);
|
||||
|
||||
message.Write(L" Thread: %s\n", WX_STR(Threading::pxGetCurrentThreadName()));
|
||||
message.Write(L" Thread: %s\n", WX_STR(Threading::pxGetCurrentThreadName()));
|
||||
|
||||
if (condition != NULL)
|
||||
message.Write(L" Condition: %ls\n", condition);
|
||||
if (condition != NULL)
|
||||
message.Write(L" Condition: %ls\n", condition);
|
||||
|
||||
if (msg != NULL)
|
||||
message.Write(L" Message: %ls\n", msg);
|
||||
if (msg != NULL)
|
||||
message.Write(L" Message: %ls\n", msg);
|
||||
|
||||
return message;
|
||||
return message;
|
||||
}
|
||||
|
||||
|
||||
|
@ -71,191 +71,196 @@ wxString DiagnosticOrigin::ToString(const wxChar *msg) const
|
|||
void pxTrap()
|
||||
{
|
||||
#if defined(__WXMSW__) && !defined(__WXMICROWIN__)
|
||||
__debugbreak();
|
||||
__debugbreak();
|
||||
#elif defined(__WXMAC__) && !defined(__DARWIN__)
|
||||
#if __powerc
|
||||
Debugger();
|
||||
Debugger();
|
||||
#else
|
||||
SysBreak();
|
||||
SysBreak();
|
||||
#endif
|
||||
#elif defined(_MSL_USING_MW_C_HEADERS) && _MSL_USING_MW_C_HEADERS
|
||||
Debugger();
|
||||
Debugger();
|
||||
#elif defined(__UNIX__)
|
||||
raise(SIGTRAP);
|
||||
raise(SIGTRAP);
|
||||
#else
|
||||
// TODO
|
||||
#endif // Win/Unix
|
||||
}
|
||||
|
||||
|
||||
bool pxAssertImpl_LogIt(const DiagnosticOrigin &origin, const wxChar *msg)
|
||||
bool pxAssertImpl_LogIt(const DiagnosticOrigin& origin, const wxChar* msg)
|
||||
{
|
||||
//wxLogError( L"%s", origin.ToString( msg ).c_str() );
|
||||
wxMessageOutputDebug().Printf(L"%s", origin.ToString(msg).c_str());
|
||||
pxTrap();
|
||||
return false;
|
||||
//wxLogError( L"%s", origin.ToString( msg ).c_str() );
|
||||
wxMessageOutputDebug().Printf(L"%s", origin.ToString(msg).c_str());
|
||||
pxTrap();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
DEVASSERT_INLINE void pxOnAssert(const DiagnosticOrigin &origin, const wxString &msg)
|
||||
DEVASSERT_INLINE void pxOnAssert(const DiagnosticOrigin& origin, const wxString& msg)
|
||||
{
|
||||
// Recursion guard: Allow at least one recursive call. This is useful because sometimes
|
||||
// we get meaningless assertions while unwinding stack traces after exceptions have occurred.
|
||||
// Recursion guard: Allow at least one recursive call. This is useful because sometimes
|
||||
// we get meaningless assertions while unwinding stack traces after exceptions have occurred.
|
||||
|
||||
RecursionGuard guard(s_assert_guard);
|
||||
if (guard.Counter > 2) {
|
||||
return pxTrap();
|
||||
}
|
||||
RecursionGuard guard(s_assert_guard);
|
||||
if (guard.Counter > 2)
|
||||
{
|
||||
return pxTrap();
|
||||
}
|
||||
|
||||
// wxWidgets doesn't come with debug builds on some Linux distros, and other distros make
|
||||
// it difficult to use the debug build (compilation failures). To handle these I've had to
|
||||
// bypass the internal wxWidgets assertion handler entirely, since it may not exist even if
|
||||
// PCSX2 itself is compiled in debug mode (assertions enabled).
|
||||
// wxWidgets doesn't come with debug builds on some Linux distros, and other distros make
|
||||
// it difficult to use the debug build (compilation failures). To handle these I've had to
|
||||
// bypass the internal wxWidgets assertion handler entirely, since it may not exist even if
|
||||
// PCSX2 itself is compiled in debug mode (assertions enabled).
|
||||
|
||||
bool trapit;
|
||||
bool trapit;
|
||||
|
||||
if (pxDoAssert == NULL) {
|
||||
// Note: Format uses MSVC's syntax for output window hotlinking.
|
||||
trapit = pxAssertImpl_LogIt(origin, msg.wc_str());
|
||||
} else {
|
||||
trapit = pxDoAssert(origin, msg.wc_str());
|
||||
}
|
||||
if (pxDoAssert == NULL)
|
||||
{
|
||||
// Note: Format uses MSVC's syntax for output window hotlinking.
|
||||
trapit = pxAssertImpl_LogIt(origin, msg.wc_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
trapit = pxDoAssert(origin, msg.wc_str());
|
||||
}
|
||||
|
||||
if (trapit) {
|
||||
pxTrap();
|
||||
}
|
||||
if (trapit)
|
||||
{
|
||||
pxTrap();
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// BaseException (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
BaseException &BaseException::SetBothMsgs(const wxChar *msg_diag)
|
||||
BaseException& BaseException::SetBothMsgs(const wxChar* msg_diag)
|
||||
{
|
||||
m_message_user = msg_diag ? wxString(wxGetTranslation(msg_diag)) : wxString("");
|
||||
return SetDiagMsg(msg_diag);
|
||||
m_message_user = msg_diag ? wxString(wxGetTranslation(msg_diag)) : wxString("");
|
||||
return SetDiagMsg(msg_diag);
|
||||
}
|
||||
|
||||
BaseException &BaseException::SetDiagMsg(const wxString &msg_diag)
|
||||
BaseException& BaseException::SetDiagMsg(const wxString& msg_diag)
|
||||
{
|
||||
m_message_diag = msg_diag;
|
||||
return *this;
|
||||
m_message_diag = msg_diag;
|
||||
return *this;
|
||||
}
|
||||
|
||||
BaseException &BaseException::SetUserMsg(const wxString &msg_user)
|
||||
BaseException& BaseException::SetUserMsg(const wxString& msg_user)
|
||||
{
|
||||
m_message_user = msg_user;
|
||||
return *this;
|
||||
m_message_user = msg_user;
|
||||
return *this;
|
||||
}
|
||||
|
||||
wxString BaseException::FormatDiagnosticMessage() const
|
||||
{
|
||||
return m_message_diag;
|
||||
return m_message_diag;
|
||||
}
|
||||
|
||||
wxString BaseException::FormatDisplayMessage() const
|
||||
{
|
||||
return m_message_user.IsEmpty() ? m_message_diag : m_message_user;
|
||||
return m_message_user.IsEmpty() ? m_message_diag : m_message_user;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Exception::RuntimeError (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
Exception::RuntimeError::RuntimeError(const std::runtime_error &ex, const wxString &prefix)
|
||||
Exception::RuntimeError::RuntimeError(const std::runtime_error& ex, const wxString& prefix)
|
||||
{
|
||||
IsSilent = false;
|
||||
IsSilent = false;
|
||||
|
||||
SetDiagMsg(pxsFmt(L"STL Runtime Error%s: %s",
|
||||
(prefix.IsEmpty() ? L"" : pxsFmt(L" (%s)", WX_STR(prefix)).c_str()),
|
||||
WX_STR(fromUTF8(ex.what()))));
|
||||
SetDiagMsg(pxsFmt(L"STL Runtime Error%s: %s",
|
||||
(prefix.IsEmpty() ? L"" : pxsFmt(L" (%s)", WX_STR(prefix)).c_str()),
|
||||
WX_STR(fromUTF8(ex.what()))));
|
||||
}
|
||||
|
||||
Exception::RuntimeError::RuntimeError(const std::exception &ex, const wxString &prefix)
|
||||
Exception::RuntimeError::RuntimeError(const std::exception& ex, const wxString& prefix)
|
||||
{
|
||||
IsSilent = false;
|
||||
IsSilent = false;
|
||||
|
||||
SetDiagMsg(pxsFmt(L"STL Exception%s: %s",
|
||||
(prefix.IsEmpty() ? L"" : pxsFmt(L" (%s)", WX_STR(prefix)).c_str()),
|
||||
WX_STR(fromUTF8(ex.what()))));
|
||||
SetDiagMsg(pxsFmt(L"STL Exception%s: %s",
|
||||
(prefix.IsEmpty() ? L"" : pxsFmt(L" (%s)", WX_STR(prefix)).c_str()),
|
||||
WX_STR(fromUTF8(ex.what()))));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Exception::OutOfMemory (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
Exception::OutOfMemory::OutOfMemory(const wxString &allocdesc)
|
||||
Exception::OutOfMemory::OutOfMemory(const wxString& allocdesc)
|
||||
{
|
||||
AllocDescription = allocdesc;
|
||||
AllocDescription = allocdesc;
|
||||
}
|
||||
|
||||
wxString Exception::OutOfMemory::FormatDiagnosticMessage() const
|
||||
{
|
||||
FastFormatUnicode retmsg;
|
||||
retmsg.Write(L"Out of memory");
|
||||
if (!AllocDescription.IsEmpty())
|
||||
retmsg.Write(L" while allocating '%s'", WX_STR(AllocDescription));
|
||||
FastFormatUnicode retmsg;
|
||||
retmsg.Write(L"Out of memory");
|
||||
if (!AllocDescription.IsEmpty())
|
||||
retmsg.Write(L" while allocating '%s'", WX_STR(AllocDescription));
|
||||
|
||||
if (!m_message_diag.IsEmpty())
|
||||
retmsg.Write(L":\n%s", WX_STR(m_message_diag));
|
||||
if (!m_message_diag.IsEmpty())
|
||||
retmsg.Write(L":\n%s", WX_STR(m_message_diag));
|
||||
|
||||
return retmsg;
|
||||
return retmsg;
|
||||
}
|
||||
|
||||
wxString Exception::OutOfMemory::FormatDisplayMessage() const
|
||||
{
|
||||
FastFormatUnicode retmsg;
|
||||
retmsg.Write(L"%s", _("Oh noes! Out of memory!"));
|
||||
FastFormatUnicode retmsg;
|
||||
retmsg.Write(L"%s", _("Oh noes! Out of memory!"));
|
||||
|
||||
if (!m_message_user.IsEmpty())
|
||||
retmsg.Write(L"\n\n%s", WX_STR(m_message_user));
|
||||
if (!m_message_user.IsEmpty())
|
||||
retmsg.Write(L"\n\n%s", WX_STR(m_message_user));
|
||||
|
||||
return retmsg;
|
||||
return retmsg;
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Exception::VirtualMemoryMapConflict (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
Exception::VirtualMemoryMapConflict::VirtualMemoryMapConflict(const wxString &allocdesc)
|
||||
Exception::VirtualMemoryMapConflict::VirtualMemoryMapConflict(const wxString& allocdesc)
|
||||
{
|
||||
AllocDescription = 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.");
|
||||
AllocDescription = 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.");
|
||||
}
|
||||
|
||||
wxString Exception::VirtualMemoryMapConflict::FormatDiagnosticMessage() const
|
||||
{
|
||||
FastFormatUnicode retmsg;
|
||||
retmsg.Write(L"Virtual memory map failed");
|
||||
if (!AllocDescription.IsEmpty())
|
||||
retmsg.Write(L" while reserving '%s'", WX_STR(AllocDescription));
|
||||
FastFormatUnicode retmsg;
|
||||
retmsg.Write(L"Virtual memory map failed");
|
||||
if (!AllocDescription.IsEmpty())
|
||||
retmsg.Write(L" while reserving '%s'", WX_STR(AllocDescription));
|
||||
|
||||
if (!m_message_diag.IsEmpty())
|
||||
retmsg.Write(L":\n%s", WX_STR(m_message_diag));
|
||||
if (!m_message_diag.IsEmpty())
|
||||
retmsg.Write(L":\n%s", WX_STR(m_message_diag));
|
||||
|
||||
return retmsg;
|
||||
return retmsg;
|
||||
}
|
||||
|
||||
wxString Exception::VirtualMemoryMapConflict::FormatDisplayMessage() const
|
||||
{
|
||||
FastFormatUnicode retmsg;
|
||||
retmsg.Write(L"%s",
|
||||
pxE(L"There is not enough virtual memory available, or necessary virtual memory mappings have already been reserved by other processes, services, or DLLs."));
|
||||
FastFormatUnicode retmsg;
|
||||
retmsg.Write(L"%s",
|
||||
pxE(L"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.IsEmpty())
|
||||
retmsg.Write(L"\n\n%s", WX_STR(m_message_diag));
|
||||
if (!m_message_diag.IsEmpty())
|
||||
retmsg.Write(L"\n\n%s", WX_STR(m_message_diag));
|
||||
|
||||
return retmsg;
|
||||
return retmsg;
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
wxString Exception::CancelEvent::FormatDiagnosticMessage() const
|
||||
{
|
||||
return L"Action canceled: " + m_message_diag;
|
||||
return L"Action canceled: " + m_message_diag;
|
||||
}
|
||||
|
||||
wxString Exception::CancelEvent::FormatDisplayMessage() const
|
||||
{
|
||||
return L"Action canceled: " + m_message_diag;
|
||||
return L"Action canceled: " + m_message_diag;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -263,40 +268,40 @@ wxString Exception::CancelEvent::FormatDisplayMessage() const
|
|||
// --------------------------------------------------------------------------------------
|
||||
wxString Exception::BadStream::FormatDiagnosticMessage() const
|
||||
{
|
||||
FastFormatUnicode retval;
|
||||
_formatDiagMsg(retval);
|
||||
return retval;
|
||||
FastFormatUnicode retval;
|
||||
_formatDiagMsg(retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
wxString Exception::BadStream::FormatDisplayMessage() const
|
||||
{
|
||||
FastFormatUnicode retval;
|
||||
_formatUserMsg(retval);
|
||||
return retval;
|
||||
FastFormatUnicode retval;
|
||||
_formatUserMsg(retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
void Exception::BadStream::_formatDiagMsg(FastFormatUnicode &dest) const
|
||||
void Exception::BadStream::_formatDiagMsg(FastFormatUnicode& dest) const
|
||||
{
|
||||
dest.Write(L"Path: ");
|
||||
if (!StreamName.IsEmpty())
|
||||
dest.Write(L"%s", WX_STR(StreamName));
|
||||
else
|
||||
dest.Write(L"[Unnamed or unknown]");
|
||||
dest.Write(L"Path: ");
|
||||
if (!StreamName.IsEmpty())
|
||||
dest.Write(L"%s", WX_STR(StreamName));
|
||||
else
|
||||
dest.Write(L"[Unnamed or unknown]");
|
||||
|
||||
if (!m_message_diag.IsEmpty())
|
||||
dest.Write(L"\n%s", WX_STR(m_message_diag));
|
||||
if (!m_message_diag.IsEmpty())
|
||||
dest.Write(L"\n%s", WX_STR(m_message_diag));
|
||||
}
|
||||
|
||||
void Exception::BadStream::_formatUserMsg(FastFormatUnicode &dest) const
|
||||
void Exception::BadStream::_formatUserMsg(FastFormatUnicode& dest) const
|
||||
{
|
||||
dest.Write(_("Path: "));
|
||||
if (!StreamName.IsEmpty())
|
||||
dest.Write(L"%s", WX_STR(StreamName));
|
||||
else
|
||||
dest.Write(_("[Unnamed or unknown]"));
|
||||
dest.Write(_("Path: "));
|
||||
if (!StreamName.IsEmpty())
|
||||
dest.Write(L"%s", WX_STR(StreamName));
|
||||
else
|
||||
dest.Write(_("[Unnamed or unknown]"));
|
||||
|
||||
if (!m_message_user.IsEmpty())
|
||||
dest.Write(L"\n%s", WX_STR(m_message_user));
|
||||
if (!m_message_user.IsEmpty())
|
||||
dest.Write(L"\n%s", WX_STR(m_message_user));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -304,19 +309,19 @@ void Exception::BadStream::_formatUserMsg(FastFormatUnicode &dest) const
|
|||
// --------------------------------------------------------------------------------------
|
||||
wxString Exception::CannotCreateStream::FormatDiagnosticMessage() const
|
||||
{
|
||||
FastFormatUnicode retval;
|
||||
retval.Write("File could not be created.");
|
||||
_formatDiagMsg(retval);
|
||||
return retval;
|
||||
FastFormatUnicode retval;
|
||||
retval.Write("File could not be created.");
|
||||
_formatDiagMsg(retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
wxString Exception::CannotCreateStream::FormatDisplayMessage() const
|
||||
{
|
||||
FastFormatUnicode retval;
|
||||
retval.Write(_("A file could not be created."));
|
||||
retval.Write("\n");
|
||||
_formatUserMsg(retval);
|
||||
return retval;
|
||||
FastFormatUnicode retval;
|
||||
retval.Write(_("A file could not be created."));
|
||||
retval.Write("\n");
|
||||
_formatUserMsg(retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -324,19 +329,19 @@ wxString Exception::CannotCreateStream::FormatDisplayMessage() const
|
|||
// --------------------------------------------------------------------------------------
|
||||
wxString Exception::FileNotFound::FormatDiagnosticMessage() const
|
||||
{
|
||||
FastFormatUnicode retval;
|
||||
retval.Write("File not found.\n");
|
||||
_formatDiagMsg(retval);
|
||||
return retval;
|
||||
FastFormatUnicode retval;
|
||||
retval.Write("File not found.\n");
|
||||
_formatDiagMsg(retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
wxString Exception::FileNotFound::FormatDisplayMessage() const
|
||||
{
|
||||
FastFormatUnicode retval;
|
||||
retval.Write(_("File not found."));
|
||||
retval.Write("\n");
|
||||
_formatUserMsg(retval);
|
||||
return retval;
|
||||
FastFormatUnicode retval;
|
||||
retval.Write(_("File not found."));
|
||||
retval.Write("\n");
|
||||
_formatUserMsg(retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -344,19 +349,19 @@ wxString Exception::FileNotFound::FormatDisplayMessage() const
|
|||
// --------------------------------------------------------------------------------------
|
||||
wxString Exception::AccessDenied::FormatDiagnosticMessage() const
|
||||
{
|
||||
FastFormatUnicode retval;
|
||||
retval.Write("Permission denied to file.\n");
|
||||
_formatDiagMsg(retval);
|
||||
return retval;
|
||||
FastFormatUnicode retval;
|
||||
retval.Write("Permission denied to file.\n");
|
||||
_formatDiagMsg(retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
wxString Exception::AccessDenied::FormatDisplayMessage() const
|
||||
{
|
||||
FastFormatUnicode retval;
|
||||
retval.Write(_("Permission denied while trying to open file, likely due to insufficient user account rights."));
|
||||
retval.Write("\n");
|
||||
_formatUserMsg(retval);
|
||||
return retval;
|
||||
FastFormatUnicode retval;
|
||||
retval.Write(_("Permission denied while trying to open file, likely due to insufficient user account rights."));
|
||||
retval.Write("\n");
|
||||
_formatUserMsg(retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -364,19 +369,19 @@ wxString Exception::AccessDenied::FormatDisplayMessage() const
|
|||
// --------------------------------------------------------------------------------------
|
||||
wxString Exception::EndOfStream::FormatDiagnosticMessage() const
|
||||
{
|
||||
FastFormatUnicode retval;
|
||||
retval.Write("Unexpected end of file or stream.\n");
|
||||
_formatDiagMsg(retval);
|
||||
return retval;
|
||||
FastFormatUnicode retval;
|
||||
retval.Write("Unexpected end of file or stream.\n");
|
||||
_formatDiagMsg(retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
wxString Exception::EndOfStream::FormatDisplayMessage() const
|
||||
{
|
||||
FastFormatUnicode retval;
|
||||
retval.Write(_("Unexpected end of file or stream encountered. File is probably truncated or corrupted."));
|
||||
retval.Write("\n");
|
||||
_formatUserMsg(retval);
|
||||
return retval;
|
||||
FastFormatUnicode retval;
|
||||
retval.Write(_("Unexpected end of file or stream encountered. File is probably truncated or corrupted."));
|
||||
retval.Write("\n");
|
||||
_formatUserMsg(retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -385,34 +390,35 @@ wxString 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(const wxString &streamname, int errcode)
|
||||
BaseException* Exception::FromErrno(const wxString& streamname, int errcode)
|
||||
{
|
||||
pxAssumeDev(errcode != 0, "Invalid NULL error code? (errno)");
|
||||
pxAssumeDev(errcode != 0, "Invalid NULL error code? (errno)");
|
||||
|
||||
switch (errcode) {
|
||||
case EINVAL:
|
||||
pxFailDev(L"Invalid argument");
|
||||
return &(new Exception::BadStream(streamname))->SetDiagMsg(L"Invalid argument? (likely caused by an unforgivable programmer error!)");
|
||||
switch (errcode)
|
||||
{
|
||||
case EINVAL:
|
||||
pxFailDev(L"Invalid argument");
|
||||
return &(new Exception::BadStream(streamname))->SetDiagMsg(L"Invalid argument? (likely caused by an unforgivable programmer error!)");
|
||||
|
||||
case EACCES: // Access denied!
|
||||
return new Exception::AccessDenied(streamname);
|
||||
case EACCES: // Access denied!
|
||||
return new Exception::AccessDenied(streamname);
|
||||
|
||||
case EMFILE: // Too many open files!
|
||||
return &(new Exception::CannotCreateStream(streamname))->SetDiagMsg(L"Too many open files"); // File handle allocation failure
|
||||
case EMFILE: // Too many open files!
|
||||
return &(new Exception::CannotCreateStream(streamname))->SetDiagMsg(L"Too many open files"); // File handle allocation failure
|
||||
|
||||
case EEXIST:
|
||||
return &(new Exception::CannotCreateStream(streamname))->SetDiagMsg(L"File already exists");
|
||||
case EEXIST:
|
||||
return &(new Exception::CannotCreateStream(streamname))->SetDiagMsg(L"File already exists");
|
||||
|
||||
case ENOENT: // File not found!
|
||||
return new Exception::FileNotFound(streamname);
|
||||
case ENOENT: // File not found!
|
||||
return new Exception::FileNotFound(streamname);
|
||||
|
||||
case EPIPE:
|
||||
return &(new Exception::BadStream(streamname))->SetDiagMsg(L"Broken pipe");
|
||||
case EPIPE:
|
||||
return &(new Exception::BadStream(streamname))->SetDiagMsg(L"Broken pipe");
|
||||
|
||||
case EBADF:
|
||||
return &(new Exception::BadStream(streamname))->SetDiagMsg(L"Bad file number");
|
||||
case EBADF:
|
||||
return &(new Exception::BadStream(streamname))->SetDiagMsg(L"Bad file number");
|
||||
|
||||
default:
|
||||
return &(new Exception::BadStream(streamname))->SetDiagMsg(pxsFmt(L"General file/stream error [errno: %d]", errcode));
|
||||
}
|
||||
default:
|
||||
return &(new Exception::BadStream(streamname))->SetDiagMsg(pxsFmt(L"General file/stream error [errno: %d]", errcode));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,115 +32,121 @@ void pxTrap();
|
|||
// 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(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;
|
||||
class BaseException;
|
||||
|
||||
int MakeNewType();
|
||||
BaseException *FromErrno(const wxString &streamname, int errcode);
|
||||
int MakeNewType();
|
||||
BaseException* FromErrno(const wxString& streamname, int errcode);
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// BaseException
|
||||
// --------------------------------------------------------------------------------------
|
||||
// std::exception sucks, and isn't entirely cross-platform reliable in its implementation,
|
||||
// so I made a replacement. The internal messages are non-const, which means that a
|
||||
// catch clause can optionally modify them and then re-throw to a top-level handler.
|
||||
//
|
||||
// Note, this class is "abstract" which means you shouldn't use it directly like, ever.
|
||||
// Use Exception::RuntimeError instead for generic exceptions.
|
||||
//
|
||||
// Because exceptions are the (only!) really useful example of multiple inheritance,
|
||||
// this class has only a trivial constructor, and must be manually initialized using
|
||||
// InitBaseEx() or by individual member assignments. This is because C++ multiple inheritence
|
||||
// is, by design, a lot of fail, especially when class initializers are mixed in.
|
||||
//
|
||||
// [TODO] : Add an InnerException component, and Clone() facility.
|
||||
//
|
||||
class BaseException
|
||||
{
|
||||
protected:
|
||||
wxString m_message_diag; // (untranslated) a "detailed" message of what disastrous thing has occurred!
|
||||
wxString m_message_user; // (translated) a "detailed" message of what disastrous thing has occurred!
|
||||
// --------------------------------------------------------------------------------------
|
||||
// BaseException
|
||||
// --------------------------------------------------------------------------------------
|
||||
// std::exception sucks, and isn't entirely cross-platform reliable in its implementation,
|
||||
// so I made a replacement. The internal messages are non-const, which means that a
|
||||
// catch clause can optionally modify them and then re-throw to a top-level handler.
|
||||
//
|
||||
// Note, this class is "abstract" which means you shouldn't use it directly like, ever.
|
||||
// Use Exception::RuntimeError instead for generic exceptions.
|
||||
//
|
||||
// Because exceptions are the (only!) really useful example of multiple inheritance,
|
||||
// this class has only a trivial constructor, and must be manually initialized using
|
||||
// InitBaseEx() or by individual member assignments. This is because C++ multiple inheritence
|
||||
// is, by design, a lot of fail, especially when class initializers are mixed in.
|
||||
//
|
||||
// [TODO] : Add an InnerException component, and Clone() facility.
|
||||
//
|
||||
class BaseException
|
||||
{
|
||||
protected:
|
||||
wxString m_message_diag; // (untranslated) a "detailed" message of what disastrous thing has occurred!
|
||||
wxString m_message_user; // (translated) a "detailed" message of what disastrous thing has occurred!
|
||||
|
||||
public:
|
||||
virtual ~BaseException() = default;
|
||||
public:
|
||||
virtual ~BaseException() = default;
|
||||
|
||||
const wxString &DiagMsg() const { return m_message_diag; }
|
||||
const wxString &UserMsg() const { return m_message_user; }
|
||||
const wxString& DiagMsg() const { return m_message_diag; }
|
||||
const wxString& UserMsg() const { return m_message_user; }
|
||||
|
||||
wxString &DiagMsg() { return m_message_diag; }
|
||||
wxString &UserMsg() { return m_message_user; }
|
||||
wxString& DiagMsg() { return m_message_diag; }
|
||||
wxString& UserMsg() { return m_message_user; }
|
||||
|
||||
BaseException &SetBothMsgs(const wxChar *msg_diag);
|
||||
BaseException &SetDiagMsg(const wxString &msg_diag);
|
||||
BaseException &SetUserMsg(const wxString &msg_user);
|
||||
BaseException& SetBothMsgs(const wxChar* msg_diag);
|
||||
BaseException& SetDiagMsg(const wxString& msg_diag);
|
||||
BaseException& SetUserMsg(const wxString& msg_user);
|
||||
|
||||
// Returns a message suitable for diagnostic / logging purposes.
|
||||
// This message is always in English, and includes a full stack trace.
|
||||
virtual wxString FormatDiagnosticMessage() const;
|
||||
// Returns a message suitable for diagnostic / logging purposes.
|
||||
// This message is always in English, and includes a full stack trace.
|
||||
virtual wxString FormatDiagnosticMessage() const;
|
||||
|
||||
// Returns a message suitable for end-user display.
|
||||
// This message is usually meant for display in a user popup or such.
|
||||
virtual wxString FormatDisplayMessage() const;
|
||||
// Returns a message suitable for end-user display.
|
||||
// This message is usually meant for display in a user popup or such.
|
||||
virtual wxString FormatDisplayMessage() const;
|
||||
|
||||
virtual void Rethrow() const = 0;
|
||||
virtual BaseException *Clone() const = 0;
|
||||
};
|
||||
virtual void Rethrow() const = 0;
|
||||
virtual BaseException* Clone() const = 0;
|
||||
};
|
||||
|
||||
typedef std::unique_ptr<BaseException> ScopedExcept;
|
||||
typedef std::unique_ptr<BaseException> ScopedExcept;
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Ps2Generic Exception
|
||||
// --------------------------------------------------------------------------------------
|
||||
// This class is used as a base exception for things tossed by PS2 cpus (EE, IOP, etc).
|
||||
//
|
||||
// Implementation note: does not derive from BaseException, so that we can use different
|
||||
// catch block hierarchies to handle them (if needed).
|
||||
//
|
||||
// Translation Note: Currently these exceptions are never translated. English/diagnostic
|
||||
// format only. :)
|
||||
//
|
||||
class Ps2Generic
|
||||
{
|
||||
protected:
|
||||
wxString m_message; // a "detailed" message of what disastrous thing has occurred!
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Ps2Generic Exception
|
||||
// --------------------------------------------------------------------------------------
|
||||
// This class is used as a base exception for things tossed by PS2 cpus (EE, IOP, etc).
|
||||
//
|
||||
// Implementation note: does not derive from BaseException, so that we can use different
|
||||
// catch block hierarchies to handle them (if needed).
|
||||
//
|
||||
// Translation Note: Currently these exceptions are never translated. English/diagnostic
|
||||
// format only. :)
|
||||
//
|
||||
class Ps2Generic
|
||||
{
|
||||
protected:
|
||||
wxString m_message; // a "detailed" message of what disastrous thing has occurred!
|
||||
|
||||
public:
|
||||
virtual ~Ps2Generic() = default;
|
||||
public:
|
||||
virtual ~Ps2Generic() = default;
|
||||
|
||||
virtual u32 GetPc() const = 0;
|
||||
virtual bool IsDelaySlot() const = 0;
|
||||
virtual wxString &Message() { return m_message; }
|
||||
virtual u32 GetPc() const = 0;
|
||||
virtual bool IsDelaySlot() const = 0;
|
||||
virtual wxString& Message() { return m_message; }
|
||||
|
||||
virtual void Rethrow() const = 0;
|
||||
virtual Ps2Generic *Clone() const = 0;
|
||||
};
|
||||
virtual void Rethrow() const = 0;
|
||||
virtual Ps2Generic* Clone() const = 0;
|
||||
};
|
||||
|
||||
// Some helper macros for defining the standard constructors of internationalized constructors
|
||||
// Parameters:
|
||||
|
@ -157,240 +163,254 @@ public:
|
|||
// (update: web searches indicate it's MSVC specific -- happens in 2008, not sure about 2010).
|
||||
//
|
||||
#define DEFINE_EXCEPTION_COPYTORS(classname, parent) \
|
||||
private: \
|
||||
typedef parent _parent; \
|
||||
\
|
||||
public: \
|
||||
virtual ~classname() = default; \
|
||||
virtual void Rethrow() const { throw * this; } \
|
||||
virtual classname *Clone() const { return new classname(*this); }
|
||||
private: \
|
||||
typedef parent _parent; \
|
||||
\
|
||||
public: \
|
||||
virtual ~classname() = default; \
|
||||
\
|
||||
virtual void Rethrow() const \
|
||||
{ \
|
||||
throw *this; \
|
||||
} \
|
||||
\
|
||||
virtual classname* Clone() const \
|
||||
{ \
|
||||
return new classname(*this); \
|
||||
}
|
||||
|
||||
#define DEFINE_EXCEPTION_MESSAGES(classname) \
|
||||
public: \
|
||||
classname &SetBothMsgs(const wxChar *msg_diag) \
|
||||
{ \
|
||||
BaseException::SetBothMsgs(msg_diag); \
|
||||
return *this; \
|
||||
} \
|
||||
classname &SetDiagMsg(const wxString &msg_diag) \
|
||||
{ \
|
||||
m_message_diag = msg_diag; \
|
||||
return *this; \
|
||||
} \
|
||||
classname &SetUserMsg(const wxString &msg_user) \
|
||||
{ \
|
||||
m_message_user = msg_user; \
|
||||
return *this; \
|
||||
}
|
||||
#define DEFINE_EXCEPTION_MESSAGES(classname) \
|
||||
public: \
|
||||
classname& SetBothMsgs(const wxChar* msg_diag) \
|
||||
{ \
|
||||
BaseException::SetBothMsgs(msg_diag); \
|
||||
return *this; \
|
||||
} \
|
||||
\
|
||||
classname& SetDiagMsg(const wxString& msg_diag) \
|
||||
{ \
|
||||
m_message_diag = msg_diag; \
|
||||
return *this; \
|
||||
} \
|
||||
\
|
||||
classname& SetUserMsg(const wxString& msg_user) \
|
||||
{ \
|
||||
m_message_user = msg_user; \
|
||||
return *this; \
|
||||
}
|
||||
|
||||
#define DEFINE_RUNTIME_EXCEPTION(classname, parent, message) \
|
||||
DEFINE_EXCEPTION_COPYTORS(classname, parent) \
|
||||
classname() { SetDiagMsg(message); } \
|
||||
DEFINE_EXCEPTION_MESSAGES(classname)
|
||||
DEFINE_EXCEPTION_COPYTORS(classname, parent) \
|
||||
classname() \
|
||||
{ \
|
||||
SetDiagMsg(message); \
|
||||
} \
|
||||
DEFINE_EXCEPTION_MESSAGES(classname)
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// RuntimeError - Generalized Exceptions with Recoverable Traits!
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// RuntimeError - Generalized Exceptions with Recoverable Traits!
|
||||
// ---------------------------------------------------------------------------------------
|
||||
|
||||
class RuntimeError : public BaseException
|
||||
{
|
||||
DEFINE_EXCEPTION_COPYTORS(RuntimeError, BaseException)
|
||||
DEFINE_EXCEPTION_MESSAGES(RuntimeError)
|
||||
class RuntimeError : public BaseException
|
||||
{
|
||||
DEFINE_EXCEPTION_COPYTORS(RuntimeError, BaseException)
|
||||
DEFINE_EXCEPTION_MESSAGES(RuntimeError)
|
||||
|
||||
public:
|
||||
bool IsSilent;
|
||||
public:
|
||||
bool IsSilent;
|
||||
|
||||
RuntimeError() { IsSilent = false; }
|
||||
RuntimeError(const std::runtime_error &ex, const wxString &prefix = wxEmptyString);
|
||||
RuntimeError(const std::exception &ex, const wxString &prefix = wxEmptyString);
|
||||
};
|
||||
RuntimeError() { IsSilent = false; }
|
||||
RuntimeError(const std::runtime_error& ex, const wxString& prefix = wxEmptyString);
|
||||
RuntimeError(const std::exception& ex, const wxString& prefix = wxEmptyString);
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// 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, pxLt("No reason given."))
|
||||
// --------------------------------------------------------------------------------------
|
||||
// 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, pxLt("No reason given."))
|
||||
|
||||
public:
|
||||
explicit CancelEvent(const wxString &logmsg)
|
||||
{
|
||||
m_message_diag = logmsg;
|
||||
// overridden message formatters only use the diagnostic version...
|
||||
}
|
||||
public:
|
||||
explicit CancelEvent(const wxString& logmsg)
|
||||
{
|
||||
m_message_diag = logmsg;
|
||||
// overridden message formatters only use the diagnostic version...
|
||||
}
|
||||
|
||||
virtual wxString FormatDisplayMessage() const;
|
||||
virtual wxString FormatDiagnosticMessage() const;
|
||||
};
|
||||
virtual wxString FormatDisplayMessage() const;
|
||||
virtual wxString FormatDiagnosticMessage() const;
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// 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, wxEmptyString)
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// 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, wxEmptyString)
|
||||
|
||||
public:
|
||||
wxString AllocDescription;
|
||||
public:
|
||||
wxString AllocDescription;
|
||||
|
||||
public:
|
||||
OutOfMemory(const wxString &allocdesc);
|
||||
public:
|
||||
OutOfMemory(const wxString& allocdesc);
|
||||
|
||||
virtual wxString FormatDisplayMessage() const;
|
||||
virtual wxString FormatDiagnosticMessage() const;
|
||||
};
|
||||
virtual wxString FormatDisplayMessage() const;
|
||||
virtual wxString FormatDiagnosticMessage() const;
|
||||
};
|
||||
|
||||
class ParseError : public RuntimeError
|
||||
{
|
||||
DEFINE_RUNTIME_EXCEPTION(ParseError, RuntimeError, pxL("Parse error"));
|
||||
};
|
||||
class ParseError : public RuntimeError
|
||||
{
|
||||
DEFINE_RUNTIME_EXCEPTION(ParseError, RuntimeError, pxL("Parse error"));
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// Hardware/OS Exceptions:
|
||||
// HardwareDeficiency / VirtualMemoryMapConflict
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// 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, wxEmptyString)
|
||||
// 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, wxEmptyString)
|
||||
|
||||
VirtualMemoryMapConflict(const wxString &allocdesc);
|
||||
VirtualMemoryMapConflict(const wxString& allocdesc);
|
||||
|
||||
virtual wxString FormatDisplayMessage() const;
|
||||
virtual wxString FormatDiagnosticMessage() const;
|
||||
};
|
||||
virtual wxString FormatDisplayMessage() const;
|
||||
virtual wxString FormatDiagnosticMessage() const;
|
||||
};
|
||||
|
||||
class HardwareDeficiency : public RuntimeError
|
||||
{
|
||||
public:
|
||||
DEFINE_RUNTIME_EXCEPTION(HardwareDeficiency, RuntimeError, pxL("Your machine's hardware is incapable of running PCSX2. Sorry dood."));
|
||||
};
|
||||
class HardwareDeficiency : public RuntimeError
|
||||
{
|
||||
public:
|
||||
DEFINE_RUNTIME_EXCEPTION(HardwareDeficiency, RuntimeError, pxL("Your machine's hardware is incapable of running PCSX2. Sorry dood."));
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// Streaming (file) Exceptions:
|
||||
// Stream / BadStream / CannotCreateStream / FileNotFound / AccessDenied / EndOfStream
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// Streaming (file) Exceptions:
|
||||
// Stream / BadStream / CannotCreateStream / FileNotFound / AccessDenied / EndOfStream
|
||||
// ---------------------------------------------------------------------------------------
|
||||
|
||||
#define DEFINE_STREAM_EXCEPTION_ACCESSORS(classname) \
|
||||
virtual classname &SetStreamName(const wxString &name) \
|
||||
{ \
|
||||
StreamName = name; \
|
||||
return *this; \
|
||||
} \
|
||||
virtual classname &SetStreamName(const char *name) \
|
||||
{ \
|
||||
StreamName = fromUTF8(name); \
|
||||
return *this; \
|
||||
}
|
||||
#define DEFINE_STREAM_EXCEPTION_ACCESSORS(classname) \
|
||||
virtual classname& SetStreamName(const wxString& name) \
|
||||
{ \
|
||||
StreamName = name; \
|
||||
return *this; \
|
||||
} \
|
||||
\
|
||||
virtual classname& SetStreamName(const char* name) \
|
||||
{ \
|
||||
StreamName = fromUTF8(name); \
|
||||
return *this; \
|
||||
}
|
||||
|
||||
#define DEFINE_STREAM_EXCEPTION(classname, parent) \
|
||||
DEFINE_RUNTIME_EXCEPTION(classname, parent, wxEmptyString) \
|
||||
classname(const wxString &filename) \
|
||||
{ \
|
||||
StreamName = filename; \
|
||||
} \
|
||||
DEFINE_STREAM_EXCEPTION_ACCESSORS(classname)
|
||||
#define DEFINE_STREAM_EXCEPTION(classname, parent) \
|
||||
DEFINE_RUNTIME_EXCEPTION(classname, parent, wxEmptyString) \
|
||||
classname(const wxString& filename) \
|
||||
{ \
|
||||
StreamName = filename; \
|
||||
} \
|
||||
DEFINE_STREAM_EXCEPTION_ACCESSORS(classname)
|
||||
|
||||
// A generic base error class for bad streams -- corrupted data, sudden closures, loss of
|
||||
// connection, or anything else that would indicate a failure to open a stream or read the
|
||||
// data after the stream was successfully opened.
|
||||
//
|
||||
class BadStream : public RuntimeError
|
||||
{
|
||||
DEFINE_STREAM_EXCEPTION(BadStream, RuntimeError)
|
||||
// A generic base error class for bad streams -- corrupted data, sudden closures, loss of
|
||||
// connection, or anything else that would indicate a failure to open a stream or read the
|
||||
// data after the stream was successfully opened.
|
||||
//
|
||||
class BadStream : public RuntimeError
|
||||
{
|
||||
DEFINE_STREAM_EXCEPTION(BadStream, RuntimeError)
|
||||
|
||||
public:
|
||||
wxString StreamName; // name of the stream (if applicable)
|
||||
public:
|
||||
wxString StreamName; // name of the stream (if applicable)
|
||||
|
||||
virtual wxString FormatDiagnosticMessage() const;
|
||||
virtual wxString FormatDisplayMessage() const;
|
||||
virtual wxString FormatDiagnosticMessage() const;
|
||||
virtual wxString FormatDisplayMessage() const;
|
||||
|
||||
protected:
|
||||
void _formatDiagMsg(FastFormatUnicode &dest) const;
|
||||
void _formatUserMsg(FastFormatUnicode &dest) const;
|
||||
};
|
||||
protected:
|
||||
void _formatDiagMsg(FastFormatUnicode& dest) const;
|
||||
void _formatUserMsg(FastFormatUnicode& dest) const;
|
||||
};
|
||||
|
||||
// A generic exception for odd-ball stream creation errors.
|
||||
//
|
||||
class CannotCreateStream : public BadStream
|
||||
{
|
||||
DEFINE_STREAM_EXCEPTION(CannotCreateStream, BadStream)
|
||||
// A generic exception for odd-ball stream creation errors.
|
||||
//
|
||||
class CannotCreateStream : public BadStream
|
||||
{
|
||||
DEFINE_STREAM_EXCEPTION(CannotCreateStream, BadStream)
|
||||
|
||||
virtual wxString FormatDiagnosticMessage() const;
|
||||
virtual wxString FormatDisplayMessage() const;
|
||||
};
|
||||
virtual wxString FormatDiagnosticMessage() const;
|
||||
virtual wxString FormatDisplayMessage() const;
|
||||
};
|
||||
|
||||
// Exception thrown when an attempt to open a non-existent file is made.
|
||||
// (this exception can also mean file permissions are invalid)
|
||||
//
|
||||
class FileNotFound : public CannotCreateStream
|
||||
{
|
||||
public:
|
||||
DEFINE_STREAM_EXCEPTION(FileNotFound, CannotCreateStream)
|
||||
// Exception thrown when an attempt to open a non-existent file is made.
|
||||
// (this exception can also mean file permissions are invalid)
|
||||
//
|
||||
class FileNotFound : public CannotCreateStream
|
||||
{
|
||||
public:
|
||||
DEFINE_STREAM_EXCEPTION(FileNotFound, CannotCreateStream)
|
||||
|
||||
virtual wxString FormatDiagnosticMessage() const;
|
||||
virtual wxString FormatDisplayMessage() const;
|
||||
};
|
||||
virtual wxString FormatDiagnosticMessage() const;
|
||||
virtual wxString FormatDisplayMessage() const;
|
||||
};
|
||||
|
||||
class AccessDenied : public CannotCreateStream
|
||||
{
|
||||
public:
|
||||
DEFINE_STREAM_EXCEPTION(AccessDenied, CannotCreateStream)
|
||||
class AccessDenied : public CannotCreateStream
|
||||
{
|
||||
public:
|
||||
DEFINE_STREAM_EXCEPTION(AccessDenied, CannotCreateStream)
|
||||
|
||||
virtual wxString FormatDiagnosticMessage() const;
|
||||
virtual wxString FormatDisplayMessage() const;
|
||||
};
|
||||
virtual wxString FormatDiagnosticMessage() const;
|
||||
virtual wxString FormatDisplayMessage() const;
|
||||
};
|
||||
|
||||
// EndOfStream can be used either as an error, or used just as a shortcut for manual
|
||||
// feof checks.
|
||||
//
|
||||
class EndOfStream : public BadStream
|
||||
{
|
||||
public:
|
||||
DEFINE_STREAM_EXCEPTION(EndOfStream, BadStream)
|
||||
// EndOfStream can be used either as an error, or used just as a shortcut for manual
|
||||
// feof checks.
|
||||
//
|
||||
class EndOfStream : public BadStream
|
||||
{
|
||||
public:
|
||||
DEFINE_STREAM_EXCEPTION(EndOfStream, BadStream)
|
||||
|
||||
virtual wxString FormatDiagnosticMessage() const;
|
||||
virtual wxString FormatDisplayMessage() const;
|
||||
};
|
||||
virtual wxString FormatDiagnosticMessage() const;
|
||||
virtual wxString FormatDisplayMessage() const;
|
||||
};
|
||||
|
||||
#ifdef __WXMSW__
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Exception::WinApiError
|
||||
// --------------------------------------------------------------------------------------
|
||||
class WinApiError : public RuntimeError
|
||||
{
|
||||
DEFINE_EXCEPTION_COPYTORS(WinApiError, RuntimeError)
|
||||
DEFINE_EXCEPTION_MESSAGES(WinApiError)
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Exception::WinApiError
|
||||
// --------------------------------------------------------------------------------------
|
||||
class WinApiError : public RuntimeError
|
||||
{
|
||||
DEFINE_EXCEPTION_COPYTORS(WinApiError, RuntimeError)
|
||||
DEFINE_EXCEPTION_MESSAGES(WinApiError)
|
||||
|
||||
public:
|
||||
int ErrorId;
|
||||
public:
|
||||
int ErrorId;
|
||||
|
||||
public:
|
||||
WinApiError();
|
||||
public:
|
||||
WinApiError();
|
||||
|
||||
wxString GetMsgFromWindows() const;
|
||||
virtual wxString FormatDisplayMessage() const;
|
||||
virtual wxString FormatDiagnosticMessage() const;
|
||||
};
|
||||
wxString GetMsgFromWindows() const;
|
||||
virtual wxString FormatDisplayMessage() const;
|
||||
virtual wxString FormatDiagnosticMessage() const;
|
||||
};
|
||||
#endif
|
||||
}
|
||||
} // namespace Exception
|
||||
|
||||
using Exception::BaseException;
|
||||
using Exception::ScopedExcept;
|
||||
|
|
|
@ -33,88 +33,88 @@ template class SafeAlignedArray<u8, 16>;
|
|||
// system deadlock.
|
||||
static const int MaxFormattedStringLength = 0x80000;
|
||||
|
||||
static
|
||||
#ifndef __linux__
|
||||
__ri
|
||||
static __ri void format_that_ascii_mess(CharBufferType& buffer, uint writepos, const char* fmt, va_list argptr)
|
||||
#else
|
||||
static void format_that_ascii_mess(CharBufferType& buffer, uint writepos, const char* fmt, va_list argptr)
|
||||
#endif
|
||||
void
|
||||
format_that_ascii_mess(CharBufferType &buffer, uint writepos, const char *fmt, va_list argptr)
|
||||
{
|
||||
va_list args;
|
||||
while (true) {
|
||||
int size = buffer.GetLength();
|
||||
va_list args;
|
||||
while (true)
|
||||
{
|
||||
int size = buffer.GetLength();
|
||||
|
||||
va_copy(args, argptr);
|
||||
int len = vsnprintf(buffer.GetPtr(writepos), size - writepos, fmt, args);
|
||||
va_end(args);
|
||||
va_copy(args, argptr);
|
||||
int len = vsnprintf(buffer.GetPtr(writepos), size - writepos, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
// some implementations of vsnprintf() don't NUL terminate
|
||||
// the string if there is not enough space for it so
|
||||
// always do it manually
|
||||
buffer[size - 1] = '\0';
|
||||
// some implementations of vsnprintf() don't NUL terminate
|
||||
// the string if there is not enough space for it so
|
||||
// always do it manually
|
||||
buffer[size - 1] = '\0';
|
||||
|
||||
if (size >= MaxFormattedStringLength)
|
||||
break;
|
||||
if (size >= MaxFormattedStringLength)
|
||||
break;
|
||||
|
||||
// vsnprintf() may return either -1 (traditional Unix behavior) or the
|
||||
// total number of characters which would have been written if the
|
||||
// buffer were large enough (newer standards such as Unix98)
|
||||
// vsnprintf() may return either -1 (traditional Unix behavior) or the
|
||||
// total number of characters which would have been written if the
|
||||
// buffer were large enough (newer standards such as Unix98)
|
||||
|
||||
if (len < 0)
|
||||
len = size + (size / 4);
|
||||
if (len < 0)
|
||||
len = size + (size / 4);
|
||||
|
||||
len += writepos;
|
||||
if (len < size)
|
||||
break;
|
||||
buffer.Resize(len + 128);
|
||||
};
|
||||
len += writepos;
|
||||
if (len < size)
|
||||
break;
|
||||
buffer.Resize(len + 128);
|
||||
};
|
||||
|
||||
// performing an assertion or log of a truncated string is unsafe, so let's not; even
|
||||
// though it'd be kinda nice if we did.
|
||||
// performing an assertion or log of a truncated string is unsafe, so let's not; even
|
||||
// though it'd be kinda nice if we did.
|
||||
}
|
||||
|
||||
// returns the length of the formatted string, in characters (wxChars).
|
||||
static
|
||||
#ifndef __linux__
|
||||
__ri
|
||||
static __ri uint format_that_unicode_mess(CharBufferType& buffer, uint writepos, const wxChar* fmt, va_list argptr)
|
||||
#else
|
||||
static uint format_that_unicode_mess(CharBufferType& buffer, uint writepos, const wxChar* fmt, va_list argptr)
|
||||
#endif
|
||||
uint
|
||||
format_that_unicode_mess(CharBufferType &buffer, uint writepos, const wxChar *fmt, va_list argptr)
|
||||
{
|
||||
va_list args;
|
||||
while (true) {
|
||||
int size = buffer.GetLength() / sizeof(wxChar);
|
||||
va_list args;
|
||||
while (true)
|
||||
{
|
||||
int size = buffer.GetLength() / sizeof(wxChar);
|
||||
|
||||
va_copy(args, argptr);
|
||||
int len = wxVsnprintf((wxChar *)buffer.GetPtr(writepos * sizeof(wxChar)), size - writepos, fmt, args);
|
||||
va_end(args);
|
||||
va_copy(args, argptr);
|
||||
int len = wxVsnprintf((wxChar*)buffer.GetPtr(writepos * sizeof(wxChar)), size - writepos, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
// some implementations of vsnprintf() don't NUL terminate
|
||||
// the string if there is not enough space for it so
|
||||
// always do it manually
|
||||
((wxChar *)buffer.GetPtr())[size - 1] = L'\0';
|
||||
// some implementations of vsnprintf() don't NUL terminate
|
||||
// the string if there is not enough space for it so
|
||||
// always do it manually
|
||||
((wxChar*)buffer.GetPtr())[size - 1] = L'\0';
|
||||
|
||||
if (size >= MaxFormattedStringLength)
|
||||
return size - 1;
|
||||
if (size >= MaxFormattedStringLength)
|
||||
return size - 1;
|
||||
|
||||
// vsnprintf() may return either -1 (traditional Unix behavior) or the
|
||||
// total number of characters which would have been written if the
|
||||
// buffer were large enough (newer standards such as Unix98)
|
||||
// vsnprintf() may return either -1 (traditional Unix behavior) or the
|
||||
// total number of characters which would have been written if the
|
||||
// buffer were large enough (newer standards such as Unix98)
|
||||
|
||||
if (len < 0)
|
||||
len = size + (size / 4);
|
||||
if (len < 0)
|
||||
len = size + (size / 4);
|
||||
|
||||
len += writepos;
|
||||
if (len < size)
|
||||
return len;
|
||||
buffer.Resize((len + 128) * sizeof(wxChar));
|
||||
};
|
||||
len += writepos;
|
||||
if (len < size)
|
||||
return len;
|
||||
buffer.Resize((len + 128) * sizeof(wxChar));
|
||||
};
|
||||
|
||||
// performing an assertion or log of a truncated string is unsafe, so let's not; even
|
||||
// though it'd be kinda nice if we did.
|
||||
// performing an assertion or log of a truncated string is unsafe, so let's not; even
|
||||
// though it'd be kinda nice if we did.
|
||||
|
||||
pxAssume(false);
|
||||
return 0; // unreachable.
|
||||
pxAssume(false);
|
||||
return 0; // unreachable.
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -127,124 +127,124 @@ static
|
|||
// this class nicely in its current state. --air
|
||||
|
||||
FastFormatUnicode::FastFormatUnicode()
|
||||
: m_dest(2048)
|
||||
: m_dest(2048)
|
||||
{
|
||||
Clear();
|
||||
Clear();
|
||||
}
|
||||
|
||||
void FastFormatUnicode::Clear()
|
||||
{
|
||||
m_Length = 0;
|
||||
((wxChar *)m_dest.GetPtr())[0] = 0;
|
||||
m_Length = 0;
|
||||
((wxChar*)m_dest.GetPtr())[0] = 0;
|
||||
}
|
||||
|
||||
FastFormatUnicode &FastFormatUnicode::WriteV(const char *fmt, va_list argptr)
|
||||
FastFormatUnicode& FastFormatUnicode::WriteV(const char* fmt, va_list argptr)
|
||||
{
|
||||
wxString converted(fromUTF8(FastFormatAscii().WriteV(fmt, argptr)));
|
||||
wxString converted(fromUTF8(FastFormatAscii().WriteV(fmt, argptr)));
|
||||
|
||||
const uint inspos = m_Length;
|
||||
const uint convLen = converted.Length();
|
||||
m_dest.MakeRoomFor((inspos + convLen + 64) * sizeof(wxChar));
|
||||
memcpy(&((wxChar *)m_dest.GetPtr())[inspos], converted.wc_str(), (convLen + 1) * sizeof(wxChar));
|
||||
m_Length += convLen;
|
||||
const uint inspos = m_Length;
|
||||
const uint convLen = converted.Length();
|
||||
m_dest.MakeRoomFor((inspos + convLen + 64) * sizeof(wxChar));
|
||||
memcpy(&((wxChar*)m_dest.GetPtr())[inspos], converted.wc_str(), (convLen + 1) * sizeof(wxChar));
|
||||
m_Length += convLen;
|
||||
|
||||
return *this;
|
||||
return *this;
|
||||
}
|
||||
|
||||
FastFormatUnicode &FastFormatUnicode::WriteV(const wxChar *fmt, va_list argptr)
|
||||
FastFormatUnicode& FastFormatUnicode::WriteV(const wxChar* fmt, va_list argptr)
|
||||
{
|
||||
m_Length = format_that_unicode_mess(m_dest, m_Length, fmt, argptr);
|
||||
return *this;
|
||||
m_Length = format_that_unicode_mess(m_dest, m_Length, fmt, argptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
FastFormatUnicode &FastFormatUnicode::Write(const char *fmt, ...)
|
||||
FastFormatUnicode& FastFormatUnicode::Write(const char* fmt, ...)
|
||||
{
|
||||
va_list list;
|
||||
va_start(list, fmt);
|
||||
WriteV(fmt, list);
|
||||
va_end(list);
|
||||
return *this;
|
||||
va_list list;
|
||||
va_start(list, fmt);
|
||||
WriteV(fmt, list);
|
||||
va_end(list);
|
||||
return *this;
|
||||
}
|
||||
|
||||
FastFormatUnicode &FastFormatUnicode::Write(const wxChar *fmt, ...)
|
||||
FastFormatUnicode& FastFormatUnicode::Write(const wxChar* fmt, ...)
|
||||
{
|
||||
va_list list;
|
||||
va_start(list, fmt);
|
||||
WriteV(fmt, list);
|
||||
va_end(list);
|
||||
return *this;
|
||||
va_list list;
|
||||
va_start(list, fmt);
|
||||
WriteV(fmt, list);
|
||||
va_end(list);
|
||||
return *this;
|
||||
}
|
||||
|
||||
FastFormatUnicode &FastFormatUnicode::Write(const wxString fmt, ...)
|
||||
FastFormatUnicode& FastFormatUnicode::Write(const wxString fmt, ...)
|
||||
{
|
||||
va_list list;
|
||||
va_start(list, fmt);
|
||||
WriteV(fmt.wx_str(), list);
|
||||
va_end(list);
|
||||
return *this;
|
||||
va_list list;
|
||||
va_start(list, fmt);
|
||||
WriteV(fmt.wx_str(), list);
|
||||
va_end(list);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool FastFormatUnicode::IsEmpty() const
|
||||
{
|
||||
return ((wxChar &)m_dest[0]) == 0;
|
||||
return ((wxChar&)m_dest[0]) == 0;
|
||||
}
|
||||
|
||||
FastFormatUnicode &FastFormatUnicode::ToUpper()
|
||||
FastFormatUnicode& FastFormatUnicode::ToUpper()
|
||||
{
|
||||
wxChar *ch = (wxChar *)m_dest.GetPtr();
|
||||
for (uint i = 0; i < m_Length; ++i, ++ch)
|
||||
*ch = (wxChar)wxToupper(*ch);
|
||||
wxChar* ch = (wxChar*)m_dest.GetPtr();
|
||||
for (uint i = 0; i < m_Length; ++i, ++ch)
|
||||
*ch = (wxChar)wxToupper(*ch);
|
||||
|
||||
return *this;
|
||||
return *this;
|
||||
}
|
||||
|
||||
FastFormatUnicode &FastFormatUnicode::ToLower()
|
||||
FastFormatUnicode& FastFormatUnicode::ToLower()
|
||||
{
|
||||
wxChar *ch = (wxChar *)m_dest.GetPtr();
|
||||
for (uint i = 0; i < m_Length; ++i, ++ch)
|
||||
*ch = (wxChar)wxTolower(*ch);
|
||||
wxChar* ch = (wxChar*)m_dest.GetPtr();
|
||||
for (uint i = 0; i < m_Length; ++i, ++ch)
|
||||
*ch = (wxChar)wxTolower(*ch);
|
||||
|
||||
return *this;
|
||||
return *this;
|
||||
}
|
||||
|
||||
FastFormatUnicode &FastFormatUnicode::operator+=(const char *psz)
|
||||
FastFormatUnicode& FastFormatUnicode::operator+=(const char* psz)
|
||||
{
|
||||
Write(L"%s", WX_STR(fromUTF8(psz)));
|
||||
return *this;
|
||||
Write(L"%s", WX_STR(fromUTF8(psz)));
|
||||
return *this;
|
||||
}
|
||||
|
||||
wxString &operator+=(wxString &str1, const FastFormatUnicode &str2)
|
||||
wxString& operator+=(wxString& str1, const FastFormatUnicode& str2)
|
||||
{
|
||||
str1.Append(str2.c_str(), str2.Length());
|
||||
return str1;
|
||||
str1.Append(str2.c_str(), str2.Length());
|
||||
return str1;
|
||||
}
|
||||
|
||||
wxString operator+(const wxString &str1, const FastFormatUnicode &str2)
|
||||
wxString operator+(const wxString& str1, const FastFormatUnicode& str2)
|
||||
{
|
||||
wxString s = str1;
|
||||
s += str2;
|
||||
return s;
|
||||
wxString s = str1;
|
||||
s += str2;
|
||||
return s;
|
||||
}
|
||||
|
||||
wxString operator+(const wxChar *str1, const FastFormatUnicode &str2)
|
||||
wxString operator+(const wxChar* str1, const FastFormatUnicode& str2)
|
||||
{
|
||||
wxString s = str1;
|
||||
s += str2;
|
||||
return s;
|
||||
wxString s = str1;
|
||||
s += str2;
|
||||
return s;
|
||||
}
|
||||
|
||||
wxString operator+(const FastFormatUnicode &str1, const wxString &str2)
|
||||
wxString operator+(const FastFormatUnicode& str1, const wxString& str2)
|
||||
{
|
||||
wxString s = str1;
|
||||
s += str2;
|
||||
return s;
|
||||
wxString s = str1;
|
||||
s += str2;
|
||||
return s;
|
||||
}
|
||||
|
||||
wxString operator+(const FastFormatUnicode &str1, const wxChar *str2)
|
||||
wxString operator+(const FastFormatUnicode& str1, const wxChar* str2)
|
||||
{
|
||||
wxString s = str1;
|
||||
s += str2;
|
||||
return s;
|
||||
wxString s = str1;
|
||||
s += str2;
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
@ -252,38 +252,38 @@ wxString operator+(const FastFormatUnicode &str1, const wxChar *str2)
|
|||
// FastFormatAscii (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
FastFormatAscii::FastFormatAscii()
|
||||
: m_dest(2048)
|
||||
: m_dest(2048)
|
||||
{
|
||||
Clear();
|
||||
Clear();
|
||||
}
|
||||
|
||||
void FastFormatAscii::Clear()
|
||||
{
|
||||
m_dest.GetPtr()[0] = 0;
|
||||
m_dest.GetPtr()[0] = 0;
|
||||
}
|
||||
|
||||
const wxString FastFormatAscii::GetString() const
|
||||
{
|
||||
return fromAscii(m_dest.GetPtr());
|
||||
return fromAscii(m_dest.GetPtr());
|
||||
}
|
||||
|
||||
FastFormatAscii &FastFormatAscii::WriteV(const char *fmt, va_list argptr)
|
||||
FastFormatAscii& FastFormatAscii::WriteV(const char* fmt, va_list argptr)
|
||||
{
|
||||
format_that_ascii_mess(m_dest, strlen(m_dest.GetPtr()), fmt, argptr);
|
||||
return *this;
|
||||
format_that_ascii_mess(m_dest, strlen(m_dest.GetPtr()), fmt, argptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
FastFormatAscii &FastFormatAscii::Write(const char *fmt, ...)
|
||||
FastFormatAscii& FastFormatAscii::Write(const char* fmt, ...)
|
||||
{
|
||||
va_list list;
|
||||
va_start(list, fmt);
|
||||
WriteV(fmt, list);
|
||||
va_end(list);
|
||||
return *this;
|
||||
va_list list;
|
||||
va_start(list, fmt);
|
||||
WriteV(fmt, list);
|
||||
va_end(list);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
bool FastFormatAscii::IsEmpty() const
|
||||
{
|
||||
return m_dest[0] == 0;
|
||||
return m_dest[0] == 0;
|
||||
}
|
||||
|
|
204
common/General.h
204
common/General.h
|
@ -26,17 +26,15 @@
|
|||
// Macro used for removing some of the redtape involved in defining bitfield/union helpers.
|
||||
//
|
||||
#define BITFIELD32() \
|
||||
union \
|
||||
{ \
|
||||
u32 bitset; \
|
||||
struct \
|
||||
{
|
||||
union \
|
||||
{ \
|
||||
u32 bitset; \
|
||||
struct \
|
||||
{
|
||||
|
||||
#define BITFIELD_END \
|
||||
} \
|
||||
; \
|
||||
} \
|
||||
;
|
||||
}; \
|
||||
};
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
@ -52,20 +50,20 @@
|
|||
class RecursionGuard
|
||||
{
|
||||
public:
|
||||
int &Counter;
|
||||
int& Counter;
|
||||
|
||||
RecursionGuard(int &counter)
|
||||
: Counter(counter)
|
||||
{
|
||||
++Counter;
|
||||
}
|
||||
RecursionGuard(int& counter)
|
||||
: Counter(counter)
|
||||
{
|
||||
++Counter;
|
||||
}
|
||||
|
||||
virtual ~RecursionGuard()
|
||||
{
|
||||
--Counter;
|
||||
}
|
||||
virtual ~RecursionGuard()
|
||||
{
|
||||
--Counter;
|
||||
}
|
||||
|
||||
bool IsReentrant() const { return Counter > 1; }
|
||||
bool IsReentrant() const { return Counter > 1; }
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -74,30 +72,30 @@ public:
|
|||
class IActionInvocation
|
||||
{
|
||||
public:
|
||||
virtual ~IActionInvocation() = default;
|
||||
virtual void InvokeAction() = 0;
|
||||
virtual ~IActionInvocation() = default;
|
||||
virtual void InvokeAction() = 0;
|
||||
};
|
||||
|
||||
class ICloneable
|
||||
{
|
||||
public:
|
||||
virtual ICloneable *Clone() const = 0;
|
||||
virtual ICloneable* Clone() const = 0;
|
||||
};
|
||||
|
||||
class IDeletableObject
|
||||
{
|
||||
public:
|
||||
virtual ~IDeletableObject() = default;
|
||||
virtual ~IDeletableObject() = default;
|
||||
|
||||
virtual void DeleteSelf() = 0;
|
||||
virtual bool IsBeingDeleted() = 0;
|
||||
virtual void DeleteSelf() = 0;
|
||||
virtual bool IsBeingDeleted() = 0;
|
||||
|
||||
protected:
|
||||
// This function is GUI implementation dependent! It's implemented by PCSX2's AppHost,
|
||||
// but if the SysCore is being linked to another front end, you'll need to implement this
|
||||
// yourself. Most GUIs have built in message pumps. If a platform lacks one then you'll
|
||||
// need to implement one yourself (yay?).
|
||||
virtual void DoDeletion() = 0;
|
||||
// This function is GUI implementation dependent! It's implemented by PCSX2's AppHost,
|
||||
// but if the SysCore is being linked to another front end, you'll need to implement this
|
||||
// yourself. Most GUIs have built in message pumps. If a platform lacks one then you'll
|
||||
// need to implement one yourself (yay?).
|
||||
virtual void DoDeletion() = 0;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -126,26 +124,26 @@ protected:
|
|||
class BaseDeletableObject : public virtual IDeletableObject
|
||||
{
|
||||
protected:
|
||||
std::atomic<bool> m_IsBeingDeleted;
|
||||
std::atomic<bool> m_IsBeingDeleted;
|
||||
|
||||
public:
|
||||
BaseDeletableObject();
|
||||
virtual ~BaseDeletableObject();
|
||||
BaseDeletableObject();
|
||||
virtual ~BaseDeletableObject();
|
||||
|
||||
void DeleteSelf();
|
||||
bool IsBeingDeleted() { return !!m_IsBeingDeleted; }
|
||||
void DeleteSelf();
|
||||
bool IsBeingDeleted() { return !!m_IsBeingDeleted; }
|
||||
|
||||
// Returns FALSE if the object is already marked for deletion, or TRUE if the app
|
||||
// should schedule the object for deletion. Only schedule if TRUE is returned, otherwise
|
||||
// the object could get deleted twice if two threads try to schedule it at the same time.
|
||||
bool MarkForDeletion();
|
||||
// Returns FALSE if the object is already marked for deletion, or TRUE if the app
|
||||
// should schedule the object for deletion. Only schedule if TRUE is returned, otherwise
|
||||
// the object could get deleted twice if two threads try to schedule it at the same time.
|
||||
bool MarkForDeletion();
|
||||
|
||||
protected:
|
||||
// This function is GUI implementation dependent! It's implemented by PCSX2's AppHost,
|
||||
// but if the SysCore is being linked to another front end, you'll need to implement this
|
||||
// yourself. Most GUIs have built in message pumps. If a platform lacks one then you'll
|
||||
// need to implement one yourself (yay?).
|
||||
virtual void DoDeletion();
|
||||
// This function is GUI implementation dependent! It's implemented by PCSX2's AppHost,
|
||||
// but if the SysCore is being linked to another front end, you'll need to implement this
|
||||
// yourself. Most GUIs have built in message pumps. If a platform lacks one then you'll
|
||||
// need to implement one yourself (yay?).
|
||||
virtual void DoDeletion();
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -154,76 +152,76 @@ protected:
|
|||
class PageProtectionMode
|
||||
{
|
||||
protected:
|
||||
bool m_read;
|
||||
bool m_write;
|
||||
bool m_exec;
|
||||
bool m_read;
|
||||
bool m_write;
|
||||
bool m_exec;
|
||||
|
||||
public:
|
||||
PageProtectionMode()
|
||||
{
|
||||
All(false);
|
||||
}
|
||||
PageProtectionMode()
|
||||
{
|
||||
All(false);
|
||||
}
|
||||
|
||||
PageProtectionMode &Read(bool allow = true)
|
||||
{
|
||||
m_read = allow;
|
||||
return *this;
|
||||
}
|
||||
PageProtectionMode& Read(bool allow = true)
|
||||
{
|
||||
m_read = allow;
|
||||
return *this;
|
||||
}
|
||||
|
||||
PageProtectionMode &Write(bool allow = true)
|
||||
{
|
||||
m_write = allow;
|
||||
return *this;
|
||||
}
|
||||
PageProtectionMode& Write(bool allow = true)
|
||||
{
|
||||
m_write = allow;
|
||||
return *this;
|
||||
}
|
||||
|
||||
PageProtectionMode &Execute(bool allow = true)
|
||||
{
|
||||
m_exec = allow;
|
||||
return *this;
|
||||
}
|
||||
PageProtectionMode& Execute(bool allow = true)
|
||||
{
|
||||
m_exec = allow;
|
||||
return *this;
|
||||
}
|
||||
|
||||
PageProtectionMode &All(bool allow = true)
|
||||
{
|
||||
m_read = m_write = m_exec = allow;
|
||||
return *this;
|
||||
}
|
||||
PageProtectionMode& All(bool allow = true)
|
||||
{
|
||||
m_read = m_write = m_exec = allow;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool CanRead() const { return m_read; }
|
||||
bool CanWrite() const { return m_write; }
|
||||
bool CanExecute() const { return m_exec && m_read; }
|
||||
bool IsNone() const { return !m_read && !m_write; }
|
||||
bool CanRead() const { return m_read; }
|
||||
bool CanWrite() const { return m_write; }
|
||||
bool CanExecute() const { return m_exec && m_read; }
|
||||
bool IsNone() const { return !m_read && !m_write; }
|
||||
|
||||
wxString ToString() const;
|
||||
wxString ToString() const;
|
||||
};
|
||||
|
||||
static __fi PageProtectionMode PageAccess_None()
|
||||
{
|
||||
return PageProtectionMode();
|
||||
return PageProtectionMode();
|
||||
}
|
||||
|
||||
static __fi PageProtectionMode PageAccess_ReadOnly()
|
||||
{
|
||||
return PageProtectionMode().Read();
|
||||
return PageProtectionMode().Read();
|
||||
}
|
||||
|
||||
static __fi PageProtectionMode PageAccess_WriteOnly()
|
||||
{
|
||||
return PageProtectionMode().Write();
|
||||
return PageProtectionMode().Write();
|
||||
}
|
||||
|
||||
static __fi PageProtectionMode PageAccess_ReadWrite()
|
||||
{
|
||||
return PageAccess_ReadOnly().Write();
|
||||
return PageAccess_ReadOnly().Write();
|
||||
}
|
||||
|
||||
static __fi PageProtectionMode PageAccess_ExecOnly()
|
||||
{
|
||||
return PageAccess_ReadOnly().Execute();
|
||||
return PageAccess_ReadOnly().Execute();
|
||||
}
|
||||
|
||||
static __fi PageProtectionMode PageAccess_Any()
|
||||
{
|
||||
return PageProtectionMode().All();
|
||||
return PageProtectionMode().All();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -233,35 +231,35 @@ static __fi PageProtectionMode PageAccess_Any()
|
|||
// platform prior to wxWidgets .. it should prolly be removed -- air)
|
||||
namespace HostSys
|
||||
{
|
||||
void *MmapReserve(uptr base, size_t size);
|
||||
bool MmapCommit(uptr base, size_t size, const PageProtectionMode &mode);
|
||||
void MmapReset(uptr base, size_t size);
|
||||
void* MmapReserve(uptr base, size_t size);
|
||||
bool MmapCommit(uptr base, size_t size, const PageProtectionMode& mode);
|
||||
void MmapReset(uptr base, size_t size);
|
||||
|
||||
void *MmapReservePtr(void *base, size_t size);
|
||||
bool MmapCommitPtr(void *base, size_t size, const PageProtectionMode &mode);
|
||||
void MmapResetPtr(void *base, size_t size);
|
||||
void* MmapReservePtr(void* base, size_t size);
|
||||
bool MmapCommitPtr(void* base, size_t size, const PageProtectionMode& mode);
|
||||
void MmapResetPtr(void* base, size_t size);
|
||||
|
||||
// Maps a block of memory for use as a recompiled code buffer.
|
||||
// Returns NULL on allocation failure.
|
||||
extern void *Mmap(uptr base, size_t size);
|
||||
// Maps a block of memory for use as a recompiled code buffer.
|
||||
// Returns NULL on allocation failure.
|
||||
extern void* Mmap(uptr base, size_t size);
|
||||
|
||||
// Unmaps a block allocated by SysMmap
|
||||
extern void Munmap(uptr base, size_t size);
|
||||
// Unmaps a block allocated by SysMmap
|
||||
extern void Munmap(uptr base, size_t size);
|
||||
|
||||
extern void MemProtect(void *baseaddr, size_t size, const PageProtectionMode &mode);
|
||||
extern void MemProtect(void* baseaddr, size_t size, const PageProtectionMode& mode);
|
||||
|
||||
extern void Munmap(void *base, size_t size);
|
||||
extern void Munmap(void* base, size_t size);
|
||||
|
||||
template <uint size>
|
||||
void MemProtectStatic(u8 (&arr)[size], const PageProtectionMode &mode)
|
||||
{
|
||||
MemProtect(arr, size, mode);
|
||||
}
|
||||
}
|
||||
template <uint size>
|
||||
void MemProtectStatic(u8 (&arr)[size], const PageProtectionMode& mode)
|
||||
{
|
||||
MemProtect(arr, size, mode);
|
||||
}
|
||||
} // namespace HostSys
|
||||
|
||||
// Safe version of Munmap -- NULLs the pointer variable immediately after free'ing it.
|
||||
#define SafeSysMunmap(ptr, size) \
|
||||
((void)(HostSys::Munmap((uptr)(ptr), size), (ptr) = NULL))
|
||||
((void)(HostSys::Munmap((uptr)(ptr), size), (ptr) = NULL))
|
||||
|
||||
extern void InitCPUTicks();
|
||||
extern u64 GetTickFrequency();
|
||||
|
|
|
@ -23,393 +23,404 @@ const wxRect wxDefaultRect(wxDefaultCoord, wxDefaultCoord, wxDefaultCoord, wxDef
|
|||
wxDirName g_fullBaseDirName = wxDirName(L"");
|
||||
void SetFullBaseDir(wxDirName appRoot)
|
||||
{
|
||||
g_fullBaseDirName = appRoot;
|
||||
g_fullBaseDirName = appRoot;
|
||||
}
|
||||
|
||||
static int _calcEnumLength(const wxChar *const *enumArray)
|
||||
static int _calcEnumLength(const wxChar* const* enumArray)
|
||||
{
|
||||
int cnt = 0;
|
||||
while (*enumArray != NULL) {
|
||||
enumArray++;
|
||||
cnt++;
|
||||
}
|
||||
int cnt = 0;
|
||||
while (*enumArray != NULL)
|
||||
{
|
||||
enumArray++;
|
||||
cnt++;
|
||||
}
|
||||
|
||||
return cnt;
|
||||
return cnt;
|
||||
}
|
||||
|
||||
ScopedIniGroup::ScopedIniGroup(IniInterface &mommy, const wxString &group)
|
||||
: m_mom(mommy)
|
||||
ScopedIniGroup::ScopedIniGroup(IniInterface& mommy, const wxString& group)
|
||||
: m_mom(mommy)
|
||||
{
|
||||
pxAssertDev(wxStringTokenize(group, L"/").Count() <= 1, L"Cannot nest more than one group deep per instance of ScopedIniGroup.");
|
||||
m_mom.SetPath(group);
|
||||
pxAssertDev(wxStringTokenize(group, L"/").Count() <= 1, L"Cannot nest more than one group deep per instance of ScopedIniGroup.");
|
||||
m_mom.SetPath(group);
|
||||
}
|
||||
|
||||
ScopedIniGroup::~ScopedIniGroup()
|
||||
{
|
||||
m_mom.SetPath(L"..");
|
||||
m_mom.SetPath(L"..");
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// IniInterface (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
IniInterface::IniInterface(wxConfigBase &config)
|
||||
IniInterface::IniInterface(wxConfigBase& config)
|
||||
{
|
||||
m_Config = &config;
|
||||
m_Config = &config;
|
||||
}
|
||||
|
||||
IniInterface::IniInterface(wxConfigBase *config)
|
||||
IniInterface::IniInterface(wxConfigBase* config)
|
||||
{
|
||||
m_Config = config;
|
||||
m_Config = config;
|
||||
}
|
||||
|
||||
IniInterface::IniInterface()
|
||||
{
|
||||
m_Config = wxConfigBase::Get(false);
|
||||
m_Config = wxConfigBase::Get(false);
|
||||
}
|
||||
|
||||
IniInterface::~IniInterface()
|
||||
{
|
||||
Flush();
|
||||
Flush();
|
||||
}
|
||||
|
||||
void IniInterface::SetPath(const wxString &path)
|
||||
void IniInterface::SetPath(const wxString& path)
|
||||
{
|
||||
if (m_Config)
|
||||
m_Config->SetPath(path);
|
||||
if (m_Config)
|
||||
m_Config->SetPath(path);
|
||||
}
|
||||
|
||||
void IniInterface::Flush()
|
||||
{
|
||||
if (m_Config)
|
||||
m_Config->Flush();
|
||||
if (m_Config)
|
||||
m_Config->Flush();
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// IniLoader (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
IniLoader::IniLoader(wxConfigBase &config)
|
||||
: IniInterface(config)
|
||||
IniLoader::IniLoader(wxConfigBase& config)
|
||||
: IniInterface(config)
|
||||
{
|
||||
}
|
||||
|
||||
IniLoader::IniLoader(wxConfigBase *config)
|
||||
: IniInterface(config)
|
||||
IniLoader::IniLoader(wxConfigBase* config)
|
||||
: IniInterface(config)
|
||||
{
|
||||
}
|
||||
|
||||
IniLoader::IniLoader()
|
||||
: IniInterface()
|
||||
: IniInterface()
|
||||
{
|
||||
}
|
||||
|
||||
void IniLoader::Entry(const wxString &var, wxString &value, const wxString defvalue)
|
||||
void IniLoader::Entry(const wxString& var, wxString& value, const wxString defvalue)
|
||||
{
|
||||
if (m_Config)
|
||||
m_Config->Read(var, &value, defvalue);
|
||||
else
|
||||
value = defvalue;
|
||||
if (m_Config)
|
||||
m_Config->Read(var, &value, defvalue);
|
||||
else
|
||||
value = defvalue;
|
||||
}
|
||||
|
||||
void IniLoader::Entry(const wxString &var, wxDirName &value, const wxDirName defvalue, bool isAllowRelative)
|
||||
void IniLoader::Entry(const wxString& var, wxDirName& value, const wxDirName defvalue, bool isAllowRelative)
|
||||
{
|
||||
wxString dest;
|
||||
if (m_Config)
|
||||
m_Config->Read(var, &dest, wxEmptyString);
|
||||
wxString dest;
|
||||
if (m_Config)
|
||||
m_Config->Read(var, &dest, wxEmptyString);
|
||||
|
||||
if (dest.IsEmpty())
|
||||
value = defvalue;
|
||||
else {
|
||||
value = dest;
|
||||
if (isAllowRelative)
|
||||
value = g_fullBaseDirName + value;
|
||||
if (dest.IsEmpty())
|
||||
value = defvalue;
|
||||
else
|
||||
{
|
||||
value = dest;
|
||||
if (isAllowRelative)
|
||||
value = g_fullBaseDirName + value;
|
||||
|
||||
if (value.IsAbsolute())
|
||||
value.Normalize();
|
||||
}
|
||||
if (value.IsAbsolute())
|
||||
value.Normalize();
|
||||
}
|
||||
}
|
||||
|
||||
void IniLoader::Entry(const wxString &var, wxFileName &value, const wxFileName defvalue, bool isAllowRelative)
|
||||
void IniLoader::Entry(const wxString& var, wxFileName& value, const wxFileName defvalue, bool isAllowRelative)
|
||||
{
|
||||
wxString dest(defvalue.GetFullPath());
|
||||
if (m_Config)
|
||||
m_Config->Read(var, &dest, defvalue.GetFullPath());
|
||||
value = dest;
|
||||
if (isAllowRelative)
|
||||
value = g_fullBaseDirName + value;
|
||||
wxString dest(defvalue.GetFullPath());
|
||||
if (m_Config)
|
||||
m_Config->Read(var, &dest, defvalue.GetFullPath());
|
||||
value = dest;
|
||||
if (isAllowRelative)
|
||||
value = g_fullBaseDirName + value;
|
||||
|
||||
if (value.IsAbsolute())
|
||||
value.Normalize();
|
||||
if (value.IsAbsolute())
|
||||
value.Normalize();
|
||||
|
||||
if (value.HasVolume())
|
||||
value.SetVolume(value.GetVolume().Upper());
|
||||
if (value.HasVolume())
|
||||
value.SetVolume(value.GetVolume().Upper());
|
||||
}
|
||||
|
||||
void IniLoader::Entry(const wxString &var, int &value, const int defvalue)
|
||||
void IniLoader::Entry(const wxString& var, int& value, const int defvalue)
|
||||
{
|
||||
if (m_Config)
|
||||
m_Config->Read(var, &value, defvalue);
|
||||
else
|
||||
value = defvalue;
|
||||
if (m_Config)
|
||||
m_Config->Read(var, &value, defvalue);
|
||||
else
|
||||
value = defvalue;
|
||||
}
|
||||
|
||||
void IniLoader::Entry(const wxString &var, uint &value, const uint defvalue)
|
||||
void IniLoader::Entry(const wxString& var, uint& value, const uint defvalue)
|
||||
{
|
||||
if (m_Config)
|
||||
m_Config->Read(var, (int *)&value, (int)defvalue);
|
||||
else
|
||||
value = defvalue;
|
||||
if (m_Config)
|
||||
m_Config->Read(var, (int*)&value, (int)defvalue);
|
||||
else
|
||||
value = defvalue;
|
||||
}
|
||||
|
||||
void IniLoader::Entry(const wxString &var, bool &value, const bool defvalue)
|
||||
void IniLoader::Entry(const wxString& var, bool& value, const bool defvalue)
|
||||
{
|
||||
// TODO : Stricter value checking on enabled/disabled?
|
||||
wxString dest;
|
||||
if(defvalue)
|
||||
dest = wxString("enabled");
|
||||
else
|
||||
dest = wxString("disabled");
|
||||
// TODO : Stricter value checking on enabled/disabled?
|
||||
wxString dest;
|
||||
if (defvalue)
|
||||
dest = wxString("enabled");
|
||||
else
|
||||
dest = wxString("disabled");
|
||||
|
||||
if (m_Config)
|
||||
m_Config->Read(var, &dest, dest);
|
||||
value = (dest == L"enabled") || (dest == L"1");
|
||||
if (m_Config)
|
||||
m_Config->Read(var, &dest, dest);
|
||||
value = (dest == L"enabled") || (dest == L"1");
|
||||
}
|
||||
|
||||
bool IniLoader::EntryBitBool(const wxString &var, bool value, const bool defvalue)
|
||||
bool IniLoader::EntryBitBool(const wxString& var, bool value, const bool defvalue)
|
||||
{
|
||||
// Note: 'value' param is used by inisaver only.
|
||||
bool result;
|
||||
Entry(var, result, defvalue);
|
||||
return result;
|
||||
// Note: 'value' param is used by inisaver only.
|
||||
bool result;
|
||||
Entry(var, result, defvalue);
|
||||
return result;
|
||||
}
|
||||
|
||||
int IniLoader::EntryBitfield(const wxString &var, int value, const int defvalue)
|
||||
int IniLoader::EntryBitfield(const wxString& var, int value, const int defvalue)
|
||||
{
|
||||
int result;
|
||||
Entry(var, result, defvalue);
|
||||
return result;
|
||||
int result;
|
||||
Entry(var, result, defvalue);
|
||||
return result;
|
||||
}
|
||||
|
||||
void IniLoader::Entry(const wxString &var, double& value, const double defvalue)
|
||||
void IniLoader::Entry(const wxString& var, double& value, const double defvalue)
|
||||
{
|
||||
auto readval = wxString::FromDouble(value);
|
||||
auto readval = wxString::FromDouble(value);
|
||||
|
||||
if (m_Config)
|
||||
m_Config->Read(var, &readval);
|
||||
if (m_Config)
|
||||
m_Config->Read(var, &readval);
|
||||
|
||||
if (!readval.ToDouble(&value))
|
||||
value = 0.0;
|
||||
if (!readval.ToDouble(&value))
|
||||
value = 0.0;
|
||||
}
|
||||
|
||||
void IniLoader::Entry(const wxString &var, wxPoint &value, const wxPoint defvalue)
|
||||
void IniLoader::Entry(const wxString& var, wxPoint& value, const wxPoint defvalue)
|
||||
{
|
||||
if (!m_Config) {
|
||||
value = defvalue;
|
||||
return;
|
||||
}
|
||||
TryParse(value, m_Config->Read(var, ToString(defvalue)), defvalue);
|
||||
if (!m_Config)
|
||||
{
|
||||
value = defvalue;
|
||||
return;
|
||||
}
|
||||
TryParse(value, m_Config->Read(var, ToString(defvalue)), defvalue);
|
||||
}
|
||||
|
||||
void IniLoader::Entry(const wxString &var, wxSize &value, const wxSize defvalue)
|
||||
void IniLoader::Entry(const wxString& var, wxSize& value, const wxSize defvalue)
|
||||
{
|
||||
if (!m_Config) {
|
||||
value = defvalue;
|
||||
return;
|
||||
}
|
||||
TryParse(value, m_Config->Read(var, ToString(defvalue)), defvalue);
|
||||
if (!m_Config)
|
||||
{
|
||||
value = defvalue;
|
||||
return;
|
||||
}
|
||||
TryParse(value, m_Config->Read(var, ToString(defvalue)), defvalue);
|
||||
}
|
||||
|
||||
void IniLoader::Entry(const wxString &var, wxRect &value, const wxRect defvalue)
|
||||
void IniLoader::Entry(const wxString& var, wxRect& value, const wxRect defvalue)
|
||||
{
|
||||
if (!m_Config) {
|
||||
value = defvalue;
|
||||
return;
|
||||
}
|
||||
TryParse(value, m_Config->Read(var, ToString(defvalue)), defvalue);
|
||||
if (!m_Config)
|
||||
{
|
||||
value = defvalue;
|
||||
return;
|
||||
}
|
||||
TryParse(value, m_Config->Read(var, ToString(defvalue)), defvalue);
|
||||
}
|
||||
|
||||
void IniLoader::_EnumEntry(const wxString &var, int &value, const wxChar *const *enumArray, int defvalue)
|
||||
void IniLoader::_EnumEntry(const wxString& var, int& value, const wxChar* const* enumArray, int defvalue)
|
||||
{
|
||||
// Confirm default value sanity...
|
||||
// Confirm default value sanity...
|
||||
|
||||
const int cnt = _calcEnumLength(enumArray);
|
||||
if (!IndexBoundsCheck(L"IniLoader EnumDefaultValue", defvalue, cnt)) {
|
||||
Console.Error("(LoadSettings) Default enumeration index is out of bounds. Truncating.");
|
||||
defvalue = cnt - 1;
|
||||
}
|
||||
const int cnt = _calcEnumLength(enumArray);
|
||||
if (!IndexBoundsCheck(L"IniLoader EnumDefaultValue", defvalue, cnt))
|
||||
{
|
||||
Console.Error("(LoadSettings) Default enumeration index is out of bounds. Truncating.");
|
||||
defvalue = cnt - 1;
|
||||
}
|
||||
|
||||
// Sanity confirmed, proceed with craziness!
|
||||
// Sanity confirmed, proceed with craziness!
|
||||
|
||||
if (!m_Config) {
|
||||
value = defvalue;
|
||||
return;
|
||||
}
|
||||
if (!m_Config)
|
||||
{
|
||||
value = defvalue;
|
||||
return;
|
||||
}
|
||||
|
||||
wxString retval;
|
||||
m_Config->Read(var, &retval, enumArray[defvalue]);
|
||||
wxString retval;
|
||||
m_Config->Read(var, &retval, enumArray[defvalue]);
|
||||
|
||||
int i = 0;
|
||||
while (enumArray[i] != NULL && (retval != enumArray[i]))
|
||||
i++;
|
||||
int i = 0;
|
||||
while (enumArray[i] != NULL && (retval != enumArray[i]))
|
||||
i++;
|
||||
|
||||
if (enumArray[i] == NULL) {
|
||||
Console.Warning(L"(LoadSettings) Warning: Unrecognized value '%s' on key '%s'\n\tUsing the default setting of '%s'.",
|
||||
WX_STR(retval), WX_STR(var), enumArray[defvalue]);
|
||||
value = defvalue;
|
||||
} else
|
||||
value = i;
|
||||
if (enumArray[i] == NULL)
|
||||
{
|
||||
Console.Warning(L"(LoadSettings) Warning: Unrecognized value '%s' on key '%s'\n\tUsing the default setting of '%s'.",
|
||||
WX_STR(retval), WX_STR(var), enumArray[defvalue]);
|
||||
value = defvalue;
|
||||
}
|
||||
else
|
||||
value = i;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// IniSaver (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
IniSaver::IniSaver(wxConfigBase &config)
|
||||
: IniInterface(config)
|
||||
IniSaver::IniSaver(wxConfigBase& config)
|
||||
: IniInterface(config)
|
||||
{
|
||||
}
|
||||
|
||||
IniSaver::IniSaver(wxConfigBase *config)
|
||||
: IniInterface(config)
|
||||
IniSaver::IniSaver(wxConfigBase* config)
|
||||
: IniInterface(config)
|
||||
{
|
||||
}
|
||||
|
||||
IniSaver::IniSaver()
|
||||
: IniInterface()
|
||||
: IniInterface()
|
||||
{
|
||||
}
|
||||
|
||||
void IniSaver::Entry(const wxString &var, wxString &value, const wxString defvalue)
|
||||
void IniSaver::Entry(const wxString& var, wxString& value, const wxString defvalue)
|
||||
{
|
||||
if (!m_Config)
|
||||
return;
|
||||
m_Config->Write(var, value);
|
||||
if (!m_Config)
|
||||
return;
|
||||
m_Config->Write(var, value);
|
||||
}
|
||||
|
||||
void IniSaver::Entry(const wxString &var, wxDirName &value, const wxDirName defvalue, bool isAllowRelative)
|
||||
void IniSaver::Entry(const wxString& var, wxDirName& value, const wxDirName defvalue, bool isAllowRelative)
|
||||
{
|
||||
if (!m_Config)
|
||||
return;
|
||||
wxDirName res(value);
|
||||
if (!m_Config)
|
||||
return;
|
||||
wxDirName res(value);
|
||||
|
||||
if (res.IsAbsolute())
|
||||
res.Normalize();
|
||||
if (res.IsAbsolute())
|
||||
res.Normalize();
|
||||
|
||||
if (isAllowRelative)
|
||||
res = wxDirName::MakeAutoRelativeTo(res, g_fullBaseDirName.ToString());
|
||||
if (isAllowRelative)
|
||||
res = wxDirName::MakeAutoRelativeTo(res, g_fullBaseDirName.ToString());
|
||||
|
||||
|
||||
/*if( value == defvalue )
|
||||
/*if( value == defvalue )
|
||||
m_Config->Write( var, wxString() );
|
||||
else*/
|
||||
m_Config->Write(var, res.ToString());
|
||||
m_Config->Write(var, res.ToString());
|
||||
}
|
||||
|
||||
void IniSaver::Entry(const wxString &var, wxFileName &value, const wxFileName defvalue, bool isAllowRelative)
|
||||
void IniSaver::Entry(const wxString& var, wxFileName& value, const wxFileName defvalue, bool isAllowRelative)
|
||||
{
|
||||
if (!m_Config)
|
||||
return;
|
||||
wxFileName res(value);
|
||||
if (!m_Config)
|
||||
return;
|
||||
wxFileName res(value);
|
||||
|
||||
if (res.IsAbsolute())
|
||||
res.Normalize();
|
||||
if (res.IsAbsolute())
|
||||
res.Normalize();
|
||||
|
||||
if (isAllowRelative)
|
||||
res = wxDirName::MakeAutoRelativeTo(res, g_fullBaseDirName.ToString());
|
||||
if (isAllowRelative)
|
||||
res = wxDirName::MakeAutoRelativeTo(res, g_fullBaseDirName.ToString());
|
||||
|
||||
m_Config->Write(var, res.GetFullPath());
|
||||
m_Config->Write(var, res.GetFullPath());
|
||||
}
|
||||
|
||||
void IniSaver::Entry(const wxString &var, int &value, const int defvalue)
|
||||
void IniSaver::Entry(const wxString& var, int& value, const int defvalue)
|
||||
{
|
||||
if (!m_Config)
|
||||
return;
|
||||
m_Config->Write(var, value);
|
||||
if (!m_Config)
|
||||
return;
|
||||
m_Config->Write(var, value);
|
||||
}
|
||||
|
||||
void IniSaver::Entry(const wxString &var, uint &value, const uint defvalue)
|
||||
void IniSaver::Entry(const wxString& var, uint& value, const uint defvalue)
|
||||
{
|
||||
if (!m_Config)
|
||||
return;
|
||||
m_Config->Write(var, (int)value);
|
||||
if (!m_Config)
|
||||
return;
|
||||
m_Config->Write(var, (int)value);
|
||||
}
|
||||
|
||||
void IniSaver::Entry(const wxString &var, bool &value, const bool defvalue)
|
||||
void IniSaver::Entry(const wxString& var, bool& value, const bool defvalue)
|
||||
{
|
||||
if (!m_Config)
|
||||
return;
|
||||
m_Config->Write(var, value ? L"enabled" : L"disabled");
|
||||
if (!m_Config)
|
||||
return;
|
||||
m_Config->Write(var, value ? L"enabled" : L"disabled");
|
||||
}
|
||||
|
||||
bool IniSaver::EntryBitBool(const wxString &var, bool value, const bool defvalue)
|
||||
bool IniSaver::EntryBitBool(const wxString& var, bool value, const bool defvalue)
|
||||
{
|
||||
if (m_Config)
|
||||
m_Config->Write(var, value ? L"enabled" : L"disabled");
|
||||
return value;
|
||||
if (m_Config)
|
||||
m_Config->Write(var, value ? L"enabled" : L"disabled");
|
||||
return value;
|
||||
}
|
||||
|
||||
int IniSaver::EntryBitfield(const wxString &var, int value, const int defvalue)
|
||||
int IniSaver::EntryBitfield(const wxString& var, int value, const int defvalue)
|
||||
{
|
||||
if (m_Config)
|
||||
m_Config->Write(var, value);
|
||||
return value;
|
||||
if (m_Config)
|
||||
m_Config->Write(var, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
void IniSaver::Entry(const wxString &var, double &value, const double defvalue)
|
||||
void IniSaver::Entry(const wxString& var, double& value, const double defvalue)
|
||||
{
|
||||
if (!m_Config)
|
||||
return;
|
||||
if (!m_Config)
|
||||
return;
|
||||
|
||||
m_Config->Write(var, wxString::FromDouble(value));
|
||||
m_Config->Write(var, wxString::FromDouble(value));
|
||||
}
|
||||
|
||||
void IniSaver::Entry(const wxString &var, wxPoint &value, const wxPoint defvalue)
|
||||
void IniSaver::Entry(const wxString& var, wxPoint& value, const wxPoint defvalue)
|
||||
{
|
||||
if (!m_Config)
|
||||
return;
|
||||
m_Config->Write(var, ToString(value));
|
||||
if (!m_Config)
|
||||
return;
|
||||
m_Config->Write(var, ToString(value));
|
||||
}
|
||||
|
||||
void IniSaver::Entry(const wxString &var, wxSize &value, const wxSize defvalue)
|
||||
void IniSaver::Entry(const wxString& var, wxSize& value, const wxSize defvalue)
|
||||
{
|
||||
if (!m_Config)
|
||||
return;
|
||||
m_Config->Write(var, ToString(value));
|
||||
if (!m_Config)
|
||||
return;
|
||||
m_Config->Write(var, ToString(value));
|
||||
}
|
||||
|
||||
void IniSaver::Entry(const wxString &var, wxRect &value, const wxRect defvalue)
|
||||
void IniSaver::Entry(const wxString& var, wxRect& value, const wxRect defvalue)
|
||||
{
|
||||
if (!m_Config)
|
||||
return;
|
||||
m_Config->Write(var, ToString(value));
|
||||
if (!m_Config)
|
||||
return;
|
||||
m_Config->Write(var, ToString(value));
|
||||
}
|
||||
|
||||
void IniSaver::_EnumEntry(const wxString &var, int &value, const wxChar *const *enumArray, int defvalue)
|
||||
void IniSaver::_EnumEntry(const wxString& var, int& value, const wxChar* const* enumArray, int defvalue)
|
||||
{
|
||||
const int cnt = _calcEnumLength(enumArray);
|
||||
const int cnt = _calcEnumLength(enumArray);
|
||||
|
||||
// Confirm default value sanity...
|
||||
// Confirm default value sanity...
|
||||
|
||||
if (!IndexBoundsCheck(L"IniSaver EnumDefaultValue", defvalue, cnt)) {
|
||||
Console.Error("(SaveSettings) Default enumeration index is out of bounds. Truncating.");
|
||||
defvalue = cnt - 1;
|
||||
}
|
||||
if (!IndexBoundsCheck(L"IniSaver EnumDefaultValue", defvalue, cnt))
|
||||
{
|
||||
Console.Error("(SaveSettings) Default enumeration index is out of bounds. Truncating.");
|
||||
defvalue = cnt - 1;
|
||||
}
|
||||
|
||||
if (!m_Config)
|
||||
return;
|
||||
if (!m_Config)
|
||||
return;
|
||||
|
||||
if (value >= cnt) {
|
||||
Console.Warning(L"(SaveSettings) An illegal enumerated index was detected when saving '%s'", WX_STR(var));
|
||||
Console.Indent().Warning(
|
||||
L"Illegal Value: %d\n"
|
||||
L"Using Default: %d (%s)\n",
|
||||
value, defvalue, enumArray[defvalue]);
|
||||
if (value >= cnt)
|
||||
{
|
||||
Console.Warning(L"(SaveSettings) An illegal enumerated index was detected when saving '%s'", WX_STR(var));
|
||||
Console.Indent().Warning(
|
||||
L"Illegal Value: %d\n"
|
||||
L"Using Default: %d (%s)\n",
|
||||
value, defvalue, enumArray[defvalue]);
|
||||
|
||||
// Cause a debug assertion, since this is a fully recoverable error.
|
||||
pxAssert(value < cnt);
|
||||
// Cause a debug assertion, since this is a fully recoverable error.
|
||||
pxAssert(value < cnt);
|
||||
|
||||
value = defvalue;
|
||||
}
|
||||
value = defvalue;
|
||||
}
|
||||
|
||||
m_Config->Write(var, enumArray[value]);
|
||||
m_Config->Write(var, enumArray[value]);
|
||||
}
|
||||
|
|
|
@ -31,58 +31,58 @@
|
|||
class IniInterface
|
||||
{
|
||||
protected:
|
||||
wxConfigBase *m_Config;
|
||||
wxConfigBase* m_Config;
|
||||
|
||||
public:
|
||||
virtual ~IniInterface();
|
||||
explicit IniInterface();
|
||||
explicit IniInterface(wxConfigBase &config);
|
||||
explicit IniInterface(wxConfigBase *config);
|
||||
virtual ~IniInterface();
|
||||
explicit IniInterface();
|
||||
explicit IniInterface(wxConfigBase& config);
|
||||
explicit IniInterface(wxConfigBase* config);
|
||||
|
||||
void SetPath(const wxString &path);
|
||||
void Flush();
|
||||
void SetPath(const wxString& path);
|
||||
void Flush();
|
||||
|
||||
wxConfigBase &GetConfig()
|
||||
{
|
||||
pxAssert(m_Config);
|
||||
return *m_Config;
|
||||
}
|
||||
bool IsOk() const { return m_Config != NULL; }
|
||||
wxConfigBase& GetConfig()
|
||||
{
|
||||
pxAssert(m_Config);
|
||||
return *m_Config;
|
||||
}
|
||||
bool IsOk() const { return m_Config != NULL; }
|
||||
|
||||
virtual bool IsLoading() const = 0;
|
||||
bool IsSaving() const { return !IsLoading(); }
|
||||
virtual bool IsLoading() const = 0;
|
||||
bool IsSaving() const { return !IsLoading(); }
|
||||
|
||||
virtual void Entry(const wxString &var, wxString &value, const wxString defvalue = wxString()) = 0;
|
||||
virtual void Entry(const wxString &var, wxDirName &value, const wxDirName defvalue = wxDirName(), bool isAllowRelative = false) = 0;
|
||||
virtual void Entry(const wxString &var, wxFileName &value, const wxFileName defvalue = wxFileName(), bool isAllowRelative = false) = 0;
|
||||
virtual void Entry(const wxString &var, int &value, const int defvalue = 0) = 0;
|
||||
virtual void Entry(const wxString &var, uint &value, const uint defvalue = 0) = 0;
|
||||
virtual void Entry(const wxString &var, bool &value, const bool defvalue = false) = 0;
|
||||
virtual void Entry(const wxString& var, wxString& value, const wxString defvalue = wxString()) = 0;
|
||||
virtual void Entry(const wxString& var, wxDirName& value, const wxDirName defvalue = wxDirName(), bool isAllowRelative = false) = 0;
|
||||
virtual void Entry(const wxString& var, wxFileName& value, const wxFileName defvalue = wxFileName(), bool isAllowRelative = false) = 0;
|
||||
virtual void Entry(const wxString& var, int& value, const int defvalue = 0) = 0;
|
||||
virtual void Entry(const wxString& var, uint& value, const uint defvalue = 0) = 0;
|
||||
virtual void Entry(const wxString& var, bool& value, const bool defvalue = false) = 0;
|
||||
|
||||
// This special form of Entry is provided for bitfields, which cannot be passed by reference.
|
||||
virtual bool EntryBitBool(const wxString &var, bool value, const bool defvalue = false) = 0;
|
||||
virtual int EntryBitfield(const wxString &var, int value, const int defvalue = 0) = 0;
|
||||
// This special form of Entry is provided for bitfields, which cannot be passed by reference.
|
||||
virtual bool EntryBitBool(const wxString& var, bool value, const bool defvalue = false) = 0;
|
||||
virtual int EntryBitfield(const wxString& var, int value, const int defvalue = 0) = 0;
|
||||
|
||||
virtual void Entry(const wxString &var, double& value, const double defvalue = 0.0) = 0;
|
||||
virtual void Entry(const wxString& var, double& value, const double defvalue = 0.0) = 0;
|
||||
|
||||
virtual void Entry(const wxString &var, wxPoint &value, const wxPoint defvalue = wxDefaultPosition) = 0;
|
||||
virtual void Entry(const wxString &var, wxSize &value, const wxSize defvalue = wxDefaultSize) = 0;
|
||||
virtual void Entry(const wxString &var, wxRect &value, const wxRect defvalue = wxDefaultRect) = 0;
|
||||
virtual void Entry(const wxString& var, wxPoint& value, const wxPoint defvalue = wxDefaultPosition) = 0;
|
||||
virtual void Entry(const wxString& var, wxSize& value, const wxSize defvalue = wxDefaultSize) = 0;
|
||||
virtual void Entry(const wxString& var, wxRect& value, const wxRect defvalue = wxDefaultRect) = 0;
|
||||
|
||||
template <typename T>
|
||||
void EnumEntry(const wxString &var, T &value, const wxChar *const *enumArray = NULL, const T defvalue = (T)0)
|
||||
{
|
||||
int tstore = (int)value;
|
||||
auto defaultvalue = enum_cast(defvalue);
|
||||
if (enumArray == NULL)
|
||||
Entry(var, tstore, defaultvalue);
|
||||
else
|
||||
_EnumEntry(var, tstore, enumArray, defaultvalue);
|
||||
value = (T)tstore;
|
||||
}
|
||||
template <typename T>
|
||||
void EnumEntry(const wxString& var, T& value, const wxChar* const* enumArray = NULL, const T defvalue = (T)0)
|
||||
{
|
||||
int tstore = (int)value;
|
||||
auto defaultvalue = enum_cast(defvalue);
|
||||
if (enumArray == NULL)
|
||||
Entry(var, tstore, defaultvalue);
|
||||
else
|
||||
_EnumEntry(var, tstore, enumArray, defaultvalue);
|
||||
value = (T)tstore;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void _EnumEntry(const wxString &var, int &value, const wxChar *const *enumArray, int defvalue) = 0;
|
||||
virtual void _EnumEntry(const wxString& var, int& value, const wxChar* const* enumArray, int defvalue) = 0;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -91,11 +91,11 @@ protected:
|
|||
class ScopedIniGroup
|
||||
{
|
||||
protected:
|
||||
IniInterface &m_mom;
|
||||
IniInterface& m_mom;
|
||||
|
||||
public:
|
||||
ScopedIniGroup(IniInterface &mommy, const wxString &group);
|
||||
virtual ~ScopedIniGroup();
|
||||
ScopedIniGroup(IniInterface& mommy, const wxString& group);
|
||||
virtual ~ScopedIniGroup();
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -109,31 +109,31 @@ public:
|
|||
class IniLoader : public IniInterface
|
||||
{
|
||||
public:
|
||||
virtual ~IniLoader() = default;
|
||||
explicit IniLoader();
|
||||
explicit IniLoader(wxConfigBase &config);
|
||||
explicit IniLoader(wxConfigBase *config);
|
||||
virtual ~IniLoader() = default;
|
||||
explicit IniLoader();
|
||||
explicit IniLoader(wxConfigBase& config);
|
||||
explicit IniLoader(wxConfigBase* config);
|
||||
|
||||
bool IsLoading() const { return true; }
|
||||
bool IsLoading() const { return true; }
|
||||
|
||||
void Entry(const wxString &var, wxString &value, const wxString defvalue = wxEmptyString);
|
||||
void Entry(const wxString &var, wxDirName &value, const wxDirName defvalue = wxDirName(), bool isAllowRelative = false);
|
||||
void Entry(const wxString &var, wxFileName &value, const wxFileName defvalue = wxFileName(), bool isAllowRelative = false);
|
||||
void Entry(const wxString &var, int &value, const int defvalue = 0);
|
||||
void Entry(const wxString &var, uint &value, const uint defvalue = 0);
|
||||
void Entry(const wxString &var, bool &value, const bool defvalue = false);
|
||||
void Entry(const wxString& var, wxString& value, const wxString defvalue = wxEmptyString);
|
||||
void Entry(const wxString& var, wxDirName& value, const wxDirName defvalue = wxDirName(), bool isAllowRelative = false);
|
||||
void Entry(const wxString& var, wxFileName& value, const wxFileName defvalue = wxFileName(), bool isAllowRelative = false);
|
||||
void Entry(const wxString& var, int& value, const int defvalue = 0);
|
||||
void Entry(const wxString& var, uint& value, const uint defvalue = 0);
|
||||
void Entry(const wxString& var, bool& value, const bool defvalue = false);
|
||||
|
||||
bool EntryBitBool(const wxString &var, bool value, const bool defvalue = false);
|
||||
int EntryBitfield(const wxString &var, int value, const int defvalue = 0);
|
||||
bool EntryBitBool(const wxString& var, bool value, const bool defvalue = false);
|
||||
int EntryBitfield(const wxString& var, int value, const int defvalue = 0);
|
||||
|
||||
void Entry(const wxString &var, double& value, const double defvalue = 0.0) override;
|
||||
void Entry(const wxString& var, double& value, const double defvalue = 0.0) override;
|
||||
|
||||
void Entry(const wxString &var, wxPoint &value, const wxPoint defvalue = wxDefaultPosition);
|
||||
void Entry(const wxString &var, wxSize &value, const wxSize defvalue = wxDefaultSize);
|
||||
void Entry(const wxString &var, wxRect &value, const wxRect defvalue = wxDefaultRect);
|
||||
void Entry(const wxString& var, wxPoint& value, const wxPoint defvalue = wxDefaultPosition);
|
||||
void Entry(const wxString& var, wxSize& value, const wxSize defvalue = wxDefaultSize);
|
||||
void Entry(const wxString& var, wxRect& value, const wxRect defvalue = wxDefaultRect);
|
||||
|
||||
protected:
|
||||
void _EnumEntry(const wxString &var, int &value, const wxChar *const *enumArray, int defvalue);
|
||||
void _EnumEntry(const wxString& var, int& value, const wxChar* const* enumArray, int defvalue);
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -147,31 +147,31 @@ protected:
|
|||
class IniSaver : public IniInterface
|
||||
{
|
||||
public:
|
||||
virtual ~IniSaver() = default;
|
||||
explicit IniSaver();
|
||||
explicit IniSaver(wxConfigBase &config);
|
||||
explicit IniSaver(wxConfigBase *config);
|
||||
virtual ~IniSaver() = default;
|
||||
explicit IniSaver();
|
||||
explicit IniSaver(wxConfigBase& config);
|
||||
explicit IniSaver(wxConfigBase* config);
|
||||
|
||||
bool IsLoading() const { return false; }
|
||||
bool IsLoading() const { return false; }
|
||||
|
||||
void Entry(const wxString &var, wxString &value, const wxString defvalue = wxString());
|
||||
void Entry(const wxString &var, wxDirName &value, const wxDirName defvalue = wxDirName(), bool isAllowRelative = false);
|
||||
void Entry(const wxString &var, wxFileName &value, const wxFileName defvalue = wxFileName(), bool isAllowRelative = false);
|
||||
void Entry(const wxString &var, int &value, const int defvalue = 0);
|
||||
void Entry(const wxString &var, uint &value, const uint defvalue = 0);
|
||||
void Entry(const wxString &var, bool &value, const bool defvalue = false);
|
||||
void Entry(const wxString& var, wxString& value, const wxString defvalue = wxString());
|
||||
void Entry(const wxString& var, wxDirName& value, const wxDirName defvalue = wxDirName(), bool isAllowRelative = false);
|
||||
void Entry(const wxString& var, wxFileName& value, const wxFileName defvalue = wxFileName(), bool isAllowRelative = false);
|
||||
void Entry(const wxString& var, int& value, const int defvalue = 0);
|
||||
void Entry(const wxString& var, uint& value, const uint defvalue = 0);
|
||||
void Entry(const wxString& var, bool& value, const bool defvalue = false);
|
||||
|
||||
bool EntryBitBool(const wxString &var, bool value, const bool defvalue = false);
|
||||
int EntryBitfield(const wxString &var, int value, const int defvalue = 0);
|
||||
bool EntryBitBool(const wxString& var, bool value, const bool defvalue = false);
|
||||
int EntryBitfield(const wxString& var, int value, const int defvalue = 0);
|
||||
|
||||
void Entry(const wxString &var, double &value, const double defvalue = 0.0) override;
|
||||
void Entry(const wxString& var, double& value, const double defvalue = 0.0) override;
|
||||
|
||||
void Entry(const wxString &var, wxPoint &value, const wxPoint defvalue = wxDefaultPosition);
|
||||
void Entry(const wxString &var, wxSize &value, const wxSize defvalue = wxDefaultSize);
|
||||
void Entry(const wxString &var, wxRect &value, const wxRect defvalue = wxDefaultRect);
|
||||
void Entry(const wxString& var, wxPoint& value, const wxPoint defvalue = wxDefaultPosition);
|
||||
void Entry(const wxString& var, wxSize& value, const wxSize defvalue = wxDefaultSize);
|
||||
void Entry(const wxString& var, wxRect& value, const wxRect defvalue = wxDefaultRect);
|
||||
|
||||
protected:
|
||||
void _EnumEntry(const wxString &var, int &value, const wxChar *const *enumArray, int defvalue);
|
||||
void _EnumEntry(const wxString& var, int& value, const wxChar* const* enumArray, int defvalue);
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
|
|
@ -33,195 +33,198 @@ extern void SignalExit(int sig);
|
|||
static const uptr m_pagemask = getpagesize() - 1;
|
||||
|
||||
// Linux implementation of SIGSEGV handler. Bind it using sigaction().
|
||||
static void SysPageFaultSignalFilter(int signal, siginfo_t *siginfo, void *)
|
||||
static void SysPageFaultSignalFilter(int signal, siginfo_t* siginfo, void*)
|
||||
{
|
||||
// [TODO] : Add a thread ID filter to the Linux Signal handler here.
|
||||
// Rationale: On windows, the __try/__except model allows per-thread specific behavior
|
||||
// for page fault handling. On linux, there is a single signal handler for the whole
|
||||
// process, but the handler is executed by the thread that caused the exception.
|
||||
// [TODO] : Add a thread ID filter to the Linux Signal handler here.
|
||||
// Rationale: On windows, the __try/__except model allows per-thread specific behavior
|
||||
// for page fault handling. On linux, there is a single signal handler for the whole
|
||||
// process, but the handler is executed by the thread that caused the exception.
|
||||
|
||||
|
||||
// Stdio Usage note: SIGSEGV handling is a synchronous in-thread signal. It is done
|
||||
// from the context of the current thread and stackframe. So long as the thread is not
|
||||
// the main/ui thread, use of the px assertion system should be safe. Use of stdio should
|
||||
// be safe even on the main thread.
|
||||
// (in other words, stdio limitations only really apply to process-level asynchronous
|
||||
// signals)
|
||||
// Stdio Usage note: SIGSEGV handling is a synchronous in-thread signal. It is done
|
||||
// from the context of the current thread and stackframe. So long as the thread is not
|
||||
// the main/ui thread, use of the px assertion system should be safe. Use of stdio should
|
||||
// be safe even on the main thread.
|
||||
// (in other words, stdio limitations only really apply to process-level asynchronous
|
||||
// signals)
|
||||
|
||||
// Note: Use of stdio functions isn't safe here. Avoid console logs,
|
||||
// assertions, file logs, or just about anything else useful.
|
||||
// Note: Use of stdio functions isn't safe here. Avoid console logs,
|
||||
// assertions, file logs, or just about anything else useful.
|
||||
|
||||
|
||||
// Note: This signal can be accessed by the EE or MTVU thread
|
||||
// Source_PageFault is a global variable with its own state information
|
||||
// so for now we lock this exception code unless someone can fix this better...
|
||||
Threading::ScopedLock lock(PageFault_Mutex);
|
||||
// Note: This signal can be accessed by the EE or MTVU thread
|
||||
// Source_PageFault is a global variable with its own state information
|
||||
// so for now we lock this exception code unless someone can fix this better...
|
||||
Threading::ScopedLock lock(PageFault_Mutex);
|
||||
|
||||
Source_PageFault->Dispatch(PageFaultInfo((uptr)siginfo->si_addr & ~m_pagemask));
|
||||
Source_PageFault->Dispatch(PageFaultInfo((uptr)siginfo->si_addr & ~m_pagemask));
|
||||
|
||||
// resumes execution right where we left off (re-executes instruction that
|
||||
// caused the SIGSEGV).
|
||||
if (Source_PageFault->WasHandled())
|
||||
return;
|
||||
// resumes execution right where we left off (re-executes instruction that
|
||||
// caused the SIGSEGV).
|
||||
if (Source_PageFault->WasHandled())
|
||||
return;
|
||||
|
||||
if (!wxThread::IsMain()) {
|
||||
pxFailRel(pxsFmt("Unhandled page fault @ 0x%08x", siginfo->si_addr));
|
||||
}
|
||||
if (!wxThread::IsMain())
|
||||
{
|
||||
pxFailRel(pxsFmt("Unhandled page fault @ 0x%08x", siginfo->si_addr));
|
||||
}
|
||||
|
||||
// Bad mojo! Completely invalid address.
|
||||
// Instigate a trap if we're in a debugger, and if not then do a SIGKILL.
|
||||
// Bad mojo! Completely invalid address.
|
||||
// Instigate a trap if we're in a debugger, and if not then do a SIGKILL.
|
||||
|
||||
pxTrap();
|
||||
if (!IsDebugBuild)
|
||||
raise(SIGKILL);
|
||||
pxTrap();
|
||||
if (!IsDebugBuild)
|
||||
raise(SIGKILL);
|
||||
}
|
||||
|
||||
void _platform_InstallSignalHandler()
|
||||
{
|
||||
Console.WriteLn("Installing POSIX SIGSEGV handler...");
|
||||
struct sigaction sa;
|
||||
Console.WriteLn("Installing POSIX SIGSEGV handler...");
|
||||
struct sigaction sa;
|
||||
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_SIGINFO;
|
||||
sa.sa_sigaction = SysPageFaultSignalFilter;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_SIGINFO;
|
||||
sa.sa_sigaction = SysPageFaultSignalFilter;
|
||||
#ifdef __APPLE__
|
||||
// MacOS uses SIGBUS for memory permission violations
|
||||
sigaction(SIGBUS, &sa, NULL);
|
||||
// MacOS uses SIGBUS for memory permission violations
|
||||
sigaction(SIGBUS, &sa, NULL);
|
||||
#else
|
||||
sigaction(SIGSEGV, &sa, NULL);
|
||||
sigaction(SIGSEGV, &sa, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
static __ri void PageSizeAssertionTest(size_t size)
|
||||
{
|
||||
pxAssertMsg((__pagesize == getpagesize()), pxsFmt(
|
||||
"Internal system error: Operating system pagesize does not match compiled pagesize.\n\t"
|
||||
L"\tOS Page Size: 0x%x (%d), Compiled Page Size: 0x%x (%u)",
|
||||
getpagesize(), getpagesize(), __pagesize, __pagesize));
|
||||
pxAssertMsg((__pagesize == getpagesize()), pxsFmt(
|
||||
"Internal system error: Operating system pagesize does not match compiled pagesize.\n\t"
|
||||
L"\tOS Page Size: 0x%x (%d), Compiled Page Size: 0x%x (%u)",
|
||||
getpagesize(), getpagesize(), __pagesize, __pagesize));
|
||||
|
||||
pxAssertDev((size & (__pagesize - 1)) == 0, pxsFmt(
|
||||
L"Memory block size must be a multiple of the target platform's page size.\n"
|
||||
L"\tPage Size: 0x%x (%u), Block Size: 0x%x (%u)",
|
||||
__pagesize, __pagesize, size, size));
|
||||
pxAssertDev((size & (__pagesize - 1)) == 0, pxsFmt(
|
||||
L"Memory block size must be a multiple of the target platform's page size.\n"
|
||||
L"\tPage Size: 0x%x (%u), Block Size: 0x%x (%u)",
|
||||
__pagesize, __pagesize, size, size));
|
||||
}
|
||||
|
||||
// returns FALSE if the mprotect call fails with an ENOMEM.
|
||||
// Raises assertions on other types of POSIX errors (since those typically reflect invalid object
|
||||
// or memory states).
|
||||
static bool _memprotect(void *baseaddr, size_t size, const PageProtectionMode &mode)
|
||||
static bool _memprotect(void* baseaddr, size_t size, const PageProtectionMode& mode)
|
||||
{
|
||||
PageSizeAssertionTest(size);
|
||||
PageSizeAssertionTest(size);
|
||||
|
||||
uint lnxmode = 0;
|
||||
uint lnxmode = 0;
|
||||
|
||||
if (mode.CanWrite())
|
||||
lnxmode |= PROT_WRITE;
|
||||
if (mode.CanRead())
|
||||
lnxmode |= PROT_READ;
|
||||
if (mode.CanExecute())
|
||||
lnxmode |= PROT_EXEC | PROT_READ;
|
||||
if (mode.CanWrite())
|
||||
lnxmode |= PROT_WRITE;
|
||||
if (mode.CanRead())
|
||||
lnxmode |= PROT_READ;
|
||||
if (mode.CanExecute())
|
||||
lnxmode |= PROT_EXEC | PROT_READ;
|
||||
|
||||
const int result = mprotect(baseaddr, size, lnxmode);
|
||||
const int result = mprotect(baseaddr, size, lnxmode);
|
||||
|
||||
if (result == 0)
|
||||
return true;
|
||||
if (result == 0)
|
||||
return true;
|
||||
|
||||
switch (errno) {
|
||||
case EINVAL:
|
||||
pxFailDev(pxsFmt(L"mprotect returned EINVAL @ 0x%08X -> 0x%08X (mode=%s)",
|
||||
baseaddr, (uptr)baseaddr + size, WX_STR(mode.ToString())));
|
||||
break;
|
||||
switch (errno)
|
||||
{
|
||||
case EINVAL:
|
||||
pxFailDev(pxsFmt(L"mprotect returned EINVAL @ 0x%08X -> 0x%08X (mode=%s)",
|
||||
baseaddr, (uptr)baseaddr + size, WX_STR(mode.ToString())));
|
||||
break;
|
||||
|
||||
case EACCES:
|
||||
pxFailDev(pxsFmt(L"mprotect returned EACCES @ 0x%08X -> 0x%08X (mode=%s)",
|
||||
baseaddr, (uptr)baseaddr + size, WX_STR(mode.ToString())));
|
||||
break;
|
||||
case EACCES:
|
||||
pxFailDev(pxsFmt(L"mprotect returned EACCES @ 0x%08X -> 0x%08X (mode=%s)",
|
||||
baseaddr, (uptr)baseaddr + size, WX_STR(mode.ToString())));
|
||||
break;
|
||||
|
||||
case ENOMEM:
|
||||
// caller handles assertion or exception, or whatever.
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
case ENOMEM:
|
||||
// caller handles assertion or exception, or whatever.
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void *HostSys::MmapReservePtr(void *base, size_t size)
|
||||
void* HostSys::MmapReservePtr(void* base, size_t size)
|
||||
{
|
||||
PageSizeAssertionTest(size);
|
||||
PageSizeAssertionTest(size);
|
||||
|
||||
// On linux a reserve-without-commit is performed by using mmap on a read-only
|
||||
// or anonymous source, with PROT_NONE (no-access) permission. Since the mapping
|
||||
// is completely inaccessible, the OS will simply reserve it and will not put it
|
||||
// against the commit table.
|
||||
return mmap(base, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
// On linux a reserve-without-commit is performed by using mmap on a read-only
|
||||
// or anonymous source, with PROT_NONE (no-access) permission. Since the mapping
|
||||
// is completely inaccessible, the OS will simply reserve it and will not put it
|
||||
// against the commit table.
|
||||
return mmap(base, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
}
|
||||
|
||||
bool HostSys::MmapCommitPtr(void *base, size_t size, const PageProtectionMode &mode)
|
||||
bool HostSys::MmapCommitPtr(void* base, size_t size, const PageProtectionMode& mode)
|
||||
{
|
||||
// In linux, reserved memory is automatically committed when its permissions are
|
||||
// changed to something other than PROT_NONE. If the user is committing memory
|
||||
// as PROT_NONE, then just ignore this call (memory will be committed automatically
|
||||
// later when the user changes permissions to something useful via calls to MemProtect).
|
||||
// In linux, reserved memory is automatically committed when its permissions are
|
||||
// changed to something other than PROT_NONE. If the user is committing memory
|
||||
// as PROT_NONE, then just ignore this call (memory will be committed automatically
|
||||
// later when the user changes permissions to something useful via calls to MemProtect).
|
||||
|
||||
if (mode.IsNone())
|
||||
return false;
|
||||
if (mode.IsNone())
|
||||
return false;
|
||||
|
||||
if (_memprotect(base, size, mode))
|
||||
return true;
|
||||
if (_memprotect(base, size, mode))
|
||||
return true;
|
||||
|
||||
if (!pxDoOutOfMemory)
|
||||
return false;
|
||||
pxDoOutOfMemory(size);
|
||||
return _memprotect(base, size, mode);
|
||||
if (!pxDoOutOfMemory)
|
||||
return false;
|
||||
pxDoOutOfMemory(size);
|
||||
return _memprotect(base, size, mode);
|
||||
}
|
||||
|
||||
void HostSys::MmapResetPtr(void *base, size_t size)
|
||||
void HostSys::MmapResetPtr(void* base, size_t size)
|
||||
{
|
||||
PageSizeAssertionTest(size);
|
||||
PageSizeAssertionTest(size);
|
||||
|
||||
void *result = mmap(base, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
|
||||
void* result = mmap(base, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
|
||||
|
||||
pxAssertRel((uptr)result == (uptr)base, pxsFmt(
|
||||
"Virtual memory decommit failed: memory at 0x%08X -> 0x%08X could not be remapped.",
|
||||
base, (uptr)base + size));
|
||||
pxAssertRel((uptr)result == (uptr)base, pxsFmt(
|
||||
"Virtual memory decommit failed: memory at 0x%08X -> 0x%08X could not be remapped.",
|
||||
base, (uptr)base + size));
|
||||
}
|
||||
|
||||
void *HostSys::MmapReserve(uptr base, size_t size)
|
||||
void* HostSys::MmapReserve(uptr base, size_t size)
|
||||
{
|
||||
return MmapReservePtr((void *)base, size);
|
||||
return MmapReservePtr((void*)base, size);
|
||||
}
|
||||
|
||||
bool HostSys::MmapCommit(uptr base, size_t size, const PageProtectionMode &mode)
|
||||
bool HostSys::MmapCommit(uptr base, size_t size, const PageProtectionMode& mode)
|
||||
{
|
||||
return MmapCommitPtr((void *)base, size, mode);
|
||||
return MmapCommitPtr((void*)base, size, mode);
|
||||
}
|
||||
|
||||
void HostSys::MmapReset(uptr base, size_t size)
|
||||
{
|
||||
MmapResetPtr((void *)base, size);
|
||||
MmapResetPtr((void*)base, size);
|
||||
}
|
||||
|
||||
void *HostSys::Mmap(uptr base, size_t size)
|
||||
void* HostSys::Mmap(uptr base, size_t size)
|
||||
{
|
||||
PageSizeAssertionTest(size);
|
||||
PageSizeAssertionTest(size);
|
||||
|
||||
// MAP_ANONYMOUS - means we have no associated file handle (or device).
|
||||
// MAP_ANONYMOUS - means we have no associated file handle (or device).
|
||||
|
||||
return mmap((void *)base, size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
return mmap((void*)base, size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
}
|
||||
|
||||
void HostSys::Munmap(uptr base, size_t size)
|
||||
{
|
||||
if (!base)
|
||||
return;
|
||||
munmap((void *)base, size);
|
||||
if (!base)
|
||||
return;
|
||||
munmap((void*)base, size);
|
||||
}
|
||||
|
||||
void HostSys::MemProtect(void *baseaddr, size_t size, const PageProtectionMode &mode)
|
||||
void HostSys::MemProtect(void* baseaddr, size_t size, const PageProtectionMode& mode)
|
||||
{
|
||||
if (!_memprotect(baseaddr, size, mode)) {
|
||||
throw Exception::OutOfMemory(L"MemProtect")
|
||||
.SetDiagMsg(pxsFmt(L"mprotect failed @ 0x%08X -> 0x%08X (mode=%s)",
|
||||
baseaddr, (uptr)baseaddr + size, WX_STR(mode.ToString())));
|
||||
}
|
||||
if (!_memprotect(baseaddr, size, mode))
|
||||
{
|
||||
throw Exception::OutOfMemory(L"MemProtect")
|
||||
.SetDiagMsg(pxsFmt(L"mprotect failed @ 0x%08X -> 0x%08X (mode=%s)",
|
||||
baseaddr, (uptr)baseaddr + size, WX_STR(mode.ToString())));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -39,21 +39,21 @@
|
|||
|
||||
__forceinline void Threading::Sleep(int ms)
|
||||
{
|
||||
usleep(1000 * ms);
|
||||
usleep(1000 * ms);
|
||||
}
|
||||
|
||||
// For use in spin/wait loops, Acts as a hint to Intel CPUs and should, in theory
|
||||
// improve performance and reduce cpu power consumption.
|
||||
__forceinline void Threading::SpinWait()
|
||||
{
|
||||
// If this doesn't compile you can just comment it out (it only serves as a
|
||||
// performance hint and isn't required).
|
||||
__asm__("pause");
|
||||
// If this doesn't compile you can just comment it out (it only serves as a
|
||||
// performance hint and isn't required).
|
||||
__asm__("pause");
|
||||
}
|
||||
|
||||
__forceinline void Threading::EnableHiresScheduler()
|
||||
{
|
||||
// Don't know if linux has a customizable scheduler resolution like Windows (doubtful)
|
||||
// Don't know if linux has a customizable scheduler resolution like Windows (doubtful)
|
||||
}
|
||||
|
||||
__forceinline void Threading::DisableHiresScheduler()
|
||||
|
@ -63,69 +63,72 @@ __forceinline void Threading::DisableHiresScheduler()
|
|||
// Unit of time of GetThreadCpuTime/GetCpuTime
|
||||
u64 Threading::GetThreadTicksPerSecond()
|
||||
{
|
||||
return 1000000;
|
||||
return 1000000;
|
||||
}
|
||||
|
||||
// Helper function to get either either the current cpu usage
|
||||
// in called thread or in id thread
|
||||
static u64 get_thread_time(uptr id = 0)
|
||||
{
|
||||
clockid_t cid;
|
||||
if (id) {
|
||||
int err = pthread_getcpuclockid((pthread_t)id, &cid);
|
||||
if (err)
|
||||
return 0;
|
||||
} else {
|
||||
cid = CLOCK_THREAD_CPUTIME_ID;
|
||||
}
|
||||
clockid_t cid;
|
||||
if (id)
|
||||
{
|
||||
int err = pthread_getcpuclockid((pthread_t)id, &cid);
|
||||
if (err)
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
cid = CLOCK_THREAD_CPUTIME_ID;
|
||||
}
|
||||
|
||||
struct timespec ts;
|
||||
int err = clock_gettime(cid, &ts);
|
||||
if (err)
|
||||
return 0;
|
||||
struct timespec ts;
|
||||
int err = clock_gettime(cid, &ts);
|
||||
if (err)
|
||||
return 0;
|
||||
|
||||
return (u64)ts.tv_sec * (u64)1e6 + (u64)ts.tv_nsec / (u64)1e3;
|
||||
return (u64)ts.tv_sec * (u64)1e6 + (u64)ts.tv_nsec / (u64)1e3;
|
||||
}
|
||||
|
||||
// Returns the current timestamp (not relative to a real world clock)
|
||||
u64 Threading::GetThreadCpuTime()
|
||||
{
|
||||
return get_thread_time();
|
||||
return get_thread_time();
|
||||
}
|
||||
|
||||
u64 Threading::pxThread::GetCpuTime() const
|
||||
{
|
||||
// Get the cpu time for the thread belonging to this object. Use m_native_id and/or
|
||||
// m_native_handle to implement it. Return value should be a measure of total time the
|
||||
// thread has used on the CPU (scaled by the value returned by GetThreadTicksPerSecond(),
|
||||
// which typically would be an OS-provided scalar or some sort).
|
||||
// Get the cpu time for the thread belonging to this object. Use m_native_id and/or
|
||||
// m_native_handle to implement it. Return value should be a measure of total time the
|
||||
// thread has used on the CPU (scaled by the value returned by GetThreadTicksPerSecond(),
|
||||
// which typically would be an OS-provided scalar or some sort).
|
||||
|
||||
if (!m_native_id)
|
||||
return 0;
|
||||
if (!m_native_id)
|
||||
return 0;
|
||||
|
||||
return get_thread_time(m_native_id);
|
||||
return get_thread_time(m_native_id);
|
||||
}
|
||||
|
||||
void Threading::pxThread::_platform_specific_OnStartInThread()
|
||||
{
|
||||
// Obtain linux-specific thread IDs or Handles here, which can be used to query
|
||||
// kernel scheduler performance information.
|
||||
m_native_id = (uptr)pthread_self();
|
||||
// Obtain linux-specific thread IDs or Handles here, which can be used to query
|
||||
// kernel scheduler performance information.
|
||||
m_native_id = (uptr)pthread_self();
|
||||
}
|
||||
|
||||
void Threading::pxThread::_platform_specific_OnCleanupInThread()
|
||||
{
|
||||
// Cleanup handles here, which were opened above.
|
||||
// Cleanup handles here, which were opened above.
|
||||
}
|
||||
|
||||
void Threading::SetNameOfCurrentThread(const char *name)
|
||||
void Threading::SetNameOfCurrentThread(const char* name)
|
||||
{
|
||||
#if defined(__linux__)
|
||||
// Extract of manpage: "The name can be up to 16 bytes long, and should be
|
||||
// null-terminated if it contains fewer bytes."
|
||||
prctl(PR_SET_NAME, name, 0, 0, 0);
|
||||
// Extract of manpage: "The name can be up to 16 bytes long, and should be
|
||||
// null-terminated if it contains fewer bytes."
|
||||
prctl(PR_SET_NAME, name, 0, 0, 0);
|
||||
#elif defined(__unix__)
|
||||
pthread_set_name_np(pthread_self(), name);
|
||||
pthread_set_name_np(pthread_self(), name);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -22,20 +22,20 @@
|
|||
// On GCC >= 4.7, this is equivalent to __builtin_clrsb(n);
|
||||
inline u32 count_leading_sign_bits(s32 n)
|
||||
{
|
||||
// If the sign bit is 1, we invert the bits to 0 for count-leading-zero.
|
||||
if (n < 0)
|
||||
n = ~n;
|
||||
// If the sign bit is 1, we invert the bits to 0 for count-leading-zero.
|
||||
if (n < 0)
|
||||
n = ~n;
|
||||
|
||||
// If BSR is used directly, it would have an undefined value for 0.
|
||||
if (n == 0)
|
||||
return 32;
|
||||
// If BSR is used directly, it would have an undefined value for 0.
|
||||
if (n == 0)
|
||||
return 32;
|
||||
|
||||
// Perform our count leading zero.
|
||||
#ifdef _MSC_VER
|
||||
unsigned long ret;
|
||||
_BitScanReverse(&ret, n);
|
||||
return 31 - (u32)ret;
|
||||
unsigned long ret;
|
||||
_BitScanReverse(&ret, n);
|
||||
return 31 - (u32)ret;
|
||||
#else
|
||||
return __builtin_clz(n);
|
||||
return __builtin_clz(n);
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
// For 32-bit MSVC compiles, memcmp performs much worse than memcmp_mmx and
|
||||
// other implementations. So for this combination only, prefer memcmp_mmx
|
||||
#if defined(_MSC_VER) && !defined(_M_X86_64)
|
||||
extern u8 memcmp_mmx(const void *src1, const void *src2, int cmpsize);
|
||||
extern u8 memcmp_mmx(const void* src1, const void* src2, int cmpsize);
|
||||
#else
|
||||
#define memcmp_mmx memcmp
|
||||
#endif
|
||||
|
@ -31,14 +31,14 @@ extern u8 memcmp_mmx(const void *src1, const void *src2, int cmpsize);
|
|||
// Structures, static arrays, etc. No need to include sizeof() crap, this does it automatically
|
||||
// for you!
|
||||
template <typename T>
|
||||
static __fi void memzero(T &object)
|
||||
static __fi void memzero(T& object)
|
||||
{
|
||||
memset(&object, 0, sizeof(T));
|
||||
memset(&object, 0, sizeof(T));
|
||||
}
|
||||
|
||||
// This method clears an object with the given 8 bit value.
|
||||
template <u8 data, typename T>
|
||||
static __fi void memset8(T &object)
|
||||
static __fi void memset8(T& object)
|
||||
{
|
||||
memset(&object, data, sizeof(T));
|
||||
memset(&object, data, sizeof(T));
|
||||
}
|
||||
|
|
|
@ -18,74 +18,78 @@
|
|||
#include <xmmintrin.h>
|
||||
|
||||
template <u8 data>
|
||||
__noinline void memset_sse_a(void *dest, const size_t size)
|
||||
__noinline void memset_sse_a(void* dest, const size_t size)
|
||||
{
|
||||
const uint MZFqwc = size / 16;
|
||||
const uint MZFqwc = size / 16;
|
||||
|
||||
pxAssert((size & 0xf) == 0);
|
||||
pxAssert((size & 0xf) == 0);
|
||||
|
||||
__m128 srcreg;
|
||||
__m128 srcreg;
|
||||
|
||||
if (data != 0) {
|
||||
static __aligned16 const u8 loadval[8] = {data, data, data, data, data, data, data, data};
|
||||
srcreg = _mm_loadh_pi(_mm_load_ps((float *)loadval), (__m64 *)loadval);
|
||||
} else
|
||||
srcreg = _mm_setzero_ps();
|
||||
if (data != 0)
|
||||
{
|
||||
static __aligned16 const u8 loadval[8] = {data, data, data, data, data, data, data, data};
|
||||
srcreg = _mm_loadh_pi(_mm_load_ps((float*)loadval), (__m64*)loadval);
|
||||
}
|
||||
else
|
||||
srcreg = _mm_setzero_ps();
|
||||
|
||||
float(*destxmm)[4] = (float(*)[4])dest;
|
||||
float(*destxmm)[4] = (float(*)[4])dest;
|
||||
|
||||
switch (MZFqwc & 0x07) {
|
||||
case 0x07:
|
||||
_mm_store_ps(&destxmm[0x07 - 1][0], srcreg);
|
||||
// Fall through
|
||||
case 0x06:
|
||||
_mm_store_ps(&destxmm[0x06 - 1][0], srcreg);
|
||||
// Fall through
|
||||
case 0x05:
|
||||
_mm_store_ps(&destxmm[0x05 - 1][0], srcreg);
|
||||
// Fall through
|
||||
case 0x04:
|
||||
_mm_store_ps(&destxmm[0x04 - 1][0], srcreg);
|
||||
// Fall through
|
||||
case 0x03:
|
||||
_mm_store_ps(&destxmm[0x03 - 1][0], srcreg);
|
||||
// Fall through
|
||||
case 0x02:
|
||||
_mm_store_ps(&destxmm[0x02 - 1][0], srcreg);
|
||||
// Fall through
|
||||
case 0x01:
|
||||
_mm_store_ps(&destxmm[0x01 - 1][0], srcreg);
|
||||
// Fall through
|
||||
}
|
||||
switch (MZFqwc & 0x07)
|
||||
{
|
||||
case 0x07:
|
||||
_mm_store_ps(&destxmm[0x07 - 1][0], srcreg);
|
||||
// Fall through
|
||||
case 0x06:
|
||||
_mm_store_ps(&destxmm[0x06 - 1][0], srcreg);
|
||||
// Fall through
|
||||
case 0x05:
|
||||
_mm_store_ps(&destxmm[0x05 - 1][0], srcreg);
|
||||
// Fall through
|
||||
case 0x04:
|
||||
_mm_store_ps(&destxmm[0x04 - 1][0], srcreg);
|
||||
// Fall through
|
||||
case 0x03:
|
||||
_mm_store_ps(&destxmm[0x03 - 1][0], srcreg);
|
||||
// Fall through
|
||||
case 0x02:
|
||||
_mm_store_ps(&destxmm[0x02 - 1][0], srcreg);
|
||||
// Fall through
|
||||
case 0x01:
|
||||
_mm_store_ps(&destxmm[0x01 - 1][0], srcreg);
|
||||
// Fall through
|
||||
}
|
||||
|
||||
destxmm += (MZFqwc & 0x07);
|
||||
for (uint i = 0; i < MZFqwc / 8; ++i, destxmm += 8) {
|
||||
_mm_store_ps(&destxmm[0][0], srcreg);
|
||||
_mm_store_ps(&destxmm[1][0], srcreg);
|
||||
_mm_store_ps(&destxmm[2][0], srcreg);
|
||||
_mm_store_ps(&destxmm[3][0], srcreg);
|
||||
_mm_store_ps(&destxmm[4][0], srcreg);
|
||||
_mm_store_ps(&destxmm[5][0], srcreg);
|
||||
_mm_store_ps(&destxmm[6][0], srcreg);
|
||||
_mm_store_ps(&destxmm[7][0], srcreg);
|
||||
}
|
||||
destxmm += (MZFqwc & 0x07);
|
||||
for (uint i = 0; i < MZFqwc / 8; ++i, destxmm += 8)
|
||||
{
|
||||
_mm_store_ps(&destxmm[0][0], srcreg);
|
||||
_mm_store_ps(&destxmm[1][0], srcreg);
|
||||
_mm_store_ps(&destxmm[2][0], srcreg);
|
||||
_mm_store_ps(&destxmm[3][0], srcreg);
|
||||
_mm_store_ps(&destxmm[4][0], srcreg);
|
||||
_mm_store_ps(&destxmm[5][0], srcreg);
|
||||
_mm_store_ps(&destxmm[6][0], srcreg);
|
||||
_mm_store_ps(&destxmm[7][0], srcreg);
|
||||
}
|
||||
};
|
||||
|
||||
static __fi void memzero_sse_a(void *dest, const size_t size)
|
||||
static __fi void memzero_sse_a(void* dest, const size_t size)
|
||||
{
|
||||
memset_sse_a<0>(dest, size);
|
||||
memset_sse_a<0>(dest, size);
|
||||
}
|
||||
|
||||
template <u8 data, typename T>
|
||||
__noinline void memset_sse_a(T &dest)
|
||||
__noinline void memset_sse_a(T& dest)
|
||||
{
|
||||
static_assert((sizeof(dest) & 0xf) == 0, "Bad size for SSE memset");
|
||||
memset_sse_a<data>(&dest, sizeof(dest));
|
||||
static_assert((sizeof(dest) & 0xf) == 0, "Bad size for SSE memset");
|
||||
memset_sse_a<data>(&dest, sizeof(dest));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void memzero_sse_a(T &dest)
|
||||
void memzero_sse_a(T& dest)
|
||||
{
|
||||
static_assert((sizeof(dest) & 0xf) == 0, "Bad size for SSE memset");
|
||||
memset_sse_a<0>(&dest, sizeof(dest));
|
||||
static_assert((sizeof(dest) & 0xf) == 0, "Bad size for SSE memset");
|
||||
memset_sse_a<0>(&dest, sizeof(dest));
|
||||
}
|
||||
|
|
318
common/Mutex.cpp
318
common/Mutex.cpp
|
@ -20,9 +20,9 @@
|
|||
|
||||
namespace Threading
|
||||
{
|
||||
static std::atomic<int> _attr_refcount(0);
|
||||
static pthread_mutexattr_t _attr_recursive;
|
||||
}
|
||||
static std::atomic<int> _attr_refcount(0);
|
||||
static pthread_mutexattr_t _attr_recursive;
|
||||
} // namespace Threading
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Mutex Implementations
|
||||
|
@ -52,90 +52,94 @@ static pthread_mutexattr_t _attr_recursive;
|
|||
// This is an implementation that emulates pthread_mutex_timedlock() via
|
||||
// pthread_mutex_trylock().
|
||||
static int xpthread_mutex_timedlock(
|
||||
pthread_mutex_t *mutex,
|
||||
const struct timespec *abs_timeout)
|
||||
pthread_mutex_t* mutex,
|
||||
const struct timespec* abs_timeout)
|
||||
{
|
||||
int err = 0;
|
||||
int err = 0;
|
||||
|
||||
while ((err = pthread_mutex_trylock(mutex)) == EBUSY) {
|
||||
// check if the timeout has expired, gettimeofday() is implemented
|
||||
// efficiently (in userspace) on OSX
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
if (now.tv_sec > abs_timeout->tv_sec
|
||||
|| (now.tv_sec == abs_timeout->tv_sec
|
||||
&& (u64)now.tv_usec * 1000ULL > (u64)abs_timeout->tv_nsec)) {
|
||||
return ETIMEDOUT;
|
||||
}
|
||||
while ((err = pthread_mutex_trylock(mutex)) == EBUSY)
|
||||
{
|
||||
// check if the timeout has expired, gettimeofday() is implemented
|
||||
// efficiently (in userspace) on OSX
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
if (now.tv_sec > abs_timeout->tv_sec || (now.tv_sec == abs_timeout->tv_sec && (u64)now.tv_usec * 1000ULL > (u64)abs_timeout->tv_nsec))
|
||||
{
|
||||
return ETIMEDOUT;
|
||||
}
|
||||
|
||||
// acquiring lock failed, sleep some
|
||||
struct timespec ts;
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = TIMEDLOCK_EMU_SLEEP_NS;
|
||||
while (nanosleep(&ts, &ts) == -1);
|
||||
}
|
||||
// acquiring lock failed, sleep some
|
||||
struct timespec ts;
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = TIMEDLOCK_EMU_SLEEP_NS;
|
||||
while (nanosleep(&ts, &ts) == -1)
|
||||
;
|
||||
}
|
||||
|
||||
return err;
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
Threading::Mutex::Mutex()
|
||||
{
|
||||
pthread_mutex_init(&m_mutex, NULL);
|
||||
pthread_mutex_init(&m_mutex, NULL);
|
||||
}
|
||||
|
||||
static wxTimeSpan def_detach_timeout(0, 0, 6, 0);
|
||||
|
||||
void Threading::Mutex::Detach()
|
||||
{
|
||||
if (EBUSY != pthread_mutex_destroy(&m_mutex))
|
||||
return;
|
||||
if (EBUSY != pthread_mutex_destroy(&m_mutex))
|
||||
return;
|
||||
|
||||
if (IsRecursive()) {
|
||||
// Sanity check: Recursive locks could be held by our own thread, which would
|
||||
// be considered an assertion failure, but can also be handled gracefully.
|
||||
// (note: if the mutex is locked recursively more than twice then this assert won't
|
||||
// detect it)
|
||||
if (IsRecursive())
|
||||
{
|
||||
// Sanity check: Recursive locks could be held by our own thread, which would
|
||||
// be considered an assertion failure, but can also be handled gracefully.
|
||||
// (note: if the mutex is locked recursively more than twice then this assert won't
|
||||
// detect it)
|
||||
|
||||
Release();
|
||||
Release(); // in case of double recursion.
|
||||
int result = pthread_mutex_destroy(&m_mutex);
|
||||
if (pxAssertDev(result != EBUSY, "Detachment of a recursively-locked mutex (self-locked!)."))
|
||||
return;
|
||||
}
|
||||
Release();
|
||||
Release(); // in case of double recursion.
|
||||
int result = pthread_mutex_destroy(&m_mutex);
|
||||
if (pxAssertDev(result != EBUSY, "Detachment of a recursively-locked mutex (self-locked!)."))
|
||||
return;
|
||||
}
|
||||
|
||||
if (Wait(def_detach_timeout))
|
||||
pthread_mutex_destroy(&m_mutex);
|
||||
else
|
||||
Console.Error("(Thread Log) Mutex cleanup failed due to possible deadlock.");
|
||||
if (Wait(def_detach_timeout))
|
||||
pthread_mutex_destroy(&m_mutex);
|
||||
else
|
||||
Console.Error("(Thread Log) Mutex cleanup failed due to possible deadlock.");
|
||||
}
|
||||
|
||||
Threading::Mutex::~Mutex()
|
||||
{
|
||||
try {
|
||||
Mutex::Detach();
|
||||
}
|
||||
DESTRUCTOR_CATCHALL;
|
||||
try
|
||||
{
|
||||
Mutex::Detach();
|
||||
}
|
||||
DESTRUCTOR_CATCHALL;
|
||||
}
|
||||
|
||||
Threading::MutexRecursive::MutexRecursive()
|
||||
: Mutex(false)
|
||||
: Mutex(false)
|
||||
{
|
||||
if (++_attr_refcount == 1) {
|
||||
if (0 != pthread_mutexattr_init(&_attr_recursive))
|
||||
throw Exception::OutOfMemory(L"Recursive mutexing attributes");
|
||||
if (++_attr_refcount == 1)
|
||||
{
|
||||
if (0 != pthread_mutexattr_init(&_attr_recursive))
|
||||
throw Exception::OutOfMemory(L"Recursive mutexing attributes");
|
||||
|
||||
pthread_mutexattr_settype(&_attr_recursive, PTHREAD_MUTEX_RECURSIVE);
|
||||
}
|
||||
pthread_mutexattr_settype(&_attr_recursive, PTHREAD_MUTEX_RECURSIVE);
|
||||
}
|
||||
|
||||
if (pthread_mutex_init(&m_mutex, &_attr_recursive))
|
||||
Console.Error("(Thread Log) Failed to initialize mutex.");
|
||||
if (pthread_mutex_init(&m_mutex, &_attr_recursive))
|
||||
Console.Error("(Thread Log) Failed to initialize mutex.");
|
||||
}
|
||||
|
||||
Threading::MutexRecursive::~MutexRecursive()
|
||||
{
|
||||
if (--_attr_refcount == 0)
|
||||
pthread_mutexattr_destroy(&_attr_recursive);
|
||||
if (--_attr_refcount == 0)
|
||||
pthread_mutexattr_destroy(&_attr_recursive);
|
||||
}
|
||||
|
||||
// This is a bit of a hackish function, which is technically unsafe, but can be useful for allowing
|
||||
|
@ -144,8 +148,8 @@ Threading::MutexRecursive::~MutexRecursive()
|
|||
// the deeper meanings of the universe for eternity.
|
||||
void Threading::Mutex::Recreate()
|
||||
{
|
||||
Detach();
|
||||
pthread_mutex_init(&m_mutex, NULL);
|
||||
Detach();
|
||||
pthread_mutex_init(&m_mutex, NULL);
|
||||
}
|
||||
|
||||
// Returns:
|
||||
|
@ -153,11 +157,12 @@ void Threading::Mutex::Recreate()
|
|||
// unlocked.
|
||||
bool Threading::Mutex::RecreateIfLocked()
|
||||
{
|
||||
if (!Wait(def_detach_timeout)) {
|
||||
Recreate();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
if (!Wait(def_detach_timeout))
|
||||
{
|
||||
Recreate();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -167,25 +172,25 @@ bool Threading::Mutex::RecreateIfLocked()
|
|||
// other than the main thread.
|
||||
void Threading::Mutex::AcquireWithoutYield()
|
||||
{
|
||||
pxAssertMsg(!wxThread::IsMain(), "Unyielding mutex acquire issued from the main/gui thread. Please use Acquire() instead.");
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
pxAssertMsg(!wxThread::IsMain(), "Unyielding mutex acquire issued from the main/gui thread. Please use Acquire() instead.");
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
}
|
||||
|
||||
bool Threading::Mutex::AcquireWithoutYield(const wxTimeSpan &timeout)
|
||||
bool Threading::Mutex::AcquireWithoutYield(const wxTimeSpan& timeout)
|
||||
{
|
||||
wxDateTime megafail(wxDateTime::UNow() + timeout);
|
||||
const timespec fail = {megafail.GetTicks(), megafail.GetMillisecond() * 1000000};
|
||||
return xpthread_mutex_timedlock(&m_mutex, &fail) == 0;
|
||||
wxDateTime megafail(wxDateTime::UNow() + timeout);
|
||||
const timespec fail = {megafail.GetTicks(), megafail.GetMillisecond() * 1000000};
|
||||
return xpthread_mutex_timedlock(&m_mutex, &fail) == 0;
|
||||
}
|
||||
|
||||
void Threading::Mutex::Release()
|
||||
{
|
||||
pthread_mutex_unlock(&m_mutex);
|
||||
pthread_mutex_unlock(&m_mutex);
|
||||
}
|
||||
|
||||
bool Threading::Mutex::TryAcquire()
|
||||
{
|
||||
return EBUSY != pthread_mutex_trylock(&m_mutex);
|
||||
return EBUSY != pthread_mutex_trylock(&m_mutex);
|
||||
}
|
||||
|
||||
// This is a wxApp-safe rendition of AcquireWithoutYield, which makes sure to execute pending app events
|
||||
|
@ -194,45 +199,56 @@ bool Threading::Mutex::TryAcquire()
|
|||
void Threading::Mutex::Acquire()
|
||||
{
|
||||
#if wxUSE_GUI
|
||||
if (!wxThread::IsMain() || (wxTheApp == NULL)) {
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
} else if (_WaitGui_RecursionGuard(L"Mutex::Acquire")) {
|
||||
ScopedBusyCursor hourglass(Cursor_ReallyBusy);
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
} else {
|
||||
//ScopedBusyCursor hourglass( Cursor_KindaBusy );
|
||||
while (!AcquireWithoutYield(def_yieldgui_interval))
|
||||
YieldToMain();
|
||||
}
|
||||
if (!wxThread::IsMain() || (wxTheApp == NULL))
|
||||
{
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
}
|
||||
else if (_WaitGui_RecursionGuard(L"Mutex::Acquire"))
|
||||
{
|
||||
ScopedBusyCursor hourglass(Cursor_ReallyBusy);
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
}
|
||||
else
|
||||
{
|
||||
//ScopedBusyCursor hourglass( Cursor_KindaBusy );
|
||||
while (!AcquireWithoutYield(def_yieldgui_interval))
|
||||
YieldToMain();
|
||||
}
|
||||
#else
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Threading::Mutex::Acquire(const wxTimeSpan &timeout)
|
||||
bool Threading::Mutex::Acquire(const wxTimeSpan& timeout)
|
||||
{
|
||||
#if wxUSE_GUI
|
||||
if (!wxThread::IsMain() || (wxTheApp == NULL)) {
|
||||
return AcquireWithoutYield(timeout);
|
||||
} else if (_WaitGui_RecursionGuard(L"Mutex::TimedAcquire")) {
|
||||
ScopedBusyCursor hourglass(Cursor_ReallyBusy);
|
||||
return AcquireWithoutYield(timeout);
|
||||
} else {
|
||||
//ScopedBusyCursor hourglass( Cursor_KindaBusy );
|
||||
wxTimeSpan countdown((timeout));
|
||||
if (!wxThread::IsMain() || (wxTheApp == NULL))
|
||||
{
|
||||
return AcquireWithoutYield(timeout);
|
||||
}
|
||||
else if (_WaitGui_RecursionGuard(L"Mutex::TimedAcquire"))
|
||||
{
|
||||
ScopedBusyCursor hourglass(Cursor_ReallyBusy);
|
||||
return AcquireWithoutYield(timeout);
|
||||
}
|
||||
else
|
||||
{
|
||||
//ScopedBusyCursor hourglass( Cursor_KindaBusy );
|
||||
wxTimeSpan countdown((timeout));
|
||||
|
||||
do {
|
||||
if (AcquireWithoutYield(def_yieldgui_interval))
|
||||
break;
|
||||
YieldToMain();
|
||||
countdown -= def_yieldgui_interval;
|
||||
} while (countdown.GetMilliseconds() > 0);
|
||||
do
|
||||
{
|
||||
if (AcquireWithoutYield(def_yieldgui_interval))
|
||||
break;
|
||||
YieldToMain();
|
||||
countdown -= def_yieldgui_interval;
|
||||
} while (countdown.GetMilliseconds() > 0);
|
||||
|
||||
return countdown.GetMilliseconds() > 0;
|
||||
}
|
||||
return countdown.GetMilliseconds() > 0;
|
||||
}
|
||||
|
||||
#else
|
||||
return AcquireWithoutYield();
|
||||
return AcquireWithoutYield();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -245,14 +261,14 @@ bool Threading::Mutex::Acquire(const wxTimeSpan &timeout)
|
|||
//
|
||||
void Threading::Mutex::Wait()
|
||||
{
|
||||
Acquire();
|
||||
Release();
|
||||
Acquire();
|
||||
Release();
|
||||
}
|
||||
|
||||
void Threading::Mutex::WaitWithoutYield()
|
||||
{
|
||||
AcquireWithoutYield();
|
||||
Release();
|
||||
AcquireWithoutYield();
|
||||
Release();
|
||||
}
|
||||
|
||||
// Performs a wait on a locked mutex, or returns instantly if the mutex is unlocked.
|
||||
|
@ -262,22 +278,24 @@ void Threading::Mutex::WaitWithoutYield()
|
|||
// true if the mutex was freed and is in an unlocked state; or false if the wait timed out
|
||||
// and the mutex is still locked by another thread.
|
||||
//
|
||||
bool Threading::Mutex::Wait(const wxTimeSpan &timeout)
|
||||
bool Threading::Mutex::Wait(const wxTimeSpan& timeout)
|
||||
{
|
||||
if (Acquire(timeout)) {
|
||||
Release();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
if (Acquire(timeout))
|
||||
{
|
||||
Release();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Threading::Mutex::WaitWithoutYield(const wxTimeSpan &timeout)
|
||||
bool Threading::Mutex::WaitWithoutYield(const wxTimeSpan& timeout)
|
||||
{
|
||||
if (AcquireWithoutYield(timeout)) {
|
||||
Release();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
if (AcquireWithoutYield(timeout))
|
||||
{
|
||||
Release();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -286,72 +304,72 @@ bool Threading::Mutex::WaitWithoutYield(const wxTimeSpan &timeout)
|
|||
|
||||
Threading::ScopedLock::~ScopedLock()
|
||||
{
|
||||
if (m_IsLocked && m_lock)
|
||||
m_lock->Release();
|
||||
if (m_IsLocked && m_lock)
|
||||
m_lock->Release();
|
||||
}
|
||||
|
||||
Threading::ScopedLock::ScopedLock(const Mutex *locker)
|
||||
Threading::ScopedLock::ScopedLock(const Mutex* locker)
|
||||
{
|
||||
m_IsLocked = false;
|
||||
AssignAndLock(locker);
|
||||
m_IsLocked = false;
|
||||
AssignAndLock(locker);
|
||||
}
|
||||
|
||||
Threading::ScopedLock::ScopedLock(const Mutex &locker)
|
||||
Threading::ScopedLock::ScopedLock(const Mutex& locker)
|
||||
{
|
||||
m_IsLocked = false;
|
||||
AssignAndLock(locker);
|
||||
m_IsLocked = false;
|
||||
AssignAndLock(locker);
|
||||
}
|
||||
|
||||
void Threading::ScopedLock::AssignAndLock(const Mutex &locker)
|
||||
void Threading::ScopedLock::AssignAndLock(const Mutex& locker)
|
||||
{
|
||||
AssignAndLock(&locker);
|
||||
AssignAndLock(&locker);
|
||||
}
|
||||
|
||||
void Threading::ScopedLock::AssignAndLock(const Mutex *locker)
|
||||
void Threading::ScopedLock::AssignAndLock(const Mutex* locker)
|
||||
{
|
||||
pxAssert(!m_IsLocked); // if we're already locked, changing the lock is bad mojo.
|
||||
pxAssert(!m_IsLocked); // if we're already locked, changing the lock is bad mojo.
|
||||
|
||||
m_lock = const_cast<Mutex *>(locker);
|
||||
if (!m_lock)
|
||||
return;
|
||||
m_lock = const_cast<Mutex*>(locker);
|
||||
if (!m_lock)
|
||||
return;
|
||||
|
||||
m_IsLocked = true;
|
||||
m_lock->Acquire();
|
||||
m_IsLocked = true;
|
||||
m_lock->Acquire();
|
||||
}
|
||||
|
||||
void Threading::ScopedLock::Assign(const Mutex &locker)
|
||||
void Threading::ScopedLock::Assign(const Mutex& locker)
|
||||
{
|
||||
m_lock = const_cast<Mutex *>(&locker);
|
||||
m_lock = const_cast<Mutex*>(&locker);
|
||||
}
|
||||
|
||||
void Threading::ScopedLock::Assign(const Mutex *locker)
|
||||
void Threading::ScopedLock::Assign(const Mutex* locker)
|
||||
{
|
||||
m_lock = const_cast<Mutex *>(locker);
|
||||
m_lock = const_cast<Mutex*>(locker);
|
||||
}
|
||||
|
||||
// Provides manual unlocking of a scoped lock prior to object destruction.
|
||||
void Threading::ScopedLock::Release()
|
||||
{
|
||||
if (!m_IsLocked)
|
||||
return;
|
||||
m_IsLocked = false;
|
||||
if (m_lock)
|
||||
m_lock->Release();
|
||||
if (!m_IsLocked)
|
||||
return;
|
||||
m_IsLocked = false;
|
||||
if (m_lock)
|
||||
m_lock->Release();
|
||||
}
|
||||
|
||||
// provides manual locking of a scoped lock, to re-lock after a manual unlocking.
|
||||
void Threading::ScopedLock::Acquire()
|
||||
{
|
||||
if (m_IsLocked || !m_lock)
|
||||
return;
|
||||
m_lock->Acquire();
|
||||
m_IsLocked = true;
|
||||
if (m_IsLocked || !m_lock)
|
||||
return;
|
||||
m_lock->Acquire();
|
||||
m_IsLocked = true;
|
||||
}
|
||||
|
||||
Threading::ScopedLock::ScopedLock(const Mutex &locker, bool isTryLock)
|
||||
Threading::ScopedLock::ScopedLock(const Mutex& locker, bool isTryLock)
|
||||
{
|
||||
m_lock = const_cast<Mutex *>(&locker);
|
||||
if (!m_lock)
|
||||
return;
|
||||
m_IsLocked = isTryLock ? m_lock->TryAcquire() : false;
|
||||
m_lock = const_cast<Mutex*>(&locker);
|
||||
if (!m_lock)
|
||||
return;
|
||||
m_IsLocked = isTryLock ? m_lock->TryAcquire() : false;
|
||||
}
|
||||
|
|
|
@ -30,12 +30,12 @@
|
|||
|
||||
struct PageFaultInfo
|
||||
{
|
||||
uptr addr;
|
||||
uptr addr;
|
||||
|
||||
PageFaultInfo(uptr address)
|
||||
{
|
||||
addr = address;
|
||||
}
|
||||
PageFaultInfo(uptr address)
|
||||
{
|
||||
addr = address;
|
||||
}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -44,22 +44,22 @@ struct PageFaultInfo
|
|||
class IEventListener_PageFault : public IEventDispatcher<PageFaultInfo>
|
||||
{
|
||||
public:
|
||||
typedef PageFaultInfo EvtParams;
|
||||
typedef PageFaultInfo EvtParams;
|
||||
|
||||
public:
|
||||
virtual ~IEventListener_PageFault() = default;
|
||||
virtual ~IEventListener_PageFault() = default;
|
||||
|
||||
virtual void DispatchEvent(const PageFaultInfo &evtinfo, bool &handled)
|
||||
{
|
||||
OnPageFaultEvent(evtinfo, handled);
|
||||
}
|
||||
virtual void DispatchEvent(const PageFaultInfo& evtinfo, bool& handled)
|
||||
{
|
||||
OnPageFaultEvent(evtinfo, handled);
|
||||
}
|
||||
|
||||
virtual void DispatchEvent(const PageFaultInfo &evtinfo)
|
||||
{
|
||||
pxFailRel("Don't call me, damnit. Use DispatchException instead.");
|
||||
}
|
||||
virtual void DispatchEvent(const PageFaultInfo& evtinfo)
|
||||
{
|
||||
pxFailRel("Don't call me, damnit. Use DispatchException instead.");
|
||||
}
|
||||
|
||||
virtual void OnPageFaultEvent(const PageFaultInfo &evtinfo, bool &handled) {}
|
||||
virtual void OnPageFaultEvent(const PageFaultInfo& evtinfo, bool& handled) {}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -68,34 +68,34 @@ public:
|
|||
class EventListener_PageFault : public IEventListener_PageFault
|
||||
{
|
||||
public:
|
||||
EventListener_PageFault();
|
||||
virtual ~EventListener_PageFault();
|
||||
EventListener_PageFault();
|
||||
virtual ~EventListener_PageFault();
|
||||
};
|
||||
|
||||
template <typename TypeToDispatchTo>
|
||||
class EventListenerHelper_PageFault : public EventListener_PageFault
|
||||
{
|
||||
public:
|
||||
TypeToDispatchTo *Owner;
|
||||
TypeToDispatchTo* Owner;
|
||||
|
||||
public:
|
||||
EventListenerHelper_PageFault(TypeToDispatchTo &dispatchTo)
|
||||
{
|
||||
Owner = &dispatchTo;
|
||||
}
|
||||
EventListenerHelper_PageFault(TypeToDispatchTo& dispatchTo)
|
||||
{
|
||||
Owner = &dispatchTo;
|
||||
}
|
||||
|
||||
EventListenerHelper_PageFault(TypeToDispatchTo *dispatchTo)
|
||||
{
|
||||
Owner = dispatchTo;
|
||||
}
|
||||
EventListenerHelper_PageFault(TypeToDispatchTo* dispatchTo)
|
||||
{
|
||||
Owner = dispatchTo;
|
||||
}
|
||||
|
||||
virtual ~EventListenerHelper_PageFault() = default;
|
||||
virtual ~EventListenerHelper_PageFault() = default;
|
||||
|
||||
protected:
|
||||
virtual void OnPageFaultEvent(const PageFaultInfo &info, bool &handled)
|
||||
{
|
||||
Owner->OnPageFaultEvent(info, handled);
|
||||
}
|
||||
virtual void OnPageFaultEvent(const PageFaultInfo& info, bool& handled)
|
||||
{
|
||||
Owner->OnPageFaultEvent(info, handled);
|
||||
}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -104,23 +104,23 @@ protected:
|
|||
class SrcType_PageFault : public EventSource<IEventListener_PageFault>
|
||||
{
|
||||
protected:
|
||||
typedef EventSource<IEventListener_PageFault> _parent;
|
||||
typedef EventSource<IEventListener_PageFault> _parent;
|
||||
|
||||
protected:
|
||||
bool m_handled;
|
||||
bool m_handled;
|
||||
|
||||
public:
|
||||
SrcType_PageFault()
|
||||
: m_handled(false)
|
||||
{
|
||||
}
|
||||
virtual ~SrcType_PageFault() = default;
|
||||
SrcType_PageFault()
|
||||
: m_handled(false)
|
||||
{
|
||||
}
|
||||
virtual ~SrcType_PageFault() = default;
|
||||
|
||||
bool WasHandled() const { return m_handled; }
|
||||
virtual void Dispatch(const PageFaultInfo ¶ms);
|
||||
bool WasHandled() const { return m_handled; }
|
||||
virtual void Dispatch(const PageFaultInfo& params);
|
||||
|
||||
protected:
|
||||
virtual void _DispatchRaw(ListenerIterator iter, const ListenerIterator &iend, const PageFaultInfo &evt);
|
||||
virtual void _DispatchRaw(ListenerIterator iter, const ListenerIterator& iend, const PageFaultInfo& evt);
|
||||
};
|
||||
|
||||
|
||||
|
@ -130,40 +130,41 @@ protected:
|
|||
// --------------------------------------------------------------------------------------
|
||||
class VirtualMemoryManager
|
||||
{
|
||||
DeclareNoncopyableObject(VirtualMemoryManager);
|
||||
DeclareNoncopyableObject(VirtualMemoryManager);
|
||||
|
||||
wxString m_name;
|
||||
wxString m_name;
|
||||
|
||||
uptr m_baseptr;
|
||||
uptr m_baseptr;
|
||||
|
||||
// An array to track page usage (to trigger asserts if things try to overlap)
|
||||
std::atomic<bool> *m_pageuse;
|
||||
// An array to track page usage (to trigger asserts if things try to overlap)
|
||||
std::atomic<bool>* m_pageuse;
|
||||
|
||||
// reserved memory (in pages)
|
||||
u32 m_pages_reserved;
|
||||
// reserved memory (in pages)
|
||||
u32 m_pages_reserved;
|
||||
|
||||
public:
|
||||
// If upper_bounds is nonzero and the OS fails to allocate memory that is below it,
|
||||
// calls to IsOk() will return false and Alloc() will always return null pointers
|
||||
// strict indicates that the allocation should quietly fail if the memory can't be mapped at `base`
|
||||
VirtualMemoryManager(const wxString &name, uptr base, size_t size, uptr upper_bounds = 0, bool strict = false);
|
||||
~VirtualMemoryManager();
|
||||
// If upper_bounds is nonzero and the OS fails to allocate memory that is below it,
|
||||
// calls to IsOk() will return false and Alloc() will always return null pointers
|
||||
// strict indicates that the allocation should quietly fail if the memory can't be mapped at `base`
|
||||
VirtualMemoryManager(const wxString& name, uptr base, size_t size, uptr upper_bounds = 0, bool strict = false);
|
||||
~VirtualMemoryManager();
|
||||
|
||||
void *GetBase() const { return (void *)m_baseptr; }
|
||||
void* GetBase() const { return (void*)m_baseptr; }
|
||||
|
||||
// Request the use of the memory at offsetLocation bytes from the start of the reserved memory area
|
||||
// offsetLocation must be page-aligned
|
||||
void *Alloc(uptr offsetLocation, size_t size) const;
|
||||
// Request the use of the memory at offsetLocation bytes from the start of the reserved memory area
|
||||
// offsetLocation must be page-aligned
|
||||
void* Alloc(uptr offsetLocation, size_t size) const;
|
||||
|
||||
void *AllocAtAddress(void *address, size_t size) const {
|
||||
return Alloc(size, (uptr)address - m_baseptr);
|
||||
}
|
||||
void* AllocAtAddress(void* address, size_t size) const
|
||||
{
|
||||
return Alloc(size, (uptr)address - m_baseptr);
|
||||
}
|
||||
|
||||
void Free(void *address, size_t size) const;
|
||||
void Free(void* address, size_t size) const;
|
||||
|
||||
// Was this VirtualMemoryManager successfully able to get its memory mapping?
|
||||
// (If not, calls to Alloc will return null pointers)
|
||||
bool IsOk() const { return m_baseptr != 0; }
|
||||
// Was this VirtualMemoryManager successfully able to get its memory mapping?
|
||||
// (If not, calls to Alloc will return null pointers)
|
||||
bool IsOk() const { return m_baseptr != 0; }
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<const VirtualMemoryManager> VirtualMemoryManagerPtr;
|
||||
|
@ -173,13 +174,14 @@ typedef std::shared_ptr<const VirtualMemoryManager> VirtualMemoryManagerPtr;
|
|||
// --------------------------------------------------------------------------------------
|
||||
class VirtualMemoryBumpAllocator
|
||||
{
|
||||
const VirtualMemoryManagerPtr m_allocator;
|
||||
std::atomic<uptr> m_baseptr{0};
|
||||
const uptr m_endptr = 0;
|
||||
const VirtualMemoryManagerPtr m_allocator;
|
||||
std::atomic<uptr> m_baseptr{0};
|
||||
const uptr m_endptr = 0;
|
||||
|
||||
public:
|
||||
VirtualMemoryBumpAllocator(VirtualMemoryManagerPtr allocator, size_t size, uptr offsetLocation);
|
||||
void *Alloc(size_t size);
|
||||
const VirtualMemoryManagerPtr& GetAllocator() { return m_allocator; }
|
||||
VirtualMemoryBumpAllocator(VirtualMemoryManagerPtr allocator, size_t size, uptr offsetLocation);
|
||||
void* Alloc(size_t size);
|
||||
const VirtualMemoryManagerPtr& GetAllocator() { return m_allocator; }
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -187,108 +189,108 @@ public:
|
|||
// --------------------------------------------------------------------------------------
|
||||
class VirtualMemoryReserve
|
||||
{
|
||||
DeclareNoncopyableObject(VirtualMemoryReserve);
|
||||
DeclareNoncopyableObject(VirtualMemoryReserve);
|
||||
|
||||
protected:
|
||||
wxString m_name;
|
||||
wxString m_name;
|
||||
|
||||
// Where the memory came from (so we can return it)
|
||||
VirtualMemoryManagerPtr m_allocator;
|
||||
// Where the memory came from (so we can return it)
|
||||
VirtualMemoryManagerPtr m_allocator;
|
||||
|
||||
// Default size of the reserve, in bytes. Can be specified when the object is constructed.
|
||||
// Is used as the reserve size when Reserve() is called, unless an override is specified
|
||||
// in the Reserve parameters.
|
||||
size_t m_defsize;
|
||||
// Default size of the reserve, in bytes. Can be specified when the object is constructed.
|
||||
// Is used as the reserve size when Reserve() is called, unless an override is specified
|
||||
// in the Reserve parameters.
|
||||
size_t m_defsize;
|
||||
|
||||
void *m_baseptr;
|
||||
void* m_baseptr;
|
||||
|
||||
// reserved memory (in pages).
|
||||
uptr m_pages_reserved;
|
||||
// reserved memory (in pages).
|
||||
uptr m_pages_reserved;
|
||||
|
||||
// Records the number of pages committed to memory.
|
||||
// (metric for analysis of buffer usage)
|
||||
uptr m_pages_commited;
|
||||
// Records the number of pages committed to memory.
|
||||
// (metric for analysis of buffer usage)
|
||||
uptr m_pages_commited;
|
||||
|
||||
// Protection mode to be applied to committed blocks.
|
||||
PageProtectionMode m_prot_mode;
|
||||
// Protection mode to be applied to committed blocks.
|
||||
PageProtectionMode m_prot_mode;
|
||||
|
||||
// Controls write access to the entire reserve. When true (the default), the reserve
|
||||
// operates normally. When set to false, all committed blocks are re-protected with
|
||||
// write disabled, and accesses to uncommitted blocks (read or write) will cause a GPF
|
||||
// as well.
|
||||
bool m_allow_writes;
|
||||
// Controls write access to the entire reserve. When true (the default), the reserve
|
||||
// operates normally. When set to false, all committed blocks are re-protected with
|
||||
// write disabled, and accesses to uncommitted blocks (read or write) will cause a GPF
|
||||
// as well.
|
||||
bool m_allow_writes;
|
||||
|
||||
// Allows the implementation to decide how much memory it needs to allocate if someone requests the given size
|
||||
// Should translate requests of size 0 to m_defsize
|
||||
virtual size_t GetSize(size_t requestedSize);
|
||||
// Allows the implementation to decide how much memory it needs to allocate if someone requests the given size
|
||||
// Should translate requests of size 0 to m_defsize
|
||||
virtual size_t GetSize(size_t requestedSize);
|
||||
|
||||
public:
|
||||
VirtualMemoryReserve(const wxString &name, size_t size = 0);
|
||||
virtual ~VirtualMemoryReserve()
|
||||
{
|
||||
Release();
|
||||
}
|
||||
VirtualMemoryReserve(const wxString& name, size_t size = 0);
|
||||
virtual ~VirtualMemoryReserve()
|
||||
{
|
||||
Release();
|
||||
}
|
||||
|
||||
// Initialize with the given piece of memory
|
||||
// Note: The memory is already allocated, the allocator is for future use to free the region
|
||||
// It may be null in which case there is no way to free the memory in a way it will be usable again
|
||||
virtual void *Assign(VirtualMemoryManagerPtr allocator, void *baseptr, size_t size);
|
||||
// Initialize with the given piece of memory
|
||||
// Note: The memory is already allocated, the allocator is for future use to free the region
|
||||
// It may be null in which case there is no way to free the memory in a way it will be usable again
|
||||
virtual void* Assign(VirtualMemoryManagerPtr allocator, void* baseptr, size_t size);
|
||||
|
||||
void *Reserve(VirtualMemoryManagerPtr allocator, uptr baseOffset, size_t size = 0)
|
||||
{
|
||||
size = GetSize(size);
|
||||
void *allocation = allocator->Alloc(baseOffset, size);
|
||||
return Assign(std::move(allocator), allocation, size);
|
||||
}
|
||||
void *Reserve(VirtualMemoryBumpAllocator& allocator, size_t size = 0)
|
||||
{
|
||||
size = GetSize(size);
|
||||
return Assign(allocator.GetAllocator(), allocator.Alloc(size), size);
|
||||
}
|
||||
void* Reserve(VirtualMemoryManagerPtr allocator, uptr baseOffset, size_t size = 0)
|
||||
{
|
||||
size = GetSize(size);
|
||||
void* allocation = allocator->Alloc(baseOffset, size);
|
||||
return Assign(std::move(allocator), allocation, size);
|
||||
}
|
||||
void* Reserve(VirtualMemoryBumpAllocator& allocator, size_t size = 0)
|
||||
{
|
||||
size = GetSize(size);
|
||||
return Assign(allocator.GetAllocator(), allocator.Alloc(size), size);
|
||||
}
|
||||
|
||||
virtual void Reset();
|
||||
virtual void Release();
|
||||
virtual bool TryResize(uint newsize);
|
||||
virtual bool Commit();
|
||||
virtual void Reset();
|
||||
virtual void Release();
|
||||
virtual bool TryResize(uint newsize);
|
||||
virtual bool Commit();
|
||||
|
||||
virtual void ForbidModification();
|
||||
virtual void AllowModification();
|
||||
virtual void ForbidModification();
|
||||
virtual void AllowModification();
|
||||
|
||||
bool IsOk() const { return m_baseptr != NULL; }
|
||||
const wxString& GetName() const { return m_name; }
|
||||
bool IsOk() const { return m_baseptr != NULL; }
|
||||
const wxString& GetName() const { return m_name; }
|
||||
|
||||
uptr GetReserveSizeInBytes() const { return m_pages_reserved * __pagesize; }
|
||||
uptr GetReserveSizeInPages() const { return m_pages_reserved; }
|
||||
uint GetCommittedPageCount() const { return m_pages_commited; }
|
||||
uint GetCommittedBytes() const { return m_pages_commited * __pagesize; }
|
||||
uptr GetReserveSizeInBytes() const { return m_pages_reserved * __pagesize; }
|
||||
uptr GetReserveSizeInPages() const { return m_pages_reserved; }
|
||||
uint GetCommittedPageCount() const { return m_pages_commited; }
|
||||
uint GetCommittedBytes() const { return m_pages_commited * __pagesize; }
|
||||
|
||||
u8 *GetPtr() { return (u8 *)m_baseptr; }
|
||||
const u8 *GetPtr() const { return (u8 *)m_baseptr; }
|
||||
u8 *GetPtrEnd() { return (u8 *)m_baseptr + (m_pages_reserved * __pagesize); }
|
||||
const u8 *GetPtrEnd() const { return (u8 *)m_baseptr + (m_pages_reserved * __pagesize); }
|
||||
u8* GetPtr() { return (u8*)m_baseptr; }
|
||||
const u8* GetPtr() const { return (u8*)m_baseptr; }
|
||||
u8* GetPtrEnd() { return (u8*)m_baseptr + (m_pages_reserved * __pagesize); }
|
||||
const u8* GetPtrEnd() const { return (u8*)m_baseptr + (m_pages_reserved * __pagesize); }
|
||||
|
||||
VirtualMemoryReserve &SetPageAccessOnCommit(const PageProtectionMode &mode);
|
||||
VirtualMemoryReserve& SetPageAccessOnCommit(const PageProtectionMode& mode);
|
||||
|
||||
operator void *() { return m_baseptr; }
|
||||
operator const void *() const { return m_baseptr; }
|
||||
operator void*() { return m_baseptr; }
|
||||
operator const void*() const { return m_baseptr; }
|
||||
|
||||
operator u8 *() { return (u8 *)m_baseptr; }
|
||||
operator const u8 *() const { return (u8 *)m_baseptr; }
|
||||
operator u8*() { return (u8*)m_baseptr; }
|
||||
operator const u8*() const { return (u8*)m_baseptr; }
|
||||
|
||||
u8 &operator[](uint idx)
|
||||
{
|
||||
pxAssert(idx < (m_pages_reserved * __pagesize));
|
||||
return *((u8 *)m_baseptr + idx);
|
||||
}
|
||||
u8& operator[](uint idx)
|
||||
{
|
||||
pxAssert(idx < (m_pages_reserved * __pagesize));
|
||||
return *((u8*)m_baseptr + idx);
|
||||
}
|
||||
|
||||
const u8 &operator[](uint idx) const
|
||||
{
|
||||
pxAssert(idx < (m_pages_reserved * __pagesize));
|
||||
return *((u8 *)m_baseptr + idx);
|
||||
}
|
||||
const u8& operator[](uint idx) const
|
||||
{
|
||||
pxAssert(idx < (m_pages_reserved * __pagesize));
|
||||
return *((u8*)m_baseptr + idx);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void ReprotectCommittedBlocks(const PageProtectionMode &newmode);
|
||||
virtual void ReprotectCommittedBlocks(const PageProtectionMode& newmode);
|
||||
};
|
||||
|
||||
#ifdef __POSIX__
|
||||
|
@ -299,11 +301,11 @@ protected:
|
|||
#elif defined(_WIN32)
|
||||
|
||||
struct _EXCEPTION_POINTERS;
|
||||
extern long __stdcall SysPageFaultExceptionFilter(struct _EXCEPTION_POINTERS *eps);
|
||||
extern long __stdcall SysPageFaultExceptionFilter(struct _EXCEPTION_POINTERS* eps);
|
||||
|
||||
#define PCSX2_PAGEFAULT_PROTECT __try
|
||||
#define PCSX2_PAGEFAULT_EXCEPT \
|
||||
__except (SysPageFaultExceptionFilter(GetExceptionInformation())) {}
|
||||
__except (SysPageFaultExceptionFilter(GetExceptionInformation())) {}
|
||||
|
||||
#else
|
||||
#error PCSX2 - Unsupported operating system platform.
|
||||
|
@ -313,5 +315,5 @@ extern void pxInstallSignalHandler();
|
|||
extern void _platform_InstallSignalHandler();
|
||||
|
||||
#include "Threading.h"
|
||||
extern SrcType_PageFault *Source_PageFault;
|
||||
extern SrcType_PageFault* Source_PageFault;
|
||||
extern Threading::Mutex PageFault_Mutex;
|
||||
|
|
312
common/Path.h
312
common/Path.h
|
@ -26,180 +26,184 @@
|
|||
class wxDirName : protected wxFileName
|
||||
{
|
||||
public:
|
||||
explicit wxDirName(const wxFileName &src)
|
||||
{
|
||||
Assign(src.GetPath(), wxEmptyString);
|
||||
}
|
||||
explicit wxDirName(const wxFileName& src)
|
||||
{
|
||||
Assign(src.GetPath(), wxEmptyString);
|
||||
}
|
||||
|
||||
wxDirName()
|
||||
: wxFileName()
|
||||
{
|
||||
}
|
||||
wxDirName(const wxDirName &src)
|
||||
: wxFileName(src)
|
||||
{
|
||||
}
|
||||
explicit wxDirName(const char *src) { Assign(fromUTF8(src)); }
|
||||
explicit wxDirName(const wxString &src) { Assign(src); }
|
||||
wxDirName()
|
||||
: wxFileName()
|
||||
{
|
||||
}
|
||||
wxDirName(const wxDirName& src)
|
||||
: wxFileName(src)
|
||||
{
|
||||
}
|
||||
explicit wxDirName(const char* src) { Assign(fromUTF8(src)); }
|
||||
explicit wxDirName(const wxString& src) { Assign(src); }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
void Assign(const wxString &volume, const wxString &path)
|
||||
{
|
||||
wxFileName::Assign(volume, path, wxEmptyString);
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
void Assign(const wxString& volume, const wxString& path)
|
||||
{
|
||||
wxFileName::Assign(volume, path, wxEmptyString);
|
||||
}
|
||||
|
||||
void Assign(const wxString &path)
|
||||
{
|
||||
wxFileName::Assign(path, wxEmptyString);
|
||||
}
|
||||
void Assign(const wxString& path)
|
||||
{
|
||||
wxFileName::Assign(path, wxEmptyString);
|
||||
}
|
||||
|
||||
void Assign(const wxDirName &path)
|
||||
{
|
||||
wxFileName::Assign(path);
|
||||
}
|
||||
void Assign(const wxDirName& path)
|
||||
{
|
||||
wxFileName::Assign(path);
|
||||
}
|
||||
|
||||
void Clear() { wxFileName::Clear(); }
|
||||
void Clear() { wxFileName::Clear(); }
|
||||
|
||||
wxCharBuffer ToUTF8() const { return GetPath().ToUTF8(); }
|
||||
wxCharBuffer ToAscii() const { return GetPath().ToAscii(); }
|
||||
wxString ToString() const { return GetPath(); }
|
||||
wxCharBuffer ToUTF8() const { return GetPath().ToUTF8(); }
|
||||
wxCharBuffer ToAscii() const { return GetPath().ToAscii(); }
|
||||
wxString ToString() const { return GetPath(); }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
bool IsWritable() const { return IsDirWritable(); }
|
||||
bool IsReadable() const { return IsDirReadable(); }
|
||||
bool Exists() const { return DirExists(); }
|
||||
bool FileExists() const { return wxFileName::FileExists(); }
|
||||
bool IsOk() const { return wxFileName::IsOk(); }
|
||||
bool IsRelative() const { return wxFileName::IsRelative(); }
|
||||
bool IsAbsolute() const { return wxFileName::IsAbsolute(); }
|
||||
// ------------------------------------------------------------------------
|
||||
bool IsWritable() const { return IsDirWritable(); }
|
||||
bool IsReadable() const { return IsDirReadable(); }
|
||||
bool Exists() const { return DirExists(); }
|
||||
bool FileExists() const { return wxFileName::FileExists(); }
|
||||
bool IsOk() const { return wxFileName::IsOk(); }
|
||||
bool IsRelative() const { return wxFileName::IsRelative(); }
|
||||
bool IsAbsolute() const { return wxFileName::IsAbsolute(); }
|
||||
|
||||
bool SameAs(const wxDirName &filepath) const
|
||||
{
|
||||
return wxFileName::SameAs(filepath);
|
||||
}
|
||||
bool SameAs(const wxDirName& filepath) const
|
||||
{
|
||||
return wxFileName::SameAs(filepath);
|
||||
}
|
||||
|
||||
//Returns true if the file is somewhere inside this directory (and both file and directory are not relative).
|
||||
bool IsContains(const wxFileName &file) const
|
||||
{
|
||||
if (this->IsRelative() || file.IsRelative())
|
||||
return false;
|
||||
//Returns true if the file is somewhere inside this directory (and both file and directory are not relative).
|
||||
bool IsContains(const wxFileName& file) const
|
||||
{
|
||||
if (this->IsRelative() || file.IsRelative())
|
||||
return false;
|
||||
|
||||
wxFileName f(file);
|
||||
wxFileName f(file);
|
||||
|
||||
while (1) {
|
||||
if (this->SameAs(wxDirName(f.GetPath())))
|
||||
return true;
|
||||
while (1)
|
||||
{
|
||||
if (this->SameAs(wxDirName(f.GetPath())))
|
||||
return true;
|
||||
|
||||
if (f.GetDirCount() == 0)
|
||||
return false;
|
||||
if (f.GetDirCount() == 0)
|
||||
return false;
|
||||
|
||||
f.RemoveLastDir();
|
||||
}
|
||||
f.RemoveLastDir();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsContains(const wxDirName &dir) const
|
||||
{
|
||||
return IsContains((wxFileName)dir);
|
||||
}
|
||||
bool IsContains(const wxDirName& dir) const
|
||||
{
|
||||
return IsContains((wxFileName)dir);
|
||||
}
|
||||
|
||||
|
||||
//Auto relative works as follows:
|
||||
// 1. if either base or subject are relative, return subject (should never be used with relative paths).
|
||||
// 2. else if subject is somewhere inside base folder, then result is subject relative to base.
|
||||
// 3. (windows only, implicitly) else if subject is on the same driveletter as base, result is absolute path of subject without the driveletter.
|
||||
// 4. else, result is absolute path of subject.
|
||||
//
|
||||
// returns ok if both this and base are absolute paths.
|
||||
static wxString MakeAutoRelativeTo(const wxFileName _subject, const wxString &pathbase)
|
||||
{
|
||||
wxFileName subject(_subject);
|
||||
wxDirName base(pathbase);
|
||||
if (base.IsRelative() || subject.IsRelative())
|
||||
return subject.GetFullPath();
|
||||
//Auto relative works as follows:
|
||||
// 1. if either base or subject are relative, return subject (should never be used with relative paths).
|
||||
// 2. else if subject is somewhere inside base folder, then result is subject relative to base.
|
||||
// 3. (windows only, implicitly) else if subject is on the same driveletter as base, result is absolute path of subject without the driveletter.
|
||||
// 4. else, result is absolute path of subject.
|
||||
//
|
||||
// returns ok if both this and base are absolute paths.
|
||||
static wxString MakeAutoRelativeTo(const wxFileName _subject, const wxString& pathbase)
|
||||
{
|
||||
wxFileName subject(_subject);
|
||||
wxDirName base(pathbase);
|
||||
if (base.IsRelative() || subject.IsRelative())
|
||||
return subject.GetFullPath();
|
||||
|
||||
wxString bv(base.GetVolume());
|
||||
bv.MakeUpper();
|
||||
wxString sv(subject.GetVolume());
|
||||
sv.MakeUpper();
|
||||
wxString bv(base.GetVolume());
|
||||
bv.MakeUpper();
|
||||
wxString sv(subject.GetVolume());
|
||||
sv.MakeUpper();
|
||||
|
||||
if (base.IsContains(subject)) {
|
||||
subject.MakeRelativeTo(base.GetFullPath());
|
||||
} else if (base.HasVolume() && subject.HasVolume() && bv == sv) {
|
||||
wxString unusedVolume;
|
||||
wxString pathSansVolume;
|
||||
subject.SplitVolume(subject.GetFullPath(), &unusedVolume, &pathSansVolume);
|
||||
subject = pathSansVolume;
|
||||
}
|
||||
//implicit else: this stays fully absolute
|
||||
if (base.IsContains(subject))
|
||||
{
|
||||
subject.MakeRelativeTo(base.GetFullPath());
|
||||
}
|
||||
else if (base.HasVolume() && subject.HasVolume() && bv == sv)
|
||||
{
|
||||
wxString unusedVolume;
|
||||
wxString pathSansVolume;
|
||||
subject.SplitVolume(subject.GetFullPath(), &unusedVolume, &pathSansVolume);
|
||||
subject = pathSansVolume;
|
||||
}
|
||||
//implicit else: this stays fully absolute
|
||||
|
||||
return subject.GetFullPath();
|
||||
}
|
||||
return subject.GetFullPath();
|
||||
}
|
||||
|
||||
static wxString MakeAutoRelativeTo(const wxDirName subject, const wxString &pathbase)
|
||||
{
|
||||
return MakeAutoRelativeTo(wxFileName(subject), pathbase);
|
||||
}
|
||||
static wxString MakeAutoRelativeTo(const wxDirName subject, const wxString& pathbase)
|
||||
{
|
||||
return MakeAutoRelativeTo(wxFileName(subject), pathbase);
|
||||
}
|
||||
|
||||
// Returns the number of sub folders in this directory path
|
||||
size_t GetCount() const { return GetDirCount(); }
|
||||
// Returns the number of sub folders in this directory path
|
||||
size_t GetCount() const { return GetDirCount(); }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
wxFileName Combine(const wxFileName &right) const;
|
||||
wxDirName Combine(const wxDirName &right) const;
|
||||
// ------------------------------------------------------------------------
|
||||
wxFileName Combine(const wxFileName& right) const;
|
||||
wxDirName Combine(const wxDirName& right) const;
|
||||
|
||||
// removes the lastmost directory from the path
|
||||
void RemoveLast() { wxFileName::RemoveDir(GetCount() - 1); }
|
||||
// removes the lastmost directory from the path
|
||||
void RemoveLast() { wxFileName::RemoveDir(GetCount() - 1); }
|
||||
|
||||
wxDirName &Normalize(int flags = wxPATH_NORM_ALL, const wxString &cwd = wxEmptyString);
|
||||
wxDirName &MakeRelativeTo(const wxString &pathBase = wxEmptyString);
|
||||
wxDirName &MakeAbsolute(const wxString &cwd = wxEmptyString);
|
||||
wxDirName& Normalize(int flags = wxPATH_NORM_ALL, const wxString& cwd = wxEmptyString);
|
||||
wxDirName& MakeRelativeTo(const wxString& pathBase = wxEmptyString);
|
||||
wxDirName& MakeAbsolute(const wxString& cwd = wxEmptyString);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
void AssignCwd(const wxString &volume = wxEmptyString) { wxFileName::AssignCwd(volume); }
|
||||
bool SetCwd() { return wxFileName::SetCwd(); }
|
||||
void AssignCwd(const wxString& volume = wxEmptyString) { wxFileName::AssignCwd(volume); }
|
||||
bool SetCwd() { return wxFileName::SetCwd(); }
|
||||
|
||||
// wxWidgets is missing the const qualifier for this one! Shame!
|
||||
void Rmdir();
|
||||
bool Mkdir();
|
||||
// wxWidgets is missing the const qualifier for this one! Shame!
|
||||
void Rmdir();
|
||||
bool Mkdir();
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
wxDirName &operator=(const wxDirName &dirname)
|
||||
{
|
||||
Assign(dirname);
|
||||
return *this;
|
||||
}
|
||||
wxDirName &operator=(const wxString &dirname)
|
||||
{
|
||||
Assign(dirname);
|
||||
return *this;
|
||||
}
|
||||
wxDirName &operator=(const char *dirname)
|
||||
{
|
||||
Assign(fromUTF8(dirname));
|
||||
return *this;
|
||||
}
|
||||
wxDirName& operator=(const wxDirName& dirname)
|
||||
{
|
||||
Assign(dirname);
|
||||
return *this;
|
||||
}
|
||||
wxDirName& operator=(const wxString& dirname)
|
||||
{
|
||||
Assign(dirname);
|
||||
return *this;
|
||||
}
|
||||
wxDirName& operator=(const char* dirname)
|
||||
{
|
||||
Assign(fromUTF8(dirname));
|
||||
return *this;
|
||||
}
|
||||
|
||||
wxFileName operator+(const wxFileName &right) const { return Combine(right); }
|
||||
wxDirName operator+(const wxDirName &right) const { return Combine(right); }
|
||||
wxFileName operator+(const wxString &right) const { return Combine(wxFileName(right)); }
|
||||
wxFileName operator+(const char *right) const { return Combine(wxFileName(fromUTF8(right))); }
|
||||
wxFileName operator+(const wxFileName& right) const { return Combine(right); }
|
||||
wxDirName operator+(const wxDirName& right) const { return Combine(right); }
|
||||
wxFileName operator+(const wxString& right) const { return Combine(wxFileName(right)); }
|
||||
wxFileName operator+(const char* right) const { return Combine(wxFileName(fromUTF8(right))); }
|
||||
|
||||
bool operator==(const wxDirName &filename) const { return SameAs(filename); }
|
||||
bool operator!=(const wxDirName &filename) const { return !SameAs(filename); }
|
||||
bool operator==(const wxDirName& filename) const { return SameAs(filename); }
|
||||
bool operator!=(const wxDirName& filename) const { return !SameAs(filename); }
|
||||
|
||||
bool operator==(const wxFileName &filename) const { return SameAs(wxDirName(filename)); }
|
||||
bool operator!=(const wxFileName &filename) const { return !SameAs(wxDirName(filename)); }
|
||||
bool operator==(const wxFileName& filename) const { return SameAs(wxDirName(filename)); }
|
||||
bool operator!=(const wxFileName& filename) const { return !SameAs(wxDirName(filename)); }
|
||||
|
||||
// compare with a filename string interpreted as a native file name
|
||||
bool operator==(const wxString &filename) const { return SameAs(wxDirName(filename)); }
|
||||
bool operator!=(const wxString &filename) const { return !SameAs(wxDirName(filename)); }
|
||||
// compare with a filename string interpreted as a native file name
|
||||
bool operator==(const wxString& filename) const { return SameAs(wxDirName(filename)); }
|
||||
bool operator!=(const wxString& filename) const { return !SameAs(wxDirName(filename)); }
|
||||
|
||||
const wxFileName &GetFilename() const { return *this; }
|
||||
wxFileName &GetFilename() { return *this; }
|
||||
const wxFileName& GetFilename() const { return *this; }
|
||||
wxFileName& GetFilename() { return *this; }
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -211,20 +215,20 @@ public:
|
|||
//
|
||||
namespace Path
|
||||
{
|
||||
extern bool IsRelative(const wxString &path);
|
||||
extern s64 GetFileSize(const wxString &path);
|
||||
extern bool IsRelative(const wxString& path);
|
||||
extern s64 GetFileSize(const wxString& path);
|
||||
|
||||
extern wxString Normalize(const wxString &srcpath);
|
||||
extern wxString Normalize(const wxDirName &srcpath);
|
||||
extern wxString MakeAbsolute(const wxString &srcpath);
|
||||
extern wxString Normalize(const wxString& srcpath);
|
||||
extern wxString Normalize(const wxDirName& srcpath);
|
||||
extern wxString MakeAbsolute(const wxString& srcpath);
|
||||
|
||||
extern wxString Combine(const wxString &srcPath, const wxString &srcFile);
|
||||
extern wxString Combine(const wxDirName &srcPath, const wxFileName &srcFile);
|
||||
extern wxString Combine(const wxString &srcPath, const wxDirName &srcFile);
|
||||
extern wxString ReplaceExtension(const wxString &src, const wxString &ext);
|
||||
extern wxString ReplaceFilename(const wxString &src, const wxString &newfilename);
|
||||
extern wxString GetFilename(const wxString &src);
|
||||
extern wxString GetDirectory(const wxString &src);
|
||||
extern wxString GetFilenameWithoutExt(const wxString &src);
|
||||
extern wxString GetRootDirectory(const wxString &src);
|
||||
}
|
||||
extern wxString Combine(const wxString& srcPath, const wxString& srcFile);
|
||||
extern wxString Combine(const wxDirName& srcPath, const wxFileName& srcFile);
|
||||
extern wxString Combine(const wxString& srcPath, const wxDirName& srcFile);
|
||||
extern wxString ReplaceExtension(const wxString& src, const wxString& ext);
|
||||
extern wxString ReplaceFilename(const wxString& src, const wxString& newfilename);
|
||||
extern wxString GetFilename(const wxString& src);
|
||||
extern wxString GetDirectory(const wxString& src);
|
||||
extern wxString GetFilenameWithoutExt(const wxString& src);
|
||||
extern wxString GetRootDirectory(const wxString& src);
|
||||
} // namespace Path
|
||||
|
|
|
@ -22,60 +22,60 @@
|
|||
// wxDirName (implementations)
|
||||
// ---------------------------------------------------------------------------------
|
||||
|
||||
wxFileName wxDirName::Combine(const wxFileName &right) const
|
||||
wxFileName wxDirName::Combine(const wxFileName& right) const
|
||||
{
|
||||
pxAssertMsg(IsDir(), L"Warning: Malformed directory name detected during wxDirName concatenation.");
|
||||
if (right.IsAbsolute())
|
||||
return right;
|
||||
pxAssertMsg(IsDir(), L"Warning: Malformed directory name detected during wxDirName concatenation.");
|
||||
if (right.IsAbsolute())
|
||||
return right;
|
||||
|
||||
// Append any directory parts from right, and then set the filename.
|
||||
// Except we can't do that because our m_members are private (argh!) and there is no API
|
||||
// for getting each component of the path. So instead let's use Normalize:
|
||||
// Append any directory parts from right, and then set the filename.
|
||||
// Except we can't do that because our m_members are private (argh!) and there is no API
|
||||
// for getting each component of the path. So instead let's use Normalize:
|
||||
|
||||
wxFileName result(right);
|
||||
result.Normalize(wxPATH_NORM_ENV_VARS | wxPATH_NORM_DOTS | wxPATH_NORM_ABSOLUTE, GetPath());
|
||||
return result;
|
||||
wxFileName result(right);
|
||||
result.Normalize(wxPATH_NORM_ENV_VARS | wxPATH_NORM_DOTS | wxPATH_NORM_ABSOLUTE, GetPath());
|
||||
return result;
|
||||
}
|
||||
|
||||
wxDirName wxDirName::Combine(const wxDirName &right) const
|
||||
wxDirName wxDirName::Combine(const wxDirName& right) const
|
||||
{
|
||||
pxAssertMsg(IsDir() && right.IsDir(), L"Warning: Malformed directory name detected during wDirName concatenation.");
|
||||
pxAssertMsg(IsDir() && right.IsDir(), L"Warning: Malformed directory name detected during wDirName concatenation.");
|
||||
|
||||
wxDirName result(right);
|
||||
result.Normalize(wxPATH_NORM_ENV_VARS | wxPATH_NORM_DOTS | wxPATH_NORM_ABSOLUTE, GetPath());
|
||||
return result;
|
||||
wxDirName result(right);
|
||||
result.Normalize(wxPATH_NORM_ENV_VARS | wxPATH_NORM_DOTS | wxPATH_NORM_ABSOLUTE, GetPath());
|
||||
return result;
|
||||
}
|
||||
|
||||
wxDirName &wxDirName::Normalize(int flags, const wxString &cwd)
|
||||
wxDirName& wxDirName::Normalize(int flags, const wxString& cwd)
|
||||
{
|
||||
pxAssertMsg(IsDir(), L"Warning: Malformed directory name detected during wDirName normalization.");
|
||||
if (!wxFileName::Normalize(flags, cwd))
|
||||
throw Exception::ParseError().SetDiagMsg(L"wxDirName::Normalize operation failed.");
|
||||
return *this;
|
||||
pxAssertMsg(IsDir(), L"Warning: Malformed directory name detected during wDirName normalization.");
|
||||
if (!wxFileName::Normalize(flags, cwd))
|
||||
throw Exception::ParseError().SetDiagMsg(L"wxDirName::Normalize operation failed.");
|
||||
return *this;
|
||||
}
|
||||
|
||||
wxDirName &wxDirName::MakeRelativeTo(const wxString &pathBase)
|
||||
wxDirName& wxDirName::MakeRelativeTo(const wxString& pathBase)
|
||||
{
|
||||
pxAssertMsg(IsDir(), L"Warning: Malformed directory name detected during wDirName normalization.");
|
||||
if (!wxFileName::MakeRelativeTo(pathBase))
|
||||
throw Exception::ParseError().SetDiagMsg(L"wxDirName::MakeRelativeTo operation failed.");
|
||||
return *this;
|
||||
pxAssertMsg(IsDir(), L"Warning: Malformed directory name detected during wDirName normalization.");
|
||||
if (!wxFileName::MakeRelativeTo(pathBase))
|
||||
throw Exception::ParseError().SetDiagMsg(L"wxDirName::MakeRelativeTo operation failed.");
|
||||
return *this;
|
||||
}
|
||||
|
||||
wxDirName &wxDirName::MakeAbsolute(const wxString &cwd)
|
||||
wxDirName& wxDirName::MakeAbsolute(const wxString& cwd)
|
||||
{
|
||||
pxAssertMsg(IsDir(), L"Warning: Malformed directory name detected during wDirName normalization.");
|
||||
if (!wxFileName::MakeAbsolute(cwd))
|
||||
throw Exception::ParseError().SetDiagMsg(L"wxDirName::MakeAbsolute operation failed.");
|
||||
return *this;
|
||||
pxAssertMsg(IsDir(), L"Warning: Malformed directory name detected during wDirName normalization.");
|
||||
if (!wxFileName::MakeAbsolute(cwd))
|
||||
throw Exception::ParseError().SetDiagMsg(L"wxDirName::MakeAbsolute operation failed.");
|
||||
return *this;
|
||||
}
|
||||
|
||||
void wxDirName::Rmdir()
|
||||
{
|
||||
if (!Exists())
|
||||
return;
|
||||
wxFileName::Rmdir();
|
||||
// TODO : Throw exception if operation failed? Do we care?
|
||||
if (!Exists())
|
||||
return;
|
||||
wxFileName::Rmdir();
|
||||
// TODO : Throw exception if operation failed? Do we care?
|
||||
}
|
||||
|
||||
bool wxDirName::Mkdir()
|
||||
|
@ -87,9 +87,9 @@ bool wxDirName::Mkdir()
|
|||
#define wxS_DIR_DEFAULT 0777
|
||||
#endif
|
||||
|
||||
if (Exists())
|
||||
return true;
|
||||
return wxFileName::Mkdir(wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL);
|
||||
if (Exists())
|
||||
return true;
|
||||
return wxFileName::Mkdir(wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL);
|
||||
}
|
||||
|
||||
|
||||
|
@ -98,111 +98,111 @@ bool wxDirName::Mkdir()
|
|||
// ---------------------------------------------------------------------------------
|
||||
|
||||
|
||||
bool Path::IsRelative(const wxString &path)
|
||||
bool Path::IsRelative(const wxString& path)
|
||||
{
|
||||
return wxDirName(path).IsRelative();
|
||||
return wxDirName(path).IsRelative();
|
||||
}
|
||||
|
||||
// Returns -1 if the file does not exist.
|
||||
s64 Path::GetFileSize(const wxString &path)
|
||||
s64 Path::GetFileSize(const wxString& path)
|
||||
{
|
||||
if (!wxFile::Exists(path.c_str()))
|
||||
return -1;
|
||||
return (s64)wxFileName::GetSize(path).GetValue();
|
||||
if (!wxFile::Exists(path.c_str()))
|
||||
return -1;
|
||||
return (s64)wxFileName::GetSize(path).GetValue();
|
||||
}
|
||||
|
||||
|
||||
wxString Path::Normalize(const wxString &src)
|
||||
wxString Path::Normalize(const wxString& src)
|
||||
{
|
||||
wxFileName normalize(src);
|
||||
normalize.Normalize();
|
||||
return normalize.GetFullPath();
|
||||
wxFileName normalize(src);
|
||||
normalize.Normalize();
|
||||
return normalize.GetFullPath();
|
||||
}
|
||||
|
||||
wxString Path::Normalize(const wxDirName &src)
|
||||
wxString Path::Normalize(const wxDirName& src)
|
||||
{
|
||||
return wxDirName(src).Normalize().ToString();
|
||||
return wxDirName(src).Normalize().ToString();
|
||||
}
|
||||
|
||||
wxString Path::MakeAbsolute(const wxString &src)
|
||||
wxString Path::MakeAbsolute(const wxString& src)
|
||||
{
|
||||
wxFileName absolute(src);
|
||||
absolute.MakeAbsolute();
|
||||
return absolute.GetFullPath();
|
||||
wxFileName absolute(src);
|
||||
absolute.MakeAbsolute();
|
||||
return absolute.GetFullPath();
|
||||
}
|
||||
|
||||
// Concatenates two pathnames together, inserting delimiters (backslash on win32)
|
||||
// as needed! Assumes the 'dest' is allocated to at least g_MaxPath length.
|
||||
//
|
||||
wxString Path::Combine(const wxString &srcPath, const wxString &srcFile)
|
||||
wxString Path::Combine(const wxString& srcPath, const wxString& srcFile)
|
||||
{
|
||||
return (wxDirName(srcPath) + srcFile).GetFullPath();
|
||||
return (wxDirName(srcPath) + srcFile).GetFullPath();
|
||||
}
|
||||
|
||||
wxString Path::Combine(const wxDirName &srcPath, const wxFileName &srcFile)
|
||||
wxString Path::Combine(const wxDirName& srcPath, const wxFileName& srcFile)
|
||||
{
|
||||
return (srcPath + srcFile).GetFullPath();
|
||||
return (srcPath + srcFile).GetFullPath();
|
||||
}
|
||||
|
||||
wxString Path::Combine(const wxString &srcPath, const wxDirName &srcFile)
|
||||
wxString Path::Combine(const wxString& srcPath, const wxDirName& srcFile)
|
||||
{
|
||||
return (wxDirName(srcPath) + srcFile).ToString();
|
||||
return (wxDirName(srcPath) + srcFile).ToString();
|
||||
}
|
||||
|
||||
// Replaces the extension of the file with the one given.
|
||||
// This function works for path names as well as file names.
|
||||
wxString Path::ReplaceExtension(const wxString &src, const wxString &ext)
|
||||
wxString Path::ReplaceExtension(const wxString& src, const wxString& ext)
|
||||
{
|
||||
wxFileName jojo(src);
|
||||
jojo.SetExt(ext);
|
||||
return jojo.GetFullPath();
|
||||
wxFileName jojo(src);
|
||||
jojo.SetExt(ext);
|
||||
return jojo.GetFullPath();
|
||||
}
|
||||
|
||||
wxString Path::ReplaceFilename(const wxString &src, const wxString &newfilename)
|
||||
wxString Path::ReplaceFilename(const wxString& src, const wxString& newfilename)
|
||||
{
|
||||
wxFileName jojo(src);
|
||||
jojo.SetFullName(newfilename);
|
||||
return jojo.GetFullPath();
|
||||
wxFileName jojo(src);
|
||||
jojo.SetFullName(newfilename);
|
||||
return jojo.GetFullPath();
|
||||
}
|
||||
|
||||
wxString Path::GetFilename(const wxString &src)
|
||||
wxString Path::GetFilename(const wxString& src)
|
||||
{
|
||||
return wxFileName(src).GetFullName();
|
||||
return wxFileName(src).GetFullName();
|
||||
}
|
||||
|
||||
wxString Path::GetFilenameWithoutExt(const wxString &src)
|
||||
wxString Path::GetFilenameWithoutExt(const wxString& src)
|
||||
{
|
||||
return wxFileName(src).GetName();
|
||||
return wxFileName(src).GetName();
|
||||
}
|
||||
|
||||
wxString Path::GetDirectory(const wxString &src)
|
||||
wxString Path::GetDirectory(const wxString& src)
|
||||
{
|
||||
return wxFileName(src).GetPath();
|
||||
return wxFileName(src).GetPath();
|
||||
}
|
||||
|
||||
|
||||
// returns the base/root directory of the given path.
|
||||
// Example /this/that/something.txt -> dest == "/"
|
||||
wxString Path::GetRootDirectory(const wxString &src)
|
||||
wxString Path::GetRootDirectory(const wxString& src)
|
||||
{
|
||||
size_t pos = src.find_first_of(wxFileName::GetPathSeparators());
|
||||
if (pos == wxString::npos)
|
||||
return wxString();
|
||||
else
|
||||
return wxString(src.begin(), src.begin() + pos);
|
||||
size_t pos = src.find_first_of(wxFileName::GetPathSeparators());
|
||||
if (pos == wxString::npos)
|
||||
return wxString();
|
||||
else
|
||||
return wxString(src.begin(), src.begin() + pos);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Launches the specified file according to its mime type
|
||||
//
|
||||
void pxLaunch(const wxString &filename)
|
||||
void pxLaunch(const wxString& filename)
|
||||
{
|
||||
wxLaunchDefaultBrowser(filename);
|
||||
wxLaunchDefaultBrowser(filename);
|
||||
}
|
||||
|
||||
void pxLaunch(const char *filename)
|
||||
void pxLaunch(const char* filename)
|
||||
{
|
||||
pxLaunch(fromUTF8(filename));
|
||||
pxLaunch(fromUTF8(filename));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
@ -211,12 +211,12 @@ void pxLaunch(const char *filename)
|
|||
// bypasses wxWidgets internal filename checking, which can end up launching things
|
||||
// through browser more often than desired.
|
||||
//
|
||||
void pxExplore(const wxString &path)
|
||||
void pxExplore(const wxString& path)
|
||||
{
|
||||
wxLaunchDefaultBrowser(!path.Contains(L"://") ? L"file://" + path : path);
|
||||
wxLaunchDefaultBrowser(!path.Contains(L"://") ? L"file://" + path : path);
|
||||
}
|
||||
|
||||
void pxExplore(const char *path)
|
||||
void pxExplore(const char* path)
|
||||
{
|
||||
pxExplore(fromUTF8(path));
|
||||
pxExplore(fromUTF8(path));
|
||||
}
|
||||
|
|
|
@ -60,116 +60,116 @@ typedef unsigned int uint;
|
|||
#ifdef __cplusplus
|
||||
union u128
|
||||
{
|
||||
struct
|
||||
{
|
||||
u64 lo;
|
||||
u64 hi;
|
||||
};
|
||||
struct
|
||||
{
|
||||
u64 lo;
|
||||
u64 hi;
|
||||
};
|
||||
|
||||
u64 _u64[2];
|
||||
u32 _u32[4];
|
||||
u16 _u16[8];
|
||||
u8 _u8[16];
|
||||
u64 _u64[2];
|
||||
u32 _u32[4];
|
||||
u16 _u16[8];
|
||||
u8 _u8[16];
|
||||
|
||||
// Explicit conversion from u64. Zero-extends the source through 128 bits.
|
||||
static u128 From64(u64 src)
|
||||
{
|
||||
u128 retval;
|
||||
retval.lo = src;
|
||||
retval.hi = 0;
|
||||
return retval;
|
||||
}
|
||||
// Explicit conversion from u64. Zero-extends the source through 128 bits.
|
||||
static u128 From64(u64 src)
|
||||
{
|
||||
u128 retval;
|
||||
retval.lo = src;
|
||||
retval.hi = 0;
|
||||
return retval;
|
||||
}
|
||||
|
||||
// Explicit conversion from u32. Zero-extends the source through 128 bits.
|
||||
static u128 From32(u32 src)
|
||||
{
|
||||
u128 retval;
|
||||
retval._u32[0] = src;
|
||||
retval._u32[1] = 0;
|
||||
retval.hi = 0;
|
||||
return retval;
|
||||
}
|
||||
// Explicit conversion from u32. Zero-extends the source through 128 bits.
|
||||
static u128 From32(u32 src)
|
||||
{
|
||||
u128 retval;
|
||||
retval._u32[0] = src;
|
||||
retval._u32[1] = 0;
|
||||
retval.hi = 0;
|
||||
return retval;
|
||||
}
|
||||
|
||||
operator u32() const { return _u32[0]; }
|
||||
operator u16() const { return _u16[0]; }
|
||||
operator u8() const { return _u8[0]; }
|
||||
operator u32() const { return _u32[0]; }
|
||||
operator u16() const { return _u16[0]; }
|
||||
operator u8() const { return _u8[0]; }
|
||||
|
||||
bool operator==(const u128 &right) const
|
||||
{
|
||||
return (lo == right.lo) && (hi == right.hi);
|
||||
}
|
||||
bool operator==(const u128& right) const
|
||||
{
|
||||
return (lo == right.lo) && (hi == right.hi);
|
||||
}
|
||||
|
||||
bool operator!=(const u128 &right) const
|
||||
{
|
||||
return (lo != right.lo) || (hi != right.hi);
|
||||
}
|
||||
bool operator!=(const u128& right) const
|
||||
{
|
||||
return (lo != right.lo) || (hi != right.hi);
|
||||
}
|
||||
|
||||
// In order for the following ToString() and WriteTo methods to be available, you must
|
||||
// be linking to both wxWidgets and the pxWidgets extension library. If you are not
|
||||
// using them, then you will need to provide your own implementations of these methods.
|
||||
wxString ToString() const;
|
||||
wxString ToString64() const;
|
||||
wxString ToString8() const;
|
||||
// In order for the following ToString() and WriteTo methods to be available, you must
|
||||
// be linking to both wxWidgets and the pxWidgets extension library. If you are not
|
||||
// using them, then you will need to provide your own implementations of these methods.
|
||||
wxString ToString() const;
|
||||
wxString ToString64() const;
|
||||
wxString ToString8() const;
|
||||
|
||||
void WriteTo(FastFormatAscii &dest) const;
|
||||
void WriteTo8(FastFormatAscii &dest) const;
|
||||
void WriteTo64(FastFormatAscii &dest) const;
|
||||
void WriteTo(FastFormatAscii& dest) const;
|
||||
void WriteTo8(FastFormatAscii& dest) const;
|
||||
void WriteTo64(FastFormatAscii& dest) const;
|
||||
};
|
||||
|
||||
struct s128
|
||||
{
|
||||
s64 lo;
|
||||
s64 hi;
|
||||
s64 lo;
|
||||
s64 hi;
|
||||
|
||||
// explicit conversion from s64, with sign extension.
|
||||
static s128 From64(s64 src)
|
||||
{
|
||||
s128 retval = {src, (src < 0) ? -1 : 0};
|
||||
return retval;
|
||||
}
|
||||
// explicit conversion from s64, with sign extension.
|
||||
static s128 From64(s64 src)
|
||||
{
|
||||
s128 retval = {src, (src < 0) ? -1 : 0};
|
||||
return retval;
|
||||
}
|
||||
|
||||
// explicit conversion from s32, with sign extension.
|
||||
static s128 From64(s32 src)
|
||||
{
|
||||
s128 retval = {src, (src < 0) ? -1 : 0};
|
||||
return retval;
|
||||
}
|
||||
// explicit conversion from s32, with sign extension.
|
||||
static s128 From64(s32 src)
|
||||
{
|
||||
s128 retval = {src, (src < 0) ? -1 : 0};
|
||||
return retval;
|
||||
}
|
||||
|
||||
operator u32() const { return (s32)lo; }
|
||||
operator u16() const { return (s16)lo; }
|
||||
operator u8() const { return (s8)lo; }
|
||||
operator u32() const { return (s32)lo; }
|
||||
operator u16() const { return (s16)lo; }
|
||||
operator u8() const { return (s8)lo; }
|
||||
|
||||
bool operator==(const s128 &right) const
|
||||
{
|
||||
return (lo == right.lo) && (hi == right.hi);
|
||||
}
|
||||
bool operator==(const s128& right) const
|
||||
{
|
||||
return (lo == right.lo) && (hi == right.hi);
|
||||
}
|
||||
|
||||
bool operator!=(const s128 &right) const
|
||||
{
|
||||
return (lo != right.lo) || (hi != right.hi);
|
||||
}
|
||||
bool operator!=(const s128& right) const
|
||||
{
|
||||
return (lo != right.lo) || (hi != right.hi);
|
||||
}
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
typedef union _u128_t
|
||||
{
|
||||
struct
|
||||
{
|
||||
u64 lo;
|
||||
u64 hi;
|
||||
};
|
||||
struct
|
||||
{
|
||||
u64 lo;
|
||||
u64 hi;
|
||||
};
|
||||
|
||||
u64 _u64[2];
|
||||
u32 _u32[4];
|
||||
u16 _u16[8];
|
||||
u8 _u8[16];
|
||||
u64 _u64[2];
|
||||
u32 _u32[4];
|
||||
u16 _u16[8];
|
||||
u8 _u8[16];
|
||||
} u128;
|
||||
|
||||
typedef union _s128_t
|
||||
{
|
||||
u64 lo;
|
||||
s64 hi;
|
||||
u64 lo;
|
||||
s64 hi;
|
||||
} s128;
|
||||
|
||||
#endif
|
||||
|
|
225
common/Perf.cpp
225
common/Perf.cpp
|
@ -33,174 +33,175 @@
|
|||
|
||||
namespace Perf
|
||||
{
|
||||
// Warning object aren't thread safe
|
||||
InfoVector any("");
|
||||
InfoVector ee("EE");
|
||||
InfoVector iop("IOP");
|
||||
InfoVector vu("VU");
|
||||
InfoVector vif("VIF");
|
||||
// Warning object aren't thread safe
|
||||
InfoVector any("");
|
||||
InfoVector ee("EE");
|
||||
InfoVector iop("IOP");
|
||||
InfoVector vu("VU");
|
||||
InfoVector vif("VIF");
|
||||
|
||||
// Perf is only supported on linux
|
||||
#if defined(__linux__) && (defined(ProfileWithPerf) || defined(ENABLE_VTUNE))
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Implementation of the Info object
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Implementation of the Info object
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Info::Info(uptr x86, u32 size, const char *symbol)
|
||||
: m_x86(x86)
|
||||
, m_size(size)
|
||||
, m_dynamic(false)
|
||||
{
|
||||
strncpy(m_symbol, symbol, sizeof(m_symbol));
|
||||
}
|
||||
Info::Info(uptr x86, u32 size, const char* symbol)
|
||||
: m_x86(x86)
|
||||
, m_size(size)
|
||||
, m_dynamic(false)
|
||||
{
|
||||
strncpy(m_symbol, symbol, sizeof(m_symbol));
|
||||
}
|
||||
|
||||
Info::Info(uptr x86, u32 size, const char *symbol, u32 pc)
|
||||
: m_x86(x86)
|
||||
, m_size(size)
|
||||
, m_dynamic(true)
|
||||
{
|
||||
snprintf(m_symbol, sizeof(m_symbol), "%s_0x%08x", symbol, pc);
|
||||
}
|
||||
Info::Info(uptr x86, u32 size, const char* symbol, u32 pc)
|
||||
: m_x86(x86)
|
||||
, m_size(size)
|
||||
, m_dynamic(true)
|
||||
{
|
||||
snprintf(m_symbol, sizeof(m_symbol), "%s_0x%08x", symbol, pc);
|
||||
}
|
||||
|
||||
void Info::Print(FILE *fp)
|
||||
{
|
||||
fprintf(fp, "%x %x %s\n", m_x86, m_size, m_symbol);
|
||||
}
|
||||
void Info::Print(FILE* fp)
|
||||
{
|
||||
fprintf(fp, "%x %x %s\n", m_x86, m_size, m_symbol);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Implementation of the InfoVector object
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Implementation of the InfoVector object
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
InfoVector::InfoVector(const char *prefix)
|
||||
{
|
||||
strncpy(m_prefix, prefix, sizeof(m_prefix));
|
||||
InfoVector::InfoVector(const char* prefix)
|
||||
{
|
||||
strncpy(m_prefix, prefix, sizeof(m_prefix));
|
||||
#ifdef ENABLE_VTUNE
|
||||
m_vtune_id = iJIT_GetNewMethodID();
|
||||
m_vtune_id = iJIT_GetNewMethodID();
|
||||
#else
|
||||
m_vtune_id = 0;
|
||||
m_vtune_id = 0;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void InfoVector::print(FILE *fp)
|
||||
{
|
||||
for (auto &&it : m_v)
|
||||
it.Print(fp);
|
||||
}
|
||||
void InfoVector::print(FILE* fp)
|
||||
{
|
||||
for (auto&& it : m_v)
|
||||
it.Print(fp);
|
||||
}
|
||||
|
||||
void InfoVector::map(uptr x86, u32 size, const char *symbol)
|
||||
{
|
||||
void InfoVector::map(uptr x86, u32 size, const char* symbol)
|
||||
{
|
||||
// This function is typically used for dispatcher and recompiler.
|
||||
// Dispatchers are on a page and must always be kept.
|
||||
// Recompilers are much bigger (TODO check VIF) and are only
|
||||
// useful when MERGE_BLOCK_RESULT is defined
|
||||
#if defined(ENABLE_VTUNE) || !defined(MERGE_BLOCK_RESULT)
|
||||
u32 max_code_size = 16 * _1kb;
|
||||
u32 max_code_size = 16 * _1kb;
|
||||
#else
|
||||
u32 max_code_size = _1gb;
|
||||
u32 max_code_size = _1gb;
|
||||
#endif
|
||||
|
||||
if (size < max_code_size) {
|
||||
m_v.emplace_back(x86, size, symbol);
|
||||
if (size < max_code_size)
|
||||
{
|
||||
m_v.emplace_back(x86, size, symbol);
|
||||
|
||||
#ifdef ENABLE_VTUNE
|
||||
std::string name = std::string(symbol);
|
||||
std::string name = std::string(symbol);
|
||||
|
||||
iJIT_Method_Load ml;
|
||||
iJIT_Method_Load ml;
|
||||
|
||||
memset(&ml, 0, sizeof(ml));
|
||||
memset(&ml, 0, sizeof(ml));
|
||||
|
||||
ml.method_id = iJIT_GetNewMethodID();
|
||||
ml.method_name = (char *)name.c_str();
|
||||
ml.method_load_address = (void *)x86;
|
||||
ml.method_size = size;
|
||||
ml.method_id = iJIT_GetNewMethodID();
|
||||
ml.method_name = (char*)name.c_str();
|
||||
ml.method_load_address = (void*)x86;
|
||||
ml.method_size = size;
|
||||
|
||||
iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, &ml);
|
||||
iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, &ml);
|
||||
|
||||
//fprintf(stderr, "mapF %s: %p size %dKB\n", ml.method_name, ml.method_load_address, ml.method_size / 1024u);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InfoVector::map(uptr x86, u32 size, u32 pc)
|
||||
{
|
||||
void InfoVector::map(uptr x86, u32 size, u32 pc)
|
||||
{
|
||||
#ifndef MERGE_BLOCK_RESULT
|
||||
m_v.emplace_back(x86, size, m_prefix, pc);
|
||||
m_v.emplace_back(x86, size, m_prefix, pc);
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_VTUNE
|
||||
iJIT_Method_Load_V2 ml;
|
||||
iJIT_Method_Load_V2 ml;
|
||||
|
||||
memset(&ml, 0, sizeof(ml));
|
||||
memset(&ml, 0, sizeof(ml));
|
||||
|
||||
#ifdef MERGE_BLOCK_RESULT
|
||||
ml.method_id = m_vtune_id;
|
||||
ml.method_name = m_prefix;
|
||||
ml.method_id = m_vtune_id;
|
||||
ml.method_name = m_prefix;
|
||||
#else
|
||||
std::string name = std::string(m_prefix) + "_" + std::to_string(pc);
|
||||
ml.method_id = iJIT_GetNewMethodID();
|
||||
ml.method_name = (char *)name.c_str();
|
||||
std::string name = std::string(m_prefix) + "_" + std::to_string(pc);
|
||||
ml.method_id = iJIT_GetNewMethodID();
|
||||
ml.method_name = (char*)name.c_str();
|
||||
#endif
|
||||
ml.method_load_address = (void *)x86;
|
||||
ml.method_size = size;
|
||||
ml.method_load_address = (void*)x86;
|
||||
ml.method_size = size;
|
||||
|
||||
iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED_V2, &ml);
|
||||
iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED_V2, &ml);
|
||||
|
||||
//fprintf(stderr, "mapB %s: %p size %d\n", ml.method_name, ml.method_load_address, ml.method_size);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void InfoVector::reset()
|
||||
{
|
||||
auto dynamic = std::remove_if(m_v.begin(), m_v.end(), [](Info i) { return i.m_dynamic; });
|
||||
m_v.erase(dynamic, m_v.end());
|
||||
}
|
||||
void InfoVector::reset()
|
||||
{
|
||||
auto dynamic = std::remove_if(m_v.begin(), m_v.end(), [](Info i) { return i.m_dynamic; });
|
||||
m_v.erase(dynamic, m_v.end());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Global function
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Global function
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void dump()
|
||||
{
|
||||
char file[256];
|
||||
snprintf(file, 250, "/tmp/perf-%d.map", getpid());
|
||||
FILE *fp = fopen(file, "w");
|
||||
void dump()
|
||||
{
|
||||
char file[256];
|
||||
snprintf(file, 250, "/tmp/perf-%d.map", getpid());
|
||||
FILE* fp = fopen(file, "w");
|
||||
|
||||
any.print(fp);
|
||||
ee.print(fp);
|
||||
iop.print(fp);
|
||||
vu.print(fp);
|
||||
any.print(fp);
|
||||
ee.print(fp);
|
||||
iop.print(fp);
|
||||
vu.print(fp);
|
||||
|
||||
if (fp)
|
||||
fclose(fp);
|
||||
}
|
||||
if (fp)
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
void dump_and_reset()
|
||||
{
|
||||
dump();
|
||||
void dump_and_reset()
|
||||
{
|
||||
dump();
|
||||
|
||||
any.reset();
|
||||
ee.reset();
|
||||
iop.reset();
|
||||
vu.reset();
|
||||
}
|
||||
any.reset();
|
||||
ee.reset();
|
||||
iop.reset();
|
||||
vu.reset();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Dummy implementation
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Dummy implementation
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
InfoVector::InfoVector(const char *prefix)
|
||||
: m_vtune_id(0)
|
||||
{
|
||||
}
|
||||
void InfoVector::map(uptr x86, u32 size, const char *symbol) {}
|
||||
void InfoVector::map(uptr x86, u32 size, u32 pc) {}
|
||||
void InfoVector::reset() {}
|
||||
InfoVector::InfoVector(const char* prefix)
|
||||
: m_vtune_id(0)
|
||||
{
|
||||
}
|
||||
void InfoVector::map(uptr x86, u32 size, const char* symbol) {}
|
||||
void InfoVector::map(uptr x86, u32 size, u32 pc) {}
|
||||
void InfoVector::reset() {}
|
||||
|
||||
void dump() {}
|
||||
void dump_and_reset() {}
|
||||
void dump() {}
|
||||
void dump_and_reset() {}
|
||||
|
||||
#endif
|
||||
}
|
||||
} // namespace Perf
|
||||
|
|
|
@ -22,41 +22,41 @@
|
|||
namespace Perf
|
||||
{
|
||||
|
||||
struct Info
|
||||
{
|
||||
uptr m_x86;
|
||||
u32 m_size;
|
||||
char m_symbol[20];
|
||||
// The idea is to keep static zones that are set only
|
||||
// once.
|
||||
bool m_dynamic;
|
||||
struct Info
|
||||
{
|
||||
uptr m_x86;
|
||||
u32 m_size;
|
||||
char m_symbol[20];
|
||||
// The idea is to keep static zones that are set only
|
||||
// once.
|
||||
bool m_dynamic;
|
||||
|
||||
Info(uptr x86, u32 size, const char *symbol);
|
||||
Info(uptr x86, u32 size, const char *symbol, u32 pc);
|
||||
void Print(FILE *fp);
|
||||
};
|
||||
Info(uptr x86, u32 size, const char* symbol);
|
||||
Info(uptr x86, u32 size, const char* symbol, u32 pc);
|
||||
void Print(FILE* fp);
|
||||
};
|
||||
|
||||
class InfoVector
|
||||
{
|
||||
std::vector<Info> m_v;
|
||||
char m_prefix[20];
|
||||
unsigned int m_vtune_id;
|
||||
class InfoVector
|
||||
{
|
||||
std::vector<Info> m_v;
|
||||
char m_prefix[20];
|
||||
unsigned int m_vtune_id;
|
||||
|
||||
public:
|
||||
InfoVector(const char *prefix);
|
||||
public:
|
||||
InfoVector(const char* prefix);
|
||||
|
||||
void print(FILE *fp);
|
||||
void map(uptr x86, u32 size, const char *symbol);
|
||||
void map(uptr x86, u32 size, u32 pc);
|
||||
void reset();
|
||||
};
|
||||
void print(FILE* fp);
|
||||
void map(uptr x86, u32 size, const char* symbol);
|
||||
void map(uptr x86, u32 size, u32 pc);
|
||||
void reset();
|
||||
};
|
||||
|
||||
void dump();
|
||||
void dump_and_reset();
|
||||
void dump();
|
||||
void dump_and_reset();
|
||||
|
||||
extern InfoVector any;
|
||||
extern InfoVector ee;
|
||||
extern InfoVector iop;
|
||||
extern InfoVector vu;
|
||||
extern InfoVector vif;
|
||||
}
|
||||
extern InfoVector any;
|
||||
extern InfoVector ee;
|
||||
extern InfoVector iop;
|
||||
extern InfoVector vu;
|
||||
extern InfoVector vif;
|
||||
} // namespace Perf
|
||||
|
|
|
@ -22,188 +22,188 @@
|
|||
namespace Threading
|
||||
{
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// ThreadDeleteEvent
|
||||
// --------------------------------------------------------------------------------------
|
||||
class EventListener_Thread : public IEventDispatcher<int>
|
||||
{
|
||||
public:
|
||||
typedef int EvtParams;
|
||||
// --------------------------------------------------------------------------------------
|
||||
// ThreadDeleteEvent
|
||||
// --------------------------------------------------------------------------------------
|
||||
class EventListener_Thread : public IEventDispatcher<int>
|
||||
{
|
||||
public:
|
||||
typedef int EvtParams;
|
||||
|
||||
protected:
|
||||
pxThread *m_thread;
|
||||
protected:
|
||||
pxThread* m_thread;
|
||||
|
||||
public:
|
||||
EventListener_Thread()
|
||||
{
|
||||
m_thread = NULL;
|
||||
}
|
||||
public:
|
||||
EventListener_Thread()
|
||||
{
|
||||
m_thread = NULL;
|
||||
}
|
||||
|
||||
virtual ~EventListener_Thread() = default;
|
||||
virtual ~EventListener_Thread() = default;
|
||||
|
||||
void SetThread(pxThread &thr) { m_thread = &thr; }
|
||||
void SetThread(pxThread *thr) { m_thread = thr; }
|
||||
void SetThread(pxThread& thr) { m_thread = &thr; }
|
||||
void SetThread(pxThread* thr) { m_thread = thr; }
|
||||
|
||||
void DispatchEvent(const int ¶ms)
|
||||
{
|
||||
OnThreadCleanup();
|
||||
}
|
||||
void DispatchEvent(const int& params)
|
||||
{
|
||||
OnThreadCleanup();
|
||||
}
|
||||
|
||||
protected:
|
||||
// Invoked by the pxThread when the thread execution is ending. This is
|
||||
// typically more useful than a delete listener since the extended thread information
|
||||
// provided by virtualized functions/methods will be available.
|
||||
// Important! This event is executed *by the thread*, so care must be taken to ensure
|
||||
// thread sync when necessary (posting messages to the main thread, etc).
|
||||
virtual void OnThreadCleanup() = 0;
|
||||
};
|
||||
protected:
|
||||
// Invoked by the pxThread when the thread execution is ending. This is
|
||||
// typically more useful than a delete listener since the extended thread information
|
||||
// provided by virtualized functions/methods will be available.
|
||||
// Important! This event is executed *by the thread*, so care must be taken to ensure
|
||||
// thread sync when necessary (posting messages to the main thread, etc).
|
||||
virtual void OnThreadCleanup() = 0;
|
||||
};
|
||||
|
||||
/// Set the name of the current thread
|
||||
void SetNameOfCurrentThread(const char* name);
|
||||
/// Set the name of the current thread
|
||||
void SetNameOfCurrentThread(const char* name);
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// pxThread - Helper class for the basics of starting/managing persistent threads.
|
||||
// --------------------------------------------------------------------------------------
|
||||
// This class is meant to be a helper for the typical threading model of "start once and
|
||||
// reuse many times." This class incorporates a lot of extra overhead in stopping and
|
||||
// starting threads, but in turn provides most of the basic thread-safety and event-handling
|
||||
// functionality needed for a threaded operation. In practice this model is usually an
|
||||
// ideal one for efficiency since Operating Systems themselves typically subscribe to a
|
||||
// design where sleeping, suspending, and resuming threads is very efficient, but starting
|
||||
// new threads has quite a bit of overhead.
|
||||
//
|
||||
// To use this as a base class for your threaded procedure, overload the following virtual
|
||||
// methods:
|
||||
// void OnStart();
|
||||
// void ExecuteTaskInThread();
|
||||
// void OnCleanupInThread();
|
||||
//
|
||||
// Use the public methods Start() and Cancel() to start and shutdown the thread, and use
|
||||
// m_sem_event internally to post/receive events for the thread (make a public accessor for
|
||||
// it in your derived class if your thread utilizes the post).
|
||||
//
|
||||
// Notes:
|
||||
// * Constructing threads as static global vars isn't recommended since it can potentially
|
||||
// confuse w32pthreads, if the static initializers are executed out-of-order (C++ offers
|
||||
// no dependency options for ensuring correct static var initializations). Use heap
|
||||
// allocation to create thread objects instead.
|
||||
//
|
||||
class pxThread
|
||||
{
|
||||
DeclareNoncopyableObject(pxThread);
|
||||
// --------------------------------------------------------------------------------------
|
||||
// pxThread - Helper class for the basics of starting/managing persistent threads.
|
||||
// --------------------------------------------------------------------------------------
|
||||
// This class is meant to be a helper for the typical threading model of "start once and
|
||||
// reuse many times." This class incorporates a lot of extra overhead in stopping and
|
||||
// starting threads, but in turn provides most of the basic thread-safety and event-handling
|
||||
// functionality needed for a threaded operation. In practice this model is usually an
|
||||
// ideal one for efficiency since Operating Systems themselves typically subscribe to a
|
||||
// design where sleeping, suspending, and resuming threads is very efficient, but starting
|
||||
// new threads has quite a bit of overhead.
|
||||
//
|
||||
// To use this as a base class for your threaded procedure, overload the following virtual
|
||||
// methods:
|
||||
// void OnStart();
|
||||
// void ExecuteTaskInThread();
|
||||
// void OnCleanupInThread();
|
||||
//
|
||||
// Use the public methods Start() and Cancel() to start and shutdown the thread, and use
|
||||
// m_sem_event internally to post/receive events for the thread (make a public accessor for
|
||||
// it in your derived class if your thread utilizes the post).
|
||||
//
|
||||
// Notes:
|
||||
// * Constructing threads as static global vars isn't recommended since it can potentially
|
||||
// confuse w32pthreads, if the static initializers are executed out-of-order (C++ offers
|
||||
// no dependency options for ensuring correct static var initializations). Use heap
|
||||
// allocation to create thread objects instead.
|
||||
//
|
||||
class pxThread
|
||||
{
|
||||
DeclareNoncopyableObject(pxThread);
|
||||
|
||||
friend void pxYield(int ms);
|
||||
friend void pxYield(int ms);
|
||||
|
||||
protected:
|
||||
wxString m_name; // diagnostic name for our thread.
|
||||
pthread_t m_thread;
|
||||
uptr m_native_id; // typically an id, but implementing platforms can do whatever.
|
||||
uptr m_native_handle; // typically a pointer/handle, but implementing platforms can do whatever.
|
||||
protected:
|
||||
wxString m_name; // diagnostic name for our thread.
|
||||
pthread_t m_thread;
|
||||
uptr m_native_id; // typically an id, but implementing platforms can do whatever.
|
||||
uptr m_native_handle; // typically a pointer/handle, but implementing platforms can do whatever.
|
||||
|
||||
Semaphore m_sem_event; // general wait event that's needed by most threads
|
||||
Semaphore m_sem_startup; // startup sync tool
|
||||
Mutex m_mtx_InThread; // used for canceling and closing threads in a deadlock-safe manner
|
||||
MutexRecursive m_mtx_start; // used to lock the Start() code from starting simultaneous threads accidentally.
|
||||
Mutex m_mtx_ThreadName;
|
||||
Semaphore m_sem_event; // general wait event that's needed by most threads
|
||||
Semaphore m_sem_startup; // startup sync tool
|
||||
Mutex m_mtx_InThread; // used for canceling and closing threads in a deadlock-safe manner
|
||||
MutexRecursive m_mtx_start; // used to lock the Start() code from starting simultaneous threads accidentally.
|
||||
Mutex m_mtx_ThreadName;
|
||||
|
||||
std::atomic<bool> m_detached; // a boolean value which indicates if the m_thread handle is valid
|
||||
std::atomic<bool> m_running; // set true by Start(), and set false by Cancel(), Block(), etc.
|
||||
std::atomic<bool> m_detached; // a boolean value which indicates if the m_thread handle is valid
|
||||
std::atomic<bool> m_running; // set true by Start(), and set false by Cancel(), Block(), etc.
|
||||
|
||||
// exception handle, set non-NULL if the thread terminated with an exception
|
||||
// Use RethrowException() to re-throw the exception using its original exception type.
|
||||
ScopedPtrMT<BaseException> m_except;
|
||||
// exception handle, set non-NULL if the thread terminated with an exception
|
||||
// Use RethrowException() to re-throw the exception using its original exception type.
|
||||
ScopedPtrMT<BaseException> m_except;
|
||||
|
||||
EventSource<EventListener_Thread> m_evtsrc_OnDelete;
|
||||
EventSource<EventListener_Thread> m_evtsrc_OnDelete;
|
||||
|
||||
|
||||
public:
|
||||
virtual ~pxThread();
|
||||
pxThread(const wxString &name = L"pxThread");
|
||||
public:
|
||||
virtual ~pxThread();
|
||||
pxThread(const wxString& name = L"pxThread");
|
||||
|
||||
pthread_t GetId() const { return m_thread; }
|
||||
u64 GetCpuTime() const;
|
||||
pthread_t GetId() const { return m_thread; }
|
||||
u64 GetCpuTime() const;
|
||||
|
||||
virtual void Start();
|
||||
virtual void Cancel(bool isBlocking = true);
|
||||
virtual bool Cancel(const wxTimeSpan &timeout);
|
||||
virtual bool Detach();
|
||||
virtual void Block();
|
||||
virtual bool Block(const wxTimeSpan &timeout);
|
||||
virtual void RethrowException() const;
|
||||
virtual void Start();
|
||||
virtual void Cancel(bool isBlocking = true);
|
||||
virtual bool Cancel(const wxTimeSpan& timeout);
|
||||
virtual bool Detach();
|
||||
virtual void Block();
|
||||
virtual bool Block(const wxTimeSpan& timeout);
|
||||
virtual void RethrowException() const;
|
||||
|
||||
void AddListener(EventListener_Thread &evt);
|
||||
void AddListener(EventListener_Thread *evt)
|
||||
{
|
||||
if (evt == NULL)
|
||||
return;
|
||||
AddListener(*evt);
|
||||
}
|
||||
void AddListener(EventListener_Thread& evt);
|
||||
void AddListener(EventListener_Thread* evt)
|
||||
{
|
||||
if (evt == NULL)
|
||||
return;
|
||||
AddListener(*evt);
|
||||
}
|
||||
|
||||
void WaitOnSelf(Semaphore &mutex) const;
|
||||
void WaitOnSelf(Mutex &mutex) const;
|
||||
bool WaitOnSelf(Semaphore &mutex, const wxTimeSpan &timeout) const;
|
||||
bool WaitOnSelf(Mutex &mutex, const wxTimeSpan &timeout) const;
|
||||
void WaitOnSelf(Semaphore& mutex) const;
|
||||
void WaitOnSelf(Mutex& mutex) const;
|
||||
bool WaitOnSelf(Semaphore& mutex, const wxTimeSpan& timeout) const;
|
||||
bool WaitOnSelf(Mutex& mutex, const wxTimeSpan& timeout) const;
|
||||
|
||||
bool IsRunning() const;
|
||||
bool IsSelf() const;
|
||||
bool HasPendingException() const { return !!m_except; }
|
||||
bool IsRunning() const;
|
||||
bool IsSelf() const;
|
||||
bool HasPendingException() const { return !!m_except; }
|
||||
|
||||
wxString GetName() const;
|
||||
void SetName(const wxString &newname);
|
||||
wxString GetName() const;
|
||||
void SetName(const wxString& newname);
|
||||
|
||||
protected:
|
||||
// Extending classes should always implement your own OnStart(), which is called by
|
||||
// Start() once necessary locks have been obtained. Do not override Start() directly
|
||||
// unless you're really sure that's what you need to do. ;)
|
||||
virtual void OnStart();
|
||||
protected:
|
||||
// Extending classes should always implement your own OnStart(), which is called by
|
||||
// Start() once necessary locks have been obtained. Do not override Start() directly
|
||||
// unless you're really sure that's what you need to do. ;)
|
||||
virtual void OnStart();
|
||||
|
||||
virtual void OnStartInThread();
|
||||
virtual void OnStartInThread();
|
||||
|
||||
// This is called when the thread has been canceled or exits normally. The pxThread
|
||||
// automatically binds it to the pthread cleanup routines as soon as the thread starts.
|
||||
virtual void OnCleanupInThread();
|
||||
// This is called when the thread has been canceled or exits normally. The pxThread
|
||||
// automatically binds it to the pthread cleanup routines as soon as the thread starts.
|
||||
virtual void OnCleanupInThread();
|
||||
|
||||
// Implemented by derived class to perform actual threaded task!
|
||||
virtual void ExecuteTaskInThread() = 0;
|
||||
// Implemented by derived class to perform actual threaded task!
|
||||
virtual void ExecuteTaskInThread() = 0;
|
||||
|
||||
void TestCancel() const;
|
||||
void TestCancel() const;
|
||||
|
||||
// Yields this thread to other threads and checks for cancellation. A sleeping thread should
|
||||
// always test for cancellation, however if you really don't want to, you can use Threading::Sleep()
|
||||
// or better yet, disable cancellation of the thread completely with DisableCancellation().
|
||||
//
|
||||
// Parameters:
|
||||
// ms - 'minimum' yield time in milliseconds (rough -- typically yields are longer by 1-5ms
|
||||
// depending on operating system/platform). If ms is 0 or unspecified, then a single
|
||||
// timeslice is yielded to other contending threads. If no threads are contending for
|
||||
// time when ms==0, then no yield is done, but cancellation is still tested.
|
||||
void Yield(int ms = 0)
|
||||
{
|
||||
pxAssert(IsSelf());
|
||||
Threading::Sleep(ms);
|
||||
TestCancel();
|
||||
}
|
||||
// Yields this thread to other threads and checks for cancellation. A sleeping thread should
|
||||
// always test for cancellation, however if you really don't want to, you can use Threading::Sleep()
|
||||
// or better yet, disable cancellation of the thread completely with DisableCancellation().
|
||||
//
|
||||
// Parameters:
|
||||
// ms - 'minimum' yield time in milliseconds (rough -- typically yields are longer by 1-5ms
|
||||
// depending on operating system/platform). If ms is 0 or unspecified, then a single
|
||||
// timeslice is yielded to other contending threads. If no threads are contending for
|
||||
// time when ms==0, then no yield is done, but cancellation is still tested.
|
||||
void Yield(int ms = 0)
|
||||
{
|
||||
pxAssert(IsSelf());
|
||||
Threading::Sleep(ms);
|
||||
TestCancel();
|
||||
}
|
||||
|
||||
void FrankenMutex(Mutex &mutex);
|
||||
void FrankenMutex(Mutex& mutex);
|
||||
|
||||
bool AffinityAssert_AllowFromSelf(const DiagnosticOrigin &origin) const;
|
||||
bool AffinityAssert_DisallowFromSelf(const DiagnosticOrigin &origin) const;
|
||||
bool AffinityAssert_AllowFromSelf(const DiagnosticOrigin& origin) const;
|
||||
bool AffinityAssert_DisallowFromSelf(const DiagnosticOrigin& origin) const;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Section of methods for internal use only.
|
||||
// ----------------------------------------------------------------------------
|
||||
// Section of methods for internal use only.
|
||||
|
||||
void _platform_specific_OnStartInThread();
|
||||
void _platform_specific_OnCleanupInThread();
|
||||
bool _basecancel();
|
||||
void _selfRunningTest(const wxChar *name) const;
|
||||
void _DoSetThreadName(const wxString &name);
|
||||
void _DoSetThreadName(const char *name) { SetNameOfCurrentThread(name); }
|
||||
void _internal_execute();
|
||||
void _try_virtual_invoke(void (pxThread::*method)());
|
||||
void _ThreadCleanup();
|
||||
void _platform_specific_OnStartInThread();
|
||||
void _platform_specific_OnCleanupInThread();
|
||||
bool _basecancel();
|
||||
void _selfRunningTest(const wxChar* name) const;
|
||||
void _DoSetThreadName(const wxString& name);
|
||||
void _DoSetThreadName(const char* name) { SetNameOfCurrentThread(name); }
|
||||
void _internal_execute();
|
||||
void _try_virtual_invoke(void (pxThread::*method)());
|
||||
void _ThreadCleanup();
|
||||
|
||||
static void *_internal_callback(void *func);
|
||||
static void internal_callback_helper(void *func);
|
||||
static void _pt_callback_cleanup(void *handle);
|
||||
};
|
||||
}
|
||||
static void* _internal_callback(void* func);
|
||||
static void internal_callback_helper(void* func);
|
||||
static void _pt_callback_cleanup(void* handle);
|
||||
};
|
||||
} // namespace Threading
|
||||
|
|
|
@ -20,37 +20,37 @@
|
|||
// --------------------------------------------------------------------------------------
|
||||
Threading::RwMutex::RwMutex()
|
||||
{
|
||||
pthread_rwlock_init(&m_rwlock, NULL);
|
||||
pthread_rwlock_init(&m_rwlock, NULL);
|
||||
}
|
||||
|
||||
Threading::RwMutex::~RwMutex()
|
||||
{
|
||||
pthread_rwlock_destroy(&m_rwlock);
|
||||
pthread_rwlock_destroy(&m_rwlock);
|
||||
}
|
||||
|
||||
void Threading::RwMutex::AcquireRead()
|
||||
{
|
||||
pthread_rwlock_rdlock(&m_rwlock);
|
||||
pthread_rwlock_rdlock(&m_rwlock);
|
||||
}
|
||||
|
||||
void Threading::RwMutex::AcquireWrite()
|
||||
{
|
||||
pthread_rwlock_wrlock(&m_rwlock);
|
||||
pthread_rwlock_wrlock(&m_rwlock);
|
||||
}
|
||||
|
||||
bool Threading::RwMutex::TryAcquireRead()
|
||||
{
|
||||
return pthread_rwlock_tryrdlock(&m_rwlock) != EBUSY;
|
||||
return pthread_rwlock_tryrdlock(&m_rwlock) != EBUSY;
|
||||
}
|
||||
|
||||
bool Threading::RwMutex::TryAcquireWrite()
|
||||
{
|
||||
return pthread_rwlock_trywrlock(&m_rwlock) != EBUSY;
|
||||
return pthread_rwlock_trywrlock(&m_rwlock) != EBUSY;
|
||||
}
|
||||
|
||||
void Threading::RwMutex::Release()
|
||||
{
|
||||
pthread_rwlock_unlock(&m_rwlock);
|
||||
pthread_rwlock_unlock(&m_rwlock);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -58,57 +58,57 @@ void Threading::RwMutex::Release()
|
|||
// --------------------------------------------------------------------------------------
|
||||
Threading::BaseScopedReadWriteLock::~BaseScopedReadWriteLock()
|
||||
{
|
||||
if (m_IsLocked)
|
||||
m_lock.Release();
|
||||
if (m_IsLocked)
|
||||
m_lock.Release();
|
||||
}
|
||||
|
||||
// Provides manual unlocking of a scoped lock prior to object destruction.
|
||||
void Threading::BaseScopedReadWriteLock::Release()
|
||||
{
|
||||
if (!m_IsLocked)
|
||||
return;
|
||||
m_IsLocked = false;
|
||||
m_lock.Release();
|
||||
if (!m_IsLocked)
|
||||
return;
|
||||
m_IsLocked = false;
|
||||
m_lock.Release();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// ScopedReadLock / ScopedWriteLock
|
||||
// --------------------------------------------------------------------------------------
|
||||
Threading::ScopedReadLock::ScopedReadLock(RwMutex &locker)
|
||||
: BaseScopedReadWriteLock(locker)
|
||||
Threading::ScopedReadLock::ScopedReadLock(RwMutex& locker)
|
||||
: BaseScopedReadWriteLock(locker)
|
||||
{
|
||||
m_IsLocked = true;
|
||||
m_lock.AcquireRead();
|
||||
m_IsLocked = true;
|
||||
m_lock.AcquireRead();
|
||||
}
|
||||
|
||||
// provides manual locking of a scoped lock, to re-lock after a manual unlocking.
|
||||
void Threading::ScopedReadLock::Acquire()
|
||||
{
|
||||
if (m_IsLocked)
|
||||
return;
|
||||
m_lock.AcquireRead();
|
||||
m_IsLocked = true;
|
||||
if (m_IsLocked)
|
||||
return;
|
||||
m_lock.AcquireRead();
|
||||
m_IsLocked = true;
|
||||
}
|
||||
|
||||
Threading::ScopedWriteLock::ScopedWriteLock(RwMutex &locker)
|
||||
: BaseScopedReadWriteLock(locker)
|
||||
Threading::ScopedWriteLock::ScopedWriteLock(RwMutex& locker)
|
||||
: BaseScopedReadWriteLock(locker)
|
||||
{
|
||||
m_IsLocked = true;
|
||||
m_lock.AcquireWrite();
|
||||
m_IsLocked = true;
|
||||
m_lock.AcquireWrite();
|
||||
}
|
||||
|
||||
// provides manual locking of a scoped lock, to re-lock after a manual unlocking.
|
||||
void Threading::ScopedWriteLock::Acquire()
|
||||
{
|
||||
if (m_IsLocked)
|
||||
return;
|
||||
m_lock.AcquireWrite();
|
||||
m_IsLocked = true;
|
||||
if (m_IsLocked)
|
||||
return;
|
||||
m_lock.AcquireWrite();
|
||||
m_IsLocked = true;
|
||||
}
|
||||
|
||||
// Special constructor used by ScopedTryLock
|
||||
Threading::ScopedWriteLock::ScopedWriteLock(RwMutex &locker, bool isTryLock)
|
||||
: BaseScopedReadWriteLock(locker)
|
||||
Threading::ScopedWriteLock::ScopedWriteLock(RwMutex& locker, bool isTryLock)
|
||||
: BaseScopedReadWriteLock(locker)
|
||||
{
|
||||
//m_IsLocked = isTryLock ? m_lock.TryAcquireWrite() : false;
|
||||
//m_IsLocked = isTryLock ? m_lock.TryAcquireWrite() : false;
|
||||
}
|
||||
|
|
110
common/RwMutex.h
110
common/RwMutex.h
|
@ -19,72 +19,72 @@
|
|||
|
||||
namespace Threading
|
||||
{
|
||||
// --------------------------------------------------------------------------------------
|
||||
// RwMutex
|
||||
// --------------------------------------------------------------------------------------
|
||||
class RwMutex
|
||||
{
|
||||
DeclareNoncopyableObject(RwMutex);
|
||||
// --------------------------------------------------------------------------------------
|
||||
// RwMutex
|
||||
// --------------------------------------------------------------------------------------
|
||||
class RwMutex
|
||||
{
|
||||
DeclareNoncopyableObject(RwMutex);
|
||||
|
||||
protected:
|
||||
pthread_rwlock_t m_rwlock;
|
||||
protected:
|
||||
pthread_rwlock_t m_rwlock;
|
||||
|
||||
public:
|
||||
RwMutex();
|
||||
virtual ~RwMutex();
|
||||
public:
|
||||
RwMutex();
|
||||
virtual ~RwMutex();
|
||||
|
||||
virtual void AcquireRead();
|
||||
virtual void AcquireWrite();
|
||||
virtual bool TryAcquireRead();
|
||||
virtual bool TryAcquireWrite();
|
||||
virtual void AcquireRead();
|
||||
virtual void AcquireWrite();
|
||||
virtual bool TryAcquireRead();
|
||||
virtual bool TryAcquireWrite();
|
||||
|
||||
virtual void Release();
|
||||
};
|
||||
virtual void Release();
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// BaseScopedReadWriteLock
|
||||
// --------------------------------------------------------------------------------------
|
||||
class BaseScopedReadWriteLock
|
||||
{
|
||||
DeclareNoncopyableObject(BaseScopedReadWriteLock);
|
||||
// --------------------------------------------------------------------------------------
|
||||
// BaseScopedReadWriteLock
|
||||
// --------------------------------------------------------------------------------------
|
||||
class BaseScopedReadWriteLock
|
||||
{
|
||||
DeclareNoncopyableObject(BaseScopedReadWriteLock);
|
||||
|
||||
protected:
|
||||
RwMutex &m_lock;
|
||||
bool m_IsLocked;
|
||||
protected:
|
||||
RwMutex& m_lock;
|
||||
bool m_IsLocked;
|
||||
|
||||
public:
|
||||
BaseScopedReadWriteLock(RwMutex &locker)
|
||||
: m_lock(locker)
|
||||
{
|
||||
}
|
||||
public:
|
||||
BaseScopedReadWriteLock(RwMutex& locker)
|
||||
: m_lock(locker)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~BaseScopedReadWriteLock();
|
||||
virtual ~BaseScopedReadWriteLock();
|
||||
|
||||
void Release();
|
||||
bool IsLocked() const { return m_IsLocked; }
|
||||
};
|
||||
void Release();
|
||||
bool IsLocked() const { return m_IsLocked; }
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// ScopedReadLock / ScopedWriteLock
|
||||
// --------------------------------------------------------------------------------------
|
||||
class ScopedReadLock : public BaseScopedReadWriteLock
|
||||
{
|
||||
public:
|
||||
ScopedReadLock(RwMutex &locker);
|
||||
virtual ~ScopedReadLock() = default;
|
||||
// --------------------------------------------------------------------------------------
|
||||
// ScopedReadLock / ScopedWriteLock
|
||||
// --------------------------------------------------------------------------------------
|
||||
class ScopedReadLock : public BaseScopedReadWriteLock
|
||||
{
|
||||
public:
|
||||
ScopedReadLock(RwMutex& locker);
|
||||
virtual ~ScopedReadLock() = default;
|
||||
|
||||
void Acquire();
|
||||
};
|
||||
void Acquire();
|
||||
};
|
||||
|
||||
class ScopedWriteLock : public BaseScopedReadWriteLock
|
||||
{
|
||||
public:
|
||||
ScopedWriteLock(RwMutex &locker);
|
||||
virtual ~ScopedWriteLock() = default;
|
||||
class ScopedWriteLock : public BaseScopedReadWriteLock
|
||||
{
|
||||
public:
|
||||
ScopedWriteLock(RwMutex& locker);
|
||||
virtual ~ScopedWriteLock() = default;
|
||||
|
||||
void Acquire();
|
||||
void Acquire();
|
||||
|
||||
protected:
|
||||
ScopedWriteLock(RwMutex &locker, bool isTryLock);
|
||||
};
|
||||
}
|
||||
protected:
|
||||
ScopedWriteLock(RwMutex& locker, bool isTryLock);
|
||||
};
|
||||
} // namespace Threading
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
// Microsoft Windows only macro, useful for freeing out COM objects:
|
||||
#define safe_release(ptr) \
|
||||
((void)((((ptr) != NULL) && ((ptr)->Release(), !!0)), (ptr) = NULL))
|
||||
((void)((((ptr) != NULL) && ((ptr)->Release(), !!0)), (ptr) = NULL))
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SafeArray
|
||||
|
@ -37,72 +37,72 @@
|
|||
template <typename T>
|
||||
class SafeArray
|
||||
{
|
||||
DeclareNoncopyableObject(SafeArray);
|
||||
DeclareNoncopyableObject(SafeArray);
|
||||
|
||||
public:
|
||||
static const int DefaultChunkSize = 0x1000 * sizeof(T);
|
||||
static const int DefaultChunkSize = 0x1000 * sizeof(T);
|
||||
|
||||
public:
|
||||
wxString Name; // user-assigned block name
|
||||
int ChunkSize;
|
||||
wxString Name; // user-assigned block name
|
||||
int ChunkSize;
|
||||
|
||||
protected:
|
||||
T *m_ptr;
|
||||
int m_size; // size of the allocation of memory
|
||||
T* m_ptr;
|
||||
int m_size; // size of the allocation of memory
|
||||
|
||||
protected:
|
||||
SafeArray(const wxChar *name, T *allocated_mem, int initSize);
|
||||
virtual T *_virtual_realloc(int newsize);
|
||||
SafeArray(const wxChar* name, T* allocated_mem, int initSize);
|
||||
virtual T* _virtual_realloc(int newsize);
|
||||
|
||||
// A safe array index fetcher. Asserts if the index is out of bounds (dev and debug
|
||||
// builds only -- no bounds checking is done in release builds).
|
||||
T *_getPtr(uint i) const;
|
||||
// A safe array index fetcher. Asserts if the index is out of bounds (dev and debug
|
||||
// builds only -- no bounds checking is done in release builds).
|
||||
T* _getPtr(uint i) const;
|
||||
|
||||
public:
|
||||
virtual ~SafeArray();
|
||||
virtual ~SafeArray();
|
||||
|
||||
explicit SafeArray(const wxChar *name = L"Unnamed");
|
||||
explicit SafeArray(int initialSize, const wxChar *name = L"Unnamed");
|
||||
explicit SafeArray(const wxChar* name = L"Unnamed");
|
||||
explicit SafeArray(int initialSize, const wxChar* name = L"Unnamed");
|
||||
|
||||
void Dispose();
|
||||
void ExactAlloc(int newsize);
|
||||
void MakeRoomFor(int newsize)
|
||||
{
|
||||
if (newsize > m_size)
|
||||
ExactAlloc(newsize);
|
||||
}
|
||||
void Dispose();
|
||||
void ExactAlloc(int newsize);
|
||||
void MakeRoomFor(int newsize)
|
||||
{
|
||||
if (newsize > m_size)
|
||||
ExactAlloc(newsize);
|
||||
}
|
||||
|
||||
bool IsDisposed() const { return (m_ptr == NULL); }
|
||||
bool IsDisposed() const { return (m_ptr == NULL); }
|
||||
|
||||
// Returns the size of the memory allocation, as according to the array type.
|
||||
int GetLength() const { return m_size; }
|
||||
// Returns the size of the memory allocation in bytes.
|
||||
int GetSizeInBytes() const { return m_size * sizeof(T); }
|
||||
// Returns the size of the memory allocation, as according to the array type.
|
||||
int GetLength() const { return m_size; }
|
||||
// Returns the size of the memory allocation in bytes.
|
||||
int GetSizeInBytes() const { return m_size * sizeof(T); }
|
||||
|
||||
// Extends the containment area of the array. Extensions are performed
|
||||
// in chunks.
|
||||
void GrowBy(int items)
|
||||
{
|
||||
MakeRoomFor(m_size + ChunkSize + items + 1);
|
||||
}
|
||||
// Extends the containment area of the array. Extensions are performed
|
||||
// in chunks.
|
||||
void GrowBy(int items)
|
||||
{
|
||||
MakeRoomFor(m_size + ChunkSize + items + 1);
|
||||
}
|
||||
|
||||
// Gets a pointer to the requested allocation index.
|
||||
// DevBuilds : Generates assertion if the index is invalid.
|
||||
T *GetPtr(uint idx = 0) { return _getPtr(idx); }
|
||||
const T *GetPtr(uint idx = 0) const { return _getPtr(idx); }
|
||||
// Gets a pointer to the requested allocation index.
|
||||
// DevBuilds : Generates assertion if the index is invalid.
|
||||
T* GetPtr(uint idx = 0) { return _getPtr(idx); }
|
||||
const T* GetPtr(uint idx = 0) const { return _getPtr(idx); }
|
||||
|
||||
// Gets a pointer to the element directly after the last element in the array.
|
||||
// This is equivalent to doing GetPtr(GetLength()), except that this call *avoids*
|
||||
// the out-of-bounds assertion check that typically occurs when you do that. :)
|
||||
T *GetPtrEnd() { return &m_ptr[m_size]; }
|
||||
const T *GetPtrEnd() const { return &m_ptr[m_size]; }
|
||||
// Gets a pointer to the element directly after the last element in the array.
|
||||
// This is equivalent to doing GetPtr(GetLength()), except that this call *avoids*
|
||||
// the out-of-bounds assertion check that typically occurs when you do that. :)
|
||||
T* GetPtrEnd() { return &m_ptr[m_size]; }
|
||||
const T* GetPtrEnd() const { return &m_ptr[m_size]; }
|
||||
|
||||
// Gets an element of this memory allocation much as if it were an array.
|
||||
// DevBuilds : Generates assertion if the index is invalid.
|
||||
T &operator[](int idx) { return *_getPtr((uint)idx); }
|
||||
const T &operator[](int idx) const { return *_getPtr((uint)idx); }
|
||||
// Gets an element of this memory allocation much as if it were an array.
|
||||
// DevBuilds : Generates assertion if the index is invalid.
|
||||
T& operator[](int idx) { return *_getPtr((uint)idx); }
|
||||
const T& operator[](int idx) const { return *_getPtr((uint)idx); }
|
||||
|
||||
virtual SafeArray<T> *Clone() const;
|
||||
virtual SafeArray<T>* Clone() const;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -118,73 +118,73 @@ public:
|
|||
template <typename T>
|
||||
class SafeList
|
||||
{
|
||||
DeclareNoncopyableObject(SafeList);
|
||||
DeclareNoncopyableObject(SafeList);
|
||||
|
||||
public:
|
||||
static const int DefaultChunkSize = 0x80 * sizeof(T);
|
||||
static const int DefaultChunkSize = 0x80 * sizeof(T);
|
||||
|
||||
public:
|
||||
wxString Name; // user-assigned block name
|
||||
int ChunkSize; // assigned DefaultChunkSize on init, reconfigurable at any time.
|
||||
wxString Name; // user-assigned block name
|
||||
int ChunkSize; // assigned DefaultChunkSize on init, reconfigurable at any time.
|
||||
|
||||
protected:
|
||||
T *m_ptr;
|
||||
int m_allocsize; // size of the allocation of memory
|
||||
uint m_length; // length of the array (active items, not buffer allocation)
|
||||
T* m_ptr;
|
||||
int m_allocsize; // size of the allocation of memory
|
||||
uint m_length; // length of the array (active items, not buffer allocation)
|
||||
|
||||
protected:
|
||||
virtual T *_virtual_realloc(int newsize);
|
||||
void _MakeRoomFor_threshold(int newsize);
|
||||
virtual T* _virtual_realloc(int newsize);
|
||||
void _MakeRoomFor_threshold(int newsize);
|
||||
|
||||
T *_getPtr(uint i) const;
|
||||
T* _getPtr(uint i) const;
|
||||
|
||||
public:
|
||||
virtual ~SafeList();
|
||||
explicit SafeList(const wxChar *name = L"Unnamed");
|
||||
explicit SafeList(int initialSize, const wxChar *name = L"Unnamed");
|
||||
virtual SafeList<T> *Clone() const;
|
||||
virtual ~SafeList();
|
||||
explicit SafeList(const wxChar* name = L"Unnamed");
|
||||
explicit SafeList(int initialSize, const wxChar* name = L"Unnamed");
|
||||
virtual SafeList<T>* Clone() const;
|
||||
|
||||
void Remove(int index);
|
||||
void MakeRoomFor(int blockSize);
|
||||
void Remove(int index);
|
||||
void MakeRoomFor(int blockSize);
|
||||
|
||||
T &New();
|
||||
int Add(const T &src);
|
||||
T &AddNew(const T &src);
|
||||
T& New();
|
||||
int Add(const T& src);
|
||||
T& AddNew(const T& src);
|
||||
|
||||
// Returns the size of the list, as according to the array type. This includes
|
||||
// mapped items only. The actual size of the allocation may differ.
|
||||
int GetLength() const { return m_length; }
|
||||
// Returns the size of the list, as according to the array type. This includes
|
||||
// mapped items only. The actual size of the allocation may differ.
|
||||
int GetLength() const { return m_length; }
|
||||
|
||||
// Returns the size of the list, in bytes. This includes mapped items only.
|
||||
// The actual size of the allocation may differ.
|
||||
int GetSizeInBytes() const { return m_length * sizeof(T); }
|
||||
// Returns the size of the list, in bytes. This includes mapped items only.
|
||||
// The actual size of the allocation may differ.
|
||||
int GetSizeInBytes() const { return m_length * sizeof(T); }
|
||||
|
||||
void MatchLengthToAllocatedSize()
|
||||
{
|
||||
m_length = m_allocsize;
|
||||
}
|
||||
void MatchLengthToAllocatedSize()
|
||||
{
|
||||
m_length = m_allocsize;
|
||||
}
|
||||
|
||||
void GrowBy(int items)
|
||||
{
|
||||
MakeRoomFor(m_length + ChunkSize + items + 1);
|
||||
}
|
||||
void GrowBy(int items)
|
||||
{
|
||||
MakeRoomFor(m_length + ChunkSize + items + 1);
|
||||
}
|
||||
|
||||
// Sets the item length to zero. Does not free memory allocations.
|
||||
void Clear()
|
||||
{
|
||||
m_length = 0;
|
||||
}
|
||||
// Sets the item length to zero. Does not free memory allocations.
|
||||
void Clear()
|
||||
{
|
||||
m_length = 0;
|
||||
}
|
||||
|
||||
// Gets an element of this memory allocation much as if it were an array.
|
||||
// DevBuilds : Generates assertion if the index is invalid.
|
||||
T &operator[](int idx) { return *_getPtr((uint)idx); }
|
||||
const T &operator[](int idx) const { return *_getPtr((uint)idx); }
|
||||
// Gets an element of this memory allocation much as if it were an array.
|
||||
// DevBuilds : Generates assertion if the index is invalid.
|
||||
T& operator[](int idx) { return *_getPtr((uint)idx); }
|
||||
const T& operator[](int idx) const { return *_getPtr((uint)idx); }
|
||||
|
||||
T *GetPtr() { return m_ptr; }
|
||||
const T *GetPtr() const { return m_ptr; }
|
||||
T* GetPtr() { return m_ptr; }
|
||||
const T* GetPtr() const { return m_ptr; }
|
||||
|
||||
T &GetLast() { return m_ptr[m_length - 1]; }
|
||||
const T &GetLast() const { return m_ptr[m_length - 1]; }
|
||||
T& GetLast() { return m_ptr[m_length - 1]; }
|
||||
const T& GetLast() const { return m_ptr[m_length - 1]; }
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -197,21 +197,21 @@ public:
|
|||
template <typename T, uint Alignment>
|
||||
class SafeAlignedArray : public SafeArray<T>
|
||||
{
|
||||
typedef SafeArray<T> _parent;
|
||||
typedef SafeArray<T> _parent;
|
||||
|
||||
protected:
|
||||
T *_virtual_realloc(int newsize);
|
||||
T* _virtual_realloc(int newsize);
|
||||
|
||||
public:
|
||||
using _parent::operator[];
|
||||
using _parent::operator[];
|
||||
|
||||
virtual ~SafeAlignedArray();
|
||||
virtual ~SafeAlignedArray();
|
||||
|
||||
explicit SafeAlignedArray(const wxChar *name = L"Unnamed")
|
||||
: SafeArray<T>::SafeArray(name)
|
||||
{
|
||||
}
|
||||
explicit SafeAlignedArray(const wxChar* name = L"Unnamed")
|
||||
: SafeArray<T>::SafeArray(name)
|
||||
{
|
||||
}
|
||||
|
||||
explicit SafeAlignedArray(int initialSize, const wxChar *name = L"Unnamed");
|
||||
virtual SafeAlignedArray<T, Alignment> *Clone() const;
|
||||
explicit SafeAlignedArray(int initialSize, const wxChar* name = L"Unnamed");
|
||||
virtual SafeAlignedArray<T, Alignment>* Clone() const;
|
||||
};
|
||||
|
|
|
@ -23,79 +23,80 @@
|
|||
// Throws:
|
||||
// Exception::OutOfMemory if the allocated_mem pointer is NULL.
|
||||
template <typename T>
|
||||
SafeArray<T>::SafeArray(const wxChar *name, T *allocated_mem, int initSize)
|
||||
: Name(name)
|
||||
SafeArray<T>::SafeArray(const wxChar* name, T* allocated_mem, int initSize)
|
||||
: Name(name)
|
||||
{
|
||||
ChunkSize = DefaultChunkSize;
|
||||
m_ptr = allocated_mem;
|
||||
m_size = initSize;
|
||||
ChunkSize = DefaultChunkSize;
|
||||
m_ptr = allocated_mem;
|
||||
m_size = initSize;
|
||||
|
||||
if (m_ptr == NULL)
|
||||
throw Exception::OutOfMemory(name)
|
||||
.SetDiagMsg(wxsFormat(L"Called from 'SafeArray::ctor' [size=%d]", initSize));
|
||||
if (m_ptr == NULL)
|
||||
throw Exception::OutOfMemory(name)
|
||||
.SetDiagMsg(wxsFormat(L"Called from 'SafeArray::ctor' [size=%d]", initSize));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T *SafeArray<T>::_virtual_realloc(int newsize)
|
||||
T* SafeArray<T>::_virtual_realloc(int newsize)
|
||||
{
|
||||
T *retval = (T *)((m_ptr == NULL) ?
|
||||
malloc(newsize * sizeof(T)) :
|
||||
realloc(m_ptr, newsize * sizeof(T)));
|
||||
T* retval = (T*)((m_ptr == NULL) ?
|
||||
malloc(newsize * sizeof(T)) :
|
||||
realloc(m_ptr, newsize * sizeof(T)));
|
||||
|
||||
if (IsDebugBuild && (retval != NULL)) {
|
||||
// Zero everything out to 0xbaadf00d, so that its obviously uncleared
|
||||
// to a debuggee
|
||||
if (IsDebugBuild && (retval != NULL))
|
||||
{
|
||||
// Zero everything out to 0xbaadf00d, so that its obviously uncleared
|
||||
// to a debuggee
|
||||
|
||||
u32 *fill = (u32 *)&retval[m_size];
|
||||
const u32 *end = (u32 *)((((uptr)&retval[newsize - 1]) - 3) & ~0x3);
|
||||
for (; fill < end; ++fill)
|
||||
*fill = 0xbaadf00d;
|
||||
}
|
||||
u32* fill = (u32*)&retval[m_size];
|
||||
const u32* end = (u32*)((((uptr)&retval[newsize - 1]) - 3) & ~0x3);
|
||||
for (; fill < end; ++fill)
|
||||
*fill = 0xbaadf00d;
|
||||
}
|
||||
|
||||
return retval;
|
||||
return retval;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
SafeArray<T>::~SafeArray()
|
||||
{
|
||||
safe_free(m_ptr);
|
||||
safe_free(m_ptr);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
SafeArray<T>::SafeArray(const wxChar *name)
|
||||
: Name(name)
|
||||
SafeArray<T>::SafeArray(const wxChar* name)
|
||||
: Name(name)
|
||||
{
|
||||
ChunkSize = DefaultChunkSize;
|
||||
m_ptr = NULL;
|
||||
m_size = 0;
|
||||
ChunkSize = DefaultChunkSize;
|
||||
m_ptr = NULL;
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
SafeArray<T>::SafeArray(int initialSize, const wxChar *name)
|
||||
: Name(name)
|
||||
SafeArray<T>::SafeArray(int initialSize, const wxChar* name)
|
||||
: Name(name)
|
||||
{
|
||||
ChunkSize = DefaultChunkSize;
|
||||
m_ptr = (initialSize == 0) ? NULL : (T *)malloc(initialSize * sizeof(T));
|
||||
m_size = initialSize;
|
||||
ChunkSize = DefaultChunkSize;
|
||||
m_ptr = (initialSize == 0) ? NULL : (T*)malloc(initialSize * sizeof(T));
|
||||
m_size = initialSize;
|
||||
|
||||
if ((initialSize != 0) && (m_ptr == NULL))
|
||||
throw Exception::OutOfMemory(name)
|
||||
.SetDiagMsg(wxsFormat(L"Called from 'SafeArray::ctor' [size=%d]", initialSize));
|
||||
if ((initialSize != 0) && (m_ptr == NULL))
|
||||
throw Exception::OutOfMemory(name)
|
||||
.SetDiagMsg(wxsFormat(L"Called from 'SafeArray::ctor' [size=%d]", initialSize));
|
||||
}
|
||||
|
||||
// Clears the contents of the array to zero, and frees all memory allocations.
|
||||
template <typename T>
|
||||
void SafeArray<T>::Dispose()
|
||||
{
|
||||
m_size = 0;
|
||||
safe_free(m_ptr);
|
||||
m_size = 0;
|
||||
safe_free(m_ptr);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T *SafeArray<T>::_getPtr(uint i) const
|
||||
T* SafeArray<T>::_getPtr(uint i) const
|
||||
{
|
||||
IndexBoundsAssumeDev(WX_STR(Name), i, m_size);
|
||||
return &m_ptr[i];
|
||||
IndexBoundsAssumeDev(WX_STR(Name), i, m_size);
|
||||
return &m_ptr[i];
|
||||
}
|
||||
|
||||
// reallocates the array to the explicit size. Can be used to shrink or grow an
|
||||
|
@ -103,23 +104,23 @@ T *SafeArray<T>::_getPtr(uint i) const
|
|||
template <typename T>
|
||||
void SafeArray<T>::ExactAlloc(int newsize)
|
||||
{
|
||||
if (newsize == m_size)
|
||||
return;
|
||||
if (newsize == m_size)
|
||||
return;
|
||||
|
||||
m_ptr = _virtual_realloc(newsize);
|
||||
if (m_ptr == NULL)
|
||||
throw Exception::OutOfMemory(Name)
|
||||
.SetDiagMsg(wxsFormat(L"Called from 'SafeArray::ExactAlloc' [oldsize=%d] [newsize=%d]", m_size, newsize));
|
||||
m_ptr = _virtual_realloc(newsize);
|
||||
if (m_ptr == NULL)
|
||||
throw Exception::OutOfMemory(Name)
|
||||
.SetDiagMsg(wxsFormat(L"Called from 'SafeArray::ExactAlloc' [oldsize=%d] [newsize=%d]", m_size, newsize));
|
||||
|
||||
m_size = newsize;
|
||||
m_size = newsize;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
SafeArray<T> *SafeArray<T>::Clone() const
|
||||
SafeArray<T>* SafeArray<T>::Clone() const
|
||||
{
|
||||
SafeArray<T> *retval = new SafeArray<T>(m_size);
|
||||
memcpy(retval->GetPtr(), m_ptr, sizeof(T) * m_size);
|
||||
return retval;
|
||||
SafeArray<T>* retval = new SafeArray<T>(m_size);
|
||||
memcpy(retval->GetPtr(), m_ptr, sizeof(T) * m_size);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
|
@ -128,11 +129,11 @@ SafeArray<T> *SafeArray<T>::Clone() const
|
|||
// --------------------------------------------------------------------------------------
|
||||
|
||||
template <typename T, uint Alignment>
|
||||
T *SafeAlignedArray<T, Alignment>::_virtual_realloc(int newsize)
|
||||
T* SafeAlignedArray<T, Alignment>::_virtual_realloc(int newsize)
|
||||
{
|
||||
return (T *)((this->m_ptr == NULL) ?
|
||||
_aligned_malloc(newsize * sizeof(T), Alignment) :
|
||||
pcsx2_aligned_realloc(this->m_ptr, newsize * sizeof(T), Alignment, this->m_size * sizeof(T)));
|
||||
return (T*)((this->m_ptr == NULL) ?
|
||||
_aligned_malloc(newsize * sizeof(T), Alignment) :
|
||||
pcsx2_aligned_realloc(this->m_ptr, newsize * sizeof(T), Alignment, this->m_size * sizeof(T)));
|
||||
}
|
||||
|
||||
// Appends "(align: xx)" to the name of the allocation in devel builds.
|
||||
|
@ -141,25 +142,25 @@ T *SafeAlignedArray<T, Alignment>::_virtual_realloc(int newsize)
|
|||
template <typename T, uint Alignment>
|
||||
SafeAlignedArray<T, Alignment>::~SafeAlignedArray()
|
||||
{
|
||||
safe_aligned_free(this->m_ptr);
|
||||
// mptr is set to null, so the parent class's destructor won't re-free it.
|
||||
safe_aligned_free(this->m_ptr);
|
||||
// mptr is set to null, so the parent class's destructor won't re-free it.
|
||||
}
|
||||
|
||||
template <typename T, uint Alignment>
|
||||
SafeAlignedArray<T, Alignment>::SafeAlignedArray(int initialSize, const wxChar *name)
|
||||
: SafeArray<T>::SafeArray(
|
||||
name,
|
||||
(T *)_aligned_malloc(initialSize * sizeof(T), Alignment),
|
||||
initialSize)
|
||||
SafeAlignedArray<T, Alignment>::SafeAlignedArray(int initialSize, const wxChar* name)
|
||||
: SafeArray<T>::SafeArray(
|
||||
name,
|
||||
(T*)_aligned_malloc(initialSize * sizeof(T), Alignment),
|
||||
initialSize)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T, uint Alignment>
|
||||
SafeAlignedArray<T, Alignment> *SafeAlignedArray<T, Alignment>::Clone() const
|
||||
SafeAlignedArray<T, Alignment>* SafeAlignedArray<T, Alignment>::Clone() const
|
||||
{
|
||||
SafeAlignedArray<T, Alignment> *retval = new SafeAlignedArray<T, Alignment>(this->m_size);
|
||||
memcpy(retval->GetPtr(), this->m_ptr, sizeof(T) * this->m_size);
|
||||
return retval;
|
||||
SafeAlignedArray<T, Alignment>* retval = new SafeAlignedArray<T, Alignment>(this->m_size);
|
||||
memcpy(retval->GetPtr(), this->m_ptr, sizeof(T) * this->m_size);
|
||||
return retval;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -167,50 +168,51 @@ SafeAlignedArray<T, Alignment> *SafeAlignedArray<T, Alignment>::Clone() const
|
|||
// --------------------------------------------------------------------------------------
|
||||
|
||||
template <typename T>
|
||||
T *SafeList<T>::_virtual_realloc(int newsize)
|
||||
T* SafeList<T>::_virtual_realloc(int newsize)
|
||||
{
|
||||
return (T *)realloc(m_ptr, newsize * sizeof(T));
|
||||
return (T*)realloc(m_ptr, newsize * sizeof(T));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
SafeList<T>::~SafeList()
|
||||
{
|
||||
safe_free(m_ptr);
|
||||
safe_free(m_ptr);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
SafeList<T>::SafeList(const wxChar *name)
|
||||
: Name(name)
|
||||
SafeList<T>::SafeList(const wxChar* name)
|
||||
: Name(name)
|
||||
{
|
||||
ChunkSize = DefaultChunkSize;
|
||||
m_ptr = NULL;
|
||||
m_allocsize = 0;
|
||||
m_length = 0;
|
||||
ChunkSize = DefaultChunkSize;
|
||||
m_ptr = NULL;
|
||||
m_allocsize = 0;
|
||||
m_length = 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
SafeList<T>::SafeList(int initialSize, const wxChar *name)
|
||||
: Name(name)
|
||||
SafeList<T>::SafeList(int initialSize, const wxChar* name)
|
||||
: Name(name)
|
||||
{
|
||||
ChunkSize = DefaultChunkSize;
|
||||
m_allocsize = initialSize;
|
||||
m_length = 0;
|
||||
m_ptr = (T *)malloc(initialSize * sizeof(T));
|
||||
ChunkSize = DefaultChunkSize;
|
||||
m_allocsize = initialSize;
|
||||
m_length = 0;
|
||||
m_ptr = (T*)malloc(initialSize * sizeof(T));
|
||||
|
||||
if (m_ptr == NULL)
|
||||
throw Exception::OutOfMemory(Name)
|
||||
.SetDiagMsg(wxsFormat(L"called from 'SafeList::ctor' [length=%d]", m_length));
|
||||
if (m_ptr == NULL)
|
||||
throw Exception::OutOfMemory(Name)
|
||||
.SetDiagMsg(wxsFormat(L"called from 'SafeList::ctor' [length=%d]", m_length));
|
||||
|
||||
for (int i = 0; i < m_allocsize; ++i) {
|
||||
new (&m_ptr[i]) T();
|
||||
}
|
||||
for (int i = 0; i < m_allocsize; ++i)
|
||||
{
|
||||
new (&m_ptr[i]) T();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T *SafeList<T>::_getPtr(uint i) const
|
||||
T* SafeList<T>::_getPtr(uint i) const
|
||||
{
|
||||
IndexBoundsAssumeDev(WX_STR(Name), i, m_length);
|
||||
return &m_ptr[i];
|
||||
IndexBoundsAssumeDev(WX_STR(Name), i, m_length);
|
||||
return &m_ptr[i];
|
||||
}
|
||||
|
||||
// Ensures that the allocation is large enough to fit data of the
|
||||
|
@ -218,42 +220,44 @@ T *SafeList<T>::_getPtr(uint i) const
|
|||
template <typename T>
|
||||
void SafeList<T>::MakeRoomFor(int blockSize)
|
||||
{
|
||||
if (blockSize > m_allocsize) {
|
||||
const int newalloc = blockSize + ChunkSize;
|
||||
m_ptr = _virtual_realloc(newalloc);
|
||||
if (m_ptr == NULL)
|
||||
throw Exception::OutOfMemory(Name)
|
||||
.SetDiagMsg(wxsFormat(L"Called from 'SafeList::MakeRoomFor' [oldlen=%d] [newlen=%d]", m_length, blockSize));
|
||||
if (blockSize > m_allocsize)
|
||||
{
|
||||
const int newalloc = blockSize + ChunkSize;
|
||||
m_ptr = _virtual_realloc(newalloc);
|
||||
if (m_ptr == NULL)
|
||||
throw Exception::OutOfMemory(Name)
|
||||
.SetDiagMsg(wxsFormat(L"Called from 'SafeList::MakeRoomFor' [oldlen=%d] [newlen=%d]", m_length, blockSize));
|
||||
|
||||
for (; m_allocsize < newalloc; ++m_allocsize) {
|
||||
new (&m_ptr[m_allocsize]) T();
|
||||
}
|
||||
}
|
||||
for (; m_allocsize < newalloc; ++m_allocsize)
|
||||
{
|
||||
new (&m_ptr[m_allocsize]) T();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Appends an item to the end of the list and returns a handle to it.
|
||||
template <typename T>
|
||||
T &SafeList<T>::New()
|
||||
T& SafeList<T>::New()
|
||||
{
|
||||
_MakeRoomFor_threshold(m_length + 1);
|
||||
return m_ptr[m_length++];
|
||||
_MakeRoomFor_threshold(m_length + 1);
|
||||
return m_ptr[m_length++];
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
int SafeList<T>::Add(const T &src)
|
||||
int SafeList<T>::Add(const T& src)
|
||||
{
|
||||
_MakeRoomFor_threshold(m_length + 1);
|
||||
m_ptr[m_length] = src;
|
||||
return m_length++;
|
||||
_MakeRoomFor_threshold(m_length + 1);
|
||||
m_ptr[m_length] = src;
|
||||
return m_length++;
|
||||
}
|
||||
|
||||
// Same as Add, but returns the handle of the new object instead of it's array index.
|
||||
template <typename T>
|
||||
T &SafeList<T>::AddNew(const T &src)
|
||||
T& SafeList<T>::AddNew(const T& src)
|
||||
{
|
||||
_MakeRoomFor_threshold(m_length + 1);
|
||||
m_ptr[m_length] = src;
|
||||
return m_ptr[m_length];
|
||||
_MakeRoomFor_threshold(m_length + 1);
|
||||
m_ptr[m_length] = src;
|
||||
return m_ptr[m_length];
|
||||
}
|
||||
|
||||
// Performs a standard array-copy removal of the given item. All items past the
|
||||
|
@ -262,23 +266,23 @@ T &SafeList<T>::AddNew(const T &src)
|
|||
template <typename T>
|
||||
void SafeList<T>::Remove(int index)
|
||||
{
|
||||
IndexBoundsAssumeDev(Name.c_str(), index, m_length);
|
||||
IndexBoundsAssumeDev(Name.c_str(), index, m_length);
|
||||
|
||||
int copylen = m_length - index;
|
||||
if (copylen > 0)
|
||||
memcpy(&m_ptr[index], &m_ptr[index + 1], copylen);
|
||||
int copylen = m_length - index;
|
||||
if (copylen > 0)
|
||||
memcpy(&m_ptr[index], &m_ptr[index + 1], copylen);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
SafeList<T> *SafeList<T>::Clone() const
|
||||
SafeList<T>* SafeList<T>::Clone() const
|
||||
{
|
||||
SafeList<T> *retval = new SafeList<T>(m_length);
|
||||
memcpy(retval->m_ptr, m_ptr, sizeof(T) * m_length);
|
||||
return retval;
|
||||
SafeList<T>* retval = new SafeList<T>(m_length);
|
||||
memcpy(retval->m_ptr, m_ptr, sizeof(T) * m_length);
|
||||
return retval;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void SafeList<T>::_MakeRoomFor_threshold(int newsize)
|
||||
{
|
||||
MakeRoomFor(newsize + ChunkSize);
|
||||
MakeRoomFor(newsize + ChunkSize);
|
||||
}
|
||||
|
|
|
@ -28,34 +28,34 @@
|
|||
// pointer to null after deallocation.
|
||||
|
||||
#define safe_delete(ptr) \
|
||||
((void)(delete (ptr)), (ptr) = NULL)
|
||||
((void)(delete (ptr)), (ptr) = NULL)
|
||||
|
||||
#define safe_delete_array(ptr) \
|
||||
((void)(delete[](ptr)), (ptr) = NULL)
|
||||
((void)(delete[](ptr)), (ptr) = NULL)
|
||||
|
||||
// No checks for NULL -- wxWidgets says it's safe to skip NULL checks and it runs on
|
||||
// just about every compiler and libc implementation of any recentness.
|
||||
#define safe_free(ptr) \
|
||||
((void)(free(ptr), !!0), (ptr) = NULL)
|
||||
((void)(free(ptr), !!0), (ptr) = NULL)
|
||||
//((void) (( ( (ptr) != NULL ) && (free( ptr ), !!0) ), (ptr) = NULL))
|
||||
|
||||
#define safe_fclose(ptr) \
|
||||
((void)((((ptr) != NULL) && (fclose(ptr), !!0)), (ptr) = NULL))
|
||||
((void)((((ptr) != NULL) && (fclose(ptr), !!0)), (ptr) = NULL))
|
||||
|
||||
// Implementation note: all known implementations of _aligned_free check the pointer for
|
||||
// NULL status (our implementation under GCC, and microsoft's under MSVC), so no need to
|
||||
// do it here.
|
||||
#define safe_aligned_free(ptr) \
|
||||
((void)(_aligned_free(ptr), (ptr) = NULL))
|
||||
((void)(_aligned_free(ptr), (ptr) = NULL))
|
||||
|
||||
// aligned_malloc: Implement/declare linux equivalents here!
|
||||
#if !defined(_MSC_VER)
|
||||
extern void *__fastcall _aligned_malloc(size_t size, size_t align);
|
||||
extern void *__fastcall pcsx2_aligned_realloc(void *handle, size_t new_size, size_t align, size_t old_size);
|
||||
extern void _aligned_free(void *pmem);
|
||||
extern void* __fastcall _aligned_malloc(size_t size, size_t align);
|
||||
extern void* __fastcall pcsx2_aligned_realloc(void* handle, size_t new_size, size_t align, size_t old_size);
|
||||
extern void _aligned_free(void* pmem);
|
||||
#else
|
||||
#define pcsx2_aligned_realloc(handle, new_size, align, old_size) \
|
||||
_aligned_realloc(handle, new_size, align)
|
||||
_aligned_realloc(handle, new_size, align)
|
||||
#endif
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -63,7 +63,7 @@ extern void _aligned_free(void *pmem);
|
|||
// --------------------------------------------------------------------------------------
|
||||
|
||||
typedef void FnType_OutOfMemory(uptr blocksize);
|
||||
typedef FnType_OutOfMemory *Fnptr_OutOfMemory;
|
||||
typedef FnType_OutOfMemory* Fnptr_OutOfMemory;
|
||||
|
||||
// This method is meant to be assigned by applications that link against pxWex. It is called
|
||||
// (invoked) prior to most pxWex built-in memory/array classes throwing exceptions, and can be
|
||||
|
@ -93,74 +93,74 @@ template <typename T>
|
|||
class BaseScopedAlloc
|
||||
{
|
||||
protected:
|
||||
T *m_buffer;
|
||||
uint m_size;
|
||||
T* m_buffer;
|
||||
uint m_size;
|
||||
|
||||
public:
|
||||
BaseScopedAlloc()
|
||||
{
|
||||
m_buffer = NULL;
|
||||
m_size = 0;
|
||||
}
|
||||
BaseScopedAlloc()
|
||||
{
|
||||
m_buffer = NULL;
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
virtual ~BaseScopedAlloc()
|
||||
{
|
||||
//pxAssert(m_buffer==NULL);
|
||||
}
|
||||
virtual ~BaseScopedAlloc()
|
||||
{
|
||||
//pxAssert(m_buffer==NULL);
|
||||
}
|
||||
|
||||
public:
|
||||
size_t GetSize() const { return m_size; }
|
||||
size_t GetLength() const { return m_size; }
|
||||
size_t GetSize() const { return m_size; }
|
||||
size_t GetLength() const { return m_size; }
|
||||
|
||||
// Allocates the object to the specified size. If an existing allocation is in
|
||||
// place, it is freed and replaced with the new allocation, and all data is lost.
|
||||
// Parameter:
|
||||
// newSize - size of the new allocation, in elements (not bytes!). If the specified
|
||||
// size is 0, the the allocation is freed, same as calling Free().
|
||||
virtual void Alloc(size_t newsize) = 0;
|
||||
// Allocates the object to the specified size. If an existing allocation is in
|
||||
// place, it is freed and replaced with the new allocation, and all data is lost.
|
||||
// Parameter:
|
||||
// newSize - size of the new allocation, in elements (not bytes!). If the specified
|
||||
// size is 0, the the allocation is freed, same as calling Free().
|
||||
virtual void Alloc(size_t newsize) = 0;
|
||||
|
||||
// Re-sizes the allocation to the requested size, without any data loss.
|
||||
// Parameter:
|
||||
// newSize - size of the new allocation, in elements (not bytes!). If the specified
|
||||
// size is 0, the the allocation is freed, same as calling Free().
|
||||
virtual void Resize(size_t newsize) = 0;
|
||||
// Re-sizes the allocation to the requested size, without any data loss.
|
||||
// Parameter:
|
||||
// newSize - size of the new allocation, in elements (not bytes!). If the specified
|
||||
// size is 0, the the allocation is freed, same as calling Free().
|
||||
virtual void Resize(size_t newsize) = 0;
|
||||
|
||||
void Free()
|
||||
{
|
||||
Alloc(0);
|
||||
}
|
||||
void Free()
|
||||
{
|
||||
Alloc(0);
|
||||
}
|
||||
|
||||
// Makes enough room for the requested size. Existing data in the array is retained.
|
||||
void MakeRoomFor(uint size)
|
||||
{
|
||||
if (size <= m_size)
|
||||
return;
|
||||
Resize(size);
|
||||
}
|
||||
// Makes enough room for the requested size. Existing data in the array is retained.
|
||||
void MakeRoomFor(uint size)
|
||||
{
|
||||
if (size <= m_size)
|
||||
return;
|
||||
Resize(size);
|
||||
}
|
||||
|
||||
T *GetPtr(uint idx = 0) const
|
||||
{
|
||||
T* GetPtr(uint idx = 0) const
|
||||
{
|
||||
#if pxUSE_SECURE_MALLOC
|
||||
IndexBoundsAssumeDev("ScopedAlloc", idx, m_size);
|
||||
IndexBoundsAssumeDev("ScopedAlloc", idx, m_size);
|
||||
#endif
|
||||
return &m_buffer[idx];
|
||||
}
|
||||
return &m_buffer[idx];
|
||||
}
|
||||
|
||||
T &operator[](uint idx)
|
||||
{
|
||||
T& operator[](uint idx)
|
||||
{
|
||||
#if pxUSE_SECURE_MALLOC
|
||||
IndexBoundsAssumeDev("ScopedAlloc", idx, m_size);
|
||||
IndexBoundsAssumeDev("ScopedAlloc", idx, m_size);
|
||||
#endif
|
||||
return m_buffer[idx];
|
||||
}
|
||||
return m_buffer[idx];
|
||||
}
|
||||
|
||||
const T &operator[](uint idx) const
|
||||
{
|
||||
const T& operator[](uint idx) const
|
||||
{
|
||||
#if pxUSE_SECURE_MALLOC
|
||||
IndexBoundsAssumeDev("ScopedAlloc", idx, m_size);
|
||||
IndexBoundsAssumeDev("ScopedAlloc", idx, m_size);
|
||||
#endif
|
||||
return m_buffer[idx];
|
||||
}
|
||||
return m_buffer[idx];
|
||||
}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -175,42 +175,42 @@ public:
|
|||
template <typename T>
|
||||
class ScopedAlloc : public BaseScopedAlloc<T>
|
||||
{
|
||||
typedef BaseScopedAlloc<T> _parent;
|
||||
typedef BaseScopedAlloc<T> _parent;
|
||||
|
||||
public:
|
||||
ScopedAlloc(size_t size = 0)
|
||||
: _parent()
|
||||
{
|
||||
Alloc(size);
|
||||
}
|
||||
ScopedAlloc(size_t size = 0)
|
||||
: _parent()
|
||||
{
|
||||
Alloc(size);
|
||||
}
|
||||
|
||||
virtual ~ScopedAlloc()
|
||||
{
|
||||
safe_free(this->m_buffer);
|
||||
}
|
||||
virtual ~ScopedAlloc()
|
||||
{
|
||||
safe_free(this->m_buffer);
|
||||
}
|
||||
|
||||
virtual void Alloc(size_t newsize)
|
||||
{
|
||||
safe_free(this->m_buffer);
|
||||
this->m_size = newsize;
|
||||
if (!this->m_size)
|
||||
return;
|
||||
virtual void Alloc(size_t newsize)
|
||||
{
|
||||
safe_free(this->m_buffer);
|
||||
this->m_size = newsize;
|
||||
if (!this->m_size)
|
||||
return;
|
||||
|
||||
this->m_buffer = (T *)malloc(this->m_size * sizeof(T));
|
||||
if (!this->m_buffer)
|
||||
throw Exception::OutOfMemory(L"ScopedAlloc");
|
||||
}
|
||||
this->m_buffer = (T*)malloc(this->m_size * sizeof(T));
|
||||
if (!this->m_buffer)
|
||||
throw Exception::OutOfMemory(L"ScopedAlloc");
|
||||
}
|
||||
|
||||
virtual void Resize(size_t newsize)
|
||||
{
|
||||
this->m_size = newsize;
|
||||
this->m_buffer = (T *)realloc(this->m_buffer, this->m_size * sizeof(T));
|
||||
virtual void Resize(size_t newsize)
|
||||
{
|
||||
this->m_size = newsize;
|
||||
this->m_buffer = (T*)realloc(this->m_buffer, this->m_size * sizeof(T));
|
||||
|
||||
if (!this->m_buffer)
|
||||
throw Exception::OutOfMemory(L"ScopedAlloc::Resize");
|
||||
}
|
||||
if (!this->m_buffer)
|
||||
throw Exception::OutOfMemory(L"ScopedAlloc::Resize");
|
||||
}
|
||||
|
||||
using _parent::operator[];
|
||||
using _parent::operator[];
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -225,40 +225,40 @@ public:
|
|||
template <typename T, uint align>
|
||||
class ScopedAlignedAlloc : public BaseScopedAlloc<T>
|
||||
{
|
||||
typedef BaseScopedAlloc<T> _parent;
|
||||
typedef BaseScopedAlloc<T> _parent;
|
||||
|
||||
public:
|
||||
ScopedAlignedAlloc(size_t size = 0)
|
||||
: _parent()
|
||||
{
|
||||
Alloc(size);
|
||||
}
|
||||
ScopedAlignedAlloc(size_t size = 0)
|
||||
: _parent()
|
||||
{
|
||||
Alloc(size);
|
||||
}
|
||||
|
||||
virtual ~ScopedAlignedAlloc()
|
||||
{
|
||||
safe_aligned_free(this->m_buffer);
|
||||
}
|
||||
virtual ~ScopedAlignedAlloc()
|
||||
{
|
||||
safe_aligned_free(this->m_buffer);
|
||||
}
|
||||
|
||||
virtual void Alloc(size_t newsize)
|
||||
{
|
||||
safe_aligned_free(this->m_buffer);
|
||||
this->m_size = newsize;
|
||||
if (!this->m_size)
|
||||
return;
|
||||
virtual void Alloc(size_t newsize)
|
||||
{
|
||||
safe_aligned_free(this->m_buffer);
|
||||
this->m_size = newsize;
|
||||
if (!this->m_size)
|
||||
return;
|
||||
|
||||
this->m_buffer = (T *)_aligned_malloc(this->m_size * sizeof(T), align);
|
||||
if (!this->m_buffer)
|
||||
throw Exception::OutOfMemory(L"ScopedAlignedAlloc");
|
||||
}
|
||||
this->m_buffer = (T*)_aligned_malloc(this->m_size * sizeof(T), align);
|
||||
if (!this->m_buffer)
|
||||
throw Exception::OutOfMemory(L"ScopedAlignedAlloc");
|
||||
}
|
||||
|
||||
virtual void Resize(size_t newsize)
|
||||
{
|
||||
this->m_buffer = (T *)pcsx2_aligned_realloc(this->m_buffer, newsize * sizeof(T), align, this->m_size * sizeof(T));
|
||||
this->m_size = newsize;
|
||||
virtual void Resize(size_t newsize)
|
||||
{
|
||||
this->m_buffer = (T*)pcsx2_aligned_realloc(this->m_buffer, newsize * sizeof(T), align, this->m_size * sizeof(T));
|
||||
this->m_size = newsize;
|
||||
|
||||
if (!this->m_buffer)
|
||||
throw Exception::OutOfMemory(L"ScopedAlignedAlloc::Resize");
|
||||
}
|
||||
if (!this->m_buffer)
|
||||
throw Exception::OutOfMemory(L"ScopedAlignedAlloc::Resize");
|
||||
}
|
||||
|
||||
using _parent::operator[];
|
||||
using _parent::operator[];
|
||||
};
|
||||
|
|
|
@ -25,91 +25,91 @@ using Threading::ScopedLock;
|
|||
template <typename T>
|
||||
class ScopedPtrMT
|
||||
{
|
||||
DeclareNoncopyableObject(ScopedPtrMT);
|
||||
DeclareNoncopyableObject(ScopedPtrMT);
|
||||
|
||||
protected:
|
||||
std::atomic<T *> m_ptr;
|
||||
Threading::Mutex m_mtx;
|
||||
std::atomic<T*> m_ptr;
|
||||
Threading::Mutex m_mtx;
|
||||
|
||||
public:
|
||||
typedef T element_type;
|
||||
typedef T element_type;
|
||||
|
||||
wxEXPLICIT ScopedPtrMT(T *ptr = nullptr)
|
||||
{
|
||||
m_ptr = ptr;
|
||||
}
|
||||
wxEXPLICIT ScopedPtrMT(T* ptr = nullptr)
|
||||
{
|
||||
m_ptr = ptr;
|
||||
}
|
||||
|
||||
~ScopedPtrMT() { _Delete_unlocked(); }
|
||||
~ScopedPtrMT() { _Delete_unlocked(); }
|
||||
|
||||
ScopedPtrMT &Reassign(T *ptr = nullptr)
|
||||
{
|
||||
T *doh = m_ptr.exchange(ptr);
|
||||
if (ptr != doh)
|
||||
delete doh;
|
||||
return *this;
|
||||
}
|
||||
ScopedPtrMT& Reassign(T* ptr = nullptr)
|
||||
{
|
||||
T* doh = m_ptr.exchange(ptr);
|
||||
if (ptr != doh)
|
||||
delete doh;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ScopedPtrMT &Delete() noexcept
|
||||
{
|
||||
ScopedLock lock(m_mtx);
|
||||
_Delete_unlocked();
|
||||
}
|
||||
ScopedPtrMT& Delete() noexcept
|
||||
{
|
||||
ScopedLock lock(m_mtx);
|
||||
_Delete_unlocked();
|
||||
}
|
||||
|
||||
// Removes the pointer from scoped management, but does not delete!
|
||||
// (ScopedPtr will be nullptr after this method)
|
||||
T *DetachPtr()
|
||||
{
|
||||
ScopedLock lock(m_mtx);
|
||||
// Removes the pointer from scoped management, but does not delete!
|
||||
// (ScopedPtr will be nullptr after this method)
|
||||
T* DetachPtr()
|
||||
{
|
||||
ScopedLock lock(m_mtx);
|
||||
|
||||
return m_ptr.exchange(nullptr);
|
||||
}
|
||||
return m_ptr.exchange(nullptr);
|
||||
}
|
||||
|
||||
// Returns the managed pointer. Can return nullptr as a valid result if the ScopedPtrMT
|
||||
// has no object in management.
|
||||
T *GetPtr() const
|
||||
{
|
||||
return m_ptr;
|
||||
}
|
||||
// Returns the managed pointer. Can return nullptr as a valid result if the ScopedPtrMT
|
||||
// has no object in management.
|
||||
T* GetPtr() const
|
||||
{
|
||||
return m_ptr;
|
||||
}
|
||||
|
||||
void SwapPtr(ScopedPtrMT &other)
|
||||
{
|
||||
ScopedLock lock(m_mtx);
|
||||
m_ptr.exchange(other.m_ptr.exchange(m_ptr.load()));
|
||||
T *const tmp = other.m_ptr;
|
||||
other.m_ptr = m_ptr;
|
||||
m_ptr = tmp;
|
||||
}
|
||||
void SwapPtr(ScopedPtrMT& other)
|
||||
{
|
||||
ScopedLock lock(m_mtx);
|
||||
m_ptr.exchange(other.m_ptr.exchange(m_ptr.load()));
|
||||
T* const tmp = other.m_ptr;
|
||||
other.m_ptr = m_ptr;
|
||||
m_ptr = tmp;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// ScopedPtrMT Operators
|
||||
// ----------------------------------------------------------------------------
|
||||
// I've decided to use the ATL's approach to pointer validity tests, opposed to
|
||||
// the wx/boost approach (which uses some bizarre member method pointer crap, and can't
|
||||
// allow the T* implicit casting.
|
||||
// ----------------------------------------------------------------------------
|
||||
// ScopedPtrMT Operators
|
||||
// ----------------------------------------------------------------------------
|
||||
// I've decided to use the ATL's approach to pointer validity tests, opposed to
|
||||
// the wx/boost approach (which uses some bizarre member method pointer crap, and can't
|
||||
// allow the T* implicit casting.
|
||||
|
||||
bool operator!() const noexcept
|
||||
{
|
||||
return m_ptr.load() == nullptr;
|
||||
}
|
||||
bool operator!() const noexcept
|
||||
{
|
||||
return m_ptr.load() == nullptr;
|
||||
}
|
||||
|
||||
// Equality
|
||||
bool operator==(T *pT) const noexcept
|
||||
{
|
||||
return m_ptr == pT;
|
||||
}
|
||||
// Equality
|
||||
bool operator==(T* pT) const noexcept
|
||||
{
|
||||
return m_ptr == pT;
|
||||
}
|
||||
|
||||
// Inequality
|
||||
bool operator!=(T *pT) const noexcept
|
||||
{
|
||||
return !operator==(pT);
|
||||
}
|
||||
// Inequality
|
||||
bool operator!=(T* pT) const noexcept
|
||||
{
|
||||
return !operator==(pT);
|
||||
}
|
||||
|
||||
// Convenient assignment operator. ScopedPtrMT = nullptr will issue an automatic deletion
|
||||
// of the managed pointer.
|
||||
ScopedPtrMT &operator=(T *src)
|
||||
{
|
||||
return Reassign(src);
|
||||
}
|
||||
// Convenient assignment operator. ScopedPtrMT = nullptr will issue an automatic deletion
|
||||
// of the managed pointer.
|
||||
ScopedPtrMT& operator=(T* src)
|
||||
{
|
||||
return Reassign(src);
|
||||
}
|
||||
|
||||
#if 0
|
||||
operator T*() const
|
||||
|
@ -133,8 +133,8 @@ public:
|
|||
#endif
|
||||
|
||||
protected:
|
||||
void _Delete_unlocked() noexcept
|
||||
{
|
||||
delete m_ptr.exchange(nullptr);
|
||||
}
|
||||
void _Delete_unlocked() noexcept
|
||||
{
|
||||
delete m_ptr.exchange(nullptr);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -26,49 +26,50 @@
|
|||
|
||||
Threading::Semaphore::Semaphore()
|
||||
{
|
||||
sem_init(&m_sema, false, 0);
|
||||
sem_init(&m_sema, false, 0);
|
||||
}
|
||||
|
||||
Threading::Semaphore::~Semaphore()
|
||||
{
|
||||
sem_destroy(&m_sema);
|
||||
sem_destroy(&m_sema);
|
||||
}
|
||||
|
||||
void Threading::Semaphore::Reset()
|
||||
{
|
||||
sem_destroy(&m_sema);
|
||||
sem_init(&m_sema, false, 0);
|
||||
sem_destroy(&m_sema);
|
||||
sem_init(&m_sema, false, 0);
|
||||
}
|
||||
|
||||
void Threading::Semaphore::Post()
|
||||
{
|
||||
sem_post(&m_sema);
|
||||
sem_post(&m_sema);
|
||||
}
|
||||
|
||||
void Threading::Semaphore::Post(int multiple)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
sem_post_multiple(&m_sema, multiple);
|
||||
sem_post_multiple(&m_sema, multiple);
|
||||
#else
|
||||
// Only w32pthreads has the post_multiple, but it's easy enough to fake:
|
||||
while (multiple > 0) {
|
||||
multiple--;
|
||||
sem_post(&m_sema);
|
||||
}
|
||||
// Only w32pthreads has the post_multiple, but it's easy enough to fake:
|
||||
while (multiple > 0)
|
||||
{
|
||||
multiple--;
|
||||
sem_post(&m_sema);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Threading::Semaphore::WaitWithoutYield()
|
||||
{
|
||||
pxAssertMsg(!wxThread::IsMain(), "Unyielding semaphore wait issued from the main/gui thread. Please use Wait() instead.");
|
||||
sem_wait(&m_sema);
|
||||
pxAssertMsg(!wxThread::IsMain(), "Unyielding semaphore wait issued from the main/gui thread. Please use Wait() instead.");
|
||||
sem_wait(&m_sema);
|
||||
}
|
||||
|
||||
bool Threading::Semaphore::WaitWithoutYield(const wxTimeSpan &timeout)
|
||||
bool Threading::Semaphore::WaitWithoutYield(const wxTimeSpan& timeout)
|
||||
{
|
||||
wxDateTime megafail(wxDateTime::UNow() + timeout);
|
||||
const timespec fail = {megafail.GetTicks(), megafail.GetMillisecond() * 1000000};
|
||||
return sem_timedwait(&m_sema, &fail) == 0;
|
||||
wxDateTime megafail(wxDateTime::UNow() + timeout);
|
||||
const timespec fail = {megafail.GetTicks(), megafail.GetMillisecond() * 1000000};
|
||||
return sem_timedwait(&m_sema, &fail) == 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -80,18 +81,23 @@ bool Threading::Semaphore::WaitWithoutYield(const wxTimeSpan &timeout)
|
|||
void Threading::Semaphore::Wait()
|
||||
{
|
||||
#if wxUSE_GUI
|
||||
if (!wxThread::IsMain() || (wxTheApp == NULL)) {
|
||||
sem_wait(&m_sema);
|
||||
} else if (_WaitGui_RecursionGuard(L"Semaphore::Wait")) {
|
||||
ScopedBusyCursor hourglass(Cursor_ReallyBusy);
|
||||
sem_wait(&m_sema);
|
||||
} else {
|
||||
//ScopedBusyCursor hourglass( Cursor_KindaBusy );
|
||||
while (!WaitWithoutYield(def_yieldgui_interval))
|
||||
YieldToMain();
|
||||
}
|
||||
if (!wxThread::IsMain() || (wxTheApp == NULL))
|
||||
{
|
||||
sem_wait(&m_sema);
|
||||
}
|
||||
else if (_WaitGui_RecursionGuard(L"Semaphore::Wait"))
|
||||
{
|
||||
ScopedBusyCursor hourglass(Cursor_ReallyBusy);
|
||||
sem_wait(&m_sema);
|
||||
}
|
||||
else
|
||||
{
|
||||
//ScopedBusyCursor hourglass( Cursor_KindaBusy );
|
||||
while (!WaitWithoutYield(def_yieldgui_interval))
|
||||
YieldToMain();
|
||||
}
|
||||
#else
|
||||
sem_wait(&m_sema);
|
||||
sem_wait(&m_sema);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -104,29 +110,35 @@ void Threading::Semaphore::Wait()
|
|||
// false if the wait timed out before the semaphore was signaled, or true if the signal was
|
||||
// reached prior to timeout.
|
||||
//
|
||||
bool Threading::Semaphore::Wait(const wxTimeSpan &timeout)
|
||||
bool Threading::Semaphore::Wait(const wxTimeSpan& timeout)
|
||||
{
|
||||
#if wxUSE_GUI
|
||||
if (!wxThread::IsMain() || (wxTheApp == NULL)) {
|
||||
return WaitWithoutYield(timeout);
|
||||
} else if (_WaitGui_RecursionGuard(L"Semaphore::TimedWait")) {
|
||||
ScopedBusyCursor hourglass(Cursor_ReallyBusy);
|
||||
return WaitWithoutYield(timeout);
|
||||
} else {
|
||||
//ScopedBusyCursor hourglass( Cursor_KindaBusy );
|
||||
wxTimeSpan countdown((timeout));
|
||||
if (!wxThread::IsMain() || (wxTheApp == NULL))
|
||||
{
|
||||
return WaitWithoutYield(timeout);
|
||||
}
|
||||
else if (_WaitGui_RecursionGuard(L"Semaphore::TimedWait"))
|
||||
{
|
||||
ScopedBusyCursor hourglass(Cursor_ReallyBusy);
|
||||
return WaitWithoutYield(timeout);
|
||||
}
|
||||
else
|
||||
{
|
||||
//ScopedBusyCursor hourglass( Cursor_KindaBusy );
|
||||
wxTimeSpan countdown((timeout));
|
||||
|
||||
do {
|
||||
if (WaitWithoutYield(def_yieldgui_interval))
|
||||
break;
|
||||
YieldToMain();
|
||||
countdown -= def_yieldgui_interval;
|
||||
} while (countdown.GetMilliseconds() > 0);
|
||||
do
|
||||
{
|
||||
if (WaitWithoutYield(def_yieldgui_interval))
|
||||
break;
|
||||
YieldToMain();
|
||||
countdown -= def_yieldgui_interval;
|
||||
} while (countdown.GetMilliseconds() > 0);
|
||||
|
||||
return countdown.GetMilliseconds() > 0;
|
||||
}
|
||||
return countdown.GetMilliseconds() > 0;
|
||||
}
|
||||
#else
|
||||
return WaitWithoutYield(timeout);
|
||||
return WaitWithoutYield(timeout);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -140,26 +152,26 @@ bool Threading::Semaphore::Wait(const wxTimeSpan &timeout)
|
|||
// to do a lot of no-cancel waits in a tight loop worker thread, for example.
|
||||
void Threading::Semaphore::WaitNoCancel()
|
||||
{
|
||||
int oldstate;
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
|
||||
//WaitWithoutYield();
|
||||
Wait();
|
||||
pthread_setcancelstate(oldstate, NULL);
|
||||
int oldstate;
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
|
||||
//WaitWithoutYield();
|
||||
Wait();
|
||||
pthread_setcancelstate(oldstate, NULL);
|
||||
}
|
||||
|
||||
void Threading::Semaphore::WaitNoCancel(const wxTimeSpan &timeout)
|
||||
void Threading::Semaphore::WaitNoCancel(const wxTimeSpan& timeout)
|
||||
{
|
||||
int oldstate;
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
|
||||
//WaitWithoutYield( timeout );
|
||||
Wait(timeout);
|
||||
pthread_setcancelstate(oldstate, NULL);
|
||||
int oldstate;
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
|
||||
//WaitWithoutYield( timeout );
|
||||
Wait(timeout);
|
||||
pthread_setcancelstate(oldstate, NULL);
|
||||
}
|
||||
|
||||
int Threading::Semaphore::Count()
|
||||
{
|
||||
int retval;
|
||||
sem_getvalue(&m_sema, &retval);
|
||||
return retval;
|
||||
int retval;
|
||||
sem_getvalue(&m_sema, &retval);
|
||||
return retval;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -17,59 +17,59 @@
|
|||
#include "common/Pcsx2Defs.h"
|
||||
#include "common/StringHelpers.h"
|
||||
|
||||
__fi wxString fromUTF8(const char *src)
|
||||
__fi wxString fromUTF8(const char* src)
|
||||
{
|
||||
// IMPORTANT: We cannot use wxString::FromUTF8 because it *stupidly* relies on a C++ global instance of
|
||||
// wxMBConvUTF8(). C++ initializes and destroys these globals at random, so any object constructor or
|
||||
// destructor that attempts to do logging may crash the app (either during startup or during exit) unless
|
||||
// we use a LOCAL instance of wxMBConvUTF8(). --air
|
||||
// IMPORTANT: We cannot use wxString::FromUTF8 because it *stupidly* relies on a C++ global instance of
|
||||
// wxMBConvUTF8(). C++ initializes and destroys these globals at random, so any object constructor or
|
||||
// destructor that attempts to do logging may crash the app (either during startup or during exit) unless
|
||||
// we use a LOCAL instance of wxMBConvUTF8(). --air
|
||||
|
||||
// Performance? No worries. wxMBConvUTF8() is virtually free. Initializing a stack copy of the class
|
||||
// is just as efficient as passing a pointer to a pre-instanced global. (which makes me wonder wh wxWidgets
|
||||
// uses the stupid globals in the first place!) --air
|
||||
// Performance? No worries. wxMBConvUTF8() is virtually free. Initializing a stack copy of the class
|
||||
// is just as efficient as passing a pointer to a pre-instanced global. (which makes me wonder wh wxWidgets
|
||||
// uses the stupid globals in the first place!) --air
|
||||
|
||||
return wxString(src, wxMBConvUTF8());
|
||||
return wxString(src, wxMBConvUTF8());
|
||||
}
|
||||
|
||||
__fi wxString fromAscii(const char *src)
|
||||
__fi wxString fromAscii(const char* src)
|
||||
{
|
||||
return wxString::FromAscii(src);
|
||||
return wxString::FromAscii(src);
|
||||
}
|
||||
|
||||
wxString u128::ToString() const
|
||||
{
|
||||
return pxsFmt(L"0x%08X.%08X.%08X.%08X", _u32[0], _u32[1], _u32[2], _u32[3]);
|
||||
return pxsFmt(L"0x%08X.%08X.%08X.%08X", _u32[0], _u32[1], _u32[2], _u32[3]);
|
||||
}
|
||||
|
||||
wxString u128::ToString64() const
|
||||
{
|
||||
return pxsFmt(L"0x%08X%08X.%08X%08X", _u32[0], _u32[1], _u32[2], _u32[3]);
|
||||
return pxsFmt(L"0x%08X%08X.%08X%08X", _u32[0], _u32[1], _u32[2], _u32[3]);
|
||||
}
|
||||
|
||||
wxString u128::ToString8() const
|
||||
{
|
||||
FastFormatUnicode result;
|
||||
result.Write(L"0x%02X.%02X", _u8[0], _u8[1]);
|
||||
for (uint i = 2; i < 16; i += 2)
|
||||
result.Write(L".%02X.%02X", _u8[i], _u8[i + 1]);
|
||||
return result;
|
||||
FastFormatUnicode result;
|
||||
result.Write(L"0x%02X.%02X", _u8[0], _u8[1]);
|
||||
for (uint i = 2; i < 16; i += 2)
|
||||
result.Write(L".%02X.%02X", _u8[i], _u8[i + 1]);
|
||||
return result;
|
||||
}
|
||||
|
||||
void u128::WriteTo(FastFormatAscii &dest) const
|
||||
void u128::WriteTo(FastFormatAscii& dest) const
|
||||
{
|
||||
dest.Write("0x%08X.%08X.%08X.%08X", _u32[0], _u32[1], _u32[2], _u32[3]);
|
||||
dest.Write("0x%08X.%08X.%08X.%08X", _u32[0], _u32[1], _u32[2], _u32[3]);
|
||||
}
|
||||
|
||||
void u128::WriteTo64(FastFormatAscii &dest) const
|
||||
void u128::WriteTo64(FastFormatAscii& dest) const
|
||||
{
|
||||
dest.Write("0x%08X%08X.%08X%08X", _u32[0], _u32[1], _u32[2], _u32[3]);
|
||||
dest.Write("0x%08X%08X.%08X%08X", _u32[0], _u32[1], _u32[2], _u32[3]);
|
||||
}
|
||||
|
||||
void u128::WriteTo8(FastFormatAscii &dest) const
|
||||
void u128::WriteTo8(FastFormatAscii& dest) const
|
||||
{
|
||||
dest.Write("0x%02X.%02X", _u8[0], _u8[1]);
|
||||
for (uint i = 2; i < 16; i += 2)
|
||||
dest.Write(".%02X.%02X", _u8[i], _u8[i + 1]);
|
||||
dest.Write("0x%02X.%02X", _u8[0], _u8[1]);
|
||||
for (uint i = 2; i < 16; i += 2)
|
||||
dest.Write(".%02X.%02X", _u8[i], _u8[i + 1]);
|
||||
}
|
||||
|
||||
// Splits a string into parts and adds the parts into the given SafeList.
|
||||
|
@ -78,11 +78,11 @@ void u128::WriteTo8(FastFormatAscii &dest) const
|
|||
//
|
||||
// Note: wxWidgets 2.9 / 3.0 has a wxSplit function, but we're using 2.8 so I had to make
|
||||
// my own.
|
||||
void SplitString(wxArrayString &dest, const wxString &src, const wxString &delims, wxStringTokenizerMode mode)
|
||||
void SplitString(wxArrayString& dest, const wxString& src, const wxString& delims, wxStringTokenizerMode mode)
|
||||
{
|
||||
wxStringTokenizer parts(src, delims, mode);
|
||||
while (parts.HasMoreTokens())
|
||||
dest.Add(parts.GetNextToken());
|
||||
wxStringTokenizer parts(src, delims, mode);
|
||||
while (parts.HasMoreTokens())
|
||||
dest.Add(parts.GetNextToken());
|
||||
}
|
||||
|
||||
// Joins a list of strings into one larger string, using the given string concatenation
|
||||
|
@ -91,32 +91,34 @@ void SplitString(wxArrayString &dest, const wxString &src, const wxString &delim
|
|||
//
|
||||
// Note: wxWidgets 2.9 / 3.0 has a wxJoin function, but we're using 2.8 so I had to make
|
||||
// my own.
|
||||
wxString JoinString(const wxArrayString &src, const wxString &separator)
|
||||
wxString JoinString(const wxArrayString& src, const wxString& separator)
|
||||
{
|
||||
wxString dest;
|
||||
for (int i = 0, len = src.GetCount(); i < len; ++i) {
|
||||
if (src[i].IsEmpty())
|
||||
continue;
|
||||
if (!dest.IsEmpty())
|
||||
dest += separator;
|
||||
dest += src[i];
|
||||
}
|
||||
return dest;
|
||||
wxString dest;
|
||||
for (int i = 0, len = src.GetCount(); i < len; ++i)
|
||||
{
|
||||
if (src[i].IsEmpty())
|
||||
continue;
|
||||
if (!dest.IsEmpty())
|
||||
dest += separator;
|
||||
dest += src[i];
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
wxString JoinString(const wxChar **src, const wxString &separator)
|
||||
wxString JoinString(const wxChar** src, const wxString& separator)
|
||||
{
|
||||
wxString dest;
|
||||
while (*src != NULL) {
|
||||
if (*src[0] == 0)
|
||||
continue;
|
||||
wxString dest;
|
||||
while (*src != NULL)
|
||||
{
|
||||
if (*src[0] == 0)
|
||||
continue;
|
||||
|
||||
if (!dest.IsEmpty())
|
||||
dest += separator;
|
||||
dest += *src;
|
||||
++src;
|
||||
}
|
||||
return dest;
|
||||
if (!dest.IsEmpty())
|
||||
dest += separator;
|
||||
dest += *src;
|
||||
++src;
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
|
||||
|
@ -127,12 +129,12 @@ wxString JoinString(const wxChar **src, const wxString &separator)
|
|||
// This, so far, include types such as wxPoint, wxRect, and wxSize.
|
||||
//
|
||||
template <typename T>
|
||||
T Parse(const wxString &src, const wxString &separators = L",")
|
||||
T Parse(const wxString& src, const wxString& separators = L",")
|
||||
{
|
||||
T retval;
|
||||
if (!TryParse(retval, src, separators))
|
||||
throw Exception::ParseError("Parse failure on call to " + fromUTF8(__WXFUNCTION__) + ": " + src);
|
||||
return retval;
|
||||
T retval;
|
||||
if (!TryParse(retval, src, separators))
|
||||
throw Exception::ParseError("Parse failure on call to " + fromUTF8(__WXFUNCTION__) + ": " + src);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
|
@ -141,104 +143,104 @@ T Parse(const wxString &src, const wxString &separators = L",")
|
|||
// --------------------------------------------------------------------------------------
|
||||
|
||||
// Converts a wxPoint into a comma-delimited string!
|
||||
wxString ToString(const wxPoint &src, const wxString &separator)
|
||||
wxString ToString(const wxPoint& src, const wxString& separator)
|
||||
{
|
||||
return wxString() << src.x << separator << src.y;
|
||||
return wxString() << src.x << separator << src.y;
|
||||
}
|
||||
|
||||
wxString ToString(const wxSize &src, const wxString &separator)
|
||||
wxString ToString(const wxSize& src, const wxString& separator)
|
||||
{
|
||||
return wxString() << src.GetWidth() << separator << src.GetHeight();
|
||||
return wxString() << src.GetWidth() << separator << src.GetHeight();
|
||||
}
|
||||
|
||||
// Converts a wxRect into a comma-delimited string!
|
||||
// Example: 32,64,128,5
|
||||
wxString ToString(const wxRect &src, const wxString &separator)
|
||||
wxString ToString(const wxRect& src, const wxString& separator)
|
||||
{
|
||||
return ToString(src.GetLeftTop(), separator) << separator << ToString(src.GetSize(), separator);
|
||||
return ToString(src.GetLeftTop(), separator) << separator << ToString(src.GetSize(), separator);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Parse helpers for wxString!
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
bool TryParse(wxPoint &dest, wxStringTokenizer &parts)
|
||||
bool TryParse(wxPoint& dest, wxStringTokenizer& parts)
|
||||
{
|
||||
long result[2];
|
||||
long result[2];
|
||||
|
||||
if (!parts.HasMoreTokens() || !parts.GetNextToken().ToLong(&result[0]))
|
||||
return false;
|
||||
if (!parts.HasMoreTokens() || !parts.GetNextToken().ToLong(&result[1]))
|
||||
return false;
|
||||
dest.x = result[0];
|
||||
dest.y = result[1];
|
||||
if (!parts.HasMoreTokens() || !parts.GetNextToken().ToLong(&result[0]))
|
||||
return false;
|
||||
if (!parts.HasMoreTokens() || !parts.GetNextToken().ToLong(&result[1]))
|
||||
return false;
|
||||
dest.x = result[0];
|
||||
dest.y = result[1];
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TryParse(wxSize &dest, wxStringTokenizer &parts)
|
||||
bool TryParse(wxSize& dest, wxStringTokenizer& parts)
|
||||
{
|
||||
long result[2];
|
||||
long result[2];
|
||||
|
||||
if (!parts.HasMoreTokens() || !parts.GetNextToken().ToLong(&result[0]))
|
||||
return false;
|
||||
if (!parts.HasMoreTokens() || !parts.GetNextToken().ToLong(&result[1]))
|
||||
return false;
|
||||
dest.SetWidth(result[0]);
|
||||
dest.SetHeight(result[1]);
|
||||
if (!parts.HasMoreTokens() || !parts.GetNextToken().ToLong(&result[0]))
|
||||
return false;
|
||||
if (!parts.HasMoreTokens() || !parts.GetNextToken().ToLong(&result[1]))
|
||||
return false;
|
||||
dest.SetWidth(result[0]);
|
||||
dest.SetHeight(result[1]);
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Tries to parse the given string into a wxPoint value at 'dest.' If the parse fails, the
|
||||
// method aborts and returns false.
|
||||
bool TryParse(wxPoint &dest, const wxString &src, const wxPoint &defval, const wxString &separators)
|
||||
bool TryParse(wxPoint& dest, const wxString& src, const wxPoint& defval, const wxString& separators)
|
||||
{
|
||||
dest = defval;
|
||||
wxStringTokenizer parts(src, separators);
|
||||
return TryParse(dest, parts);
|
||||
dest = defval;
|
||||
wxStringTokenizer parts(src, separators);
|
||||
return TryParse(dest, parts);
|
||||
}
|
||||
|
||||
bool TryParse(wxSize &dest, const wxString &src, const wxSize &defval, const wxString &separators)
|
||||
bool TryParse(wxSize& dest, const wxString& src, const wxSize& defval, const wxString& separators)
|
||||
{
|
||||
dest = defval;
|
||||
wxStringTokenizer parts(src, separators);
|
||||
return TryParse(dest, parts);
|
||||
dest = defval;
|
||||
wxStringTokenizer parts(src, separators);
|
||||
return TryParse(dest, parts);
|
||||
}
|
||||
|
||||
bool TryParse(wxRect &dest, const wxString &src, const wxRect &defval, const wxString &separators)
|
||||
bool TryParse(wxRect& dest, const wxString& src, const wxRect& defval, const wxString& separators)
|
||||
{
|
||||
dest = defval;
|
||||
dest = defval;
|
||||
|
||||
wxStringTokenizer parts(src, separators);
|
||||
wxStringTokenizer parts(src, separators);
|
||||
|
||||
wxPoint point;
|
||||
wxSize size;
|
||||
wxPoint point;
|
||||
wxSize size;
|
||||
|
||||
if (!TryParse(point, parts))
|
||||
return false;
|
||||
if (!TryParse(size, parts))
|
||||
return false;
|
||||
if (!TryParse(point, parts))
|
||||
return false;
|
||||
if (!TryParse(size, parts))
|
||||
return false;
|
||||
|
||||
dest = wxRect(point, size);
|
||||
return true;
|
||||
dest = wxRect(point, size);
|
||||
return true;
|
||||
}
|
||||
|
||||
// returns TRUE if the parse is valid, or FALSE if it's a comment.
|
||||
bool pxParseAssignmentString(const wxString &src, wxString &ldest, wxString &rdest)
|
||||
bool pxParseAssignmentString(const wxString& src, wxString& ldest, wxString& rdest)
|
||||
{
|
||||
if (src.StartsWith(L"--") || src.StartsWith(L"//") || src.StartsWith(L";"))
|
||||
return false;
|
||||
if (src.StartsWith(L"--") || src.StartsWith(L"//") || src.StartsWith(L";"))
|
||||
return false;
|
||||
|
||||
ldest = src.BeforeFirst(L'=').Trim(true).Trim(false);
|
||||
rdest = src.AfterFirst(L'=').Trim(true).Trim(false);
|
||||
ldest = src.BeforeFirst(L'=').Trim(true).Trim(false);
|
||||
rdest = src.AfterFirst(L'=').Trim(true).Trim(false);
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
ParsedAssignmentString::ParsedAssignmentString(const wxString &src)
|
||||
ParsedAssignmentString::ParsedAssignmentString(const wxString& src)
|
||||
{
|
||||
IsComment = pxParseAssignmentString(src, lvalue, rvalue);
|
||||
IsComment = pxParseAssignmentString(src, lvalue, rvalue);
|
||||
}
|
||||
|
||||
// Performs a cross-platform puts operation, which adds CRs to naked LFs on Win32 platforms,
|
||||
|
@ -249,37 +251,41 @@ ParsedAssignmentString::ParsedAssignmentString(const wxString &src)
|
|||
// from incoming data. Mac platforms may need an implementation of their own that converts
|
||||
// newlines to CRs...?
|
||||
//
|
||||
void px_fputs(FILE *fp, const char *src)
|
||||
void px_fputs(FILE* fp, const char* src)
|
||||
{
|
||||
if (fp == NULL)
|
||||
return;
|
||||
if (fp == NULL)
|
||||
return;
|
||||
|
||||
#ifdef _WIN32
|
||||
// Windows needs CR's partnered with all newlines, or else notepad.exe can't view
|
||||
// the stupid logfile. Best way is to write one char at a time.. >_<
|
||||
// Windows needs CR's partnered with all newlines, or else notepad.exe can't view
|
||||
// the stupid logfile. Best way is to write one char at a time.. >_<
|
||||
|
||||
const char *curchar = src;
|
||||
bool prevcr = false;
|
||||
while (*curchar != 0) {
|
||||
if (*curchar == '\r') {
|
||||
prevcr = true;
|
||||
} else {
|
||||
// Only write a CR/LF pair if the current LF is not prefixed nor
|
||||
// post-fixed by a CR.
|
||||
if (*curchar == '\n' && !prevcr && (*(curchar + 1) != '\r'))
|
||||
fputs("\r\n", fp);
|
||||
else
|
||||
fputc(*curchar, fp);
|
||||
const char* curchar = src;
|
||||
bool prevcr = false;
|
||||
while (*curchar != 0)
|
||||
{
|
||||
if (*curchar == '\r')
|
||||
{
|
||||
prevcr = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Only write a CR/LF pair if the current LF is not prefixed nor
|
||||
// post-fixed by a CR.
|
||||
if (*curchar == '\n' && !prevcr && (*(curchar + 1) != '\r'))
|
||||
fputs("\r\n", fp);
|
||||
else
|
||||
fputc(*curchar, fp);
|
||||
|
||||
prevcr = false;
|
||||
}
|
||||
++curchar;
|
||||
}
|
||||
prevcr = false;
|
||||
}
|
||||
++curchar;
|
||||
}
|
||||
|
||||
#else
|
||||
// Linux is happy with plain old LFs. Not sure about Macs... does OSX still
|
||||
// go by the old school Mac style of using Crs only?
|
||||
// Linux is happy with plain old LFs. Not sure about Macs... does OSX still
|
||||
// go by the old school Mac style of using Crs only?
|
||||
|
||||
fputs(src, fp); // fputs does not do automatic newlines, so it's ok!
|
||||
fputs(src, fp); // fputs does not do automatic newlines, so it's ok!
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#define WX_STR(str) (str.wc_str())
|
||||
#else
|
||||
// Stupid wx3.0 doesn't support c_str for vararg function
|
||||
#define WX_STR(str) (static_cast<const char *>(str.c_str()))
|
||||
#define WX_STR(str) (static_cast<const char*>(str.c_str()))
|
||||
#endif
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -33,59 +33,59 @@
|
|||
// Converts a string to UTF8 and provides an interface for getting its length.
|
||||
class pxToUTF8
|
||||
{
|
||||
DeclareNoncopyableObject(pxToUTF8);
|
||||
DeclareNoncopyableObject(pxToUTF8);
|
||||
|
||||
protected:
|
||||
wxCharBuffer m_result;
|
||||
int m_length;
|
||||
wxCharBuffer m_result;
|
||||
int m_length;
|
||||
|
||||
public:
|
||||
explicit pxToUTF8(const wxString &src)
|
||||
: m_result(src.ToUTF8())
|
||||
{
|
||||
m_length = -1;
|
||||
}
|
||||
explicit pxToUTF8(const wxString& src)
|
||||
: m_result(src.ToUTF8())
|
||||
{
|
||||
m_length = -1;
|
||||
}
|
||||
|
||||
size_t Length()
|
||||
{
|
||||
if (-1 == m_length)
|
||||
m_length = strlen(m_result);
|
||||
return m_length;
|
||||
}
|
||||
size_t Length()
|
||||
{
|
||||
if (-1 == m_length)
|
||||
m_length = strlen(m_result);
|
||||
return m_length;
|
||||
}
|
||||
|
||||
void Convert(const wxString &src)
|
||||
{
|
||||
m_result = src.ToUTF8();
|
||||
m_length = -1;
|
||||
}
|
||||
void Convert(const wxString& src)
|
||||
{
|
||||
m_result = src.ToUTF8();
|
||||
m_length = -1;
|
||||
}
|
||||
|
||||
const char *data() const { return m_result; }
|
||||
const char* data() const { return m_result; }
|
||||
|
||||
operator const char *() const
|
||||
{
|
||||
return m_result.data();
|
||||
}
|
||||
operator const char*() const
|
||||
{
|
||||
return m_result.data();
|
||||
}
|
||||
};
|
||||
|
||||
extern void px_fputs(FILE *fp, const char *src);
|
||||
extern void px_fputs(FILE* fp, const char* src);
|
||||
|
||||
// wxWidgets lacks one of its own...
|
||||
extern const wxRect wxDefaultRect;
|
||||
|
||||
extern void SplitString(wxArrayString &dest, const wxString &src, const wxString &delims, wxStringTokenizerMode mode = wxTOKEN_RET_EMPTY_ALL);
|
||||
extern wxString JoinString(const wxArrayString &src, const wxString &separator);
|
||||
extern wxString JoinString(const wxChar **src, const wxString &separator);
|
||||
extern void SplitString(wxArrayString& dest, const wxString& src, const wxString& delims, wxStringTokenizerMode mode = wxTOKEN_RET_EMPTY_ALL);
|
||||
extern wxString JoinString(const wxArrayString& src, const wxString& separator);
|
||||
extern wxString JoinString(const wxChar** src, const wxString& separator);
|
||||
|
||||
extern wxString ToString(const wxPoint &src, const wxString &separator = L",");
|
||||
extern wxString ToString(const wxSize &src, const wxString &separator = L",");
|
||||
extern wxString ToString(const wxRect &src, const wxString &separator = L",");
|
||||
extern wxString ToString(const wxPoint& src, const wxString& separator = L",");
|
||||
extern wxString ToString(const wxSize& src, const wxString& separator = L",");
|
||||
extern wxString ToString(const wxRect& src, const wxString& separator = L",");
|
||||
|
||||
extern bool TryParse(wxPoint &dest, const wxStringTokenizer &parts);
|
||||
extern bool TryParse(wxSize &dest, const wxStringTokenizer &parts);
|
||||
extern bool TryParse(wxPoint& dest, const wxStringTokenizer& parts);
|
||||
extern bool TryParse(wxSize& dest, const wxStringTokenizer& parts);
|
||||
|
||||
extern bool TryParse(wxPoint &dest, const wxString &src, const wxPoint &defval = wxDefaultPosition, const wxString &separators = L",");
|
||||
extern bool TryParse(wxSize &dest, const wxString &src, const wxSize &defval = wxDefaultSize, const wxString &separators = L",");
|
||||
extern bool TryParse(wxRect &dest, const wxString &src, const wxRect &defval = wxDefaultRect, const wxString &separators = L",");
|
||||
extern bool TryParse(wxPoint& dest, const wxString& src, const wxPoint& defval = wxDefaultPosition, const wxString& separators = L",");
|
||||
extern bool TryParse(wxSize& dest, const wxString& src, const wxSize& defval = wxDefaultSize, const wxString& separators = L",");
|
||||
extern bool TryParse(wxRect& dest, const wxString& src, const wxRect& defval = wxDefaultRect, const wxString& separators = L",");
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// ParsedAssignmentString
|
||||
|
@ -103,11 +103,11 @@ extern bool TryParse(wxRect &dest, const wxString &src, const wxRect &defval = w
|
|||
//
|
||||
struct ParsedAssignmentString
|
||||
{
|
||||
wxString lvalue;
|
||||
wxString rvalue;
|
||||
bool IsComment;
|
||||
wxString lvalue;
|
||||
wxString rvalue;
|
||||
bool IsComment;
|
||||
|
||||
ParsedAssignmentString(const wxString &src);
|
||||
ParsedAssignmentString(const wxString& src);
|
||||
};
|
||||
|
||||
// ======================================================================================
|
||||
|
@ -139,40 +139,40 @@ typedef ScopedAlignedAlloc<char, 16> CharBufferType;
|
|||
class FastFormatAscii
|
||||
{
|
||||
protected:
|
||||
CharBufferType m_dest;
|
||||
CharBufferType m_dest;
|
||||
|
||||
public:
|
||||
FastFormatAscii();
|
||||
~FastFormatAscii() = default;
|
||||
FastFormatAscii &Write(const char *fmt, ...);
|
||||
FastFormatAscii &WriteV(const char *fmt, va_list argptr);
|
||||
FastFormatAscii();
|
||||
~FastFormatAscii() = default;
|
||||
FastFormatAscii& Write(const char* fmt, ...);
|
||||
FastFormatAscii& WriteV(const char* fmt, va_list argptr);
|
||||
|
||||
void Clear();
|
||||
bool IsEmpty() const;
|
||||
void Clear();
|
||||
bool IsEmpty() const;
|
||||
|
||||
const char *c_str() const { return m_dest.GetPtr(); }
|
||||
operator const char *() const { return m_dest.GetPtr(); }
|
||||
const char* c_str() const { return m_dest.GetPtr(); }
|
||||
operator const char*() const { return m_dest.GetPtr(); }
|
||||
|
||||
const wxString GetString() const;
|
||||
//operator wxString() const;
|
||||
const wxString GetString() const;
|
||||
//operator wxString() const;
|
||||
|
||||
FastFormatAscii &operator+=(const wxString &s)
|
||||
{
|
||||
Write("%s", WX_STR(s));
|
||||
return *this;
|
||||
}
|
||||
FastFormatAscii& operator+=(const wxString& s)
|
||||
{
|
||||
Write("%s", WX_STR(s));
|
||||
return *this;
|
||||
}
|
||||
|
||||
FastFormatAscii &operator+=(const wxChar *psz)
|
||||
{
|
||||
Write("%ls", psz);
|
||||
return *this;
|
||||
}
|
||||
FastFormatAscii& operator+=(const wxChar* psz)
|
||||
{
|
||||
Write("%ls", psz);
|
||||
return *this;
|
||||
}
|
||||
|
||||
FastFormatAscii &operator+=(const char *psz)
|
||||
{
|
||||
Write("%s", psz);
|
||||
return *this;
|
||||
}
|
||||
FastFormatAscii& operator+=(const char* psz)
|
||||
{
|
||||
Write("%s", psz);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -181,54 +181,54 @@ public:
|
|||
class FastFormatUnicode
|
||||
{
|
||||
protected:
|
||||
CharBufferType m_dest;
|
||||
uint m_Length;
|
||||
CharBufferType m_dest;
|
||||
uint m_Length;
|
||||
|
||||
public:
|
||||
FastFormatUnicode();
|
||||
~FastFormatUnicode() = default;
|
||||
FastFormatUnicode();
|
||||
~FastFormatUnicode() = default;
|
||||
|
||||
FastFormatUnicode &Write(const char *fmt, ...);
|
||||
FastFormatUnicode &Write(const wxChar *fmt, ...);
|
||||
FastFormatUnicode &Write(const wxString fmt, ...);
|
||||
FastFormatUnicode &WriteV(const char *fmt, va_list argptr);
|
||||
FastFormatUnicode &WriteV(const wxChar *fmt, va_list argptr);
|
||||
FastFormatUnicode& Write(const char* fmt, ...);
|
||||
FastFormatUnicode& Write(const wxChar* fmt, ...);
|
||||
FastFormatUnicode& Write(const wxString fmt, ...);
|
||||
FastFormatUnicode& WriteV(const char* fmt, va_list argptr);
|
||||
FastFormatUnicode& WriteV(const wxChar* fmt, va_list argptr);
|
||||
|
||||
void Clear();
|
||||
bool IsEmpty() const;
|
||||
uint Length() const { return m_Length; }
|
||||
void Clear();
|
||||
bool IsEmpty() const;
|
||||
uint Length() const { return m_Length; }
|
||||
|
||||
FastFormatUnicode &ToUpper();
|
||||
FastFormatUnicode &ToLower();
|
||||
FastFormatUnicode& ToUpper();
|
||||
FastFormatUnicode& ToLower();
|
||||
|
||||
const wxChar *c_str() const { return (const wxChar *)m_dest.GetPtr(); }
|
||||
operator const wxChar *() const { return (const wxChar *)m_dest.GetPtr(); }
|
||||
operator wxString() const { return (const wxChar *)m_dest.GetPtr(); }
|
||||
const wxChar* c_str() const { return (const wxChar*)m_dest.GetPtr(); }
|
||||
operator const wxChar*() const { return (const wxChar*)m_dest.GetPtr(); }
|
||||
operator wxString() const { return (const wxChar*)m_dest.GetPtr(); }
|
||||
|
||||
FastFormatUnicode &operator+=(const wxString &s)
|
||||
{
|
||||
Write(L"%s", WX_STR(s));
|
||||
return *this;
|
||||
}
|
||||
FastFormatUnicode& operator+=(const wxString& s)
|
||||
{
|
||||
Write(L"%s", WX_STR(s));
|
||||
return *this;
|
||||
}
|
||||
|
||||
FastFormatUnicode &operator+=(const wxChar *psz)
|
||||
{
|
||||
Write(L"%s", psz);
|
||||
return *this;
|
||||
}
|
||||
FastFormatUnicode& operator+=(const wxChar* psz)
|
||||
{
|
||||
Write(L"%s", psz);
|
||||
return *this;
|
||||
}
|
||||
|
||||
FastFormatUnicode &operator+=(const char *psz);
|
||||
FastFormatUnicode& operator+=(const char* psz);
|
||||
};
|
||||
|
||||
extern bool pxParseAssignmentString(const wxString &src, wxString &ldest, wxString &rdest);
|
||||
extern bool pxParseAssignmentString(const wxString& src, wxString& ldest, wxString& rdest);
|
||||
|
||||
#define pxsFmt FastFormatUnicode().Write
|
||||
#define pxsFmtV FastFormatUnicode().WriteV
|
||||
|
||||
#define pxsPtr(ptr) pxsFmt("0x%08X", (ptr)).c_str()
|
||||
|
||||
extern wxString &operator+=(wxString &str1, const FastFormatUnicode &str2);
|
||||
extern wxString operator+(const wxString &str1, const FastFormatUnicode &str2);
|
||||
extern wxString operator+(const wxChar *str1, const FastFormatUnicode &str2);
|
||||
extern wxString operator+(const FastFormatUnicode &str1, const wxString &str2);
|
||||
extern wxString operator+(const FastFormatUnicode &str1, const wxChar *str2);
|
||||
extern wxString& operator+=(wxString& str1, const FastFormatUnicode& str2);
|
||||
extern wxString operator+(const wxString& str1, const FastFormatUnicode& str2);
|
||||
extern wxString operator+(const wxChar* str1, const FastFormatUnicode& str2);
|
||||
extern wxString operator+(const FastFormatUnicode& str1, const wxString& str2);
|
||||
extern wxString operator+(const FastFormatUnicode& str1, const wxChar* str2);
|
||||
|
|
|
@ -33,12 +33,12 @@ const wxTimeSpan Threading::def_yieldgui_interval(0, 0, 0, 100);
|
|||
|
||||
ConsoleLogSource_Threading::ConsoleLogSource_Threading()
|
||||
{
|
||||
static const TraceLogDescriptor myDesc =
|
||||
{
|
||||
L"p&xThread", L"pxThread",
|
||||
pxLt("Threading activity: start, detach, sync, deletion, etc.")};
|
||||
static const TraceLogDescriptor myDesc =
|
||||
{
|
||||
L"p&xThread", L"pxThread",
|
||||
pxLt("Threading activity: start, detach, sync, deletion, etc.")};
|
||||
|
||||
m_Descriptor = &myDesc;
|
||||
m_Descriptor = &myDesc;
|
||||
}
|
||||
|
||||
ConsoleLogSource_Threading pxConLog_Thread;
|
||||
|
@ -47,18 +47,18 @@ ConsoleLogSource_Threading pxConLog_Thread;
|
|||
class StaticMutex : public Mutex
|
||||
{
|
||||
protected:
|
||||
bool &m_DeletedFlag;
|
||||
bool& m_DeletedFlag;
|
||||
|
||||
public:
|
||||
StaticMutex(bool &deletedFlag)
|
||||
: m_DeletedFlag(deletedFlag)
|
||||
{
|
||||
}
|
||||
StaticMutex(bool& deletedFlag)
|
||||
: m_DeletedFlag(deletedFlag)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~StaticMutex()
|
||||
{
|
||||
m_DeletedFlag = true;
|
||||
}
|
||||
virtual ~StaticMutex()
|
||||
{
|
||||
m_DeletedFlag = true;
|
||||
}
|
||||
};
|
||||
|
||||
static pthread_key_t curthread_key = 0;
|
||||
|
@ -67,111 +67,115 @@ static s32 total_key_count = 0;
|
|||
static bool tkl_destructed = false;
|
||||
static StaticMutex total_key_lock(tkl_destructed);
|
||||
|
||||
static void make_curthread_key(const pxThread *thr)
|
||||
static void make_curthread_key(const pxThread* thr)
|
||||
{
|
||||
pxAssumeDev(!tkl_destructed, "total_key_lock is destroyed; program is shutting down; cannot create new thread key.");
|
||||
pxAssumeDev(!tkl_destructed, "total_key_lock is destroyed; program is shutting down; cannot create new thread key.");
|
||||
|
||||
ScopedLock lock(total_key_lock);
|
||||
if (total_key_count++ != 0)
|
||||
return;
|
||||
ScopedLock lock(total_key_lock);
|
||||
if (total_key_count++ != 0)
|
||||
return;
|
||||
|
||||
if (0 != pthread_key_create(&curthread_key, NULL)) {
|
||||
pxThreadLog.Error(thr->GetName(), L"Thread key creation failed (probably out of memory >_<)");
|
||||
curthread_key = 0;
|
||||
}
|
||||
if (0 != pthread_key_create(&curthread_key, NULL))
|
||||
{
|
||||
pxThreadLog.Error(thr->GetName(), L"Thread key creation failed (probably out of memory >_<)");
|
||||
curthread_key = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void unmake_curthread_key()
|
||||
{
|
||||
ScopedLock lock;
|
||||
if (!tkl_destructed)
|
||||
lock.AssignAndLock(total_key_lock);
|
||||
ScopedLock lock;
|
||||
if (!tkl_destructed)
|
||||
lock.AssignAndLock(total_key_lock);
|
||||
|
||||
if (--total_key_count > 0)
|
||||
return;
|
||||
if (--total_key_count > 0)
|
||||
return;
|
||||
|
||||
if (curthread_key)
|
||||
pthread_key_delete(curthread_key);
|
||||
if (curthread_key)
|
||||
pthread_key_delete(curthread_key);
|
||||
|
||||
curthread_key = 0;
|
||||
curthread_key = 0;
|
||||
}
|
||||
|
||||
void Threading::pxTestCancel()
|
||||
{
|
||||
pthread_testcancel();
|
||||
pthread_testcancel();
|
||||
}
|
||||
|
||||
// Returns a handle to the current persistent thread. If the current thread does not belong
|
||||
// to the pxThread table, NULL is returned. Since the main/ui thread is not created
|
||||
// through pxThread it will also return NULL. Callers can use wxThread::IsMain() to
|
||||
// test if the NULL thread is the main thread.
|
||||
pxThread *Threading::pxGetCurrentThread()
|
||||
pxThread* Threading::pxGetCurrentThread()
|
||||
{
|
||||
return !curthread_key ? NULL : (pxThread *)pthread_getspecific(curthread_key);
|
||||
return !curthread_key ? NULL : (pxThread*)pthread_getspecific(curthread_key);
|
||||
}
|
||||
|
||||
// returns the name of the current thread, or "Unknown" if the thread is neither a pxThread
|
||||
// nor the Main/UI thread.
|
||||
wxString Threading::pxGetCurrentThreadName()
|
||||
{
|
||||
if (pxThread *thr = pxGetCurrentThread()) {
|
||||
return thr->GetName();
|
||||
} else if (wxThread::IsMain()) {
|
||||
return L"Main/UI";
|
||||
}
|
||||
if (pxThread* thr = pxGetCurrentThread())
|
||||
{
|
||||
return thr->GetName();
|
||||
}
|
||||
else if (wxThread::IsMain())
|
||||
{
|
||||
return L"Main/UI";
|
||||
}
|
||||
|
||||
return L"Unknown";
|
||||
return L"Unknown";
|
||||
}
|
||||
|
||||
void Threading::pxYield(int ms)
|
||||
{
|
||||
if (pxThread *thr = pxGetCurrentThread())
|
||||
thr->Yield(ms);
|
||||
else
|
||||
Sleep(ms);
|
||||
if (pxThread* thr = pxGetCurrentThread())
|
||||
thr->Yield(ms);
|
||||
else
|
||||
Sleep(ms);
|
||||
}
|
||||
|
||||
// (intended for internal use only)
|
||||
// Returns true if the Wait is recursive, or false if the Wait is safe and should be
|
||||
// handled via normal yielding methods.
|
||||
bool Threading::_WaitGui_RecursionGuard(const wxChar *name)
|
||||
bool Threading::_WaitGui_RecursionGuard(const wxChar* name)
|
||||
{
|
||||
AffinityAssert_AllowFrom_MainUI();
|
||||
AffinityAssert_AllowFrom_MainUI();
|
||||
|
||||
// In order to avoid deadlock we need to make sure we cut some time to handle messages.
|
||||
// But this can result in recursive yield calls, which would crash the app. Protect
|
||||
// against them here and, if recursion is detected, perform a standard blocking wait.
|
||||
// In order to avoid deadlock we need to make sure we cut some time to handle messages.
|
||||
// But this can result in recursive yield calls, which would crash the app. Protect
|
||||
// against them here and, if recursion is detected, perform a standard blocking wait.
|
||||
|
||||
static int __Guard = 0;
|
||||
RecursionGuard guard(__Guard);
|
||||
static int __Guard = 0;
|
||||
RecursionGuard guard(__Guard);
|
||||
|
||||
//if( pxAssertDev( !guard.IsReentrant(), "Recursion during UI-bound threading wait object." ) ) return false;
|
||||
//if( pxAssertDev( !guard.IsReentrant(), "Recursion during UI-bound threading wait object." ) ) return false;
|
||||
|
||||
if (!guard.IsReentrant())
|
||||
return false;
|
||||
pxThreadLog.Write(pxGetCurrentThreadName(),
|
||||
pxsFmt(L"Yield recursion in %s; opening modal dialog.", name));
|
||||
return true;
|
||||
if (!guard.IsReentrant())
|
||||
return false;
|
||||
pxThreadLog.Write(pxGetCurrentThreadName(),
|
||||
pxsFmt(L"Yield recursion in %s; opening modal dialog.", name));
|
||||
return true;
|
||||
}
|
||||
|
||||
__fi void Threading::Timeslice()
|
||||
{
|
||||
sched_yield();
|
||||
sched_yield();
|
||||
}
|
||||
|
||||
void Threading::pxThread::_pt_callback_cleanup(void *handle)
|
||||
void Threading::pxThread::_pt_callback_cleanup(void* handle)
|
||||
{
|
||||
((pxThread *)handle)->_ThreadCleanup();
|
||||
((pxThread*)handle)->_ThreadCleanup();
|
||||
}
|
||||
|
||||
|
||||
Threading::pxThread::pxThread(const wxString &name)
|
||||
: m_name(name)
|
||||
, m_thread()
|
||||
, m_native_id(0)
|
||||
, m_native_handle(0)
|
||||
, m_detached(true) // start out with m_thread in detached/invalid state
|
||||
, m_running(false)
|
||||
Threading::pxThread::pxThread(const wxString& name)
|
||||
: m_name(name)
|
||||
, m_thread()
|
||||
, m_native_id(0)
|
||||
, m_native_handle(0)
|
||||
, m_detached(true) // start out with m_thread in detached/invalid state
|
||||
, m_running(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -184,50 +188,53 @@ Threading::pxThread::pxThread(const wxString &name)
|
|||
// like marrying your sister, and then cheating on her with your daughter.
|
||||
Threading::pxThread::~pxThread()
|
||||
{
|
||||
try {
|
||||
pxThreadLog.Write(GetName(), L"Executing default destructor!");
|
||||
try
|
||||
{
|
||||
pxThreadLog.Write(GetName(), L"Executing default destructor!");
|
||||
|
||||
if (m_running) {
|
||||
pxThreadLog.Write(GetName(), L"Waiting for running thread to end...");
|
||||
m_mtx_InThread.Wait();
|
||||
pxThreadLog.Write(GetName(), L"Thread ended gracefully.");
|
||||
}
|
||||
Threading::Sleep(1);
|
||||
Detach();
|
||||
}
|
||||
DESTRUCTOR_CATCHALL
|
||||
if (m_running)
|
||||
{
|
||||
pxThreadLog.Write(GetName(), L"Waiting for running thread to end...");
|
||||
m_mtx_InThread.Wait();
|
||||
pxThreadLog.Write(GetName(), L"Thread ended gracefully.");
|
||||
}
|
||||
Threading::Sleep(1);
|
||||
Detach();
|
||||
}
|
||||
DESTRUCTOR_CATCHALL
|
||||
}
|
||||
|
||||
bool Threading::pxThread::AffinityAssert_AllowFromSelf(const DiagnosticOrigin &origin) const
|
||||
bool Threading::pxThread::AffinityAssert_AllowFromSelf(const DiagnosticOrigin& origin) const
|
||||
{
|
||||
if (IsSelf())
|
||||
return true;
|
||||
if (IsSelf())
|
||||
return true;
|
||||
|
||||
if (IsDevBuild)
|
||||
pxOnAssert(origin, pxsFmt(L"Thread affinity violation: Call allowed from '%s' thread only.", WX_STR(GetName())));
|
||||
if (IsDevBuild)
|
||||
pxOnAssert(origin, pxsFmt(L"Thread affinity violation: Call allowed from '%s' thread only.", WX_STR(GetName())));
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Threading::pxThread::AffinityAssert_DisallowFromSelf(const DiagnosticOrigin &origin) const
|
||||
bool Threading::pxThread::AffinityAssert_DisallowFromSelf(const DiagnosticOrigin& origin) const
|
||||
{
|
||||
if (!IsSelf())
|
||||
return true;
|
||||
if (!IsSelf())
|
||||
return true;
|
||||
|
||||
if (IsDevBuild)
|
||||
pxOnAssert(origin, pxsFmt(L"Thread affinity violation: Call is *not* allowed from '%s' thread.", WX_STR(GetName())));
|
||||
if (IsDevBuild)
|
||||
pxOnAssert(origin, pxsFmt(L"Thread affinity violation: Call is *not* allowed from '%s' thread.", WX_STR(GetName())));
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
void Threading::pxThread::FrankenMutex(Mutex &mutex)
|
||||
void Threading::pxThread::FrankenMutex(Mutex& mutex)
|
||||
{
|
||||
if (mutex.RecreateIfLocked()) {
|
||||
// Our lock is bupkis, which means the previous thread probably deadlocked.
|
||||
// Let's create a new mutex lock to replace it.
|
||||
if (mutex.RecreateIfLocked())
|
||||
{
|
||||
// Our lock is bupkis, which means the previous thread probably deadlocked.
|
||||
// Let's create a new mutex lock to replace it.
|
||||
|
||||
pxThreadLog.Error(GetName(), L"Possible deadlock detected on restarted mutex!");
|
||||
}
|
||||
pxThreadLog.Error(GetName(), L"Possible deadlock detected on restarted mutex!");
|
||||
}
|
||||
}
|
||||
|
||||
// Main entry point for starting or e-starting a persistent thread. This function performs necessary
|
||||
|
@ -238,53 +245,56 @@ void Threading::pxThread::FrankenMutex(Mutex &mutex)
|
|||
// This function should not be called from the owner thread.
|
||||
void Threading::pxThread::Start()
|
||||
{
|
||||
// Prevents sudden parallel startup, and or parallel startup + cancel:
|
||||
ScopedLock startlock(m_mtx_start);
|
||||
if (m_running) {
|
||||
pxThreadLog.Write(GetName(), L"Start() called on running thread; ignorning...");
|
||||
return;
|
||||
}
|
||||
// Prevents sudden parallel startup, and or parallel startup + cancel:
|
||||
ScopedLock startlock(m_mtx_start);
|
||||
if (m_running)
|
||||
{
|
||||
pxThreadLog.Write(GetName(), L"Start() called on running thread; ignorning...");
|
||||
return;
|
||||
}
|
||||
|
||||
Detach(); // clean up previous thread handle, if one exists.
|
||||
OnStart();
|
||||
Detach(); // clean up previous thread handle, if one exists.
|
||||
OnStart();
|
||||
|
||||
m_except = NULL;
|
||||
m_except = NULL;
|
||||
|
||||
pxThreadLog.Write(GetName(), L"Calling pthread_create...");
|
||||
if (pthread_create(&m_thread, NULL, _internal_callback, this) != 0)
|
||||
throw Exception::ThreadCreationError(this).SetDiagMsg(L"Thread creation error: " + wxString(std::strerror(errno)));
|
||||
pxThreadLog.Write(GetName(), L"Calling pthread_create...");
|
||||
if (pthread_create(&m_thread, NULL, _internal_callback, this) != 0)
|
||||
throw Exception::ThreadCreationError(this).SetDiagMsg(L"Thread creation error: " + wxString(std::strerror(errno)));
|
||||
|
||||
#ifdef ASAN_WORKAROUND
|
||||
// Recent Asan + libc6 do pretty bad stuff on the thread init => https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77982
|
||||
//
|
||||
// In our case, the semaphore was posted (counter is 1) but thread is still
|
||||
// waiting... So waits 100ms and checks the counter value manually
|
||||
if (!m_sem_startup.WaitWithoutYield(wxTimeSpan(0, 0, 0, 100))) {
|
||||
if (m_sem_startup.Count() == 0)
|
||||
throw Exception::ThreadCreationError(this).SetDiagMsg(L"Thread creation error: %s thread never posted startup semaphore.");
|
||||
}
|
||||
// Recent Asan + libc6 do pretty bad stuff on the thread init => https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77982
|
||||
//
|
||||
// In our case, the semaphore was posted (counter is 1) but thread is still
|
||||
// waiting... So waits 100ms and checks the counter value manually
|
||||
if (!m_sem_startup.WaitWithoutYield(wxTimeSpan(0, 0, 0, 100)))
|
||||
{
|
||||
if (m_sem_startup.Count() == 0)
|
||||
throw Exception::ThreadCreationError(this).SetDiagMsg(L"Thread creation error: %s thread never posted startup semaphore.");
|
||||
}
|
||||
#else
|
||||
if (!m_sem_startup.WaitWithoutYield(wxTimeSpan(0, 0, 3, 0))) {
|
||||
RethrowException();
|
||||
if (!m_sem_startup.WaitWithoutYield(wxTimeSpan(0, 0, 3, 0)))
|
||||
{
|
||||
RethrowException();
|
||||
|
||||
// And if the thread threw nothing of its own:
|
||||
throw Exception::ThreadCreationError(this).SetDiagMsg(L"Thread creation error: %s thread never posted startup semaphore.");
|
||||
}
|
||||
// And if the thread threw nothing of its own:
|
||||
throw Exception::ThreadCreationError(this).SetDiagMsg(L"Thread creation error: %s thread never posted startup semaphore.");
|
||||
}
|
||||
#endif
|
||||
|
||||
// Event Rationale (above): Performing this semaphore wait on the created thread is "slow" in the
|
||||
// sense that it stalls the calling thread completely until the new thread is created
|
||||
// (which may not always be desirable). But too bad. In order to safely use 'running' locks
|
||||
// and detachment management, this *has* to be done. By rule, starting new threads shouldn't
|
||||
// be done very often anyway, hence the concept of Threadpooling for rapidly rotating tasks.
|
||||
// (and indeed, this semaphore wait might, in fact, be very swift compared to other kernel
|
||||
// overhead in starting threads).
|
||||
// Event Rationale (above): Performing this semaphore wait on the created thread is "slow" in the
|
||||
// sense that it stalls the calling thread completely until the new thread is created
|
||||
// (which may not always be desirable). But too bad. In order to safely use 'running' locks
|
||||
// and detachment management, this *has* to be done. By rule, starting new threads shouldn't
|
||||
// be done very often anyway, hence the concept of Threadpooling for rapidly rotating tasks.
|
||||
// (and indeed, this semaphore wait might, in fact, be very swift compared to other kernel
|
||||
// overhead in starting threads).
|
||||
|
||||
// (this could also be done using operating system specific calls, since any threaded OS has
|
||||
// functions that allow us to see if a thread is running or not, and to block against it even if
|
||||
// it's been detached -- removing the need for m_mtx_InThread and the semaphore wait above. But
|
||||
// pthreads kinda lacks that stuff, since pthread_join() has no timeout option making it im-
|
||||
// possible to safely block against a running thread)
|
||||
// (this could also be done using operating system specific calls, since any threaded OS has
|
||||
// functions that allow us to see if a thread is running or not, and to block against it even if
|
||||
// it's been detached -- removing the need for m_mtx_InThread and the semaphore wait above. But
|
||||
// pthreads kinda lacks that stuff, since pthread_join() has no timeout option making it im-
|
||||
// possible to safely block against a running thread)
|
||||
}
|
||||
|
||||
// Returns: TRUE if the detachment was performed, or FALSE if the thread was
|
||||
|
@ -292,26 +302,27 @@ void Threading::pxThread::Start()
|
|||
// This function should not be called from the owner thread.
|
||||
bool Threading::pxThread::Detach()
|
||||
{
|
||||
AffinityAssert_DisallowFromSelf(pxDiagSpot);
|
||||
AffinityAssert_DisallowFromSelf(pxDiagSpot);
|
||||
|
||||
if (m_detached.exchange(true))
|
||||
return false;
|
||||
pthread_detach(m_thread);
|
||||
return true;
|
||||
if (m_detached.exchange(true))
|
||||
return false;
|
||||
pthread_detach(m_thread);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Threading::pxThread::_basecancel()
|
||||
{
|
||||
if (!m_running)
|
||||
return false;
|
||||
if (!m_running)
|
||||
return false;
|
||||
|
||||
if (m_detached) {
|
||||
pxThreadLog.Warn(GetName(), L"Ignoring attempted cancellation of detached thread.");
|
||||
return false;
|
||||
}
|
||||
if (m_detached)
|
||||
{
|
||||
pxThreadLog.Warn(GetName(), L"Ignoring attempted cancellation of detached thread.");
|
||||
return false;
|
||||
}
|
||||
|
||||
pthread_cancel(m_thread);
|
||||
return true;
|
||||
pthread_cancel(m_thread);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Remarks:
|
||||
|
@ -330,34 +341,35 @@ bool Threading::pxThread::_basecancel()
|
|||
//
|
||||
void Threading::pxThread::Cancel(bool isBlocking)
|
||||
{
|
||||
AffinityAssert_DisallowFromSelf(pxDiagSpot);
|
||||
AffinityAssert_DisallowFromSelf(pxDiagSpot);
|
||||
|
||||
// Prevent simultaneous startup and cancel, necessary to avoid
|
||||
ScopedLock startlock(m_mtx_start);
|
||||
// Prevent simultaneous startup and cancel, necessary to avoid
|
||||
ScopedLock startlock(m_mtx_start);
|
||||
|
||||
if (!_basecancel())
|
||||
return;
|
||||
if (!_basecancel())
|
||||
return;
|
||||
|
||||
if (isBlocking) {
|
||||
WaitOnSelf(m_mtx_InThread);
|
||||
Detach();
|
||||
}
|
||||
if (isBlocking)
|
||||
{
|
||||
WaitOnSelf(m_mtx_InThread);
|
||||
Detach();
|
||||
}
|
||||
}
|
||||
|
||||
bool Threading::pxThread::Cancel(const wxTimeSpan ×pan)
|
||||
bool Threading::pxThread::Cancel(const wxTimeSpan& timespan)
|
||||
{
|
||||
AffinityAssert_DisallowFromSelf(pxDiagSpot);
|
||||
AffinityAssert_DisallowFromSelf(pxDiagSpot);
|
||||
|
||||
// Prevent simultaneous startup and cancel:
|
||||
ScopedLock startlock(m_mtx_start);
|
||||
// Prevent simultaneous startup and cancel:
|
||||
ScopedLock startlock(m_mtx_start);
|
||||
|
||||
if (!_basecancel())
|
||||
return true;
|
||||
if (!_basecancel())
|
||||
return true;
|
||||
|
||||
if (!WaitOnSelf(m_mtx_InThread, timespan))
|
||||
return false;
|
||||
Detach();
|
||||
return true;
|
||||
if (!WaitOnSelf(m_mtx_InThread, timespan))
|
||||
return false;
|
||||
Detach();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -373,32 +385,32 @@ bool Threading::pxThread::Cancel(const wxTimeSpan ×pan)
|
|||
//
|
||||
void Threading::pxThread::Block()
|
||||
{
|
||||
AffinityAssert_DisallowFromSelf(pxDiagSpot);
|
||||
WaitOnSelf(m_mtx_InThread);
|
||||
AffinityAssert_DisallowFromSelf(pxDiagSpot);
|
||||
WaitOnSelf(m_mtx_InThread);
|
||||
}
|
||||
|
||||
bool Threading::pxThread::Block(const wxTimeSpan &timeout)
|
||||
bool Threading::pxThread::Block(const wxTimeSpan& timeout)
|
||||
{
|
||||
AffinityAssert_DisallowFromSelf(pxDiagSpot);
|
||||
return WaitOnSelf(m_mtx_InThread, timeout);
|
||||
AffinityAssert_DisallowFromSelf(pxDiagSpot);
|
||||
return WaitOnSelf(m_mtx_InThread, timeout);
|
||||
}
|
||||
|
||||
bool Threading::pxThread::IsSelf() const
|
||||
{
|
||||
// Detached threads may have their pthread handles recycled as newer threads, causing
|
||||
// false IsSelf reports.
|
||||
return !m_detached && (pthread_self() == m_thread);
|
||||
// Detached threads may have their pthread handles recycled as newer threads, causing
|
||||
// false IsSelf reports.
|
||||
return !m_detached && (pthread_self() == m_thread);
|
||||
}
|
||||
|
||||
bool Threading::pxThread::IsRunning() const
|
||||
{
|
||||
return m_running;
|
||||
return m_running;
|
||||
}
|
||||
|
||||
void Threading::pxThread::AddListener(EventListener_Thread &evt)
|
||||
void Threading::pxThread::AddListener(EventListener_Thread& evt)
|
||||
{
|
||||
evt.SetThread(this);
|
||||
m_evtsrc_OnDelete.Add(evt);
|
||||
evt.SetThread(this);
|
||||
m_evtsrc_OnDelete.Add(evt);
|
||||
}
|
||||
|
||||
// Throws an exception if the thread encountered one. Uses the BaseException's Rethrow() method,
|
||||
|
@ -406,49 +418,51 @@ void Threading::pxThread::AddListener(EventListener_Thread &evt)
|
|||
// the thread will have allowed itself to terminate properly.
|
||||
void Threading::pxThread::RethrowException() const
|
||||
{
|
||||
// Thread safety note: always detach the m_except pointer. If we checked it for NULL, the
|
||||
// pointer might still be invalid after detachment, so might as well just detach and check
|
||||
// after.
|
||||
// Thread safety note: always detach the m_except pointer. If we checked it for NULL, the
|
||||
// pointer might still be invalid after detachment, so might as well just detach and check
|
||||
// after.
|
||||
|
||||
ScopedExcept ptr(const_cast<pxThread *>(this)->m_except.DetachPtr());
|
||||
if (ptr)
|
||||
ptr->Rethrow();
|
||||
ScopedExcept ptr(const_cast<pxThread*>(this)->m_except.DetachPtr());
|
||||
if (ptr)
|
||||
ptr->Rethrow();
|
||||
}
|
||||
|
||||
static bool m_BlockDeletions = false;
|
||||
|
||||
bool Threading::AllowDeletions()
|
||||
{
|
||||
AffinityAssert_AllowFrom_MainUI();
|
||||
return !m_BlockDeletions;
|
||||
AffinityAssert_AllowFrom_MainUI();
|
||||
return !m_BlockDeletions;
|
||||
}
|
||||
|
||||
void Threading::YieldToMain()
|
||||
{
|
||||
m_BlockDeletions = true;
|
||||
wxTheApp->Yield(true);
|
||||
m_BlockDeletions = false;
|
||||
m_BlockDeletions = true;
|
||||
wxTheApp->Yield(true);
|
||||
m_BlockDeletions = false;
|
||||
}
|
||||
|
||||
void Threading::pxThread::_selfRunningTest(const wxChar *name) const
|
||||
void Threading::pxThread::_selfRunningTest(const wxChar* name) const
|
||||
{
|
||||
if (HasPendingException()) {
|
||||
pxThreadLog.Error(GetName(), pxsFmt(L"An exception was thrown while waiting on a %s.", name));
|
||||
RethrowException();
|
||||
}
|
||||
if (HasPendingException())
|
||||
{
|
||||
pxThreadLog.Error(GetName(), pxsFmt(L"An exception was thrown while waiting on a %s.", name));
|
||||
RethrowException();
|
||||
}
|
||||
|
||||
if (!m_running) {
|
||||
throw Exception::CancelEvent(pxsFmt(
|
||||
L"Blocking thread %s was terminated while another thread was waiting on a %s.",
|
||||
WX_STR(GetName()), name));
|
||||
}
|
||||
if (!m_running)
|
||||
{
|
||||
throw Exception::CancelEvent(pxsFmt(
|
||||
L"Blocking thread %s was terminated while another thread was waiting on a %s.",
|
||||
WX_STR(GetName()), name));
|
||||
}
|
||||
|
||||
// Thread is still alive and kicking (for now) -- yield to other messages and hope
|
||||
// that impending chaos does not ensue. [it shouldn't since we block pxThread
|
||||
// objects from being deleted until outside the scope of a mutex/semaphore wait).
|
||||
// Thread is still alive and kicking (for now) -- yield to other messages and hope
|
||||
// that impending chaos does not ensue. [it shouldn't since we block pxThread
|
||||
// objects from being deleted until outside the scope of a mutex/semaphore wait).
|
||||
|
||||
if ((wxTheApp != NULL) && wxThread::IsMain() && !_WaitGui_RecursionGuard(L"WaitForSelf"))
|
||||
Threading::YieldToMain();
|
||||
if ((wxTheApp != NULL) && wxThread::IsMain() && !_WaitGui_RecursionGuard(L"WaitForSelf"))
|
||||
Threading::YieldToMain();
|
||||
}
|
||||
|
||||
// This helper function is a deadlock-safe method of waiting on a semaphore in a pxThread. If the
|
||||
|
@ -462,16 +476,17 @@ void Threading::pxThread::_selfRunningTest(const wxChar *name) const
|
|||
// This function will rethrow exceptions raised by the persistent thread, if it throws an error
|
||||
// while the calling thread is blocking (which also means the persistent thread has terminated).
|
||||
//
|
||||
void Threading::pxThread::WaitOnSelf(Semaphore &sem) const
|
||||
void Threading::pxThread::WaitOnSelf(Semaphore& sem) const
|
||||
{
|
||||
if (!AffinityAssert_DisallowFromSelf(pxDiagSpot))
|
||||
return;
|
||||
if (!AffinityAssert_DisallowFromSelf(pxDiagSpot))
|
||||
return;
|
||||
|
||||
while (true) {
|
||||
if (sem.WaitWithoutYield(wxTimeSpan(0, 0, 0, 333)))
|
||||
return;
|
||||
_selfRunningTest(L"semaphore");
|
||||
}
|
||||
while (true)
|
||||
{
|
||||
if (sem.WaitWithoutYield(wxTimeSpan(0, 0, 0, 333)))
|
||||
return;
|
||||
_selfRunningTest(L"semaphore");
|
||||
}
|
||||
}
|
||||
|
||||
// This helper function is a deadlock-safe method of waiting on a mutex in a pxThread.
|
||||
|
@ -487,52 +502,55 @@ void Threading::pxThread::WaitOnSelf(Semaphore &sem) const
|
|||
// error while the calling thread is blocking (which also means the persistent thread has
|
||||
// terminated).
|
||||
//
|
||||
void Threading::pxThread::WaitOnSelf(Mutex &mutex) const
|
||||
void Threading::pxThread::WaitOnSelf(Mutex& mutex) const
|
||||
{
|
||||
if (!AffinityAssert_DisallowFromSelf(pxDiagSpot))
|
||||
return;
|
||||
if (!AffinityAssert_DisallowFromSelf(pxDiagSpot))
|
||||
return;
|
||||
|
||||
while (true) {
|
||||
if (mutex.WaitWithoutYield(wxTimeSpan(0, 0, 0, 333)))
|
||||
return;
|
||||
_selfRunningTest(L"mutex");
|
||||
}
|
||||
while (true)
|
||||
{
|
||||
if (mutex.WaitWithoutYield(wxTimeSpan(0, 0, 0, 333)))
|
||||
return;
|
||||
_selfRunningTest(L"mutex");
|
||||
}
|
||||
}
|
||||
|
||||
static const wxTimeSpan SelfWaitInterval(0, 0, 0, 333);
|
||||
|
||||
bool Threading::pxThread::WaitOnSelf(Semaphore &sem, const wxTimeSpan &timeout) const
|
||||
bool Threading::pxThread::WaitOnSelf(Semaphore& sem, const wxTimeSpan& timeout) const
|
||||
{
|
||||
if (!AffinityAssert_DisallowFromSelf(pxDiagSpot))
|
||||
return true;
|
||||
if (!AffinityAssert_DisallowFromSelf(pxDiagSpot))
|
||||
return true;
|
||||
|
||||
wxTimeSpan runningout(timeout);
|
||||
wxTimeSpan runningout(timeout);
|
||||
|
||||
while (runningout.GetMilliseconds() > 0) {
|
||||
const wxTimeSpan interval((SelfWaitInterval < runningout) ? SelfWaitInterval : runningout);
|
||||
if (sem.WaitWithoutYield(interval))
|
||||
return true;
|
||||
_selfRunningTest(L"semaphore");
|
||||
runningout -= interval;
|
||||
}
|
||||
return false;
|
||||
while (runningout.GetMilliseconds() > 0)
|
||||
{
|
||||
const wxTimeSpan interval((SelfWaitInterval < runningout) ? SelfWaitInterval : runningout);
|
||||
if (sem.WaitWithoutYield(interval))
|
||||
return true;
|
||||
_selfRunningTest(L"semaphore");
|
||||
runningout -= interval;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Threading::pxThread::WaitOnSelf(Mutex &mutex, const wxTimeSpan &timeout) const
|
||||
bool Threading::pxThread::WaitOnSelf(Mutex& mutex, const wxTimeSpan& timeout) const
|
||||
{
|
||||
if (!AffinityAssert_DisallowFromSelf(pxDiagSpot))
|
||||
return true;
|
||||
if (!AffinityAssert_DisallowFromSelf(pxDiagSpot))
|
||||
return true;
|
||||
|
||||
wxTimeSpan runningout(timeout);
|
||||
wxTimeSpan runningout(timeout);
|
||||
|
||||
while (runningout.GetMilliseconds() > 0) {
|
||||
const wxTimeSpan interval((SelfWaitInterval < runningout) ? SelfWaitInterval : runningout);
|
||||
if (mutex.WaitWithoutYield(interval))
|
||||
return true;
|
||||
_selfRunningTest(L"mutex");
|
||||
runningout -= interval;
|
||||
}
|
||||
return false;
|
||||
while (runningout.GetMilliseconds() > 0)
|
||||
{
|
||||
const wxTimeSpan interval((SelfWaitInterval < runningout) ? SelfWaitInterval : runningout);
|
||||
if (mutex.WaitWithoutYield(interval))
|
||||
return true;
|
||||
_selfRunningTest(L"mutex");
|
||||
runningout -= interval;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Inserts a thread cancellation point. If the thread has received a cancel request, this
|
||||
|
@ -541,36 +559,39 @@ bool Threading::pxThread::WaitOnSelf(Mutex &mutex, const wxTimeSpan &timeout) co
|
|||
// and cleanup, or use the DoThreadCleanup() override to perform resource cleanup).
|
||||
void Threading::pxThread::TestCancel() const
|
||||
{
|
||||
AffinityAssert_AllowFromSelf(pxDiagSpot);
|
||||
pthread_testcancel();
|
||||
AffinityAssert_AllowFromSelf(pxDiagSpot);
|
||||
pthread_testcancel();
|
||||
}
|
||||
|
||||
// Executes the virtual member method
|
||||
void Threading::pxThread::_try_virtual_invoke(void (pxThread::*method)())
|
||||
{
|
||||
try {
|
||||
(this->*method)();
|
||||
}
|
||||
try
|
||||
{
|
||||
(this->*method)();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Neat repackaging for STL Runtime errors...
|
||||
//
|
||||
catch (std::runtime_error &ex) {
|
||||
m_except = new Exception::RuntimeError(ex, WX_STR(GetName()));
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
// Neat repackaging for STL Runtime errors...
|
||||
//
|
||||
catch (std::runtime_error& ex)
|
||||
{
|
||||
m_except = new Exception::RuntimeError(ex, WX_STR(GetName()));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
catch (Exception::RuntimeError &ex) {
|
||||
BaseException *woot = ex.Clone();
|
||||
woot->DiagMsg() += pxsFmt(L"(thread:%s)", WX_STR(GetName()));
|
||||
m_except = woot;
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
catch (Exception::RuntimeError& ex)
|
||||
{
|
||||
BaseException* woot = ex.Clone();
|
||||
woot->DiagMsg() += pxsFmt(L"(thread:%s)", WX_STR(GetName()));
|
||||
m_except = woot;
|
||||
}
|
||||
#ifndef PCSX2_DEVBUILD
|
||||
// ----------------------------------------------------------------------------
|
||||
// Bleh... don't bother with std::exception. runtime_error should catch anything
|
||||
// useful coming out of the core STL libraries anyway, and these are best handled by
|
||||
// the MSVC debugger (or by silent random annoying fail on debug-less linux).
|
||||
/*catch( std::logic_error& ex )
|
||||
// ----------------------------------------------------------------------------
|
||||
// Bleh... don't bother with std::exception. runtime_error should catch anything
|
||||
// useful coming out of the core STL libraries anyway, and these are best handled by
|
||||
// the MSVC debugger (or by silent random annoying fail on debug-less linux).
|
||||
/*catch( std::logic_error& ex )
|
||||
{
|
||||
throw BaseException( pxsFmt( L"STL Logic Error (thread:%s): %s",
|
||||
WX_STR(GetName()), WX_STR(fromUTF8( ex.what() )) )
|
||||
|
@ -582,14 +603,15 @@ void Threading::pxThread::_try_virtual_invoke(void (pxThread::*method)())
|
|||
WX_STR(GetName()), WX_STR(fromUTF8( ex.what() )) )
|
||||
);
|
||||
}*/
|
||||
// ----------------------------------------------------------------------------
|
||||
// BaseException -- same deal as LogicErrors.
|
||||
//
|
||||
catch (BaseException &ex) {
|
||||
BaseException *woot = ex.Clone();
|
||||
woot->DiagMsg() += pxsFmt(L"(thread:%s)", WX_STR(GetName()));
|
||||
m_except = woot;
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
// BaseException -- same deal as LogicErrors.
|
||||
//
|
||||
catch (BaseException& ex)
|
||||
{
|
||||
BaseException* woot = ex.Clone();
|
||||
woot->DiagMsg() += pxsFmt(L"(thread:%s)", WX_STR(GetName()));
|
||||
m_except = woot;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -597,25 +619,25 @@ void Threading::pxThread::_try_virtual_invoke(void (pxThread::*method)())
|
|||
// OnCleanupInThread() to extend cleanup functionality.
|
||||
void Threading::pxThread::_ThreadCleanup()
|
||||
{
|
||||
AffinityAssert_AllowFromSelf(pxDiagSpot);
|
||||
_try_virtual_invoke(&pxThread::OnCleanupInThread);
|
||||
m_mtx_InThread.Release();
|
||||
AffinityAssert_AllowFromSelf(pxDiagSpot);
|
||||
_try_virtual_invoke(&pxThread::OnCleanupInThread);
|
||||
m_mtx_InThread.Release();
|
||||
|
||||
// Must set m_running LAST, as thread destructors depend on this value (it is used
|
||||
// to avoid destruction of the thread until all internal data use has stopped.
|
||||
m_running = false;
|
||||
// Must set m_running LAST, as thread destructors depend on this value (it is used
|
||||
// to avoid destruction of the thread until all internal data use has stopped.
|
||||
m_running = false;
|
||||
}
|
||||
|
||||
wxString Threading::pxThread::GetName() const
|
||||
{
|
||||
ScopedLock lock(m_mtx_ThreadName);
|
||||
return m_name;
|
||||
ScopedLock lock(m_mtx_ThreadName);
|
||||
return m_name;
|
||||
}
|
||||
|
||||
void Threading::pxThread::SetName(const wxString &newname)
|
||||
void Threading::pxThread::SetName(const wxString& newname)
|
||||
{
|
||||
ScopedLock lock(m_mtx_ThreadName);
|
||||
m_name = newname;
|
||||
ScopedLock lock(m_mtx_ThreadName);
|
||||
m_name = newname;
|
||||
}
|
||||
|
||||
// This override is called by PeristentThread when the thread is first created, prior to
|
||||
|
@ -627,82 +649,82 @@ void Threading::pxThread::SetName(const wxString &newname)
|
|||
//
|
||||
void Threading::pxThread::OnStartInThread()
|
||||
{
|
||||
m_detached = false;
|
||||
m_running = true;
|
||||
m_detached = false;
|
||||
m_running = true;
|
||||
|
||||
_platform_specific_OnStartInThread();
|
||||
_platform_specific_OnStartInThread();
|
||||
}
|
||||
|
||||
void Threading::pxThread::_internal_execute()
|
||||
{
|
||||
m_mtx_InThread.Acquire();
|
||||
m_mtx_InThread.Acquire();
|
||||
|
||||
_DoSetThreadName(GetName());
|
||||
make_curthread_key(this);
|
||||
if (curthread_key)
|
||||
pthread_setspecific(curthread_key, this);
|
||||
_DoSetThreadName(GetName());
|
||||
make_curthread_key(this);
|
||||
if (curthread_key)
|
||||
pthread_setspecific(curthread_key, this);
|
||||
|
||||
OnStartInThread();
|
||||
m_sem_startup.Post();
|
||||
OnStartInThread();
|
||||
m_sem_startup.Post();
|
||||
|
||||
_try_virtual_invoke(&pxThread::ExecuteTaskInThread);
|
||||
_try_virtual_invoke(&pxThread::ExecuteTaskInThread);
|
||||
}
|
||||
|
||||
// Called by Start, prior to actual starting of the thread, and after any previous
|
||||
// running thread has been canceled or detached.
|
||||
void Threading::pxThread::OnStart()
|
||||
{
|
||||
m_native_handle = 0;
|
||||
m_native_id = 0;
|
||||
m_native_handle = 0;
|
||||
m_native_id = 0;
|
||||
|
||||
FrankenMutex(m_mtx_InThread);
|
||||
m_sem_event.Reset();
|
||||
m_sem_startup.Reset();
|
||||
FrankenMutex(m_mtx_InThread);
|
||||
m_sem_event.Reset();
|
||||
m_sem_startup.Reset();
|
||||
}
|
||||
|
||||
// Extending classes that override this method should always call it last from their
|
||||
// personal implementations.
|
||||
void Threading::pxThread::OnCleanupInThread()
|
||||
{
|
||||
if (curthread_key)
|
||||
pthread_setspecific(curthread_key, NULL);
|
||||
if (curthread_key)
|
||||
pthread_setspecific(curthread_key, NULL);
|
||||
|
||||
unmake_curthread_key();
|
||||
unmake_curthread_key();
|
||||
|
||||
_platform_specific_OnCleanupInThread();
|
||||
_platform_specific_OnCleanupInThread();
|
||||
|
||||
m_native_handle = 0;
|
||||
m_native_id = 0;
|
||||
m_native_handle = 0;
|
||||
m_native_id = 0;
|
||||
|
||||
m_evtsrc_OnDelete.Dispatch(0);
|
||||
m_evtsrc_OnDelete.Dispatch(0);
|
||||
}
|
||||
|
||||
// passed into pthread_create, and is used to dispatch the thread's object oriented
|
||||
// callback function
|
||||
void *Threading::pxThread::_internal_callback(void *itsme)
|
||||
void* Threading::pxThread::_internal_callback(void* itsme)
|
||||
{
|
||||
if (!pxAssertDev(itsme != NULL, wxNullChar))
|
||||
return NULL;
|
||||
if (!pxAssertDev(itsme != NULL, wxNullChar))
|
||||
return NULL;
|
||||
|
||||
internal_callback_helper(itsme);
|
||||
return nullptr;
|
||||
internal_callback_helper(itsme);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// __try is used in pthread_cleanup_push when CLEANUP_SEH is used as the cleanup model.
|
||||
// That can't be used in a function that has objects that require unwinding (compile
|
||||
// error C2712), so move it into a separate function.
|
||||
void Threading::pxThread::internal_callback_helper(void *itsme)
|
||||
void Threading::pxThread::internal_callback_helper(void* itsme)
|
||||
{
|
||||
pxThread &owner = *static_cast<pxThread *>(itsme);
|
||||
pxThread& owner = *static_cast<pxThread*>(itsme);
|
||||
|
||||
pthread_cleanup_push(_pt_callback_cleanup, itsme);
|
||||
owner._internal_execute();
|
||||
pthread_cleanup_pop(true);
|
||||
pthread_cleanup_push(_pt_callback_cleanup, itsme);
|
||||
owner._internal_execute();
|
||||
pthread_cleanup_pop(true);
|
||||
}
|
||||
|
||||
void Threading::pxThread::_DoSetThreadName(const wxString &name)
|
||||
void Threading::pxThread::_DoSetThreadName(const wxString& name)
|
||||
{
|
||||
_DoSetThreadName(static_cast<const char *>(name.ToUTF8()));
|
||||
_DoSetThreadName(static_cast<const char*>(name.ToUTF8()));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -746,23 +768,23 @@ void Threading::WaitEvent::Wait()
|
|||
|
||||
wxString Exception::BaseThreadError::FormatDiagnosticMessage() const
|
||||
{
|
||||
wxString null_str(L"Null Thread Object");
|
||||
return pxsFmt(m_message_diag, (m_thread == NULL) ? WX_STR(null_str) : WX_STR(m_thread->GetName()));
|
||||
wxString null_str(L"Null Thread Object");
|
||||
return pxsFmt(m_message_diag, (m_thread == NULL) ? WX_STR(null_str) : WX_STR(m_thread->GetName()));
|
||||
}
|
||||
|
||||
wxString Exception::BaseThreadError::FormatDisplayMessage() const
|
||||
{
|
||||
wxString null_str(L"Null Thread Object");
|
||||
return pxsFmt(m_message_user, (m_thread == NULL) ? WX_STR(null_str) : WX_STR(m_thread->GetName()));
|
||||
wxString null_str(L"Null Thread Object");
|
||||
return pxsFmt(m_message_user, (m_thread == NULL) ? WX_STR(null_str) : WX_STR(m_thread->GetName()));
|
||||
}
|
||||
|
||||
pxThread &Exception::BaseThreadError::Thread()
|
||||
pxThread& Exception::BaseThreadError::Thread()
|
||||
{
|
||||
pxAssertDev(m_thread != NULL, "NULL thread object on ThreadError exception.");
|
||||
return *m_thread;
|
||||
pxAssertDev(m_thread != NULL, "NULL thread object on ThreadError exception.");
|
||||
return *m_thread;
|
||||
}
|
||||
const pxThread &Exception::BaseThreadError::Thread() const
|
||||
const pxThread& Exception::BaseThreadError::Thread() const
|
||||
{
|
||||
pxAssertDev(m_thread != NULL, "NULL thread object on ThreadError exception.");
|
||||
return *m_thread;
|
||||
pxAssertDev(m_thread != NULL, "NULL thread object on ThreadError exception.");
|
||||
return *m_thread;
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
#undef Yield // release the burden of windows.h global namespace spam.
|
||||
|
||||
#define AffinityAssert_AllowFrom_MainUI() \
|
||||
pxAssertMsg(wxThread::IsMain(), "Thread affinity violation: Call allowed from main thread only.")
|
||||
pxAssertMsg(wxThread::IsMain(), "Thread affinity violation: Call allowed from main thread only.")
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// pxThreadLog / ConsoleLogSource_Threading
|
||||
|
@ -40,25 +40,25 @@
|
|||
|
||||
class ConsoleLogSource_Threading : ConsoleLogSource
|
||||
{
|
||||
typedef ConsoleLogSource _parent;
|
||||
typedef ConsoleLogSource _parent;
|
||||
|
||||
public:
|
||||
using _parent::IsActive;
|
||||
using _parent::IsActive;
|
||||
|
||||
ConsoleLogSource_Threading();
|
||||
ConsoleLogSource_Threading();
|
||||
|
||||
bool Write(const wxString &thrname, const wxChar *msg)
|
||||
{
|
||||
return _parent::Write(wxsFormat(L"(thread:%s) ", WX_STR(thrname)) + msg);
|
||||
}
|
||||
bool Warn(const wxString &thrname, const wxChar *msg)
|
||||
{
|
||||
return _parent::Warn(wxsFormat(L"(thread:%s) ", WX_STR(thrname)) + msg);
|
||||
}
|
||||
bool Error(const wxString &thrname, const wxChar *msg)
|
||||
{
|
||||
return _parent::Error(wxsFormat(L"(thread:%s) ", WX_STR(thrname)) + msg);
|
||||
}
|
||||
bool Write(const wxString& thrname, const wxChar* msg)
|
||||
{
|
||||
return _parent::Write(wxsFormat(L"(thread:%s) ", WX_STR(thrname)) + msg);
|
||||
}
|
||||
bool Warn(const wxString& thrname, const wxChar* msg)
|
||||
{
|
||||
return _parent::Warn(wxsFormat(L"(thread:%s) ", WX_STR(thrname)) + msg);
|
||||
}
|
||||
bool Error(const wxString& thrname, const wxChar* msg)
|
||||
{
|
||||
return _parent::Error(wxsFormat(L"(thread:%s) ", WX_STR(thrname)) + msg);
|
||||
}
|
||||
};
|
||||
|
||||
extern ConsoleLogSource_Threading pxConLog_Thread;
|
||||
|
@ -88,97 +88,97 @@ class wxTimeSpan;
|
|||
|
||||
namespace Threading
|
||||
{
|
||||
class pxThread;
|
||||
class RwMutex;
|
||||
class pxThread;
|
||||
class RwMutex;
|
||||
|
||||
extern void pxTestCancel();
|
||||
extern pxThread *pxGetCurrentThread();
|
||||
extern wxString pxGetCurrentThreadName();
|
||||
extern u64 GetThreadCpuTime();
|
||||
extern u64 GetThreadTicksPerSecond();
|
||||
extern void pxTestCancel();
|
||||
extern pxThread* pxGetCurrentThread();
|
||||
extern wxString pxGetCurrentThreadName();
|
||||
extern u64 GetThreadCpuTime();
|
||||
extern u64 GetThreadTicksPerSecond();
|
||||
|
||||
// Yields the current thread and provides cancellation points if the thread is managed by
|
||||
// pxThread. Unmanaged threads use standard Sleep.
|
||||
extern void pxYield(int ms);
|
||||
}
|
||||
// Yields the current thread and provides cancellation points if the thread is managed by
|
||||
// pxThread. Unmanaged threads use standard Sleep.
|
||||
extern void pxYield(int ms);
|
||||
} // namespace Threading
|
||||
|
||||
namespace Exception
|
||||
{
|
||||
class BaseThreadError : public RuntimeError
|
||||
{
|
||||
DEFINE_EXCEPTION_COPYTORS(BaseThreadError, RuntimeError)
|
||||
DEFINE_EXCEPTION_MESSAGES(BaseThreadError)
|
||||
class BaseThreadError : public RuntimeError
|
||||
{
|
||||
DEFINE_EXCEPTION_COPYTORS(BaseThreadError, RuntimeError)
|
||||
DEFINE_EXCEPTION_MESSAGES(BaseThreadError)
|
||||
|
||||
public:
|
||||
Threading::pxThread *m_thread;
|
||||
public:
|
||||
Threading::pxThread* m_thread;
|
||||
|
||||
protected:
|
||||
BaseThreadError()
|
||||
{
|
||||
m_thread = NULL;
|
||||
}
|
||||
protected:
|
||||
BaseThreadError()
|
||||
{
|
||||
m_thread = NULL;
|
||||
}
|
||||
|
||||
public:
|
||||
explicit BaseThreadError(Threading::pxThread *_thread)
|
||||
{
|
||||
m_thread = _thread;
|
||||
m_message_diag = L"An unspecified thread-related error occurred (thread=%s)";
|
||||
}
|
||||
public:
|
||||
explicit BaseThreadError(Threading::pxThread* _thread)
|
||||
{
|
||||
m_thread = _thread;
|
||||
m_message_diag = L"An unspecified thread-related error occurred (thread=%s)";
|
||||
}
|
||||
|
||||
explicit BaseThreadError(Threading::pxThread &_thread)
|
||||
{
|
||||
m_thread = &_thread;
|
||||
m_message_diag = L"An unspecified thread-related error occurred (thread=%s)";
|
||||
}
|
||||
explicit BaseThreadError(Threading::pxThread& _thread)
|
||||
{
|
||||
m_thread = &_thread;
|
||||
m_message_diag = L"An unspecified thread-related error occurred (thread=%s)";
|
||||
}
|
||||
|
||||
virtual wxString FormatDiagnosticMessage() const;
|
||||
virtual wxString FormatDisplayMessage() const;
|
||||
virtual wxString FormatDiagnosticMessage() const;
|
||||
virtual wxString FormatDisplayMessage() const;
|
||||
|
||||
Threading::pxThread &Thread();
|
||||
const Threading::pxThread &Thread() const;
|
||||
};
|
||||
Threading::pxThread& Thread();
|
||||
const Threading::pxThread& Thread() const;
|
||||
};
|
||||
|
||||
class ThreadCreationError : public BaseThreadError
|
||||
{
|
||||
DEFINE_EXCEPTION_COPYTORS(ThreadCreationError, BaseThreadError)
|
||||
class ThreadCreationError : public BaseThreadError
|
||||
{
|
||||
DEFINE_EXCEPTION_COPYTORS(ThreadCreationError, BaseThreadError)
|
||||
|
||||
public:
|
||||
explicit ThreadCreationError(Threading::pxThread *_thread)
|
||||
{
|
||||
m_thread = _thread;
|
||||
SetBothMsgs(L"Thread creation failure. An unspecified error occurred while trying to create the %s thread.");
|
||||
}
|
||||
public:
|
||||
explicit ThreadCreationError(Threading::pxThread* _thread)
|
||||
{
|
||||
m_thread = _thread;
|
||||
SetBothMsgs(L"Thread creation failure. An unspecified error occurred while trying to create the %s thread.");
|
||||
}
|
||||
|
||||
explicit ThreadCreationError(Threading::pxThread &_thread)
|
||||
{
|
||||
m_thread = &_thread;
|
||||
SetBothMsgs(L"Thread creation failure. An unspecified error occurred while trying to create the %s thread.");
|
||||
}
|
||||
};
|
||||
}
|
||||
explicit ThreadCreationError(Threading::pxThread& _thread)
|
||||
{
|
||||
m_thread = &_thread;
|
||||
SetBothMsgs(L"Thread creation failure. An unspecified error occurred while trying to create the %s thread.");
|
||||
}
|
||||
};
|
||||
} // namespace Exception
|
||||
|
||||
|
||||
namespace Threading
|
||||
{
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Platform Specific External APIs
|
||||
// --------------------------------------------------------------------------------------
|
||||
// The following set of documented functions have Linux/Win32 specific implementations,
|
||||
// which are found in WinThreads.cpp and LnxThreads.cpp
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Platform Specific External APIs
|
||||
// --------------------------------------------------------------------------------------
|
||||
// The following set of documented functions have Linux/Win32 specific implementations,
|
||||
// which are found in WinThreads.cpp and LnxThreads.cpp
|
||||
|
||||
// Releases a timeslice to other threads.
|
||||
extern void Timeslice();
|
||||
// Releases a timeslice to other threads.
|
||||
extern void Timeslice();
|
||||
|
||||
// For use in spin/wait loops.
|
||||
extern void SpinWait();
|
||||
// For use in spin/wait loops.
|
||||
extern void SpinWait();
|
||||
|
||||
// Optional implementation to enable hires thread/process scheduler for the operating system.
|
||||
// Needed by Windows, but might not be relevant to other platforms.
|
||||
extern void EnableHiresScheduler();
|
||||
extern void DisableHiresScheduler();
|
||||
// Optional implementation to enable hires thread/process scheduler for the operating system.
|
||||
// Needed by Windows, but might not be relevant to other platforms.
|
||||
extern void EnableHiresScheduler();
|
||||
extern void DisableHiresScheduler();
|
||||
|
||||
// sleeps the current thread for the given number of milliseconds.
|
||||
extern void Sleep(int ms);
|
||||
// sleeps the current thread for the given number of milliseconds.
|
||||
extern void Sleep(int ms);
|
||||
|
||||
// pthread Cond is an evil api that is not suited for Pcsx2 needs.
|
||||
// Let's not use it. Use mutexes and semaphores instead to create waits. (Air)
|
||||
|
@ -196,230 +196,230 @@ extern void Sleep(int ms);
|
|||
};
|
||||
#endif
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// NonblockingMutex
|
||||
// --------------------------------------------------------------------------------------
|
||||
// This is a very simple non-blocking mutex, which behaves similarly to pthread_mutex's
|
||||
// trylock(), but without any of the extra overhead needed to set up a structure capable
|
||||
// of blocking waits. It basically optimizes to a single InterlockedExchange.
|
||||
//
|
||||
// Simple use: if TryAcquire() returns false, the Bool is already interlocked by another thread.
|
||||
// If TryAcquire() returns true, you've locked the object and are *responsible* for unlocking
|
||||
// it later.
|
||||
//
|
||||
class NonblockingMutex
|
||||
{
|
||||
protected:
|
||||
std::atomic_flag val;
|
||||
// --------------------------------------------------------------------------------------
|
||||
// NonblockingMutex
|
||||
// --------------------------------------------------------------------------------------
|
||||
// This is a very simple non-blocking mutex, which behaves similarly to pthread_mutex's
|
||||
// trylock(), but without any of the extra overhead needed to set up a structure capable
|
||||
// of blocking waits. It basically optimizes to a single InterlockedExchange.
|
||||
//
|
||||
// Simple use: if TryAcquire() returns false, the Bool is already interlocked by another thread.
|
||||
// If TryAcquire() returns true, you've locked the object and are *responsible* for unlocking
|
||||
// it later.
|
||||
//
|
||||
class NonblockingMutex
|
||||
{
|
||||
protected:
|
||||
std::atomic_flag val;
|
||||
|
||||
public:
|
||||
NonblockingMutex() { val.clear(); }
|
||||
virtual ~NonblockingMutex() = default;
|
||||
public:
|
||||
NonblockingMutex() { val.clear(); }
|
||||
virtual ~NonblockingMutex() = default;
|
||||
|
||||
bool TryAcquire() noexcept
|
||||
{
|
||||
return !val.test_and_set();
|
||||
}
|
||||
bool TryAcquire() noexcept
|
||||
{
|
||||
return !val.test_and_set();
|
||||
}
|
||||
|
||||
// Can be done with a TryAcquire/Release but it is likely better to do it outside of the object
|
||||
bool IsLocked()
|
||||
{
|
||||
pxAssertMsg(0, "IsLocked isn't supported for NonblockingMutex");
|
||||
return false;
|
||||
}
|
||||
// Can be done with a TryAcquire/Release but it is likely better to do it outside of the object
|
||||
bool IsLocked()
|
||||
{
|
||||
pxAssertMsg(0, "IsLocked isn't supported for NonblockingMutex");
|
||||
return false;
|
||||
}
|
||||
|
||||
void Release()
|
||||
{
|
||||
val.clear();
|
||||
}
|
||||
};
|
||||
void Release()
|
||||
{
|
||||
val.clear();
|
||||
}
|
||||
};
|
||||
|
||||
class Semaphore
|
||||
{
|
||||
protected:
|
||||
class Semaphore
|
||||
{
|
||||
protected:
|
||||
#ifdef __APPLE__
|
||||
semaphore_t m_sema;
|
||||
int m_counter;
|
||||
semaphore_t m_sema;
|
||||
int m_counter;
|
||||
#else
|
||||
sem_t m_sema;
|
||||
sem_t m_sema;
|
||||
#endif
|
||||
|
||||
public:
|
||||
Semaphore();
|
||||
virtual ~Semaphore();
|
||||
public:
|
||||
Semaphore();
|
||||
virtual ~Semaphore();
|
||||
|
||||
void Reset();
|
||||
void Post();
|
||||
void Post(int multiple);
|
||||
void Reset();
|
||||
void Post();
|
||||
void Post(int multiple);
|
||||
|
||||
void WaitWithoutYield();
|
||||
bool WaitWithoutYield(const wxTimeSpan &timeout);
|
||||
void WaitNoCancel();
|
||||
void WaitNoCancel(const wxTimeSpan &timeout);
|
||||
int Count();
|
||||
void WaitWithoutYield();
|
||||
bool WaitWithoutYield(const wxTimeSpan& timeout);
|
||||
void WaitNoCancel();
|
||||
void WaitNoCancel(const wxTimeSpan& timeout);
|
||||
int Count();
|
||||
|
||||
void Wait();
|
||||
bool Wait(const wxTimeSpan &timeout);
|
||||
};
|
||||
void Wait();
|
||||
bool Wait(const wxTimeSpan& timeout);
|
||||
};
|
||||
|
||||
class Mutex
|
||||
{
|
||||
protected:
|
||||
pthread_mutex_t m_mutex;
|
||||
class Mutex
|
||||
{
|
||||
protected:
|
||||
pthread_mutex_t m_mutex;
|
||||
|
||||
public:
|
||||
Mutex();
|
||||
virtual ~Mutex();
|
||||
virtual bool IsRecursive() const { return false; }
|
||||
public:
|
||||
Mutex();
|
||||
virtual ~Mutex();
|
||||
virtual bool IsRecursive() const { return false; }
|
||||
|
||||
void Recreate();
|
||||
bool RecreateIfLocked();
|
||||
void Detach();
|
||||
void Recreate();
|
||||
bool RecreateIfLocked();
|
||||
void Detach();
|
||||
|
||||
void Acquire();
|
||||
bool Acquire(const wxTimeSpan &timeout);
|
||||
bool TryAcquire();
|
||||
void Release();
|
||||
void Acquire();
|
||||
bool Acquire(const wxTimeSpan& timeout);
|
||||
bool TryAcquire();
|
||||
void Release();
|
||||
|
||||
void AcquireWithoutYield();
|
||||
bool AcquireWithoutYield(const wxTimeSpan &timeout);
|
||||
void AcquireWithoutYield();
|
||||
bool AcquireWithoutYield(const wxTimeSpan& timeout);
|
||||
|
||||
void Wait();
|
||||
bool Wait(const wxTimeSpan &timeout);
|
||||
void WaitWithoutYield();
|
||||
bool WaitWithoutYield(const wxTimeSpan &timeout);
|
||||
void Wait();
|
||||
bool Wait(const wxTimeSpan& timeout);
|
||||
void WaitWithoutYield();
|
||||
bool WaitWithoutYield(const wxTimeSpan& timeout);
|
||||
|
||||
protected:
|
||||
// empty constructor used by MutexLockRecursive
|
||||
Mutex(bool) {}
|
||||
};
|
||||
protected:
|
||||
// empty constructor used by MutexLockRecursive
|
||||
Mutex(bool) {}
|
||||
};
|
||||
|
||||
class MutexRecursive : public Mutex
|
||||
{
|
||||
public:
|
||||
MutexRecursive();
|
||||
virtual ~MutexRecursive();
|
||||
virtual bool IsRecursive() const { return true; }
|
||||
};
|
||||
class MutexRecursive : public Mutex
|
||||
{
|
||||
public:
|
||||
MutexRecursive();
|
||||
virtual ~MutexRecursive();
|
||||
virtual bool IsRecursive() const { return true; }
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// ScopedLock
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Helper class for using Mutexes. Using this class provides an exception-safe (and
|
||||
// generally clean) method of locking code inside a function or conditional block. The lock
|
||||
// will be automatically released on any return or exit from the function.
|
||||
//
|
||||
// Const qualification note:
|
||||
// ScopedLock takes const instances of the mutex, even though the mutex is modified
|
||||
// by locking and unlocking. Two rationales:
|
||||
//
|
||||
// 1) when designing classes with accessors (GetString, GetValue, etc) that need mutexes,
|
||||
// this class needs a const hack to allow those accessors to be const (which is typically
|
||||
// *very* important).
|
||||
//
|
||||
// 2) The state of the Mutex is guaranteed to be unchanged when the calling function or
|
||||
// scope exits, by any means. Only via manual calls to Release or Acquire does that
|
||||
// change, and typically those are only used in very special circumstances of their own.
|
||||
//
|
||||
class ScopedLock
|
||||
{
|
||||
DeclareNoncopyableObject(ScopedLock);
|
||||
// --------------------------------------------------------------------------------------
|
||||
// ScopedLock
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Helper class for using Mutexes. Using this class provides an exception-safe (and
|
||||
// generally clean) method of locking code inside a function or conditional block. The lock
|
||||
// will be automatically released on any return or exit from the function.
|
||||
//
|
||||
// Const qualification note:
|
||||
// ScopedLock takes const instances of the mutex, even though the mutex is modified
|
||||
// by locking and unlocking. Two rationales:
|
||||
//
|
||||
// 1) when designing classes with accessors (GetString, GetValue, etc) that need mutexes,
|
||||
// this class needs a const hack to allow those accessors to be const (which is typically
|
||||
// *very* important).
|
||||
//
|
||||
// 2) The state of the Mutex is guaranteed to be unchanged when the calling function or
|
||||
// scope exits, by any means. Only via manual calls to Release or Acquire does that
|
||||
// change, and typically those are only used in very special circumstances of their own.
|
||||
//
|
||||
class ScopedLock
|
||||
{
|
||||
DeclareNoncopyableObject(ScopedLock);
|
||||
|
||||
protected:
|
||||
Mutex *m_lock;
|
||||
bool m_IsLocked;
|
||||
protected:
|
||||
Mutex* m_lock;
|
||||
bool m_IsLocked;
|
||||
|
||||
public:
|
||||
virtual ~ScopedLock();
|
||||
explicit ScopedLock(const Mutex *locker = NULL);
|
||||
explicit ScopedLock(const Mutex &locker);
|
||||
void AssignAndLock(const Mutex &locker);
|
||||
void AssignAndLock(const Mutex *locker);
|
||||
public:
|
||||
virtual ~ScopedLock();
|
||||
explicit ScopedLock(const Mutex* locker = NULL);
|
||||
explicit ScopedLock(const Mutex& locker);
|
||||
void AssignAndLock(const Mutex& locker);
|
||||
void AssignAndLock(const Mutex* locker);
|
||||
|
||||
void Assign(const Mutex &locker);
|
||||
void Assign(const Mutex *locker);
|
||||
void Assign(const Mutex& locker);
|
||||
void Assign(const Mutex* locker);
|
||||
|
||||
void Release();
|
||||
void Acquire();
|
||||
void Release();
|
||||
void Acquire();
|
||||
|
||||
bool IsLocked() const { return m_IsLocked; }
|
||||
bool IsLocked() const { return m_IsLocked; }
|
||||
|
||||
protected:
|
||||
// Special constructor used by ScopedTryLock
|
||||
ScopedLock(const Mutex &locker, bool isTryLock);
|
||||
};
|
||||
protected:
|
||||
// Special constructor used by ScopedTryLock
|
||||
ScopedLock(const Mutex& locker, bool isTryLock);
|
||||
};
|
||||
|
||||
class ScopedTryLock : public ScopedLock
|
||||
{
|
||||
public:
|
||||
ScopedTryLock(const Mutex &locker)
|
||||
: ScopedLock(locker, true)
|
||||
{
|
||||
}
|
||||
virtual ~ScopedTryLock() = default;
|
||||
bool Failed() const { return !m_IsLocked; }
|
||||
};
|
||||
class ScopedTryLock : public ScopedLock
|
||||
{
|
||||
public:
|
||||
ScopedTryLock(const Mutex& locker)
|
||||
: ScopedLock(locker, true)
|
||||
{
|
||||
}
|
||||
virtual ~ScopedTryLock() = default;
|
||||
bool Failed() const { return !m_IsLocked; }
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// ScopedNonblockingLock
|
||||
// --------------------------------------------------------------------------------------
|
||||
// A ScopedTryLock branded for use with Nonblocking mutexes. See ScopedTryLock for details.
|
||||
//
|
||||
class ScopedNonblockingLock
|
||||
{
|
||||
DeclareNoncopyableObject(ScopedNonblockingLock);
|
||||
// --------------------------------------------------------------------------------------
|
||||
// ScopedNonblockingLock
|
||||
// --------------------------------------------------------------------------------------
|
||||
// A ScopedTryLock branded for use with Nonblocking mutexes. See ScopedTryLock for details.
|
||||
//
|
||||
class ScopedNonblockingLock
|
||||
{
|
||||
DeclareNoncopyableObject(ScopedNonblockingLock);
|
||||
|
||||
protected:
|
||||
NonblockingMutex &m_lock;
|
||||
bool m_IsLocked;
|
||||
protected:
|
||||
NonblockingMutex& m_lock;
|
||||
bool m_IsLocked;
|
||||
|
||||
public:
|
||||
ScopedNonblockingLock(NonblockingMutex &locker)
|
||||
: m_lock(locker)
|
||||
, m_IsLocked(m_lock.TryAcquire())
|
||||
{
|
||||
}
|
||||
public:
|
||||
ScopedNonblockingLock(NonblockingMutex& locker)
|
||||
: m_lock(locker)
|
||||
, m_IsLocked(m_lock.TryAcquire())
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~ScopedNonblockingLock()
|
||||
{
|
||||
if (m_IsLocked)
|
||||
m_lock.Release();
|
||||
}
|
||||
virtual ~ScopedNonblockingLock()
|
||||
{
|
||||
if (m_IsLocked)
|
||||
m_lock.Release();
|
||||
}
|
||||
|
||||
bool Failed() const { return !m_IsLocked; }
|
||||
};
|
||||
bool Failed() const { return !m_IsLocked; }
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// ScopedLockBool
|
||||
// --------------------------------------------------------------------------------------
|
||||
// A ScopedLock in which you specify an external bool to get updated on locks/unlocks.
|
||||
// Note that the isLockedBool should only be used as an indicator for the locked status,
|
||||
// and not actually depended on for thread synchronization...
|
||||
// --------------------------------------------------------------------------------------
|
||||
// ScopedLockBool
|
||||
// --------------------------------------------------------------------------------------
|
||||
// A ScopedLock in which you specify an external bool to get updated on locks/unlocks.
|
||||
// Note that the isLockedBool should only be used as an indicator for the locked status,
|
||||
// and not actually depended on for thread synchronization...
|
||||
|
||||
struct ScopedLockBool
|
||||
{
|
||||
ScopedLock m_lock;
|
||||
std::atomic<bool> &m_bool;
|
||||
struct ScopedLockBool
|
||||
{
|
||||
ScopedLock m_lock;
|
||||
std::atomic<bool>& m_bool;
|
||||
|
||||
ScopedLockBool(Mutex &mutexToLock, std::atomic<bool> &isLockedBool)
|
||||
: m_lock(mutexToLock)
|
||||
, m_bool(isLockedBool)
|
||||
{
|
||||
m_bool.store(m_lock.IsLocked(), std::memory_order_relaxed);
|
||||
}
|
||||
virtual ~ScopedLockBool()
|
||||
{
|
||||
m_bool.store(false, std::memory_order_relaxed);
|
||||
}
|
||||
void Acquire()
|
||||
{
|
||||
m_lock.Acquire();
|
||||
m_bool.store(m_lock.IsLocked(), std::memory_order_relaxed);
|
||||
}
|
||||
void Release()
|
||||
{
|
||||
m_bool.store(false, std::memory_order_relaxed);
|
||||
m_lock.Release();
|
||||
}
|
||||
};
|
||||
}
|
||||
ScopedLockBool(Mutex& mutexToLock, std::atomic<bool>& isLockedBool)
|
||||
: m_lock(mutexToLock)
|
||||
, m_bool(isLockedBool)
|
||||
{
|
||||
m_bool.store(m_lock.IsLocked(), std::memory_order_relaxed);
|
||||
}
|
||||
virtual ~ScopedLockBool()
|
||||
{
|
||||
m_bool.store(false, std::memory_order_relaxed);
|
||||
}
|
||||
void Acquire()
|
||||
{
|
||||
m_lock.Acquire();
|
||||
m_bool.store(m_lock.IsLocked(), std::memory_order_relaxed);
|
||||
}
|
||||
void Release()
|
||||
{
|
||||
m_bool.store(false, std::memory_order_relaxed);
|
||||
m_lock.Release();
|
||||
}
|
||||
};
|
||||
} // namespace Threading
|
||||
|
|
|
@ -25,60 +25,60 @@ wxDEFINE_EVENT(pxEvt_ThreadedTaskComplete, wxCommandEvent);
|
|||
// --------------------------------------------------------------------------------------
|
||||
wxIMPLEMENT_DYNAMIC_CLASS(WaitForTaskDialog, wxDialogWithHelpers);
|
||||
|
||||
Threading::WaitForTaskDialog::WaitForTaskDialog(const wxString &title, const wxString &heading)
|
||||
: wxDialogWithHelpers(NULL, _("Waiting for tasks..."))
|
||||
Threading::WaitForTaskDialog::WaitForTaskDialog(const wxString& title, const wxString& heading)
|
||||
: wxDialogWithHelpers(NULL, _("Waiting for tasks..."))
|
||||
//, m_Timer(this)
|
||||
{
|
||||
SetMinWidth(300);
|
||||
SetMinWidth(300);
|
||||
|
||||
//m_sem = sem;
|
||||
//m_mutex = mutex;
|
||||
//m_sem = sem;
|
||||
//m_mutex = mutex;
|
||||
|
||||
wxString m_title(title);
|
||||
wxString m_heading(heading);
|
||||
wxString m_title(title);
|
||||
wxString m_heading(heading);
|
||||
|
||||
if (m_title.IsEmpty())
|
||||
m_title = _("Waiting for task...");
|
||||
if (m_heading.IsEmpty())
|
||||
m_heading = m_title;
|
||||
if (m_title.IsEmpty())
|
||||
m_title = _("Waiting for task...");
|
||||
if (m_heading.IsEmpty())
|
||||
m_heading = m_title;
|
||||
|
||||
Bind(pxEvt_ThreadedTaskComplete, &WaitForTaskDialog::OnTaskComplete, this);
|
||||
Bind(pxEvt_ThreadedTaskComplete, &WaitForTaskDialog::OnTaskComplete, this);
|
||||
|
||||
*this += 12;
|
||||
*this += Heading(m_heading).Unwrapped() | StdExpand();
|
||||
*this += 12;
|
||||
*this += 12;
|
||||
*this += Heading(m_heading).Unwrapped() | StdExpand();
|
||||
*this += 12;
|
||||
|
||||
// TODO : Implement a cancel button. Not quite sure the best way to do
|
||||
// that, since it requires a thread or event handler context, or something.
|
||||
// TODO : Implement a cancel button. Not quite sure the best way to do
|
||||
// that, since it requires a thread or event handler context, or something.
|
||||
|
||||
//applyDlg += new wxButton( &applyDlg, wxID_CANCEL ) | pxCenter;
|
||||
//applyDlg += 6;
|
||||
//applyDlg += new wxButton( &applyDlg, wxID_CANCEL ) | pxCenter;
|
||||
//applyDlg += 6;
|
||||
|
||||
//Bind(wxEVT_TIMER, &WaitForTaskDialog::OnTimer, this, m_Timer.GetId());
|
||||
//m_Timer.Start( 200 );
|
||||
//GetSysExecutorThread().PostEvent( new SysExecEvent_ApplyPlugins( this, m_sync ) );
|
||||
//Bind(wxEVT_TIMER, &WaitForTaskDialog::OnTimer, this, m_Timer.GetId());
|
||||
//m_Timer.Start( 200 );
|
||||
//GetSysExecutorThread().PostEvent( new SysExecEvent_ApplyPlugins( this, m_sync ) );
|
||||
}
|
||||
|
||||
void Threading::WaitForTaskDialog::OnTaskComplete(wxCommandEvent &evt)
|
||||
void Threading::WaitForTaskDialog::OnTaskComplete(wxCommandEvent& evt)
|
||||
{
|
||||
evt.Skip();
|
||||
evt.Skip();
|
||||
|
||||
// Note: we don't throw exceptions from the pending task here.
|
||||
// Instead we wait until we exit the modal loop below -- this gives
|
||||
// the caller a chance to handle the exception themselves, and if
|
||||
// not the exception will still fall back on the standard app-level
|
||||
// exception handler.
|
||||
// Note: we don't throw exceptions from the pending task here.
|
||||
// Instead we wait until we exit the modal loop below -- this gives
|
||||
// the caller a chance to handle the exception themselves, and if
|
||||
// not the exception will still fall back on the standard app-level
|
||||
// exception handler.
|
||||
|
||||
// (this also avoids any sticky business with the modal dialog not getting
|
||||
// closed out right due to stack unwinding skipping dialog closure crap)
|
||||
// (this also avoids any sticky business with the modal dialog not getting
|
||||
// closed out right due to stack unwinding skipping dialog closure crap)
|
||||
|
||||
m_sync.WaitForResult_NoExceptions();
|
||||
EndModal(wxID_OK);
|
||||
m_sync.WaitForResult_NoExceptions();
|
||||
EndModal(wxID_OK);
|
||||
}
|
||||
|
||||
int Threading::WaitForTaskDialog::ShowModal()
|
||||
{
|
||||
int result = _parent::ShowModal();
|
||||
m_sync.RethrowException();
|
||||
return result;
|
||||
int result = _parent::ShowModal();
|
||||
m_sync.RethrowException();
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -22,31 +22,31 @@ wxDECLARE_EVENT(pxEvt_ThreadedTaskComplete, wxCommandEvent);
|
|||
|
||||
namespace Threading
|
||||
{
|
||||
// --------------------------------------------------------------------------------------
|
||||
// WaitForTaskDialog
|
||||
// --------------------------------------------------------------------------------------
|
||||
// This dialog is displayed whenever the main thread is recursively waiting on multiple
|
||||
// mutexes or semaphores. wxwidgets does not support recursive yielding to pending events
|
||||
// but it *does* support opening a modal dialog, which disables the interface (preventing
|
||||
// the user from starting additional actions), and processes messages (allowing the system
|
||||
// to continue to manage threads and process logging).
|
||||
//
|
||||
class WaitForTaskDialog : public wxDialogWithHelpers
|
||||
{
|
||||
wxDECLARE_DYNAMIC_CLASS_NO_COPY(WaitForTaskDialog);
|
||||
// --------------------------------------------------------------------------------------
|
||||
// WaitForTaskDialog
|
||||
// --------------------------------------------------------------------------------------
|
||||
// This dialog is displayed whenever the main thread is recursively waiting on multiple
|
||||
// mutexes or semaphores. wxwidgets does not support recursive yielding to pending events
|
||||
// but it *does* support opening a modal dialog, which disables the interface (preventing
|
||||
// the user from starting additional actions), and processes messages (allowing the system
|
||||
// to continue to manage threads and process logging).
|
||||
//
|
||||
class WaitForTaskDialog : public wxDialogWithHelpers
|
||||
{
|
||||
wxDECLARE_DYNAMIC_CLASS_NO_COPY(WaitForTaskDialog);
|
||||
|
||||
typedef wxDialogWithHelpers _parent;
|
||||
typedef wxDialogWithHelpers _parent;
|
||||
|
||||
protected:
|
||||
SynchronousActionState m_sync;
|
||||
protected:
|
||||
SynchronousActionState m_sync;
|
||||
|
||||
public:
|
||||
WaitForTaskDialog(const wxString &title = wxEmptyString, const wxString &heading = wxEmptyString);
|
||||
virtual ~WaitForTaskDialog() = default;
|
||||
virtual int ShowModal();
|
||||
public:
|
||||
WaitForTaskDialog(const wxString& title = wxEmptyString, const wxString& heading = wxEmptyString);
|
||||
virtual ~WaitForTaskDialog() = default;
|
||||
virtual int ShowModal();
|
||||
|
||||
protected:
|
||||
void OnTaskComplete(wxCommandEvent &evt);
|
||||
//void OnTimer( wxTimerEvent& evt );
|
||||
};
|
||||
}
|
||||
protected:
|
||||
void OnTaskComplete(wxCommandEvent& evt);
|
||||
//void OnTimer( wxTimerEvent& evt );
|
||||
};
|
||||
} // namespace Threading
|
||||
|
|
|
@ -21,10 +21,10 @@
|
|||
|
||||
namespace Threading
|
||||
{
|
||||
extern const wxTimeSpan def_yieldgui_interval;
|
||||
extern const wxTimeSpan def_yieldgui_interval;
|
||||
|
||||
extern bool _WaitGui_RecursionGuard(const wxChar *name);
|
||||
extern bool _WaitGui_RecursionGuard(const wxChar* name);
|
||||
|
||||
extern void YieldToMain();
|
||||
extern bool AllowDeletions();
|
||||
}
|
||||
extern void YieldToMain();
|
||||
extern bool AllowDeletions();
|
||||
} // namespace Threading
|
||||
|
|
|
@ -29,20 +29,20 @@
|
|||
//
|
||||
struct TraceLogDescriptor
|
||||
{
|
||||
// short name, alphanumerics only: used for saving/loading options.
|
||||
const wxChar *ShortName;
|
||||
// short name, alphanumerics only: used for saving/loading options.
|
||||
const wxChar* ShortName;
|
||||
|
||||
// Standard UI name for this log source. Used in menus, options dialogs.
|
||||
const wxChar *Name;
|
||||
// Standard UI name for this log source. Used in menus, options dialogs.
|
||||
const wxChar* Name;
|
||||
|
||||
// Length description for use as a tooltip or menu item description.
|
||||
const wxChar *Description;
|
||||
// Length description for use as a tooltip or menu item description.
|
||||
const wxChar* Description;
|
||||
|
||||
wxString GetShortName() const
|
||||
{
|
||||
pxAssumeDev(Name, "Tracelog descriptors require a valid name!");
|
||||
return ShortName ? ShortName : Name;
|
||||
}
|
||||
wxString GetShortName() const
|
||||
{
|
||||
pxAssumeDev(Name, "Tracelog descriptors require a valid name!");
|
||||
return ShortName ? ShortName : Name;
|
||||
}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -66,51 +66,51 @@ struct TraceLogDescriptor
|
|||
class BaseTraceLogSource
|
||||
{
|
||||
protected:
|
||||
const TraceLogDescriptor *m_Descriptor;
|
||||
const TraceLogDescriptor* m_Descriptor;
|
||||
|
||||
public:
|
||||
// Indicates if the user has enabled this specific log. This boolean only represents
|
||||
// the configured status of this log, and does *NOT* actually mean the log is active
|
||||
// even when TRUE. Because many tracelogs have master enablers that act on a group
|
||||
// of logs, logging checks should always use IsActive() instead to determine if a log
|
||||
// should be processed or not.
|
||||
bool Enabled;
|
||||
// Indicates if the user has enabled this specific log. This boolean only represents
|
||||
// the configured status of this log, and does *NOT* actually mean the log is active
|
||||
// even when TRUE. Because many tracelogs have master enablers that act on a group
|
||||
// of logs, logging checks should always use IsActive() instead to determine if a log
|
||||
// should be processed or not.
|
||||
bool Enabled;
|
||||
|
||||
protected:
|
||||
BaseTraceLogSource()
|
||||
: m_Descriptor(NULL)
|
||||
, Enabled(false)
|
||||
{
|
||||
}
|
||||
BaseTraceLogSource()
|
||||
: m_Descriptor(NULL)
|
||||
, Enabled(false)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
TraceLog_ImplementBaseAPI(BaseTraceLogSource)
|
||||
TraceLog_ImplementBaseAPI(BaseTraceLogSource)
|
||||
|
||||
BaseTraceLogSource(const TraceLogDescriptor *desc)
|
||||
{
|
||||
pxAssumeDev(desc, "Trace logs must have a valid (non-NULL) descriptor.");
|
||||
Enabled = false;
|
||||
m_Descriptor = desc;
|
||||
}
|
||||
BaseTraceLogSource(const TraceLogDescriptor* desc)
|
||||
{
|
||||
pxAssumeDev(desc, "Trace logs must have a valid (non-NULL) descriptor.");
|
||||
Enabled = false;
|
||||
m_Descriptor = desc;
|
||||
}
|
||||
|
||||
// Provides a categorical identifier, typically in "group.subgroup.subgroup" form.
|
||||
// (use periods in favor of colons, since they do not require escape characters when
|
||||
// written to ini/config files).
|
||||
virtual wxString GetCategory() const { return wxEmptyString; }
|
||||
// Provides a categorical identifier, typically in "group.subgroup.subgroup" form.
|
||||
// (use periods in favor of colons, since they do not require escape characters when
|
||||
// written to ini/config files).
|
||||
virtual wxString GetCategory() const { return wxEmptyString; }
|
||||
|
||||
// This method should be used to determine if a log should be generated or not.
|
||||
// See the class overview comments for details on how and why this method should
|
||||
// be used.
|
||||
virtual bool IsActive() const { return Enabled; }
|
||||
// This method should be used to determine if a log should be generated or not.
|
||||
// See the class overview comments for details on how and why this method should
|
||||
// be used.
|
||||
virtual bool IsActive() const { return Enabled; }
|
||||
|
||||
virtual wxString GetShortName() const { return m_Descriptor->GetShortName(); }
|
||||
virtual const wxChar *GetName() const { return m_Descriptor->Name; }
|
||||
virtual const wxChar *GetDescription() const
|
||||
{
|
||||
return (m_Descriptor->Description != NULL) ? pxGetTranslation(m_Descriptor->Description) : wxEmptyString;
|
||||
}
|
||||
virtual wxString GetShortName() const { return m_Descriptor->GetShortName(); }
|
||||
virtual const wxChar* GetName() const { return m_Descriptor->Name; }
|
||||
virtual const wxChar* GetDescription() const
|
||||
{
|
||||
return (m_Descriptor->Description != NULL) ? pxGetTranslation(m_Descriptor->Description) : wxEmptyString;
|
||||
}
|
||||
|
||||
virtual bool HasDescription() const { return m_Descriptor->Description != NULL; }
|
||||
virtual bool HasDescription() const { return m_Descriptor->Description != NULL; }
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -122,32 +122,32 @@ public:
|
|||
class TextFileTraceLog : public BaseTraceLogSource
|
||||
{
|
||||
public:
|
||||
TextFileTraceLog(const TraceLogDescriptor *desc)
|
||||
: BaseTraceLogSource(desc)
|
||||
{
|
||||
}
|
||||
TextFileTraceLog(const TraceLogDescriptor* desc)
|
||||
: BaseTraceLogSource(desc)
|
||||
{
|
||||
}
|
||||
|
||||
bool Write(const char *fmt, ...) const
|
||||
{
|
||||
va_list list;
|
||||
va_start(list, fmt);
|
||||
WriteV(fmt, list);
|
||||
va_end(list);
|
||||
bool Write(const char* fmt, ...) const
|
||||
{
|
||||
va_list list;
|
||||
va_start(list, fmt);
|
||||
WriteV(fmt, list);
|
||||
va_end(list);
|
||||
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WriteV(const char *fmt, va_list list) const
|
||||
{
|
||||
FastFormatAscii ascii;
|
||||
ApplyPrefix(ascii);
|
||||
ascii.WriteV(fmt, list);
|
||||
DoWrite(ascii);
|
||||
return false;
|
||||
}
|
||||
bool WriteV(const char* fmt, va_list list) const
|
||||
{
|
||||
FastFormatAscii ascii;
|
||||
ApplyPrefix(ascii);
|
||||
ascii.WriteV(fmt, list);
|
||||
DoWrite(ascii);
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void ApplyPrefix(FastFormatAscii &ascii) const {}
|
||||
virtual void DoWrite(const char *fmt) const = 0;
|
||||
virtual void ApplyPrefix(FastFormatAscii& ascii) const {}
|
||||
virtual void DoWrite(const char* fmt) const = 0;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -159,130 +159,130 @@ public:
|
|||
class ConsoleLogSource : public BaseTraceLogSource
|
||||
{
|
||||
public:
|
||||
ConsoleColors DefaultColor;
|
||||
ConsoleColors DefaultColor;
|
||||
|
||||
protected:
|
||||
ConsoleLogSource()
|
||||
: DefaultColor(Color_Gray)
|
||||
{
|
||||
}
|
||||
ConsoleLogSource()
|
||||
: DefaultColor(Color_Gray)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
ConsoleLog_ImplementBaseAPI(ConsoleLogSource)
|
||||
ConsoleLog_ImplementBaseAPI(ConsoleLogSource)
|
||||
|
||||
ConsoleLogSource(const TraceLogDescriptor *desc, ConsoleColors defaultColor = Color_Gray)
|
||||
: BaseTraceLogSource(desc)
|
||||
{
|
||||
DefaultColor = defaultColor;
|
||||
}
|
||||
ConsoleLogSource(const TraceLogDescriptor* desc, ConsoleColors defaultColor = Color_Gray)
|
||||
: BaseTraceLogSource(desc)
|
||||
{
|
||||
DefaultColor = defaultColor;
|
||||
}
|
||||
|
||||
// Writes to the console using the source's default color. Note that the source's default
|
||||
// color will always be used, thus ConsoleColorScope() will not be effectual unless the
|
||||
// console's default color is Color_Default.
|
||||
bool Write(const char *fmt, ...) const
|
||||
{
|
||||
va_list list;
|
||||
va_start(list, fmt);
|
||||
WriteV(fmt, list);
|
||||
va_end(list);
|
||||
// Writes to the console using the source's default color. Note that the source's default
|
||||
// color will always be used, thus ConsoleColorScope() will not be effectual unless the
|
||||
// console's default color is Color_Default.
|
||||
bool Write(const char* fmt, ...) const
|
||||
{
|
||||
va_list list;
|
||||
va_start(list, fmt);
|
||||
WriteV(fmt, list);
|
||||
va_end(list);
|
||||
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Write(const wxChar *fmt, ...) const
|
||||
{
|
||||
va_list list;
|
||||
va_start(list, fmt);
|
||||
WriteV(fmt, list);
|
||||
va_end(list);
|
||||
bool Write(const wxChar* fmt, ...) const
|
||||
{
|
||||
va_list list;
|
||||
va_start(list, fmt);
|
||||
WriteV(fmt, list);
|
||||
va_end(list);
|
||||
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Write(const wxString fmt, ...) const
|
||||
{
|
||||
va_list list;
|
||||
va_start(list, fmt);
|
||||
WriteV(fmt.wx_str(), list);
|
||||
va_end(list);
|
||||
bool Write(const wxString fmt, ...) const
|
||||
{
|
||||
va_list list;
|
||||
va_start(list, fmt);
|
||||
WriteV(fmt.wx_str(), list);
|
||||
va_end(list);
|
||||
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Writes to the console using the specified color. This overrides the default color setting
|
||||
// for this log.
|
||||
bool Write(ConsoleColors color, const char *fmt, ...) const
|
||||
{
|
||||
va_list list;
|
||||
va_start(list, fmt);
|
||||
WriteV(color, fmt, list);
|
||||
va_end(list);
|
||||
// Writes to the console using the specified color. This overrides the default color setting
|
||||
// for this log.
|
||||
bool Write(ConsoleColors color, const char* fmt, ...) const
|
||||
{
|
||||
va_list list;
|
||||
va_start(list, fmt);
|
||||
WriteV(color, fmt, list);
|
||||
va_end(list);
|
||||
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Write(ConsoleColors color, const wxChar *fmt, ...) const
|
||||
{
|
||||
va_list list;
|
||||
va_start(list, fmt);
|
||||
WriteV(color, fmt, list);
|
||||
va_end(list);
|
||||
bool Write(ConsoleColors color, const wxChar* fmt, ...) const
|
||||
{
|
||||
va_list list;
|
||||
va_start(list, fmt);
|
||||
WriteV(color, fmt, list);
|
||||
va_end(list);
|
||||
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Writes to the console using bold yellow text -- overrides the log source's default
|
||||
// color settings.
|
||||
bool Warn(const wxChar *fmt, ...) const
|
||||
{
|
||||
va_list list;
|
||||
va_start(list, fmt);
|
||||
WriteV(Color_StrongYellow, fmt, list);
|
||||
va_end(list);
|
||||
// Writes to the console using bold yellow text -- overrides the log source's default
|
||||
// color settings.
|
||||
bool Warn(const wxChar* fmt, ...) const
|
||||
{
|
||||
va_list list;
|
||||
va_start(list, fmt);
|
||||
WriteV(Color_StrongYellow, fmt, list);
|
||||
va_end(list);
|
||||
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Warn(const wxString fmt, ...) const
|
||||
{
|
||||
va_list list;
|
||||
va_start(list, fmt);
|
||||
WriteV(Color_StrongYellow, fmt.wx_str(), list);
|
||||
va_end(list);
|
||||
bool Warn(const wxString fmt, ...) const
|
||||
{
|
||||
va_list list;
|
||||
va_start(list, fmt);
|
||||
WriteV(Color_StrongYellow, fmt.wx_str(), list);
|
||||
va_end(list);
|
||||
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Writes to the console using bold red text -- overrides the log source's default
|
||||
// color settings.
|
||||
bool Error(const wxChar *fmt, ...) const
|
||||
{
|
||||
va_list list;
|
||||
va_start(list, fmt);
|
||||
WriteV(Color_StrongRed, fmt, list);
|
||||
va_end(list);
|
||||
// Writes to the console using bold red text -- overrides the log source's default
|
||||
// color settings.
|
||||
bool Error(const wxChar* fmt, ...) const
|
||||
{
|
||||
va_list list;
|
||||
va_start(list, fmt);
|
||||
WriteV(Color_StrongRed, fmt, list);
|
||||
va_end(list);
|
||||
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Error(const wxString fmt, ...) const
|
||||
{
|
||||
va_list list;
|
||||
va_start(list, fmt);
|
||||
WriteV(Color_StrongRed, fmt.wx_str(), list);
|
||||
va_end(list);
|
||||
bool Error(const wxString fmt, ...) const
|
||||
{
|
||||
va_list list;
|
||||
va_start(list, fmt);
|
||||
WriteV(Color_StrongRed, fmt.wx_str(), list);
|
||||
va_end(list);
|
||||
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WriteV(const char *fmt, va_list list) const;
|
||||
bool WriteV(const wxChar *fmt, va_list list) const;
|
||||
bool WriteV(const char* fmt, va_list list) const;
|
||||
bool WriteV(const wxChar* fmt, va_list list) const;
|
||||
|
||||
bool WriteV(ConsoleColors color, const char *fmt, va_list list) const;
|
||||
bool WriteV(ConsoleColors color, const wxChar *fmt, va_list list) const;
|
||||
bool WriteV(ConsoleColors color, const char* fmt, va_list list) const;
|
||||
bool WriteV(ConsoleColors color, const wxChar* fmt, va_list list) const;
|
||||
|
||||
virtual void DoWrite(const wxChar *msg) const
|
||||
{
|
||||
Console.DoWriteLn(msg);
|
||||
}
|
||||
virtual void DoWrite(const wxChar* msg) const
|
||||
{
|
||||
Console.DoWriteLn(msg);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -22,18 +22,19 @@
|
|||
|
||||
template class EventSource<IEventListener_PageFault>;
|
||||
|
||||
SrcType_PageFault *Source_PageFault = NULL;
|
||||
SrcType_PageFault* Source_PageFault = NULL;
|
||||
Threading::Mutex PageFault_Mutex;
|
||||
|
||||
void pxInstallSignalHandler()
|
||||
{
|
||||
if (!Source_PageFault) {
|
||||
Source_PageFault = new SrcType_PageFault();
|
||||
}
|
||||
if (!Source_PageFault)
|
||||
{
|
||||
Source_PageFault = new SrcType_PageFault();
|
||||
}
|
||||
|
||||
_platform_InstallSignalHandler();
|
||||
_platform_InstallSignalHandler();
|
||||
|
||||
// NOP on Win32 systems -- we use __try{} __except{} instead.
|
||||
// NOP on Win32 systems -- we use __try{} __except{} instead.
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -41,200 +42,221 @@ void pxInstallSignalHandler()
|
|||
// --------------------------------------------------------------------------------------
|
||||
EventListener_PageFault::EventListener_PageFault()
|
||||
{
|
||||
pxAssert(Source_PageFault);
|
||||
Source_PageFault->Add(*this);
|
||||
pxAssert(Source_PageFault);
|
||||
Source_PageFault->Add(*this);
|
||||
}
|
||||
|
||||
EventListener_PageFault::~EventListener_PageFault()
|
||||
{
|
||||
if (Source_PageFault)
|
||||
Source_PageFault->Remove(*this);
|
||||
if (Source_PageFault)
|
||||
Source_PageFault->Remove(*this);
|
||||
}
|
||||
|
||||
void SrcType_PageFault::Dispatch(const PageFaultInfo ¶ms)
|
||||
void SrcType_PageFault::Dispatch(const PageFaultInfo& params)
|
||||
{
|
||||
m_handled = false;
|
||||
_parent::Dispatch(params);
|
||||
m_handled = false;
|
||||
_parent::Dispatch(params);
|
||||
}
|
||||
|
||||
void SrcType_PageFault::_DispatchRaw(ListenerIterator iter, const ListenerIterator &iend, const PageFaultInfo &evt)
|
||||
void SrcType_PageFault::_DispatchRaw(ListenerIterator iter, const ListenerIterator& iend, const PageFaultInfo& evt)
|
||||
{
|
||||
do {
|
||||
(*iter)->DispatchEvent(evt, m_handled);
|
||||
} while ((++iter != iend) && !m_handled);
|
||||
do
|
||||
{
|
||||
(*iter)->DispatchEvent(evt, m_handled);
|
||||
} while ((++iter != iend) && !m_handled);
|
||||
}
|
||||
|
||||
static size_t pageAlign(size_t size)
|
||||
{
|
||||
return (size + __pagesize - 1) / __pagesize * __pagesize;
|
||||
return (size + __pagesize - 1) / __pagesize * __pagesize;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// VirtualMemoryManager (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
VirtualMemoryManager::VirtualMemoryManager(const wxString &name, uptr base, size_t size, uptr upper_bounds, bool strict)
|
||||
: m_name(name), m_baseptr(0), m_pageuse(nullptr), m_pages_reserved(0)
|
||||
VirtualMemoryManager::VirtualMemoryManager(const wxString& name, uptr base, size_t size, uptr upper_bounds, bool strict)
|
||||
: m_name(name)
|
||||
, m_baseptr(0)
|
||||
, m_pageuse(nullptr)
|
||||
, m_pages_reserved(0)
|
||||
{
|
||||
if (!size) return;
|
||||
if (!size)
|
||||
return;
|
||||
|
||||
uptr reserved_bytes = pageAlign(size);
|
||||
m_pages_reserved = reserved_bytes / __pagesize;
|
||||
uptr reserved_bytes = pageAlign(size);
|
||||
m_pages_reserved = reserved_bytes / __pagesize;
|
||||
|
||||
m_baseptr = (uptr)HostSys::MmapReserve(base, reserved_bytes);
|
||||
m_baseptr = (uptr)HostSys::MmapReserve(base, reserved_bytes);
|
||||
|
||||
if (!m_baseptr || (upper_bounds != 0 && (((uptr)m_baseptr + reserved_bytes) > upper_bounds))) {
|
||||
DevCon.Warning(L"%s: host memory @ %ls -> %ls is unavailable; attempting to map elsewhere...",
|
||||
WX_STR(m_name), pxsPtr(base), pxsPtr(base + size));
|
||||
if (!m_baseptr || (upper_bounds != 0 && (((uptr)m_baseptr + reserved_bytes) > upper_bounds)))
|
||||
{
|
||||
DevCon.Warning(L"%s: host memory @ %ls -> %ls is unavailable; attempting to map elsewhere...",
|
||||
WX_STR(m_name), pxsPtr(base), pxsPtr(base + size));
|
||||
|
||||
SafeSysMunmap(m_baseptr, reserved_bytes);
|
||||
SafeSysMunmap(m_baseptr, reserved_bytes);
|
||||
|
||||
if (base) {
|
||||
// Let's try again at an OS-picked memory area, and then hope it meets needed
|
||||
// boundschecking criteria below.
|
||||
m_baseptr = (uptr)HostSys::MmapReserve(0, reserved_bytes);
|
||||
}
|
||||
}
|
||||
if (base)
|
||||
{
|
||||
// Let's try again at an OS-picked memory area, and then hope it meets needed
|
||||
// boundschecking criteria below.
|
||||
m_baseptr = (uptr)HostSys::MmapReserve(0, reserved_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
bool fulfillsRequirements = true;
|
||||
if (strict && m_baseptr != base)
|
||||
fulfillsRequirements = false;
|
||||
if ((upper_bounds != 0) && ((m_baseptr + reserved_bytes) > upper_bounds))
|
||||
fulfillsRequirements = false;
|
||||
if (!fulfillsRequirements) {
|
||||
SafeSysMunmap(m_baseptr, reserved_bytes);
|
||||
}
|
||||
bool fulfillsRequirements = true;
|
||||
if (strict && m_baseptr != base)
|
||||
fulfillsRequirements = false;
|
||||
if ((upper_bounds != 0) && ((m_baseptr + reserved_bytes) > upper_bounds))
|
||||
fulfillsRequirements = false;
|
||||
if (!fulfillsRequirements)
|
||||
{
|
||||
SafeSysMunmap(m_baseptr, reserved_bytes);
|
||||
}
|
||||
|
||||
if (!m_baseptr) return;
|
||||
if (!m_baseptr)
|
||||
return;
|
||||
|
||||
m_pageuse = new std::atomic<bool>[m_pages_reserved]();
|
||||
m_pageuse = new std::atomic<bool>[m_pages_reserved]();
|
||||
|
||||
FastFormatUnicode mbkb;
|
||||
uint mbytes = reserved_bytes / _1mb;
|
||||
if (mbytes)
|
||||
mbkb.Write("[%umb]", mbytes);
|
||||
else
|
||||
mbkb.Write("[%ukb]", reserved_bytes / 1024);
|
||||
FastFormatUnicode mbkb;
|
||||
uint mbytes = reserved_bytes / _1mb;
|
||||
if (mbytes)
|
||||
mbkb.Write("[%umb]", mbytes);
|
||||
else
|
||||
mbkb.Write("[%ukb]", reserved_bytes / 1024);
|
||||
|
||||
DevCon.WriteLn(Color_Gray, L"%-32s @ %ls -> %ls %ls", WX_STR(m_name),
|
||||
pxsPtr(m_baseptr), pxsPtr((uptr)m_baseptr + reserved_bytes), mbkb.c_str());
|
||||
DevCon.WriteLn(Color_Gray, L"%-32s @ %ls -> %ls %ls", WX_STR(m_name),
|
||||
pxsPtr(m_baseptr), pxsPtr((uptr)m_baseptr + reserved_bytes), mbkb.c_str());
|
||||
}
|
||||
|
||||
VirtualMemoryManager::~VirtualMemoryManager()
|
||||
{
|
||||
if (m_pageuse) delete[] m_pageuse;
|
||||
if (m_baseptr) HostSys::Munmap(m_baseptr, m_pages_reserved * __pagesize);
|
||||
if (m_pageuse)
|
||||
delete[] m_pageuse;
|
||||
if (m_baseptr)
|
||||
HostSys::Munmap(m_baseptr, m_pages_reserved * __pagesize);
|
||||
}
|
||||
|
||||
static bool VMMMarkPagesAsInUse(std::atomic<bool> *begin, std::atomic<bool> *end) {
|
||||
for (auto current = begin; current < end; current++) {
|
||||
bool expected = false;
|
||||
if (!current->compare_exchange_strong(expected, true), std::memory_order_relaxed) {
|
||||
// This was already allocated! Undo the things we've set until this point
|
||||
while (--current >= begin) {
|
||||
if (!current->compare_exchange_strong(expected, false, std::memory_order_relaxed)) {
|
||||
// In the time we were doing this, someone set one of the things we just set to true back to false
|
||||
// This should never happen, but if it does we'll just stop and hope nothing bad happens
|
||||
pxAssert(0);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void *VirtualMemoryManager::Alloc(uptr offsetLocation, size_t size) const
|
||||
static bool VMMMarkPagesAsInUse(std::atomic<bool>* begin, std::atomic<bool>* end)
|
||||
{
|
||||
size = pageAlign(size);
|
||||
if (!pxAssertDev(offsetLocation % __pagesize == 0, "(VirtualMemoryManager) alloc at unaligned offsetLocation"))
|
||||
return nullptr;
|
||||
if (!pxAssertDev(size + offsetLocation <= m_pages_reserved * __pagesize, "(VirtualMemoryManager) alloc outside reserved area"))
|
||||
return nullptr;
|
||||
if (m_baseptr == 0)
|
||||
return nullptr;
|
||||
auto puStart = &m_pageuse[offsetLocation / __pagesize];
|
||||
auto puEnd = &m_pageuse[(offsetLocation+size) / __pagesize];
|
||||
if (!pxAssertDev(VMMMarkPagesAsInUse(puStart, puEnd), "(VirtualMemoryManager) allocation requests overlapped"))
|
||||
return nullptr;
|
||||
return (void *)(m_baseptr + offsetLocation);
|
||||
for (auto current = begin; current < end; current++)
|
||||
{
|
||||
bool expected = false;
|
||||
if (!current->compare_exchange_strong(expected, true), std::memory_order_relaxed)
|
||||
{
|
||||
// This was already allocated! Undo the things we've set until this point
|
||||
while (--current >= begin)
|
||||
{
|
||||
if (!current->compare_exchange_strong(expected, false, std::memory_order_relaxed))
|
||||
{
|
||||
// In the time we were doing this, someone set one of the things we just set to true back to false
|
||||
// This should never happen, but if it does we'll just stop and hope nothing bad happens
|
||||
pxAssert(0);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void VirtualMemoryManager::Free(void *address, size_t size) const
|
||||
void* VirtualMemoryManager::Alloc(uptr offsetLocation, size_t size) const
|
||||
{
|
||||
uptr offsetLocation = (uptr)address - m_baseptr;
|
||||
if (!pxAssertDev(offsetLocation % __pagesize == 0, "(VirtualMemoryManager) free at unaligned address")) {
|
||||
uptr newLoc = pageAlign(offsetLocation);
|
||||
size -= (offsetLocation - newLoc);
|
||||
offsetLocation = newLoc;
|
||||
}
|
||||
if (!pxAssertDev(size % __pagesize == 0, "(VirtualMemoryManager) free with unaligned size"))
|
||||
size -= size % __pagesize;
|
||||
if (!pxAssertDev(size + offsetLocation <= m_pages_reserved * __pagesize, "(VirtualMemoryManager) free outside reserved area"))
|
||||
return;
|
||||
auto puStart = &m_pageuse[offsetLocation / __pagesize];
|
||||
auto puEnd = &m_pageuse[(offsetLocation+size) / __pagesize];
|
||||
for (; puStart < puEnd; puStart++) {
|
||||
bool expected = true;
|
||||
if (!puStart->compare_exchange_strong(expected, false, std::memory_order_relaxed)) {
|
||||
pxAssertDev(0, "(VirtaulMemoryManager) double-free");
|
||||
}
|
||||
}
|
||||
size = pageAlign(size);
|
||||
if (!pxAssertDev(offsetLocation % __pagesize == 0, "(VirtualMemoryManager) alloc at unaligned offsetLocation"))
|
||||
return nullptr;
|
||||
if (!pxAssertDev(size + offsetLocation <= m_pages_reserved * __pagesize, "(VirtualMemoryManager) alloc outside reserved area"))
|
||||
return nullptr;
|
||||
if (m_baseptr == 0)
|
||||
return nullptr;
|
||||
auto puStart = &m_pageuse[offsetLocation / __pagesize];
|
||||
auto puEnd = &m_pageuse[(offsetLocation + size) / __pagesize];
|
||||
if (!pxAssertDev(VMMMarkPagesAsInUse(puStart, puEnd), "(VirtualMemoryManager) allocation requests overlapped"))
|
||||
return nullptr;
|
||||
return (void*)(m_baseptr + offsetLocation);
|
||||
}
|
||||
|
||||
void VirtualMemoryManager::Free(void* address, size_t size) const
|
||||
{
|
||||
uptr offsetLocation = (uptr)address - m_baseptr;
|
||||
if (!pxAssertDev(offsetLocation % __pagesize == 0, "(VirtualMemoryManager) free at unaligned address"))
|
||||
{
|
||||
uptr newLoc = pageAlign(offsetLocation);
|
||||
size -= (offsetLocation - newLoc);
|
||||
offsetLocation = newLoc;
|
||||
}
|
||||
if (!pxAssertDev(size % __pagesize == 0, "(VirtualMemoryManager) free with unaligned size"))
|
||||
size -= size % __pagesize;
|
||||
if (!pxAssertDev(size + offsetLocation <= m_pages_reserved * __pagesize, "(VirtualMemoryManager) free outside reserved area"))
|
||||
return;
|
||||
auto puStart = &m_pageuse[offsetLocation / __pagesize];
|
||||
auto puEnd = &m_pageuse[(offsetLocation + size) / __pagesize];
|
||||
for (; puStart < puEnd; puStart++)
|
||||
{
|
||||
bool expected = true;
|
||||
if (!puStart->compare_exchange_strong(expected, false, std::memory_order_relaxed))
|
||||
{
|
||||
pxAssertDev(0, "(VirtaulMemoryManager) double-free");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// VirtualMemoryBumpAllocator (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
VirtualMemoryBumpAllocator::VirtualMemoryBumpAllocator(VirtualMemoryManagerPtr allocator, uptr offsetLocation, size_t size)
|
||||
: m_allocator(std::move(allocator)), m_baseptr((uptr)m_allocator->Alloc(offsetLocation, size)), m_endptr(m_baseptr + size)
|
||||
: m_allocator(std::move(allocator))
|
||||
, m_baseptr((uptr)m_allocator->Alloc(offsetLocation, size))
|
||||
, m_endptr(m_baseptr + size)
|
||||
{
|
||||
if (m_baseptr.load() == 0)
|
||||
pxAssertDev(0, "(VirtualMemoryBumpAllocator) tried to construct from bad VirtualMemoryManager");
|
||||
if (m_baseptr.load() == 0)
|
||||
pxAssertDev(0, "(VirtualMemoryBumpAllocator) tried to construct from bad VirtualMemoryManager");
|
||||
}
|
||||
|
||||
void *VirtualMemoryBumpAllocator::Alloc(size_t size)
|
||||
void* VirtualMemoryBumpAllocator::Alloc(size_t size)
|
||||
{
|
||||
if (m_baseptr.load() == 0) // True if constructed from bad VirtualMemoryManager (assertion was on initialization)
|
||||
return nullptr;
|
||||
if (m_baseptr.load() == 0) // True if constructed from bad VirtualMemoryManager (assertion was on initialization)
|
||||
return nullptr;
|
||||
|
||||
size_t reservedSize = pageAlign(size);
|
||||
size_t reservedSize = pageAlign(size);
|
||||
|
||||
uptr out = m_baseptr.fetch_add(reservedSize, std::memory_order_relaxed);
|
||||
uptr out = m_baseptr.fetch_add(reservedSize, std::memory_order_relaxed);
|
||||
|
||||
if (!pxAssertDev(out - reservedSize + size <= m_endptr, "(VirtualMemoryBumpAllocator) ran out of memory"))
|
||||
return nullptr;
|
||||
if (!pxAssertDev(out - reservedSize + size <= m_endptr, "(VirtualMemoryBumpAllocator) ran out of memory"))
|
||||
return nullptr;
|
||||
|
||||
return (void *)out;
|
||||
return (void*)out;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// VirtualMemoryReserve (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
VirtualMemoryReserve::VirtualMemoryReserve(const wxString &name, size_t size)
|
||||
: m_name(name)
|
||||
VirtualMemoryReserve::VirtualMemoryReserve(const wxString& name, size_t size)
|
||||
: m_name(name)
|
||||
{
|
||||
m_defsize = size;
|
||||
m_defsize = size;
|
||||
|
||||
m_allocator = nullptr;
|
||||
m_pages_commited = 0;
|
||||
m_pages_reserved = 0;
|
||||
m_baseptr = nullptr;
|
||||
m_prot_mode = PageAccess_None();
|
||||
m_allow_writes = true;
|
||||
m_allocator = nullptr;
|
||||
m_pages_commited = 0;
|
||||
m_pages_reserved = 0;
|
||||
m_baseptr = nullptr;
|
||||
m_prot_mode = PageAccess_None();
|
||||
m_allow_writes = true;
|
||||
}
|
||||
|
||||
VirtualMemoryReserve &VirtualMemoryReserve::SetPageAccessOnCommit(const PageProtectionMode &mode)
|
||||
VirtualMemoryReserve& VirtualMemoryReserve::SetPageAccessOnCommit(const PageProtectionMode& mode)
|
||||
{
|
||||
m_prot_mode = mode;
|
||||
return *this;
|
||||
m_prot_mode = mode;
|
||||
return *this;
|
||||
}
|
||||
|
||||
size_t VirtualMemoryReserve::GetSize(size_t requestedSize)
|
||||
{
|
||||
if (!requestedSize)
|
||||
return pageAlign(m_defsize);
|
||||
return pageAlign(requestedSize);
|
||||
if (!requestedSize)
|
||||
return pageAlign(m_defsize);
|
||||
return pageAlign(requestedSize);
|
||||
}
|
||||
|
||||
// Notes:
|
||||
|
@ -245,84 +267,85 @@ size_t VirtualMemoryReserve::GetSize(size_t requestedSize)
|
|||
// baseptr - the new base pointer that's about to be assigned
|
||||
// size - size of the region pointed to by baseptr
|
||||
//
|
||||
void *VirtualMemoryReserve::Assign(VirtualMemoryManagerPtr allocator, void * baseptr, size_t size)
|
||||
void* VirtualMemoryReserve::Assign(VirtualMemoryManagerPtr allocator, void* baseptr, size_t size)
|
||||
{
|
||||
if (!pxAssertDev(m_baseptr == NULL, "(VirtualMemoryReserve) Invalid object state; object has already been reserved."))
|
||||
return m_baseptr;
|
||||
if (!pxAssertDev(m_baseptr == NULL, "(VirtualMemoryReserve) Invalid object state; object has already been reserved."))
|
||||
return m_baseptr;
|
||||
|
||||
if (!size)
|
||||
return nullptr;
|
||||
if (!size)
|
||||
return nullptr;
|
||||
|
||||
m_allocator = std::move(allocator);
|
||||
m_allocator = std::move(allocator);
|
||||
|
||||
m_baseptr = baseptr;
|
||||
m_baseptr = baseptr;
|
||||
|
||||
uptr reserved_bytes = pageAlign(size);
|
||||
m_pages_reserved = reserved_bytes / __pagesize;
|
||||
uptr reserved_bytes = pageAlign(size);
|
||||
m_pages_reserved = reserved_bytes / __pagesize;
|
||||
|
||||
if (!m_baseptr)
|
||||
return nullptr;
|
||||
if (!m_baseptr)
|
||||
return nullptr;
|
||||
|
||||
FastFormatUnicode mbkb;
|
||||
uint mbytes = reserved_bytes / _1mb;
|
||||
if (mbytes)
|
||||
mbkb.Write("[%umb]", mbytes);
|
||||
else
|
||||
mbkb.Write("[%ukb]", reserved_bytes / 1024);
|
||||
FastFormatUnicode mbkb;
|
||||
uint mbytes = reserved_bytes / _1mb;
|
||||
if (mbytes)
|
||||
mbkb.Write("[%umb]", mbytes);
|
||||
else
|
||||
mbkb.Write("[%ukb]", reserved_bytes / 1024);
|
||||
|
||||
DevCon.WriteLn(Color_Gray, L"%-32s @ %ls -> %ls %ls", WX_STR(m_name),
|
||||
pxsPtr(m_baseptr), pxsPtr((uptr)m_baseptr + reserved_bytes), mbkb.c_str());
|
||||
DevCon.WriteLn(Color_Gray, L"%-32s @ %ls -> %ls %ls", WX_STR(m_name),
|
||||
pxsPtr(m_baseptr), pxsPtr((uptr)m_baseptr + reserved_bytes), mbkb.c_str());
|
||||
|
||||
return m_baseptr;
|
||||
return m_baseptr;
|
||||
}
|
||||
|
||||
void VirtualMemoryReserve::ReprotectCommittedBlocks(const PageProtectionMode &newmode)
|
||||
void VirtualMemoryReserve::ReprotectCommittedBlocks(const PageProtectionMode& newmode)
|
||||
{
|
||||
if (!m_pages_commited)
|
||||
return;
|
||||
HostSys::MemProtect(m_baseptr, m_pages_commited * __pagesize, newmode);
|
||||
if (!m_pages_commited)
|
||||
return;
|
||||
HostSys::MemProtect(m_baseptr, m_pages_commited * __pagesize, newmode);
|
||||
}
|
||||
|
||||
// Clears all committed blocks, restoring the allocation to a reserve only.
|
||||
void VirtualMemoryReserve::Reset()
|
||||
{
|
||||
if (!m_pages_commited)
|
||||
return;
|
||||
if (!m_pages_commited)
|
||||
return;
|
||||
|
||||
ReprotectCommittedBlocks(PageAccess_None());
|
||||
HostSys::MmapResetPtr(m_baseptr, m_pages_commited * __pagesize);
|
||||
m_pages_commited = 0;
|
||||
ReprotectCommittedBlocks(PageAccess_None());
|
||||
HostSys::MmapResetPtr(m_baseptr, m_pages_commited * __pagesize);
|
||||
m_pages_commited = 0;
|
||||
}
|
||||
|
||||
void VirtualMemoryReserve::Release()
|
||||
{
|
||||
if (!m_baseptr) return;
|
||||
Reset();
|
||||
m_allocator->Free(m_baseptr, m_pages_reserved * __pagesize);
|
||||
m_baseptr = nullptr;
|
||||
if (!m_baseptr)
|
||||
return;
|
||||
Reset();
|
||||
m_allocator->Free(m_baseptr, m_pages_reserved * __pagesize);
|
||||
m_baseptr = nullptr;
|
||||
}
|
||||
|
||||
bool VirtualMemoryReserve::Commit()
|
||||
{
|
||||
if (!m_pages_reserved)
|
||||
return false;
|
||||
if (!pxAssert(!m_pages_commited))
|
||||
return true;
|
||||
if (!m_pages_reserved)
|
||||
return false;
|
||||
if (!pxAssert(!m_pages_commited))
|
||||
return true;
|
||||
|
||||
m_pages_commited = m_pages_reserved;
|
||||
return HostSys::MmapCommitPtr(m_baseptr, m_pages_reserved * __pagesize, m_prot_mode);
|
||||
m_pages_commited = m_pages_reserved;
|
||||
return HostSys::MmapCommitPtr(m_baseptr, m_pages_reserved * __pagesize, m_prot_mode);
|
||||
}
|
||||
|
||||
void VirtualMemoryReserve::AllowModification()
|
||||
{
|
||||
m_allow_writes = true;
|
||||
HostSys::MemProtect(m_baseptr, m_pages_commited * __pagesize, m_prot_mode);
|
||||
m_allow_writes = true;
|
||||
HostSys::MemProtect(m_baseptr, m_pages_commited * __pagesize, m_prot_mode);
|
||||
}
|
||||
|
||||
void VirtualMemoryReserve::ForbidModification()
|
||||
{
|
||||
m_allow_writes = false;
|
||||
HostSys::MemProtect(m_baseptr, m_pages_commited * __pagesize, PageProtectionMode(m_prot_mode).Write(false));
|
||||
m_allow_writes = false;
|
||||
HostSys::MemProtect(m_baseptr, m_pages_commited * __pagesize, PageProtectionMode(m_prot_mode).Write(false));
|
||||
}
|
||||
|
||||
|
||||
|
@ -337,39 +360,43 @@ void VirtualMemoryReserve::ForbidModification()
|
|||
// newsize - new size of the reserved buffer, in bytes.
|
||||
bool VirtualMemoryReserve::TryResize(uint newsize)
|
||||
{
|
||||
uint newPages = pageAlign(newsize) / __pagesize;
|
||||
uint newPages = pageAlign(newsize) / __pagesize;
|
||||
|
||||
if (newPages > m_pages_reserved) {
|
||||
uint toReservePages = newPages - m_pages_reserved;
|
||||
uint toReserveBytes = toReservePages * __pagesize;
|
||||
if (newPages > m_pages_reserved)
|
||||
{
|
||||
uint toReservePages = newPages - m_pages_reserved;
|
||||
uint toReserveBytes = toReservePages * __pagesize;
|
||||
|
||||
DevCon.WriteLn(L"%-32s is being expanded by %u pages.", WX_STR(m_name), toReservePages);
|
||||
DevCon.WriteLn(L"%-32s is being expanded by %u pages.", WX_STR(m_name), toReservePages);
|
||||
|
||||
if (!m_allocator->AllocAtAddress(GetPtrEnd(), toReserveBytes)) {
|
||||
Console.Warning("%-32s could not be passively resized due to virtual memory conflict!", WX_STR(m_name));
|
||||
Console.Indent().Warning("(attempted to map memory @ %08p -> %08p)", m_baseptr, (uptr)m_baseptr + toReserveBytes);
|
||||
return false;
|
||||
}
|
||||
if (!m_allocator->AllocAtAddress(GetPtrEnd(), toReserveBytes))
|
||||
{
|
||||
Console.Warning("%-32s could not be passively resized due to virtual memory conflict!", WX_STR(m_name));
|
||||
Console.Indent().Warning("(attempted to map memory @ %08p -> %08p)", m_baseptr, (uptr)m_baseptr + toReserveBytes);
|
||||
return false;
|
||||
}
|
||||
|
||||
DevCon.WriteLn(Color_Gray, L"%-32s @ %08p -> %08p [%umb]", WX_STR(m_name),
|
||||
m_baseptr, (uptr)m_baseptr + toReserveBytes, toReserveBytes / _1mb);
|
||||
} else if (newPages < m_pages_reserved) {
|
||||
if (m_pages_commited > newsize)
|
||||
return false;
|
||||
DevCon.WriteLn(Color_Gray, L"%-32s @ %08p -> %08p [%umb]", WX_STR(m_name),
|
||||
m_baseptr, (uptr)m_baseptr + toReserveBytes, toReserveBytes / _1mb);
|
||||
}
|
||||
else if (newPages < m_pages_reserved)
|
||||
{
|
||||
if (m_pages_commited > newsize)
|
||||
return false;
|
||||
|
||||
uint toRemovePages = m_pages_reserved - newPages;
|
||||
uint toRemoveBytes = toRemovePages * __pagesize;
|
||||
uint toRemovePages = m_pages_reserved - newPages;
|
||||
uint toRemoveBytes = toRemovePages * __pagesize;
|
||||
|
||||
DevCon.WriteLn(L"%-32s is being shrunk by %u pages.", WX_STR(m_name), toRemovePages);
|
||||
DevCon.WriteLn(L"%-32s is being shrunk by %u pages.", WX_STR(m_name), toRemovePages);
|
||||
|
||||
m_allocator->Free(GetPtrEnd() - toRemoveBytes, toRemoveBytes);
|
||||
m_allocator->Free(GetPtrEnd() - toRemoveBytes, toRemoveBytes);
|
||||
|
||||
DevCon.WriteLn(Color_Gray, L"%-32s @ %08p -> %08p [%umb]", WX_STR(m_name),
|
||||
m_baseptr, GetPtrEnd(), GetReserveSizeInBytes() / _1mb);
|
||||
}
|
||||
DevCon.WriteLn(Color_Gray, L"%-32s @ %08p -> %08p [%umb]", WX_STR(m_name),
|
||||
m_baseptr, GetPtrEnd(), GetReserveSizeInBytes() / _1mb);
|
||||
}
|
||||
|
||||
m_pages_reserved = newPages;
|
||||
return true;
|
||||
m_pages_reserved = newPages;
|
||||
return true;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -377,27 +404,27 @@ bool VirtualMemoryReserve::TryResize(uint newsize)
|
|||
// --------------------------------------------------------------------------------------
|
||||
wxString PageProtectionMode::ToString() const
|
||||
{
|
||||
wxString modeStr;
|
||||
wxString modeStr;
|
||||
|
||||
if (m_read)
|
||||
modeStr += L"Read";
|
||||
if (m_write)
|
||||
modeStr += L"Write";
|
||||
if (m_exec)
|
||||
modeStr += L"Exec";
|
||||
if (m_read)
|
||||
modeStr += L"Read";
|
||||
if (m_write)
|
||||
modeStr += L"Write";
|
||||
if (m_exec)
|
||||
modeStr += L"Exec";
|
||||
|
||||
if (modeStr.IsEmpty())
|
||||
return L"NoAccess";
|
||||
if (modeStr.Length() <= 5)
|
||||
modeStr += L"Only";
|
||||
if (modeStr.IsEmpty())
|
||||
return L"NoAccess";
|
||||
if (modeStr.Length() <= 5)
|
||||
modeStr += L"Only";
|
||||
|
||||
return modeStr;
|
||||
return modeStr;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Common HostSys implementation
|
||||
// --------------------------------------------------------------------------------------
|
||||
void HostSys::Munmap(void *base, size_t size)
|
||||
void HostSys::Munmap(void* base, size_t size)
|
||||
{
|
||||
Munmap((uptr)base, size);
|
||||
Munmap((uptr)base, size);
|
||||
}
|
||||
|
|
|
@ -18,136 +18,146 @@
|
|||
#include "common/RedtapeWindows.h"
|
||||
#include "common/PageFaultSource.h"
|
||||
|
||||
static long DoSysPageFaultExceptionFilter(EXCEPTION_POINTERS *eps)
|
||||
static long DoSysPageFaultExceptionFilter(EXCEPTION_POINTERS* eps)
|
||||
{
|
||||
if (eps->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION)
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
if (eps->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION)
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
|
||||
// Note: This exception can be accessed by the EE or MTVU thread
|
||||
// Source_PageFault is a global variable with its own state information
|
||||
// so for now we lock this exception code unless someone can fix this better...
|
||||
Threading::ScopedLock lock(PageFault_Mutex);
|
||||
Source_PageFault->Dispatch(PageFaultInfo((uptr)eps->ExceptionRecord->ExceptionInformation[1]));
|
||||
return Source_PageFault->WasHandled() ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_CONTINUE_SEARCH;
|
||||
// Note: This exception can be accessed by the EE or MTVU thread
|
||||
// Source_PageFault is a global variable with its own state information
|
||||
// so for now we lock this exception code unless someone can fix this better...
|
||||
Threading::ScopedLock lock(PageFault_Mutex);
|
||||
Source_PageFault->Dispatch(PageFaultInfo((uptr)eps->ExceptionRecord->ExceptionInformation[1]));
|
||||
return Source_PageFault->WasHandled() ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
long __stdcall SysPageFaultExceptionFilter(EXCEPTION_POINTERS *eps)
|
||||
long __stdcall SysPageFaultExceptionFilter(EXCEPTION_POINTERS* eps)
|
||||
{
|
||||
// Prevent recursive exception filtering by catching the exception from the filter here.
|
||||
// In the event that the filter causes an access violation (happened during shutdown
|
||||
// because Source_PageFault was deallocated), this will allow the debugger to catch the
|
||||
// exception.
|
||||
// TODO: find a reliable way to debug the filter itself, I've come up with a few ways that
|
||||
// work but I don't fully understand why some do and some don't.
|
||||
__try {
|
||||
return DoSysPageFaultExceptionFilter(eps);
|
||||
} __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
// Prevent recursive exception filtering by catching the exception from the filter here.
|
||||
// In the event that the filter causes an access violation (happened during shutdown
|
||||
// because Source_PageFault was deallocated), this will allow the debugger to catch the
|
||||
// exception.
|
||||
// TODO: find a reliable way to debug the filter itself, I've come up with a few ways that
|
||||
// work but I don't fully understand why some do and some don't.
|
||||
__try
|
||||
{
|
||||
return DoSysPageFaultExceptionFilter(eps);
|
||||
}
|
||||
__except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
|
||||
{
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
}
|
||||
|
||||
void _platform_InstallSignalHandler()
|
||||
{
|
||||
#ifdef _WIN64 // We don't handle SEH properly on Win64 so use a vectored exception handler instead
|
||||
AddVectoredExceptionHandler(true, SysPageFaultExceptionFilter);
|
||||
AddVectoredExceptionHandler(true, SysPageFaultExceptionFilter);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static DWORD ConvertToWinApi(const PageProtectionMode &mode)
|
||||
static DWORD ConvertToWinApi(const PageProtectionMode& mode)
|
||||
{
|
||||
DWORD winmode = PAGE_NOACCESS;
|
||||
DWORD winmode = PAGE_NOACCESS;
|
||||
|
||||
// Windows has some really bizarre memory protection enumeration that uses bitwise
|
||||
// numbering (like flags) but is in fact not a flag value. *Someone* from the early
|
||||
// microsoft days wasn't a very good coder, me thinks. --air
|
||||
// Windows has some really bizarre memory protection enumeration that uses bitwise
|
||||
// numbering (like flags) but is in fact not a flag value. *Someone* from the early
|
||||
// microsoft days wasn't a very good coder, me thinks. --air
|
||||
|
||||
if (mode.CanExecute()) {
|
||||
winmode = mode.CanWrite() ? PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ;
|
||||
} else if (mode.CanRead()) {
|
||||
winmode = mode.CanWrite() ? PAGE_READWRITE : PAGE_READONLY;
|
||||
}
|
||||
if (mode.CanExecute())
|
||||
{
|
||||
winmode = mode.CanWrite() ? PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ;
|
||||
}
|
||||
else if (mode.CanRead())
|
||||
{
|
||||
winmode = mode.CanWrite() ? PAGE_READWRITE : PAGE_READONLY;
|
||||
}
|
||||
|
||||
return winmode;
|
||||
return winmode;
|
||||
}
|
||||
|
||||
void *HostSys::MmapReservePtr(void *base, size_t size)
|
||||
void* HostSys::MmapReservePtr(void* base, size_t size)
|
||||
{
|
||||
return VirtualAlloc(base, size, MEM_RESERVE, PAGE_NOACCESS);
|
||||
return VirtualAlloc(base, size, MEM_RESERVE, PAGE_NOACCESS);
|
||||
}
|
||||
|
||||
bool HostSys::MmapCommitPtr(void *base, size_t size, const PageProtectionMode &mode)
|
||||
bool HostSys::MmapCommitPtr(void* base, size_t size, const PageProtectionMode& mode)
|
||||
{
|
||||
void *result = VirtualAlloc(base, size, MEM_COMMIT, ConvertToWinApi(mode));
|
||||
if (result)
|
||||
return true;
|
||||
void* result = VirtualAlloc(base, size, MEM_COMMIT, ConvertToWinApi(mode));
|
||||
if (result)
|
||||
return true;
|
||||
|
||||
const DWORD errcode = GetLastError();
|
||||
if (errcode == ERROR_COMMITMENT_MINIMUM) {
|
||||
Console.Warning("(MmapCommit) Received windows error %u {Virtual Memory Minimum Too Low}.", ERROR_COMMITMENT_MINIMUM);
|
||||
Sleep(1000); // Cut windows some time to rework its memory...
|
||||
} else if (errcode != ERROR_NOT_ENOUGH_MEMORY && errcode != ERROR_OUTOFMEMORY) {
|
||||
pxFailDev(L"VirtualAlloc COMMIT failed: " + Exception::WinApiError().GetMsgFromWindows());
|
||||
return false;
|
||||
}
|
||||
const DWORD errcode = GetLastError();
|
||||
if (errcode == ERROR_COMMITMENT_MINIMUM)
|
||||
{
|
||||
Console.Warning("(MmapCommit) Received windows error %u {Virtual Memory Minimum Too Low}.", ERROR_COMMITMENT_MINIMUM);
|
||||
Sleep(1000); // Cut windows some time to rework its memory...
|
||||
}
|
||||
else if (errcode != ERROR_NOT_ENOUGH_MEMORY && errcode != ERROR_OUTOFMEMORY)
|
||||
{
|
||||
pxFailDev(L"VirtualAlloc COMMIT failed: " + Exception::WinApiError().GetMsgFromWindows());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!pxDoOutOfMemory)
|
||||
return false;
|
||||
pxDoOutOfMemory(size);
|
||||
return VirtualAlloc(base, size, MEM_COMMIT, ConvertToWinApi(mode)) != NULL;
|
||||
if (!pxDoOutOfMemory)
|
||||
return false;
|
||||
pxDoOutOfMemory(size);
|
||||
return VirtualAlloc(base, size, MEM_COMMIT, ConvertToWinApi(mode)) != NULL;
|
||||
}
|
||||
|
||||
void HostSys::MmapResetPtr(void *base, size_t size)
|
||||
void HostSys::MmapResetPtr(void* base, size_t size)
|
||||
{
|
||||
VirtualFree(base, size, MEM_DECOMMIT);
|
||||
VirtualFree(base, size, MEM_DECOMMIT);
|
||||
}
|
||||
|
||||
|
||||
void *HostSys::MmapReserve(uptr base, size_t size)
|
||||
void* HostSys::MmapReserve(uptr base, size_t size)
|
||||
{
|
||||
return MmapReservePtr((void *)base, size);
|
||||
return MmapReservePtr((void*)base, size);
|
||||
}
|
||||
|
||||
bool HostSys::MmapCommit(uptr base, size_t size, const PageProtectionMode &mode)
|
||||
bool HostSys::MmapCommit(uptr base, size_t size, const PageProtectionMode& mode)
|
||||
{
|
||||
return MmapCommitPtr((void *)base, size, mode);
|
||||
return MmapCommitPtr((void*)base, size, mode);
|
||||
}
|
||||
|
||||
void HostSys::MmapReset(uptr base, size_t size)
|
||||
{
|
||||
MmapResetPtr((void *)base, size);
|
||||
MmapResetPtr((void*)base, size);
|
||||
}
|
||||
|
||||
|
||||
void *HostSys::Mmap(uptr base, size_t size)
|
||||
void* HostSys::Mmap(uptr base, size_t size)
|
||||
{
|
||||
return VirtualAlloc((void *)base, size, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||
return VirtualAlloc((void*)base, size, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||
}
|
||||
|
||||
void HostSys::Munmap(uptr base, size_t size)
|
||||
{
|
||||
if (!base)
|
||||
return;
|
||||
//VirtualFree((void*)base, size, MEM_DECOMMIT);
|
||||
VirtualFree((void *)base, 0, MEM_RELEASE);
|
||||
if (!base)
|
||||
return;
|
||||
//VirtualFree((void*)base, size, MEM_DECOMMIT);
|
||||
VirtualFree((void*)base, 0, MEM_RELEASE);
|
||||
}
|
||||
|
||||
void HostSys::MemProtect(void *baseaddr, size_t size, const PageProtectionMode &mode)
|
||||
void HostSys::MemProtect(void* baseaddr, size_t size, const PageProtectionMode& mode)
|
||||
{
|
||||
pxAssertDev(((size & (__pagesize - 1)) == 0), pxsFmt(
|
||||
L"Memory block size must be a multiple of the target platform's page size.\n"
|
||||
L"\tPage Size: 0x%04x (%d), Block Size: 0x%04x (%d)",
|
||||
__pagesize, __pagesize, size, size));
|
||||
pxAssertDev(((size & (__pagesize - 1)) == 0), pxsFmt(
|
||||
L"Memory block size must be a multiple of the target platform's page size.\n"
|
||||
L"\tPage Size: 0x%04x (%d), Block Size: 0x%04x (%d)",
|
||||
__pagesize, __pagesize, size, size));
|
||||
|
||||
DWORD OldProtect; // enjoy my uselessness, yo!
|
||||
if (!VirtualProtect(baseaddr, size, ConvertToWinApi(mode), &OldProtect)) {
|
||||
Exception::WinApiError apiError;
|
||||
DWORD OldProtect; // enjoy my uselessness, yo!
|
||||
if (!VirtualProtect(baseaddr, size, ConvertToWinApi(mode), &OldProtect))
|
||||
{
|
||||
Exception::WinApiError apiError;
|
||||
|
||||
apiError.SetDiagMsg(
|
||||
pxsFmt(L"VirtualProtect failed @ 0x%08X -> 0x%08X (mode=%s)",
|
||||
baseaddr, (uptr)baseaddr + size, mode.ToString().c_str()));
|
||||
apiError.SetDiagMsg(
|
||||
pxsFmt(L"VirtualProtect failed @ 0x%08X -> 0x%08X (mode=%s)",
|
||||
baseaddr, (uptr)baseaddr + size, mode.ToString().c_str()));
|
||||
|
||||
pxFailDev(apiError.FormatDiagnosticMessage());
|
||||
}
|
||||
pxFailDev(apiError.FormatDiagnosticMessage());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -21,115 +21,118 @@
|
|||
|
||||
__fi void Threading::Sleep(int ms)
|
||||
{
|
||||
::Sleep(ms);
|
||||
::Sleep(ms);
|
||||
}
|
||||
|
||||
// For use in spin/wait loops, Acts as a hint to Intel CPUs and should, in theory
|
||||
// improve performance and reduce cpu power consumption.
|
||||
__fi void Threading::SpinWait()
|
||||
{
|
||||
_mm_pause();
|
||||
_mm_pause();
|
||||
}
|
||||
|
||||
__fi void Threading::EnableHiresScheduler()
|
||||
{
|
||||
// This improves accuracy of Sleep() by some amount, and only adds a negligible amount of
|
||||
// overhead on modern CPUs. Typically desktops are already set pretty low, but laptops in
|
||||
// particular may have a scheduler Period of 15 or 20ms to extend battery life.
|
||||
// This improves accuracy of Sleep() by some amount, and only adds a negligible amount of
|
||||
// overhead on modern CPUs. Typically desktops are already set pretty low, but laptops in
|
||||
// particular may have a scheduler Period of 15 or 20ms to extend battery life.
|
||||
|
||||
// (note: this same trick is used by most multimedia software and games)
|
||||
// (note: this same trick is used by most multimedia software and games)
|
||||
|
||||
timeBeginPeriod(1);
|
||||
timeBeginPeriod(1);
|
||||
}
|
||||
|
||||
__fi void Threading::DisableHiresScheduler()
|
||||
{
|
||||
timeEndPeriod(1);
|
||||
timeEndPeriod(1);
|
||||
}
|
||||
|
||||
// This hacky union would probably fail on some cpu platforms if the contents of FILETIME aren't
|
||||
// packed (but for any x86 CPU and microsoft compiler, they will be).
|
||||
union FileTimeSucks
|
||||
{
|
||||
FILETIME filetime;
|
||||
u64 u64time;
|
||||
FILETIME filetime;
|
||||
u64 u64time;
|
||||
};
|
||||
|
||||
u64 Threading::GetThreadCpuTime()
|
||||
{
|
||||
FileTimeSucks user, kernel;
|
||||
FILETIME dummy;
|
||||
GetThreadTimes(GetCurrentThread(), &dummy, &dummy, &kernel.filetime, &user.filetime);
|
||||
return user.u64time + kernel.u64time;
|
||||
FileTimeSucks user, kernel;
|
||||
FILETIME dummy;
|
||||
GetThreadTimes(GetCurrentThread(), &dummy, &dummy, &kernel.filetime, &user.filetime);
|
||||
return user.u64time + kernel.u64time;
|
||||
}
|
||||
|
||||
u64 Threading::GetThreadTicksPerSecond()
|
||||
{
|
||||
return 10000000;
|
||||
return 10000000;
|
||||
}
|
||||
|
||||
u64 Threading::pxThread::GetCpuTime() const
|
||||
{
|
||||
if (!m_native_handle)
|
||||
return 0;
|
||||
if (!m_native_handle)
|
||||
return 0;
|
||||
|
||||
FileTimeSucks user, kernel;
|
||||
FILETIME dummy;
|
||||
FileTimeSucks user, kernel;
|
||||
FILETIME dummy;
|
||||
|
||||
if (GetThreadTimes((HANDLE)m_native_handle, &dummy, &dummy, &kernel.filetime, &user.filetime))
|
||||
return user.u64time + kernel.u64time;
|
||||
if (GetThreadTimes((HANDLE)m_native_handle, &dummy, &dummy, &kernel.filetime, &user.filetime))
|
||||
return user.u64time + kernel.u64time;
|
||||
|
||||
return 0; // thread prolly doesn't exist anymore.
|
||||
return 0; // thread prolly doesn't exist anymore.
|
||||
}
|
||||
|
||||
void Threading::pxThread::_platform_specific_OnStartInThread()
|
||||
{
|
||||
// OpenThread Note: Vista and Win7 need only THREAD_QUERY_LIMITED_INFORMATION (XP and 2k need more),
|
||||
// however we own our process threads, so shouldn't matter in any case...
|
||||
// OpenThread Note: Vista and Win7 need only THREAD_QUERY_LIMITED_INFORMATION (XP and 2k need more),
|
||||
// however we own our process threads, so shouldn't matter in any case...
|
||||
|
||||
m_native_id = (uptr)GetCurrentThreadId();
|
||||
m_native_handle = (uptr)OpenThread(THREAD_QUERY_INFORMATION, false, (DWORD)m_native_id);
|
||||
m_native_id = (uptr)GetCurrentThreadId();
|
||||
m_native_handle = (uptr)OpenThread(THREAD_QUERY_INFORMATION, false, (DWORD)m_native_id);
|
||||
|
||||
pxAssertDev(m_native_handle, wxNullChar);
|
||||
pxAssertDev(m_native_handle, wxNullChar);
|
||||
}
|
||||
|
||||
void Threading::pxThread::_platform_specific_OnCleanupInThread()
|
||||
{
|
||||
CloseHandle((HANDLE)m_native_handle);
|
||||
CloseHandle((HANDLE)m_native_handle);
|
||||
}
|
||||
|
||||
void Threading::SetNameOfCurrentThread(const char *name)
|
||||
void Threading::SetNameOfCurrentThread(const char* name)
|
||||
{
|
||||
// This feature needs Windows headers and MSVC's SEH support:
|
||||
// This feature needs Windows headers and MSVC's SEH support:
|
||||
|
||||
#if defined(_WIN32) && defined(_MSC_VER)
|
||||
|
||||
// This code sample was borrowed form some obscure MSDN article.
|
||||
// In a rare bout of sanity, it's an actual Microsoft-published hack
|
||||
// that actually works!
|
||||
// This code sample was borrowed form some obscure MSDN article.
|
||||
// In a rare bout of sanity, it's an actual Microsoft-published hack
|
||||
// that actually works!
|
||||
|
||||
static const int MS_VC_EXCEPTION = 0x406D1388;
|
||||
static const int MS_VC_EXCEPTION = 0x406D1388;
|
||||
|
||||
#pragma pack(push, 8)
|
||||
struct THREADNAME_INFO
|
||||
{
|
||||
DWORD dwType; // Must be 0x1000.
|
||||
LPCSTR szName; // Pointer to name (in user addr space).
|
||||
DWORD dwThreadID; // Thread ID (-1=caller thread).
|
||||
DWORD dwFlags; // Reserved for future use, must be zero.
|
||||
};
|
||||
struct THREADNAME_INFO
|
||||
{
|
||||
DWORD dwType; // Must be 0x1000.
|
||||
LPCSTR szName; // Pointer to name (in user addr space).
|
||||
DWORD dwThreadID; // Thread ID (-1=caller thread).
|
||||
DWORD dwFlags; // Reserved for future use, must be zero.
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
THREADNAME_INFO info;
|
||||
info.dwType = 0x1000;
|
||||
info.szName = name;
|
||||
info.dwThreadID = GetCurrentThreadId();
|
||||
info.dwFlags = 0;
|
||||
THREADNAME_INFO info;
|
||||
info.dwType = 0x1000;
|
||||
info.szName = name;
|
||||
info.dwThreadID = GetCurrentThreadId();
|
||||
info.dwFlags = 0;
|
||||
|
||||
__try {
|
||||
RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR *)&info);
|
||||
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
||||
}
|
||||
__try
|
||||
{
|
||||
RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info);
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -21,10 +21,10 @@
|
|||
// FreeBSD/OsX need something far more complicated (apparently)
|
||||
void x86capabilities::CountLogicalCores()
|
||||
{
|
||||
// Note : GetCPUCount uses sysconf( _SC_NPROCESSORS_ONLN ) internally, which can return 1
|
||||
// if sysconf info isn't available (a long standing linux bug). There are no fallbacks or
|
||||
// alternatives, apparently.
|
||||
LogicalCores = wxThread::GetCPUCount();
|
||||
// Note : GetCPUCount uses sysconf( _SC_NPROCESSORS_ONLN ) internally, which can return 1
|
||||
// if sysconf info isn't available (a long standing linux bug). There are no fallbacks or
|
||||
// alternatives, apparently.
|
||||
LogicalCores = wxThread::GetCPUCount();
|
||||
}
|
||||
|
||||
// Not implemented yet for linux (see cpudetect_internal.h for details)
|
||||
|
|
|
@ -20,65 +20,66 @@
|
|||
|
||||
void x86capabilities::CountLogicalCores()
|
||||
{
|
||||
DWORD_PTR vProcessCPUs;
|
||||
DWORD_PTR vSystemCPUs;
|
||||
DWORD_PTR vProcessCPUs;
|
||||
DWORD_PTR vSystemCPUs;
|
||||
|
||||
LogicalCores = 1;
|
||||
LogicalCores = 1;
|
||||
|
||||
if (!GetProcessAffinityMask(GetCurrentProcess(), &vProcessCPUs, &vSystemCPUs))
|
||||
return;
|
||||
if (!GetProcessAffinityMask(GetCurrentProcess(), &vProcessCPUs, &vSystemCPUs))
|
||||
return;
|
||||
|
||||
uint CPUs = 0;
|
||||
for (DWORD_PTR bit = 1; bit != 0; bit <<= 1)
|
||||
if (vSystemCPUs & bit)
|
||||
CPUs++;
|
||||
uint CPUs = 0;
|
||||
for (DWORD_PTR bit = 1; bit != 0; bit <<= 1)
|
||||
if (vSystemCPUs & bit)
|
||||
CPUs++;
|
||||
|
||||
LogicalCores = CPUs;
|
||||
LogicalCores = CPUs;
|
||||
}
|
||||
|
||||
SingleCoreAffinity::SingleCoreAffinity()
|
||||
{
|
||||
s_threadId = nullptr;
|
||||
s_oldmask = ERROR_INVALID_PARAMETER;
|
||||
s_threadId = nullptr;
|
||||
s_oldmask = ERROR_INVALID_PARAMETER;
|
||||
|
||||
DWORD_PTR availProcCpus;
|
||||
DWORD_PTR availSysCpus;
|
||||
if (!GetProcessAffinityMask(GetCurrentProcess(), &availProcCpus, &availSysCpus))
|
||||
return;
|
||||
DWORD_PTR availProcCpus;
|
||||
DWORD_PTR availSysCpus;
|
||||
if (!GetProcessAffinityMask(GetCurrentProcess(), &availProcCpus, &availSysCpus))
|
||||
return;
|
||||
|
||||
int cpu = 0;
|
||||
DWORD_PTR affinityMask;
|
||||
for (affinityMask = 1; affinityMask != 0; affinityMask <<= 1, ++cpu)
|
||||
if (availProcCpus & affinityMask)
|
||||
break;
|
||||
int cpu = 0;
|
||||
DWORD_PTR affinityMask;
|
||||
for (affinityMask = 1; affinityMask != 0; affinityMask <<= 1, ++cpu)
|
||||
if (availProcCpus & affinityMask)
|
||||
break;
|
||||
|
||||
s_threadId = GetCurrentThread();
|
||||
s_oldmask = SetThreadAffinityMask(s_threadId, affinityMask);
|
||||
s_threadId = GetCurrentThread();
|
||||
s_oldmask = SetThreadAffinityMask(s_threadId, affinityMask);
|
||||
|
||||
if (s_oldmask == ERROR_INVALID_PARAMETER) {
|
||||
const int hexWidth = 2 * sizeof(DWORD_PTR);
|
||||
Console.Warning(
|
||||
"CpuDetect: SetThreadAffinityMask failed...\n"
|
||||
"\tSystem Affinity : 0x%0*x\n"
|
||||
"\tProcess Affinity: 0x%0*x\n"
|
||||
"\tAttempted Thread Affinity CPU: %i",
|
||||
hexWidth, availProcCpus, hexWidth, availSysCpus, cpu);
|
||||
}
|
||||
if (s_oldmask == ERROR_INVALID_PARAMETER)
|
||||
{
|
||||
const int hexWidth = 2 * sizeof(DWORD_PTR);
|
||||
Console.Warning(
|
||||
"CpuDetect: SetThreadAffinityMask failed...\n"
|
||||
"\tSystem Affinity : 0x%0*x\n"
|
||||
"\tProcess Affinity: 0x%0*x\n"
|
||||
"\tAttempted Thread Affinity CPU: %i",
|
||||
hexWidth, availProcCpus, hexWidth, availSysCpus, cpu);
|
||||
}
|
||||
|
||||
Sleep(2);
|
||||
Sleep(2);
|
||||
|
||||
// Sleep Explained: I arbitrarily pick Core 0 to lock to for running the CPU test. This
|
||||
// means that the current thread will need to be switched to Core 0 if it's currently
|
||||
// scheduled on a difference cpu/core. However, Windows does not necessarily perform
|
||||
// that scheduling immediately upon the call to SetThreadAffinityMask (seems dependent
|
||||
// on version: XP does, Win7 does not). So by issuing a Sleep here we give Win7 time
|
||||
// to issue a timeslice and move our thread to Core 0. Without this, it tends to move
|
||||
// the thread during the cpuSpeed test instead, causing totally wacky results.
|
||||
// Sleep Explained: I arbitrarily pick Core 0 to lock to for running the CPU test. This
|
||||
// means that the current thread will need to be switched to Core 0 if it's currently
|
||||
// scheduled on a difference cpu/core. However, Windows does not necessarily perform
|
||||
// that scheduling immediately upon the call to SetThreadAffinityMask (seems dependent
|
||||
// on version: XP does, Win7 does not). So by issuing a Sleep here we give Win7 time
|
||||
// to issue a timeslice and move our thread to Core 0. Without this, it tends to move
|
||||
// the thread during the cpuSpeed test instead, causing totally wacky results.
|
||||
};
|
||||
|
||||
SingleCoreAffinity::~SingleCoreAffinity()
|
||||
{
|
||||
if (s_oldmask != ERROR_INVALID_PARAMETER)
|
||||
SetThreadAffinityMask(s_threadId, s_oldmask);
|
||||
if (s_oldmask != ERROR_INVALID_PARAMETER)
|
||||
SetThreadAffinityMask(s_threadId, s_oldmask);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -19,17 +19,17 @@
|
|||
namespace x86Emitter
|
||||
{
|
||||
|
||||
const xImplBMI_RVM xMULX = {0xF2, 0x38, 0xF6};
|
||||
const xImplBMI_RVM xPDEP = {0xF2, 0x38, 0xF5};
|
||||
const xImplBMI_RVM xPEXT = {0xF3, 0x38, 0xF5};
|
||||
const xImplBMI_RVM xANDN_S = {0x00, 0x38, 0xF2};
|
||||
const xImplBMI_RVM xMULX = {0xF2, 0x38, 0xF6};
|
||||
const xImplBMI_RVM xPDEP = {0xF2, 0x38, 0xF5};
|
||||
const xImplBMI_RVM xPEXT = {0xF3, 0x38, 0xF5};
|
||||
const xImplBMI_RVM xANDN_S = {0x00, 0x38, 0xF2};
|
||||
|
||||
void xImplBMI_RVM::operator()(const xRegisterInt &to, const xRegisterInt &from1, const xRegisterInt &from2) const
|
||||
{
|
||||
xOpWriteC4(Prefix, MbPrefix, Opcode, to, from1, from2);
|
||||
}
|
||||
void xImplBMI_RVM::operator()(const xRegisterInt &to, const xRegisterInt &from1, const xIndirectVoid &from2) const
|
||||
{
|
||||
xOpWriteC4(Prefix, MbPrefix, Opcode, to, from1, from2);
|
||||
}
|
||||
}
|
||||
void xImplBMI_RVM::operator()(const xRegisterInt& to, const xRegisterInt& from1, const xRegisterInt& from2) const
|
||||
{
|
||||
xOpWriteC4(Prefix, MbPrefix, Opcode, to, from1, from2);
|
||||
}
|
||||
void xImplBMI_RVM::operator()(const xRegisterInt& to, const xRegisterInt& from1, const xIndirectVoid& from2) const
|
||||
{
|
||||
xOpWriteC4(Prefix, MbPrefix, Opcode, to, from1, from2);
|
||||
}
|
||||
} // namespace x86Emitter
|
||||
|
|
|
@ -31,12 +31,12 @@
|
|||
|
||||
static __inline__ __attribute__((always_inline)) void cpuidex(int CPUInfo[], const int InfoType, const int count)
|
||||
{
|
||||
__cpuid_count(InfoType, count, CPUInfo[0], CPUInfo[1], CPUInfo[2], CPUInfo[3]);
|
||||
__cpuid_count(InfoType, count, CPUInfo[0], CPUInfo[1], CPUInfo[2], CPUInfo[3]);
|
||||
}
|
||||
|
||||
static __inline__ __attribute__((always_inline)) void cpuid(int CPUInfo[], const int InfoType)
|
||||
{
|
||||
__cpuid(InfoType, CPUInfo[0], CPUInfo[1], CPUInfo[2], CPUInfo[3]);
|
||||
__cpuid(InfoType, CPUInfo[0], CPUInfo[1], CPUInfo[2], CPUInfo[3]);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -46,23 +46,23 @@ using namespace x86Emitter;
|
|||
__aligned16 x86capabilities x86caps;
|
||||
|
||||
x86capabilities::x86capabilities()
|
||||
: isIdentified(false)
|
||||
, VendorID(x86Vendor_Unknown)
|
||||
, FamilyID(0)
|
||||
, Model(0)
|
||||
, TypeID(0)
|
||||
, StepID(0)
|
||||
, Flags(0)
|
||||
, Flags2(0)
|
||||
, EFlags(0)
|
||||
, EFlags2(0)
|
||||
, SEFlag(0)
|
||||
, AllCapabilities(0)
|
||||
, PhysicalCores(0)
|
||||
, LogicalCores(0)
|
||||
: isIdentified(false)
|
||||
, VendorID(x86Vendor_Unknown)
|
||||
, FamilyID(0)
|
||||
, Model(0)
|
||||
, TypeID(0)
|
||||
, StepID(0)
|
||||
, Flags(0)
|
||||
, Flags2(0)
|
||||
, EFlags(0)
|
||||
, EFlags2(0)
|
||||
, SEFlag(0)
|
||||
, AllCapabilities(0)
|
||||
, PhysicalCores(0)
|
||||
, LogicalCores(0)
|
||||
{
|
||||
memzero(VendorName);
|
||||
memzero(FamilyName);
|
||||
memzero(VendorName);
|
||||
memzero(FamilyName);
|
||||
}
|
||||
|
||||
// Warning! We've had problems with the MXCSR detection code causing stack corruption in
|
||||
|
@ -72,28 +72,29 @@ x86capabilities::x86capabilities()
|
|||
// Note: recSSE was deleted
|
||||
void x86capabilities::SIMD_EstablishMXCSRmask()
|
||||
{
|
||||
if (!hasStreamingSIMDExtensions)
|
||||
return;
|
||||
if (!hasStreamingSIMDExtensions)
|
||||
return;
|
||||
|
||||
MXCSR_Mask.bitmask = 0xFFBF; // MMX/SSE default
|
||||
MXCSR_Mask.bitmask = 0xFFBF; // MMX/SSE default
|
||||
|
||||
if (hasStreamingSIMD2Extensions) {
|
||||
// This is generally safe assumption, but FXSAVE is the "correct" way to
|
||||
// detect MXCSR masking features of the cpu, so we use it's result below
|
||||
// and override this.
|
||||
if (hasStreamingSIMD2Extensions)
|
||||
{
|
||||
// This is generally safe assumption, but FXSAVE is the "correct" way to
|
||||
// detect MXCSR masking features of the cpu, so we use it's result below
|
||||
// and override this.
|
||||
|
||||
MXCSR_Mask.bitmask = 0xFFFF; // SSE2 features added
|
||||
}
|
||||
MXCSR_Mask.bitmask = 0xFFFF; // SSE2 features added
|
||||
}
|
||||
|
||||
__aligned16 u8 targetFXSAVE[512];
|
||||
__aligned16 u8 targetFXSAVE[512];
|
||||
|
||||
// Work for recent enough GCC/CLANG/MSVC 2012
|
||||
_fxsave(&targetFXSAVE);
|
||||
// Work for recent enough GCC/CLANG/MSVC 2012
|
||||
_fxsave(&targetFXSAVE);
|
||||
|
||||
u32 result;
|
||||
memcpy(&result, &targetFXSAVE[28], 4); // bytes 28->32 are the MXCSR_Mask.
|
||||
if (result != 0)
|
||||
MXCSR_Mask.bitmask = result;
|
||||
u32 result;
|
||||
memcpy(&result, &targetFXSAVE[28], 4); // bytes 28->32 are the MXCSR_Mask.
|
||||
if (result != 0)
|
||||
MXCSR_Mask.bitmask = result;
|
||||
}
|
||||
|
||||
// Counts the number of cpu cycles executed over the requested number of PerformanceCounter
|
||||
|
@ -103,221 +104,229 @@ void x86capabilities::SIMD_EstablishMXCSRmask()
|
|||
// by the operating system task switches.
|
||||
s64 x86capabilities::_CPUSpeedHz(u64 time) const
|
||||
{
|
||||
u64 timeStart, timeStop;
|
||||
s64 startCycle, endCycle;
|
||||
u64 timeStart, timeStop;
|
||||
s64 startCycle, endCycle;
|
||||
|
||||
if (!hasTimeStampCounter)
|
||||
return 0;
|
||||
if (!hasTimeStampCounter)
|
||||
return 0;
|
||||
|
||||
SingleCoreAffinity affinity_lock;
|
||||
SingleCoreAffinity affinity_lock;
|
||||
|
||||
// Align the cpu execution to a cpuTick boundary.
|
||||
// Align the cpu execution to a cpuTick boundary.
|
||||
|
||||
do {
|
||||
timeStart = GetCPUTicks();
|
||||
startCycle = __rdtsc();
|
||||
} while (GetCPUTicks() == timeStart);
|
||||
do
|
||||
{
|
||||
timeStart = GetCPUTicks();
|
||||
startCycle = __rdtsc();
|
||||
} while (GetCPUTicks() == timeStart);
|
||||
|
||||
do {
|
||||
timeStop = GetCPUTicks();
|
||||
endCycle = __rdtsc();
|
||||
} while ((timeStop - timeStart) < time);
|
||||
do
|
||||
{
|
||||
timeStop = GetCPUTicks();
|
||||
endCycle = __rdtsc();
|
||||
} while ((timeStop - timeStart) < time);
|
||||
|
||||
s64 cycleCount = endCycle - startCycle;
|
||||
s64 timeCount = timeStop - timeStart;
|
||||
s64 overrun = timeCount - time;
|
||||
if (!overrun)
|
||||
return cycleCount;
|
||||
s64 cycleCount = endCycle - startCycle;
|
||||
s64 timeCount = timeStop - timeStart;
|
||||
s64 overrun = timeCount - time;
|
||||
if (!overrun)
|
||||
return cycleCount;
|
||||
|
||||
// interference could cause us to overshoot the target time, compensate:
|
||||
// interference could cause us to overshoot the target time, compensate:
|
||||
|
||||
double cyclesPerTick = (double)cycleCount / (double)timeCount;
|
||||
double newCycleCount = (double)cycleCount - (cyclesPerTick * overrun);
|
||||
double cyclesPerTick = (double)cycleCount / (double)timeCount;
|
||||
double newCycleCount = (double)cycleCount - (cyclesPerTick * overrun);
|
||||
|
||||
return (s64)newCycleCount;
|
||||
return (s64)newCycleCount;
|
||||
}
|
||||
|
||||
wxString x86capabilities::GetTypeName() const
|
||||
{
|
||||
switch (TypeID) {
|
||||
case 0:
|
||||
return L"Standard OEM";
|
||||
case 1:
|
||||
return L"Overdrive";
|
||||
case 2:
|
||||
return L"Dual";
|
||||
case 3:
|
||||
return L"Reserved";
|
||||
default:
|
||||
return L"Unknown";
|
||||
}
|
||||
switch (TypeID)
|
||||
{
|
||||
case 0:
|
||||
return L"Standard OEM";
|
||||
case 1:
|
||||
return L"Overdrive";
|
||||
case 2:
|
||||
return L"Dual";
|
||||
case 3:
|
||||
return L"Reserved";
|
||||
default:
|
||||
return L"Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
void x86capabilities::CountCores()
|
||||
{
|
||||
Identify();
|
||||
Identify();
|
||||
|
||||
s32 regs[4];
|
||||
u32 cmds;
|
||||
s32 regs[4];
|
||||
u32 cmds;
|
||||
|
||||
cpuid(regs, 0x80000000);
|
||||
cmds = regs[0];
|
||||
cpuid(regs, 0x80000000);
|
||||
cmds = regs[0];
|
||||
|
||||
// detect multicore for AMD cpu
|
||||
// detect multicore for AMD cpu
|
||||
|
||||
if ((cmds >= 0x80000008) && (VendorID == x86Vendor_AMD)) {
|
||||
// AMD note: they don't support hyperthreading, but they like to flag this true
|
||||
// anyway. Let's force-unflag it until we come up with a better solution.
|
||||
// (note: seems to affect some Phenom II's only? -- Athlon X2's and PhenomI's do
|
||||
// not seem to do this) --air
|
||||
hasMultiThreading = 0;
|
||||
}
|
||||
if ((cmds >= 0x80000008) && (VendorID == x86Vendor_AMD))
|
||||
{
|
||||
// AMD note: they don't support hyperthreading, but they like to flag this true
|
||||
// anyway. Let's force-unflag it until we come up with a better solution.
|
||||
// (note: seems to affect some Phenom II's only? -- Athlon X2's and PhenomI's do
|
||||
// not seem to do this) --air
|
||||
hasMultiThreading = 0;
|
||||
}
|
||||
|
||||
// This will assign values into LogicalCores and PhysicalCores
|
||||
CountLogicalCores();
|
||||
// This will assign values into LogicalCores and PhysicalCores
|
||||
CountLogicalCores();
|
||||
}
|
||||
|
||||
static const char *tbl_x86vendors[] =
|
||||
{
|
||||
"GenuineIntel",
|
||||
"AuthenticAMD",
|
||||
"Unknown ",
|
||||
static const char* tbl_x86vendors[] =
|
||||
{
|
||||
"GenuineIntel",
|
||||
"AuthenticAMD",
|
||||
"Unknown ",
|
||||
};
|
||||
|
||||
// Performs all _cpuid-related activity. This fills *most* of the x86caps structure, except for
|
||||
// the cpuSpeed and the mxcsr masks. Those must be completed manually.
|
||||
void x86capabilities::Identify()
|
||||
{
|
||||
if (isIdentified)
|
||||
return;
|
||||
isIdentified = true;
|
||||
if (isIdentified)
|
||||
return;
|
||||
isIdentified = true;
|
||||
|
||||
s32 regs[4];
|
||||
u32 cmds;
|
||||
s32 regs[4];
|
||||
u32 cmds;
|
||||
|
||||
memzero(VendorName);
|
||||
cpuid(regs, 0);
|
||||
memzero(VendorName);
|
||||
cpuid(regs, 0);
|
||||
|
||||
cmds = regs[0];
|
||||
memcpy(&VendorName[0], ®s[1], 4);
|
||||
memcpy(&VendorName[4], ®s[3], 4);
|
||||
memcpy(&VendorName[8], ®s[2], 4);
|
||||
cmds = regs[0];
|
||||
memcpy(&VendorName[0], ®s[1], 4);
|
||||
memcpy(&VendorName[4], ®s[3], 4);
|
||||
memcpy(&VendorName[8], ®s[2], 4);
|
||||
|
||||
// Determine Vendor Specifics!
|
||||
// It's really not recommended that we base much (if anything) on CPU vendor names,
|
||||
// however it's currently necessary in order to gain a (pseudo)reliable count of cores
|
||||
// and threads used by the CPU (AMD and Intel can't agree on how to make this info available).
|
||||
// Determine Vendor Specifics!
|
||||
// It's really not recommended that we base much (if anything) on CPU vendor names,
|
||||
// however it's currently necessary in order to gain a (pseudo)reliable count of cores
|
||||
// and threads used by the CPU (AMD and Intel can't agree on how to make this info available).
|
||||
|
||||
int vid;
|
||||
for (vid = 0; vid < x86Vendor_Unknown; ++vid) {
|
||||
if (memcmp(VendorName, tbl_x86vendors[vid], 12) == 0)
|
||||
break;
|
||||
}
|
||||
VendorID = static_cast<x86VendorType>(vid);
|
||||
int vid;
|
||||
for (vid = 0; vid < x86Vendor_Unknown; ++vid)
|
||||
{
|
||||
if (memcmp(VendorName, tbl_x86vendors[vid], 12) == 0)
|
||||
break;
|
||||
}
|
||||
VendorID = static_cast<x86VendorType>(vid);
|
||||
|
||||
if (cmds >= 0x00000001) {
|
||||
cpuid(regs, 0x00000001);
|
||||
if (cmds >= 0x00000001)
|
||||
{
|
||||
cpuid(regs, 0x00000001);
|
||||
|
||||
StepID = regs[0] & 0xf;
|
||||
Model = (regs[0] >> 4) & 0xf;
|
||||
FamilyID = (regs[0] >> 8) & 0xf;
|
||||
TypeID = (regs[0] >> 12) & 0x3;
|
||||
StepID = regs[0] & 0xf;
|
||||
Model = (regs[0] >> 4) & 0xf;
|
||||
FamilyID = (regs[0] >> 8) & 0xf;
|
||||
TypeID = (regs[0] >> 12) & 0x3;
|
||||
#ifdef __M_X86_64
|
||||
//u32 x86_64_8BITBRANDID = regs[1] & 0xff;
|
||||
//u32 x86_64_8BITBRANDID = regs[1] & 0xff;
|
||||
#endif
|
||||
Flags = regs[3];
|
||||
Flags2 = regs[2];
|
||||
}
|
||||
Flags = regs[3];
|
||||
Flags2 = regs[2];
|
||||
}
|
||||
|
||||
if (cmds >= 0x00000007) {
|
||||
// Note: ECX must be 0 for AVX2 detection.
|
||||
cpuidex(regs, 0x00000007, 0);
|
||||
if (cmds >= 0x00000007)
|
||||
{
|
||||
// Note: ECX must be 0 for AVX2 detection.
|
||||
cpuidex(regs, 0x00000007, 0);
|
||||
|
||||
SEFlag = regs[1];
|
||||
}
|
||||
SEFlag = regs[1];
|
||||
}
|
||||
|
||||
cpuid(regs, 0x80000000);
|
||||
cmds = regs[0];
|
||||
if (cmds >= 0x80000001) {
|
||||
cpuid(regs, 0x80000001);
|
||||
cpuid(regs, 0x80000000);
|
||||
cmds = regs[0];
|
||||
if (cmds >= 0x80000001)
|
||||
{
|
||||
cpuid(regs, 0x80000001);
|
||||
|
||||
#ifdef __M_X86_64
|
||||
//u32 x86_64_12BITBRANDID = regs[1] & 0xfff;
|
||||
//u32 x86_64_12BITBRANDID = regs[1] & 0xfff;
|
||||
#endif
|
||||
EFlags2 = regs[2];
|
||||
EFlags = regs[3];
|
||||
}
|
||||
EFlags2 = regs[2];
|
||||
EFlags = regs[3];
|
||||
}
|
||||
|
||||
memzero(FamilyName);
|
||||
cpuid((int *)FamilyName, 0x80000002);
|
||||
cpuid((int *)(FamilyName + 16), 0x80000003);
|
||||
cpuid((int *)(FamilyName + 32), 0x80000004);
|
||||
memzero(FamilyName);
|
||||
cpuid((int*)FamilyName, 0x80000002);
|
||||
cpuid((int*)(FamilyName + 16), 0x80000003);
|
||||
cpuid((int*)(FamilyName + 32), 0x80000004);
|
||||
|
||||
hasFloatingPointUnit = (Flags >> 0) & 1;
|
||||
hasVirtual8086ModeEnhancements = (Flags >> 1) & 1;
|
||||
hasDebuggingExtensions = (Flags >> 2) & 1;
|
||||
hasPageSizeExtensions = (Flags >> 3) & 1;
|
||||
hasTimeStampCounter = (Flags >> 4) & 1;
|
||||
hasModelSpecificRegisters = (Flags >> 5) & 1;
|
||||
hasPhysicalAddressExtension = (Flags >> 6) & 1;
|
||||
hasMachineCheckArchitecture = (Flags >> 7) & 1;
|
||||
hasCOMPXCHG8BInstruction = (Flags >> 8) & 1;
|
||||
hasAdvancedProgrammableInterruptController = (Flags >> 9) & 1;
|
||||
hasSEPFastSystemCall = (Flags >> 11) & 1;
|
||||
hasMemoryTypeRangeRegisters = (Flags >> 12) & 1;
|
||||
hasPTEGlobalFlag = (Flags >> 13) & 1;
|
||||
hasMachineCheckArchitecture = (Flags >> 14) & 1;
|
||||
hasConditionalMoveAndCompareInstructions = (Flags >> 15) & 1;
|
||||
hasFGPageAttributeTable = (Flags >> 16) & 1;
|
||||
has36bitPageSizeExtension = (Flags >> 17) & 1;
|
||||
hasProcessorSerialNumber = (Flags >> 18) & 1;
|
||||
hasCFLUSHInstruction = (Flags >> 19) & 1;
|
||||
hasDebugStore = (Flags >> 21) & 1;
|
||||
hasACPIThermalMonitorAndClockControl = (Flags >> 22) & 1;
|
||||
hasFastStreamingSIMDExtensionsSaveRestore = (Flags >> 24) & 1;
|
||||
hasStreamingSIMDExtensions = (Flags >> 25) & 1; //sse
|
||||
hasStreamingSIMD2Extensions = (Flags >> 26) & 1; //sse2
|
||||
hasSelfSnoop = (Flags >> 27) & 1;
|
||||
hasMultiThreading = (Flags >> 28) & 1;
|
||||
hasThermalMonitor = (Flags >> 29) & 1;
|
||||
hasIntel64BitArchitecture = (Flags >> 30) & 1;
|
||||
hasFloatingPointUnit = (Flags >> 0) & 1;
|
||||
hasVirtual8086ModeEnhancements = (Flags >> 1) & 1;
|
||||
hasDebuggingExtensions = (Flags >> 2) & 1;
|
||||
hasPageSizeExtensions = (Flags >> 3) & 1;
|
||||
hasTimeStampCounter = (Flags >> 4) & 1;
|
||||
hasModelSpecificRegisters = (Flags >> 5) & 1;
|
||||
hasPhysicalAddressExtension = (Flags >> 6) & 1;
|
||||
hasMachineCheckArchitecture = (Flags >> 7) & 1;
|
||||
hasCOMPXCHG8BInstruction = (Flags >> 8) & 1;
|
||||
hasAdvancedProgrammableInterruptController = (Flags >> 9) & 1;
|
||||
hasSEPFastSystemCall = (Flags >> 11) & 1;
|
||||
hasMemoryTypeRangeRegisters = (Flags >> 12) & 1;
|
||||
hasPTEGlobalFlag = (Flags >> 13) & 1;
|
||||
hasMachineCheckArchitecture = (Flags >> 14) & 1;
|
||||
hasConditionalMoveAndCompareInstructions = (Flags >> 15) & 1;
|
||||
hasFGPageAttributeTable = (Flags >> 16) & 1;
|
||||
has36bitPageSizeExtension = (Flags >> 17) & 1;
|
||||
hasProcessorSerialNumber = (Flags >> 18) & 1;
|
||||
hasCFLUSHInstruction = (Flags >> 19) & 1;
|
||||
hasDebugStore = (Flags >> 21) & 1;
|
||||
hasACPIThermalMonitorAndClockControl = (Flags >> 22) & 1;
|
||||
hasFastStreamingSIMDExtensionsSaveRestore = (Flags >> 24) & 1;
|
||||
hasStreamingSIMDExtensions = (Flags >> 25) & 1; //sse
|
||||
hasStreamingSIMD2Extensions = (Flags >> 26) & 1; //sse2
|
||||
hasSelfSnoop = (Flags >> 27) & 1;
|
||||
hasMultiThreading = (Flags >> 28) & 1;
|
||||
hasThermalMonitor = (Flags >> 29) & 1;
|
||||
hasIntel64BitArchitecture = (Flags >> 30) & 1;
|
||||
|
||||
// -------------------------------------------------
|
||||
// --> SSE3 / SSSE3 / SSE4.1 / SSE 4.2 detection <--
|
||||
// -------------------------------------------------
|
||||
// -------------------------------------------------
|
||||
// --> SSE3 / SSSE3 / SSE4.1 / SSE 4.2 detection <--
|
||||
// -------------------------------------------------
|
||||
|
||||
hasStreamingSIMD3Extensions = (Flags2 >> 0) & 1; //sse3
|
||||
hasSupplementalStreamingSIMD3Extensions = (Flags2 >> 9) & 1; //ssse3
|
||||
hasStreamingSIMD4Extensions = (Flags2 >> 19) & 1; //sse4.1
|
||||
hasStreamingSIMD4Extensions2 = (Flags2 >> 20) & 1; //sse4.2
|
||||
hasStreamingSIMD3Extensions = (Flags2 >> 0) & 1; //sse3
|
||||
hasSupplementalStreamingSIMD3Extensions = (Flags2 >> 9) & 1; //ssse3
|
||||
hasStreamingSIMD4Extensions = (Flags2 >> 19) & 1; //sse4.1
|
||||
hasStreamingSIMD4Extensions2 = (Flags2 >> 20) & 1; //sse4.2
|
||||
|
||||
if ((Flags2 >> 27) & 1) // OSXSAVE
|
||||
{
|
||||
// Note: In theory, we should use xgetbv to check OS support
|
||||
// but all OSes we officially run under support it
|
||||
// and its intrinsic requires extra compiler flags
|
||||
hasAVX = (Flags2 >> 28) & 1; //avx
|
||||
hasFMA = (Flags2 >> 12) & 1; //fma
|
||||
hasAVX2 = (SEFlag >> 5) & 1; //avx2
|
||||
}
|
||||
if ((Flags2 >> 27) & 1) // OSXSAVE
|
||||
{
|
||||
// Note: In theory, we should use xgetbv to check OS support
|
||||
// but all OSes we officially run under support it
|
||||
// and its intrinsic requires extra compiler flags
|
||||
hasAVX = (Flags2 >> 28) & 1; //avx
|
||||
hasFMA = (Flags2 >> 12) & 1; //fma
|
||||
hasAVX2 = (SEFlag >> 5) & 1; //avx2
|
||||
}
|
||||
|
||||
hasBMI1 = (SEFlag >> 3) & 1;
|
||||
hasBMI2 = (SEFlag >> 8) & 1;
|
||||
hasBMI1 = (SEFlag >> 3) & 1;
|
||||
hasBMI2 = (SEFlag >> 8) & 1;
|
||||
|
||||
// Ones only for AMDs:
|
||||
hasAMD64BitArchitecture = (EFlags >> 29) & 1; //64bit cpu
|
||||
hasStreamingSIMD4ExtensionsA = (EFlags2 >> 6) & 1; //INSERTQ / EXTRQ / MOVNT
|
||||
// Ones only for AMDs:
|
||||
hasAMD64BitArchitecture = (EFlags >> 29) & 1; //64bit cpu
|
||||
hasStreamingSIMD4ExtensionsA = (EFlags2 >> 6) & 1; //INSERTQ / EXTRQ / MOVNT
|
||||
|
||||
isIdentified = true;
|
||||
isIdentified = true;
|
||||
}
|
||||
|
||||
u32 x86capabilities::CalculateMHz() const
|
||||
{
|
||||
InitCPUTicks();
|
||||
u64 span = GetTickFrequency();
|
||||
InitCPUTicks();
|
||||
u64 span = GetTickFrequency();
|
||||
|
||||
if ((span % 1000) < 400) // helps minimize rounding errors
|
||||
return (u32)(_CPUSpeedHz(span / 1000) / 1000);
|
||||
else
|
||||
return (u32)(_CPUSpeedHz(span / 500) / 2000);
|
||||
if ((span % 1000) < 400) // helps minimize rounding errors
|
||||
return (u32)(_CPUSpeedHz(span / 1000) / 1000);
|
||||
else
|
||||
return (u32)(_CPUSpeedHz(span / 500) / 2000);
|
||||
}
|
||||
|
|
|
@ -28,11 +28,11 @@ class SingleCoreAffinity
|
|||
{
|
||||
protected:
|
||||
#ifdef _WIN32
|
||||
HANDLE s_threadId;
|
||||
DWORD_PTR s_oldmask;
|
||||
HANDLE s_threadId;
|
||||
DWORD_PTR s_oldmask;
|
||||
#endif
|
||||
|
||||
public:
|
||||
SingleCoreAffinity();
|
||||
virtual ~SingleCoreAffinity();
|
||||
SingleCoreAffinity();
|
||||
virtual ~SingleCoreAffinity();
|
||||
};
|
||||
|
|
|
@ -21,9 +21,9 @@
|
|||
/* fld m32 to fpu reg stack */
|
||||
emitterT void FLD32(u32 from)
|
||||
{
|
||||
xWrite8(0xD9);
|
||||
ModRM(0, 0x0, DISP32);
|
||||
xWrite32(MEMADDR(from, 4));
|
||||
xWrite8(0xD9);
|
||||
ModRM(0, 0x0, DISP32);
|
||||
xWrite32(MEMADDR(from, 4));
|
||||
}
|
||||
|
||||
// fld st(i)
|
||||
|
@ -34,9 +34,9 @@ emitterT void FLDL2E() { xWrite16(0xead9); }
|
|||
/* fstp m32 from fpu reg stack */
|
||||
emitterT void FSTP32(u32 to)
|
||||
{
|
||||
xWrite8(0xD9);
|
||||
ModRM(0, 0x3, DISP32);
|
||||
xWrite32(MEMADDR(to, 4));
|
||||
xWrite8(0xD9);
|
||||
ModRM(0, 0x3, DISP32);
|
||||
xWrite32(MEMADDR(to, 4));
|
||||
}
|
||||
|
||||
// fstp st(i)
|
||||
|
@ -52,21 +52,21 @@ emitterT void FSIN(void) { xWrite16(0xfed9); }
|
|||
/* fadd ST(0) to fpu reg stack ST(src) */
|
||||
emitterT void FADD320toR(x86IntRegType src)
|
||||
{
|
||||
xWrite8(0xDC);
|
||||
xWrite8(0xC0 + src);
|
||||
xWrite8(0xDC);
|
||||
xWrite8(0xC0 + src);
|
||||
}
|
||||
|
||||
/* fsub ST(src) to fpu reg stack ST(0) */
|
||||
emitterT void FSUB32Rto0(x86IntRegType src)
|
||||
{
|
||||
xWrite8(0xD8);
|
||||
xWrite8(0xE0 + src);
|
||||
xWrite8(0xD8);
|
||||
xWrite8(0xE0 + src);
|
||||
}
|
||||
|
||||
/* fmul m32 to fpu reg stack */
|
||||
emitterT void FMUL32(u32 from)
|
||||
{
|
||||
xWrite8(0xD8);
|
||||
ModRM(0, 0x1, DISP32);
|
||||
xWrite32(MEMADDR(from, 4));
|
||||
xWrite8(0xD8);
|
||||
ModRM(0, 0x1, DISP32);
|
||||
xWrite32(MEMADDR(from, 4));
|
||||
}
|
||||
|
|
|
@ -34,222 +34,237 @@
|
|||
namespace x86Emitter
|
||||
{
|
||||
|
||||
// =====================================================================================================
|
||||
// Group 1 Instructions - ADD, SUB, ADC, etc.
|
||||
// =====================================================================================================
|
||||
// =====================================================================================================
|
||||
// Group 1 Instructions - ADD, SUB, ADC, etc.
|
||||
// =====================================================================================================
|
||||
|
||||
// Note on "[Indirect],Imm" forms : use int as the source operand since it's "reasonably inert" from a
|
||||
// compiler perspective. (using uint tends to make the compiler try and fail to match signed immediates
|
||||
// with one of the other overloads).
|
||||
static void _g1_IndirectImm(G1Type InstType, const xIndirect64orLess &sibdest, int imm)
|
||||
{
|
||||
if (sibdest.Is8BitOp()) {
|
||||
xOpWrite(sibdest.GetPrefix16(), 0x80, InstType, sibdest);
|
||||
// Note on "[Indirect],Imm" forms : use int as the source operand since it's "reasonably inert" from a
|
||||
// compiler perspective. (using uint tends to make the compiler try and fail to match signed immediates
|
||||
// with one of the other overloads).
|
||||
static void _g1_IndirectImm(G1Type InstType, const xIndirect64orLess& sibdest, int imm)
|
||||
{
|
||||
if (sibdest.Is8BitOp())
|
||||
{
|
||||
xOpWrite(sibdest.GetPrefix16(), 0x80, InstType, sibdest);
|
||||
|
||||
xWrite<s8>(imm);
|
||||
} else {
|
||||
u8 opcode = is_s8(imm) ? 0x83 : 0x81;
|
||||
xOpWrite(sibdest.GetPrefix16(), opcode, InstType, sibdest, is_s8(imm) ? 1 : sibdest.GetImmSize());
|
||||
xWrite<s8>(imm);
|
||||
}
|
||||
else
|
||||
{
|
||||
u8 opcode = is_s8(imm) ? 0x83 : 0x81;
|
||||
xOpWrite(sibdest.GetPrefix16(), opcode, InstType, sibdest, is_s8(imm) ? 1 : sibdest.GetImmSize());
|
||||
|
||||
if (is_s8(imm))
|
||||
xWrite<s8>(imm);
|
||||
else
|
||||
sibdest.xWriteImm(imm);
|
||||
}
|
||||
}
|
||||
if (is_s8(imm))
|
||||
xWrite<s8>(imm);
|
||||
else
|
||||
sibdest.xWriteImm(imm);
|
||||
}
|
||||
}
|
||||
|
||||
void _g1_EmitOp(G1Type InstType, const xRegisterInt &to, const xRegisterInt &from)
|
||||
{
|
||||
pxAssert(to.GetOperandSize() == from.GetOperandSize());
|
||||
void _g1_EmitOp(G1Type InstType, const xRegisterInt& to, const xRegisterInt& from)
|
||||
{
|
||||
pxAssert(to.GetOperandSize() == from.GetOperandSize());
|
||||
|
||||
u8 opcode = (to.Is8BitOp() ? 0 : 1) | (InstType << 3);
|
||||
xOpWrite(to.GetPrefix16(), opcode, from, to);
|
||||
}
|
||||
u8 opcode = (to.Is8BitOp() ? 0 : 1) | (InstType << 3);
|
||||
xOpWrite(to.GetPrefix16(), opcode, from, to);
|
||||
}
|
||||
|
||||
static void _g1_EmitOp(G1Type InstType, const xIndirectVoid &sibdest, const xRegisterInt &from)
|
||||
{
|
||||
u8 opcode = (from.Is8BitOp() ? 0 : 1) | (InstType << 3);
|
||||
xOpWrite(from.GetPrefix16(), opcode, from, sibdest);
|
||||
}
|
||||
static void _g1_EmitOp(G1Type InstType, const xIndirectVoid& sibdest, const xRegisterInt& from)
|
||||
{
|
||||
u8 opcode = (from.Is8BitOp() ? 0 : 1) | (InstType << 3);
|
||||
xOpWrite(from.GetPrefix16(), opcode, from, sibdest);
|
||||
}
|
||||
|
||||
static void _g1_EmitOp(G1Type InstType, const xRegisterInt &to, const xIndirectVoid &sibsrc)
|
||||
{
|
||||
u8 opcode = (to.Is8BitOp() ? 2 : 3) | (InstType << 3);
|
||||
xOpWrite(to.GetPrefix16(), opcode, to, sibsrc);
|
||||
}
|
||||
static void _g1_EmitOp(G1Type InstType, const xRegisterInt& to, const xIndirectVoid& sibsrc)
|
||||
{
|
||||
u8 opcode = (to.Is8BitOp() ? 2 : 3) | (InstType << 3);
|
||||
xOpWrite(to.GetPrefix16(), opcode, to, sibsrc);
|
||||
}
|
||||
|
||||
static void _g1_EmitOp(G1Type InstType, const xRegisterInt &to, int imm)
|
||||
{
|
||||
if (!to.Is8BitOp() && is_s8(imm)) {
|
||||
xOpWrite(to.GetPrefix16(), 0x83, InstType, to);
|
||||
xWrite<s8>(imm);
|
||||
} else {
|
||||
if (to.IsAccumulator()) {
|
||||
u8 opcode = (to.Is8BitOp() ? 4 : 5) | (InstType << 3);
|
||||
xOpAccWrite(to.GetPrefix16(), opcode, InstType, to);
|
||||
} else {
|
||||
u8 opcode = to.Is8BitOp() ? 0x80 : 0x81;
|
||||
xOpWrite(to.GetPrefix16(), opcode, InstType, to);
|
||||
}
|
||||
to.xWriteImm(imm);
|
||||
}
|
||||
}
|
||||
static void _g1_EmitOp(G1Type InstType, const xRegisterInt& to, int imm)
|
||||
{
|
||||
if (!to.Is8BitOp() && is_s8(imm))
|
||||
{
|
||||
xOpWrite(to.GetPrefix16(), 0x83, InstType, to);
|
||||
xWrite<s8>(imm);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (to.IsAccumulator())
|
||||
{
|
||||
u8 opcode = (to.Is8BitOp() ? 4 : 5) | (InstType << 3);
|
||||
xOpAccWrite(to.GetPrefix16(), opcode, InstType, to);
|
||||
}
|
||||
else
|
||||
{
|
||||
u8 opcode = to.Is8BitOp() ? 0x80 : 0x81;
|
||||
xOpWrite(to.GetPrefix16(), opcode, InstType, to);
|
||||
}
|
||||
to.xWriteImm(imm);
|
||||
}
|
||||
}
|
||||
|
||||
#define ImplementGroup1(g1type, insttype) \
|
||||
void g1type::operator()(const xRegisterInt &to, const xRegisterInt &from) const { _g1_EmitOp(insttype, to, from); } \
|
||||
void g1type::operator()(const xIndirectVoid &to, const xRegisterInt &from) const { _g1_EmitOp(insttype, to, from); } \
|
||||
void g1type::operator()(const xRegisterInt &to, const xIndirectVoid &from) const { _g1_EmitOp(insttype, to, from); } \
|
||||
void g1type::operator()(const xRegisterInt &to, int imm) const { _g1_EmitOp(insttype, to, imm); } \
|
||||
void g1type::operator()(const xIndirect64orLess &sibdest, int imm) const { _g1_IndirectImm(insttype, sibdest, imm); }
|
||||
#define ImplementGroup1(g1type, insttype) \
|
||||
void g1type::operator()(const xRegisterInt& to, const xRegisterInt& from) const { _g1_EmitOp(insttype, to, from); } \
|
||||
void g1type::operator()(const xIndirectVoid& to, const xRegisterInt& from) const { _g1_EmitOp(insttype, to, from); } \
|
||||
void g1type::operator()(const xRegisterInt& to, const xIndirectVoid& from) const { _g1_EmitOp(insttype, to, from); } \
|
||||
void g1type::operator()(const xRegisterInt& to, int imm) const { _g1_EmitOp(insttype, to, imm); } \
|
||||
void g1type::operator()(const xIndirect64orLess& sibdest, int imm) const { _g1_IndirectImm(insttype, sibdest, imm); }
|
||||
|
||||
ImplementGroup1(xImpl_Group1, InstType)
|
||||
ImplementGroup1(xImpl_G1Logic, InstType)
|
||||
ImplementGroup1(xImpl_G1Arith, InstType)
|
||||
ImplementGroup1(xImpl_G1Compare, G1Type_CMP)
|
||||
ImplementGroup1(xImpl_Group1, InstType)
|
||||
ImplementGroup1(xImpl_G1Logic, InstType)
|
||||
ImplementGroup1(xImpl_G1Arith, InstType)
|
||||
ImplementGroup1(xImpl_G1Compare, G1Type_CMP)
|
||||
|
||||
const xImpl_G1Logic xAND = {G1Type_AND, {0x00, 0x54}, {0x66, 0x54}};
|
||||
const xImpl_G1Logic xOR = {G1Type_OR, {0x00, 0x56}, {0x66, 0x56}};
|
||||
const xImpl_G1Logic xXOR = {G1Type_XOR, {0x00, 0x57}, {0x66, 0x57}};
|
||||
const xImpl_G1Logic xAND = {G1Type_AND, {0x00, 0x54}, {0x66, 0x54}};
|
||||
const xImpl_G1Logic xOR = {G1Type_OR, {0x00, 0x56}, {0x66, 0x56}};
|
||||
const xImpl_G1Logic xXOR = {G1Type_XOR, {0x00, 0x57}, {0x66, 0x57}};
|
||||
|
||||
const xImpl_G1Arith xADD = {G1Type_ADD, {0x00, 0x58}, {0x66, 0x58}, {0xf3, 0x58}, {0xf2, 0x58}};
|
||||
const xImpl_G1Arith xSUB = {G1Type_SUB, {0x00, 0x5c}, {0x66, 0x5c}, {0xf3, 0x5c}, {0xf2, 0x5c}};
|
||||
const xImpl_G1Compare xCMP = {{0x00, 0xc2}, {0x66, 0xc2}, {0xf3, 0xc2}, {0xf2, 0xc2}};
|
||||
const xImpl_G1Arith xADD = {G1Type_ADD, {0x00, 0x58}, {0x66, 0x58}, {0xf3, 0x58}, {0xf2, 0x58}};
|
||||
const xImpl_G1Arith xSUB = {G1Type_SUB, {0x00, 0x5c}, {0x66, 0x5c}, {0xf3, 0x5c}, {0xf2, 0x5c}};
|
||||
const xImpl_G1Compare xCMP = {{0x00, 0xc2}, {0x66, 0xc2}, {0xf3, 0xc2}, {0xf2, 0xc2}};
|
||||
|
||||
const xImpl_Group1 xADC = {G1Type_ADC};
|
||||
const xImpl_Group1 xSBB = {G1Type_SBB};
|
||||
const xImpl_Group1 xADC = {G1Type_ADC};
|
||||
const xImpl_Group1 xSBB = {G1Type_SBB};
|
||||
|
||||
// =====================================================================================================
|
||||
// Group 2 Instructions - SHR, SHL, etc.
|
||||
// =====================================================================================================
|
||||
// =====================================================================================================
|
||||
// Group 2 Instructions - SHR, SHL, etc.
|
||||
// =====================================================================================================
|
||||
|
||||
void xImpl_Group2::operator()(const xRegisterInt &to, const xRegisterCL & /* from */) const
|
||||
{
|
||||
xOpWrite(to.GetPrefix16(), to.Is8BitOp() ? 0xd2 : 0xd3, InstType, to);
|
||||
}
|
||||
void xImpl_Group2::operator()(const xRegisterInt& to, const xRegisterCL& /* from */) const
|
||||
{
|
||||
xOpWrite(to.GetPrefix16(), to.Is8BitOp() ? 0xd2 : 0xd3, InstType, to);
|
||||
}
|
||||
|
||||
void xImpl_Group2::operator()(const xRegisterInt &to, u8 imm) const
|
||||
{
|
||||
if (imm == 0)
|
||||
return;
|
||||
void xImpl_Group2::operator()(const xRegisterInt& to, u8 imm) const
|
||||
{
|
||||
if (imm == 0)
|
||||
return;
|
||||
|
||||
if (imm == 1) {
|
||||
// special encoding of 1's
|
||||
xOpWrite(to.GetPrefix16(), to.Is8BitOp() ? 0xd0 : 0xd1, InstType, to);
|
||||
} else {
|
||||
xOpWrite(to.GetPrefix16(), to.Is8BitOp() ? 0xc0 : 0xc1, InstType, to);
|
||||
xWrite8(imm);
|
||||
}
|
||||
}
|
||||
if (imm == 1)
|
||||
{
|
||||
// special encoding of 1's
|
||||
xOpWrite(to.GetPrefix16(), to.Is8BitOp() ? 0xd0 : 0xd1, InstType, to);
|
||||
}
|
||||
else
|
||||
{
|
||||
xOpWrite(to.GetPrefix16(), to.Is8BitOp() ? 0xc0 : 0xc1, InstType, to);
|
||||
xWrite8(imm);
|
||||
}
|
||||
}
|
||||
|
||||
void xImpl_Group2::operator()(const xIndirect64orLess &sibdest, const xRegisterCL & /* from */) const
|
||||
{
|
||||
xOpWrite(sibdest.GetPrefix16(), sibdest.Is8BitOp() ? 0xd2 : 0xd3, InstType, sibdest);
|
||||
}
|
||||
void xImpl_Group2::operator()(const xIndirect64orLess& sibdest, const xRegisterCL& /* from */) const
|
||||
{
|
||||
xOpWrite(sibdest.GetPrefix16(), sibdest.Is8BitOp() ? 0xd2 : 0xd3, InstType, sibdest);
|
||||
}
|
||||
|
||||
void xImpl_Group2::operator()(const xIndirect64orLess &sibdest, u8 imm) const
|
||||
{
|
||||
if (imm == 0)
|
||||
return;
|
||||
void xImpl_Group2::operator()(const xIndirect64orLess& sibdest, u8 imm) const
|
||||
{
|
||||
if (imm == 0)
|
||||
return;
|
||||
|
||||
if (imm == 1) {
|
||||
// special encoding of 1's
|
||||
xOpWrite(sibdest.GetPrefix16(), sibdest.Is8BitOp() ? 0xd0 : 0xd1, InstType, sibdest);
|
||||
} else {
|
||||
xOpWrite(sibdest.GetPrefix16(), sibdest.Is8BitOp() ? 0xc0 : 0xc1, InstType, sibdest, 1);
|
||||
xWrite8(imm);
|
||||
}
|
||||
}
|
||||
if (imm == 1)
|
||||
{
|
||||
// special encoding of 1's
|
||||
xOpWrite(sibdest.GetPrefix16(), sibdest.Is8BitOp() ? 0xd0 : 0xd1, InstType, sibdest);
|
||||
}
|
||||
else
|
||||
{
|
||||
xOpWrite(sibdest.GetPrefix16(), sibdest.Is8BitOp() ? 0xc0 : 0xc1, InstType, sibdest, 1);
|
||||
xWrite8(imm);
|
||||
}
|
||||
}
|
||||
|
||||
const xImpl_Group2 xROL = {G2Type_ROL};
|
||||
const xImpl_Group2 xROR = {G2Type_ROR};
|
||||
const xImpl_Group2 xRCL = {G2Type_RCL};
|
||||
const xImpl_Group2 xRCR = {G2Type_RCR};
|
||||
const xImpl_Group2 xSHL = {G2Type_SHL};
|
||||
const xImpl_Group2 xSHR = {G2Type_SHR};
|
||||
const xImpl_Group2 xSAR = {G2Type_SAR};
|
||||
const xImpl_Group2 xROL = {G2Type_ROL};
|
||||
const xImpl_Group2 xROR = {G2Type_ROR};
|
||||
const xImpl_Group2 xRCL = {G2Type_RCL};
|
||||
const xImpl_Group2 xRCR = {G2Type_RCR};
|
||||
const xImpl_Group2 xSHL = {G2Type_SHL};
|
||||
const xImpl_Group2 xSHR = {G2Type_SHR};
|
||||
const xImpl_Group2 xSAR = {G2Type_SAR};
|
||||
|
||||
|
||||
// =====================================================================================================
|
||||
// Group 3 Instructions - NOT, NEG, MUL, DIV
|
||||
// =====================================================================================================
|
||||
// =====================================================================================================
|
||||
// Group 3 Instructions - NOT, NEG, MUL, DIV
|
||||
// =====================================================================================================
|
||||
|
||||
static void _g3_EmitOp(G3Type InstType, const xRegisterInt &from)
|
||||
{
|
||||
xOpWrite(from.GetPrefix16(), from.Is8BitOp() ? 0xf6 : 0xf7, InstType, from);
|
||||
}
|
||||
static void _g3_EmitOp(G3Type InstType, const xRegisterInt& from)
|
||||
{
|
||||
xOpWrite(from.GetPrefix16(), from.Is8BitOp() ? 0xf6 : 0xf7, InstType, from);
|
||||
}
|
||||
|
||||
static void _g3_EmitOp(G3Type InstType, const xIndirect64orLess &from)
|
||||
{
|
||||
xOpWrite(from.GetPrefix16(), from.Is8BitOp() ? 0xf6 : 0xf7, InstType, from);
|
||||
}
|
||||
static void _g3_EmitOp(G3Type InstType, const xIndirect64orLess& from)
|
||||
{
|
||||
xOpWrite(from.GetPrefix16(), from.Is8BitOp() ? 0xf6 : 0xf7, InstType, from);
|
||||
}
|
||||
|
||||
void xImpl_Group3::operator()(const xRegisterInt &from) const { _g3_EmitOp(InstType, from); }
|
||||
void xImpl_Group3::operator()(const xIndirect64orLess &from) const { _g3_EmitOp(InstType, from); }
|
||||
void xImpl_Group3::operator()(const xRegisterInt& from) const { _g3_EmitOp(InstType, from); }
|
||||
void xImpl_Group3::operator()(const xIndirect64orLess& from) const { _g3_EmitOp(InstType, from); }
|
||||
|
||||
void xImpl_iDiv::operator()(const xRegisterInt &from) const { _g3_EmitOp(G3Type_iDIV, from); }
|
||||
void xImpl_iDiv::operator()(const xIndirect64orLess &from) const { _g3_EmitOp(G3Type_iDIV, from); }
|
||||
void xImpl_iDiv::operator()(const xRegisterInt& from) const { _g3_EmitOp(G3Type_iDIV, from); }
|
||||
void xImpl_iDiv::operator()(const xIndirect64orLess& from) const { _g3_EmitOp(G3Type_iDIV, from); }
|
||||
|
||||
template <typename SrcType>
|
||||
static void _imul_ImmStyle(const xRegisterInt ¶m1, const SrcType ¶m2, int imm)
|
||||
{
|
||||
pxAssert(param1.GetOperandSize() == param2.GetOperandSize());
|
||||
template <typename SrcType>
|
||||
static void _imul_ImmStyle(const xRegisterInt& param1, const SrcType& param2, int imm)
|
||||
{
|
||||
pxAssert(param1.GetOperandSize() == param2.GetOperandSize());
|
||||
|
||||
xOpWrite0F(param1.GetPrefix16(), is_s8(imm) ? 0x6b : 0x69, param1, param2, is_s8(imm) ? 1 : param1.GetImmSize());
|
||||
xOpWrite0F(param1.GetPrefix16(), is_s8(imm) ? 0x6b : 0x69, param1, param2, is_s8(imm) ? 1 : param1.GetImmSize());
|
||||
|
||||
if (is_s8(imm))
|
||||
xWrite8((u8)imm);
|
||||
else
|
||||
param1.xWriteImm(imm);
|
||||
}
|
||||
if (is_s8(imm))
|
||||
xWrite8((u8)imm);
|
||||
else
|
||||
param1.xWriteImm(imm);
|
||||
}
|
||||
|
||||
void xImpl_iMul::operator()(const xRegisterInt &from) const { _g3_EmitOp(G3Type_iMUL, from); }
|
||||
void xImpl_iMul::operator()(const xIndirect64orLess &from) const { _g3_EmitOp(G3Type_iMUL, from); }
|
||||
void xImpl_iMul::operator()(const xRegisterInt& from) const { _g3_EmitOp(G3Type_iMUL, from); }
|
||||
void xImpl_iMul::operator()(const xIndirect64orLess& from) const { _g3_EmitOp(G3Type_iMUL, from); }
|
||||
|
||||
void xImpl_iMul::operator()(const xRegister32 &to, const xRegister32 &from) const { xOpWrite0F(0xaf, to, from); }
|
||||
void xImpl_iMul::operator()(const xRegister32 &to, const xIndirectVoid &src) const { xOpWrite0F(0xaf, to, src); }
|
||||
void xImpl_iMul::operator()(const xRegister16 &to, const xRegister16 &from) const { xOpWrite0F(0x66, 0xaf, to, from); }
|
||||
void xImpl_iMul::operator()(const xRegister16 &to, const xIndirectVoid &src) const { xOpWrite0F(0x66, 0xaf, to, src); }
|
||||
void xImpl_iMul::operator()(const xRegister32& to, const xRegister32& from) const { xOpWrite0F(0xaf, to, from); }
|
||||
void xImpl_iMul::operator()(const xRegister32& to, const xIndirectVoid& src) const { xOpWrite0F(0xaf, to, src); }
|
||||
void xImpl_iMul::operator()(const xRegister16& to, const xRegister16& from) const { xOpWrite0F(0x66, 0xaf, to, from); }
|
||||
void xImpl_iMul::operator()(const xRegister16& to, const xIndirectVoid& src) const { xOpWrite0F(0x66, 0xaf, to, src); }
|
||||
|
||||
void xImpl_iMul::operator()(const xRegister32 &to, const xRegister32 &from, s32 imm) const { _imul_ImmStyle(to, from, imm); }
|
||||
void xImpl_iMul::operator()(const xRegister32 &to, const xIndirectVoid &from, s32 imm) const { _imul_ImmStyle(to, from, imm); }
|
||||
void xImpl_iMul::operator()(const xRegister16 &to, const xRegister16 &from, s16 imm) const { _imul_ImmStyle(to, from, imm); }
|
||||
void xImpl_iMul::operator()(const xRegister16 &to, const xIndirectVoid &from, s16 imm) const { _imul_ImmStyle(to, from, imm); }
|
||||
void xImpl_iMul::operator()(const xRegister32& to, const xRegister32& from, s32 imm) const { _imul_ImmStyle(to, from, imm); }
|
||||
void xImpl_iMul::operator()(const xRegister32& to, const xIndirectVoid& from, s32 imm) const { _imul_ImmStyle(to, from, imm); }
|
||||
void xImpl_iMul::operator()(const xRegister16& to, const xRegister16& from, s16 imm) const { _imul_ImmStyle(to, from, imm); }
|
||||
void xImpl_iMul::operator()(const xRegister16& to, const xIndirectVoid& from, s16 imm) const { _imul_ImmStyle(to, from, imm); }
|
||||
|
||||
const xImpl_Group3 xNOT = {G3Type_NOT};
|
||||
const xImpl_Group3 xNEG = {G3Type_NEG};
|
||||
const xImpl_Group3 xUMUL = {G3Type_MUL};
|
||||
const xImpl_Group3 xUDIV = {G3Type_DIV};
|
||||
const xImpl_Group3 xNOT = {G3Type_NOT};
|
||||
const xImpl_Group3 xNEG = {G3Type_NEG};
|
||||
const xImpl_Group3 xUMUL = {G3Type_MUL};
|
||||
const xImpl_Group3 xUDIV = {G3Type_DIV};
|
||||
|
||||
const xImpl_iDiv xDIV = {{0x00, 0x5e}, {0x66, 0x5e}, {0xf3, 0x5e}, {0xf2, 0x5e}};
|
||||
const xImpl_iMul xMUL = {{0x00, 0x59}, {0x66, 0x59}, {0xf3, 0x59}, {0xf2, 0x59}};
|
||||
const xImpl_iDiv xDIV = {{0x00, 0x5e}, {0x66, 0x5e}, {0xf3, 0x5e}, {0xf2, 0x5e}};
|
||||
const xImpl_iMul xMUL = {{0x00, 0x59}, {0x66, 0x59}, {0xf3, 0x59}, {0xf2, 0x59}};
|
||||
|
||||
// =====================================================================================================
|
||||
// Group 8 Instructions
|
||||
// =====================================================================================================
|
||||
// =====================================================================================================
|
||||
// Group 8 Instructions
|
||||
// =====================================================================================================
|
||||
|
||||
void xImpl_Group8::operator()(const xRegister16or32or64 &bitbase, const xRegister16or32or64 &bitoffset) const
|
||||
{
|
||||
pxAssert(bitbase->GetOperandSize() == bitoffset->GetOperandSize());
|
||||
xOpWrite0F(bitbase->GetPrefix16(), 0xa3 | (InstType << 3), bitbase, bitoffset);
|
||||
}
|
||||
void xImpl_Group8::operator()(const xIndirect64 &bitbase, u8 bitoffset) const { xOpWrite0F(0xba, InstType, bitbase, bitoffset); }
|
||||
void xImpl_Group8::operator()(const xIndirect32 &bitbase, u8 bitoffset) const { xOpWrite0F(0xba, InstType, bitbase, bitoffset); }
|
||||
void xImpl_Group8::operator()(const xIndirect16 &bitbase, u8 bitoffset) const { xOpWrite0F(0x66, 0xba, InstType, bitbase, bitoffset); }
|
||||
void xImpl_Group8::operator()(const xRegister16or32or64& bitbase, const xRegister16or32or64& bitoffset) const
|
||||
{
|
||||
pxAssert(bitbase->GetOperandSize() == bitoffset->GetOperandSize());
|
||||
xOpWrite0F(bitbase->GetPrefix16(), 0xa3 | (InstType << 3), bitbase, bitoffset);
|
||||
}
|
||||
void xImpl_Group8::operator()(const xIndirect64& bitbase, u8 bitoffset) const { xOpWrite0F(0xba, InstType, bitbase, bitoffset); }
|
||||
void xImpl_Group8::operator()(const xIndirect32& bitbase, u8 bitoffset) const { xOpWrite0F(0xba, InstType, bitbase, bitoffset); }
|
||||
void xImpl_Group8::operator()(const xIndirect16& bitbase, u8 bitoffset) const { xOpWrite0F(0x66, 0xba, InstType, bitbase, bitoffset); }
|
||||
|
||||
void xImpl_Group8::operator()(const xRegister16or32or64 &bitbase, u8 bitoffset) const
|
||||
{
|
||||
xOpWrite0F(bitbase->GetPrefix16(), 0xba, InstType, bitbase, bitoffset);
|
||||
}
|
||||
void xImpl_Group8::operator()(const xRegister16or32or64& bitbase, u8 bitoffset) const
|
||||
{
|
||||
xOpWrite0F(bitbase->GetPrefix16(), 0xba, InstType, bitbase, bitoffset);
|
||||
}
|
||||
|
||||
void xImpl_Group8::operator()(const xIndirectVoid &bitbase, const xRegister16or32or64 &bitoffset) const
|
||||
{
|
||||
xOpWrite0F(bitoffset->GetPrefix16(), 0xa3 | (InstType << 3), bitoffset, bitbase);
|
||||
}
|
||||
void xImpl_Group8::operator()(const xIndirectVoid& bitbase, const xRegister16or32or64& bitoffset) const
|
||||
{
|
||||
xOpWrite0F(bitoffset->GetPrefix16(), 0xa3 | (InstType << 3), bitoffset, bitbase);
|
||||
}
|
||||
|
||||
const xImpl_Group8 xBT = {G8Type_BT};
|
||||
const xImpl_Group8 xBTR = {G8Type_BTR};
|
||||
const xImpl_Group8 xBTS = {G8Type_BTS};
|
||||
const xImpl_Group8 xBTC = {G8Type_BTC};
|
||||
const xImpl_Group8 xBT = {G8Type_BT};
|
||||
const xImpl_Group8 xBTR = {G8Type_BTR};
|
||||
const xImpl_Group8 xBTS = {G8Type_BTS};
|
||||
const xImpl_Group8 xBTC = {G8Type_BTC};
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -20,19 +20,19 @@
|
|||
namespace x86Emitter
|
||||
{
|
||||
|
||||
struct xImplBMI_RVM
|
||||
{
|
||||
u8 Prefix;
|
||||
u8 MbPrefix;
|
||||
u8 Opcode;
|
||||
struct xImplBMI_RVM
|
||||
{
|
||||
u8 Prefix;
|
||||
u8 MbPrefix;
|
||||
u8 Opcode;
|
||||
|
||||
// RVM
|
||||
// MULX Unsigned multiply without affecting flags, and arbitrary destination registers
|
||||
// PDEP Parallel bits deposit
|
||||
// PEXT Parallel bits extract
|
||||
// ANDN Logical and not ~x & y
|
||||
void operator()(const xRegisterInt &to, const xRegisterInt &from1, const xRegisterInt &from2) const;
|
||||
void operator()(const xRegisterInt &to, const xRegisterInt &from1, const xIndirectVoid &from2) const;
|
||||
// RVM
|
||||
// MULX Unsigned multiply without affecting flags, and arbitrary destination registers
|
||||
// PDEP Parallel bits deposit
|
||||
// PEXT Parallel bits extract
|
||||
// ANDN Logical and not ~x & y
|
||||
void operator()(const xRegisterInt& to, const xRegisterInt& from1, const xRegisterInt& from2) const;
|
||||
void operator()(const xRegisterInt& to, const xRegisterInt& from1, const xIndirectVoid& from2) const;
|
||||
|
||||
#if 0
|
||||
// RMV
|
||||
|
@ -57,5 +57,5 @@ struct xImplBMI_RVM
|
|||
void operator()( const xRegisterInt& to, const xRegisterInt& from, u8 imm) const;
|
||||
void operator()( const xRegisterInt& to, const xIndirectVoid& from, u8 imm) const;
|
||||
#endif
|
||||
};
|
||||
}
|
||||
};
|
||||
} // namespace x86Emitter
|
||||
|
|
|
@ -18,27 +18,27 @@
|
|||
namespace x86Emitter
|
||||
{
|
||||
|
||||
// Implementations here cover SHLD and SHRD.
|
||||
// Implementations here cover SHLD and SHRD.
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImpl_DowrdShift
|
||||
// --------------------------------------------------------------------------------------
|
||||
// I use explicit method declarations here instead of templates, in order to provide
|
||||
// *only* 32 and 16 bit register operand forms (8 bit registers are not valid in SHLD/SHRD).
|
||||
//
|
||||
// Optimization Note: Imm shifts by 0 are ignore (no code generated). This is a safe optimization
|
||||
// because shifts by 0 do *not* affect flags status (intel docs cited).
|
||||
//
|
||||
struct xImpl_DwordShift
|
||||
{
|
||||
u16 OpcodeBase;
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImpl_DowrdShift
|
||||
// --------------------------------------------------------------------------------------
|
||||
// I use explicit method declarations here instead of templates, in order to provide
|
||||
// *only* 32 and 16 bit register operand forms (8 bit registers are not valid in SHLD/SHRD).
|
||||
//
|
||||
// Optimization Note: Imm shifts by 0 are ignore (no code generated). This is a safe optimization
|
||||
// because shifts by 0 do *not* affect flags status (intel docs cited).
|
||||
//
|
||||
struct xImpl_DwordShift
|
||||
{
|
||||
u16 OpcodeBase;
|
||||
|
||||
void operator()(const xRegister16or32or64 &to, const xRegister16or32or64 &from, const xRegisterCL &clreg) const;
|
||||
void operator()(const xRegister16or32or64& to, const xRegister16or32or64& from, const xRegisterCL& clreg) const;
|
||||
|
||||
void operator()(const xRegister16or32or64 &to, const xRegister16or32or64 &from, u8 shiftcnt) const;
|
||||
void operator()(const xRegister16or32or64& to, const xRegister16or32or64& from, u8 shiftcnt) const;
|
||||
|
||||
void operator()(const xIndirectVoid &dest, const xRegister16or32or64 &from, const xRegisterCL &clreg) const;
|
||||
void operator()(const xIndirectVoid &dest, const xRegister16or32or64 &from, u8 shiftcnt) const;
|
||||
};
|
||||
void operator()(const xIndirectVoid& dest, const xRegister16or32or64& from, const xRegisterCL& clreg) const;
|
||||
void operator()(const xIndirectVoid& dest, const xRegister16or32or64& from, u8 shiftcnt) const;
|
||||
};
|
||||
|
||||
} // End namespace x86Emitter
|
||||
|
|
|
@ -18,32 +18,33 @@
|
|||
namespace x86Emitter
|
||||
{
|
||||
|
||||
enum G1Type {
|
||||
G1Type_ADD = 0,
|
||||
G1Type_OR,
|
||||
G1Type_ADC,
|
||||
G1Type_SBB,
|
||||
G1Type_AND,
|
||||
G1Type_SUB,
|
||||
G1Type_XOR,
|
||||
G1Type_CMP
|
||||
};
|
||||
enum G1Type
|
||||
{
|
||||
G1Type_ADD = 0,
|
||||
G1Type_OR,
|
||||
G1Type_ADC,
|
||||
G1Type_SBB,
|
||||
G1Type_AND,
|
||||
G1Type_SUB,
|
||||
G1Type_XOR,
|
||||
G1Type_CMP
|
||||
};
|
||||
|
||||
extern void _g1_EmitOp(G1Type InstType, const xRegisterInt &to, const xRegisterInt &from);
|
||||
extern void _g1_EmitOp(G1Type InstType, const xRegisterInt& to, const xRegisterInt& from);
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImpl_Group1
|
||||
// --------------------------------------------------------------------------------------
|
||||
struct xImpl_Group1
|
||||
{
|
||||
G1Type InstType;
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImpl_Group1
|
||||
// --------------------------------------------------------------------------------------
|
||||
struct xImpl_Group1
|
||||
{
|
||||
G1Type InstType;
|
||||
|
||||
void operator()(const xRegisterInt &to, const xRegisterInt &from) const;
|
||||
void operator()(const xRegisterInt& to, const xRegisterInt& from) const;
|
||||
|
||||
void operator()(const xIndirectVoid &to, const xRegisterInt &from) const;
|
||||
void operator()(const xRegisterInt &to, const xIndirectVoid &from) const;
|
||||
void operator()(const xRegisterInt &to, int imm) const;
|
||||
void operator()(const xIndirect64orLess &to, int imm) const;
|
||||
void operator()(const xIndirectVoid& to, const xRegisterInt& from) const;
|
||||
void operator()(const xRegisterInt& to, const xIndirectVoid& from) const;
|
||||
void operator()(const xRegisterInt& to, int imm) const;
|
||||
void operator()(const xIndirect64orLess& to, int imm) const;
|
||||
|
||||
#if 0
|
||||
// ------------------------------------------------------------------------
|
||||
|
@ -79,64 +80,64 @@ struct xImpl_Group1
|
|||
_DoI_helpermess( *this, to, xDirectOrIndirect<T>( from ) );
|
||||
}
|
||||
#endif
|
||||
};
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// This class combines x86 with SSE/SSE2 logic operations (ADD, OR, and NOT).
|
||||
// Note: ANDN [AndNot] is handled below separately.
|
||||
//
|
||||
struct xImpl_G1Logic
|
||||
{
|
||||
G1Type InstType;
|
||||
// ------------------------------------------------------------------------
|
||||
// This class combines x86 with SSE/SSE2 logic operations (ADD, OR, and NOT).
|
||||
// Note: ANDN [AndNot] is handled below separately.
|
||||
//
|
||||
struct xImpl_G1Logic
|
||||
{
|
||||
G1Type InstType;
|
||||
|
||||
void operator()(const xRegisterInt &to, const xRegisterInt &from) const;
|
||||
void operator()(const xRegisterInt& to, const xRegisterInt& from) const;
|
||||
|
||||
void operator()(const xIndirectVoid &to, const xRegisterInt &from) const;
|
||||
void operator()(const xRegisterInt &to, const xIndirectVoid &from) const;
|
||||
void operator()(const xRegisterInt &to, int imm) const;
|
||||
void operator()(const xIndirectVoid& to, const xRegisterInt& from) const;
|
||||
void operator()(const xRegisterInt& to, const xIndirectVoid& from) const;
|
||||
void operator()(const xRegisterInt& to, int imm) const;
|
||||
|
||||
void operator()(const xIndirect64orLess &to, int imm) const;
|
||||
void operator()(const xIndirect64orLess& to, int imm) const;
|
||||
|
||||
xImplSimd_DestRegSSE PS; // packed single precision
|
||||
xImplSimd_DestRegSSE PD; // packed double precision
|
||||
};
|
||||
xImplSimd_DestRegSSE PS; // packed single precision
|
||||
xImplSimd_DestRegSSE PD; // packed double precision
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// This class combines x86 with SSE/SSE2 arithmetic operations (ADD/SUB).
|
||||
//
|
||||
struct xImpl_G1Arith
|
||||
{
|
||||
G1Type InstType;
|
||||
// ------------------------------------------------------------------------
|
||||
// This class combines x86 with SSE/SSE2 arithmetic operations (ADD/SUB).
|
||||
//
|
||||
struct xImpl_G1Arith
|
||||
{
|
||||
G1Type InstType;
|
||||
|
||||
void operator()(const xRegisterInt &to, const xRegisterInt &from) const;
|
||||
void operator()(const xRegisterInt& to, const xRegisterInt& from) const;
|
||||
|
||||
void operator()(const xIndirectVoid &to, const xRegisterInt &from) const;
|
||||
void operator()(const xRegisterInt &to, const xIndirectVoid &from) const;
|
||||
void operator()(const xRegisterInt &to, int imm) const;
|
||||
void operator()(const xIndirectVoid& to, const xRegisterInt& from) const;
|
||||
void operator()(const xRegisterInt& to, const xIndirectVoid& from) const;
|
||||
void operator()(const xRegisterInt& to, int imm) const;
|
||||
|
||||
void operator()(const xIndirect64orLess &to, int imm) const;
|
||||
void operator()(const xIndirect64orLess& to, int imm) const;
|
||||
|
||||
xImplSimd_DestRegSSE PS; // packed single precision
|
||||
xImplSimd_DestRegSSE PD; // packed double precision
|
||||
xImplSimd_DestRegSSE SS; // scalar single precision
|
||||
xImplSimd_DestRegSSE SD; // scalar double precision
|
||||
};
|
||||
xImplSimd_DestRegSSE PS; // packed single precision
|
||||
xImplSimd_DestRegSSE PD; // packed double precision
|
||||
xImplSimd_DestRegSSE SS; // scalar single precision
|
||||
xImplSimd_DestRegSSE SD; // scalar double precision
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
struct xImpl_G1Compare
|
||||
{
|
||||
void operator()(const xRegisterInt &to, const xRegisterInt &from) const;
|
||||
// ------------------------------------------------------------------------
|
||||
struct xImpl_G1Compare
|
||||
{
|
||||
void operator()(const xRegisterInt& to, const xRegisterInt& from) const;
|
||||
|
||||
void operator()(const xIndirectVoid &to, const xRegisterInt &from) const;
|
||||
void operator()(const xRegisterInt &to, const xIndirectVoid &from) const;
|
||||
void operator()(const xRegisterInt &to, int imm) const;
|
||||
void operator()(const xIndirectVoid& to, const xRegisterInt& from) const;
|
||||
void operator()(const xRegisterInt& to, const xIndirectVoid& from) const;
|
||||
void operator()(const xRegisterInt& to, int imm) const;
|
||||
|
||||
void operator()(const xIndirect64orLess &to, int imm) const;
|
||||
void operator()(const xIndirect64orLess& to, int imm) const;
|
||||
|
||||
xImplSimd_DestSSE_CmpImm PS;
|
||||
xImplSimd_DestSSE_CmpImm PD;
|
||||
xImplSimd_DestSSE_CmpImm SS;
|
||||
xImplSimd_DestSSE_CmpImm SD;
|
||||
};
|
||||
xImplSimd_DestSSE_CmpImm PS;
|
||||
xImplSimd_DestSSE_CmpImm PD;
|
||||
xImplSimd_DestSSE_CmpImm SS;
|
||||
xImplSimd_DestSSE_CmpImm SD;
|
||||
};
|
||||
|
||||
} // End namespace x86Emitter
|
||||
|
|
|
@ -18,32 +18,33 @@
|
|||
namespace x86Emitter
|
||||
{
|
||||
|
||||
enum G2Type {
|
||||
G2Type_ROL = 0,
|
||||
G2Type_ROR,
|
||||
G2Type_RCL,
|
||||
G2Type_RCR,
|
||||
G2Type_SHL,
|
||||
G2Type_SHR,
|
||||
G2Type_Unused,
|
||||
G2Type_SAR
|
||||
};
|
||||
enum G2Type
|
||||
{
|
||||
G2Type_ROL = 0,
|
||||
G2Type_ROR,
|
||||
G2Type_RCL,
|
||||
G2Type_RCR,
|
||||
G2Type_SHL,
|
||||
G2Type_SHR,
|
||||
G2Type_Unused,
|
||||
G2Type_SAR
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImpl_Group2
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Group 2 (shift) instructions have no Sib/ModRM forms.
|
||||
// Optimization Note: For Imm forms, we ignore the instruction if the shift count is zero.
|
||||
// This is a safe optimization since any zero-value shift does not affect any flags.
|
||||
//
|
||||
struct xImpl_Group2
|
||||
{
|
||||
G2Type InstType;
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImpl_Group2
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Group 2 (shift) instructions have no Sib/ModRM forms.
|
||||
// Optimization Note: For Imm forms, we ignore the instruction if the shift count is zero.
|
||||
// This is a safe optimization since any zero-value shift does not affect any flags.
|
||||
//
|
||||
struct xImpl_Group2
|
||||
{
|
||||
G2Type InstType;
|
||||
|
||||
void operator()(const xRegisterInt &to, const xRegisterCL &from) const;
|
||||
void operator()(const xIndirect64orLess &to, const xRegisterCL &from) const;
|
||||
void operator()(const xRegisterInt &to, u8 imm) const;
|
||||
void operator()(const xIndirect64orLess &to, u8 imm) const;
|
||||
void operator()(const xRegisterInt& to, const xRegisterCL& from) const;
|
||||
void operator()(const xIndirect64orLess& to, const xRegisterCL& from) const;
|
||||
void operator()(const xRegisterInt& to, u8 imm) const;
|
||||
void operator()(const xIndirect64orLess& to, u8 imm) const;
|
||||
|
||||
#if 0
|
||||
// ------------------------------------------------------------------------
|
||||
|
@ -57,6 +58,6 @@ struct xImpl_Group2
|
|||
_DoI_helpermess( *this, to, from );
|
||||
}
|
||||
#endif
|
||||
};
|
||||
};
|
||||
|
||||
} // End namespace x86Emitter
|
||||
|
|
|
@ -18,24 +18,25 @@
|
|||
namespace x86Emitter
|
||||
{
|
||||
|
||||
enum G3Type {
|
||||
G3Type_NOT = 2,
|
||||
G3Type_NEG = 3,
|
||||
G3Type_MUL = 4,
|
||||
G3Type_iMUL = 5, // partial implementation, iMul has additional forms in ix86.cpp
|
||||
G3Type_DIV = 6,
|
||||
G3Type_iDIV = 7
|
||||
};
|
||||
enum G3Type
|
||||
{
|
||||
G3Type_NOT = 2,
|
||||
G3Type_NEG = 3,
|
||||
G3Type_MUL = 4,
|
||||
G3Type_iMUL = 5, // partial implementation, iMul has additional forms in ix86.cpp
|
||||
G3Type_DIV = 6,
|
||||
G3Type_iDIV = 7
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImpl_Group3
|
||||
// --------------------------------------------------------------------------------------
|
||||
struct xImpl_Group3
|
||||
{
|
||||
G3Type InstType;
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImpl_Group3
|
||||
// --------------------------------------------------------------------------------------
|
||||
struct xImpl_Group3
|
||||
{
|
||||
G3Type InstType;
|
||||
|
||||
void operator()(const xRegisterInt &from) const;
|
||||
void operator()(const xIndirect64orLess &from) const;
|
||||
void operator()(const xRegisterInt& from) const;
|
||||
void operator()(const xIndirect64orLess& from) const;
|
||||
|
||||
#if 0
|
||||
template< typename T >
|
||||
|
@ -44,65 +45,65 @@ struct xImpl_Group3
|
|||
_DoI_helpermess( *this, from );
|
||||
}
|
||||
#endif
|
||||
};
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImpl_MulDivBase
|
||||
// --------------------------------------------------------------------------------------
|
||||
// This class combines x86 and SSE/SSE2 instructions for iMUL and iDIV.
|
||||
//
|
||||
struct xImpl_MulDivBase
|
||||
{
|
||||
G3Type InstType;
|
||||
u16 OpcodeSSE;
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImpl_MulDivBase
|
||||
// --------------------------------------------------------------------------------------
|
||||
// This class combines x86 and SSE/SSE2 instructions for iMUL and iDIV.
|
||||
//
|
||||
struct xImpl_MulDivBase
|
||||
{
|
||||
G3Type InstType;
|
||||
u16 OpcodeSSE;
|
||||
|
||||
void operator()(const xRegisterInt &from) const;
|
||||
void operator()(const xIndirect64orLess &from) const;
|
||||
void operator()(const xRegisterInt& from) const;
|
||||
void operator()(const xIndirect64orLess& from) const;
|
||||
|
||||
const xImplSimd_DestRegSSE PS;
|
||||
const xImplSimd_DestRegSSE PD;
|
||||
const xImplSimd_DestRegSSE SS;
|
||||
const xImplSimd_DestRegSSE SD;
|
||||
};
|
||||
const xImplSimd_DestRegSSE PS;
|
||||
const xImplSimd_DestRegSSE PD;
|
||||
const xImplSimd_DestRegSSE SS;
|
||||
const xImplSimd_DestRegSSE SD;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImpl_iDiv
|
||||
// --------------------------------------------------------------------------------------
|
||||
struct xImpl_iDiv
|
||||
{
|
||||
void operator()(const xRegisterInt &from) const;
|
||||
void operator()(const xIndirect64orLess &from) const;
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImpl_iDiv
|
||||
// --------------------------------------------------------------------------------------
|
||||
struct xImpl_iDiv
|
||||
{
|
||||
void operator()(const xRegisterInt& from) const;
|
||||
void operator()(const xIndirect64orLess& from) const;
|
||||
|
||||
const xImplSimd_DestRegSSE PS;
|
||||
const xImplSimd_DestRegSSE PD;
|
||||
const xImplSimd_DestRegSSE SS;
|
||||
const xImplSimd_DestRegSSE SD;
|
||||
};
|
||||
const xImplSimd_DestRegSSE PS;
|
||||
const xImplSimd_DestRegSSE PD;
|
||||
const xImplSimd_DestRegSSE SS;
|
||||
const xImplSimd_DestRegSSE SD;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImpl_iMul
|
||||
// --------------------------------------------------------------------------------------
|
||||
//
|
||||
struct xImpl_iMul
|
||||
{
|
||||
void operator()(const xRegisterInt &from) const;
|
||||
void operator()(const xIndirect64orLess &from) const;
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImpl_iMul
|
||||
// --------------------------------------------------------------------------------------
|
||||
//
|
||||
struct xImpl_iMul
|
||||
{
|
||||
void operator()(const xRegisterInt& from) const;
|
||||
void operator()(const xIndirect64orLess& from) const;
|
||||
|
||||
// The following iMul-specific forms are valid for 16 and 32 bit register operands only!
|
||||
// The following iMul-specific forms are valid for 16 and 32 bit register operands only!
|
||||
|
||||
void operator()(const xRegister32 &to, const xRegister32 &from) const;
|
||||
void operator()(const xRegister32 &to, const xIndirectVoid &src) const;
|
||||
void operator()(const xRegister16 &to, const xRegister16 &from) const;
|
||||
void operator()(const xRegister16 &to, const xIndirectVoid &src) const;
|
||||
void operator()(const xRegister32& to, const xRegister32& from) const;
|
||||
void operator()(const xRegister32& to, const xIndirectVoid& src) const;
|
||||
void operator()(const xRegister16& to, const xRegister16& from) const;
|
||||
void operator()(const xRegister16& to, const xIndirectVoid& src) const;
|
||||
|
||||
void operator()(const xRegister32 &to, const xRegister32 &from, s32 imm) const;
|
||||
void operator()(const xRegister32 &to, const xIndirectVoid &from, s32 imm) const;
|
||||
void operator()(const xRegister16 &to, const xRegister16 &from, s16 imm) const;
|
||||
void operator()(const xRegister16 &to, const xIndirectVoid &from, s16 imm) const;
|
||||
void operator()(const xRegister32& to, const xRegister32& from, s32 imm) const;
|
||||
void operator()(const xRegister32& to, const xIndirectVoid& from, s32 imm) const;
|
||||
void operator()(const xRegister16& to, const xRegister16& from, s16 imm) const;
|
||||
void operator()(const xRegister16& to, const xIndirectVoid& from, s16 imm) const;
|
||||
|
||||
const xImplSimd_DestRegSSE PS;
|
||||
const xImplSimd_DestRegSSE PD;
|
||||
const xImplSimd_DestRegSSE SS;
|
||||
const xImplSimd_DestRegSSE SD;
|
||||
};
|
||||
}
|
||||
const xImplSimd_DestRegSSE PS;
|
||||
const xImplSimd_DestRegSSE PD;
|
||||
const xImplSimd_DestRegSSE SS;
|
||||
const xImplSimd_DestRegSSE SD;
|
||||
};
|
||||
} // namespace x86Emitter
|
||||
|
|
|
@ -21,15 +21,15 @@
|
|||
namespace x86Emitter
|
||||
{
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImpl_IncDec
|
||||
// --------------------------------------------------------------------------------------
|
||||
struct xImpl_IncDec
|
||||
{
|
||||
bool isDec;
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImpl_IncDec
|
||||
// --------------------------------------------------------------------------------------
|
||||
struct xImpl_IncDec
|
||||
{
|
||||
bool isDec;
|
||||
|
||||
void operator()(const xRegisterInt &to) const;
|
||||
void operator()(const xIndirect64orLess &to) const;
|
||||
};
|
||||
void operator()(const xRegisterInt& to) const;
|
||||
void operator()(const xIndirect64orLess& to) const;
|
||||
};
|
||||
|
||||
} // End namespace x86Emitter
|
||||
|
|
|
@ -20,74 +20,75 @@
|
|||
namespace x86Emitter
|
||||
{
|
||||
|
||||
extern void xJccKnownTarget(JccComparisonType comparison, const void *target, bool slideForward);
|
||||
extern void xJccKnownTarget(JccComparisonType comparison, const void* target, bool slideForward);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
struct xImpl_JmpCall
|
||||
{
|
||||
bool isJmp;
|
||||
// ------------------------------------------------------------------------
|
||||
struct xImpl_JmpCall
|
||||
{
|
||||
bool isJmp;
|
||||
|
||||
void operator()(const xAddressReg &absreg) const;
|
||||
void operator()(const xIndirectNative &src) const;
|
||||
void operator()(const xAddressReg& absreg) const;
|
||||
void operator()(const xIndirectNative& src) const;
|
||||
|
||||
// Special form for calling functions. This form automatically resolves the
|
||||
// correct displacement based on the size of the instruction being generated.
|
||||
void operator()(void *func) const
|
||||
{
|
||||
if (isJmp)
|
||||
xJccKnownTarget(Jcc_Unconditional, (void *)(uptr)func, false); // double cast to/from (uptr) needed to appease GCC
|
||||
else {
|
||||
// calls are relative to the instruction after this one, and length is
|
||||
// always 5 bytes (16 bit calls are bad mojo, so no bother to do special logic).
|
||||
// Special form for calling functions. This form automatically resolves the
|
||||
// correct displacement based on the size of the instruction being generated.
|
||||
void operator()(void* func) const
|
||||
{
|
||||
if (isJmp)
|
||||
xJccKnownTarget(Jcc_Unconditional, (void*)(uptr)func, false); // double cast to/from (uptr) needed to appease GCC
|
||||
else
|
||||
{
|
||||
// calls are relative to the instruction after this one, and length is
|
||||
// always 5 bytes (16 bit calls are bad mojo, so no bother to do special logic).
|
||||
|
||||
sptr dest = (sptr)func - ((sptr)xGetPtr() + 5);
|
||||
pxAssertMsg(dest == (s32)dest, "Indirect jump is too far, must use a register!");
|
||||
xWrite8(0xe8);
|
||||
xWrite32(dest);
|
||||
}
|
||||
}
|
||||
};
|
||||
sptr dest = (sptr)func - ((sptr)xGetPtr() + 5);
|
||||
pxAssertMsg(dest == (s32)dest, "Indirect jump is too far, must use a register!");
|
||||
xWrite8(0xe8);
|
||||
xWrite32(dest);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// yes it is awful. Due to template code is in a header with a nice circular dep.
|
||||
extern const xImpl_Mov xMOV;
|
||||
extern const xImpl_JmpCall xCALL;
|
||||
// yes it is awful. Due to template code is in a header with a nice circular dep.
|
||||
extern const xImpl_Mov xMOV;
|
||||
extern const xImpl_JmpCall xCALL;
|
||||
|
||||
struct xImpl_FastCall
|
||||
{
|
||||
// FIXME: current 64 bits is mostly a copy/past potentially it would require to push/pop
|
||||
// some registers. But I think it is enough to handle the first call.
|
||||
struct xImpl_FastCall
|
||||
{
|
||||
// FIXME: current 64 bits is mostly a copy/past potentially it would require to push/pop
|
||||
// some registers. But I think it is enough to handle the first call.
|
||||
|
||||
void operator()(void *f, const xRegister32 &a1 = xEmptyReg, const xRegister32 &a2 = xEmptyReg) const;
|
||||
void operator()(void* f, const xRegister32& a1 = xEmptyReg, const xRegister32& a2 = xEmptyReg) const;
|
||||
|
||||
void operator()(void *f, u32 a1, const xRegister32 &a2) const;
|
||||
void operator()(void *f, const xIndirect32 &a1) const;
|
||||
void operator()(void *f, u32 a1, u32 a2) const;
|
||||
void operator()(void *f, void *a1) const;
|
||||
void operator()(void* f, u32 a1, const xRegister32& a2) const;
|
||||
void operator()(void* f, const xIndirect32& a1) const;
|
||||
void operator()(void* f, u32 a1, u32 a2) const;
|
||||
void operator()(void* f, void* a1) const;
|
||||
|
||||
#ifdef __M_X86_64
|
||||
void operator()(void *f, const xRegisterLong &a1, const xRegisterLong &a2 = xEmptyReg) const;
|
||||
void operator()(void *f, u32 a1, const xRegisterLong &a2) const;
|
||||
void operator()(void* f, const xRegisterLong& a1, const xRegisterLong& a2 = xEmptyReg) const;
|
||||
void operator()(void* f, u32 a1, const xRegisterLong& a2) const;
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
__fi void operator()(T *func, u32 a1, const xRegisterLong &a2 = xEmptyReg) const
|
||||
{
|
||||
(*this)((void *)func, a1, a2);
|
||||
}
|
||||
template <typename T>
|
||||
__fi void operator()(T* func, u32 a1, const xRegisterLong& a2 = xEmptyReg) const
|
||||
{
|
||||
(*this)((void*)func, a1, a2);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
__fi void operator()(T *func, const xIndirect32 &a1) const
|
||||
{
|
||||
(*this)((void*)func, a1);
|
||||
}
|
||||
template <typename T>
|
||||
__fi void operator()(T* func, const xIndirect32& a1) const
|
||||
{
|
||||
(*this)((void*)func, a1);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
__fi void operator()(T *func, u32 a1, u32 a2) const
|
||||
{
|
||||
(*this)((void*)func, a1, a2);
|
||||
}
|
||||
template <typename T>
|
||||
__fi void operator()(T* func, u32 a1, u32 a2) const
|
||||
{
|
||||
(*this)((void*)func, a1, a2);
|
||||
}
|
||||
|
||||
void operator()(const xIndirectNative &f, const xRegisterLong &a1 = xEmptyReg, const xRegisterLong &a2 = xEmptyReg) const;
|
||||
};
|
||||
void operator()(const xIndirectNative& f, const xRegisterLong& a1 = xEmptyReg, const xRegisterLong& a2 = xEmptyReg) const;
|
||||
};
|
||||
|
||||
} // End namespace x86Emitter
|
||||
|
|
|
@ -21,20 +21,20 @@
|
|||
namespace x86Emitter
|
||||
{
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// MovImplAll
|
||||
// --------------------------------------------------------------------------------------
|
||||
// MOV instruction Implementation, plus many SIMD sub-mov variants.
|
||||
//
|
||||
struct xImpl_Mov
|
||||
{
|
||||
xImpl_Mov() {} // Satisfy GCC's whims.
|
||||
// --------------------------------------------------------------------------------------
|
||||
// MovImplAll
|
||||
// --------------------------------------------------------------------------------------
|
||||
// MOV instruction Implementation, plus many SIMD sub-mov variants.
|
||||
//
|
||||
struct xImpl_Mov
|
||||
{
|
||||
xImpl_Mov() {} // Satisfy GCC's whims.
|
||||
|
||||
void operator()(const xRegisterInt &to, const xRegisterInt &from) const;
|
||||
void operator()(const xIndirectVoid &dest, const xRegisterInt &from) const;
|
||||
void operator()(const xRegisterInt &to, const xIndirectVoid &src) const;
|
||||
void operator()(const xIndirect64orLess &dest, sptr imm) const;
|
||||
void operator()(const xRegisterInt &to, sptr imm, bool preserve_flags = false) const;
|
||||
void operator()(const xRegisterInt& to, const xRegisterInt& from) const;
|
||||
void operator()(const xIndirectVoid& dest, const xRegisterInt& from) const;
|
||||
void operator()(const xRegisterInt& to, const xIndirectVoid& src) const;
|
||||
void operator()(const xIndirect64orLess& dest, sptr imm) const;
|
||||
void operator()(const xRegisterInt& to, sptr imm, bool preserve_flags = false) const;
|
||||
|
||||
#if 0
|
||||
template< typename T > __noinline void operator()( const ModSibBase& to, const xImmReg<T>& immOrReg ) const
|
||||
|
@ -68,73 +68,73 @@ struct xImpl_Mov
|
|||
_DoI_helpermess( *this, to, xDirectOrIndirect<T>( from ) );
|
||||
}*/
|
||||
#endif
|
||||
};
|
||||
};
|
||||
|
||||
#ifdef __M_X86_64
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImpl_MovImm64
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Mov with 64-bit immediates (only available on 64-bit platforms)
|
||||
//
|
||||
struct xImpl_MovImm64
|
||||
{
|
||||
xImpl_MovImm64() {} // Satisfy GCC's whims.
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImpl_MovImm64
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Mov with 64-bit immediates (only available on 64-bit platforms)
|
||||
//
|
||||
struct xImpl_MovImm64
|
||||
{
|
||||
xImpl_MovImm64() {} // Satisfy GCC's whims.
|
||||
|
||||
void operator()(const xRegister64 &to, s64 imm, bool preserve_flags = false) const;
|
||||
};
|
||||
void operator()(const xRegister64& to, s64 imm, bool preserve_flags = false) const;
|
||||
};
|
||||
#endif
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImpl_CMov
|
||||
// --------------------------------------------------------------------------------------
|
||||
// CMOVcc !! [in all of it's disappointing lack-of glory] .. and ..
|
||||
// SETcc !! [more glory, less lack!]
|
||||
//
|
||||
// CMOV Disclaimer: Caution! This instruction can look exciting and cool, until you
|
||||
// realize that it cannot load immediate values into registers. -_-
|
||||
//
|
||||
// I use explicit method declarations here instead of templates, in order to provide
|
||||
// *only* 32 and 16 bit register operand forms (8 bit registers are not valid in CMOV).
|
||||
//
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImpl_CMov
|
||||
// --------------------------------------------------------------------------------------
|
||||
// CMOVcc !! [in all of it's disappointing lack-of glory] .. and ..
|
||||
// SETcc !! [more glory, less lack!]
|
||||
//
|
||||
// CMOV Disclaimer: Caution! This instruction can look exciting and cool, until you
|
||||
// realize that it cannot load immediate values into registers. -_-
|
||||
//
|
||||
// I use explicit method declarations here instead of templates, in order to provide
|
||||
// *only* 32 and 16 bit register operand forms (8 bit registers are not valid in CMOV).
|
||||
//
|
||||
|
||||
struct xImpl_CMov
|
||||
{
|
||||
JccComparisonType ccType;
|
||||
void operator()(const xRegister16or32or64 &to, const xRegister16or32or64 &from) const;
|
||||
void operator()(const xRegister16or32or64 &to, const xIndirectVoid &sibsrc) const;
|
||||
struct xImpl_CMov
|
||||
{
|
||||
JccComparisonType ccType;
|
||||
void operator()(const xRegister16or32or64& to, const xRegister16or32or64& from) const;
|
||||
void operator()(const xRegister16or32or64& to, const xIndirectVoid& sibsrc) const;
|
||||
|
||||
//void operator()( const xDirectOrIndirect32& to, const xDirectOrIndirect32& from );
|
||||
//void operator()( const xDirectOrIndirect16& to, const xDirectOrIndirect16& from ) const;
|
||||
};
|
||||
//void operator()( const xDirectOrIndirect32& to, const xDirectOrIndirect32& from );
|
||||
//void operator()( const xDirectOrIndirect16& to, const xDirectOrIndirect16& from ) const;
|
||||
};
|
||||
|
||||
struct xImpl_Set
|
||||
{
|
||||
JccComparisonType ccType;
|
||||
struct xImpl_Set
|
||||
{
|
||||
JccComparisonType ccType;
|
||||
|
||||
void operator()(const xRegister8 &to) const;
|
||||
void operator()(const xIndirect8 &dest) const;
|
||||
void operator()(const xRegister8& to) const;
|
||||
void operator()(const xIndirect8& dest) const;
|
||||
|
||||
//void operator()( const xDirectOrIndirect8& dest ) const;
|
||||
};
|
||||
//void operator()( const xDirectOrIndirect8& dest ) const;
|
||||
};
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImpl_MovExtend
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Mov with sign/zero extension implementations (movsx / movzx)
|
||||
//
|
||||
struct xImpl_MovExtend
|
||||
{
|
||||
bool SignExtend;
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImpl_MovExtend
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Mov with sign/zero extension implementations (movsx / movzx)
|
||||
//
|
||||
struct xImpl_MovExtend
|
||||
{
|
||||
bool SignExtend;
|
||||
|
||||
void operator()(const xRegister16or32or64 &to, const xRegister8 &from) const;
|
||||
void operator()(const xRegister16or32or64 &to, const xIndirect8 &sibsrc) const;
|
||||
void operator()(const xRegister32or64 &to, const xRegister16 &from) const;
|
||||
void operator()(const xRegister32or64 &to, const xIndirect16 &sibsrc) const;
|
||||
void operator()(const xRegister16or32or64& to, const xRegister8& from) const;
|
||||
void operator()(const xRegister16or32or64& to, const xIndirect8& sibsrc) const;
|
||||
void operator()(const xRegister32or64& to, const xRegister16& from) const;
|
||||
void operator()(const xRegister32or64& to, const xIndirect16& sibsrc) const;
|
||||
|
||||
//void operator()( const xRegister32& to, const xDirectOrIndirect16& src ) const;
|
||||
//void operator()( const xRegister16or32& to, const xDirectOrIndirect8& src ) const;
|
||||
//void operator()( const xRegister16& to, const xDirectOrIndirect8& src ) const;
|
||||
};
|
||||
//void operator()( const xRegister32& to, const xDirectOrIndirect16& src ) const;
|
||||
//void operator()( const xRegister16or32& to, const xDirectOrIndirect8& src ) const;
|
||||
//void operator()( const xRegister16& to, const xDirectOrIndirect8& src ) const;
|
||||
};
|
||||
|
||||
} // End namespace x86Emitter
|
||||
|
|
|
@ -18,299 +18,299 @@
|
|||
namespace x86Emitter
|
||||
{
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// _SimdShiftHelper
|
||||
// --------------------------------------------------------------------------------------
|
||||
struct _SimdShiftHelper
|
||||
{
|
||||
u8 Prefix;
|
||||
u16 Opcode;
|
||||
u16 OpcodeImm;
|
||||
u8 Modcode;
|
||||
// --------------------------------------------------------------------------------------
|
||||
// _SimdShiftHelper
|
||||
// --------------------------------------------------------------------------------------
|
||||
struct _SimdShiftHelper
|
||||
{
|
||||
u8 Prefix;
|
||||
u16 Opcode;
|
||||
u16 OpcodeImm;
|
||||
u8 Modcode;
|
||||
|
||||
void operator()(const xRegisterSSE &to, const xRegisterSSE &from) const;
|
||||
void operator()(const xRegisterSSE &to, const xIndirectVoid &from) const;
|
||||
void operator()(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||
void operator()(const xRegisterSSE& to, const xIndirectVoid& from) const;
|
||||
|
||||
void operator()(const xRegisterSSE &to, u8 imm8) const;
|
||||
};
|
||||
void operator()(const xRegisterSSE& to, u8 imm8) const;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImplSimd_Shift / xImplSimd_ShiftWithoutQ
|
||||
// --------------------------------------------------------------------------------------
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImplSimd_Shift / xImplSimd_ShiftWithoutQ
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
// Used for PSRA, which lacks the Q form.
|
||||
//
|
||||
struct xImplSimd_ShiftWithoutQ
|
||||
{
|
||||
const _SimdShiftHelper W;
|
||||
const _SimdShiftHelper D;
|
||||
};
|
||||
// Used for PSRA, which lacks the Q form.
|
||||
//
|
||||
struct xImplSimd_ShiftWithoutQ
|
||||
{
|
||||
const _SimdShiftHelper W;
|
||||
const _SimdShiftHelper D;
|
||||
};
|
||||
|
||||
// Implements PSRL and PSLL
|
||||
//
|
||||
struct xImplSimd_Shift
|
||||
{
|
||||
const _SimdShiftHelper W;
|
||||
const _SimdShiftHelper D;
|
||||
const _SimdShiftHelper Q;
|
||||
// Implements PSRL and PSLL
|
||||
//
|
||||
struct xImplSimd_Shift
|
||||
{
|
||||
const _SimdShiftHelper W;
|
||||
const _SimdShiftHelper D;
|
||||
const _SimdShiftHelper Q;
|
||||
|
||||
void DQ(const xRegisterSSE &to, u8 imm8) const;
|
||||
};
|
||||
void DQ(const xRegisterSSE& to, u8 imm8) const;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
struct xImplSimd_AddSub
|
||||
{
|
||||
const xImplSimd_DestRegEither B;
|
||||
const xImplSimd_DestRegEither W;
|
||||
const xImplSimd_DestRegEither D;
|
||||
const xImplSimd_DestRegEither Q;
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
struct xImplSimd_AddSub
|
||||
{
|
||||
const xImplSimd_DestRegEither B;
|
||||
const xImplSimd_DestRegEither W;
|
||||
const xImplSimd_DestRegEither D;
|
||||
const xImplSimd_DestRegEither Q;
|
||||
|
||||
// Add/Sub packed signed byte [8bit] integers from src into dest, and saturate the results.
|
||||
const xImplSimd_DestRegEither SB;
|
||||
// Add/Sub packed signed byte [8bit] integers from src into dest, and saturate the results.
|
||||
const xImplSimd_DestRegEither SB;
|
||||
|
||||
// Add/Sub packed signed word [16bit] integers from src into dest, and saturate the results.
|
||||
const xImplSimd_DestRegEither SW;
|
||||
// Add/Sub packed signed word [16bit] integers from src into dest, and saturate the results.
|
||||
const xImplSimd_DestRegEither SW;
|
||||
|
||||
// Add/Sub packed unsigned byte [8bit] integers from src into dest, and saturate the results.
|
||||
const xImplSimd_DestRegEither USB;
|
||||
// Add/Sub packed unsigned byte [8bit] integers from src into dest, and saturate the results.
|
||||
const xImplSimd_DestRegEither USB;
|
||||
|
||||
// Add/Sub packed unsigned word [16bit] integers from src into dest, and saturate the results.
|
||||
const xImplSimd_DestRegEither USW;
|
||||
};
|
||||
// Add/Sub packed unsigned word [16bit] integers from src into dest, and saturate the results.
|
||||
const xImplSimd_DestRegEither USW;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
struct xImplSimd_PMul
|
||||
{
|
||||
const xImplSimd_DestRegEither LW;
|
||||
const xImplSimd_DestRegEither HW;
|
||||
const xImplSimd_DestRegEither HUW;
|
||||
const xImplSimd_DestRegEither UDQ;
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
struct xImplSimd_PMul
|
||||
{
|
||||
const xImplSimd_DestRegEither LW;
|
||||
const xImplSimd_DestRegEither HW;
|
||||
const xImplSimd_DestRegEither HUW;
|
||||
const xImplSimd_DestRegEither UDQ;
|
||||
|
||||
// [SSE-3] PMULHRSW multiplies vertically each signed 16-bit integer from dest with the
|
||||
// corresponding signed 16-bit integer of source, producing intermediate signed 32-bit
|
||||
// integers. Each intermediate 32-bit integer is truncated to the 18 most significant
|
||||
// bits. Rounding is always performed by adding 1 to the least significant bit of the
|
||||
// 18-bit intermediate result. The final result is obtained by selecting the 16 bits
|
||||
// immediately to the right of the most significant bit of each 18-bit intermediate
|
||||
// result and packed to the destination operand.
|
||||
//
|
||||
// Both operands can be MMX or XMM registers. Source can be register or memory.
|
||||
//
|
||||
const xImplSimd_DestRegEither HRSW;
|
||||
// [SSE-3] PMULHRSW multiplies vertically each signed 16-bit integer from dest with the
|
||||
// corresponding signed 16-bit integer of source, producing intermediate signed 32-bit
|
||||
// integers. Each intermediate 32-bit integer is truncated to the 18 most significant
|
||||
// bits. Rounding is always performed by adding 1 to the least significant bit of the
|
||||
// 18-bit intermediate result. The final result is obtained by selecting the 16 bits
|
||||
// immediately to the right of the most significant bit of each 18-bit intermediate
|
||||
// result and packed to the destination operand.
|
||||
//
|
||||
// Both operands can be MMX or XMM registers. Source can be register or memory.
|
||||
//
|
||||
const xImplSimd_DestRegEither HRSW;
|
||||
|
||||
// [SSE-4.1] Multiply the packed dword signed integers in dest with src, and store
|
||||
// the low 32 bits of each product in xmm1.
|
||||
const xImplSimd_DestRegSSE LD;
|
||||
// [SSE-4.1] Multiply the packed dword signed integers in dest with src, and store
|
||||
// the low 32 bits of each product in xmm1.
|
||||
const xImplSimd_DestRegSSE LD;
|
||||
|
||||
// [SSE-4.1] Multiply the packed signed dword integers in dest with src.
|
||||
const xImplSimd_DestRegSSE DQ;
|
||||
};
|
||||
// [SSE-4.1] Multiply the packed signed dword integers in dest with src.
|
||||
const xImplSimd_DestRegSSE DQ;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// For instructions that have PS/SS form only (most commonly reciprocal Sqrt functions)
|
||||
//
|
||||
struct xImplSimd_rSqrt
|
||||
{
|
||||
const xImplSimd_DestRegSSE PS;
|
||||
const xImplSimd_DestRegSSE SS;
|
||||
};
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// For instructions that have PS/SS form only (most commonly reciprocal Sqrt functions)
|
||||
//
|
||||
struct xImplSimd_rSqrt
|
||||
{
|
||||
const xImplSimd_DestRegSSE PS;
|
||||
const xImplSimd_DestRegSSE SS;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// SQRT has PS/SS/SD forms, but not the PD form.
|
||||
//
|
||||
struct xImplSimd_Sqrt
|
||||
{
|
||||
const xImplSimd_DestRegSSE PS;
|
||||
const xImplSimd_DestRegSSE SS;
|
||||
const xImplSimd_DestRegSSE SD;
|
||||
};
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// SQRT has PS/SS/SD forms, but not the PD form.
|
||||
//
|
||||
struct xImplSimd_Sqrt
|
||||
{
|
||||
const xImplSimd_DestRegSSE PS;
|
||||
const xImplSimd_DestRegSSE SS;
|
||||
const xImplSimd_DestRegSSE SD;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
struct xImplSimd_AndNot
|
||||
{
|
||||
const xImplSimd_DestRegSSE PS;
|
||||
const xImplSimd_DestRegSSE PD;
|
||||
};
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
struct xImplSimd_AndNot
|
||||
{
|
||||
const xImplSimd_DestRegSSE PS;
|
||||
const xImplSimd_DestRegSSE PD;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Packed absolute value. [sSSE3 only]
|
||||
//
|
||||
struct xImplSimd_PAbsolute
|
||||
{
|
||||
// [sSSE-3] Computes the absolute value of bytes in the src, and stores the result
|
||||
// in dest, as UNSIGNED.
|
||||
const xImplSimd_DestRegEither B;
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Packed absolute value. [sSSE3 only]
|
||||
//
|
||||
struct xImplSimd_PAbsolute
|
||||
{
|
||||
// [sSSE-3] Computes the absolute value of bytes in the src, and stores the result
|
||||
// in dest, as UNSIGNED.
|
||||
const xImplSimd_DestRegEither B;
|
||||
|
||||
// [sSSE-3] Computes the absolute value of word in the src, and stores the result
|
||||
// in dest, as UNSIGNED.
|
||||
const xImplSimd_DestRegEither W;
|
||||
// [sSSE-3] Computes the absolute value of word in the src, and stores the result
|
||||
// in dest, as UNSIGNED.
|
||||
const xImplSimd_DestRegEither W;
|
||||
|
||||
// [sSSE-3] Computes the absolute value of doublewords in the src, and stores the
|
||||
// result in dest, as UNSIGNED.
|
||||
const xImplSimd_DestRegEither D;
|
||||
};
|
||||
// [sSSE-3] Computes the absolute value of doublewords in the src, and stores the
|
||||
// result in dest, as UNSIGNED.
|
||||
const xImplSimd_DestRegEither D;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Packed Sign [sSSE3 only] - Negate/zero/preserve packed integers in dest depending on the
|
||||
// corresponding sign in src.
|
||||
//
|
||||
struct xImplSimd_PSign
|
||||
{
|
||||
// [sSSE-3] negates each byte element of dest if the signed integer value of the
|
||||
// corresponding data element in src is less than zero. If the signed integer value
|
||||
// of a data element in src is positive, the corresponding data element in dest is
|
||||
// unchanged. If a data element in src is zero, the corresponding data element in
|
||||
// dest is set to zero.
|
||||
const xImplSimd_DestRegEither B;
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Packed Sign [sSSE3 only] - Negate/zero/preserve packed integers in dest depending on the
|
||||
// corresponding sign in src.
|
||||
//
|
||||
struct xImplSimd_PSign
|
||||
{
|
||||
// [sSSE-3] negates each byte element of dest if the signed integer value of the
|
||||
// corresponding data element in src is less than zero. If the signed integer value
|
||||
// of a data element in src is positive, the corresponding data element in dest is
|
||||
// unchanged. If a data element in src is zero, the corresponding data element in
|
||||
// dest is set to zero.
|
||||
const xImplSimd_DestRegEither B;
|
||||
|
||||
// [sSSE-3] negates each word element of dest if the signed integer value of the
|
||||
// corresponding data element in src is less than zero. If the signed integer value
|
||||
// of a data element in src is positive, the corresponding data element in dest is
|
||||
// unchanged. If a data element in src is zero, the corresponding data element in
|
||||
// dest is set to zero.
|
||||
const xImplSimd_DestRegEither W;
|
||||
// [sSSE-3] negates each word element of dest if the signed integer value of the
|
||||
// corresponding data element in src is less than zero. If the signed integer value
|
||||
// of a data element in src is positive, the corresponding data element in dest is
|
||||
// unchanged. If a data element in src is zero, the corresponding data element in
|
||||
// dest is set to zero.
|
||||
const xImplSimd_DestRegEither W;
|
||||
|
||||
// [sSSE-3] negates each doubleword element of dest if the signed integer value
|
||||
// of the corresponding data element in src is less than zero. If the signed integer
|
||||
// value of a data element in src is positive, the corresponding data element in dest
|
||||
// is unchanged. If a data element in src is zero, the corresponding data element in
|
||||
// dest is set to zero.
|
||||
const xImplSimd_DestRegEither D;
|
||||
};
|
||||
// [sSSE-3] negates each doubleword element of dest if the signed integer value
|
||||
// of the corresponding data element in src is less than zero. If the signed integer
|
||||
// value of a data element in src is positive, the corresponding data element in dest
|
||||
// is unchanged. If a data element in src is zero, the corresponding data element in
|
||||
// dest is set to zero.
|
||||
const xImplSimd_DestRegEither D;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Packed Multiply and Add!!
|
||||
//
|
||||
struct xImplSimd_PMultAdd
|
||||
{
|
||||
// Multiplies the individual signed words of dest by the corresponding signed words
|
||||
// of src, producing temporary signed, doubleword results. The adjacent doubleword
|
||||
// results are then summed and stored in the destination operand.
|
||||
//
|
||||
// DEST[31:0] = ( DEST[15:0] * SRC[15:0]) + (DEST[31:16] * SRC[31:16] );
|
||||
// DEST[63:32] = ( DEST[47:32] * SRC[47:32]) + (DEST[63:48] * SRC[63:48] );
|
||||
// [.. repeat in the case of XMM src/dest operands ..]
|
||||
//
|
||||
const xImplSimd_DestRegEither WD;
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Packed Multiply and Add!!
|
||||
//
|
||||
struct xImplSimd_PMultAdd
|
||||
{
|
||||
// Multiplies the individual signed words of dest by the corresponding signed words
|
||||
// of src, producing temporary signed, doubleword results. The adjacent doubleword
|
||||
// results are then summed and stored in the destination operand.
|
||||
//
|
||||
// DEST[31:0] = ( DEST[15:0] * SRC[15:0]) + (DEST[31:16] * SRC[31:16] );
|
||||
// DEST[63:32] = ( DEST[47:32] * SRC[47:32]) + (DEST[63:48] * SRC[63:48] );
|
||||
// [.. repeat in the case of XMM src/dest operands ..]
|
||||
//
|
||||
const xImplSimd_DestRegEither WD;
|
||||
|
||||
// [sSSE-3] multiplies vertically each unsigned byte of dest with the corresponding
|
||||
// signed byte of src, producing intermediate signed 16-bit integers. Each adjacent
|
||||
// pair of signed words is added and the saturated result is packed to dest.
|
||||
// For example, the lowest-order bytes (bits 7-0) in src and dest are multiplied
|
||||
// and the intermediate signed word result is added with the corresponding
|
||||
// intermediate result from the 2nd lowest-order bytes (bits 15-8) of the operands;
|
||||
// the sign-saturated result is stored in the lowest word of dest (bits 15-0).
|
||||
// The same operation is performed on the other pairs of adjacent bytes.
|
||||
//
|
||||
// In Coder Speak:
|
||||
// DEST[15-0] = SaturateToSignedWord( SRC[15-8] * DEST[15-8] + SRC[7-0] * DEST[7-0] );
|
||||
// DEST[31-16] = SaturateToSignedWord( SRC[31-24] * DEST[31-24] + SRC[23-16] * DEST[23-16] );
|
||||
// [.. repeat for each 16 bits up to 64 (mmx) or 128 (xmm) ..]
|
||||
//
|
||||
const xImplSimd_DestRegEither UBSW;
|
||||
};
|
||||
// [sSSE-3] multiplies vertically each unsigned byte of dest with the corresponding
|
||||
// signed byte of src, producing intermediate signed 16-bit integers. Each adjacent
|
||||
// pair of signed words is added and the saturated result is packed to dest.
|
||||
// For example, the lowest-order bytes (bits 7-0) in src and dest are multiplied
|
||||
// and the intermediate signed word result is added with the corresponding
|
||||
// intermediate result from the 2nd lowest-order bytes (bits 15-8) of the operands;
|
||||
// the sign-saturated result is stored in the lowest word of dest (bits 15-0).
|
||||
// The same operation is performed on the other pairs of adjacent bytes.
|
||||
//
|
||||
// In Coder Speak:
|
||||
// DEST[15-0] = SaturateToSignedWord( SRC[15-8] * DEST[15-8] + SRC[7-0] * DEST[7-0] );
|
||||
// DEST[31-16] = SaturateToSignedWord( SRC[31-24] * DEST[31-24] + SRC[23-16] * DEST[23-16] );
|
||||
// [.. repeat for each 16 bits up to 64 (mmx) or 128 (xmm) ..]
|
||||
//
|
||||
const xImplSimd_DestRegEither UBSW;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Packed Horizontal Add [SSE3 only]
|
||||
//
|
||||
struct xImplSimd_HorizAdd
|
||||
{
|
||||
// [SSE-3] Horizontal Add of Packed Data. A three step process:
|
||||
// * Adds the single-precision floating-point values in the first and second dwords of
|
||||
// dest and stores the result in the first dword of dest.
|
||||
// * Adds single-precision floating-point values in the third and fourth dword of dest
|
||||
// stores the result in the second dword of dest.
|
||||
// * Adds single-precision floating-point values in the first and second dword of *src*
|
||||
// and stores the result in the third dword of dest.
|
||||
const xImplSimd_DestRegSSE PS;
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Packed Horizontal Add [SSE3 only]
|
||||
//
|
||||
struct xImplSimd_HorizAdd
|
||||
{
|
||||
// [SSE-3] Horizontal Add of Packed Data. A three step process:
|
||||
// * Adds the single-precision floating-point values in the first and second dwords of
|
||||
// dest and stores the result in the first dword of dest.
|
||||
// * Adds single-precision floating-point values in the third and fourth dword of dest
|
||||
// stores the result in the second dword of dest.
|
||||
// * Adds single-precision floating-point values in the first and second dword of *src*
|
||||
// and stores the result in the third dword of dest.
|
||||
const xImplSimd_DestRegSSE PS;
|
||||
|
||||
// [SSE-3] Horizontal Add of Packed Data. A two step process:
|
||||
// * Adds the double-precision floating-point values in the high and low quadwords of
|
||||
// dest and stores the result in the low quadword of dest.
|
||||
// * Adds the double-precision floating-point values in the high and low quadwords of
|
||||
// *src* stores the result in the high quadword of dest.
|
||||
const xImplSimd_DestRegSSE PD;
|
||||
};
|
||||
// [SSE-3] Horizontal Add of Packed Data. A two step process:
|
||||
// * Adds the double-precision floating-point values in the high and low quadwords of
|
||||
// dest and stores the result in the low quadword of dest.
|
||||
// * Adds the double-precision floating-point values in the high and low quadwords of
|
||||
// *src* stores the result in the high quadword of dest.
|
||||
const xImplSimd_DestRegSSE PD;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// DotProduct calculation (SSE4.1 only!)
|
||||
//
|
||||
struct xImplSimd_DotProduct
|
||||
{
|
||||
// [SSE-4.1] Conditionally multiplies the packed single precision floating-point
|
||||
// values in dest with the packed single-precision floats in src depending on a
|
||||
// mask extracted from the high 4 bits of the immediate byte. If a condition mask
|
||||
// bit in Imm8[7:4] is zero, the corresponding multiplication is replaced by a value
|
||||
// of 0.0. The four resulting single-precision values are summed into an inter-
|
||||
// mediate result.
|
||||
//
|
||||
// The intermediate result is conditionally broadcasted to the destination using a
|
||||
// broadcast mask specified by bits [3:0] of the immediate byte. If a broadcast
|
||||
// mask bit is 1, the intermediate result is copied to the corresponding dword
|
||||
// element in dest. If a broadcast mask bit is zero, the corresponding element in
|
||||
// the destination is set to zero.
|
||||
//
|
||||
xImplSimd_DestRegImmSSE PS;
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// DotProduct calculation (SSE4.1 only!)
|
||||
//
|
||||
struct xImplSimd_DotProduct
|
||||
{
|
||||
// [SSE-4.1] Conditionally multiplies the packed single precision floating-point
|
||||
// values in dest with the packed single-precision floats in src depending on a
|
||||
// mask extracted from the high 4 bits of the immediate byte. If a condition mask
|
||||
// bit in Imm8[7:4] is zero, the corresponding multiplication is replaced by a value
|
||||
// of 0.0. The four resulting single-precision values are summed into an inter-
|
||||
// mediate result.
|
||||
//
|
||||
// The intermediate result is conditionally broadcasted to the destination using a
|
||||
// broadcast mask specified by bits [3:0] of the immediate byte. If a broadcast
|
||||
// mask bit is 1, the intermediate result is copied to the corresponding dword
|
||||
// element in dest. If a broadcast mask bit is zero, the corresponding element in
|
||||
// the destination is set to zero.
|
||||
//
|
||||
xImplSimd_DestRegImmSSE PS;
|
||||
|
||||
// [SSE-4.1]
|
||||
xImplSimd_DestRegImmSSE PD;
|
||||
};
|
||||
// [SSE-4.1]
|
||||
xImplSimd_DestRegImmSSE PD;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Rounds floating point values (packed or single scalar) by an arbitrary rounding mode.
|
||||
// (SSE4.1 only!)
|
||||
struct xImplSimd_Round
|
||||
{
|
||||
// [SSE-4.1] Rounds the 4 packed single-precision src values and stores them in dest.
|
||||
//
|
||||
// Imm8 specifies control fields for the rounding operation:
|
||||
// Bit 3 - processor behavior for a precision exception (0: normal, 1: inexact)
|
||||
// Bit 2 - If enabled, use MXCSR.RC, else use RC specified in bits 1:0 of this Imm8.
|
||||
// Bits 1:0 - Specifies a rounding mode for this instruction only.
|
||||
//
|
||||
// Rounding Mode Reference:
|
||||
// 0 - Nearest, 1 - Negative Infinity, 2 - Positive infinity, 3 - Truncate.
|
||||
//
|
||||
const xImplSimd_DestRegImmSSE PS;
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Rounds floating point values (packed or single scalar) by an arbitrary rounding mode.
|
||||
// (SSE4.1 only!)
|
||||
struct xImplSimd_Round
|
||||
{
|
||||
// [SSE-4.1] Rounds the 4 packed single-precision src values and stores them in dest.
|
||||
//
|
||||
// Imm8 specifies control fields for the rounding operation:
|
||||
// Bit 3 - processor behavior for a precision exception (0: normal, 1: inexact)
|
||||
// Bit 2 - If enabled, use MXCSR.RC, else use RC specified in bits 1:0 of this Imm8.
|
||||
// Bits 1:0 - Specifies a rounding mode for this instruction only.
|
||||
//
|
||||
// Rounding Mode Reference:
|
||||
// 0 - Nearest, 1 - Negative Infinity, 2 - Positive infinity, 3 - Truncate.
|
||||
//
|
||||
const xImplSimd_DestRegImmSSE PS;
|
||||
|
||||
// [SSE-4.1] Rounds the 2 packed double-precision src values and stores them in dest.
|
||||
//
|
||||
// Imm8 specifies control fields for the rounding operation:
|
||||
// Bit 3 - processor behavior for a precision exception (0: normal, 1: inexact)
|
||||
// Bit 2 - If enabled, use MXCSR.RC, else use RC specified in bits 1:0 of this Imm8.
|
||||
// Bits 1:0 - Specifies a rounding mode for this instruction only.
|
||||
//
|
||||
// Rounding Mode Reference:
|
||||
// 0 - Nearest, 1 - Negative Infinity, 2 - Positive infinity, 3 - Truncate.
|
||||
//
|
||||
const xImplSimd_DestRegImmSSE PD;
|
||||
// [SSE-4.1] Rounds the 2 packed double-precision src values and stores them in dest.
|
||||
//
|
||||
// Imm8 specifies control fields for the rounding operation:
|
||||
// Bit 3 - processor behavior for a precision exception (0: normal, 1: inexact)
|
||||
// Bit 2 - If enabled, use MXCSR.RC, else use RC specified in bits 1:0 of this Imm8.
|
||||
// Bits 1:0 - Specifies a rounding mode for this instruction only.
|
||||
//
|
||||
// Rounding Mode Reference:
|
||||
// 0 - Nearest, 1 - Negative Infinity, 2 - Positive infinity, 3 - Truncate.
|
||||
//
|
||||
const xImplSimd_DestRegImmSSE PD;
|
||||
|
||||
// [SSE-4.1] Rounds the single-precision src value and stores in dest.
|
||||
//
|
||||
// Imm8 specifies control fields for the rounding operation:
|
||||
// Bit 3 - processor behavior for a precision exception (0: normal, 1: inexact)
|
||||
// Bit 2 - If enabled, use MXCSR.RC, else use RC specified in bits 1:0 of this Imm8.
|
||||
// Bits 1:0 - Specifies a rounding mode for this instruction only.
|
||||
//
|
||||
// Rounding Mode Reference:
|
||||
// 0 - Nearest, 1 - Negative Infinity, 2 - Positive infinity, 3 - Truncate.
|
||||
//
|
||||
const xImplSimd_DestRegImmSSE SS;
|
||||
// [SSE-4.1] Rounds the single-precision src value and stores in dest.
|
||||
//
|
||||
// Imm8 specifies control fields for the rounding operation:
|
||||
// Bit 3 - processor behavior for a precision exception (0: normal, 1: inexact)
|
||||
// Bit 2 - If enabled, use MXCSR.RC, else use RC specified in bits 1:0 of this Imm8.
|
||||
// Bits 1:0 - Specifies a rounding mode for this instruction only.
|
||||
//
|
||||
// Rounding Mode Reference:
|
||||
// 0 - Nearest, 1 - Negative Infinity, 2 - Positive infinity, 3 - Truncate.
|
||||
//
|
||||
const xImplSimd_DestRegImmSSE SS;
|
||||
|
||||
// [SSE-4.1] Rounds the double-precision src value and stores in dest.
|
||||
//
|
||||
// Imm8 specifies control fields for the rounding operation:
|
||||
// Bit 3 - processor behavior for a precision exception (0: normal, 1: inexact)
|
||||
// Bit 2 - If enabled, use MXCSR.RC, else use RC specified in bits 1:0 of this Imm8.
|
||||
// Bits 1:0 - Specifies a rounding mode for this instruction only.
|
||||
//
|
||||
// Rounding Mode Reference:
|
||||
// 0 - Nearest, 1 - Negative Infinity, 2 - Positive infinity, 3 - Truncate.
|
||||
//
|
||||
const xImplSimd_DestRegImmSSE SD;
|
||||
};
|
||||
// [SSE-4.1] Rounds the double-precision src value and stores in dest.
|
||||
//
|
||||
// Imm8 specifies control fields for the rounding operation:
|
||||
// Bit 3 - processor behavior for a precision exception (0: normal, 1: inexact)
|
||||
// Bit 2 - If enabled, use MXCSR.RC, else use RC specified in bits 1:0 of this Imm8.
|
||||
// Bits 1:0 - Specifies a rounding mode for this instruction only.
|
||||
//
|
||||
// Rounding Mode Reference:
|
||||
// 0 - Nearest, 1 - Negative Infinity, 2 - Positive infinity, 3 - Truncate.
|
||||
//
|
||||
const xImplSimd_DestRegImmSSE SD;
|
||||
};
|
||||
|
||||
} // End namespace x86Emitter
|
||||
|
|
|
@ -18,106 +18,106 @@
|
|||
namespace x86Emitter
|
||||
{
|
||||
|
||||
struct xImplSimd_MinMax
|
||||
{
|
||||
const xImplSimd_DestRegSSE PS; // packed single precision
|
||||
const xImplSimd_DestRegSSE PD; // packed double precision
|
||||
const xImplSimd_DestRegSSE SS; // scalar single precision
|
||||
const xImplSimd_DestRegSSE SD; // scalar double precision
|
||||
};
|
||||
struct xImplSimd_MinMax
|
||||
{
|
||||
const xImplSimd_DestRegSSE PS; // packed single precision
|
||||
const xImplSimd_DestRegSSE PD; // packed double precision
|
||||
const xImplSimd_DestRegSSE SS; // scalar single precision
|
||||
const xImplSimd_DestRegSSE SD; // scalar double precision
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
struct xImplSimd_Compare
|
||||
{
|
||||
SSE2_ComparisonType CType;
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
struct xImplSimd_Compare
|
||||
{
|
||||
SSE2_ComparisonType CType;
|
||||
|
||||
void PS(const xRegisterSSE &to, const xRegisterSSE &from) const;
|
||||
void PS(const xRegisterSSE &to, const xIndirectVoid &from) const;
|
||||
void PS(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||
void PS(const xRegisterSSE& to, const xIndirectVoid& from) const;
|
||||
|
||||
void PD(const xRegisterSSE &to, const xRegisterSSE &from) const;
|
||||
void PD(const xRegisterSSE &to, const xIndirectVoid &from) const;
|
||||
void PD(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||
void PD(const xRegisterSSE& to, const xIndirectVoid& from) const;
|
||||
|
||||
void SS(const xRegisterSSE &to, const xRegisterSSE &from) const;
|
||||
void SS(const xRegisterSSE &to, const xIndirectVoid &from) const;
|
||||
void SS(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||
void SS(const xRegisterSSE& to, const xIndirectVoid& from) const;
|
||||
|
||||
void SD(const xRegisterSSE &to, const xRegisterSSE &from) const;
|
||||
void SD(const xRegisterSSE &to, const xIndirectVoid &from) const;
|
||||
};
|
||||
void SD(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||
void SD(const xRegisterSSE& to, const xIndirectVoid& from) const;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Compare scalar floating point values and set EFLAGS (Ordered or Unordered)
|
||||
//
|
||||
struct xImplSimd_COMI
|
||||
{
|
||||
const xImplSimd_DestRegSSE SS;
|
||||
const xImplSimd_DestRegSSE SD;
|
||||
};
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Compare scalar floating point values and set EFLAGS (Ordered or Unordered)
|
||||
//
|
||||
struct xImplSimd_COMI
|
||||
{
|
||||
const xImplSimd_DestRegSSE SS;
|
||||
const xImplSimd_DestRegSSE SD;
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
struct xImplSimd_PCompare
|
||||
{
|
||||
public:
|
||||
// Compare packed bytes for equality.
|
||||
// If a data element in dest is equal to the corresponding date element src, the
|
||||
// corresponding data element in dest is set to all 1s; otherwise, it is set to all 0s.
|
||||
const xImplSimd_DestRegEither EQB;
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
struct xImplSimd_PCompare
|
||||
{
|
||||
public:
|
||||
// Compare packed bytes for equality.
|
||||
// If a data element in dest is equal to the corresponding date element src, the
|
||||
// corresponding data element in dest is set to all 1s; otherwise, it is set to all 0s.
|
||||
const xImplSimd_DestRegEither EQB;
|
||||
|
||||
// Compare packed words for equality.
|
||||
// If a data element in dest is equal to the corresponding date element src, the
|
||||
// corresponding data element in dest is set to all 1s; otherwise, it is set to all 0s.
|
||||
const xImplSimd_DestRegEither EQW;
|
||||
// Compare packed words for equality.
|
||||
// If a data element in dest is equal to the corresponding date element src, the
|
||||
// corresponding data element in dest is set to all 1s; otherwise, it is set to all 0s.
|
||||
const xImplSimd_DestRegEither EQW;
|
||||
|
||||
// Compare packed doublewords [32-bits] for equality.
|
||||
// If a data element in dest is equal to the corresponding date element src, the
|
||||
// corresponding data element in dest is set to all 1s; otherwise, it is set to all 0s.
|
||||
const xImplSimd_DestRegEither EQD;
|
||||
// Compare packed doublewords [32-bits] for equality.
|
||||
// If a data element in dest is equal to the corresponding date element src, the
|
||||
// corresponding data element in dest is set to all 1s; otherwise, it is set to all 0s.
|
||||
const xImplSimd_DestRegEither EQD;
|
||||
|
||||
// Compare packed signed bytes for greater than.
|
||||
// If a data element in dest is greater than the corresponding date element src, the
|
||||
// corresponding data element in dest is set to all 1s; otherwise, it is set to all 0s.
|
||||
const xImplSimd_DestRegEither GTB;
|
||||
// Compare packed signed bytes for greater than.
|
||||
// If a data element in dest is greater than the corresponding date element src, the
|
||||
// corresponding data element in dest is set to all 1s; otherwise, it is set to all 0s.
|
||||
const xImplSimd_DestRegEither GTB;
|
||||
|
||||
// Compare packed signed words for greater than.
|
||||
// If a data element in dest is greater than the corresponding date element src, the
|
||||
// corresponding data element in dest is set to all 1s; otherwise, it is set to all 0s.
|
||||
const xImplSimd_DestRegEither GTW;
|
||||
// Compare packed signed words for greater than.
|
||||
// If a data element in dest is greater than the corresponding date element src, the
|
||||
// corresponding data element in dest is set to all 1s; otherwise, it is set to all 0s.
|
||||
const xImplSimd_DestRegEither GTW;
|
||||
|
||||
// Compare packed signed doublewords [32-bits] for greater than.
|
||||
// If a data element in dest is greater than the corresponding date element src, the
|
||||
// corresponding data element in dest is set to all 1s; otherwise, it is set to all 0s.
|
||||
const xImplSimd_DestRegEither GTD;
|
||||
};
|
||||
// Compare packed signed doublewords [32-bits] for greater than.
|
||||
// If a data element in dest is greater than the corresponding date element src, the
|
||||
// corresponding data element in dest is set to all 1s; otherwise, it is set to all 0s.
|
||||
const xImplSimd_DestRegEither GTD;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
struct xImplSimd_PMinMax
|
||||
{
|
||||
// Compare packed unsigned byte integers in dest to src and store packed min/max
|
||||
// values in dest.
|
||||
const xImplSimd_DestRegEither UB;
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
struct xImplSimd_PMinMax
|
||||
{
|
||||
// Compare packed unsigned byte integers in dest to src and store packed min/max
|
||||
// values in dest.
|
||||
const xImplSimd_DestRegEither UB;
|
||||
|
||||
// Compare packed signed word integers in dest to src and store packed min/max
|
||||
// values in dest.
|
||||
const xImplSimd_DestRegEither SW;
|
||||
// Compare packed signed word integers in dest to src and store packed min/max
|
||||
// values in dest.
|
||||
const xImplSimd_DestRegEither SW;
|
||||
|
||||
// [SSE-4.1] Compare packed signed byte integers in dest to src and store
|
||||
// packed min/max values in dest. (SSE operands only)
|
||||
const xImplSimd_DestRegSSE SB;
|
||||
// [SSE-4.1] Compare packed signed byte integers in dest to src and store
|
||||
// packed min/max values in dest. (SSE operands only)
|
||||
const xImplSimd_DestRegSSE SB;
|
||||
|
||||
// [SSE-4.1] Compare packed signed doubleword integers in dest to src and store
|
||||
// packed min/max values in dest. (SSE operands only)
|
||||
const xImplSimd_DestRegSSE SD;
|
||||
// [SSE-4.1] Compare packed signed doubleword integers in dest to src and store
|
||||
// packed min/max values in dest. (SSE operands only)
|
||||
const xImplSimd_DestRegSSE SD;
|
||||
|
||||
// [SSE-4.1] Compare packed unsigned word integers in dest to src and store
|
||||
// packed min/max values in dest. (SSE operands only)
|
||||
const xImplSimd_DestRegSSE UW;
|
||||
// [SSE-4.1] Compare packed unsigned word integers in dest to src and store
|
||||
// packed min/max values in dest. (SSE operands only)
|
||||
const xImplSimd_DestRegSSE UW;
|
||||
|
||||
// [SSE-4.1] Compare packed unsigned doubleword integers in dest to src and store
|
||||
// packed min/max values in dest. (SSE operands only)
|
||||
const xImplSimd_DestRegSSE UD;
|
||||
};
|
||||
// [SSE-4.1] Compare packed unsigned doubleword integers in dest to src and store
|
||||
// packed min/max values in dest. (SSE operands only)
|
||||
const xImplSimd_DestRegSSE UD;
|
||||
};
|
||||
|
||||
} // end namespace x86Emitter
|
||||
|
|
|
@ -18,56 +18,56 @@
|
|||
namespace x86Emitter
|
||||
{
|
||||
|
||||
// =====================================================================================================
|
||||
// xImpl_SIMD Types (template free!)
|
||||
// =====================================================================================================
|
||||
// =====================================================================================================
|
||||
// xImpl_SIMD Types (template free!)
|
||||
// =====================================================================================================
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// For implementing SSE-only logic operations that have xmmreg,xmmreg/rm forms only,
|
||||
// like ANDPS/ANDPD
|
||||
//
|
||||
struct xImplSimd_DestRegSSE
|
||||
{
|
||||
u8 Prefix;
|
||||
u16 Opcode;
|
||||
// ------------------------------------------------------------------------
|
||||
// For implementing SSE-only logic operations that have xmmreg,xmmreg/rm forms only,
|
||||
// like ANDPS/ANDPD
|
||||
//
|
||||
struct xImplSimd_DestRegSSE
|
||||
{
|
||||
u8 Prefix;
|
||||
u16 Opcode;
|
||||
|
||||
void operator()(const xRegisterSSE &to, const xRegisterSSE &from) const;
|
||||
void operator()(const xRegisterSSE &to, const xIndirectVoid &from) const;
|
||||
};
|
||||
void operator()(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||
void operator()(const xRegisterSSE& to, const xIndirectVoid& from) const;
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// For implementing SSE-only logic operations that have xmmreg,reg/rm,imm forms only
|
||||
// (PSHUFD / PSHUFHW / etc).
|
||||
//
|
||||
struct xImplSimd_DestRegImmSSE
|
||||
{
|
||||
u8 Prefix;
|
||||
u16 Opcode;
|
||||
// ------------------------------------------------------------------------
|
||||
// For implementing SSE-only logic operations that have xmmreg,reg/rm,imm forms only
|
||||
// (PSHUFD / PSHUFHW / etc).
|
||||
//
|
||||
struct xImplSimd_DestRegImmSSE
|
||||
{
|
||||
u8 Prefix;
|
||||
u16 Opcode;
|
||||
|
||||
void operator()(const xRegisterSSE &to, const xRegisterSSE &from, u8 imm) const;
|
||||
void operator()(const xRegisterSSE &to, const xIndirectVoid &from, u8 imm) const;
|
||||
};
|
||||
void operator()(const xRegisterSSE& to, const xRegisterSSE& from, u8 imm) const;
|
||||
void operator()(const xRegisterSSE& to, const xIndirectVoid& from, u8 imm) const;
|
||||
};
|
||||
|
||||
struct xImplSimd_DestSSE_CmpImm
|
||||
{
|
||||
u8 Prefix;
|
||||
u16 Opcode;
|
||||
struct xImplSimd_DestSSE_CmpImm
|
||||
{
|
||||
u8 Prefix;
|
||||
u16 Opcode;
|
||||
|
||||
void operator()(const xRegisterSSE &to, const xRegisterSSE &from, SSE2_ComparisonType imm) const;
|
||||
void operator()(const xRegisterSSE &to, const xIndirectVoid &from, SSE2_ComparisonType imm) const;
|
||||
};
|
||||
void operator()(const xRegisterSSE& to, const xRegisterSSE& from, SSE2_ComparisonType imm) const;
|
||||
void operator()(const xRegisterSSE& to, const xIndirectVoid& from, SSE2_ComparisonType imm) const;
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// For implementing SSE operations that have reg,reg/rm forms only,
|
||||
// but accept either MM or XMM destinations (most PADD/PSUB and other P arithmetic ops).
|
||||
//
|
||||
struct xImplSimd_DestRegEither
|
||||
{
|
||||
u8 Prefix;
|
||||
u16 Opcode;
|
||||
// ------------------------------------------------------------------------
|
||||
// For implementing SSE operations that have reg,reg/rm forms only,
|
||||
// but accept either MM or XMM destinations (most PADD/PSUB and other P arithmetic ops).
|
||||
//
|
||||
struct xImplSimd_DestRegEither
|
||||
{
|
||||
u8 Prefix;
|
||||
u16 Opcode;
|
||||
|
||||
void operator()(const xRegisterSSE &to, const xRegisterSSE &from) const;
|
||||
void operator()(const xRegisterSSE &to, const xIndirectVoid &from) const;
|
||||
};
|
||||
void operator()(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||
void operator()(const xRegisterSSE& to, const xIndirectVoid& from) const;
|
||||
};
|
||||
|
||||
} // end namespace x86Emitter
|
||||
|
|
|
@ -18,156 +18,156 @@
|
|||
namespace x86Emitter
|
||||
{
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImplSimd_MovHL
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Moves to/from high/low portions of an xmm register.
|
||||
// These instructions cannot be used in reg/reg form.
|
||||
//
|
||||
struct xImplSimd_MovHL
|
||||
{
|
||||
u16 Opcode;
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImplSimd_MovHL
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Moves to/from high/low portions of an xmm register.
|
||||
// These instructions cannot be used in reg/reg form.
|
||||
//
|
||||
struct xImplSimd_MovHL
|
||||
{
|
||||
u16 Opcode;
|
||||
|
||||
void PS(const xRegisterSSE &to, const xIndirectVoid &from) const;
|
||||
void PS(const xIndirectVoid &to, const xRegisterSSE &from) const;
|
||||
void PS(const xRegisterSSE& to, const xIndirectVoid& from) const;
|
||||
void PS(const xIndirectVoid& to, const xRegisterSSE& from) const;
|
||||
|
||||
void PD(const xRegisterSSE &to, const xIndirectVoid &from) const;
|
||||
void PD(const xIndirectVoid &to, const xRegisterSSE &from) const;
|
||||
};
|
||||
void PD(const xRegisterSSE& to, const xIndirectVoid& from) const;
|
||||
void PD(const xIndirectVoid& to, const xRegisterSSE& from) const;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImplSimd_MovHL_RtoR
|
||||
// --------------------------------------------------------------------------------------
|
||||
// RegtoReg forms of MOVHL/MOVLH -- these are the same opcodes as MOVH/MOVL but
|
||||
// do something kinda different! Fun!
|
||||
//
|
||||
struct xImplSimd_MovHL_RtoR
|
||||
{
|
||||
u16 Opcode;
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImplSimd_MovHL_RtoR
|
||||
// --------------------------------------------------------------------------------------
|
||||
// RegtoReg forms of MOVHL/MOVLH -- these are the same opcodes as MOVH/MOVL but
|
||||
// do something kinda different! Fun!
|
||||
//
|
||||
struct xImplSimd_MovHL_RtoR
|
||||
{
|
||||
u16 Opcode;
|
||||
|
||||
void PS(const xRegisterSSE &to, const xRegisterSSE &from) const;
|
||||
void PD(const xRegisterSSE &to, const xRegisterSSE &from) const;
|
||||
};
|
||||
void PS(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||
void PD(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImplSimd_MoveSSE
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Legends in their own right: MOVAPS / MOVAPD / MOVUPS / MOVUPD
|
||||
//
|
||||
// All implementations of Unaligned Movs will, when possible, use aligned movs instead.
|
||||
// This happens when using Mem,Reg or Reg,Mem forms where the address is simple displacement
|
||||
// which can be checked for alignment at runtime.
|
||||
//
|
||||
struct xImplSimd_MoveSSE
|
||||
{
|
||||
u8 Prefix;
|
||||
bool isAligned;
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImplSimd_MoveSSE
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Legends in their own right: MOVAPS / MOVAPD / MOVUPS / MOVUPD
|
||||
//
|
||||
// All implementations of Unaligned Movs will, when possible, use aligned movs instead.
|
||||
// This happens when using Mem,Reg or Reg,Mem forms where the address is simple displacement
|
||||
// which can be checked for alignment at runtime.
|
||||
//
|
||||
struct xImplSimd_MoveSSE
|
||||
{
|
||||
u8 Prefix;
|
||||
bool isAligned;
|
||||
|
||||
void operator()(const xRegisterSSE &to, const xRegisterSSE &from) const;
|
||||
void operator()(const xRegisterSSE &to, const xIndirectVoid &from) const;
|
||||
void operator()(const xIndirectVoid &to, const xRegisterSSE &from) const;
|
||||
};
|
||||
void operator()(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||
void operator()(const xRegisterSSE& to, const xIndirectVoid& from) const;
|
||||
void operator()(const xIndirectVoid& to, const xRegisterSSE& from) const;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImplSimd_MoveDQ
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Implementations for MOVDQA / MOVDQU
|
||||
//
|
||||
// All implementations of Unaligned Movs will, when possible, use aligned movs instead.
|
||||
// This happens when using Mem,Reg or Reg,Mem forms where the address is simple displacement
|
||||
// which can be checked for alignment at runtime.
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImplSimd_MoveDQ
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Implementations for MOVDQA / MOVDQU
|
||||
//
|
||||
// All implementations of Unaligned Movs will, when possible, use aligned movs instead.
|
||||
// This happens when using Mem,Reg or Reg,Mem forms where the address is simple displacement
|
||||
// which can be checked for alignment at runtime.
|
||||
|
||||
struct xImplSimd_MoveDQ
|
||||
{
|
||||
u8 Prefix;
|
||||
bool isAligned;
|
||||
struct xImplSimd_MoveDQ
|
||||
{
|
||||
u8 Prefix;
|
||||
bool isAligned;
|
||||
|
||||
void operator()(const xRegisterSSE &to, const xRegisterSSE &from) const;
|
||||
void operator()(const xRegisterSSE &to, const xIndirectVoid &from) const;
|
||||
void operator()(const xIndirectVoid &to, const xRegisterSSE &from) const;
|
||||
};
|
||||
void operator()(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||
void operator()(const xRegisterSSE& to, const xIndirectVoid& from) const;
|
||||
void operator()(const xIndirectVoid& to, const xRegisterSSE& from) const;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImplSimd_Blend
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Blend - Conditional copying of values in src into dest.
|
||||
//
|
||||
struct xImplSimd_Blend
|
||||
{
|
||||
// [SSE-4.1] Conditionally copies dword values from src to dest, depending on the
|
||||
// mask bits in the immediate operand (bits [3:0]). Each mask bit corresponds to a
|
||||
// dword element in a 128-bit operand.
|
||||
//
|
||||
// If a mask bit is 1, then the corresponding dword in the source operand is copied
|
||||
// to dest, else the dword element in dest is left unchanged.
|
||||
//
|
||||
xImplSimd_DestRegImmSSE PS;
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImplSimd_Blend
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Blend - Conditional copying of values in src into dest.
|
||||
//
|
||||
struct xImplSimd_Blend
|
||||
{
|
||||
// [SSE-4.1] Conditionally copies dword values from src to dest, depending on the
|
||||
// mask bits in the immediate operand (bits [3:0]). Each mask bit corresponds to a
|
||||
// dword element in a 128-bit operand.
|
||||
//
|
||||
// If a mask bit is 1, then the corresponding dword in the source operand is copied
|
||||
// to dest, else the dword element in dest is left unchanged.
|
||||
//
|
||||
xImplSimd_DestRegImmSSE PS;
|
||||
|
||||
// [SSE-4.1] Conditionally copies quadword values from src to dest, depending on the
|
||||
// mask bits in the immediate operand (bits [1:0]). Each mask bit corresponds to a
|
||||
// quadword element in a 128-bit operand.
|
||||
//
|
||||
// If a mask bit is 1, then the corresponding dword in the source operand is copied
|
||||
// to dest, else the dword element in dest is left unchanged.
|
||||
//
|
||||
xImplSimd_DestRegImmSSE PD;
|
||||
// [SSE-4.1] Conditionally copies quadword values from src to dest, depending on the
|
||||
// mask bits in the immediate operand (bits [1:0]). Each mask bit corresponds to a
|
||||
// quadword element in a 128-bit operand.
|
||||
//
|
||||
// If a mask bit is 1, then the corresponding dword in the source operand is copied
|
||||
// to dest, else the dword element in dest is left unchanged.
|
||||
//
|
||||
xImplSimd_DestRegImmSSE PD;
|
||||
|
||||
// [SSE-4.1] Conditionally copies dword values from src to dest, depending on the
|
||||
// mask (bits [3:0]) in XMM0 (yes, the fixed register). Each mask bit corresponds
|
||||
// to a dword element in the 128-bit operand.
|
||||
//
|
||||
// If a mask bit is 1, then the corresponding dword in the source operand is copied
|
||||
// to dest, else the dword element in dest is left unchanged.
|
||||
//
|
||||
xImplSimd_DestRegSSE VPS;
|
||||
// [SSE-4.1] Conditionally copies dword values from src to dest, depending on the
|
||||
// mask (bits [3:0]) in XMM0 (yes, the fixed register). Each mask bit corresponds
|
||||
// to a dword element in the 128-bit operand.
|
||||
//
|
||||
// If a mask bit is 1, then the corresponding dword in the source operand is copied
|
||||
// to dest, else the dword element in dest is left unchanged.
|
||||
//
|
||||
xImplSimd_DestRegSSE VPS;
|
||||
|
||||
// [SSE-4.1] Conditionally copies quadword values from src to dest, depending on the
|
||||
// mask (bits [1:0]) in XMM0 (yes, the fixed register). Each mask bit corresponds
|
||||
// to a quadword element in the 128-bit operand.
|
||||
//
|
||||
// If a mask bit is 1, then the corresponding dword in the source operand is copied
|
||||
// to dest, else the dword element in dest is left unchanged.
|
||||
//
|
||||
xImplSimd_DestRegSSE VPD;
|
||||
};
|
||||
// [SSE-4.1] Conditionally copies quadword values from src to dest, depending on the
|
||||
// mask (bits [1:0]) in XMM0 (yes, the fixed register). Each mask bit corresponds
|
||||
// to a quadword element in the 128-bit operand.
|
||||
//
|
||||
// If a mask bit is 1, then the corresponding dword in the source operand is copied
|
||||
// to dest, else the dword element in dest is left unchanged.
|
||||
//
|
||||
xImplSimd_DestRegSSE VPD;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImplSimd_PMove
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Packed Move with Sign or Zero extension.
|
||||
//
|
||||
struct xImplSimd_PMove
|
||||
{
|
||||
u16 OpcodeBase;
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImplSimd_PMove
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Packed Move with Sign or Zero extension.
|
||||
//
|
||||
struct xImplSimd_PMove
|
||||
{
|
||||
u16 OpcodeBase;
|
||||
|
||||
// [SSE-4.1] Zero/Sign-extend the low byte values in src into word integers
|
||||
// and store them in dest.
|
||||
void BW(const xRegisterSSE &to, const xRegisterSSE &from) const;
|
||||
void BW(const xRegisterSSE &to, const xIndirect64 &from) const;
|
||||
// [SSE-4.1] Zero/Sign-extend the low byte values in src into word integers
|
||||
// and store them in dest.
|
||||
void BW(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||
void BW(const xRegisterSSE& to, const xIndirect64& from) const;
|
||||
|
||||
// [SSE-4.1] Zero/Sign-extend the low byte values in src into dword integers
|
||||
// and store them in dest.
|
||||
void BD(const xRegisterSSE &to, const xRegisterSSE &from) const;
|
||||
void BD(const xRegisterSSE &to, const xIndirect32 &from) const;
|
||||
// [SSE-4.1] Zero/Sign-extend the low byte values in src into dword integers
|
||||
// and store them in dest.
|
||||
void BD(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||
void BD(const xRegisterSSE& to, const xIndirect32& from) const;
|
||||
|
||||
// [SSE-4.1] Zero/Sign-extend the low byte values in src into qword integers
|
||||
// and store them in dest.
|
||||
void BQ(const xRegisterSSE &to, const xRegisterSSE &from) const;
|
||||
void BQ(const xRegisterSSE &to, const xIndirect16 &from) const;
|
||||
// [SSE-4.1] Zero/Sign-extend the low byte values in src into qword integers
|
||||
// and store them in dest.
|
||||
void BQ(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||
void BQ(const xRegisterSSE& to, const xIndirect16& from) const;
|
||||
|
||||
// [SSE-4.1] Zero/Sign-extend the low word values in src into dword integers
|
||||
// and store them in dest.
|
||||
void WD(const xRegisterSSE &to, const xRegisterSSE &from) const;
|
||||
void WD(const xRegisterSSE &to, const xIndirect64 &from) const;
|
||||
// [SSE-4.1] Zero/Sign-extend the low word values in src into dword integers
|
||||
// and store them in dest.
|
||||
void WD(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||
void WD(const xRegisterSSE& to, const xIndirect64& from) const;
|
||||
|
||||
// [SSE-4.1] Zero/Sign-extend the low word values in src into qword integers
|
||||
// and store them in dest.
|
||||
void WQ(const xRegisterSSE &to, const xRegisterSSE &from) const;
|
||||
void WQ(const xRegisterSSE &to, const xIndirect32 &from) const;
|
||||
// [SSE-4.1] Zero/Sign-extend the low word values in src into qword integers
|
||||
// and store them in dest.
|
||||
void WQ(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||
void WQ(const xRegisterSSE& to, const xIndirect32& from) const;
|
||||
|
||||
// [SSE-4.1] Zero/Sign-extend the low dword values in src into qword integers
|
||||
// and store them in dest.
|
||||
void DQ(const xRegisterSSE &to, const xRegisterSSE &from) const;
|
||||
void DQ(const xRegisterSSE &to, const xIndirect64 &from) const;
|
||||
};
|
||||
}
|
||||
// [SSE-4.1] Zero/Sign-extend the low dword values in src into qword integers
|
||||
// and store them in dest.
|
||||
void DQ(const xRegisterSSE& to, const xRegisterSSE& from) const;
|
||||
void DQ(const xRegisterSSE& to, const xIndirect64& from) const;
|
||||
};
|
||||
} // namespace x86Emitter
|
||||
|
|
|
@ -18,50 +18,50 @@
|
|||
namespace x86Emitter
|
||||
{
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImplSimd_Shuffle
|
||||
// --------------------------------------------------------------------------------------
|
||||
struct xImplSimd_Shuffle
|
||||
{
|
||||
inline void _selector_assertion_check(u8 selector) const;
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImplSimd_Shuffle
|
||||
// --------------------------------------------------------------------------------------
|
||||
struct xImplSimd_Shuffle
|
||||
{
|
||||
inline void _selector_assertion_check(u8 selector) const;
|
||||
|
||||
void PS(const xRegisterSSE &to, const xRegisterSSE &from, u8 selector) const;
|
||||
void PS(const xRegisterSSE &to, const xIndirectVoid &from, u8 selector) const;
|
||||
void PS(const xRegisterSSE& to, const xRegisterSSE& from, u8 selector) const;
|
||||
void PS(const xRegisterSSE& to, const xIndirectVoid& from, u8 selector) const;
|
||||
|
||||
void PD(const xRegisterSSE &to, const xRegisterSSE &from, u8 selector) const;
|
||||
void PD(const xRegisterSSE &to, const xIndirectVoid &from, u8 selector) const;
|
||||
};
|
||||
void PD(const xRegisterSSE& to, const xRegisterSSE& from, u8 selector) const;
|
||||
void PD(const xRegisterSSE& to, const xIndirectVoid& from, u8 selector) const;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImplSimd_PShuffle
|
||||
// --------------------------------------------------------------------------------------
|
||||
struct xImplSimd_PShuffle
|
||||
{
|
||||
// Copies doublewords from src and inserts them into dest at dword locations selected
|
||||
// with the order operand (8 bit immediate).
|
||||
const xImplSimd_DestRegImmSSE D;
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImplSimd_PShuffle
|
||||
// --------------------------------------------------------------------------------------
|
||||
struct xImplSimd_PShuffle
|
||||
{
|
||||
// Copies doublewords from src and inserts them into dest at dword locations selected
|
||||
// with the order operand (8 bit immediate).
|
||||
const xImplSimd_DestRegImmSSE D;
|
||||
|
||||
// Copies words from the low quadword of src and inserts them into the low quadword
|
||||
// of dest at word locations selected with the order operand (8 bit immediate).
|
||||
// The high quadword of src is copied to the high quadword of dest.
|
||||
const xImplSimd_DestRegImmSSE LW;
|
||||
// Copies words from the low quadword of src and inserts them into the low quadword
|
||||
// of dest at word locations selected with the order operand (8 bit immediate).
|
||||
// The high quadword of src is copied to the high quadword of dest.
|
||||
const xImplSimd_DestRegImmSSE LW;
|
||||
|
||||
// Copies words from the high quadword of src and inserts them into the high quadword
|
||||
// of dest at word locations selected with the order operand (8 bit immediate).
|
||||
// The low quadword of src is copied to the low quadword of dest.
|
||||
const xImplSimd_DestRegImmSSE HW;
|
||||
// Copies words from the high quadword of src and inserts them into the high quadword
|
||||
// of dest at word locations selected with the order operand (8 bit immediate).
|
||||
// The low quadword of src is copied to the low quadword of dest.
|
||||
const xImplSimd_DestRegImmSSE HW;
|
||||
|
||||
// [sSSE-3] Performs in-place shuffles of bytes in dest according to the shuffle
|
||||
// control mask in src. If the most significant bit (bit[7]) of each byte of the
|
||||
// shuffle control mask is set, then constant zero is written in the result byte.
|
||||
// Each byte in the shuffle control mask forms an index to permute the corresponding
|
||||
// byte in dest. The value of each index is the least significant 4 bits (128-bit
|
||||
// operation) or 3 bits (64-bit operation) of the shuffle control byte.
|
||||
//
|
||||
const xImplSimd_DestRegEither B;
|
||||
// [sSSE-3] Performs in-place shuffles of bytes in dest according to the shuffle
|
||||
// control mask in src. If the most significant bit (bit[7]) of each byte of the
|
||||
// shuffle control mask is set, then constant zero is written in the result byte.
|
||||
// Each byte in the shuffle control mask forms an index to permute the corresponding
|
||||
// byte in dest. The value of each index is the least significant 4 bits (128-bit
|
||||
// operation) or 3 bits (64-bit operation) of the shuffle control byte.
|
||||
//
|
||||
const xImplSimd_DestRegEither B;
|
||||
|
||||
// below is my test bed for a new system, free of subclasses. Was supposed to improve intellisense
|
||||
// but it doesn't (makes it worse). Will try again in MSVC 2010. --air
|
||||
// below is my test bed for a new system, free of subclasses. Was supposed to improve intellisense
|
||||
// but it doesn't (makes it worse). Will try again in MSVC 2010. --air
|
||||
|
||||
#if 0
|
||||
// Copies words from src and inserts them into dest at word locations selected with
|
||||
|
@ -94,148 +94,148 @@ struct xImplSimd_PShuffle
|
|||
void B( const xRegisterSSE& to, const xRegisterSSE& from ) const { OpWriteSSE( 0x66, 0x0038 ); }
|
||||
void B( const xRegisterSSE& to, const xIndirectVoid& from ) const { OpWriteSSE( 0x66, 0x0038 ); }
|
||||
#endif
|
||||
};
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SimdImpl_PUnpack
|
||||
// --------------------------------------------------------------------------------------
|
||||
struct SimdImpl_PUnpack
|
||||
{
|
||||
// Unpack and interleave low-order bytes from src and dest into dest.
|
||||
const xImplSimd_DestRegEither LBW;
|
||||
// Unpack and interleave low-order words from src and dest into dest.
|
||||
const xImplSimd_DestRegEither LWD;
|
||||
// Unpack and interleave low-order doublewords from src and dest into dest.
|
||||
const xImplSimd_DestRegEither LDQ;
|
||||
// Unpack and interleave low-order quadwords from src and dest into dest.
|
||||
const xImplSimd_DestRegSSE LQDQ;
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SimdImpl_PUnpack
|
||||
// --------------------------------------------------------------------------------------
|
||||
struct SimdImpl_PUnpack
|
||||
{
|
||||
// Unpack and interleave low-order bytes from src and dest into dest.
|
||||
const xImplSimd_DestRegEither LBW;
|
||||
// Unpack and interleave low-order words from src and dest into dest.
|
||||
const xImplSimd_DestRegEither LWD;
|
||||
// Unpack and interleave low-order doublewords from src and dest into dest.
|
||||
const xImplSimd_DestRegEither LDQ;
|
||||
// Unpack and interleave low-order quadwords from src and dest into dest.
|
||||
const xImplSimd_DestRegSSE LQDQ;
|
||||
|
||||
// Unpack and interleave high-order bytes from src and dest into dest.
|
||||
const xImplSimd_DestRegEither HBW;
|
||||
// Unpack and interleave high-order words from src and dest into dest.
|
||||
const xImplSimd_DestRegEither HWD;
|
||||
// Unpack and interleave high-order doublewords from src and dest into dest.
|
||||
const xImplSimd_DestRegEither HDQ;
|
||||
// Unpack and interleave high-order quadwords from src and dest into dest.
|
||||
const xImplSimd_DestRegSSE HQDQ;
|
||||
};
|
||||
// Unpack and interleave high-order bytes from src and dest into dest.
|
||||
const xImplSimd_DestRegEither HBW;
|
||||
// Unpack and interleave high-order words from src and dest into dest.
|
||||
const xImplSimd_DestRegEither HWD;
|
||||
// Unpack and interleave high-order doublewords from src and dest into dest.
|
||||
const xImplSimd_DestRegEither HDQ;
|
||||
// Unpack and interleave high-order quadwords from src and dest into dest.
|
||||
const xImplSimd_DestRegSSE HQDQ;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SimdImpl_Pack
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Pack with Signed or Unsigned Saturation
|
||||
//
|
||||
struct SimdImpl_Pack
|
||||
{
|
||||
// Converts packed signed word integers from src and dest into packed signed
|
||||
// byte integers in dest, using signed saturation.
|
||||
const xImplSimd_DestRegEither SSWB;
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SimdImpl_Pack
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Pack with Signed or Unsigned Saturation
|
||||
//
|
||||
struct SimdImpl_Pack
|
||||
{
|
||||
// Converts packed signed word integers from src and dest into packed signed
|
||||
// byte integers in dest, using signed saturation.
|
||||
const xImplSimd_DestRegEither SSWB;
|
||||
|
||||
// Converts packed signed dword integers from src and dest into packed signed
|
||||
// word integers in dest, using signed saturation.
|
||||
const xImplSimd_DestRegEither SSDW;
|
||||
// Converts packed signed dword integers from src and dest into packed signed
|
||||
// word integers in dest, using signed saturation.
|
||||
const xImplSimd_DestRegEither SSDW;
|
||||
|
||||
// Converts packed unsigned word integers from src and dest into packed unsigned
|
||||
// byte integers in dest, using unsigned saturation.
|
||||
const xImplSimd_DestRegEither USWB;
|
||||
// Converts packed unsigned word integers from src and dest into packed unsigned
|
||||
// byte integers in dest, using unsigned saturation.
|
||||
const xImplSimd_DestRegEither USWB;
|
||||
|
||||
// [SSE-4.1] Converts packed unsigned dword integers from src and dest into packed
|
||||
// unsigned word integers in dest, using signed saturation.
|
||||
const xImplSimd_DestRegSSE USDW;
|
||||
};
|
||||
// [SSE-4.1] Converts packed unsigned dword integers from src and dest into packed
|
||||
// unsigned word integers in dest, using signed saturation.
|
||||
const xImplSimd_DestRegSSE USDW;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SimdImpl_Unpack
|
||||
// --------------------------------------------------------------------------------------
|
||||
struct xImplSimd_Unpack
|
||||
{
|
||||
// Unpacks the high doubleword [single-precision] values from src and dest into
|
||||
// dest, such that the result of dest looks like this:
|
||||
// dest[0] <- dest[2]
|
||||
// dest[1] <- src[2]
|
||||
// dest[2] <- dest[3]
|
||||
// dest[3] <- src[3]
|
||||
//
|
||||
const xImplSimd_DestRegSSE HPS;
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SimdImpl_Unpack
|
||||
// --------------------------------------------------------------------------------------
|
||||
struct xImplSimd_Unpack
|
||||
{
|
||||
// Unpacks the high doubleword [single-precision] values from src and dest into
|
||||
// dest, such that the result of dest looks like this:
|
||||
// dest[0] <- dest[2]
|
||||
// dest[1] <- src[2]
|
||||
// dest[2] <- dest[3]
|
||||
// dest[3] <- src[3]
|
||||
//
|
||||
const xImplSimd_DestRegSSE HPS;
|
||||
|
||||
// Unpacks the high quadword [double-precision] values from src and dest into
|
||||
// dest, such that the result of dest looks like this:
|
||||
// dest.lo <- dest.hi
|
||||
// dest.hi <- src.hi
|
||||
//
|
||||
const xImplSimd_DestRegSSE HPD;
|
||||
// Unpacks the high quadword [double-precision] values from src and dest into
|
||||
// dest, such that the result of dest looks like this:
|
||||
// dest.lo <- dest.hi
|
||||
// dest.hi <- src.hi
|
||||
//
|
||||
const xImplSimd_DestRegSSE HPD;
|
||||
|
||||
// Unpacks the low doubleword [single-precision] values from src and dest into
|
||||
// dest, such that the result of dest looks like this:
|
||||
// dest[3] <- src[1]
|
||||
// dest[2] <- dest[1]
|
||||
// dest[1] <- src[0]
|
||||
// dest[0] <- dest[0]
|
||||
//
|
||||
const xImplSimd_DestRegSSE LPS;
|
||||
// Unpacks the low doubleword [single-precision] values from src and dest into
|
||||
// dest, such that the result of dest looks like this:
|
||||
// dest[3] <- src[1]
|
||||
// dest[2] <- dest[1]
|
||||
// dest[1] <- src[0]
|
||||
// dest[0] <- dest[0]
|
||||
//
|
||||
const xImplSimd_DestRegSSE LPS;
|
||||
|
||||
// Unpacks the low quadword [double-precision] values from src and dest into
|
||||
// dest, effectively moving the low portion of src into the upper portion of dest.
|
||||
// The result of dest is loaded as such:
|
||||
// dest.hi <- src.lo
|
||||
// dest.lo <- dest.lo [remains unchanged!]
|
||||
//
|
||||
const xImplSimd_DestRegSSE LPD;
|
||||
};
|
||||
// Unpacks the low quadword [double-precision] values from src and dest into
|
||||
// dest, effectively moving the low portion of src into the upper portion of dest.
|
||||
// The result of dest is loaded as such:
|
||||
// dest.hi <- src.lo
|
||||
// dest.lo <- dest.lo [remains unchanged!]
|
||||
//
|
||||
const xImplSimd_DestRegSSE LPD;
|
||||
};
|
||||
|
||||
|
||||
struct xImplSimd_InsertExtractHelper
|
||||
{
|
||||
u16 Opcode;
|
||||
struct xImplSimd_InsertExtractHelper
|
||||
{
|
||||
u16 Opcode;
|
||||
|
||||
// [SSE-4.1] Allowed with SSE registers only (MMX regs are invalid)
|
||||
void operator()(const xRegisterSSE &to, const xRegister32 &from, u8 imm8) const;
|
||||
// [SSE-4.1] Allowed with SSE registers only (MMX regs are invalid)
|
||||
void operator()(const xRegisterSSE& to, const xRegister32& from, u8 imm8) const;
|
||||
|
||||
// [SSE-4.1] Allowed with SSE registers only (MMX regs are invalid)
|
||||
void operator()(const xRegisterSSE &to, const xIndirectVoid &from, u8 imm8) const;
|
||||
};
|
||||
// [SSE-4.1] Allowed with SSE registers only (MMX regs are invalid)
|
||||
void operator()(const xRegisterSSE& to, const xIndirectVoid& from, u8 imm8) const;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SimdImpl_PInsert
|
||||
// --------------------------------------------------------------------------------------
|
||||
// PINSRW/B/D [all but Word form are SSE4.1 only!]
|
||||
//
|
||||
struct xImplSimd_PInsert
|
||||
{
|
||||
void W(const xRegisterSSE &to, const xRegister32 &from, u8 imm8) const;
|
||||
void W(const xRegisterSSE &to, const xIndirectVoid &from, u8 imm8) const;
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SimdImpl_PInsert
|
||||
// --------------------------------------------------------------------------------------
|
||||
// PINSRW/B/D [all but Word form are SSE4.1 only!]
|
||||
//
|
||||
struct xImplSimd_PInsert
|
||||
{
|
||||
void W(const xRegisterSSE& to, const xRegister32& from, u8 imm8) const;
|
||||
void W(const xRegisterSSE& to, const xIndirectVoid& from, u8 imm8) const;
|
||||
|
||||
// [SSE-4.1] Allowed with SSE registers only (MMX regs are invalid)
|
||||
xImplSimd_InsertExtractHelper B;
|
||||
// [SSE-4.1] Allowed with SSE registers only (MMX regs are invalid)
|
||||
xImplSimd_InsertExtractHelper B;
|
||||
|
||||
// [SSE-4.1] Allowed with SSE registers only (MMX regs are invalid)
|
||||
xImplSimd_InsertExtractHelper D;
|
||||
};
|
||||
// [SSE-4.1] Allowed with SSE registers only (MMX regs are invalid)
|
||||
xImplSimd_InsertExtractHelper D;
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// PEXTRW/B/D [all but Word form are SSE4.1 only!]
|
||||
//
|
||||
// Note: Word form's indirect memory form is only available in SSE4.1.
|
||||
//
|
||||
struct SimdImpl_PExtract
|
||||
{
|
||||
// Copies the word element specified by imm8 from src to dest. The upper bits
|
||||
// of dest are zero-extended (cleared). This can be used to extract any single packed
|
||||
// word value from src into an x86 32 bit register.
|
||||
//
|
||||
// [SSE-4.1] Note: Indirect memory forms of this instruction are an SSE-4.1 extension!
|
||||
//
|
||||
void W(const xRegister32 &to, const xRegisterSSE &from, u8 imm8) const;
|
||||
void W(const xIndirectVoid &dest, const xRegisterSSE &from, u8 imm8) const;
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// PEXTRW/B/D [all but Word form are SSE4.1 only!]
|
||||
//
|
||||
// Note: Word form's indirect memory form is only available in SSE4.1.
|
||||
//
|
||||
struct SimdImpl_PExtract
|
||||
{
|
||||
// Copies the word element specified by imm8 from src to dest. The upper bits
|
||||
// of dest are zero-extended (cleared). This can be used to extract any single packed
|
||||
// word value from src into an x86 32 bit register.
|
||||
//
|
||||
// [SSE-4.1] Note: Indirect memory forms of this instruction are an SSE-4.1 extension!
|
||||
//
|
||||
void W(const xRegister32& to, const xRegisterSSE& from, u8 imm8) const;
|
||||
void W(const xIndirectVoid& dest, const xRegisterSSE& from, u8 imm8) const;
|
||||
|
||||
// [SSE-4.1] Copies the byte element specified by imm8 from src to dest. The upper bits
|
||||
// of dest are zero-extended (cleared). This can be used to extract any single packed
|
||||
// byte value from src into an x86 32 bit register.
|
||||
const xImplSimd_InsertExtractHelper B;
|
||||
// [SSE-4.1] Copies the byte element specified by imm8 from src to dest. The upper bits
|
||||
// of dest are zero-extended (cleared). This can be used to extract any single packed
|
||||
// byte value from src into an x86 32 bit register.
|
||||
const xImplSimd_InsertExtractHelper B;
|
||||
|
||||
// [SSE-4.1] Copies the dword element specified by imm8 from src to dest. This can be
|
||||
// used to extract any single packed dword value from src into an x86 32 bit register.
|
||||
const xImplSimd_InsertExtractHelper D;
|
||||
};
|
||||
}
|
||||
// [SSE-4.1] Copies the dword element specified by imm8 from src to dest. This can be
|
||||
// used to extract any single packed dword value from src into an x86 32 bit register.
|
||||
const xImplSimd_InsertExtractHelper D;
|
||||
};
|
||||
} // namespace x86Emitter
|
||||
|
|
|
@ -26,13 +26,13 @@ template <u8 Prefix, u16 Opcode>
|
|||
class SimdImpl_DestRegSSE
|
||||
{
|
||||
public:
|
||||
__forceinline void operator()(const xRegisterSSE &to, const xRegisterSSE &from) const { xOpWrite0F(Prefix, Opcode, to, from); }
|
||||
__forceinline void operator()(const xRegisterSSE &to, const ModSibBase &from) const
|
||||
{
|
||||
bool isReallyAligned = ((from.Displacement & 0x0f) == 0) && from.Index.IsEmpty() && from.Base.IsEmpty();
|
||||
pxAssertDev(isReallyAligned, "Alignment check failed on SSE indirect load.");
|
||||
xOpWrite0F(Prefix, Opcode, to, from);
|
||||
}
|
||||
__forceinline void operator()(const xRegisterSSE& to, const xRegisterSSE& from) const { xOpWrite0F(Prefix, Opcode, to, from); }
|
||||
__forceinline void operator()(const xRegisterSSE& to, const ModSibBase& from) const
|
||||
{
|
||||
bool isReallyAligned = ((from.Displacement & 0x0f) == 0) && from.Index.IsEmpty() && from.Base.IsEmpty();
|
||||
pxAssertDev(isReallyAligned, "Alignment check failed on SSE indirect load.");
|
||||
xOpWrite0F(Prefix, Opcode, to, from);
|
||||
}
|
||||
|
||||
SimdImpl_DestRegSSE() {} //GCWho?
|
||||
SimdImpl_DestRegSSE() {} //GCWho?
|
||||
};
|
||||
|
|
|
@ -20,55 +20,56 @@
|
|||
namespace x86Emitter
|
||||
{
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImpl_Test
|
||||
// --------------------------------------------------------------------------------------
|
||||
//
|
||||
struct xImpl_Test
|
||||
{
|
||||
void operator()(const xRegisterInt &to, const xRegisterInt &from) const;
|
||||
void operator()(const xIndirect64orLess &dest, int imm) const;
|
||||
void operator()(const xRegisterInt &to, int imm) const;
|
||||
};
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImpl_Test
|
||||
// --------------------------------------------------------------------------------------
|
||||
//
|
||||
struct xImpl_Test
|
||||
{
|
||||
void operator()(const xRegisterInt& to, const xRegisterInt& from) const;
|
||||
void operator()(const xIndirect64orLess& dest, int imm) const;
|
||||
void operator()(const xRegisterInt& to, int imm) const;
|
||||
};
|
||||
|
||||
enum G8Type {
|
||||
G8Type_BT = 4,
|
||||
G8Type_BTS,
|
||||
G8Type_BTR,
|
||||
G8Type_BTC,
|
||||
};
|
||||
enum G8Type
|
||||
{
|
||||
G8Type_BT = 4,
|
||||
G8Type_BTS,
|
||||
G8Type_BTR,
|
||||
G8Type_BTC,
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// BSF / BSR
|
||||
// --------------------------------------------------------------------------------------
|
||||
// 16/32 operands are available. No 8 bit ones, not that any of you cared, I bet.
|
||||
//
|
||||
struct xImpl_BitScan
|
||||
{
|
||||
// 0xbc [fwd] / 0xbd [rev]
|
||||
u16 Opcode;
|
||||
// --------------------------------------------------------------------------------------
|
||||
// BSF / BSR
|
||||
// --------------------------------------------------------------------------------------
|
||||
// 16/32 operands are available. No 8 bit ones, not that any of you cared, I bet.
|
||||
//
|
||||
struct xImpl_BitScan
|
||||
{
|
||||
// 0xbc [fwd] / 0xbd [rev]
|
||||
u16 Opcode;
|
||||
|
||||
void operator()(const xRegister16or32or64 &to, const xRegister16or32or64 &from) const;
|
||||
void operator()(const xRegister16or32or64 &to, const xIndirectVoid &sibsrc) const;
|
||||
};
|
||||
void operator()(const xRegister16or32or64& to, const xRegister16or32or64& from) const;
|
||||
void operator()(const xRegister16or32or64& to, const xIndirectVoid& sibsrc) const;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImpl_Group8
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Bit Test Instructions - Valid on 16/32 bit instructions only.
|
||||
//
|
||||
struct xImpl_Group8
|
||||
{
|
||||
G8Type InstType;
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImpl_Group8
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Bit Test Instructions - Valid on 16/32 bit instructions only.
|
||||
//
|
||||
struct xImpl_Group8
|
||||
{
|
||||
G8Type InstType;
|
||||
|
||||
void operator()(const xRegister16or32or64 &bitbase, const xRegister16or32or64 &bitoffset) const;
|
||||
void operator()(const xRegister16or32or64 &bitbase, u8 bitoffset) const;
|
||||
void operator()(const xRegister16or32or64& bitbase, const xRegister16or32or64& bitoffset) const;
|
||||
void operator()(const xRegister16or32or64& bitbase, u8 bitoffset) const;
|
||||
|
||||
void operator()(const xIndirectVoid &bitbase, const xRegister16or32or64 &bitoffset) const;
|
||||
void operator()(const xIndirectVoid& bitbase, const xRegister16or32or64& bitoffset) const;
|
||||
|
||||
void operator()(const xIndirect64 &bitbase, u8 bitoffset) const;
|
||||
void operator()(const xIndirect32 &bitbase, u8 bitoffset) const;
|
||||
void operator()(const xIndirect16 &bitbase, u8 bitoffset) const;
|
||||
};
|
||||
void operator()(const xIndirect64& bitbase, u8 bitoffset) const;
|
||||
void operator()(const xIndirect32& bitbase, u8 bitoffset) const;
|
||||
void operator()(const xIndirect16& bitbase, u8 bitoffset) const;
|
||||
};
|
||||
|
||||
} // End namespace x86Emitter
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -23,165 +23,168 @@ namespace x86Emitter
|
|||
|
||||
#define OpWriteSSE(pre, op) xOpWrite0F(pre, op, to, from)
|
||||
|
||||
extern void SimdPrefix(u8 prefix, u16 opcode);
|
||||
extern void EmitSibMagic(uint regfield, const void *address, int extraRIPOffset = 0);
|
||||
extern void EmitSibMagic(uint regfield, const xIndirectVoid &info, int extraRIPOffset = 0);
|
||||
extern void EmitSibMagic(uint reg1, const xRegisterBase ®2, int = 0);
|
||||
extern void EmitSibMagic(const xRegisterBase ®1, const xRegisterBase ®2, int = 0);
|
||||
extern void EmitSibMagic(const xRegisterBase ®1, const void *src, int extraRIPOffset = 0);
|
||||
extern void EmitSibMagic(const xRegisterBase ®1, const xIndirectVoid &sib, int extraRIPOffset = 0);
|
||||
extern void SimdPrefix(u8 prefix, u16 opcode);
|
||||
extern void EmitSibMagic(uint regfield, const void* address, int extraRIPOffset = 0);
|
||||
extern void EmitSibMagic(uint regfield, const xIndirectVoid& info, int extraRIPOffset = 0);
|
||||
extern void EmitSibMagic(uint reg1, const xRegisterBase& reg2, int = 0);
|
||||
extern void EmitSibMagic(const xRegisterBase& reg1, const xRegisterBase& reg2, int = 0);
|
||||
extern void EmitSibMagic(const xRegisterBase& reg1, const void* src, int extraRIPOffset = 0);
|
||||
extern void EmitSibMagic(const xRegisterBase& reg1, const xIndirectVoid& sib, int extraRIPOffset = 0);
|
||||
|
||||
extern void EmitRex(uint regfield, const void *address);
|
||||
extern void EmitRex(uint regfield, const xIndirectVoid &info);
|
||||
extern void EmitRex(uint reg1, const xRegisterBase ®2);
|
||||
extern void EmitRex(const xRegisterBase ®1, const xRegisterBase ®2);
|
||||
extern void EmitRex(const xRegisterBase ®1, const void *src);
|
||||
extern void EmitRex(const xRegisterBase ®1, const xIndirectVoid &sib);
|
||||
extern void EmitRex(uint regfield, const void* address);
|
||||
extern void EmitRex(uint regfield, const xIndirectVoid& info);
|
||||
extern void EmitRex(uint reg1, const xRegisterBase& reg2);
|
||||
extern void EmitRex(const xRegisterBase& reg1, const xRegisterBase& reg2);
|
||||
extern void EmitRex(const xRegisterBase& reg1, const void* src);
|
||||
extern void EmitRex(const xRegisterBase& reg1, const xIndirectVoid& sib);
|
||||
|
||||
extern void _xMovRtoR(const xRegisterInt &to, const xRegisterInt &from);
|
||||
extern void _xMovRtoR(const xRegisterInt& to, const xRegisterInt& from);
|
||||
|
||||
template <typename T>
|
||||
inline void xWrite(T val)
|
||||
{
|
||||
*(T *)x86Ptr = val;
|
||||
x86Ptr += sizeof(T);
|
||||
}
|
||||
template <typename T>
|
||||
inline void xWrite(T val)
|
||||
{
|
||||
*(T*)x86Ptr = val;
|
||||
x86Ptr += sizeof(T);
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
__emitinline void xOpWrite(u8 prefix, u8 opcode, const T1 ¶m1, const T2 ¶m2, int extraRIPOffset = 0)
|
||||
{
|
||||
if (prefix != 0)
|
||||
xWrite8(prefix);
|
||||
EmitRex(param1, param2);
|
||||
template <typename T1, typename T2>
|
||||
__emitinline void xOpWrite(u8 prefix, u8 opcode, const T1& param1, const T2& param2, int extraRIPOffset = 0)
|
||||
{
|
||||
if (prefix != 0)
|
||||
xWrite8(prefix);
|
||||
EmitRex(param1, param2);
|
||||
|
||||
xWrite8(opcode);
|
||||
xWrite8(opcode);
|
||||
|
||||
EmitSibMagic(param1, param2, extraRIPOffset);
|
||||
}
|
||||
EmitSibMagic(param1, param2, extraRIPOffset);
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
__emitinline void xOpAccWrite(u8 prefix, u8 opcode, const T1 ¶m1, const T2 ¶m2)
|
||||
{
|
||||
if (prefix != 0)
|
||||
xWrite8(prefix);
|
||||
EmitRex(param1, param2);
|
||||
template <typename T1, typename T2>
|
||||
__emitinline void xOpAccWrite(u8 prefix, u8 opcode, const T1& param1, const T2& param2)
|
||||
{
|
||||
if (prefix != 0)
|
||||
xWrite8(prefix);
|
||||
EmitRex(param1, param2);
|
||||
|
||||
xWrite8(opcode);
|
||||
}
|
||||
xWrite8(opcode);
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// emitter helpers for xmm instruction with prefixes, most of which are using
|
||||
// the basic opcode format (items inside braces denote optional or conditional
|
||||
// emission):
|
||||
//
|
||||
// [Prefix] / 0x0f / [OpcodePrefix] / Opcode / ModRM+[SibSB]
|
||||
//
|
||||
// Prefixes are typically 0x66, 0xf2, or 0xf3. OpcodePrefixes are either 0x38 or
|
||||
// 0x3a [and other value will result in assertion failue].
|
||||
//
|
||||
template <typename T1, typename T2>
|
||||
__emitinline void xOpWrite0F(u8 prefix, u16 opcode, const T1 ¶m1, const T2 ¶m2)
|
||||
{
|
||||
if (prefix != 0)
|
||||
xWrite8(prefix);
|
||||
EmitRex(param1, param2);
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// emitter helpers for xmm instruction with prefixes, most of which are using
|
||||
// the basic opcode format (items inside braces denote optional or conditional
|
||||
// emission):
|
||||
//
|
||||
// [Prefix] / 0x0f / [OpcodePrefix] / Opcode / ModRM+[SibSB]
|
||||
//
|
||||
// Prefixes are typically 0x66, 0xf2, or 0xf3. OpcodePrefixes are either 0x38 or
|
||||
// 0x3a [and other value will result in assertion failue].
|
||||
//
|
||||
template <typename T1, typename T2>
|
||||
__emitinline void xOpWrite0F(u8 prefix, u16 opcode, const T1& param1, const T2& param2)
|
||||
{
|
||||
if (prefix != 0)
|
||||
xWrite8(prefix);
|
||||
EmitRex(param1, param2);
|
||||
|
||||
SimdPrefix(0, opcode);
|
||||
SimdPrefix(0, opcode);
|
||||
|
||||
EmitSibMagic(param1, param2);
|
||||
}
|
||||
EmitSibMagic(param1, param2);
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
__emitinline void xOpWrite0F(u8 prefix, u16 opcode, const T1 ¶m1, const T2 ¶m2, u8 imm8)
|
||||
{
|
||||
if (prefix != 0)
|
||||
xWrite8(prefix);
|
||||
EmitRex(param1, param2);
|
||||
template <typename T1, typename T2>
|
||||
__emitinline void xOpWrite0F(u8 prefix, u16 opcode, const T1& param1, const T2& param2, u8 imm8)
|
||||
{
|
||||
if (prefix != 0)
|
||||
xWrite8(prefix);
|
||||
EmitRex(param1, param2);
|
||||
|
||||
SimdPrefix(0, opcode);
|
||||
SimdPrefix(0, opcode);
|
||||
|
||||
EmitSibMagic(param1, param2, 1);
|
||||
xWrite8(imm8);
|
||||
}
|
||||
EmitSibMagic(param1, param2, 1);
|
||||
xWrite8(imm8);
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
__emitinline void xOpWrite0F(u16 opcode, const T1 ¶m1, const T2 ¶m2)
|
||||
{
|
||||
xOpWrite0F(0, opcode, param1, param2);
|
||||
}
|
||||
template <typename T1, typename T2>
|
||||
__emitinline void xOpWrite0F(u16 opcode, const T1& param1, const T2& param2)
|
||||
{
|
||||
xOpWrite0F(0, opcode, param1, param2);
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
__emitinline void xOpWrite0F(u16 opcode, const T1 ¶m1, const T2 ¶m2, u8 imm8)
|
||||
{
|
||||
xOpWrite0F(0, opcode, param1, param2, imm8);
|
||||
}
|
||||
template <typename T1, typename T2>
|
||||
__emitinline void xOpWrite0F(u16 opcode, const T1& param1, const T2& param2, u8 imm8)
|
||||
{
|
||||
xOpWrite0F(0, opcode, param1, param2, imm8);
|
||||
}
|
||||
|
||||
// VEX 2 Bytes Prefix
|
||||
template <typename T1, typename T2, typename T3>
|
||||
__emitinline void xOpWriteC5(u8 prefix, u8 opcode, const T1 ¶m1, const T2 ¶m2, const T3 ¶m3)
|
||||
{
|
||||
pxAssert(prefix == 0 || prefix == 0x66 || prefix == 0xF3 || prefix == 0xF2);
|
||||
// VEX 2 Bytes Prefix
|
||||
template <typename T1, typename T2, typename T3>
|
||||
__emitinline void xOpWriteC5(u8 prefix, u8 opcode, const T1& param1, const T2& param2, const T3& param3)
|
||||
{
|
||||
pxAssert(prefix == 0 || prefix == 0x66 || prefix == 0xF3 || prefix == 0xF2);
|
||||
|
||||
const xRegisterInt ® = param1.IsReg() ? param1 : param2;
|
||||
const xRegisterInt& reg = param1.IsReg() ? param1 : param2;
|
||||
|
||||
#ifdef __M_X86_64
|
||||
u8 nR = reg.IsExtended() ? 0x00 : 0x80;
|
||||
u8 nR = reg.IsExtended() ? 0x00 : 0x80;
|
||||
#else
|
||||
u8 nR = 0x80;
|
||||
u8 nR = 0x80;
|
||||
#endif
|
||||
u8 L = reg.IsWideSIMD() ? 4 : 0;
|
||||
u8 L = reg.IsWideSIMD() ? 4 : 0;
|
||||
|
||||
u8 nv = (~param2.GetId() & 0xF) << 3;
|
||||
u8 nv = (~param2.GetId() & 0xF) << 3;
|
||||
|
||||
u8 p =
|
||||
prefix == 0xF2 ? 3 :
|
||||
prefix == 0xF3 ? 2 :
|
||||
prefix == 0x66 ? 1 : 0;
|
||||
u8 p =
|
||||
prefix == 0xF2 ? 3 :
|
||||
prefix == 0xF3 ? 2 :
|
||||
prefix == 0x66 ? 1 :
|
||||
0;
|
||||
|
||||
xWrite8(0xC5);
|
||||
xWrite8(nR | nv | L | p);
|
||||
xWrite8(opcode);
|
||||
EmitSibMagic(param1, param3);
|
||||
}
|
||||
xWrite8(0xC5);
|
||||
xWrite8(nR | nv | L | p);
|
||||
xWrite8(opcode);
|
||||
EmitSibMagic(param1, param3);
|
||||
}
|
||||
|
||||
// VEX 3 Bytes Prefix
|
||||
template <typename T1, typename T2, typename T3>
|
||||
__emitinline void xOpWriteC4(u8 prefix, u8 mb_prefix, u8 opcode, const T1 ¶m1, const T2 ¶m2, const T3 ¶m3, int w = -1)
|
||||
{
|
||||
pxAssert(prefix == 0 || prefix == 0x66 || prefix == 0xF3 || prefix == 0xF2);
|
||||
pxAssert(mb_prefix == 0x0F || mb_prefix == 0x38 || mb_prefix == 0x3A);
|
||||
// VEX 3 Bytes Prefix
|
||||
template <typename T1, typename T2, typename T3>
|
||||
__emitinline void xOpWriteC4(u8 prefix, u8 mb_prefix, u8 opcode, const T1& param1, const T2& param2, const T3& param3, int w = -1)
|
||||
{
|
||||
pxAssert(prefix == 0 || prefix == 0x66 || prefix == 0xF3 || prefix == 0xF2);
|
||||
pxAssert(mb_prefix == 0x0F || mb_prefix == 0x38 || mb_prefix == 0x3A);
|
||||
|
||||
const xRegisterInt ® = param1.IsReg() ? param1 : param2;
|
||||
const xRegisterInt& reg = param1.IsReg() ? param1 : param2;
|
||||
|
||||
#ifdef __M_X86_64
|
||||
u8 nR = reg.IsExtended() ? 0x00 : 0x80;
|
||||
u8 nB = param3.IsExtended() ? 0x00 : 0x20;
|
||||
u8 nX = 0x40; // likely unused so hardwired to disabled
|
||||
u8 nR = reg.IsExtended() ? 0x00 : 0x80;
|
||||
u8 nB = param3.IsExtended() ? 0x00 : 0x20;
|
||||
u8 nX = 0x40; // likely unused so hardwired to disabled
|
||||
#else
|
||||
u8 nR = 0x80;
|
||||
u8 nB = 0x20;
|
||||
u8 nX = 0x40;
|
||||
u8 nR = 0x80;
|
||||
u8 nB = 0x20;
|
||||
u8 nX = 0x40;
|
||||
#endif
|
||||
u8 L = reg.IsWideSIMD() ? 4 : 0;
|
||||
u8 W = (w == -1) ? (reg.GetOperandSize() == 8 ? 0x80 : 0) : // autodetect the size
|
||||
0x80 * w; // take directly the W value
|
||||
u8 L = reg.IsWideSIMD() ? 4 : 0;
|
||||
u8 W = (w == -1) ? (reg.GetOperandSize() == 8 ? 0x80 : 0) : // autodetect the size
|
||||
0x80 * w; // take directly the W value
|
||||
|
||||
u8 nv = (~param2.GetId() & 0xF) << 3;
|
||||
u8 nv = (~param2.GetId() & 0xF) << 3;
|
||||
|
||||
u8 p =
|
||||
prefix == 0xF2 ? 3 :
|
||||
prefix == 0xF3 ? 2 :
|
||||
prefix == 0x66 ? 1 : 0;
|
||||
u8 p =
|
||||
prefix == 0xF2 ? 3 :
|
||||
prefix == 0xF3 ? 2 :
|
||||
prefix == 0x66 ? 1 :
|
||||
0;
|
||||
|
||||
u8 m =
|
||||
mb_prefix == 0x3A ? 3 :
|
||||
mb_prefix == 0x38 ? 2 : 1;
|
||||
u8 m =
|
||||
mb_prefix == 0x3A ? 3 :
|
||||
mb_prefix == 0x38 ? 2 :
|
||||
1;
|
||||
|
||||
xWrite8(0xC4);
|
||||
xWrite8(nR | nX | nB | m);
|
||||
xWrite8(W | nv | L | p);
|
||||
xWrite8(opcode);
|
||||
EmitSibMagic(param1, param3);
|
||||
}
|
||||
}
|
||||
xWrite8(0xC4);
|
||||
xWrite8(nR | nX | nB | m);
|
||||
xWrite8(W | nv | L | p);
|
||||
xWrite8(opcode);
|
||||
EmitSibMagic(param1, param3);
|
||||
}
|
||||
} // namespace x86Emitter
|
||||
|
|
|
@ -33,215 +33,253 @@
|
|||
namespace x86Emitter
|
||||
{
|
||||
|
||||
void xImpl_JmpCall::operator()(const xAddressReg &absreg) const {
|
||||
// Jumps are always wide and don't need the rex.W
|
||||
xOpWrite(0, 0xff, isJmp ? 4 : 2, absreg.GetNonWide());
|
||||
}
|
||||
void xImpl_JmpCall::operator()(const xIndirectNative &src) const {
|
||||
// Jumps are always wide and don't need the rex.W
|
||||
EmitRex(0, xIndirect32(src.Base, src.Index, 1, 0));
|
||||
xWrite8(0xff);
|
||||
EmitSibMagic(isJmp ? 4 : 2, src);
|
||||
}
|
||||
void xImpl_JmpCall::operator()(const xAddressReg& absreg) const
|
||||
{
|
||||
// Jumps are always wide and don't need the rex.W
|
||||
xOpWrite(0, 0xff, isJmp ? 4 : 2, absreg.GetNonWide());
|
||||
}
|
||||
void xImpl_JmpCall::operator()(const xIndirectNative& src) const
|
||||
{
|
||||
// Jumps are always wide and don't need the rex.W
|
||||
EmitRex(0, xIndirect32(src.Base, src.Index, 1, 0));
|
||||
xWrite8(0xff);
|
||||
EmitSibMagic(isJmp ? 4 : 2, src);
|
||||
}
|
||||
|
||||
const xImpl_JmpCall xJMP = {true};
|
||||
const xImpl_JmpCall xCALL = {false};
|
||||
const xImpl_JmpCall xJMP = {true};
|
||||
const xImpl_JmpCall xCALL = {false};
|
||||
|
||||
|
||||
template <typename Reg1, typename Reg2>
|
||||
void prepareRegsForFastcall(const Reg1 &a1, const Reg2 &a2) {
|
||||
if (a1.IsEmpty()) return;
|
||||
template <typename Reg1, typename Reg2>
|
||||
void prepareRegsForFastcall(const Reg1& a1, const Reg2& a2)
|
||||
{
|
||||
if (a1.IsEmpty())
|
||||
return;
|
||||
|
||||
// Make sure we don't mess up if someone tries to fastcall with a1 in arg2reg and a2 in arg1reg
|
||||
if (a2.Id != arg1reg.Id) {
|
||||
xMOV(Reg1(arg1reg), a1);
|
||||
if (!a2.IsEmpty()) {
|
||||
xMOV(Reg2(arg2reg), a2);
|
||||
}
|
||||
} else if (a1.Id != arg2reg.Id) {
|
||||
xMOV(Reg2(arg2reg), a2);
|
||||
xMOV(Reg1(arg1reg), a1);
|
||||
} else {
|
||||
xPUSH(a1);
|
||||
xMOV(Reg2(arg2reg), a2);
|
||||
xPOP(Reg1(arg1reg));
|
||||
}
|
||||
}
|
||||
// Make sure we don't mess up if someone tries to fastcall with a1 in arg2reg and a2 in arg1reg
|
||||
if (a2.Id != arg1reg.Id)
|
||||
{
|
||||
xMOV(Reg1(arg1reg), a1);
|
||||
if (!a2.IsEmpty())
|
||||
{
|
||||
xMOV(Reg2(arg2reg), a2);
|
||||
}
|
||||
}
|
||||
else if (a1.Id != arg2reg.Id)
|
||||
{
|
||||
xMOV(Reg2(arg2reg), a2);
|
||||
xMOV(Reg1(arg1reg), a1);
|
||||
}
|
||||
else
|
||||
{
|
||||
xPUSH(a1);
|
||||
xMOV(Reg2(arg2reg), a2);
|
||||
xPOP(Reg1(arg1reg));
|
||||
}
|
||||
}
|
||||
|
||||
void xImpl_FastCall::operator()(void *f, const xRegister32 &a1, const xRegister32 &a2) const {
|
||||
prepareRegsForFastcall(a1, a2);
|
||||
uptr disp = ((uptr)xGetPtr() + 5) - (uptr)f;
|
||||
if ((sptr)disp == (s32)disp) {
|
||||
xCALL(f);
|
||||
} else {
|
||||
xMOV(rax, ptrNative[f]);
|
||||
xCALL(rax);
|
||||
}
|
||||
}
|
||||
void xImpl_FastCall::operator()(void* f, const xRegister32& a1, const xRegister32& a2) const
|
||||
{
|
||||
prepareRegsForFastcall(a1, a2);
|
||||
uptr disp = ((uptr)xGetPtr() + 5) - (uptr)f;
|
||||
if ((sptr)disp == (s32)disp)
|
||||
{
|
||||
xCALL(f);
|
||||
}
|
||||
else
|
||||
{
|
||||
xMOV(rax, ptrNative[f]);
|
||||
xCALL(rax);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __M_X86_64
|
||||
void xImpl_FastCall::operator()(void *f, const xRegisterLong &a1, const xRegisterLong &a2) const {
|
||||
prepareRegsForFastcall(a1, a2);
|
||||
uptr disp = ((uptr)xGetPtr() + 5) - (uptr)f;
|
||||
if ((sptr)disp == (s32)disp) {
|
||||
xCALL(f);
|
||||
} else {
|
||||
xMOV(rax, ptrNative[f]);
|
||||
xCALL(rax);
|
||||
}
|
||||
}
|
||||
void xImpl_FastCall::operator()(void* f, const xRegisterLong& a1, const xRegisterLong& a2) const
|
||||
{
|
||||
prepareRegsForFastcall(a1, a2);
|
||||
uptr disp = ((uptr)xGetPtr() + 5) - (uptr)f;
|
||||
if ((sptr)disp == (s32)disp)
|
||||
{
|
||||
xCALL(f);
|
||||
}
|
||||
else
|
||||
{
|
||||
xMOV(rax, ptrNative[f]);
|
||||
xCALL(rax);
|
||||
}
|
||||
}
|
||||
|
||||
void xImpl_FastCall::operator()(void *f, u32 a1, const xRegisterLong &a2) const {
|
||||
if (!a2.IsEmpty()) { xMOV(arg2reg, a2); }
|
||||
xMOV(arg1reg, a1);
|
||||
(*this)(f, arg1reg, arg2reg);
|
||||
}
|
||||
void xImpl_FastCall::operator()(void* f, u32 a1, const xRegisterLong& a2) const
|
||||
{
|
||||
if (!a2.IsEmpty())
|
||||
{
|
||||
xMOV(arg2reg, a2);
|
||||
}
|
||||
xMOV(arg1reg, a1);
|
||||
(*this)(f, arg1reg, arg2reg);
|
||||
}
|
||||
#endif
|
||||
|
||||
void xImpl_FastCall::operator()(void *f, void *a1) const {
|
||||
xLEA(arg1reg, ptr[a1]);
|
||||
(*this)(f, arg1reg, arg2reg);
|
||||
}
|
||||
void xImpl_FastCall::operator()(void* f, void* a1) const
|
||||
{
|
||||
xLEA(arg1reg, ptr[a1]);
|
||||
(*this)(f, arg1reg, arg2reg);
|
||||
}
|
||||
|
||||
void xImpl_FastCall::operator()(void *f, u32 a1, const xRegister32 &a2) const {
|
||||
if (!a2.IsEmpty()) { xMOV(arg2regd, a2); }
|
||||
xMOV(arg1regd, a1);
|
||||
(*this)(f, arg1regd, arg2regd);
|
||||
}
|
||||
void xImpl_FastCall::operator()(void* f, u32 a1, const xRegister32& a2) const
|
||||
{
|
||||
if (!a2.IsEmpty())
|
||||
{
|
||||
xMOV(arg2regd, a2);
|
||||
}
|
||||
xMOV(arg1regd, a1);
|
||||
(*this)(f, arg1regd, arg2regd);
|
||||
}
|
||||
|
||||
void xImpl_FastCall::operator()(void *f, const xIndirect32 &a1) const {
|
||||
xMOV(arg1regd, a1);
|
||||
(*this)(f, arg1regd);
|
||||
}
|
||||
void xImpl_FastCall::operator()(void* f, const xIndirect32& a1) const
|
||||
{
|
||||
xMOV(arg1regd, a1);
|
||||
(*this)(f, arg1regd);
|
||||
}
|
||||
|
||||
void xImpl_FastCall::operator()(void *f, u32 a1, u32 a2) const {
|
||||
xMOV(arg1regd, a1);
|
||||
xMOV(arg2regd, a2);
|
||||
(*this)(f, arg1regd, arg2regd);
|
||||
}
|
||||
void xImpl_FastCall::operator()(void* f, u32 a1, u32 a2) const
|
||||
{
|
||||
xMOV(arg1regd, a1);
|
||||
xMOV(arg2regd, a2);
|
||||
(*this)(f, arg1regd, arg2regd);
|
||||
}
|
||||
|
||||
void xImpl_FastCall::operator()(const xIndirectNative &f, const xRegisterLong &a1, const xRegisterLong &a2) const {
|
||||
prepareRegsForFastcall(a1, a2);
|
||||
xCALL(f);
|
||||
}
|
||||
void xImpl_FastCall::operator()(const xIndirectNative& f, const xRegisterLong& a1, const xRegisterLong& a2) const
|
||||
{
|
||||
prepareRegsForFastcall(a1, a2);
|
||||
xCALL(f);
|
||||
}
|
||||
|
||||
const xImpl_FastCall xFastCall = {};
|
||||
const xImpl_FastCall xFastCall = {};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Emits a 32 bit jump, and returns a pointer to the 32 bit displacement.
|
||||
// (displacements should be assigned relative to the end of the jump instruction,
|
||||
// or in other words *(retval+1) )
|
||||
__emitinline s32 *xJcc32(JccComparisonType comparison, s32 displacement)
|
||||
{
|
||||
if (comparison == Jcc_Unconditional)
|
||||
xWrite8(0xe9);
|
||||
else {
|
||||
xWrite8(0x0f);
|
||||
xWrite8(0x80 | comparison);
|
||||
}
|
||||
xWrite<s32>(displacement);
|
||||
// ------------------------------------------------------------------------
|
||||
// Emits a 32 bit jump, and returns a pointer to the 32 bit displacement.
|
||||
// (displacements should be assigned relative to the end of the jump instruction,
|
||||
// or in other words *(retval+1) )
|
||||
__emitinline s32* xJcc32(JccComparisonType comparison, s32 displacement)
|
||||
{
|
||||
if (comparison == Jcc_Unconditional)
|
||||
xWrite8(0xe9);
|
||||
else
|
||||
{
|
||||
xWrite8(0x0f);
|
||||
xWrite8(0x80 | comparison);
|
||||
}
|
||||
xWrite<s32>(displacement);
|
||||
|
||||
return ((s32 *)xGetPtr()) - 1;
|
||||
}
|
||||
return ((s32*)xGetPtr()) - 1;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Emits a 32 bit jump, and returns a pointer to the 8 bit displacement.
|
||||
// (displacements should be assigned relative to the end of the jump instruction,
|
||||
// or in other words *(retval+1) )
|
||||
__emitinline s8 *xJcc8(JccComparisonType comparison, s8 displacement)
|
||||
{
|
||||
xWrite8((comparison == Jcc_Unconditional) ? 0xeb : (0x70 | comparison));
|
||||
xWrite<s8>(displacement);
|
||||
return (s8 *)xGetPtr() - 1;
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
// Emits a 32 bit jump, and returns a pointer to the 8 bit displacement.
|
||||
// (displacements should be assigned relative to the end of the jump instruction,
|
||||
// or in other words *(retval+1) )
|
||||
__emitinline s8* xJcc8(JccComparisonType comparison, s8 displacement)
|
||||
{
|
||||
xWrite8((comparison == Jcc_Unconditional) ? 0xeb : (0x70 | comparison));
|
||||
xWrite<s8>(displacement);
|
||||
return (s8*)xGetPtr() - 1;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Writes a jump at the current x86Ptr, which targets a pre-established target address.
|
||||
// (usually a backwards jump)
|
||||
//
|
||||
// slideForward - used internally by xSmartJump to indicate that the jump target is going
|
||||
// to slide forward in the event of an 8 bit displacement.
|
||||
//
|
||||
__emitinline void xJccKnownTarget(JccComparisonType comparison, const void *target, bool slideForward)
|
||||
{
|
||||
// Calculate the potential j8 displacement first, assuming an instruction length of 2:
|
||||
sptr displacement8 = (sptr)target - (sptr)(xGetPtr() + 2);
|
||||
// ------------------------------------------------------------------------
|
||||
// Writes a jump at the current x86Ptr, which targets a pre-established target address.
|
||||
// (usually a backwards jump)
|
||||
//
|
||||
// slideForward - used internally by xSmartJump to indicate that the jump target is going
|
||||
// to slide forward in the event of an 8 bit displacement.
|
||||
//
|
||||
__emitinline void xJccKnownTarget(JccComparisonType comparison, const void* target, bool slideForward)
|
||||
{
|
||||
// Calculate the potential j8 displacement first, assuming an instruction length of 2:
|
||||
sptr displacement8 = (sptr)target - (sptr)(xGetPtr() + 2);
|
||||
|
||||
const int slideVal = slideForward ? ((comparison == Jcc_Unconditional) ? 3 : 4) : 0;
|
||||
displacement8 -= slideVal;
|
||||
const int slideVal = slideForward ? ((comparison == Jcc_Unconditional) ? 3 : 4) : 0;
|
||||
displacement8 -= slideVal;
|
||||
|
||||
if (slideForward) {
|
||||
pxAssertDev(displacement8 >= 0, "Used slideForward on a backward jump; nothing to slide!");
|
||||
}
|
||||
if (slideForward)
|
||||
{
|
||||
pxAssertDev(displacement8 >= 0, "Used slideForward on a backward jump; nothing to slide!");
|
||||
}
|
||||
|
||||
if (is_s8(displacement8))
|
||||
xJcc8(comparison, displacement8);
|
||||
else {
|
||||
// Perform a 32 bit jump instead. :(
|
||||
s32 *bah = xJcc32(comparison);
|
||||
sptr distance = (sptr)target - (sptr)xGetPtr();
|
||||
if (is_s8(displacement8))
|
||||
xJcc8(comparison, displacement8);
|
||||
else
|
||||
{
|
||||
// Perform a 32 bit jump instead. :(
|
||||
s32* bah = xJcc32(comparison);
|
||||
sptr distance = (sptr)target - (sptr)xGetPtr();
|
||||
|
||||
#ifdef __M_X86_64
|
||||
// This assert won't physically happen on x86 targets
|
||||
pxAssertDev(distance >= -0x80000000LL && distance < 0x80000000LL, "Jump target is too far away, needs an indirect register");
|
||||
// This assert won't physically happen on x86 targets
|
||||
pxAssertDev(distance >= -0x80000000LL && distance < 0x80000000LL, "Jump target is too far away, needs an indirect register");
|
||||
#endif
|
||||
|
||||
*bah = (s32)distance;
|
||||
}
|
||||
}
|
||||
*bah = (s32)distance;
|
||||
}
|
||||
}
|
||||
|
||||
// Low-level jump instruction! Specify a comparison type and a target in void* form, and
|
||||
// a jump (either 8 or 32 bit) is generated.
|
||||
__emitinline void xJcc(JccComparisonType comparison, const void *target)
|
||||
{
|
||||
xJccKnownTarget(comparison, target, false);
|
||||
}
|
||||
// Low-level jump instruction! Specify a comparison type and a target in void* form, and
|
||||
// a jump (either 8 or 32 bit) is generated.
|
||||
__emitinline void xJcc(JccComparisonType comparison, const void* target)
|
||||
{
|
||||
xJccKnownTarget(comparison, target, false);
|
||||
}
|
||||
|
||||
xForwardJumpBase::xForwardJumpBase(uint opsize, JccComparisonType cctype)
|
||||
{
|
||||
pxAssert(opsize == 1 || opsize == 4);
|
||||
pxAssertDev(cctype != Jcc_Unknown, "Invalid ForwardJump conditional type.");
|
||||
xForwardJumpBase::xForwardJumpBase(uint opsize, JccComparisonType cctype)
|
||||
{
|
||||
pxAssert(opsize == 1 || opsize == 4);
|
||||
pxAssertDev(cctype != Jcc_Unknown, "Invalid ForwardJump conditional type.");
|
||||
|
||||
BasePtr = (s8 *)xGetPtr() +
|
||||
((opsize == 1) ? 2 : // j8's are always 2 bytes.
|
||||
((cctype == Jcc_Unconditional) ? 5 : 6)); // j32's are either 5 or 6 bytes
|
||||
BasePtr = (s8*)xGetPtr() +
|
||||
((opsize == 1) ? 2 : // j8's are always 2 bytes.
|
||||
((cctype == Jcc_Unconditional) ? 5 : 6)); // j32's are either 5 or 6 bytes
|
||||
|
||||
if (opsize == 1)
|
||||
xWrite8((cctype == Jcc_Unconditional) ? 0xeb : (0x70 | cctype));
|
||||
else {
|
||||
if (cctype == Jcc_Unconditional)
|
||||
xWrite8(0xe9);
|
||||
else {
|
||||
xWrite8(0x0f);
|
||||
xWrite8(0x80 | cctype);
|
||||
}
|
||||
}
|
||||
if (opsize == 1)
|
||||
xWrite8((cctype == Jcc_Unconditional) ? 0xeb : (0x70 | cctype));
|
||||
else
|
||||
{
|
||||
if (cctype == Jcc_Unconditional)
|
||||
xWrite8(0xe9);
|
||||
else
|
||||
{
|
||||
xWrite8(0x0f);
|
||||
xWrite8(0x80 | cctype);
|
||||
}
|
||||
}
|
||||
|
||||
xAdvancePtr(opsize);
|
||||
}
|
||||
xAdvancePtr(opsize);
|
||||
}
|
||||
|
||||
void xForwardJumpBase::_setTarget(uint opsize) const
|
||||
{
|
||||
pxAssertDev(BasePtr != NULL, "");
|
||||
void xForwardJumpBase::_setTarget(uint opsize) const
|
||||
{
|
||||
pxAssertDev(BasePtr != NULL, "");
|
||||
|
||||
sptr displacement = (sptr)xGetPtr() - (sptr)BasePtr;
|
||||
if (opsize == 1) {
|
||||
pxAssertDev(is_s8(displacement), "Emitter Error: Invalid short jump displacement.");
|
||||
BasePtr[-1] = (s8)displacement;
|
||||
} else {
|
||||
// full displacement, no sanity checks needed :D
|
||||
((s32 *)BasePtr)[-1] = displacement;
|
||||
}
|
||||
}
|
||||
sptr displacement = (sptr)xGetPtr() - (sptr)BasePtr;
|
||||
if (opsize == 1)
|
||||
{
|
||||
pxAssertDev(is_s8(displacement), "Emitter Error: Invalid short jump displacement.");
|
||||
BasePtr[-1] = (s8)displacement;
|
||||
}
|
||||
else
|
||||
{
|
||||
// full displacement, no sanity checks needed :D
|
||||
((s32*)BasePtr)[-1] = displacement;
|
||||
}
|
||||
}
|
||||
|
||||
// returns the inverted conditional type for this Jcc condition. Ie, JNS will become JS.
|
||||
__fi JccComparisonType xInvertCond(JccComparisonType src)
|
||||
{
|
||||
pxAssert(src != Jcc_Unknown);
|
||||
if (Jcc_Unconditional == src)
|
||||
return Jcc_Unconditional;
|
||||
// returns the inverted conditional type for this Jcc condition. Ie, JNS will become JS.
|
||||
__fi JccComparisonType xInvertCond(JccComparisonType src)
|
||||
{
|
||||
pxAssert(src != Jcc_Unknown);
|
||||
if (Jcc_Unconditional == src)
|
||||
return Jcc_Unconditional;
|
||||
|
||||
// x86 conditionals are clever! To invert conditional types, just invert the lower bit:
|
||||
return (JccComparisonType)((int)src ^ 1);
|
||||
}
|
||||
}
|
||||
// x86 conditionals are clever! To invert conditional types, just invert the lower bit:
|
||||
return (JccComparisonType)((int)src ^ 1);
|
||||
}
|
||||
} // namespace x86Emitter
|
||||
|
|
|
@ -29,24 +29,24 @@
|
|||
|
||||
emitterT void ModRM(uint mod, uint reg, uint rm)
|
||||
{
|
||||
// Note: Following assertions are for legacy support only.
|
||||
// The new emitter performs these sanity checks during operand construction, so these
|
||||
// assertions can probably be removed once all legacy emitter code has been removed.
|
||||
pxAssert(mod < 4);
|
||||
pxAssert(reg < 8);
|
||||
pxAssert(rm < 8);
|
||||
xWrite8((mod << 6) | (reg << 3) | rm);
|
||||
// Note: Following assertions are for legacy support only.
|
||||
// The new emitter performs these sanity checks during operand construction, so these
|
||||
// assertions can probably be removed once all legacy emitter code has been removed.
|
||||
pxAssert(mod < 4);
|
||||
pxAssert(reg < 8);
|
||||
pxAssert(rm < 8);
|
||||
xWrite8((mod << 6) | (reg << 3) | rm);
|
||||
}
|
||||
|
||||
emitterT void SibSB(uint ss, uint index, uint base)
|
||||
{
|
||||
// Note: Following asserts are for legacy support only.
|
||||
// The new emitter performs these sanity checks during operand construction, so these
|
||||
// assertions can probably be removed once all legacy emitter code has been removed.
|
||||
pxAssert(ss < 4);
|
||||
pxAssert(index < 8);
|
||||
pxAssert(base < 8);
|
||||
xWrite8((ss << 6) | (index << 3) | base);
|
||||
// Note: Following asserts are for legacy support only.
|
||||
// The new emitter performs these sanity checks during operand construction, so these
|
||||
// assertions can probably be removed once all legacy emitter code has been removed.
|
||||
pxAssert(ss < 4);
|
||||
pxAssert(index < 8);
|
||||
pxAssert(base < 8);
|
||||
xWrite8((ss << 6) | (index << 3) | base);
|
||||
}
|
||||
|
||||
using namespace x86Emitter;
|
||||
|
@ -57,33 +57,33 @@ using namespace x86Emitter;
|
|||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
emitterT u8 *J8Rel(int cc, int to)
|
||||
emitterT u8* J8Rel(int cc, int to)
|
||||
{
|
||||
xWrite8(cc);
|
||||
xWrite8(to);
|
||||
return (u8 *)(x86Ptr - 1);
|
||||
xWrite8(cc);
|
||||
xWrite8(to);
|
||||
return (u8*)(x86Ptr - 1);
|
||||
}
|
||||
|
||||
emitterT u16 *J16Rel(int cc, u32 to)
|
||||
emitterT u16* J16Rel(int cc, u32 to)
|
||||
{
|
||||
xWrite16(0x0F66);
|
||||
xWrite8(cc);
|
||||
xWrite16(to);
|
||||
return (u16 *)(x86Ptr - 2);
|
||||
xWrite16(0x0F66);
|
||||
xWrite8(cc);
|
||||
xWrite16(to);
|
||||
return (u16*)(x86Ptr - 2);
|
||||
}
|
||||
|
||||
emitterT u32 *J32Rel(int cc, u32 to)
|
||||
emitterT u32* J32Rel(int cc, u32 to)
|
||||
{
|
||||
xWrite8(0x0F);
|
||||
xWrite8(cc);
|
||||
xWrite32(to);
|
||||
return (u32 *)(x86Ptr - 4);
|
||||
xWrite8(0x0F);
|
||||
xWrite8(cc);
|
||||
xWrite32(to);
|
||||
return (u32*)(x86Ptr - 4);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
emitterT void x86SetPtr(u8 *ptr)
|
||||
emitterT void x86SetPtr(u8* ptr)
|
||||
{
|
||||
x86Ptr = ptr;
|
||||
x86Ptr = ptr;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -92,57 +92,61 @@ emitterT void x86SetPtr(u8 *ptr)
|
|||
// I don't auto-inline these because of the console logging in case of error, which tends
|
||||
// to cause quite a bit of code bloat.
|
||||
//
|
||||
void x86SetJ8(u8 *j8)
|
||||
void x86SetJ8(u8* j8)
|
||||
{
|
||||
u32 jump = (x86Ptr - j8) - 1;
|
||||
u32 jump = (x86Ptr - j8) - 1;
|
||||
|
||||
if (jump > 0x7f) {
|
||||
Console.Error("j8 greater than 0x7f!!");
|
||||
assert(0);
|
||||
}
|
||||
*j8 = (u8)jump;
|
||||
if (jump > 0x7f)
|
||||
{
|
||||
Console.Error("j8 greater than 0x7f!!");
|
||||
assert(0);
|
||||
}
|
||||
*j8 = (u8)jump;
|
||||
}
|
||||
|
||||
void x86SetJ8A(u8 *j8)
|
||||
void x86SetJ8A(u8* j8)
|
||||
{
|
||||
u32 jump = (x86Ptr - j8) - 1;
|
||||
u32 jump = (x86Ptr - j8) - 1;
|
||||
|
||||
if (jump > 0x7f) {
|
||||
Console.Error("j8 greater than 0x7f!!");
|
||||
assert(0);
|
||||
}
|
||||
if (jump > 0x7f)
|
||||
{
|
||||
Console.Error("j8 greater than 0x7f!!");
|
||||
assert(0);
|
||||
}
|
||||
|
||||
if (((uptr)x86Ptr & 0xf) > 4) {
|
||||
if (((uptr)x86Ptr & 0xf) > 4)
|
||||
{
|
||||
|
||||
uptr newjump = jump + 16 - ((uptr)x86Ptr & 0xf);
|
||||
uptr newjump = jump + 16 - ((uptr)x86Ptr & 0xf);
|
||||
|
||||
if (newjump <= 0x7f) {
|
||||
jump = newjump;
|
||||
while ((uptr)x86Ptr & 0xf)
|
||||
*x86Ptr++ = 0x90;
|
||||
}
|
||||
}
|
||||
*j8 = (u8)jump;
|
||||
if (newjump <= 0x7f)
|
||||
{
|
||||
jump = newjump;
|
||||
while ((uptr)x86Ptr & 0xf)
|
||||
*x86Ptr++ = 0x90;
|
||||
}
|
||||
}
|
||||
*j8 = (u8)jump;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
emitterT void x86SetJ32(u32 *j32)
|
||||
emitterT void x86SetJ32(u32* j32)
|
||||
{
|
||||
*j32 = (x86Ptr - (u8 *)j32) - 4;
|
||||
*j32 = (x86Ptr - (u8*)j32) - 4;
|
||||
}
|
||||
|
||||
emitterT void x86SetJ32A(u32 *j32)
|
||||
emitterT void x86SetJ32A(u32* j32)
|
||||
{
|
||||
while ((uptr)x86Ptr & 0xf)
|
||||
*x86Ptr++ = 0x90;
|
||||
x86SetJ32(j32);
|
||||
while ((uptr)x86Ptr & 0xf)
|
||||
*x86Ptr++ = 0x90;
|
||||
x86SetJ32(j32);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
emitterT void x86Align(int bytes)
|
||||
{
|
||||
// forward align
|
||||
x86Ptr = (u8 *)(((uptr)x86Ptr + bytes - 1) & ~(bytes - 1));
|
||||
// forward align
|
||||
x86Ptr = (u8*)(((uptr)x86Ptr + bytes - 1) & ~(bytes - 1));
|
||||
}
|
||||
|
||||
/********************/
|
||||
|
@ -154,262 +158,262 @@ emitterT void x86Align(int bytes)
|
|||
////////////////////////////////////
|
||||
|
||||
/* jmp rel8 */
|
||||
emitterT u8 *JMP8(u8 to)
|
||||
emitterT u8* JMP8(u8 to)
|
||||
{
|
||||
xWrite8(0xEB);
|
||||
xWrite8(to);
|
||||
return x86Ptr - 1;
|
||||
xWrite8(0xEB);
|
||||
xWrite8(to);
|
||||
return x86Ptr - 1;
|
||||
}
|
||||
|
||||
/* jmp rel32 */
|
||||
emitterT u32 *JMP32(uptr to)
|
||||
emitterT u32* JMP32(uptr to)
|
||||
{
|
||||
assert((sptr)to <= 0x7fffffff && (sptr)to >= -0x7fffffff);
|
||||
xWrite8(0xE9);
|
||||
xWrite32(to);
|
||||
return (u32 *)(x86Ptr - 4);
|
||||
assert((sptr)to <= 0x7fffffff && (sptr)to >= -0x7fffffff);
|
||||
xWrite8(0xE9);
|
||||
xWrite32(to);
|
||||
return (u32*)(x86Ptr - 4);
|
||||
}
|
||||
|
||||
/* jp rel8 */
|
||||
emitterT u8 *JP8(u8 to)
|
||||
emitterT u8* JP8(u8 to)
|
||||
{
|
||||
return J8Rel(0x7A, to);
|
||||
return J8Rel(0x7A, to);
|
||||
}
|
||||
|
||||
/* jnp rel8 */
|
||||
emitterT u8 *JNP8(u8 to)
|
||||
emitterT u8* JNP8(u8 to)
|
||||
{
|
||||
return J8Rel(0x7B, to);
|
||||
return J8Rel(0x7B, to);
|
||||
}
|
||||
|
||||
/* je rel8 */
|
||||
emitterT u8 *JE8(u8 to)
|
||||
emitterT u8* JE8(u8 to)
|
||||
{
|
||||
return J8Rel(0x74, to);
|
||||
return J8Rel(0x74, to);
|
||||
}
|
||||
|
||||
/* jz rel8 */
|
||||
emitterT u8 *JZ8(u8 to)
|
||||
emitterT u8* JZ8(u8 to)
|
||||
{
|
||||
return J8Rel(0x74, to);
|
||||
return J8Rel(0x74, to);
|
||||
}
|
||||
|
||||
/* js rel8 */
|
||||
emitterT u8 *JS8(u8 to)
|
||||
emitterT u8* JS8(u8 to)
|
||||
{
|
||||
return J8Rel(0x78, to);
|
||||
return J8Rel(0x78, to);
|
||||
}
|
||||
|
||||
/* jns rel8 */
|
||||
emitterT u8 *JNS8(u8 to)
|
||||
emitterT u8* JNS8(u8 to)
|
||||
{
|
||||
return J8Rel(0x79, to);
|
||||
return J8Rel(0x79, to);
|
||||
}
|
||||
|
||||
/* jg rel8 */
|
||||
emitterT u8 *JG8(u8 to)
|
||||
emitterT u8* JG8(u8 to)
|
||||
{
|
||||
return J8Rel(0x7F, to);
|
||||
return J8Rel(0x7F, to);
|
||||
}
|
||||
|
||||
/* jge rel8 */
|
||||
emitterT u8 *JGE8(u8 to)
|
||||
emitterT u8* JGE8(u8 to)
|
||||
{
|
||||
return J8Rel(0x7D, to);
|
||||
return J8Rel(0x7D, to);
|
||||
}
|
||||
|
||||
/* jl rel8 */
|
||||
emitterT u8 *JL8(u8 to)
|
||||
emitterT u8* JL8(u8 to)
|
||||
{
|
||||
return J8Rel(0x7C, to);
|
||||
return J8Rel(0x7C, to);
|
||||
}
|
||||
|
||||
/* ja rel8 */
|
||||
emitterT u8 *JA8(u8 to)
|
||||
emitterT u8* JA8(u8 to)
|
||||
{
|
||||
return J8Rel(0x77, to);
|
||||
return J8Rel(0x77, to);
|
||||
}
|
||||
|
||||
emitterT u8 *JAE8(u8 to)
|
||||
emitterT u8* JAE8(u8 to)
|
||||
{
|
||||
return J8Rel(0x73, to);
|
||||
return J8Rel(0x73, to);
|
||||
}
|
||||
|
||||
/* jb rel8 */
|
||||
emitterT u8 *JB8(u8 to)
|
||||
emitterT u8* JB8(u8 to)
|
||||
{
|
||||
return J8Rel(0x72, to);
|
||||
return J8Rel(0x72, to);
|
||||
}
|
||||
|
||||
/* jbe rel8 */
|
||||
emitterT u8 *JBE8(u8 to)
|
||||
emitterT u8* JBE8(u8 to)
|
||||
{
|
||||
return J8Rel(0x76, to);
|
||||
return J8Rel(0x76, to);
|
||||
}
|
||||
|
||||
/* jle rel8 */
|
||||
emitterT u8 *JLE8(u8 to)
|
||||
emitterT u8* JLE8(u8 to)
|
||||
{
|
||||
return J8Rel(0x7E, to);
|
||||
return J8Rel(0x7E, to);
|
||||
}
|
||||
|
||||
/* jne rel8 */
|
||||
emitterT u8 *JNE8(u8 to)
|
||||
emitterT u8* JNE8(u8 to)
|
||||
{
|
||||
return J8Rel(0x75, to);
|
||||
return J8Rel(0x75, to);
|
||||
}
|
||||
|
||||
/* jnz rel8 */
|
||||
emitterT u8 *JNZ8(u8 to)
|
||||
emitterT u8* JNZ8(u8 to)
|
||||
{
|
||||
return J8Rel(0x75, to);
|
||||
return J8Rel(0x75, to);
|
||||
}
|
||||
|
||||
/* jng rel8 */
|
||||
emitterT u8 *JNG8(u8 to)
|
||||
emitterT u8* JNG8(u8 to)
|
||||
{
|
||||
return J8Rel(0x7E, to);
|
||||
return J8Rel(0x7E, to);
|
||||
}
|
||||
|
||||
/* jnge rel8 */
|
||||
emitterT u8 *JNGE8(u8 to)
|
||||
emitterT u8* JNGE8(u8 to)
|
||||
{
|
||||
return J8Rel(0x7C, to);
|
||||
return J8Rel(0x7C, to);
|
||||
}
|
||||
|
||||
/* jnl rel8 */
|
||||
emitterT u8 *JNL8(u8 to)
|
||||
emitterT u8* JNL8(u8 to)
|
||||
{
|
||||
return J8Rel(0x7D, to);
|
||||
return J8Rel(0x7D, to);
|
||||
}
|
||||
|
||||
/* jnle rel8 */
|
||||
emitterT u8 *JNLE8(u8 to)
|
||||
emitterT u8* JNLE8(u8 to)
|
||||
{
|
||||
return J8Rel(0x7F, to);
|
||||
return J8Rel(0x7F, to);
|
||||
}
|
||||
|
||||
/* jo rel8 */
|
||||
emitterT u8 *JO8(u8 to)
|
||||
emitterT u8* JO8(u8 to)
|
||||
{
|
||||
return J8Rel(0x70, to);
|
||||
return J8Rel(0x70, to);
|
||||
}
|
||||
|
||||
/* jno rel8 */
|
||||
emitterT u8 *JNO8(u8 to)
|
||||
emitterT u8* JNO8(u8 to)
|
||||
{
|
||||
return J8Rel(0x71, to);
|
||||
return J8Rel(0x71, to);
|
||||
}
|
||||
// jb rel32
|
||||
emitterT u32 *JB32(u32 to)
|
||||
emitterT u32* JB32(u32 to)
|
||||
{
|
||||
return J32Rel(0x82, to);
|
||||
return J32Rel(0x82, to);
|
||||
}
|
||||
|
||||
/* je rel32 */
|
||||
emitterT u32 *JE32(u32 to)
|
||||
emitterT u32* JE32(u32 to)
|
||||
{
|
||||
return J32Rel(0x84, to);
|
||||
return J32Rel(0x84, to);
|
||||
}
|
||||
|
||||
/* jz rel32 */
|
||||
emitterT u32 *JZ32(u32 to)
|
||||
emitterT u32* JZ32(u32 to)
|
||||
{
|
||||
return J32Rel(0x84, to);
|
||||
return J32Rel(0x84, to);
|
||||
}
|
||||
|
||||
/* js rel32 */
|
||||
emitterT u32 *JS32(u32 to)
|
||||
emitterT u32* JS32(u32 to)
|
||||
{
|
||||
return J32Rel(0x88, to);
|
||||
return J32Rel(0x88, to);
|
||||
}
|
||||
|
||||
/* jns rel32 */
|
||||
emitterT u32 *JNS32(u32 to)
|
||||
emitterT u32* JNS32(u32 to)
|
||||
{
|
||||
return J32Rel(0x89, to);
|
||||
return J32Rel(0x89, to);
|
||||
}
|
||||
|
||||
/* jg rel32 */
|
||||
emitterT u32 *JG32(u32 to)
|
||||
emitterT u32* JG32(u32 to)
|
||||
{
|
||||
return J32Rel(0x8F, to);
|
||||
return J32Rel(0x8F, to);
|
||||
}
|
||||
|
||||
/* jge rel32 */
|
||||
emitterT u32 *JGE32(u32 to)
|
||||
emitterT u32* JGE32(u32 to)
|
||||
{
|
||||
return J32Rel(0x8D, to);
|
||||
return J32Rel(0x8D, to);
|
||||
}
|
||||
|
||||
/* jl rel32 */
|
||||
emitterT u32 *JL32(u32 to)
|
||||
emitterT u32* JL32(u32 to)
|
||||
{
|
||||
return J32Rel(0x8C, to);
|
||||
return J32Rel(0x8C, to);
|
||||
}
|
||||
|
||||
/* jle rel32 */
|
||||
emitterT u32 *JLE32(u32 to)
|
||||
emitterT u32* JLE32(u32 to)
|
||||
{
|
||||
return J32Rel(0x8E, to);
|
||||
return J32Rel(0x8E, to);
|
||||
}
|
||||
|
||||
/* ja rel32 */
|
||||
emitterT u32 *JA32(u32 to)
|
||||
emitterT u32* JA32(u32 to)
|
||||
{
|
||||
return J32Rel(0x87, to);
|
||||
return J32Rel(0x87, to);
|
||||
}
|
||||
|
||||
/* jae rel32 */
|
||||
emitterT u32 *JAE32(u32 to)
|
||||
emitterT u32* JAE32(u32 to)
|
||||
{
|
||||
return J32Rel(0x83, to);
|
||||
return J32Rel(0x83, to);
|
||||
}
|
||||
|
||||
/* jne rel32 */
|
||||
emitterT u32 *JNE32(u32 to)
|
||||
emitterT u32* JNE32(u32 to)
|
||||
{
|
||||
return J32Rel(0x85, to);
|
||||
return J32Rel(0x85, to);
|
||||
}
|
||||
|
||||
/* jnz rel32 */
|
||||
emitterT u32 *JNZ32(u32 to)
|
||||
emitterT u32* JNZ32(u32 to)
|
||||
{
|
||||
return J32Rel(0x85, to);
|
||||
return J32Rel(0x85, to);
|
||||
}
|
||||
|
||||
/* jng rel32 */
|
||||
emitterT u32 *JNG32(u32 to)
|
||||
emitterT u32* JNG32(u32 to)
|
||||
{
|
||||
return J32Rel(0x8E, to);
|
||||
return J32Rel(0x8E, to);
|
||||
}
|
||||
|
||||
/* jnge rel32 */
|
||||
emitterT u32 *JNGE32(u32 to)
|
||||
emitterT u32* JNGE32(u32 to)
|
||||
{
|
||||
return J32Rel(0x8C, to);
|
||||
return J32Rel(0x8C, to);
|
||||
}
|
||||
|
||||
/* jnl rel32 */
|
||||
emitterT u32 *JNL32(u32 to)
|
||||
emitterT u32* JNL32(u32 to)
|
||||
{
|
||||
return J32Rel(0x8D, to);
|
||||
return J32Rel(0x8D, to);
|
||||
}
|
||||
|
||||
/* jnle rel32 */
|
||||
emitterT u32 *JNLE32(u32 to)
|
||||
emitterT u32* JNLE32(u32 to)
|
||||
{
|
||||
return J32Rel(0x8F, to);
|
||||
return J32Rel(0x8F, to);
|
||||
}
|
||||
|
||||
/* jo rel32 */
|
||||
emitterT u32 *JO32(u32 to)
|
||||
emitterT u32* JO32(u32 to)
|
||||
{
|
||||
return J32Rel(0x80, to);
|
||||
return J32Rel(0x80, to);
|
||||
}
|
||||
|
||||
/* jno rel32 */
|
||||
emitterT u32 *JNO32(u32 to)
|
||||
emitterT u32* JNO32(u32 to)
|
||||
{
|
||||
return J32Rel(0x81, to);
|
||||
return J32Rel(0x81, to);
|
||||
}
|
||||
|
|
|
@ -25,13 +25,13 @@
|
|||
//------------------------------------------------------------------
|
||||
// legacy jump/align functions
|
||||
//------------------------------------------------------------------
|
||||
ATTR_DEP extern void x86SetPtr(u8 *ptr);
|
||||
ATTR_DEP extern void x86SetJ8(u8 *j8);
|
||||
ATTR_DEP extern void x86SetJ8A(u8 *j8);
|
||||
ATTR_DEP extern void x86SetJ16(u16 *j16);
|
||||
ATTR_DEP extern void x86SetJ16A(u16 *j16);
|
||||
ATTR_DEP extern void x86SetJ32(u32 *j32);
|
||||
ATTR_DEP extern void x86SetJ32A(u32 *j32);
|
||||
ATTR_DEP extern void x86SetPtr(u8* ptr);
|
||||
ATTR_DEP extern void x86SetJ8(u8* j8);
|
||||
ATTR_DEP extern void x86SetJ8A(u8* j8);
|
||||
ATTR_DEP extern void x86SetJ16(u16* j16);
|
||||
ATTR_DEP extern void x86SetJ16A(u16* j16);
|
||||
ATTR_DEP extern void x86SetJ32(u32* j32);
|
||||
ATTR_DEP extern void x86SetJ32A(u32* j32);
|
||||
ATTR_DEP extern void x86Align(int bytes);
|
||||
ATTR_DEP extern void x86AlignExecutable(int align);
|
||||
//------------------------------------------------------------------
|
||||
|
@ -41,55 +41,55 @@ ATTR_DEP extern void x86AlignExecutable(int align);
|
|||
////////////////////////////////////
|
||||
|
||||
// jmp rel8
|
||||
ATTR_DEP extern u8 *JMP8(u8 to);
|
||||
ATTR_DEP extern u8* JMP8(u8 to);
|
||||
|
||||
// jmp rel32
|
||||
ATTR_DEP extern u32 *JMP32(uptr to);
|
||||
ATTR_DEP extern u32* JMP32(uptr to);
|
||||
|
||||
// jp rel8
|
||||
ATTR_DEP extern u8 *JP8(u8 to);
|
||||
ATTR_DEP extern u8* JP8(u8 to);
|
||||
// jnp rel8
|
||||
ATTR_DEP extern u8 *JNP8(u8 to);
|
||||
ATTR_DEP extern u8* JNP8(u8 to);
|
||||
// je rel8
|
||||
ATTR_DEP extern u8 *JE8(u8 to);
|
||||
ATTR_DEP extern u8* JE8(u8 to);
|
||||
// jz rel8
|
||||
ATTR_DEP extern u8 *JZ8(u8 to);
|
||||
ATTR_DEP extern u8* JZ8(u8 to);
|
||||
// jg rel8
|
||||
ATTR_DEP extern u8 *JG8(u8 to);
|
||||
ATTR_DEP extern u8* JG8(u8 to);
|
||||
// jge rel8
|
||||
ATTR_DEP extern u8 *JGE8(u8 to);
|
||||
ATTR_DEP extern u8* JGE8(u8 to);
|
||||
// js rel8
|
||||
ATTR_DEP extern u8 *JS8(u8 to);
|
||||
ATTR_DEP extern u8* JS8(u8 to);
|
||||
// jns rel8
|
||||
ATTR_DEP extern u8 *JNS8(u8 to);
|
||||
ATTR_DEP extern u8* JNS8(u8 to);
|
||||
// jl rel8
|
||||
ATTR_DEP extern u8 *JL8(u8 to);
|
||||
ATTR_DEP extern u8* JL8(u8 to);
|
||||
// ja rel8
|
||||
ATTR_DEP extern u8 *JA8(u8 to);
|
||||
ATTR_DEP extern u8* JA8(u8 to);
|
||||
// jae rel8
|
||||
ATTR_DEP extern u8 *JAE8(u8 to);
|
||||
ATTR_DEP extern u8* JAE8(u8 to);
|
||||
// jb rel8
|
||||
ATTR_DEP extern u8 *JB8(u8 to);
|
||||
ATTR_DEP extern u8* JB8(u8 to);
|
||||
// jbe rel8
|
||||
ATTR_DEP extern u8 *JBE8(u8 to);
|
||||
ATTR_DEP extern u8* JBE8(u8 to);
|
||||
// jle rel8
|
||||
ATTR_DEP extern u8 *JLE8(u8 to);
|
||||
ATTR_DEP extern u8* JLE8(u8 to);
|
||||
// jne rel8
|
||||
ATTR_DEP extern u8 *JNE8(u8 to);
|
||||
ATTR_DEP extern u8* JNE8(u8 to);
|
||||
// jnz rel8
|
||||
ATTR_DEP extern u8 *JNZ8(u8 to);
|
||||
ATTR_DEP extern u8* JNZ8(u8 to);
|
||||
// jng rel8
|
||||
ATTR_DEP extern u8 *JNG8(u8 to);
|
||||
ATTR_DEP extern u8* JNG8(u8 to);
|
||||
// jnge rel8
|
||||
ATTR_DEP extern u8 *JNGE8(u8 to);
|
||||
ATTR_DEP extern u8* JNGE8(u8 to);
|
||||
// jnl rel8
|
||||
ATTR_DEP extern u8 *JNL8(u8 to);
|
||||
ATTR_DEP extern u8* JNL8(u8 to);
|
||||
// jnle rel8
|
||||
ATTR_DEP extern u8 *JNLE8(u8 to);
|
||||
ATTR_DEP extern u8* JNLE8(u8 to);
|
||||
// jo rel8
|
||||
ATTR_DEP extern u8 *JO8(u8 to);
|
||||
ATTR_DEP extern u8* JO8(u8 to);
|
||||
// jno rel8
|
||||
ATTR_DEP extern u8 *JNO8(u8 to);
|
||||
ATTR_DEP extern u8* JNO8(u8 to);
|
||||
|
||||
/*
|
||||
// jb rel16
|
||||
|
@ -103,44 +103,44 @@ ATTR_DEP extern u16* JZ16( u16 to );
|
|||
*/
|
||||
|
||||
// jns rel32
|
||||
ATTR_DEP extern u32 *JNS32(u32 to);
|
||||
ATTR_DEP extern u32* JNS32(u32 to);
|
||||
// js rel32
|
||||
ATTR_DEP extern u32 *JS32(u32 to);
|
||||
ATTR_DEP extern u32* JS32(u32 to);
|
||||
|
||||
// jb rel32
|
||||
ATTR_DEP extern u32 *JB32(u32 to);
|
||||
ATTR_DEP extern u32* JB32(u32 to);
|
||||
// je rel32
|
||||
ATTR_DEP extern u32 *JE32(u32 to);
|
||||
ATTR_DEP extern u32* JE32(u32 to);
|
||||
// jz rel32
|
||||
ATTR_DEP extern u32 *JZ32(u32 to);
|
||||
ATTR_DEP extern u32* JZ32(u32 to);
|
||||
// jg rel32
|
||||
ATTR_DEP extern u32 *JG32(u32 to);
|
||||
ATTR_DEP extern u32* JG32(u32 to);
|
||||
// jge rel32
|
||||
ATTR_DEP extern u32 *JGE32(u32 to);
|
||||
ATTR_DEP extern u32* JGE32(u32 to);
|
||||
// jl rel32
|
||||
ATTR_DEP extern u32 *JL32(u32 to);
|
||||
ATTR_DEP extern u32* JL32(u32 to);
|
||||
// jle rel32
|
||||
ATTR_DEP extern u32 *JLE32(u32 to);
|
||||
ATTR_DEP extern u32* JLE32(u32 to);
|
||||
// jae rel32
|
||||
ATTR_DEP extern u32 *JAE32(u32 to);
|
||||
ATTR_DEP extern u32* JAE32(u32 to);
|
||||
// jne rel32
|
||||
ATTR_DEP extern u32 *JNE32(u32 to);
|
||||
ATTR_DEP extern u32* JNE32(u32 to);
|
||||
// jnz rel32
|
||||
ATTR_DEP extern u32 *JNZ32(u32 to);
|
||||
ATTR_DEP extern u32* JNZ32(u32 to);
|
||||
// jng rel32
|
||||
ATTR_DEP extern u32 *JNG32(u32 to);
|
||||
ATTR_DEP extern u32* JNG32(u32 to);
|
||||
// jnge rel32
|
||||
ATTR_DEP extern u32 *JNGE32(u32 to);
|
||||
ATTR_DEP extern u32* JNGE32(u32 to);
|
||||
// jnl rel32
|
||||
ATTR_DEP extern u32 *JNL32(u32 to);
|
||||
ATTR_DEP extern u32* JNL32(u32 to);
|
||||
// jnle rel32
|
||||
ATTR_DEP extern u32 *JNLE32(u32 to);
|
||||
ATTR_DEP extern u32* JNLE32(u32 to);
|
||||
// jo rel32
|
||||
ATTR_DEP extern u32 *JO32(u32 to);
|
||||
ATTR_DEP extern u32* JO32(u32 to);
|
||||
// jno rel32
|
||||
ATTR_DEP extern u32 *JNO32(u32 to);
|
||||
ATTR_DEP extern u32* JNO32(u32 to);
|
||||
// js rel32
|
||||
ATTR_DEP extern u32 *JS32(u32 to);
|
||||
ATTR_DEP extern u32* JS32(u32 to);
|
||||
|
||||
//******************
|
||||
// FPU instructions
|
||||
|
|
|
@ -36,5 +36,5 @@ using x86Emitter::xWrite64;
|
|||
extern void ModRM(uint mod, uint reg, uint rm);
|
||||
extern void SibSB(uint ss, uint index, uint base);
|
||||
extern void SET8R(int cc, int to);
|
||||
extern u8 *J8Rel(int cc, int to);
|
||||
extern u32 *J32Rel(int cc, u32 to);
|
||||
extern u8* J8Rel(int cc, int to);
|
||||
extern u32* J32Rel(int cc, u32 to);
|
||||
|
|
|
@ -34,132 +34,146 @@
|
|||
namespace x86Emitter
|
||||
{
|
||||
|
||||
void _xMovRtoR(const xRegisterInt &to, const xRegisterInt &from)
|
||||
{
|
||||
pxAssert(to.GetOperandSize() == from.GetOperandSize());
|
||||
void _xMovRtoR(const xRegisterInt& to, const xRegisterInt& from)
|
||||
{
|
||||
pxAssert(to.GetOperandSize() == from.GetOperandSize());
|
||||
|
||||
if (to == from)
|
||||
return; // ignore redundant MOVs.
|
||||
if (to == from)
|
||||
return; // ignore redundant MOVs.
|
||||
|
||||
xOpWrite(from.GetPrefix16(), from.Is8BitOp() ? 0x88 : 0x89, from, to);
|
||||
}
|
||||
xOpWrite(from.GetPrefix16(), from.Is8BitOp() ? 0x88 : 0x89, from, to);
|
||||
}
|
||||
|
||||
void xImpl_Mov::operator()(const xRegisterInt &to, const xRegisterInt &from) const
|
||||
{
|
||||
// FIXME WTF?
|
||||
_xMovRtoR(to, from);
|
||||
}
|
||||
void xImpl_Mov::operator()(const xRegisterInt& to, const xRegisterInt& from) const
|
||||
{
|
||||
// FIXME WTF?
|
||||
_xMovRtoR(to, from);
|
||||
}
|
||||
|
||||
void xImpl_Mov::operator()(const xIndirectVoid &dest, const xRegisterInt &from) const
|
||||
{
|
||||
// mov eax has a special from when writing directly to a DISP32 address
|
||||
// (sans any register index/base registers).
|
||||
void xImpl_Mov::operator()(const xIndirectVoid& dest, const xRegisterInt& from) const
|
||||
{
|
||||
// mov eax has a special from when writing directly to a DISP32 address
|
||||
// (sans any register index/base registers).
|
||||
|
||||
#ifndef __M_X86_64
|
||||
// Note: On x86-64 this is an immediate 64-bit address, which is larger than the equivalent rip offset instr
|
||||
if (from.IsAccumulator() && dest.Index.IsEmpty() && dest.Base.IsEmpty()) {
|
||||
xOpAccWrite(from.GetPrefix16(), from.Is8BitOp() ? 0xa2 : 0xa3, from, dest);
|
||||
xWrite32(dest.Displacement);
|
||||
} else
|
||||
// Note: On x86-64 this is an immediate 64-bit address, which is larger than the equivalent rip offset instr
|
||||
if (from.IsAccumulator() && dest.Index.IsEmpty() && dest.Base.IsEmpty())
|
||||
{
|
||||
xOpAccWrite(from.GetPrefix16(), from.Is8BitOp() ? 0xa2 : 0xa3, from, dest);
|
||||
xWrite32(dest.Displacement);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
xOpWrite(from.GetPrefix16(), from.Is8BitOp() ? 0x88 : 0x89, from, dest);
|
||||
}
|
||||
}
|
||||
{
|
||||
xOpWrite(from.GetPrefix16(), from.Is8BitOp() ? 0x88 : 0x89, from, dest);
|
||||
}
|
||||
}
|
||||
|
||||
void xImpl_Mov::operator()(const xRegisterInt &to, const xIndirectVoid &src) const
|
||||
{
|
||||
// mov eax has a special from when reading directly from a DISP32 address
|
||||
// (sans any register index/base registers).
|
||||
void xImpl_Mov::operator()(const xRegisterInt& to, const xIndirectVoid& src) const
|
||||
{
|
||||
// mov eax has a special from when reading directly from a DISP32 address
|
||||
// (sans any register index/base registers).
|
||||
|
||||
#ifndef __M_X86_64
|
||||
// Note: On x86-64 this is an immediate 64-bit address, which is larger than the equivalent rip offset instr
|
||||
if (to.IsAccumulator() && src.Index.IsEmpty() && src.Base.IsEmpty()) {
|
||||
xOpAccWrite(to.GetPrefix16(), to.Is8BitOp() ? 0xa0 : 0xa1, to, src);
|
||||
xWrite32(src.Displacement);
|
||||
} else
|
||||
// Note: On x86-64 this is an immediate 64-bit address, which is larger than the equivalent rip offset instr
|
||||
if (to.IsAccumulator() && src.Index.IsEmpty() && src.Base.IsEmpty())
|
||||
{
|
||||
xOpAccWrite(to.GetPrefix16(), to.Is8BitOp() ? 0xa0 : 0xa1, to, src);
|
||||
xWrite32(src.Displacement);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
xOpWrite(to.GetPrefix16(), to.Is8BitOp() ? 0x8a : 0x8b, to, src);
|
||||
}
|
||||
}
|
||||
{
|
||||
xOpWrite(to.GetPrefix16(), to.Is8BitOp() ? 0x8a : 0x8b, to, src);
|
||||
}
|
||||
}
|
||||
|
||||
void xImpl_Mov::operator()(const xIndirect64orLess &dest, sptr imm) const
|
||||
{
|
||||
switch (dest.GetOperandSize()) {
|
||||
case 1:
|
||||
pxAssertMsg(imm == (s8)imm || imm == (u8)imm, "Immediate won't fit!");
|
||||
break;
|
||||
case 2:
|
||||
pxAssertMsg(imm == (s16)imm || imm == (u16)imm, "Immediate won't fit!");
|
||||
break;
|
||||
case 4:
|
||||
pxAssertMsg(imm == (s32)imm || imm == (u32)imm, "Immediate won't fit!");
|
||||
break;
|
||||
case 8:
|
||||
pxAssertMsg(imm == (s32)imm, "Immediate won't fit in immediate slot, go through a register!");
|
||||
break;
|
||||
default:
|
||||
pxAssertMsg(0, "Bad indirect size!");
|
||||
}
|
||||
xOpWrite(dest.GetPrefix16(), dest.Is8BitOp() ? 0xc6 : 0xc7, 0, dest, dest.GetImmSize());
|
||||
dest.xWriteImm(imm);
|
||||
}
|
||||
void xImpl_Mov::operator()(const xIndirect64orLess& dest, sptr imm) const
|
||||
{
|
||||
switch (dest.GetOperandSize())
|
||||
{
|
||||
case 1:
|
||||
pxAssertMsg(imm == (s8)imm || imm == (u8)imm, "Immediate won't fit!");
|
||||
break;
|
||||
case 2:
|
||||
pxAssertMsg(imm == (s16)imm || imm == (u16)imm, "Immediate won't fit!");
|
||||
break;
|
||||
case 4:
|
||||
pxAssertMsg(imm == (s32)imm || imm == (u32)imm, "Immediate won't fit!");
|
||||
break;
|
||||
case 8:
|
||||
pxAssertMsg(imm == (s32)imm, "Immediate won't fit in immediate slot, go through a register!");
|
||||
break;
|
||||
default:
|
||||
pxAssertMsg(0, "Bad indirect size!");
|
||||
}
|
||||
xOpWrite(dest.GetPrefix16(), dest.Is8BitOp() ? 0xc6 : 0xc7, 0, dest, dest.GetImmSize());
|
||||
dest.xWriteImm(imm);
|
||||
}
|
||||
|
||||
// preserve_flags - set to true to disable optimizations which could alter the state of
|
||||
// the flags (namely replacing mov reg,0 with xor).
|
||||
void xImpl_Mov::operator()(const xRegisterInt &to, sptr imm, bool preserve_flags) const
|
||||
{
|
||||
switch (to.GetOperandSize()) {
|
||||
case 1:
|
||||
pxAssertMsg(imm == (s8)imm || imm == (u8)imm, "Immediate won't fit!");
|
||||
break;
|
||||
case 2:
|
||||
pxAssertMsg(imm == (s16)imm || imm == (u16)imm, "Immediate won't fit!");
|
||||
break;
|
||||
case 4:
|
||||
pxAssertMsg(imm == (s32)imm || imm == (u32)imm, "Immediate won't fit!");
|
||||
break;
|
||||
case 8:
|
||||
pxAssertMsg(imm == (s32)imm || imm == (u32)imm, "Immediate won't fit in immediate slot, use mov64 or lea!");
|
||||
break;
|
||||
default:
|
||||
pxAssertMsg(0, "Bad indirect size!");
|
||||
}
|
||||
const xRegisterInt& to_ = to.GetNonWide();
|
||||
if (!preserve_flags && (imm == 0)) {
|
||||
_g1_EmitOp(G1Type_XOR, to_, to_);
|
||||
} else if (imm == (u32)imm || !to.IsWide()) {
|
||||
// Note: MOV does not have (reg16/32,imm8) forms.
|
||||
u8 opcode = (to_.Is8BitOp() ? 0xb0 : 0xb8) | to_.Id;
|
||||
xOpAccWrite(to_.GetPrefix16(), opcode, 0, to_);
|
||||
to_.xWriteImm(imm);
|
||||
} else {
|
||||
xOpWrite(to.GetPrefix16(), 0xc7, 0, to);
|
||||
to.xWriteImm(imm);
|
||||
}
|
||||
}
|
||||
// preserve_flags - set to true to disable optimizations which could alter the state of
|
||||
// the flags (namely replacing mov reg,0 with xor).
|
||||
void xImpl_Mov::operator()(const xRegisterInt& to, sptr imm, bool preserve_flags) const
|
||||
{
|
||||
switch (to.GetOperandSize())
|
||||
{
|
||||
case 1:
|
||||
pxAssertMsg(imm == (s8)imm || imm == (u8)imm, "Immediate won't fit!");
|
||||
break;
|
||||
case 2:
|
||||
pxAssertMsg(imm == (s16)imm || imm == (u16)imm, "Immediate won't fit!");
|
||||
break;
|
||||
case 4:
|
||||
pxAssertMsg(imm == (s32)imm || imm == (u32)imm, "Immediate won't fit!");
|
||||
break;
|
||||
case 8:
|
||||
pxAssertMsg(imm == (s32)imm || imm == (u32)imm, "Immediate won't fit in immediate slot, use mov64 or lea!");
|
||||
break;
|
||||
default:
|
||||
pxAssertMsg(0, "Bad indirect size!");
|
||||
}
|
||||
const xRegisterInt& to_ = to.GetNonWide();
|
||||
if (!preserve_flags && (imm == 0))
|
||||
{
|
||||
_g1_EmitOp(G1Type_XOR, to_, to_);
|
||||
}
|
||||
else if (imm == (u32)imm || !to.IsWide())
|
||||
{
|
||||
// Note: MOV does not have (reg16/32,imm8) forms.
|
||||
u8 opcode = (to_.Is8BitOp() ? 0xb0 : 0xb8) | to_.Id;
|
||||
xOpAccWrite(to_.GetPrefix16(), opcode, 0, to_);
|
||||
to_.xWriteImm(imm);
|
||||
}
|
||||
else
|
||||
{
|
||||
xOpWrite(to.GetPrefix16(), 0xc7, 0, to);
|
||||
to.xWriteImm(imm);
|
||||
}
|
||||
}
|
||||
|
||||
const xImpl_Mov xMOV;
|
||||
const xImpl_Mov xMOV;
|
||||
|
||||
#ifdef __M_X86_64
|
||||
void xImpl_MovImm64::operator()(const xRegister64& to, s64 imm, bool preserve_flags) const
|
||||
{
|
||||
if (imm == (u32)imm || imm == (s32)imm) {
|
||||
xMOV(to, imm, preserve_flags);
|
||||
} else {
|
||||
u8 opcode = 0xb8 | to.Id;
|
||||
xOpAccWrite(to.GetPrefix16(), opcode, 0, to);
|
||||
xWrite64(imm);
|
||||
}
|
||||
}
|
||||
void xImpl_MovImm64::operator()(const xRegister64& to, s64 imm, bool preserve_flags) const
|
||||
{
|
||||
if (imm == (u32)imm || imm == (s32)imm)
|
||||
{
|
||||
xMOV(to, imm, preserve_flags);
|
||||
}
|
||||
else
|
||||
{
|
||||
u8 opcode = 0xb8 | to.Id;
|
||||
xOpAccWrite(to.GetPrefix16(), opcode, 0, to);
|
||||
xWrite64(imm);
|
||||
}
|
||||
}
|
||||
|
||||
const xImpl_MovImm64 xMOV64;
|
||||
const xImpl_MovImm64 xMOV64;
|
||||
#endif
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// CMOVcc
|
||||
// --------------------------------------------------------------------------------------
|
||||
// --------------------------------------------------------------------------------------
|
||||
// CMOVcc
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
#define ccSane() pxAssertDev(ccType >= 0 && ccType <= 0x0f, "Invalid comparison type specifier.")
|
||||
|
||||
|
@ -169,63 +183,63 @@ const xImpl_MovImm64 xMOV64;
|
|||
|
||||
|
||||
|
||||
void xImpl_CMov::operator()(const xRegister16or32or64 &to, const xRegister16or32or64 &from) const
|
||||
{
|
||||
pxAssert(to->GetOperandSize() == from->GetOperandSize());
|
||||
ccSane();
|
||||
xOpWrite0F(to->GetPrefix16(), 0x40 | ccType, to, from);
|
||||
}
|
||||
void xImpl_CMov::operator()(const xRegister16or32or64& to, const xRegister16or32or64& from) const
|
||||
{
|
||||
pxAssert(to->GetOperandSize() == from->GetOperandSize());
|
||||
ccSane();
|
||||
xOpWrite0F(to->GetPrefix16(), 0x40 | ccType, to, from);
|
||||
}
|
||||
|
||||
void xImpl_CMov::operator()(const xRegister16or32or64 &to, const xIndirectVoid &sibsrc) const
|
||||
{
|
||||
ccSane();
|
||||
xOpWrite0F(to->GetPrefix16(), 0x40 | ccType, to, sibsrc);
|
||||
}
|
||||
void xImpl_CMov::operator()(const xRegister16or32or64& to, const xIndirectVoid& sibsrc) const
|
||||
{
|
||||
ccSane();
|
||||
xOpWrite0F(to->GetPrefix16(), 0x40 | ccType, to, sibsrc);
|
||||
}
|
||||
|
||||
//void xImpl_CMov::operator()( const xDirectOrIndirect32& to, const xDirectOrIndirect32& from ) const { ccSane(); _DoI_helpermess( *this, to, from ); }
|
||||
//void xImpl_CMov::operator()( const xDirectOrIndirect16& to, const xDirectOrIndirect16& from ) const { ccSane(); _DoI_helpermess( *this, to, from ); }
|
||||
//void xImpl_CMov::operator()( const xDirectOrIndirect32& to, const xDirectOrIndirect32& from ) const { ccSane(); _DoI_helpermess( *this, to, from ); }
|
||||
//void xImpl_CMov::operator()( const xDirectOrIndirect16& to, const xDirectOrIndirect16& from ) const { ccSane(); _DoI_helpermess( *this, to, from ); }
|
||||
|
||||
void xImpl_Set::operator()(const xRegister8 &to) const
|
||||
{
|
||||
ccSane();
|
||||
xOpWrite0F(0x90 | ccType, 0, to);
|
||||
}
|
||||
void xImpl_Set::operator()(const xIndirect8 &dest) const
|
||||
{
|
||||
ccSane();
|
||||
xOpWrite0F(0x90 | ccType, 0, dest);
|
||||
}
|
||||
//void xImpl_Set::operator()( const xDirectOrIndirect8& dest ) const { ccSane(); _DoI_helpermess( *this, dest ); }
|
||||
void xImpl_Set::operator()(const xRegister8& to) const
|
||||
{
|
||||
ccSane();
|
||||
xOpWrite0F(0x90 | ccType, 0, to);
|
||||
}
|
||||
void xImpl_Set::operator()(const xIndirect8& dest) const
|
||||
{
|
||||
ccSane();
|
||||
xOpWrite0F(0x90 | ccType, 0, dest);
|
||||
}
|
||||
//void xImpl_Set::operator()( const xDirectOrIndirect8& dest ) const { ccSane(); _DoI_helpermess( *this, dest ); }
|
||||
|
||||
void xImpl_MovExtend::operator()(const xRegister16or32or64 &to, const xRegister8 &from) const
|
||||
{
|
||||
EbpAssert();
|
||||
xOpWrite0F(
|
||||
(to->GetOperandSize() == 2) ? 0x66 : 0,
|
||||
SignExtend ? 0xbe : 0xb6,
|
||||
to, from);
|
||||
}
|
||||
void xImpl_MovExtend::operator()(const xRegister16or32or64& to, const xRegister8& from) const
|
||||
{
|
||||
EbpAssert();
|
||||
xOpWrite0F(
|
||||
(to->GetOperandSize() == 2) ? 0x66 : 0,
|
||||
SignExtend ? 0xbe : 0xb6,
|
||||
to, from);
|
||||
}
|
||||
|
||||
void xImpl_MovExtend::operator()(const xRegister16or32or64 &to, const xIndirect8 &sibsrc) const
|
||||
{
|
||||
EbpAssert();
|
||||
xOpWrite0F(
|
||||
(to->GetOperandSize() == 2) ? 0x66 : 0,
|
||||
SignExtend ? 0xbe : 0xb6,
|
||||
to, sibsrc);
|
||||
}
|
||||
void xImpl_MovExtend::operator()(const xRegister16or32or64& to, const xIndirect8& sibsrc) const
|
||||
{
|
||||
EbpAssert();
|
||||
xOpWrite0F(
|
||||
(to->GetOperandSize() == 2) ? 0x66 : 0,
|
||||
SignExtend ? 0xbe : 0xb6,
|
||||
to, sibsrc);
|
||||
}
|
||||
|
||||
void xImpl_MovExtend::operator()(const xRegister32or64 &to, const xRegister16 &from) const
|
||||
{
|
||||
EbpAssert();
|
||||
xOpWrite0F(SignExtend ? 0xbf : 0xb7, to, from);
|
||||
}
|
||||
void xImpl_MovExtend::operator()(const xRegister32or64& to, const xRegister16& from) const
|
||||
{
|
||||
EbpAssert();
|
||||
xOpWrite0F(SignExtend ? 0xbf : 0xb7, to, from);
|
||||
}
|
||||
|
||||
void xImpl_MovExtend::operator()(const xRegister32or64 &to, const xIndirect16 &sibsrc) const
|
||||
{
|
||||
EbpAssert();
|
||||
xOpWrite0F(SignExtend ? 0xbf : 0xb7, to, sibsrc);
|
||||
}
|
||||
void xImpl_MovExtend::operator()(const xRegister32or64& to, const xIndirect16& sibsrc) const
|
||||
{
|
||||
EbpAssert();
|
||||
xOpWrite0F(SignExtend ? 0xbf : 0xb7, to, sibsrc);
|
||||
}
|
||||
|
||||
#if 0
|
||||
void xImpl_MovExtend::operator()( const xRegister32& to, const xDirectOrIndirect16& src ) const
|
||||
|
@ -241,58 +255,58 @@ void xImpl_MovExtend::operator()( const xRegister16or32& to, const xDirectOrIndi
|
|||
}
|
||||
#endif
|
||||
|
||||
const xImpl_MovExtend xMOVSX = {true};
|
||||
const xImpl_MovExtend xMOVZX = {false};
|
||||
const xImpl_MovExtend xMOVSX = {true};
|
||||
const xImpl_MovExtend xMOVZX = {false};
|
||||
|
||||
const xImpl_CMov xCMOVA = {Jcc_Above};
|
||||
const xImpl_CMov xCMOVAE = {Jcc_AboveOrEqual};
|
||||
const xImpl_CMov xCMOVB = {Jcc_Below};
|
||||
const xImpl_CMov xCMOVBE = {Jcc_BelowOrEqual};
|
||||
const xImpl_CMov xCMOVA = {Jcc_Above};
|
||||
const xImpl_CMov xCMOVAE = {Jcc_AboveOrEqual};
|
||||
const xImpl_CMov xCMOVB = {Jcc_Below};
|
||||
const xImpl_CMov xCMOVBE = {Jcc_BelowOrEqual};
|
||||
|
||||
const xImpl_CMov xCMOVG = {Jcc_Greater};
|
||||
const xImpl_CMov xCMOVGE = {Jcc_GreaterOrEqual};
|
||||
const xImpl_CMov xCMOVL = {Jcc_Less};
|
||||
const xImpl_CMov xCMOVLE = {Jcc_LessOrEqual};
|
||||
const xImpl_CMov xCMOVG = {Jcc_Greater};
|
||||
const xImpl_CMov xCMOVGE = {Jcc_GreaterOrEqual};
|
||||
const xImpl_CMov xCMOVL = {Jcc_Less};
|
||||
const xImpl_CMov xCMOVLE = {Jcc_LessOrEqual};
|
||||
|
||||
const xImpl_CMov xCMOVZ = {Jcc_Zero};
|
||||
const xImpl_CMov xCMOVE = {Jcc_Equal};
|
||||
const xImpl_CMov xCMOVNZ = {Jcc_NotZero};
|
||||
const xImpl_CMov xCMOVNE = {Jcc_NotEqual};
|
||||
const xImpl_CMov xCMOVZ = {Jcc_Zero};
|
||||
const xImpl_CMov xCMOVE = {Jcc_Equal};
|
||||
const xImpl_CMov xCMOVNZ = {Jcc_NotZero};
|
||||
const xImpl_CMov xCMOVNE = {Jcc_NotEqual};
|
||||
|
||||
const xImpl_CMov xCMOVO = {Jcc_Overflow};
|
||||
const xImpl_CMov xCMOVNO = {Jcc_NotOverflow};
|
||||
const xImpl_CMov xCMOVC = {Jcc_Carry};
|
||||
const xImpl_CMov xCMOVNC = {Jcc_NotCarry};
|
||||
const xImpl_CMov xCMOVO = {Jcc_Overflow};
|
||||
const xImpl_CMov xCMOVNO = {Jcc_NotOverflow};
|
||||
const xImpl_CMov xCMOVC = {Jcc_Carry};
|
||||
const xImpl_CMov xCMOVNC = {Jcc_NotCarry};
|
||||
|
||||
const xImpl_CMov xCMOVS = {Jcc_Signed};
|
||||
const xImpl_CMov xCMOVNS = {Jcc_Unsigned};
|
||||
const xImpl_CMov xCMOVPE = {Jcc_ParityEven};
|
||||
const xImpl_CMov xCMOVPO = {Jcc_ParityOdd};
|
||||
const xImpl_CMov xCMOVS = {Jcc_Signed};
|
||||
const xImpl_CMov xCMOVNS = {Jcc_Unsigned};
|
||||
const xImpl_CMov xCMOVPE = {Jcc_ParityEven};
|
||||
const xImpl_CMov xCMOVPO = {Jcc_ParityOdd};
|
||||
|
||||
|
||||
const xImpl_Set xSETA = {Jcc_Above};
|
||||
const xImpl_Set xSETAE = {Jcc_AboveOrEqual};
|
||||
const xImpl_Set xSETB = {Jcc_Below};
|
||||
const xImpl_Set xSETBE = {Jcc_BelowOrEqual};
|
||||
const xImpl_Set xSETA = {Jcc_Above};
|
||||
const xImpl_Set xSETAE = {Jcc_AboveOrEqual};
|
||||
const xImpl_Set xSETB = {Jcc_Below};
|
||||
const xImpl_Set xSETBE = {Jcc_BelowOrEqual};
|
||||
|
||||
const xImpl_Set xSETG = {Jcc_Greater};
|
||||
const xImpl_Set xSETGE = {Jcc_GreaterOrEqual};
|
||||
const xImpl_Set xSETL = {Jcc_Less};
|
||||
const xImpl_Set xSETLE = {Jcc_LessOrEqual};
|
||||
const xImpl_Set xSETG = {Jcc_Greater};
|
||||
const xImpl_Set xSETGE = {Jcc_GreaterOrEqual};
|
||||
const xImpl_Set xSETL = {Jcc_Less};
|
||||
const xImpl_Set xSETLE = {Jcc_LessOrEqual};
|
||||
|
||||
const xImpl_Set xSETZ = {Jcc_Zero};
|
||||
const xImpl_Set xSETE = {Jcc_Equal};
|
||||
const xImpl_Set xSETNZ = {Jcc_NotZero};
|
||||
const xImpl_Set xSETNE = {Jcc_NotEqual};
|
||||
const xImpl_Set xSETZ = {Jcc_Zero};
|
||||
const xImpl_Set xSETE = {Jcc_Equal};
|
||||
const xImpl_Set xSETNZ = {Jcc_NotZero};
|
||||
const xImpl_Set xSETNE = {Jcc_NotEqual};
|
||||
|
||||
const xImpl_Set xSETO = {Jcc_Overflow};
|
||||
const xImpl_Set xSETNO = {Jcc_NotOverflow};
|
||||
const xImpl_Set xSETC = {Jcc_Carry};
|
||||
const xImpl_Set xSETNC = {Jcc_NotCarry};
|
||||
const xImpl_Set xSETO = {Jcc_Overflow};
|
||||
const xImpl_Set xSETNO = {Jcc_NotOverflow};
|
||||
const xImpl_Set xSETC = {Jcc_Carry};
|
||||
const xImpl_Set xSETNC = {Jcc_NotCarry};
|
||||
|
||||
const xImpl_Set xSETS = {Jcc_Signed};
|
||||
const xImpl_Set xSETNS = {Jcc_Unsigned};
|
||||
const xImpl_Set xSETPE = {Jcc_ParityEven};
|
||||
const xImpl_Set xSETPO = {Jcc_ParityOdd};
|
||||
const xImpl_Set xSETS = {Jcc_Signed};
|
||||
const xImpl_Set xSETNS = {Jcc_Unsigned};
|
||||
const xImpl_Set xSETPE = {Jcc_ParityEven};
|
||||
const xImpl_Set xSETPO = {Jcc_ParityOdd};
|
||||
|
||||
} // end namespace x86Emitter
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -17,10 +17,11 @@
|
|||
|
||||
#include "common/Dependencies.h"
|
||||
|
||||
enum x86VendorType {
|
||||
x86Vendor_Intel = 0,
|
||||
x86Vendor_AMD = 1,
|
||||
x86Vendor_Unknown = 2
|
||||
enum x86VendorType
|
||||
{
|
||||
x86Vendor_Intel = 0,
|
||||
x86Vendor_AMD = 1,
|
||||
x86Vendor_Unknown = 2
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -29,117 +30,120 @@ enum x86VendorType {
|
|||
class x86capabilities
|
||||
{
|
||||
public:
|
||||
bool isIdentified;
|
||||
bool isIdentified;
|
||||
|
||||
public:
|
||||
x86VendorType VendorID;
|
||||
x86VendorType VendorID;
|
||||
|
||||
uint FamilyID; // Processor Family
|
||||
uint Model; // Processor Model
|
||||
uint TypeID; // Processor Type
|
||||
uint StepID; // Stepping ID
|
||||
uint FamilyID; // Processor Family
|
||||
uint Model; // Processor Model
|
||||
uint TypeID; // Processor Type
|
||||
uint StepID; // Stepping ID
|
||||
|
||||
u32 Flags; // Feature Flags
|
||||
u32 Flags2; // More Feature Flags
|
||||
u32 EFlags; // Extended Feature Flags
|
||||
u32 EFlags2; // Extended Feature Flags pg2
|
||||
u32 SEFlag; // Structured Extended Feature Flags Enumeration
|
||||
u32 Flags; // Feature Flags
|
||||
u32 Flags2; // More Feature Flags
|
||||
u32 EFlags; // Extended Feature Flags
|
||||
u32 EFlags2; // Extended Feature Flags pg2
|
||||
u32 SEFlag; // Structured Extended Feature Flags Enumeration
|
||||
|
||||
char VendorName[16]; // Vendor/Creator ID
|
||||
char FamilyName[50]; // the original cpu name
|
||||
char VendorName[16]; // Vendor/Creator ID
|
||||
char FamilyName[50]; // the original cpu name
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// x86 CPU Capabilities Section (all boolean flags!)
|
||||
// ----------------------------------------------------------------------------
|
||||
// ----------------------------------------------------------------------------
|
||||
// x86 CPU Capabilities Section (all boolean flags!)
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
u32 hasFloatingPointUnit : 1;
|
||||
u32 hasVirtual8086ModeEnhancements : 1;
|
||||
u32 hasDebuggingExtensions : 1;
|
||||
u32 hasPageSizeExtensions : 1;
|
||||
u32 hasTimeStampCounter : 1;
|
||||
u32 hasModelSpecificRegisters : 1;
|
||||
u32 hasPhysicalAddressExtension : 1;
|
||||
u32 hasCOMPXCHG8BInstruction : 1;
|
||||
u32 hasAdvancedProgrammableInterruptController : 1;
|
||||
u32 hasSEPFastSystemCall : 1;
|
||||
u32 hasMemoryTypeRangeRegisters : 1;
|
||||
u32 hasPTEGlobalFlag : 1;
|
||||
u32 hasMachineCheckArchitecture : 1;
|
||||
u32 hasConditionalMoveAndCompareInstructions : 1;
|
||||
u32 hasFGPageAttributeTable : 1;
|
||||
u32 has36bitPageSizeExtension : 1;
|
||||
u32 hasProcessorSerialNumber : 1;
|
||||
u32 hasCFLUSHInstruction : 1;
|
||||
u32 hasDebugStore : 1;
|
||||
u32 hasACPIThermalMonitorAndClockControl : 1;
|
||||
u32 hasFastStreamingSIMDExtensionsSaveRestore : 1;
|
||||
u32 hasStreamingSIMDExtensions : 1;
|
||||
u32 hasStreamingSIMD2Extensions : 1;
|
||||
u32 hasSelfSnoop : 1;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
u32 hasFloatingPointUnit : 1;
|
||||
u32 hasVirtual8086ModeEnhancements : 1;
|
||||
u32 hasDebuggingExtensions : 1;
|
||||
u32 hasPageSizeExtensions : 1;
|
||||
u32 hasTimeStampCounter : 1;
|
||||
u32 hasModelSpecificRegisters : 1;
|
||||
u32 hasPhysicalAddressExtension : 1;
|
||||
u32 hasCOMPXCHG8BInstruction : 1;
|
||||
u32 hasAdvancedProgrammableInterruptController : 1;
|
||||
u32 hasSEPFastSystemCall : 1;
|
||||
u32 hasMemoryTypeRangeRegisters : 1;
|
||||
u32 hasPTEGlobalFlag : 1;
|
||||
u32 hasMachineCheckArchitecture : 1;
|
||||
u32 hasConditionalMoveAndCompareInstructions : 1;
|
||||
u32 hasFGPageAttributeTable : 1;
|
||||
u32 has36bitPageSizeExtension : 1;
|
||||
u32 hasProcessorSerialNumber : 1;
|
||||
u32 hasCFLUSHInstruction : 1;
|
||||
u32 hasDebugStore : 1;
|
||||
u32 hasACPIThermalMonitorAndClockControl : 1;
|
||||
u32 hasFastStreamingSIMDExtensionsSaveRestore : 1;
|
||||
u32 hasStreamingSIMDExtensions : 1;
|
||||
u32 hasStreamingSIMD2Extensions : 1;
|
||||
u32 hasSelfSnoop : 1;
|
||||
|
||||
// is TRUE for both multi-core and Hyperthreaded CPUs.
|
||||
u32 hasMultiThreading : 1;
|
||||
// is TRUE for both multi-core and Hyperthreaded CPUs.
|
||||
u32 hasMultiThreading : 1;
|
||||
|
||||
u32 hasThermalMonitor : 1;
|
||||
u32 hasIntel64BitArchitecture : 1;
|
||||
u32 hasStreamingSIMD3Extensions : 1;
|
||||
u32 hasSupplementalStreamingSIMD3Extensions : 1;
|
||||
u32 hasStreamingSIMD4Extensions : 1;
|
||||
u32 hasStreamingSIMD4Extensions2 : 1;
|
||||
u32 hasAVX : 1;
|
||||
u32 hasAVX2 : 1;
|
||||
u32 hasBMI1 : 1;
|
||||
u32 hasBMI2 : 1;
|
||||
u32 hasFMA : 1;
|
||||
u32 hasThermalMonitor : 1;
|
||||
u32 hasIntel64BitArchitecture : 1;
|
||||
u32 hasStreamingSIMD3Extensions : 1;
|
||||
u32 hasSupplementalStreamingSIMD3Extensions : 1;
|
||||
u32 hasStreamingSIMD4Extensions : 1;
|
||||
u32 hasStreamingSIMD4Extensions2 : 1;
|
||||
u32 hasAVX : 1;
|
||||
u32 hasAVX2 : 1;
|
||||
u32 hasBMI1 : 1;
|
||||
u32 hasBMI2 : 1;
|
||||
u32 hasFMA : 1;
|
||||
|
||||
// AMD-specific CPU Features
|
||||
u32 hasAMD64BitArchitecture : 1;
|
||||
u32 hasStreamingSIMD4ExtensionsA : 1;
|
||||
};
|
||||
// AMD-specific CPU Features
|
||||
u32 hasAMD64BitArchitecture : 1;
|
||||
u32 hasStreamingSIMD4ExtensionsA : 1;
|
||||
};
|
||||
|
||||
u64 AllCapabilities;
|
||||
};
|
||||
u64 AllCapabilities;
|
||||
};
|
||||
|
||||
// Core Counts!
|
||||
u32 PhysicalCores;
|
||||
u32 LogicalCores;
|
||||
// Core Counts!
|
||||
u32 PhysicalCores;
|
||||
u32 LogicalCores;
|
||||
|
||||
public:
|
||||
x86capabilities();
|
||||
x86capabilities();
|
||||
|
||||
void Identify();
|
||||
void CountCores();
|
||||
wxString GetTypeName() const;
|
||||
void Identify();
|
||||
void CountCores();
|
||||
wxString GetTypeName() const;
|
||||
|
||||
u32 CalculateMHz() const;
|
||||
u32 CalculateMHz() const;
|
||||
|
||||
void SIMD_EstablishMXCSRmask();
|
||||
void SIMD_EstablishMXCSRmask();
|
||||
|
||||
protected:
|
||||
s64 _CPUSpeedHz(u64 time) const;
|
||||
void CountLogicalCores();
|
||||
s64 _CPUSpeedHz(u64 time) const;
|
||||
void CountLogicalCores();
|
||||
};
|
||||
|
||||
enum SSE_RoundMode {
|
||||
SSE_RoundMode_FIRST = 0,
|
||||
SSEround_Nearest = 0,
|
||||
SSEround_NegInf,
|
||||
SSEround_PosInf,
|
||||
SSEround_Chop,
|
||||
SSE_RoundMode_COUNT
|
||||
enum SSE_RoundMode
|
||||
{
|
||||
SSE_RoundMode_FIRST = 0,
|
||||
SSEround_Nearest = 0,
|
||||
SSEround_NegInf,
|
||||
SSEround_PosInf,
|
||||
SSEround_Chop,
|
||||
SSE_RoundMode_COUNT
|
||||
};
|
||||
|
||||
ImplementEnumOperators(SSE_RoundMode);
|
||||
|
||||
// Predeclaration for xIndirect32
|
||||
namespace x86Emitter {
|
||||
template <typename T> class xIndirect;
|
||||
namespace x86Emitter
|
||||
{
|
||||
template <typename T>
|
||||
class xIndirect;
|
||||
typedef xIndirect<u32> xIndirect32;
|
||||
}
|
||||
} // namespace x86Emitter
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SSE_MXCSR - Control/Status Register (bitfield)
|
||||
|
@ -153,52 +157,52 @@ namespace x86Emitter {
|
|||
//
|
||||
union SSE_MXCSR
|
||||
{
|
||||
u32 bitmask;
|
||||
struct
|
||||
{
|
||||
u32
|
||||
InvalidOpFlag : 1,
|
||||
DenormalFlag : 1,
|
||||
DivideByZeroFlag : 1,
|
||||
OverflowFlag : 1,
|
||||
UnderflowFlag : 1,
|
||||
PrecisionFlag : 1,
|
||||
u32 bitmask;
|
||||
struct
|
||||
{
|
||||
u32
|
||||
InvalidOpFlag : 1,
|
||||
DenormalFlag : 1,
|
||||
DivideByZeroFlag : 1,
|
||||
OverflowFlag : 1,
|
||||
UnderflowFlag : 1,
|
||||
PrecisionFlag : 1,
|
||||
|
||||
// This bit is supported only on SSE2 or better CPUs. Setting it to 1 on
|
||||
// SSE1 cpus will result in an invalid instruction exception when executing
|
||||
// LDMXSCR.
|
||||
DenormalsAreZero : 1,
|
||||
// This bit is supported only on SSE2 or better CPUs. Setting it to 1 on
|
||||
// SSE1 cpus will result in an invalid instruction exception when executing
|
||||
// LDMXSCR.
|
||||
DenormalsAreZero : 1,
|
||||
|
||||
InvalidOpMask : 1,
|
||||
DenormalMask : 1,
|
||||
DivideByZeroMask : 1,
|
||||
OverflowMask : 1,
|
||||
UnderflowMask : 1,
|
||||
PrecisionMask : 1,
|
||||
InvalidOpMask : 1,
|
||||
DenormalMask : 1,
|
||||
DivideByZeroMask : 1,
|
||||
OverflowMask : 1,
|
||||
UnderflowMask : 1,
|
||||
PrecisionMask : 1,
|
||||
|
||||
RoundingControl : 2,
|
||||
FlushToZero : 1;
|
||||
};
|
||||
RoundingControl : 2,
|
||||
FlushToZero : 1;
|
||||
};
|
||||
|
||||
SSE_RoundMode GetRoundMode() const;
|
||||
SSE_MXCSR &SetRoundMode(SSE_RoundMode mode);
|
||||
SSE_MXCSR &ClearExceptionFlags();
|
||||
SSE_MXCSR &EnableExceptions();
|
||||
SSE_MXCSR &DisableExceptions();
|
||||
SSE_RoundMode GetRoundMode() const;
|
||||
SSE_MXCSR& SetRoundMode(SSE_RoundMode mode);
|
||||
SSE_MXCSR& ClearExceptionFlags();
|
||||
SSE_MXCSR& EnableExceptions();
|
||||
SSE_MXCSR& DisableExceptions();
|
||||
|
||||
SSE_MXCSR &ApplyReserveMask();
|
||||
SSE_MXCSR& ApplyReserveMask();
|
||||
|
||||
bool operator==(const SSE_MXCSR &right) const
|
||||
{
|
||||
return bitmask == right.bitmask;
|
||||
}
|
||||
bool operator==(const SSE_MXCSR& right) const
|
||||
{
|
||||
return bitmask == right.bitmask;
|
||||
}
|
||||
|
||||
bool operator!=(const SSE_MXCSR &right) const
|
||||
{
|
||||
return bitmask != right.bitmask;
|
||||
}
|
||||
bool operator!=(const SSE_MXCSR& right) const
|
||||
{
|
||||
return bitmask != right.bitmask;
|
||||
}
|
||||
|
||||
operator x86Emitter::xIndirect32() const;
|
||||
operator x86Emitter::xIndirect32() const;
|
||||
};
|
||||
|
||||
extern SSE_MXCSR MXCSR_Mask;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -22,115 +22,117 @@ using namespace pxSizerFlags;
|
|||
// pxCheckBox Implementations
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
pxCheckBox::pxCheckBox(wxWindow *parent, const wxString &label, const wxString &subtext, int flags)
|
||||
: wxPanelWithHelpers(parent, wxVERTICAL)
|
||||
pxCheckBox::pxCheckBox(wxWindow* parent, const wxString& label, const wxString& subtext, int flags)
|
||||
: wxPanelWithHelpers(parent, wxVERTICAL)
|
||||
{
|
||||
Init(label, subtext, flags);
|
||||
Init(label, subtext, flags);
|
||||
}
|
||||
|
||||
pxCheckBox::pxCheckBox(wxWindow *parent, const wxString &label, int flags)
|
||||
: wxPanelWithHelpers(parent, wxVERTICAL)
|
||||
pxCheckBox::pxCheckBox(wxWindow* parent, const wxString& label, int flags)
|
||||
: wxPanelWithHelpers(parent, wxVERTICAL)
|
||||
{
|
||||
Init(label, wxEmptyString, flags);
|
||||
Init(label, wxEmptyString, flags);
|
||||
}
|
||||
|
||||
void pxCheckBox::Init(const wxString &label, const wxString &subtext, int flags)
|
||||
void pxCheckBox::Init(const wxString& label, const wxString& subtext, int flags)
|
||||
{
|
||||
m_subtext = NULL;
|
||||
m_subPadding = StdPadding * 2;
|
||||
m_checkbox = new wxCheckBox(this, wxID_ANY, label, wxDefaultPosition, wxDefaultSize, flags);
|
||||
m_subtext = NULL;
|
||||
m_subPadding = StdPadding * 2;
|
||||
m_checkbox = new wxCheckBox(this, wxID_ANY, label, wxDefaultPosition, wxDefaultSize, flags);
|
||||
|
||||
*this += m_checkbox | pxSizerFlags::StdExpand();
|
||||
*this += m_checkbox | pxSizerFlags::StdExpand();
|
||||
|
||||
static const int Indentation = 23;
|
||||
if (!subtext.IsEmpty()) {
|
||||
m_subtext = new pxStaticText(this, subtext, wxALIGN_LEFT);
|
||||
static const int Indentation = 23;
|
||||
if (!subtext.IsEmpty())
|
||||
{
|
||||
m_subtext = new pxStaticText(this, subtext, wxALIGN_LEFT);
|
||||
|
||||
wxFlexGridSizer &spaced(*new wxFlexGridSizer(3));
|
||||
spaced.AddGrowableCol(1);
|
||||
spaced += Indentation;
|
||||
m_sizerItem_subtext = spaced.Add(m_subtext, pxBorder(wxBOTTOM, m_subPadding).Expand());
|
||||
//spaced += pxSizerFlags::StdPadding;
|
||||
wxFlexGridSizer& spaced(*new wxFlexGridSizer(3));
|
||||
spaced.AddGrowableCol(1);
|
||||
spaced += Indentation;
|
||||
m_sizerItem_subtext = spaced.Add(m_subtext, pxBorder(wxBOTTOM, m_subPadding).Expand());
|
||||
//spaced += pxSizerFlags::StdPadding;
|
||||
|
||||
*this += &spaced | pxExpand;
|
||||
}
|
||||
*this += &spaced | pxExpand;
|
||||
}
|
||||
|
||||
Bind(wxEVT_CHECKBOX, &pxCheckBox::OnCheckpartCommand, this, m_checkbox->GetId());
|
||||
Bind(wxEVT_CHECKBOX, &pxCheckBox::OnCheckpartCommand, this, m_checkbox->GetId());
|
||||
}
|
||||
|
||||
pxCheckBox &pxCheckBox::SetSubPadding(int pad)
|
||||
pxCheckBox& pxCheckBox::SetSubPadding(int pad)
|
||||
{
|
||||
m_subPadding = pad;
|
||||
if (m_sizerItem_subtext) {
|
||||
m_sizerItem_subtext->SetBorder(m_subPadding);
|
||||
Fit();
|
||||
}
|
||||
return *this;
|
||||
m_subPadding = pad;
|
||||
if (m_sizerItem_subtext)
|
||||
{
|
||||
m_sizerItem_subtext->SetBorder(m_subPadding);
|
||||
Fit();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// applies the tooltip to both both the checkbox and it's static subtext (if present), and
|
||||
// performs word wrapping on platforms that need it (eg mswindows).
|
||||
pxCheckBox &pxCheckBox::SetToolTip(const wxString &tip)
|
||||
pxCheckBox& pxCheckBox::SetToolTip(const wxString& tip)
|
||||
{
|
||||
pxSetToolTip(m_checkbox, tip);
|
||||
pxSetToolTip(m_subtext, tip);
|
||||
return *this;
|
||||
pxSetToolTip(m_checkbox, tip);
|
||||
pxSetToolTip(m_subtext, tip);
|
||||
return *this;
|
||||
}
|
||||
|
||||
pxCheckBox &pxCheckBox::SetValue(bool val)
|
||||
pxCheckBox& pxCheckBox::SetValue(bool val)
|
||||
{
|
||||
pxAssert(m_checkbox);
|
||||
m_checkbox->SetValue(val);
|
||||
return *this;
|
||||
pxAssert(m_checkbox);
|
||||
m_checkbox->SetValue(val);
|
||||
return *this;
|
||||
}
|
||||
|
||||
pxCheckBox &pxCheckBox::SetIndeterminate()
|
||||
pxCheckBox& pxCheckBox::SetIndeterminate()
|
||||
{
|
||||
pxAssert(m_checkbox);
|
||||
m_checkbox->Set3StateValue(wxCHK_UNDETERMINED);
|
||||
return *this;
|
||||
pxAssert(m_checkbox);
|
||||
m_checkbox->Set3StateValue(wxCHK_UNDETERMINED);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
pxCheckBox &pxCheckBox::SetState(wxCheckBoxState state)
|
||||
pxCheckBox& pxCheckBox::SetState(wxCheckBoxState state)
|
||||
{
|
||||
pxAssert(m_checkbox);
|
||||
m_checkbox->Set3StateValue(state);
|
||||
return *this;
|
||||
pxAssert(m_checkbox);
|
||||
m_checkbox->Set3StateValue(state);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Forwards checkbox actions on the internal checkbox (called 'checkpart') to listeners
|
||||
// bound to the pxCheckBox "parent" panel. This helps the pxCheckBox behave more like a
|
||||
// traditional checkbox.
|
||||
void pxCheckBox::OnCheckpartCommand(wxCommandEvent &evt)
|
||||
void pxCheckBox::OnCheckpartCommand(wxCommandEvent& evt)
|
||||
{
|
||||
evt.Skip();
|
||||
evt.Skip();
|
||||
|
||||
wxCommandEvent newevt(evt);
|
||||
newevt.SetEventObject(this);
|
||||
newevt.SetId(GetId());
|
||||
GetEventHandler()->ProcessEvent(newevt);
|
||||
wxCommandEvent newevt(evt);
|
||||
newevt.SetEventObject(this);
|
||||
newevt.SetId(GetId());
|
||||
GetEventHandler()->ProcessEvent(newevt);
|
||||
}
|
||||
|
||||
void pxCheckBox::OnSubtextClicked(wxCommandEvent &evt)
|
||||
void pxCheckBox::OnSubtextClicked(wxCommandEvent& evt)
|
||||
{
|
||||
// TODO?
|
||||
// We can enable the ability to allow clicks on the subtext desc/label to toggle
|
||||
// the checkmark. Not sure if that's desirable.
|
||||
// TODO?
|
||||
// We can enable the ability to allow clicks on the subtext desc/label to toggle
|
||||
// the checkmark. Not sure if that's desirable.
|
||||
}
|
||||
|
||||
void operator+=(wxSizer &target, pxCheckBox *src)
|
||||
void operator+=(wxSizer& target, pxCheckBox* src)
|
||||
{
|
||||
if (src)
|
||||
target.Add(src, pxExpand);
|
||||
if (src)
|
||||
target.Add(src, pxExpand);
|
||||
}
|
||||
|
||||
void operator+=(wxSizer &target, pxCheckBox &src)
|
||||
void operator+=(wxSizer& target, pxCheckBox& src)
|
||||
{
|
||||
target.Add(&src, pxExpand);
|
||||
target.Add(&src, pxExpand);
|
||||
}
|
||||
|
||||
void operator+=(wxSizer *target, pxCheckBox &src)
|
||||
void operator+=(wxSizer* target, pxCheckBox& src)
|
||||
{
|
||||
target->Add(&src, pxExpand);
|
||||
target->Add(&src, pxExpand);
|
||||
}
|
||||
|
|
|
@ -29,74 +29,74 @@
|
|||
class pxCheckBox : public wxPanelWithHelpers
|
||||
{
|
||||
protected:
|
||||
wxCheckBox *m_checkbox;
|
||||
pxStaticText *m_subtext;
|
||||
wxCheckBox* m_checkbox;
|
||||
pxStaticText* m_subtext;
|
||||
|
||||
// padding below the subtext (if there's subtext). If there's no subtext, this value is unused.
|
||||
int m_subPadding;
|
||||
// padding below the subtext (if there's subtext). If there's no subtext, this value is unused.
|
||||
int m_subPadding;
|
||||
|
||||
wxSizerItem *m_sizerItem_subtext;
|
||||
wxSizerItem* m_sizerItem_subtext;
|
||||
|
||||
public:
|
||||
pxCheckBox(wxWindow *parent, const wxString &label, const wxString &subtext = wxEmptyString, int flags = wxCHK_2STATE);
|
||||
pxCheckBox(wxWindow *parent, const wxString &label, int flags);
|
||||
virtual ~pxCheckBox() = default;
|
||||
pxCheckBox(wxWindow* parent, const wxString& label, const wxString& subtext = wxEmptyString, int flags = wxCHK_2STATE);
|
||||
pxCheckBox(wxWindow* parent, const wxString& label, int flags);
|
||||
virtual ~pxCheckBox() = default;
|
||||
|
||||
bool HasSubText() const { return m_subtext != NULL; }
|
||||
const pxStaticText *GetSubText() const { return m_subtext; }
|
||||
bool HasSubText() const { return m_subtext != NULL; }
|
||||
const pxStaticText* GetSubText() const { return m_subtext; }
|
||||
|
||||
pxCheckBox &SetSubPadding(int pad);
|
||||
pxCheckBox &SetToolTip(const wxString &tip);
|
||||
pxCheckBox &SetValue(bool val);
|
||||
pxCheckBox &SetIndeterminate();
|
||||
pxCheckBox &SetState(wxCheckBoxState state);
|
||||
pxCheckBox& SetSubPadding(int pad);
|
||||
pxCheckBox& SetToolTip(const wxString& tip);
|
||||
pxCheckBox& SetValue(bool val);
|
||||
pxCheckBox& SetIndeterminate();
|
||||
pxCheckBox& SetState(wxCheckBoxState state);
|
||||
|
||||
wxCheckBoxState GetState() const
|
||||
{
|
||||
pxAssert(m_checkbox != NULL);
|
||||
return m_checkbox->Get3StateValue();
|
||||
}
|
||||
bool GetValue() const
|
||||
{
|
||||
pxAssert(m_checkbox != NULL);
|
||||
return m_checkbox->GetValue();
|
||||
}
|
||||
bool IsChecked() const
|
||||
{
|
||||
pxAssert(m_checkbox != NULL);
|
||||
return m_checkbox->IsChecked();
|
||||
}
|
||||
bool IsIndeterminate() const
|
||||
{
|
||||
pxAssert(m_checkbox != NULL);
|
||||
return m_checkbox->Get3StateValue() == wxCHK_UNDETERMINED;
|
||||
}
|
||||
operator wxCheckBox &()
|
||||
{
|
||||
pxAssert(m_checkbox != NULL);
|
||||
return *m_checkbox;
|
||||
}
|
||||
operator const wxCheckBox &() const
|
||||
{
|
||||
pxAssert(m_checkbox != NULL);
|
||||
return *m_checkbox;
|
||||
}
|
||||
wxCheckBoxState GetState() const
|
||||
{
|
||||
pxAssert(m_checkbox != NULL);
|
||||
return m_checkbox->Get3StateValue();
|
||||
}
|
||||
bool GetValue() const
|
||||
{
|
||||
pxAssert(m_checkbox != NULL);
|
||||
return m_checkbox->GetValue();
|
||||
}
|
||||
bool IsChecked() const
|
||||
{
|
||||
pxAssert(m_checkbox != NULL);
|
||||
return m_checkbox->IsChecked();
|
||||
}
|
||||
bool IsIndeterminate() const
|
||||
{
|
||||
pxAssert(m_checkbox != NULL);
|
||||
return m_checkbox->Get3StateValue() == wxCHK_UNDETERMINED;
|
||||
}
|
||||
operator wxCheckBox&()
|
||||
{
|
||||
pxAssert(m_checkbox != NULL);
|
||||
return *m_checkbox;
|
||||
}
|
||||
operator const wxCheckBox&() const
|
||||
{
|
||||
pxAssert(m_checkbox != NULL);
|
||||
return *m_checkbox;
|
||||
}
|
||||
|
||||
wxCheckBox *GetWxPtr() { return m_checkbox; }
|
||||
const wxCheckBox *GetWxPtr() const { return m_checkbox; }
|
||||
wxCheckBox* GetWxPtr() { return m_checkbox; }
|
||||
const wxCheckBox* GetWxPtr() const { return m_checkbox; }
|
||||
|
||||
//wxWindowID GetId() const { pxAssert( m_checkbox != NULL ); return m_checkbox->GetId(); }
|
||||
//wxWindowID GetId() const { pxAssert( m_checkbox != NULL ); return m_checkbox->GetId(); }
|
||||
|
||||
protected:
|
||||
void Init(const wxString &label, const wxString &subtext, int flags);
|
||||
void OnCheckpartCommand(wxCommandEvent &evt);
|
||||
void OnSubtextClicked(wxCommandEvent &evt);
|
||||
void Init(const wxString& label, const wxString& subtext, int flags);
|
||||
void OnCheckpartCommand(wxCommandEvent& evt);
|
||||
void OnSubtextClicked(wxCommandEvent& evt);
|
||||
};
|
||||
|
||||
extern void operator+=(wxSizer &target, pxCheckBox &src);
|
||||
extern void operator+=(wxSizer& target, pxCheckBox& src);
|
||||
|
||||
template <>
|
||||
inline void operator+=(wxSizer &target, const pxWindowAndFlags<pxCheckBox> &src)
|
||||
inline void operator+=(wxSizer& target, const pxWindowAndFlags<pxCheckBox>& src)
|
||||
{
|
||||
target.Add(src.window, src.flags);
|
||||
target.Add(src.window, src.flags);
|
||||
}
|
||||
|
|
|
@ -31,36 +31,36 @@ typedef void FnType_Void();
|
|||
// --------------------------------------------------------------------------------------
|
||||
class SynchronousActionState
|
||||
{
|
||||
DeclareNoncopyableObject(SynchronousActionState);
|
||||
DeclareNoncopyableObject(SynchronousActionState);
|
||||
|
||||
protected:
|
||||
bool m_posted;
|
||||
Threading::Semaphore m_sema;
|
||||
ScopedExcept m_exception;
|
||||
bool m_posted;
|
||||
Threading::Semaphore m_sema;
|
||||
ScopedExcept m_exception;
|
||||
|
||||
public:
|
||||
sptr return_value;
|
||||
sptr return_value;
|
||||
|
||||
SynchronousActionState()
|
||||
{
|
||||
m_posted = false;
|
||||
return_value = 0;
|
||||
}
|
||||
SynchronousActionState()
|
||||
{
|
||||
m_posted = false;
|
||||
return_value = 0;
|
||||
}
|
||||
|
||||
virtual ~SynchronousActionState() = default;
|
||||
virtual ~SynchronousActionState() = default;
|
||||
|
||||
void SetException(const BaseException &ex);
|
||||
void SetException(BaseException *ex);
|
||||
void SetException(const BaseException& ex);
|
||||
void SetException(BaseException* ex);
|
||||
|
||||
Threading::Semaphore &GetSemaphore() { return m_sema; }
|
||||
const Threading::Semaphore &GetSemaphore() const { return m_sema; }
|
||||
Threading::Semaphore& GetSemaphore() { return m_sema; }
|
||||
const Threading::Semaphore& GetSemaphore() const { return m_sema; }
|
||||
|
||||
void RethrowException() const;
|
||||
int WaitForResult();
|
||||
int WaitForResult_NoExceptions();
|
||||
void PostResult(int res);
|
||||
void ClearResult();
|
||||
void PostResult();
|
||||
void RethrowException() const;
|
||||
int WaitForResult();
|
||||
int WaitForResult_NoExceptions();
|
||||
void PostResult(int res);
|
||||
void ClearResult();
|
||||
void PostResult();
|
||||
};
|
||||
|
||||
|
||||
|
@ -73,21 +73,21 @@ public:
|
|||
//
|
||||
class pxSimpleEvent : public wxEvent
|
||||
{
|
||||
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxSimpleEvent);
|
||||
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxSimpleEvent);
|
||||
|
||||
public:
|
||||
explicit pxSimpleEvent(int evtid = 0)
|
||||
: wxEvent(0, evtid)
|
||||
{
|
||||
}
|
||||
explicit pxSimpleEvent(int evtid = 0)
|
||||
: wxEvent(0, evtid)
|
||||
{
|
||||
}
|
||||
|
||||
pxSimpleEvent(wxWindowID winId, int evtid)
|
||||
: wxEvent(winId, evtid)
|
||||
{
|
||||
}
|
||||
pxSimpleEvent(wxWindowID winId, int evtid)
|
||||
: wxEvent(winId, evtid)
|
||||
{
|
||||
}
|
||||
|
||||
pxSimpleEvent(const pxSimpleEvent&) = default;
|
||||
virtual wxEvent *Clone() const { return new pxSimpleEvent(*this); }
|
||||
pxSimpleEvent(const pxSimpleEvent&) = default;
|
||||
virtual wxEvent* Clone() const { return new pxSimpleEvent(*this); }
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -99,41 +99,41 @@ wxDECLARE_EVENT(pxEvt_InvokeAction, pxActionEvent);
|
|||
|
||||
class pxActionEvent : public wxEvent
|
||||
{
|
||||
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxActionEvent);
|
||||
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxActionEvent);
|
||||
|
||||
protected:
|
||||
SynchronousActionState *m_state;
|
||||
SynchronousActionState* m_state;
|
||||
|
||||
public:
|
||||
virtual ~pxActionEvent() = default;
|
||||
virtual pxActionEvent *Clone() const { return new pxActionEvent(*this); }
|
||||
virtual ~pxActionEvent() = default;
|
||||
virtual pxActionEvent* Clone() const { return new pxActionEvent(*this); }
|
||||
|
||||
explicit pxActionEvent(SynchronousActionState *sema = NULL, int msgtype = pxEvt_InvokeAction);
|
||||
explicit pxActionEvent(SynchronousActionState &sema, int msgtype = pxEvt_InvokeAction);
|
||||
pxActionEvent(const pxActionEvent &src);
|
||||
explicit pxActionEvent(SynchronousActionState* sema = NULL, int msgtype = pxEvt_InvokeAction);
|
||||
explicit pxActionEvent(SynchronousActionState& sema, int msgtype = pxEvt_InvokeAction);
|
||||
pxActionEvent(const pxActionEvent& src);
|
||||
|
||||
Threading::Semaphore *GetSemaphore() const { return m_state ? &m_state->GetSemaphore() : NULL; }
|
||||
Threading::Semaphore* GetSemaphore() const { return m_state ? &m_state->GetSemaphore() : NULL; }
|
||||
|
||||
const SynchronousActionState *GetSyncState() const { return m_state; }
|
||||
SynchronousActionState *GetSyncState() { return m_state; }
|
||||
const SynchronousActionState* GetSyncState() const { return m_state; }
|
||||
SynchronousActionState* GetSyncState() { return m_state; }
|
||||
|
||||
void SetSyncState(SynchronousActionState *obj) { m_state = obj; }
|
||||
void SetSyncState(SynchronousActionState &obj) { m_state = &obj; }
|
||||
void SetSyncState(SynchronousActionState* obj) { m_state = obj; }
|
||||
void SetSyncState(SynchronousActionState& obj) { m_state = &obj; }
|
||||
|
||||
virtual void SetException(BaseException *ex);
|
||||
void SetException(const BaseException &ex);
|
||||
virtual void SetException(BaseException* ex);
|
||||
void SetException(const BaseException& ex);
|
||||
|
||||
virtual void _DoInvokeEvent();
|
||||
virtual void _DoInvokeEvent();
|
||||
|
||||
protected:
|
||||
// Extending classes should implement this method to perform whatever action it is
|
||||
// the event is supposed to do. :) Thread affinity is guaranteed to be the Main/UI
|
||||
// thread, and exceptions will be handled automatically.
|
||||
//
|
||||
// Exception note: exceptions are passed back to the thread that posted the event
|
||||
// to the queue, when possible. If the calling thread is not blocking for a result
|
||||
// from this event, then the exception will be posted to the Main/UI thread instead.
|
||||
virtual void InvokeEvent() {}
|
||||
// Extending classes should implement this method to perform whatever action it is
|
||||
// the event is supposed to do. :) Thread affinity is guaranteed to be the Main/UI
|
||||
// thread, and exceptions will be handled automatically.
|
||||
//
|
||||
// Exception note: exceptions are passed back to the thread that posted the event
|
||||
// to the queue, when possible. If the calling thread is not blocking for a result
|
||||
// from this event, then the exception will be posted to the Main/UI thread instead.
|
||||
virtual void InvokeEvent() {}
|
||||
};
|
||||
|
||||
|
||||
|
@ -142,27 +142,27 @@ protected:
|
|||
// --------------------------------------------------------------------------------------
|
||||
class pxExceptionEvent : public pxActionEvent
|
||||
{
|
||||
typedef pxActionEvent _parent;
|
||||
typedef pxActionEvent _parent;
|
||||
|
||||
protected:
|
||||
BaseException *m_except;
|
||||
BaseException* m_except;
|
||||
|
||||
public:
|
||||
pxExceptionEvent(BaseException *ex = NULL)
|
||||
{
|
||||
m_except = ex;
|
||||
}
|
||||
pxExceptionEvent(BaseException* ex = NULL)
|
||||
{
|
||||
m_except = ex;
|
||||
}
|
||||
|
||||
pxExceptionEvent(const BaseException &ex);
|
||||
pxExceptionEvent(const BaseException& ex);
|
||||
|
||||
virtual ~pxExceptionEvent()
|
||||
{
|
||||
}
|
||||
virtual ~pxExceptionEvent()
|
||||
{
|
||||
}
|
||||
|
||||
virtual pxExceptionEvent *Clone() const { return new pxExceptionEvent(*this); }
|
||||
virtual pxExceptionEvent* Clone() const { return new pxExceptionEvent(*this); }
|
||||
|
||||
protected:
|
||||
void InvokeEvent();
|
||||
void InvokeEvent();
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -171,29 +171,29 @@ protected:
|
|||
|
||||
class pxSynchronousCommandEvent : public wxCommandEvent
|
||||
{
|
||||
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxSynchronousCommandEvent);
|
||||
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxSynchronousCommandEvent);
|
||||
|
||||
protected:
|
||||
SynchronousActionState *m_sync;
|
||||
wxEventType m_realEvent;
|
||||
SynchronousActionState* m_sync;
|
||||
wxEventType m_realEvent;
|
||||
|
||||
public:
|
||||
virtual ~pxSynchronousCommandEvent() = default;
|
||||
virtual pxSynchronousCommandEvent *Clone() const { return new pxSynchronousCommandEvent(*this); }
|
||||
virtual ~pxSynchronousCommandEvent() = default;
|
||||
virtual pxSynchronousCommandEvent* Clone() const { return new pxSynchronousCommandEvent(*this); }
|
||||
|
||||
pxSynchronousCommandEvent(SynchronousActionState *sema = NULL, wxEventType commandType = wxEVT_NULL, int winid = 0);
|
||||
pxSynchronousCommandEvent(SynchronousActionState &sema, wxEventType commandType = wxEVT_NULL, int winid = 0);
|
||||
pxSynchronousCommandEvent(SynchronousActionState* sema = NULL, wxEventType commandType = wxEVT_NULL, int winid = 0);
|
||||
pxSynchronousCommandEvent(SynchronousActionState& sema, wxEventType commandType = wxEVT_NULL, int winid = 0);
|
||||
|
||||
pxSynchronousCommandEvent(SynchronousActionState *sema, const wxCommandEvent &evt);
|
||||
pxSynchronousCommandEvent(SynchronousActionState &sema, const wxCommandEvent &evt);
|
||||
pxSynchronousCommandEvent(SynchronousActionState* sema, const wxCommandEvent& evt);
|
||||
pxSynchronousCommandEvent(SynchronousActionState& sema, const wxCommandEvent& evt);
|
||||
|
||||
pxSynchronousCommandEvent(const pxSynchronousCommandEvent &src);
|
||||
pxSynchronousCommandEvent(const pxSynchronousCommandEvent& src);
|
||||
|
||||
Threading::Semaphore *GetSemaphore() { return m_sync ? &m_sync->GetSemaphore() : NULL; }
|
||||
wxEventType GetRealEventType() const { return m_realEvent; }
|
||||
Threading::Semaphore* GetSemaphore() { return m_sync ? &m_sync->GetSemaphore() : NULL; }
|
||||
wxEventType GetRealEventType() const { return m_realEvent; }
|
||||
|
||||
void SetException(BaseException *ex);
|
||||
void SetException(const BaseException &ex);
|
||||
void SetException(BaseException* ex);
|
||||
void SetException(const BaseException& ex);
|
||||
};
|
||||
|
||||
wxDECLARE_EVENT(pxEvt_SynchronousCommand, pxSynchronousCommandEvent);
|
||||
|
@ -203,23 +203,23 @@ wxDECLARE_EVENT(pxEvt_SynchronousCommand, pxSynchronousCommandEvent);
|
|||
// --------------------------------------------------------------------------------------
|
||||
class BaseMessageBoxEvent : public pxActionEvent
|
||||
{
|
||||
typedef pxActionEvent _parent;
|
||||
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(BaseMessageBoxEvent);
|
||||
typedef pxActionEvent _parent;
|
||||
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(BaseMessageBoxEvent);
|
||||
|
||||
protected:
|
||||
wxString m_Content;
|
||||
wxString m_Content;
|
||||
|
||||
public:
|
||||
virtual ~BaseMessageBoxEvent() = default;
|
||||
virtual BaseMessageBoxEvent *Clone() const { return new BaseMessageBoxEvent(*this); }
|
||||
virtual ~BaseMessageBoxEvent() = default;
|
||||
virtual BaseMessageBoxEvent* Clone() const { return new BaseMessageBoxEvent(*this); }
|
||||
|
||||
explicit BaseMessageBoxEvent(const wxString &content = wxEmptyString, SynchronousActionState *instdata = NULL);
|
||||
BaseMessageBoxEvent(const wxString &content, SynchronousActionState &instdata);
|
||||
BaseMessageBoxEvent(const BaseMessageBoxEvent &event);
|
||||
explicit BaseMessageBoxEvent(const wxString& content = wxEmptyString, SynchronousActionState* instdata = NULL);
|
||||
BaseMessageBoxEvent(const wxString& content, SynchronousActionState& instdata);
|
||||
BaseMessageBoxEvent(const BaseMessageBoxEvent& event);
|
||||
|
||||
protected:
|
||||
virtual void InvokeEvent();
|
||||
virtual int _DoDialog() const;
|
||||
virtual void InvokeEvent();
|
||||
virtual int _DoDialog() const;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -228,134 +228,134 @@ protected:
|
|||
class MsgButtons
|
||||
{
|
||||
protected:
|
||||
BITFIELD32()
|
||||
bool
|
||||
m_OK : 1,
|
||||
m_Cancel : 1,
|
||||
m_Yes : 1,
|
||||
m_No : 1,
|
||||
m_AllowToAll : 1,
|
||||
m_Apply : 1,
|
||||
m_Abort : 1,
|
||||
m_Retry : 1,
|
||||
m_Ignore : 1,
|
||||
m_Reset : 1,
|
||||
m_Close : 1;
|
||||
BITFIELD_END
|
||||
BITFIELD32()
|
||||
bool
|
||||
m_OK : 1,
|
||||
m_Cancel : 1,
|
||||
m_Yes : 1,
|
||||
m_No : 1,
|
||||
m_AllowToAll : 1,
|
||||
m_Apply : 1,
|
||||
m_Abort : 1,
|
||||
m_Retry : 1,
|
||||
m_Ignore : 1,
|
||||
m_Reset : 1,
|
||||
m_Close : 1;
|
||||
BITFIELD_END
|
||||
|
||||
wxString m_CustomLabel;
|
||||
wxString m_CustomLabelId;
|
||||
wxString m_CustomLabel;
|
||||
wxString m_CustomLabelId;
|
||||
|
||||
public:
|
||||
MsgButtons() { bitset = 0; }
|
||||
MsgButtons() { bitset = 0; }
|
||||
|
||||
MsgButtons &OK()
|
||||
{
|
||||
m_OK = true;
|
||||
return *this;
|
||||
}
|
||||
MsgButtons &Cancel()
|
||||
{
|
||||
m_Cancel = true;
|
||||
return *this;
|
||||
}
|
||||
MsgButtons &Apply()
|
||||
{
|
||||
m_Apply = true;
|
||||
return *this;
|
||||
}
|
||||
MsgButtons &Yes()
|
||||
{
|
||||
m_Yes = true;
|
||||
return *this;
|
||||
}
|
||||
MsgButtons &No()
|
||||
{
|
||||
m_No = true;
|
||||
return *this;
|
||||
}
|
||||
MsgButtons &ToAll()
|
||||
{
|
||||
m_AllowToAll = true;
|
||||
return *this;
|
||||
}
|
||||
MsgButtons& OK()
|
||||
{
|
||||
m_OK = true;
|
||||
return *this;
|
||||
}
|
||||
MsgButtons& Cancel()
|
||||
{
|
||||
m_Cancel = true;
|
||||
return *this;
|
||||
}
|
||||
MsgButtons& Apply()
|
||||
{
|
||||
m_Apply = true;
|
||||
return *this;
|
||||
}
|
||||
MsgButtons& Yes()
|
||||
{
|
||||
m_Yes = true;
|
||||
return *this;
|
||||
}
|
||||
MsgButtons& No()
|
||||
{
|
||||
m_No = true;
|
||||
return *this;
|
||||
}
|
||||
MsgButtons& ToAll()
|
||||
{
|
||||
m_AllowToAll = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
MsgButtons &Abort()
|
||||
{
|
||||
m_Abort = true;
|
||||
return *this;
|
||||
}
|
||||
MsgButtons &Retry()
|
||||
{
|
||||
m_Retry = true;
|
||||
return *this;
|
||||
}
|
||||
MsgButtons &Ignore()
|
||||
{
|
||||
m_Ignore = true;
|
||||
return *this;
|
||||
}
|
||||
MsgButtons &Reset()
|
||||
{
|
||||
m_Reset = true;
|
||||
return *this;
|
||||
}
|
||||
MsgButtons &Close()
|
||||
{
|
||||
m_Close = true;
|
||||
return *this;
|
||||
}
|
||||
MsgButtons& Abort()
|
||||
{
|
||||
m_Abort = true;
|
||||
return *this;
|
||||
}
|
||||
MsgButtons& Retry()
|
||||
{
|
||||
m_Retry = true;
|
||||
return *this;
|
||||
}
|
||||
MsgButtons& Ignore()
|
||||
{
|
||||
m_Ignore = true;
|
||||
return *this;
|
||||
}
|
||||
MsgButtons& Reset()
|
||||
{
|
||||
m_Reset = true;
|
||||
return *this;
|
||||
}
|
||||
MsgButtons& Close()
|
||||
{
|
||||
m_Close = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// label - native language label displayed to user
|
||||
// id - raw ASCII identifier used in the config file (do not translate, hence char*)
|
||||
MsgButtons &Custom(const wxString &label, const char *id)
|
||||
{
|
||||
m_CustomLabel = label;
|
||||
m_CustomLabelId = fromUTF8(id);
|
||||
return *this;
|
||||
}
|
||||
// label - native language label displayed to user
|
||||
// id - raw ASCII identifier used in the config file (do not translate, hence char*)
|
||||
MsgButtons& Custom(const wxString& label, const char* id)
|
||||
{
|
||||
m_CustomLabel = label;
|
||||
m_CustomLabelId = fromUTF8(id);
|
||||
return *this;
|
||||
}
|
||||
|
||||
MsgButtons &OKCancel()
|
||||
{
|
||||
m_OK = m_Cancel = true;
|
||||
return *this;
|
||||
}
|
||||
MsgButtons &YesNo()
|
||||
{
|
||||
m_Yes = m_No = true;
|
||||
return *this;
|
||||
}
|
||||
MsgButtons& OKCancel()
|
||||
{
|
||||
m_OK = m_Cancel = true;
|
||||
return *this;
|
||||
}
|
||||
MsgButtons& YesNo()
|
||||
{
|
||||
m_Yes = m_No = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool HasOK() const { return m_OK; }
|
||||
bool HasCancel() const { return m_Cancel; }
|
||||
bool HasApply() const { return m_Apply; }
|
||||
bool HasYes() const { return m_Yes; }
|
||||
bool HasNo() const { return m_No; }
|
||||
bool AllowsToAll() const { return m_AllowToAll; }
|
||||
bool HasOK() const { return m_OK; }
|
||||
bool HasCancel() const { return m_Cancel; }
|
||||
bool HasApply() const { return m_Apply; }
|
||||
bool HasYes() const { return m_Yes; }
|
||||
bool HasNo() const { return m_No; }
|
||||
bool AllowsToAll() const { return m_AllowToAll; }
|
||||
|
||||
bool HasAbort() const { return m_Abort; }
|
||||
bool HasRetry() const { return m_Retry; }
|
||||
bool HasIgnore() const { return m_Ignore; }
|
||||
bool HasReset() const { return m_Reset; }
|
||||
bool HasClose() const { return m_Close; }
|
||||
bool HasAbort() const { return m_Abort; }
|
||||
bool HasRetry() const { return m_Retry; }
|
||||
bool HasIgnore() const { return m_Ignore; }
|
||||
bool HasReset() const { return m_Reset; }
|
||||
bool HasClose() const { return m_Close; }
|
||||
|
||||
bool HasCustom() const { return !m_CustomLabel.IsEmpty(); }
|
||||
const wxString &GetCustomLabel() const { return m_CustomLabel; }
|
||||
const wxString &GetCustomLabelId() const { return m_CustomLabelId; }
|
||||
bool HasCustom() const { return !m_CustomLabel.IsEmpty(); }
|
||||
const wxString& GetCustomLabel() const { return m_CustomLabel; }
|
||||
const wxString& GetCustomLabelId() const { return m_CustomLabelId; }
|
||||
|
||||
bool Allows(wxWindowID id) const;
|
||||
void SetBestFocus(wxWindow *dialog) const;
|
||||
void SetBestFocus(wxWindow &dialog) const;
|
||||
bool Allows(wxWindowID id) const;
|
||||
void SetBestFocus(wxWindow* dialog) const;
|
||||
void SetBestFocus(wxWindow& dialog) const;
|
||||
|
||||
bool operator==(const MsgButtons &right) const
|
||||
{
|
||||
return OpEqu(bitset);
|
||||
}
|
||||
bool operator==(const MsgButtons& right) const
|
||||
{
|
||||
return OpEqu(bitset);
|
||||
}
|
||||
|
||||
bool operator!=(const MsgButtons &right) const
|
||||
{
|
||||
return !OpEqu(bitset);
|
||||
}
|
||||
bool operator!=(const MsgButtons& right) const
|
||||
{
|
||||
return !OpEqu(bitset);
|
||||
}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -378,24 +378,24 @@ public:
|
|||
//
|
||||
class pxMessageBoxEvent : public BaseMessageBoxEvent
|
||||
{
|
||||
typedef BaseMessageBoxEvent _parent;
|
||||
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxMessageBoxEvent);
|
||||
typedef BaseMessageBoxEvent _parent;
|
||||
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxMessageBoxEvent);
|
||||
|
||||
protected:
|
||||
wxString m_Title;
|
||||
MsgButtons m_Buttons;
|
||||
wxString m_Title;
|
||||
MsgButtons m_Buttons;
|
||||
|
||||
public:
|
||||
virtual ~pxMessageBoxEvent() = default;
|
||||
virtual pxMessageBoxEvent *Clone() const { return new pxMessageBoxEvent(*this); }
|
||||
virtual ~pxMessageBoxEvent() = default;
|
||||
virtual pxMessageBoxEvent* Clone() const { return new pxMessageBoxEvent(*this); }
|
||||
|
||||
pxMessageBoxEvent() {}
|
||||
pxMessageBoxEvent(const wxString &title, const wxString &content, const MsgButtons &buttons, SynchronousActionState &instdata);
|
||||
pxMessageBoxEvent(const wxString &title, const wxString &content, const MsgButtons &buttons, SynchronousActionState *instdata = NULL);
|
||||
pxMessageBoxEvent(const pxMessageBoxEvent &event) = default;
|
||||
pxMessageBoxEvent() {}
|
||||
pxMessageBoxEvent(const wxString& title, const wxString& content, const MsgButtons& buttons, SynchronousActionState& instdata);
|
||||
pxMessageBoxEvent(const wxString& title, const wxString& content, const MsgButtons& buttons, SynchronousActionState* instdata = NULL);
|
||||
pxMessageBoxEvent(const pxMessageBoxEvent& event) = default;
|
||||
|
||||
protected:
|
||||
int _DoDialog() const;
|
||||
int _DoDialog() const;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -403,22 +403,22 @@ protected:
|
|||
// --------------------------------------------------------------------------------------
|
||||
class pxAssertionEvent : public BaseMessageBoxEvent
|
||||
{
|
||||
typedef BaseMessageBoxEvent _parent;
|
||||
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxAssertionEvent);
|
||||
typedef BaseMessageBoxEvent _parent;
|
||||
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxAssertionEvent);
|
||||
|
||||
protected:
|
||||
wxString m_Stacktrace;
|
||||
wxString m_Stacktrace;
|
||||
|
||||
public:
|
||||
virtual ~pxAssertionEvent() = default;
|
||||
virtual pxAssertionEvent *Clone() const { return new pxAssertionEvent(*this); }
|
||||
virtual ~pxAssertionEvent() = default;
|
||||
virtual pxAssertionEvent* Clone() const { return new pxAssertionEvent(*this); }
|
||||
|
||||
pxAssertionEvent(const wxString &content = wxEmptyString, const wxString &trace = wxEmptyString, SynchronousActionState *instdata = NULL);
|
||||
pxAssertionEvent(const wxString &content, const wxString &trace, SynchronousActionState &instdata);
|
||||
pxAssertionEvent(const pxAssertionEvent &event) = default;
|
||||
pxAssertionEvent(const wxString& content = wxEmptyString, const wxString& trace = wxEmptyString, SynchronousActionState* instdata = NULL);
|
||||
pxAssertionEvent(const wxString& content, const wxString& trace, SynchronousActionState& instdata);
|
||||
pxAssertionEvent(const pxAssertionEvent& event) = default;
|
||||
|
||||
pxAssertionEvent &SetStacktrace(const wxString &trace);
|
||||
pxAssertionEvent& SetStacktrace(const wxString& trace);
|
||||
|
||||
protected:
|
||||
int _DoDialog() const;
|
||||
int _DoDialog() const;
|
||||
};
|
||||
|
|
|
@ -40,12 +40,12 @@ extern const wxPoint wxDefaultPosition;
|
|||
|
||||
namespace Threading
|
||||
{
|
||||
class Mutex;
|
||||
class Semaphore;
|
||||
class pxThread;
|
||||
}
|
||||
class Mutex;
|
||||
class Semaphore;
|
||||
class pxThread;
|
||||
} // namespace Threading
|
||||
|
||||
namespace Exception
|
||||
{
|
||||
class BaseException;
|
||||
class BaseException;
|
||||
}
|
||||
|
|
|
@ -24,232 +24,239 @@ template class SafeArray<RadioPanelObjects>;
|
|||
// ===========================================================================================
|
||||
|
||||
#define VerifyRealizedState() \
|
||||
pxAssertDev(m_IsRealized, "Invalid object state: RadioButtonGroup as not been realized.")
|
||||
pxAssertDev(m_IsRealized, "Invalid object state: RadioButtonGroup as not been realized.")
|
||||
|
||||
void pxRadioPanel::Init(const RadioPanelItem *srcArray, int arrsize)
|
||||
void pxRadioPanel::Init(const RadioPanelItem* srcArray, int arrsize)
|
||||
{
|
||||
m_DefaultIdx = -1;
|
||||
m_IsRealized = false;
|
||||
m_DefaultIdx = -1;
|
||||
m_IsRealized = false;
|
||||
|
||||
// FIXME: This probably needs to be platform-dependent, and/or based on font size.
|
||||
m_Indentation = 23;
|
||||
// FIXME: This probably needs to be platform-dependent, and/or based on font size.
|
||||
m_Indentation = 23;
|
||||
|
||||
for (int i = 0; i < arrsize; ++i)
|
||||
Append(srcArray[i]);
|
||||
for (int i = 0; i < arrsize; ++i)
|
||||
Append(srcArray[i]);
|
||||
}
|
||||
|
||||
pxRadioPanel &pxRadioPanel::Append(const RadioPanelItem &entry)
|
||||
pxRadioPanel& pxRadioPanel::Append(const RadioPanelItem& entry)
|
||||
{
|
||||
m_buttonStrings.push_back(entry);
|
||||
return *this;
|
||||
m_buttonStrings.push_back(entry);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void pxRadioPanel::Reset()
|
||||
{
|
||||
m_IsRealized = false;
|
||||
const int numbuttons = m_buttonStrings.size();
|
||||
if (numbuttons == 0)
|
||||
return;
|
||||
m_IsRealized = false;
|
||||
const int numbuttons = m_buttonStrings.size();
|
||||
if (numbuttons == 0)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < numbuttons; ++i) {
|
||||
safe_delete(m_objects[i].LabelObj);
|
||||
safe_delete(m_objects[i].SubTextObj);
|
||||
}
|
||||
m_buttonStrings.clear();
|
||||
for (int i = 0; i < numbuttons; ++i)
|
||||
{
|
||||
safe_delete(m_objects[i].LabelObj);
|
||||
safe_delete(m_objects[i].SubTextObj);
|
||||
}
|
||||
m_buttonStrings.clear();
|
||||
}
|
||||
|
||||
void pxRadioPanel::Realize()
|
||||
{
|
||||
const int numbuttons = m_buttonStrings.size();
|
||||
if (numbuttons == 0)
|
||||
return;
|
||||
if (m_IsRealized)
|
||||
return;
|
||||
m_IsRealized = true;
|
||||
const int numbuttons = m_buttonStrings.size();
|
||||
if (numbuttons == 0)
|
||||
return;
|
||||
if (m_IsRealized)
|
||||
return;
|
||||
m_IsRealized = true;
|
||||
|
||||
m_objects.MakeRoomFor(numbuttons);
|
||||
m_objects.MakeRoomFor(numbuttons);
|
||||
|
||||
// Add all RadioButtons in one pass, and then go back and create all the subtext
|
||||
// objects. This ensures the radio buttons have consecutive tab order IDs, which
|
||||
// is the "preferred" method when using grouping features of the native window
|
||||
// managers (GTK tends to not care either way, but Win32 definitely prefers a
|
||||
// linear tab order).
|
||||
// Add all RadioButtons in one pass, and then go back and create all the subtext
|
||||
// objects. This ensures the radio buttons have consecutive tab order IDs, which
|
||||
// is the "preferred" method when using grouping features of the native window
|
||||
// managers (GTK tends to not care either way, but Win32 definitely prefers a
|
||||
// linear tab order).
|
||||
|
||||
// first object has the group flag set to ensure it's the start of a radio group.
|
||||
m_objects[0].LabelObj = new wxRadioButton(this, wxID_ANY, m_buttonStrings[0].Label, wxDefaultPosition, wxDefaultSize, wxRB_GROUP);
|
||||
for (int i = 1; i < numbuttons; ++i)
|
||||
m_objects[i].LabelObj = new wxRadioButton(this, wxID_ANY, m_buttonStrings[i].Label);
|
||||
// first object has the group flag set to ensure it's the start of a radio group.
|
||||
m_objects[0].LabelObj = new wxRadioButton(this, wxID_ANY, m_buttonStrings[0].Label, wxDefaultPosition, wxDefaultSize, wxRB_GROUP);
|
||||
for (int i = 1; i < numbuttons; ++i)
|
||||
m_objects[i].LabelObj = new wxRadioButton(this, wxID_ANY, m_buttonStrings[i].Label);
|
||||
|
||||
for (int i = 0; i < numbuttons; ++i) {
|
||||
m_objects[i].SubTextObj = NULL;
|
||||
if (m_buttonStrings[i].SubText.IsEmpty())
|
||||
continue;
|
||||
m_objects[i].SubTextObj = new pxStaticText(this, m_buttonStrings[i].SubText, wxALIGN_LEFT);
|
||||
}
|
||||
for (int i = 0; i < numbuttons; ++i)
|
||||
{
|
||||
m_objects[i].SubTextObj = NULL;
|
||||
if (m_buttonStrings[i].SubText.IsEmpty())
|
||||
continue;
|
||||
m_objects[i].SubTextObj = new pxStaticText(this, m_buttonStrings[i].SubText, wxALIGN_LEFT);
|
||||
}
|
||||
|
||||
pxAssert(GetSizer() != NULL);
|
||||
pxAssert(GetSizer() != NULL);
|
||||
|
||||
for (int i = 0; i < numbuttons; ++i) {
|
||||
*this += m_objects[i].LabelObj | pxSizerFlags::StdExpand();
|
||||
for (int i = 0; i < numbuttons; ++i)
|
||||
{
|
||||
*this += m_objects[i].LabelObj | pxSizerFlags::StdExpand();
|
||||
|
||||
if (pxStaticText *subobj = m_objects[i].SubTextObj) {
|
||||
*this += subobj | pxBorder(wxLEFT, m_Indentation).Expand();
|
||||
*this += 9 + m_padding.GetHeight();
|
||||
}
|
||||
if (!m_buttonStrings[i].ToolTip.IsEmpty())
|
||||
_setToolTipImmediate(i, m_buttonStrings[i].ToolTip);
|
||||
}
|
||||
if (pxStaticText* subobj = m_objects[i].SubTextObj)
|
||||
{
|
||||
*this += subobj | pxBorder(wxLEFT, m_Indentation).Expand();
|
||||
*this += 9 + m_padding.GetHeight();
|
||||
}
|
||||
if (!m_buttonStrings[i].ToolTip.IsEmpty())
|
||||
_setToolTipImmediate(i, m_buttonStrings[i].ToolTip);
|
||||
}
|
||||
|
||||
_RealizeDefaultOption();
|
||||
_RealizeDefaultOption();
|
||||
}
|
||||
|
||||
void pxRadioPanel::_setToolTipImmediate(int idx, const wxString &tip)
|
||||
void pxRadioPanel::_setToolTipImmediate(int idx, const wxString& tip)
|
||||
{
|
||||
if (wxRadioButton *woot = m_objects[idx].LabelObj)
|
||||
woot->SetToolTip(tip);
|
||||
if (wxRadioButton* woot = m_objects[idx].LabelObj)
|
||||
woot->SetToolTip(tip);
|
||||
|
||||
if (pxStaticText *woot = m_objects[idx].SubTextObj)
|
||||
woot->SetToolTip(tip);
|
||||
if (pxStaticText* woot = m_objects[idx].SubTextObj)
|
||||
woot->SetToolTip(tip);
|
||||
}
|
||||
|
||||
// The SetToolTip API provided by this function applies the tooltip to both the radio
|
||||
// button and it's static subtext (if present), and performs word wrapping on platforms
|
||||
// that need it (eg mswindows).
|
||||
pxRadioPanel &pxRadioPanel::SetToolTip(int idx, const wxString &tip)
|
||||
pxRadioPanel& pxRadioPanel::SetToolTip(int idx, const wxString& tip)
|
||||
{
|
||||
m_buttonStrings[idx].SetToolTip(tip);
|
||||
m_buttonStrings[idx].SetToolTip(tip);
|
||||
|
||||
if (m_IsRealized)
|
||||
_setToolTipImmediate(idx, tip);
|
||||
if (m_IsRealized)
|
||||
_setToolTipImmediate(idx, tip);
|
||||
|
||||
return *this;
|
||||
return *this;
|
||||
}
|
||||
|
||||
pxRadioPanel &pxRadioPanel::SetSelection(int idx)
|
||||
pxRadioPanel& pxRadioPanel::SetSelection(int idx)
|
||||
{
|
||||
if (!VerifyRealizedState())
|
||||
return *this;
|
||||
if (!VerifyRealizedState())
|
||||
return *this;
|
||||
|
||||
pxAssert(m_objects[idx].LabelObj != NULL);
|
||||
m_objects[idx].LabelObj->SetValue(true);
|
||||
return *this;
|
||||
pxAssert(m_objects[idx].LabelObj != NULL);
|
||||
m_objects[idx].LabelObj->SetValue(true);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void pxRadioPanel::_RealizeDefaultOption()
|
||||
{
|
||||
if (m_IsRealized && m_DefaultIdx != -1) {
|
||||
wxFont def(GetFont());
|
||||
def.SetWeight(wxFONTWEIGHT_BOLD);
|
||||
//def.SetStyle( wxFONTSTYLE_ITALIC );
|
||||
m_objects[m_DefaultIdx].LabelObj->SetFont(def);
|
||||
m_objects[m_DefaultIdx].LabelObj->SetForegroundColour(wxColour(20, 128, 40));
|
||||
}
|
||||
if (m_IsRealized && m_DefaultIdx != -1)
|
||||
{
|
||||
wxFont def(GetFont());
|
||||
def.SetWeight(wxFONTWEIGHT_BOLD);
|
||||
//def.SetStyle( wxFONTSTYLE_ITALIC );
|
||||
m_objects[m_DefaultIdx].LabelObj->SetFont(def);
|
||||
m_objects[m_DefaultIdx].LabelObj->SetForegroundColour(wxColour(20, 128, 40));
|
||||
}
|
||||
}
|
||||
|
||||
// Highlights (bold) the text of the default radio.
|
||||
// Not intended for restoring default value at later time.
|
||||
pxRadioPanel &pxRadioPanel::SetDefaultItem(int idx)
|
||||
pxRadioPanel& pxRadioPanel::SetDefaultItem(int idx)
|
||||
{
|
||||
if (idx == m_DefaultIdx)
|
||||
return *this;
|
||||
if (idx == m_DefaultIdx)
|
||||
return *this;
|
||||
|
||||
if (m_IsRealized && m_DefaultIdx != -1) {
|
||||
wxFont def(GetFont());
|
||||
m_objects[m_DefaultIdx].LabelObj->SetFont(def);
|
||||
m_objects[m_DefaultIdx].LabelObj->SetForegroundColour(GetForegroundColour());
|
||||
}
|
||||
if (m_IsRealized && m_DefaultIdx != -1)
|
||||
{
|
||||
wxFont def(GetFont());
|
||||
m_objects[m_DefaultIdx].LabelObj->SetFont(def);
|
||||
m_objects[m_DefaultIdx].LabelObj->SetForegroundColour(GetForegroundColour());
|
||||
}
|
||||
|
||||
m_DefaultIdx = idx;
|
||||
_RealizeDefaultOption();
|
||||
m_DefaultIdx = idx;
|
||||
_RealizeDefaultOption();
|
||||
|
||||
return *this;
|
||||
return *this;
|
||||
}
|
||||
|
||||
pxRadioPanel &pxRadioPanel::EnableItem(int idx, bool enable)
|
||||
pxRadioPanel& pxRadioPanel::EnableItem(int idx, bool enable)
|
||||
{
|
||||
pxAssertDev(m_IsRealized, "RadioPanel must be realized first, prior to enabling or disabling individual items.");
|
||||
pxAssertDev(m_IsRealized, "RadioPanel must be realized first, prior to enabling or disabling individual items.");
|
||||
|
||||
if (m_objects[idx].LabelObj)
|
||||
m_objects[idx].LabelObj->Enable(enable);
|
||||
if (m_objects[idx].LabelObj)
|
||||
m_objects[idx].LabelObj->Enable(enable);
|
||||
|
||||
if (m_objects[idx].SubTextObj)
|
||||
m_objects[idx].SubTextObj->Enable(enable);
|
||||
if (m_objects[idx].SubTextObj)
|
||||
m_objects[idx].SubTextObj->Enable(enable);
|
||||
|
||||
return *this;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const RadioPanelItem &pxRadioPanel::Item(int idx) const
|
||||
const RadioPanelItem& pxRadioPanel::Item(int idx) const
|
||||
{
|
||||
return m_buttonStrings[idx];
|
||||
return m_buttonStrings[idx];
|
||||
}
|
||||
|
||||
RadioPanelItem &pxRadioPanel::Item(int idx)
|
||||
RadioPanelItem& pxRadioPanel::Item(int idx)
|
||||
{
|
||||
return m_buttonStrings[idx];
|
||||
return m_buttonStrings[idx];
|
||||
}
|
||||
|
||||
int pxRadioPanel::GetSelection() const
|
||||
{
|
||||
if (!VerifyRealizedState())
|
||||
return 0;
|
||||
if (!VerifyRealizedState())
|
||||
return 0;
|
||||
|
||||
for (uint i = 0; i < m_buttonStrings.size(); ++i) {
|
||||
if (wxRadioButton *woot = m_objects[i].LabelObj)
|
||||
if (woot->GetValue())
|
||||
return i;
|
||||
}
|
||||
for (uint i = 0; i < m_buttonStrings.size(); ++i)
|
||||
{
|
||||
if (wxRadioButton* woot = m_objects[i].LabelObj)
|
||||
if (woot->GetValue())
|
||||
return i;
|
||||
}
|
||||
|
||||
// Technically radio buttons should never allow for a case where none are selected.
|
||||
// However it *can* happen on some platforms if the program code doesn't explicitly
|
||||
// select one of the members of the group (which is, as far as I'm concerned, a
|
||||
// programmer error!). so Assert here in such cases, and return 0 as the assumed
|
||||
// default, so that calling code has a "valid" return code in release builds.
|
||||
// Technically radio buttons should never allow for a case where none are selected.
|
||||
// However it *can* happen on some platforms if the program code doesn't explicitly
|
||||
// select one of the members of the group (which is, as far as I'm concerned, a
|
||||
// programmer error!). so Assert here in such cases, and return 0 as the assumed
|
||||
// default, so that calling code has a "valid" return code in release builds.
|
||||
|
||||
pxFailDev("No valid selection was found in this group!");
|
||||
return 0;
|
||||
pxFailDev("No valid selection was found in this group!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Returns the wxWindowID for the currently selected radio button.
|
||||
wxWindowID pxRadioPanel::GetSelectionId() const
|
||||
{
|
||||
if (!VerifyRealizedState())
|
||||
return 0;
|
||||
return m_objects[GetSelection()].LabelObj->GetId();
|
||||
if (!VerifyRealizedState())
|
||||
return 0;
|
||||
return m_objects[GetSelection()].LabelObj->GetId();
|
||||
}
|
||||
|
||||
|
||||
bool pxRadioPanel::IsSelected(int idx) const
|
||||
{
|
||||
if (!VerifyRealizedState())
|
||||
return false;
|
||||
pxAssert(m_objects[idx].LabelObj != NULL);
|
||||
return m_objects[idx].LabelObj->GetValue();
|
||||
if (!VerifyRealizedState())
|
||||
return false;
|
||||
pxAssert(m_objects[idx].LabelObj != NULL);
|
||||
return m_objects[idx].LabelObj->GetValue();
|
||||
}
|
||||
|
||||
pxStaticText *pxRadioPanel::GetSubText(int idx)
|
||||
pxStaticText* pxRadioPanel::GetSubText(int idx)
|
||||
{
|
||||
if (!VerifyRealizedState())
|
||||
return NULL;
|
||||
return m_objects[idx].SubTextObj;
|
||||
if (!VerifyRealizedState())
|
||||
return NULL;
|
||||
return m_objects[idx].SubTextObj;
|
||||
}
|
||||
|
||||
const pxStaticText *pxRadioPanel::GetSubText(int idx) const
|
||||
const pxStaticText* pxRadioPanel::GetSubText(int idx) const
|
||||
{
|
||||
if (!VerifyRealizedState())
|
||||
return NULL;
|
||||
return m_objects[idx].SubTextObj;
|
||||
if (!VerifyRealizedState())
|
||||
return NULL;
|
||||
return m_objects[idx].SubTextObj;
|
||||
}
|
||||
|
||||
wxRadioButton *pxRadioPanel::GetButton(int idx)
|
||||
wxRadioButton* pxRadioPanel::GetButton(int idx)
|
||||
{
|
||||
if (!VerifyRealizedState())
|
||||
return NULL;
|
||||
return m_objects[idx].LabelObj;
|
||||
if (!VerifyRealizedState())
|
||||
return NULL;
|
||||
return m_objects[idx].LabelObj;
|
||||
}
|
||||
|
||||
const wxRadioButton *pxRadioPanel::GetButton(int idx) const
|
||||
const wxRadioButton* pxRadioPanel::GetButton(int idx) const
|
||||
{
|
||||
if (!VerifyRealizedState())
|
||||
return NULL;
|
||||
return m_objects[idx].LabelObj;
|
||||
if (!VerifyRealizedState())
|
||||
return NULL;
|
||||
return m_objects[idx].LabelObj;
|
||||
}
|
||||
|
|
|
@ -25,45 +25,45 @@
|
|||
|
||||
struct RadioPanelItem
|
||||
{
|
||||
wxString Label;
|
||||
wxString SubText;
|
||||
wxString ToolTip;
|
||||
wxString Label;
|
||||
wxString SubText;
|
||||
wxString ToolTip;
|
||||
|
||||
int SomeInt;
|
||||
void *SomePtr;
|
||||
int SomeInt;
|
||||
void* SomePtr;
|
||||
|
||||
RadioPanelItem(const wxString &label, const wxString &subtext = wxEmptyString, const wxString &tooltip = wxEmptyString)
|
||||
: Label(label)
|
||||
, SubText(subtext)
|
||||
, ToolTip(tooltip)
|
||||
{
|
||||
SomeInt = 0;
|
||||
SomePtr = NULL;
|
||||
}
|
||||
RadioPanelItem(const wxString& label, const wxString& subtext = wxEmptyString, const wxString& tooltip = wxEmptyString)
|
||||
: Label(label)
|
||||
, SubText(subtext)
|
||||
, ToolTip(tooltip)
|
||||
{
|
||||
SomeInt = 0;
|
||||
SomePtr = NULL;
|
||||
}
|
||||
|
||||
RadioPanelItem &SetToolTip(const wxString &tip)
|
||||
{
|
||||
ToolTip = tip;
|
||||
return *this;
|
||||
}
|
||||
RadioPanelItem& SetToolTip(const wxString& tip)
|
||||
{
|
||||
ToolTip = tip;
|
||||
return *this;
|
||||
}
|
||||
|
||||
RadioPanelItem &SetSubText(const wxString &text)
|
||||
{
|
||||
SubText = text;
|
||||
return *this;
|
||||
}
|
||||
RadioPanelItem& SetSubText(const wxString& text)
|
||||
{
|
||||
SubText = text;
|
||||
return *this;
|
||||
}
|
||||
|
||||
RadioPanelItem &SetInt(int intval)
|
||||
{
|
||||
SomeInt = intval;
|
||||
return *this;
|
||||
}
|
||||
RadioPanelItem& SetInt(int intval)
|
||||
{
|
||||
SomeInt = intval;
|
||||
return *this;
|
||||
}
|
||||
|
||||
RadioPanelItem &SetPtr(void *ptrval)
|
||||
{
|
||||
SomePtr = ptrval;
|
||||
return *this;
|
||||
}
|
||||
RadioPanelItem& SetPtr(void* ptrval)
|
||||
{
|
||||
SomePtr = ptrval;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -71,8 +71,8 @@ struct RadioPanelItem
|
|||
// wrapped and re-wrapped with multiple calls to OnResize().
|
||||
struct RadioPanelObjects
|
||||
{
|
||||
wxRadioButton *LabelObj;
|
||||
pxStaticText *SubTextObj;
|
||||
wxRadioButton* LabelObj;
|
||||
pxStaticText* SubTextObj;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -91,86 +91,86 @@ struct RadioPanelObjects
|
|||
class pxRadioPanel : public wxPanelWithHelpers
|
||||
{
|
||||
protected:
|
||||
typedef std::vector<RadioPanelItem> ButtonArray;
|
||||
typedef SafeArray<RadioPanelObjects> ButtonObjArray;
|
||||
typedef std::vector<RadioPanelItem> ButtonArray;
|
||||
typedef SafeArray<RadioPanelObjects> ButtonObjArray;
|
||||
|
||||
ButtonArray m_buttonStrings;
|
||||
ButtonObjArray m_objects;
|
||||
ButtonArray m_buttonStrings;
|
||||
ButtonObjArray m_objects;
|
||||
|
||||
bool m_IsRealized;
|
||||
bool m_IsRealized;
|
||||
|
||||
wxSize m_padding;
|
||||
int m_Indentation;
|
||||
int m_DefaultIdx; // index of the default option (gets specific color/font treatment)
|
||||
wxSize m_padding;
|
||||
int m_Indentation;
|
||||
int m_DefaultIdx; // index of the default option (gets specific color/font treatment)
|
||||
|
||||
public:
|
||||
template <int size>
|
||||
pxRadioPanel(wxWindow *parent, const RadioPanelItem (&src)[size])
|
||||
: wxPanelWithHelpers(parent, wxVERTICAL)
|
||||
{
|
||||
Init(src, size);
|
||||
}
|
||||
template <int size>
|
||||
pxRadioPanel(wxWindow* parent, const RadioPanelItem (&src)[size])
|
||||
: wxPanelWithHelpers(parent, wxVERTICAL)
|
||||
{
|
||||
Init(src, size);
|
||||
}
|
||||
|
||||
pxRadioPanel(wxWindow *parent)
|
||||
: wxPanelWithHelpers(parent, wxVERTICAL)
|
||||
{
|
||||
Init();
|
||||
}
|
||||
pxRadioPanel(wxWindow* parent)
|
||||
: wxPanelWithHelpers(parent, wxVERTICAL)
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
virtual ~pxRadioPanel() = default;
|
||||
virtual ~pxRadioPanel() = default;
|
||||
|
||||
void Reset();
|
||||
void Realize();
|
||||
void Reset();
|
||||
void Realize();
|
||||
|
||||
pxStaticText *GetSubText(int idx);
|
||||
const pxStaticText *GetSubText(int idx) const;
|
||||
pxRadioPanel &Append(const RadioPanelItem &entry);
|
||||
pxStaticText* GetSubText(int idx);
|
||||
const pxStaticText* GetSubText(int idx) const;
|
||||
pxRadioPanel& Append(const RadioPanelItem& entry);
|
||||
|
||||
pxRadioPanel &SetToolTip(int idx, const wxString &tip);
|
||||
pxRadioPanel &SetSelection(int idx);
|
||||
pxRadioPanel &SetDefaultItem(int idx);
|
||||
pxRadioPanel &EnableItem(int idx, bool enable = true);
|
||||
pxRadioPanel& SetToolTip(int idx, const wxString& tip);
|
||||
pxRadioPanel& SetSelection(int idx);
|
||||
pxRadioPanel& SetDefaultItem(int idx);
|
||||
pxRadioPanel& EnableItem(int idx, bool enable = true);
|
||||
|
||||
const RadioPanelItem &Item(int idx) const;
|
||||
RadioPanelItem &Item(int idx);
|
||||
const RadioPanelItem& Item(int idx) const;
|
||||
RadioPanelItem& Item(int idx);
|
||||
|
||||
int GetSelection() const;
|
||||
wxWindowID GetSelectionId() const;
|
||||
bool IsSelected(int idx) const;
|
||||
int GetSelection() const;
|
||||
wxWindowID GetSelectionId() const;
|
||||
bool IsSelected(int idx) const;
|
||||
|
||||
const RadioPanelItem &SelectedItem() const { return Item(GetSelection()); }
|
||||
RadioPanelItem &SelectedItem() { return Item(GetSelection()); }
|
||||
const RadioPanelItem& SelectedItem() const { return Item(GetSelection()); }
|
||||
RadioPanelItem& SelectedItem() { return Item(GetSelection()); }
|
||||
|
||||
wxRadioButton *GetButton(int idx);
|
||||
const wxRadioButton *GetButton(int idx) const;
|
||||
wxRadioButton* GetButton(int idx);
|
||||
const wxRadioButton* GetButton(int idx) const;
|
||||
|
||||
int GetPaddingVert() const { return m_padding.GetHeight(); }
|
||||
int GetIndentation() const { return m_Indentation; }
|
||||
int GetPaddingVert() const { return m_padding.GetHeight(); }
|
||||
int GetIndentation() const { return m_Indentation; }
|
||||
|
||||
pxRadioPanel &SetPaddingHoriz(int newpad)
|
||||
{
|
||||
m_padding.SetHeight(newpad);
|
||||
return *this;
|
||||
}
|
||||
pxRadioPanel& SetPaddingHoriz(int newpad)
|
||||
{
|
||||
m_padding.SetHeight(newpad);
|
||||
return *this;
|
||||
}
|
||||
|
||||
pxRadioPanel &SetIndentation(int newdent)
|
||||
{
|
||||
m_Indentation = newdent;
|
||||
return *this;
|
||||
}
|
||||
pxRadioPanel& SetIndentation(int newdent)
|
||||
{
|
||||
m_Indentation = newdent;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool HasSubText(int idx) const
|
||||
{
|
||||
return !m_buttonStrings[idx].SubText.IsEmpty();
|
||||
}
|
||||
bool HasSubText(int idx) const
|
||||
{
|
||||
return !m_buttonStrings[idx].SubText.IsEmpty();
|
||||
}
|
||||
|
||||
pxRadioPanel &Append(const wxString &label, const wxString &subtext = wxEmptyString, const wxString &tooltip = wxEmptyString)
|
||||
{
|
||||
return Append(RadioPanelItem(label, subtext, tooltip));
|
||||
}
|
||||
pxRadioPanel& Append(const wxString& label, const wxString& subtext = wxEmptyString, const wxString& tooltip = wxEmptyString)
|
||||
{
|
||||
return Append(RadioPanelItem(label, subtext, tooltip));
|
||||
}
|
||||
|
||||
protected:
|
||||
void Init(const RadioPanelItem *srcArray = NULL, int arrsize = 0);
|
||||
void _setToolTipImmediate(int idx, const wxString &tip);
|
||||
void _RealizeDefaultOption();
|
||||
void Init(const RadioPanelItem* srcArray = NULL, int arrsize = 0);
|
||||
void _setToolTipImmediate(int idx, const wxString& tip);
|
||||
void _RealizeDefaultOption();
|
||||
};
|
||||
|
|
|
@ -20,33 +20,33 @@
|
|||
// --------------------------------------------------------------------------------------
|
||||
// pxStaticText (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
pxStaticText::pxStaticText(wxWindow *parent)
|
||||
: _parent(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNO_BORDER)
|
||||
pxStaticText::pxStaticText(wxWindow* parent)
|
||||
: _parent(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNO_BORDER)
|
||||
{
|
||||
m_align = wxALIGN_CENTRE_HORIZONTAL;
|
||||
m_autowrap = true;
|
||||
m_wrappedWidth = -1;
|
||||
m_heightInLines = 1;
|
||||
m_align = wxALIGN_CENTRE_HORIZONTAL;
|
||||
m_autowrap = true;
|
||||
m_wrappedWidth = -1;
|
||||
m_heightInLines = 1;
|
||||
|
||||
SetPaddingDefaults();
|
||||
SetPaddingDefaults();
|
||||
}
|
||||
|
||||
pxStaticText::pxStaticText(wxWindow *parent, const wxString &label, wxAlignment align)
|
||||
: _parent(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNO_BORDER)
|
||||
pxStaticText::pxStaticText(wxWindow* parent, const wxString& label, wxAlignment align)
|
||||
: _parent(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNO_BORDER)
|
||||
{
|
||||
m_heightInLines = 1;
|
||||
m_align = align;
|
||||
m_heightInLines = 1;
|
||||
m_align = align;
|
||||
|
||||
SetPaddingDefaults();
|
||||
Init(label);
|
||||
SetPaddingDefaults();
|
||||
Init(label);
|
||||
}
|
||||
|
||||
void pxStaticText::Init(const wxString &label)
|
||||
void pxStaticText::Init(const wxString& label)
|
||||
{
|
||||
m_autowrap = true;
|
||||
m_wrappedWidth = -1;
|
||||
m_label = label;
|
||||
Bind(wxEVT_PAINT, &pxStaticText::paintEvent, this);
|
||||
m_autowrap = true;
|
||||
m_wrappedWidth = -1;
|
||||
m_label = label;
|
||||
Bind(wxEVT_PAINT, &pxStaticText::paintEvent, this);
|
||||
}
|
||||
|
||||
// we need to refresh the window after changing its size as the standard
|
||||
|
@ -54,328 +54,338 @@ void pxStaticText::Init(const wxString &label)
|
|||
// the control is expanded to fit -- ie the control's size changes but the position does not)
|
||||
void pxStaticText::DoSetSize(int x, int y, int w, int h, int sizeFlags)
|
||||
{
|
||||
_parent::DoSetSize(x, y, w, h, sizeFlags);
|
||||
Refresh();
|
||||
_parent::DoSetSize(x, y, w, h, sizeFlags);
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void pxStaticText::SetPaddingDefaults()
|
||||
{
|
||||
m_paddingPix_horiz = 7;
|
||||
m_paddingPix_vert = 1;
|
||||
m_paddingPix_horiz = 7;
|
||||
m_paddingPix_vert = 1;
|
||||
|
||||
m_paddingPct_horiz = 0.0f;
|
||||
m_paddingPct_vert = 0.0f;
|
||||
m_paddingPct_horiz = 0.0f;
|
||||
m_paddingPct_vert = 0.0f;
|
||||
}
|
||||
|
||||
pxStaticText &pxStaticText::SetMinWidth(int width)
|
||||
pxStaticText& pxStaticText::SetMinWidth(int width)
|
||||
{
|
||||
SetMinSize(wxSize(width, GetMinHeight()));
|
||||
return *this;
|
||||
SetMinSize(wxSize(width, GetMinHeight()));
|
||||
return *this;
|
||||
}
|
||||
|
||||
pxStaticText &pxStaticText::SetMinHeight(int height)
|
||||
pxStaticText& pxStaticText::SetMinHeight(int height)
|
||||
{
|
||||
SetMinSize(wxSize(GetMinWidth(), height));
|
||||
return *this;
|
||||
SetMinSize(wxSize(GetMinWidth(), height));
|
||||
return *this;
|
||||
}
|
||||
|
||||
pxStaticText &pxStaticText::SetHeight(int lines)
|
||||
pxStaticText& pxStaticText::SetHeight(int lines)
|
||||
{
|
||||
if (!pxAssert(lines > 0))
|
||||
lines = 2;
|
||||
m_heightInLines = lines;
|
||||
if (!pxAssert(lines > 0))
|
||||
lines = 2;
|
||||
m_heightInLines = lines;
|
||||
|
||||
const int newHeight = (pxGetCharHeight(this) * m_heightInLines) + (m_paddingPix_vert * 2);
|
||||
SetMinSize(wxSize(GetMinWidth(), newHeight));
|
||||
const int newHeight = (pxGetCharHeight(this) * m_heightInLines) + (m_paddingPix_vert * 2);
|
||||
SetMinSize(wxSize(GetMinWidth(), newHeight));
|
||||
|
||||
return *this;
|
||||
return *this;
|
||||
}
|
||||
|
||||
pxStaticText &pxStaticText::Align(wxAlignment align)
|
||||
pxStaticText& pxStaticText::Align(wxAlignment align)
|
||||
{
|
||||
m_align = align;
|
||||
return *this;
|
||||
m_align = align;
|
||||
return *this;
|
||||
}
|
||||
|
||||
pxStaticText &pxStaticText::Bold()
|
||||
pxStaticText& pxStaticText::Bold()
|
||||
{
|
||||
wxFont bold(GetFont());
|
||||
bold.SetWeight(wxFONTWEIGHT_BOLD);
|
||||
SetFont(bold);
|
||||
return *this;
|
||||
wxFont bold(GetFont());
|
||||
bold.SetWeight(wxFONTWEIGHT_BOLD);
|
||||
SetFont(bold);
|
||||
return *this;
|
||||
}
|
||||
|
||||
pxStaticText &pxStaticText::PaddingPixH(int pixels)
|
||||
pxStaticText& pxStaticText::PaddingPixH(int pixels)
|
||||
{
|
||||
m_paddingPix_horiz = pixels;
|
||||
UpdateWrapping(false);
|
||||
Refresh();
|
||||
return *this;
|
||||
m_paddingPix_horiz = pixels;
|
||||
UpdateWrapping(false);
|
||||
Refresh();
|
||||
return *this;
|
||||
}
|
||||
|
||||
pxStaticText &pxStaticText::PaddingPixV(int pixels)
|
||||
pxStaticText& pxStaticText::PaddingPixV(int pixels)
|
||||
{
|
||||
m_paddingPix_vert = pixels;
|
||||
Refresh();
|
||||
return *this;
|
||||
m_paddingPix_vert = pixels;
|
||||
Refresh();
|
||||
return *this;
|
||||
}
|
||||
|
||||
pxStaticText &pxStaticText::PaddingPctH(float pct)
|
||||
pxStaticText& pxStaticText::PaddingPctH(float pct)
|
||||
{
|
||||
pxAssert(pct < 0.5);
|
||||
pxAssert(pct < 0.5);
|
||||
|
||||
m_paddingPct_horiz = pct;
|
||||
UpdateWrapping(false);
|
||||
Refresh();
|
||||
return *this;
|
||||
m_paddingPct_horiz = pct;
|
||||
UpdateWrapping(false);
|
||||
Refresh();
|
||||
return *this;
|
||||
}
|
||||
|
||||
pxStaticText &pxStaticText::PaddingPctV(float pct)
|
||||
pxStaticText& pxStaticText::PaddingPctV(float pct)
|
||||
{
|
||||
pxAssert(pct < 0.5);
|
||||
pxAssert(pct < 0.5);
|
||||
|
||||
m_paddingPct_vert = pct;
|
||||
Refresh();
|
||||
return *this;
|
||||
m_paddingPct_vert = pct;
|
||||
Refresh();
|
||||
return *this;
|
||||
}
|
||||
|
||||
pxStaticText &pxStaticText::Unwrapped()
|
||||
pxStaticText& pxStaticText::Unwrapped()
|
||||
{
|
||||
m_autowrap = false;
|
||||
UpdateWrapping(false);
|
||||
return *this;
|
||||
m_autowrap = false;
|
||||
UpdateWrapping(false);
|
||||
return *this;
|
||||
}
|
||||
|
||||
int pxStaticText::calcPaddingWidth(int newWidth) const
|
||||
{
|
||||
return (int)(newWidth * m_paddingPct_horiz * 2) + (m_paddingPix_horiz * 2);
|
||||
return (int)(newWidth * m_paddingPct_horiz * 2) + (m_paddingPix_horiz * 2);
|
||||
}
|
||||
|
||||
int pxStaticText::calcPaddingHeight(int newHeight) const
|
||||
{
|
||||
return (int)(newHeight * m_paddingPct_vert * 2) + (m_paddingPix_vert * 2);
|
||||
return (int)(newHeight * m_paddingPct_vert * 2) + (m_paddingPix_vert * 2);
|
||||
}
|
||||
|
||||
wxSize pxStaticText::GetBestWrappedSize(const wxClientDC &dc) const
|
||||
wxSize pxStaticText::GetBestWrappedSize(const wxClientDC& dc) const
|
||||
{
|
||||
pxAssert(m_autowrap);
|
||||
pxAssert(m_autowrap);
|
||||
|
||||
// Find an ideal(-ish) width, based on a search of all parent controls and their
|
||||
// valid Minimum sizes.
|
||||
// Find an ideal(-ish) width, based on a search of all parent controls and their
|
||||
// valid Minimum sizes.
|
||||
|
||||
int idealWidth = wxDefaultCoord;
|
||||
int parentalAdjust = 0;
|
||||
double parentalFactor = 1.0;
|
||||
const wxWindow *millrun = this;
|
||||
int idealWidth = wxDefaultCoord;
|
||||
int parentalAdjust = 0;
|
||||
double parentalFactor = 1.0;
|
||||
const wxWindow* millrun = this;
|
||||
|
||||
while (millrun) {
|
||||
// IMPORTANT : wxWizard changes its min size and then expects everything else
|
||||
// to play nice and NOT resize according to the new min size. (wtf stupid)
|
||||
// Anyway, this fixes it -- ignore min size specifier on wxWizard!
|
||||
if (wxIsKindOf(millrun, wxWizard))
|
||||
break;
|
||||
while (millrun)
|
||||
{
|
||||
// IMPORTANT : wxWizard changes its min size and then expects everything else
|
||||
// to play nice and NOT resize according to the new min size. (wtf stupid)
|
||||
// Anyway, this fixes it -- ignore min size specifier on wxWizard!
|
||||
if (wxIsKindOf(millrun, wxWizard))
|
||||
break;
|
||||
|
||||
int min = (int)((millrun->GetMinWidth() - parentalAdjust) * parentalFactor);
|
||||
int min = (int)((millrun->GetMinWidth() - parentalAdjust) * parentalFactor);
|
||||
|
||||
if (min > 0 && ((idealWidth < 0) || (min < idealWidth))) {
|
||||
idealWidth = min;
|
||||
}
|
||||
if (min > 0 && ((idealWidth < 0) || (min < idealWidth)))
|
||||
{
|
||||
idealWidth = min;
|
||||
}
|
||||
|
||||
parentalAdjust += pxSizerFlags::StdPadding * 2;
|
||||
millrun = millrun->GetParent();
|
||||
}
|
||||
parentalAdjust += pxSizerFlags::StdPadding * 2;
|
||||
millrun = millrun->GetParent();
|
||||
}
|
||||
|
||||
if (idealWidth <= 0) {
|
||||
// FIXME: The minimum size of this control is unknown, so let's just pick a guess based on
|
||||
// the size of the user's display area.
|
||||
if (idealWidth <= 0)
|
||||
{
|
||||
// FIXME: The minimum size of this control is unknown, so let's just pick a guess based on
|
||||
// the size of the user's display area.
|
||||
|
||||
idealWidth = (int)(wxGetDisplaySize().GetWidth() * 0.66) - (parentalAdjust * 2);
|
||||
}
|
||||
idealWidth = (int)(wxGetDisplaySize().GetWidth() * 0.66) - (parentalAdjust * 2);
|
||||
}
|
||||
|
||||
return dc.GetMultiLineTextExtent(pxTextWrapper().Wrap(this, m_label, idealWidth - calcPaddingWidth(idealWidth)).GetResult());
|
||||
return dc.GetMultiLineTextExtent(pxTextWrapper().Wrap(this, m_label, idealWidth - calcPaddingWidth(idealWidth)).GetResult());
|
||||
}
|
||||
|
||||
pxStaticText &pxStaticText::WrapAt(int width)
|
||||
pxStaticText& pxStaticText::WrapAt(int width)
|
||||
{
|
||||
m_autowrap = false;
|
||||
m_autowrap = false;
|
||||
|
||||
if ((width <= 1) || (width == m_wrappedWidth))
|
||||
return *this;
|
||||
if ((width <= 1) || (width == m_wrappedWidth))
|
||||
return *this;
|
||||
|
||||
wxString wrappedLabel;
|
||||
m_wrappedWidth = width;
|
||||
wxString wrappedLabel;
|
||||
m_wrappedWidth = width;
|
||||
|
||||
if (width > 1)
|
||||
wrappedLabel = pxTextWrapper().Wrap(this, m_label, width).GetResult();
|
||||
if (width > 1)
|
||||
wrappedLabel = pxTextWrapper().Wrap(this, m_label, width).GetResult();
|
||||
|
||||
if (m_wrappedLabel != wrappedLabel) {
|
||||
m_wrappedLabel = wrappedLabel;
|
||||
wxSize area = wxClientDC(this).GetMultiLineTextExtent(m_wrappedLabel);
|
||||
SetMinSize(wxSize(
|
||||
area.GetWidth() + calcPaddingWidth(area.GetWidth()),
|
||||
area.GetHeight() + calcPaddingHeight(area.GetHeight())));
|
||||
}
|
||||
return *this;
|
||||
if (m_wrappedLabel != wrappedLabel)
|
||||
{
|
||||
m_wrappedLabel = wrappedLabel;
|
||||
wxSize area = wxClientDC(this).GetMultiLineTextExtent(m_wrappedLabel);
|
||||
SetMinSize(wxSize(
|
||||
area.GetWidth() + calcPaddingWidth(area.GetWidth()),
|
||||
area.GetHeight() + calcPaddingHeight(area.GetHeight())));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool pxStaticText::_updateWrapping(bool textChanged)
|
||||
{
|
||||
if (!m_autowrap) {
|
||||
//m_wrappedLabel = wxEmptyString;
|
||||
//m_wrappedWidth = -1;
|
||||
return false;
|
||||
}
|
||||
if (!m_autowrap)
|
||||
{
|
||||
//m_wrappedLabel = wxEmptyString;
|
||||
//m_wrappedWidth = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
wxString wrappedLabel;
|
||||
int newWidth = GetSize().GetWidth();
|
||||
wxString wrappedLabel;
|
||||
int newWidth = GetSize().GetWidth();
|
||||
|
||||
if (!textChanged && (newWidth == m_wrappedWidth))
|
||||
return false;
|
||||
if (!textChanged && (newWidth == m_wrappedWidth))
|
||||
return false;
|
||||
|
||||
// Note: during various stages of sizer-calc, width can be 1, 0, or -1.
|
||||
// We ignore wrapping in these cases. (the PaintEvent also checks the wrapping
|
||||
// and updates it if needed, in case the control's size isn't figured out prior
|
||||
// to being painted).
|
||||
// Note: during various stages of sizer-calc, width can be 1, 0, or -1.
|
||||
// We ignore wrapping in these cases. (the PaintEvent also checks the wrapping
|
||||
// and updates it if needed, in case the control's size isn't figured out prior
|
||||
// to being painted).
|
||||
|
||||
m_wrappedWidth = newWidth;
|
||||
if (m_wrappedWidth > 1)
|
||||
wrappedLabel = pxTextWrapper().Wrap(this, m_label, m_wrappedWidth).GetResult();
|
||||
m_wrappedWidth = newWidth;
|
||||
if (m_wrappedWidth > 1)
|
||||
wrappedLabel = pxTextWrapper().Wrap(this, m_label, m_wrappedWidth).GetResult();
|
||||
|
||||
if (m_wrappedLabel == wrappedLabel)
|
||||
return false;
|
||||
m_wrappedLabel = wrappedLabel;
|
||||
if (m_wrappedLabel == wrappedLabel)
|
||||
return false;
|
||||
m_wrappedLabel = wrappedLabel;
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void pxStaticText::UpdateWrapping(bool textChanged)
|
||||
{
|
||||
if (_updateWrapping(textChanged))
|
||||
Refresh();
|
||||
if (_updateWrapping(textChanged))
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void pxStaticText::SetLabel(const wxString &label)
|
||||
void pxStaticText::SetLabel(const wxString& label)
|
||||
{
|
||||
const bool labelChanged(label != m_label);
|
||||
if (labelChanged) {
|
||||
m_label = label;
|
||||
Refresh();
|
||||
}
|
||||
const bool labelChanged(label != m_label);
|
||||
if (labelChanged)
|
||||
{
|
||||
m_label = label;
|
||||
Refresh();
|
||||
}
|
||||
|
||||
// Always update wrapping, in case window width or something else also changed.
|
||||
UpdateWrapping(labelChanged);
|
||||
InvalidateBestSize();
|
||||
// Always update wrapping, in case window width or something else also changed.
|
||||
UpdateWrapping(labelChanged);
|
||||
InvalidateBestSize();
|
||||
}
|
||||
|
||||
wxFont pxStaticText::GetFontOk() const
|
||||
{
|
||||
wxFont font(GetFont());
|
||||
if (!font.Ok())
|
||||
return wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
|
||||
return font;
|
||||
wxFont font(GetFont());
|
||||
if (!font.Ok())
|
||||
return wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
|
||||
return font;
|
||||
}
|
||||
|
||||
bool pxStaticText::Enable(bool enabled)
|
||||
{
|
||||
if (_parent::Enable(enabled)) {
|
||||
Refresh();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
if (_parent::Enable(enabled))
|
||||
{
|
||||
Refresh();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void pxStaticText::paintEvent(wxPaintEvent &evt)
|
||||
void pxStaticText::paintEvent(wxPaintEvent& evt)
|
||||
{
|
||||
wxPaintDC dc(this);
|
||||
const int dcWidth = dc.GetSize().GetWidth();
|
||||
const int dcHeight = dc.GetSize().GetHeight();
|
||||
if (dcWidth < 1)
|
||||
return;
|
||||
dc.SetFont(GetFontOk());
|
||||
wxPaintDC dc(this);
|
||||
const int dcWidth = dc.GetSize().GetWidth();
|
||||
const int dcHeight = dc.GetSize().GetHeight();
|
||||
if (dcWidth < 1)
|
||||
return;
|
||||
dc.SetFont(GetFontOk());
|
||||
|
||||
if (IsEnabled())
|
||||
dc.SetTextForeground(GetForegroundColour());
|
||||
else
|
||||
dc.SetTextForeground(*wxLIGHT_GREY);
|
||||
if (IsEnabled())
|
||||
dc.SetTextForeground(GetForegroundColour());
|
||||
else
|
||||
dc.SetTextForeground(*wxLIGHT_GREY);
|
||||
|
||||
pxWindowTextWriter writer(dc);
|
||||
writer.Align(m_align);
|
||||
pxWindowTextWriter writer(dc);
|
||||
writer.Align(m_align);
|
||||
|
||||
const wxString &label(m_autowrap ? m_wrappedLabel : m_label);
|
||||
if (m_autowrap)
|
||||
_updateWrapping(false);
|
||||
const wxString& label(m_autowrap ? m_wrappedLabel : m_label);
|
||||
if (m_autowrap)
|
||||
_updateWrapping(false);
|
||||
|
||||
int tWidth, tHeight;
|
||||
dc.GetMultiLineTextExtent(label, &tWidth, &tHeight);
|
||||
int tWidth, tHeight;
|
||||
dc.GetMultiLineTextExtent(label, &tWidth, &tHeight);
|
||||
|
||||
writer.Align(m_align);
|
||||
if (m_align & wxALIGN_CENTER_VERTICAL)
|
||||
writer.SetY((dcHeight - tHeight) / 2);
|
||||
else
|
||||
writer.SetY((int)(dcHeight * m_paddingPct_vert) + m_paddingPix_vert);
|
||||
writer.Align(m_align);
|
||||
if (m_align & wxALIGN_CENTER_VERTICAL)
|
||||
writer.SetY((dcHeight - tHeight) / 2);
|
||||
else
|
||||
writer.SetY((int)(dcHeight * m_paddingPct_vert) + m_paddingPix_vert);
|
||||
|
||||
writer.WriteLn(label); // without formatting please.
|
||||
writer.WriteLn(label); // without formatting please.
|
||||
|
||||
//dc.SetBrush( *wxTRANSPARENT_BRUSH );
|
||||
//dc.DrawRectangle(wxPoint(), dc.GetSize());
|
||||
//dc.SetBrush( *wxTRANSPARENT_BRUSH );
|
||||
//dc.DrawRectangle(wxPoint(), dc.GetSize());
|
||||
}
|
||||
|
||||
// Overloaded form wxPanel and friends.
|
||||
wxSize pxStaticText::DoGetBestSize() const
|
||||
{
|
||||
wxClientDC dc(const_cast<pxStaticText *>(this));
|
||||
dc.SetFont(GetFontOk());
|
||||
wxClientDC dc(const_cast<pxStaticText*>(this));
|
||||
dc.SetFont(GetFontOk());
|
||||
|
||||
wxSize best;
|
||||
wxSize best;
|
||||
|
||||
if (m_autowrap) {
|
||||
best = GetBestWrappedSize(dc);
|
||||
//best.x = wxDefaultCoord;
|
||||
} else {
|
||||
// No autowrapping, so we can force a specific size here!
|
||||
best = dc.GetMultiLineTextExtent(GetLabel());
|
||||
best.x += calcPaddingWidth(best.x);
|
||||
}
|
||||
if (m_autowrap)
|
||||
{
|
||||
best = GetBestWrappedSize(dc);
|
||||
//best.x = wxDefaultCoord;
|
||||
}
|
||||
else
|
||||
{
|
||||
// No autowrapping, so we can force a specific size here!
|
||||
best = dc.GetMultiLineTextExtent(GetLabel());
|
||||
best.x += calcPaddingWidth(best.x);
|
||||
}
|
||||
|
||||
best.y += calcPaddingHeight(best.y);
|
||||
best.y += calcPaddingHeight(best.y);
|
||||
|
||||
CacheBestSize(best);
|
||||
return best;
|
||||
CacheBestSize(best);
|
||||
return best;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// pxStaticHeading (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
pxStaticHeading::pxStaticHeading(wxWindow *parent, const wxString &label)
|
||||
: _parent(parent)
|
||||
pxStaticHeading::pxStaticHeading(wxWindow* parent, const wxString& label)
|
||||
: _parent(parent)
|
||||
{
|
||||
m_align = wxALIGN_CENTER;
|
||||
m_align = wxALIGN_CENTER;
|
||||
|
||||
SetPaddingDefaults();
|
||||
Init(label);
|
||||
SetPaddingDefaults();
|
||||
Init(label);
|
||||
}
|
||||
|
||||
void pxStaticHeading::SetPaddingDefaults()
|
||||
{
|
||||
m_paddingPix_horiz = 4;
|
||||
m_paddingPix_vert = 1;
|
||||
m_paddingPix_horiz = 4;
|
||||
m_paddingPix_vert = 1;
|
||||
|
||||
m_paddingPct_horiz = 0.08f;
|
||||
m_paddingPct_vert = 0.0f;
|
||||
m_paddingPct_horiz = 0.08f;
|
||||
m_paddingPct_vert = 0.0f;
|
||||
}
|
||||
|
||||
void operator+=(wxSizer &target, pxStaticText *src)
|
||||
void operator+=(wxSizer& target, pxStaticText* src)
|
||||
{
|
||||
if (src)
|
||||
target.Add(src, pxExpand);
|
||||
if (src)
|
||||
target.Add(src, pxExpand);
|
||||
}
|
||||
|
||||
void operator+=(wxSizer &target, pxStaticText &src)
|
||||
void operator+=(wxSizer& target, pxStaticText& src)
|
||||
{
|
||||
target.Add(&src, pxExpand);
|
||||
target.Add(&src, pxExpand);
|
||||
}
|
||||
|
||||
void operator+=(wxSizer *target, pxStaticText &src)
|
||||
void operator+=(wxSizer* target, pxStaticText& src)
|
||||
{
|
||||
target->Add(&src, pxExpand);
|
||||
target->Add(&src, pxExpand);
|
||||
}
|
||||
|
|
|
@ -34,92 +34,92 @@
|
|||
//
|
||||
class pxStaticText : public wxControl
|
||||
{
|
||||
typedef wxControl _parent;
|
||||
typedef wxControl _parent;
|
||||
|
||||
protected:
|
||||
wxString m_label;
|
||||
wxString m_wrappedLabel;
|
||||
wxString m_label;
|
||||
wxString m_wrappedLabel;
|
||||
|
||||
wxAlignment m_align;
|
||||
bool m_autowrap;
|
||||
int m_wrappedWidth;
|
||||
int m_heightInLines;
|
||||
wxAlignment m_align;
|
||||
bool m_autowrap;
|
||||
int m_wrappedWidth;
|
||||
int m_heightInLines;
|
||||
|
||||
int m_paddingPix_horiz;
|
||||
int m_paddingPix_vert;
|
||||
float m_paddingPct_horiz;
|
||||
float m_paddingPct_vert;
|
||||
int m_paddingPix_horiz;
|
||||
int m_paddingPix_vert;
|
||||
float m_paddingPct_horiz;
|
||||
float m_paddingPct_vert;
|
||||
|
||||
protected:
|
||||
explicit pxStaticText(wxWindow *parent = NULL);
|
||||
explicit pxStaticText(wxWindow* parent = NULL);
|
||||
|
||||
// wxWindow overloads!
|
||||
bool AcceptsFocus() const { return false; }
|
||||
bool HasTransparentBackground() { return true; }
|
||||
void DoSetSize(int x, int y, int w, int h, int sizeFlags = wxSIZE_AUTO);
|
||||
// wxWindow overloads!
|
||||
bool AcceptsFocus() const { return false; }
|
||||
bool HasTransparentBackground() { return true; }
|
||||
void DoSetSize(int x, int y, int w, int h, int sizeFlags = wxSIZE_AUTO);
|
||||
|
||||
public:
|
||||
pxStaticText(wxWindow *parent, const wxString &label, wxAlignment align = wxALIGN_CENTRE_HORIZONTAL);
|
||||
pxStaticText(wxWindow *parent, int heightInLines, const wxString &label, wxAlignment align = wxALIGN_CENTRE_HORIZONTAL);
|
||||
virtual ~pxStaticText() = default;
|
||||
pxStaticText(wxWindow* parent, const wxString& label, wxAlignment align = wxALIGN_CENTRE_HORIZONTAL);
|
||||
pxStaticText(wxWindow* parent, int heightInLines, const wxString& label, wxAlignment align = wxALIGN_CENTRE_HORIZONTAL);
|
||||
virtual ~pxStaticText() = default;
|
||||
|
||||
wxFont GetFontOk() const;
|
||||
bool Enable(bool enabled = true);
|
||||
wxFont GetFontOk() const;
|
||||
bool Enable(bool enabled = true);
|
||||
|
||||
virtual void SetLabel(const wxString &label);
|
||||
virtual wxString GetLabel() const { return m_label; }
|
||||
virtual void SetLabel(const wxString& label);
|
||||
virtual wxString GetLabel() const { return m_label; }
|
||||
|
||||
pxStaticText &SetMinWidth(int width);
|
||||
pxStaticText &SetMinHeight(int height);
|
||||
pxStaticText& SetMinWidth(int width);
|
||||
pxStaticText& SetMinHeight(int height);
|
||||
|
||||
pxStaticText &SetHeight(int lines);
|
||||
pxStaticText &Align(wxAlignment align);
|
||||
pxStaticText &Bold();
|
||||
pxStaticText &WrapAt(int width);
|
||||
pxStaticText& SetHeight(int lines);
|
||||
pxStaticText& Align(wxAlignment align);
|
||||
pxStaticText& Bold();
|
||||
pxStaticText& WrapAt(int width);
|
||||
|
||||
pxStaticText &Unwrapped();
|
||||
pxStaticText& Unwrapped();
|
||||
|
||||
pxStaticText &PaddingPixH(int pixels);
|
||||
pxStaticText &PaddingPixV(int pixels);
|
||||
pxStaticText& PaddingPixH(int pixels);
|
||||
pxStaticText& PaddingPixV(int pixels);
|
||||
|
||||
pxStaticText &PaddingPctH(float pct);
|
||||
pxStaticText &PaddingPctV(float pct);
|
||||
//pxStaticText& DoBestGuessHeight();
|
||||
pxStaticText& PaddingPctH(float pct);
|
||||
pxStaticText& PaddingPctV(float pct);
|
||||
//pxStaticText& DoBestGuessHeight();
|
||||
|
||||
protected:
|
||||
void SetPaddingDefaults();
|
||||
void Init(const wxString &label);
|
||||
void SetPaddingDefaults();
|
||||
void Init(const wxString& label);
|
||||
|
||||
wxSize GetBestWrappedSize(const wxClientDC &dc) const;
|
||||
wxSize DoGetBestSize() const;
|
||||
wxSize GetBestWrappedSize(const wxClientDC& dc) const;
|
||||
wxSize DoGetBestSize() const;
|
||||
|
||||
int calcPaddingWidth(int newWidth) const;
|
||||
int calcPaddingHeight(int newHeight) const;
|
||||
int calcPaddingWidth(int newWidth) const;
|
||||
int calcPaddingHeight(int newHeight) const;
|
||||
|
||||
void paintEvent(wxPaintEvent &evt);
|
||||
void paintEvent(wxPaintEvent& evt);
|
||||
|
||||
void UpdateWrapping(bool textChanged);
|
||||
bool _updateWrapping(bool textChanged);
|
||||
void UpdateWrapping(bool textChanged);
|
||||
bool _updateWrapping(bool textChanged);
|
||||
};
|
||||
|
||||
|
||||
class pxStaticHeading : public pxStaticText
|
||||
{
|
||||
typedef pxStaticText _parent;
|
||||
typedef pxStaticText _parent;
|
||||
|
||||
public:
|
||||
pxStaticHeading(wxWindow *parent = NULL, const wxString &label = wxEmptyString);
|
||||
pxStaticHeading(wxWindow *parent, int heightInLines, const wxString &label = wxEmptyString);
|
||||
virtual ~pxStaticHeading() = default;
|
||||
pxStaticHeading(wxWindow* parent = NULL, const wxString& label = wxEmptyString);
|
||||
pxStaticHeading(wxWindow* parent, int heightInLines, const wxString& label = wxEmptyString);
|
||||
virtual ~pxStaticHeading() = default;
|
||||
|
||||
protected:
|
||||
void SetPaddingDefaults();
|
||||
void SetPaddingDefaults();
|
||||
};
|
||||
|
||||
extern void operator+=(wxSizer &target, pxStaticText &src);
|
||||
extern void operator+=(wxSizer& target, pxStaticText& src);
|
||||
|
||||
template <>
|
||||
inline void operator+=(wxSizer &target, const pxWindowAndFlags<pxStaticText> &src)
|
||||
inline void operator+=(wxSizer& target, const pxWindowAndFlags<pxStaticText>& src)
|
||||
{
|
||||
target.Add(src.window, src.flags);
|
||||
target.Add(src.window, src.flags);
|
||||
}
|
||||
|
|
|
@ -23,22 +23,22 @@
|
|||
// --------------------------------------------------------------------------------------
|
||||
// pxStreamBase (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
pxStreamBase::pxStreamBase(const wxString &filename)
|
||||
: m_filename(filename)
|
||||
pxStreamBase::pxStreamBase(const wxString& filename)
|
||||
: m_filename(filename)
|
||||
{
|
||||
}
|
||||
|
||||
bool pxStreamBase::IsOk() const
|
||||
{
|
||||
wxStreamBase *woot = GetWxStreamBase();
|
||||
return woot && woot->IsOk();
|
||||
wxStreamBase* woot = GetWxStreamBase();
|
||||
return woot && woot->IsOk();
|
||||
}
|
||||
|
||||
wxFileOffset pxStreamBase::Length() const
|
||||
{
|
||||
if (!GetWxStreamBase())
|
||||
return 0;
|
||||
return GetWxStreamBase()->GetLength();
|
||||
if (!GetWxStreamBase())
|
||||
return 0;
|
||||
return GetWxStreamBase()->GetLength();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -47,115 +47,117 @@ wxFileOffset pxStreamBase::Length() const
|
|||
// Interface for reading data from a gzip stream.
|
||||
//
|
||||
|
||||
pxInputStream::pxInputStream(const wxString &filename, std::unique_ptr<wxInputStream> &input)
|
||||
: pxStreamBase(filename)
|
||||
, m_stream_in(std::move(input))
|
||||
pxInputStream::pxInputStream(const wxString& filename, std::unique_ptr<wxInputStream>& input)
|
||||
: pxStreamBase(filename)
|
||||
, m_stream_in(std::move(input))
|
||||
{
|
||||
}
|
||||
|
||||
pxInputStream::pxInputStream(const wxString &filename, wxInputStream *input)
|
||||
: pxStreamBase(filename)
|
||||
, m_stream_in(input)
|
||||
pxInputStream::pxInputStream(const wxString& filename, wxInputStream* input)
|
||||
: pxStreamBase(filename)
|
||||
, m_stream_in(input)
|
||||
{
|
||||
}
|
||||
|
||||
wxStreamBase *pxInputStream::GetWxStreamBase() const { return m_stream_in.get(); }
|
||||
wxStreamBase* pxInputStream::GetWxStreamBase() const { return m_stream_in.get(); }
|
||||
|
||||
wxFileOffset pxInputStream::Tell() const
|
||||
{
|
||||
return m_stream_in->TellI();
|
||||
return m_stream_in->TellI();
|
||||
}
|
||||
|
||||
wxFileOffset pxInputStream::Seek(wxFileOffset ofs, wxSeekMode mode)
|
||||
{
|
||||
return m_stream_in->SeekI(ofs, mode);
|
||||
return m_stream_in->SeekI(ofs, mode);
|
||||
}
|
||||
|
||||
void pxInputStream::SetStream(const wxString &filename, std::unique_ptr<wxInputStream> &stream)
|
||||
void pxInputStream::SetStream(const wxString& filename, std::unique_ptr<wxInputStream>& stream)
|
||||
{
|
||||
m_filename = filename;
|
||||
m_stream_in = std::move(stream);
|
||||
m_filename = filename;
|
||||
m_stream_in = std::move(stream);
|
||||
}
|
||||
|
||||
void pxInputStream::SetStream(const wxString &filename, wxInputStream *stream)
|
||||
void pxInputStream::SetStream(const wxString& filename, wxInputStream* stream)
|
||||
{
|
||||
m_filename = filename;
|
||||
m_stream_in = std::unique_ptr<wxInputStream>(stream);
|
||||
m_filename = filename;
|
||||
m_stream_in = std::unique_ptr<wxInputStream>(stream);
|
||||
}
|
||||
|
||||
void pxInputStream::Read(void *dest, size_t size)
|
||||
void pxInputStream::Read(void* dest, size_t size)
|
||||
{
|
||||
m_stream_in->Read(dest, size);
|
||||
if (m_stream_in->GetLastError() == wxSTREAM_READ_ERROR) {
|
||||
int err = errno;
|
||||
if (!err)
|
||||
throw Exception::BadStream(m_filename).SetDiagMsg(L"Cannot read from file (bad file handle?)");
|
||||
m_stream_in->Read(dest, size);
|
||||
if (m_stream_in->GetLastError() == wxSTREAM_READ_ERROR)
|
||||
{
|
||||
int err = errno;
|
||||
if (!err)
|
||||
throw Exception::BadStream(m_filename).SetDiagMsg(L"Cannot read from file (bad file handle?)");
|
||||
|
||||
ScopedExcept ex(Exception::FromErrno(m_filename, err));
|
||||
ex->SetDiagMsg(L"cannot read from file: " + ex->DiagMsg());
|
||||
ex->Rethrow();
|
||||
}
|
||||
ScopedExcept ex(Exception::FromErrno(m_filename, err));
|
||||
ex->SetDiagMsg(L"cannot read from file: " + ex->DiagMsg());
|
||||
ex->Rethrow();
|
||||
}
|
||||
|
||||
// IMPORTANT! The underlying file/source Eof() stuff is not really reliable, so we
|
||||
// must always use the explicit check against the number of bytes read to determine
|
||||
// end-of-stream conditions.
|
||||
// IMPORTANT! The underlying file/source Eof() stuff is not really reliable, so we
|
||||
// must always use the explicit check against the number of bytes read to determine
|
||||
// end-of-stream conditions.
|
||||
|
||||
if ((size_t)m_stream_in->LastRead() < size)
|
||||
throw Exception::EndOfStream(m_filename);
|
||||
if ((size_t)m_stream_in->LastRead() < size)
|
||||
throw Exception::EndOfStream(m_filename);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// pxOutputStream
|
||||
// --------------------------------------------------------------------------------------
|
||||
pxOutputStream::pxOutputStream(const wxString &filename, std::unique_ptr<wxOutputStream> &output)
|
||||
: pxStreamBase(filename)
|
||||
, m_stream_out(std::move(output))
|
||||
pxOutputStream::pxOutputStream(const wxString& filename, std::unique_ptr<wxOutputStream>& output)
|
||||
: pxStreamBase(filename)
|
||||
, m_stream_out(std::move(output))
|
||||
{
|
||||
}
|
||||
|
||||
pxOutputStream::pxOutputStream(const wxString &filename, wxOutputStream *output)
|
||||
: pxStreamBase(filename)
|
||||
, m_stream_out(output)
|
||||
pxOutputStream::pxOutputStream(const wxString& filename, wxOutputStream* output)
|
||||
: pxStreamBase(filename)
|
||||
, m_stream_out(output)
|
||||
{
|
||||
}
|
||||
|
||||
wxStreamBase *pxOutputStream::GetWxStreamBase() const { return m_stream_out.get(); }
|
||||
wxStreamBase* pxOutputStream::GetWxStreamBase() const { return m_stream_out.get(); }
|
||||
|
||||
wxFileOffset pxOutputStream::Tell() const
|
||||
{
|
||||
return m_stream_out->TellO();
|
||||
return m_stream_out->TellO();
|
||||
}
|
||||
|
||||
wxFileOffset pxOutputStream::Seek(wxFileOffset ofs, wxSeekMode mode)
|
||||
{
|
||||
return m_stream_out->SeekO(ofs, mode);
|
||||
return m_stream_out->SeekO(ofs, mode);
|
||||
}
|
||||
|
||||
void pxOutputStream::SetStream(const wxString &filename, std::unique_ptr<wxOutputStream> &stream)
|
||||
void pxOutputStream::SetStream(const wxString& filename, std::unique_ptr<wxOutputStream>& stream)
|
||||
{
|
||||
m_filename = filename;
|
||||
m_stream_out = std::move(stream);
|
||||
m_filename = filename;
|
||||
m_stream_out = std::move(stream);
|
||||
}
|
||||
|
||||
void pxOutputStream::SetStream(const wxString &filename, wxOutputStream *stream)
|
||||
void pxOutputStream::SetStream(const wxString& filename, wxOutputStream* stream)
|
||||
{
|
||||
m_filename = filename;
|
||||
m_stream_out = std::unique_ptr<wxOutputStream>(stream);
|
||||
m_filename = filename;
|
||||
m_stream_out = std::unique_ptr<wxOutputStream>(stream);
|
||||
}
|
||||
|
||||
|
||||
void pxOutputStream::Write(const void *src, size_t size)
|
||||
void pxOutputStream::Write(const void* src, size_t size)
|
||||
{
|
||||
m_stream_out->Write(src, size);
|
||||
if (m_stream_out->GetLastError() == wxSTREAM_WRITE_ERROR) {
|
||||
int err = errno;
|
||||
if (!err)
|
||||
throw Exception::BadStream(m_filename).SetDiagMsg(L"Cannot write to file/stream.");
|
||||
m_stream_out->Write(src, size);
|
||||
if (m_stream_out->GetLastError() == wxSTREAM_WRITE_ERROR)
|
||||
{
|
||||
int err = errno;
|
||||
if (!err)
|
||||
throw Exception::BadStream(m_filename).SetDiagMsg(L"Cannot write to file/stream.");
|
||||
|
||||
ScopedExcept ex(Exception::FromErrno(m_filename, err));
|
||||
ex->SetDiagMsg(L"Cannot write to file: " + ex->DiagMsg());
|
||||
ex->Rethrow();
|
||||
}
|
||||
ScopedExcept ex(Exception::FromErrno(m_filename, err));
|
||||
ex->SetDiagMsg(L"Cannot write to file: " + ex->DiagMsg());
|
||||
ex->Rethrow();
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -163,89 +165,93 @@ void pxOutputStream::Write(const void *src, size_t size)
|
|||
// --------------------------------------------------------------------------------------
|
||||
|
||||
// Returns TRUE if the source is UTF8, or FALSE if it's just ASCII crap.
|
||||
bool pxReadLine(wxInputStream &input, std::string &dest)
|
||||
bool pxReadLine(wxInputStream& input, std::string& dest)
|
||||
{
|
||||
dest.clear();
|
||||
bool isUTF8 = false;
|
||||
while (true) {
|
||||
char c;
|
||||
input.Read(&c, sizeof(c));
|
||||
if (c == 0)
|
||||
break;
|
||||
if (input.Eof())
|
||||
break;
|
||||
if (c == '\n')
|
||||
break; // eat on UNIX
|
||||
if (c == '\r') {
|
||||
input.Read(&c, sizeof(c));
|
||||
if (c == 0)
|
||||
break;
|
||||
if (input.Eof())
|
||||
break;
|
||||
if (c == '\n')
|
||||
break;
|
||||
dest.clear();
|
||||
bool isUTF8 = false;
|
||||
while (true)
|
||||
{
|
||||
char c;
|
||||
input.Read(&c, sizeof(c));
|
||||
if (c == 0)
|
||||
break;
|
||||
if (input.Eof())
|
||||
break;
|
||||
if (c == '\n')
|
||||
break; // eat on UNIX
|
||||
if (c == '\r')
|
||||
{
|
||||
input.Read(&c, sizeof(c));
|
||||
if (c == 0)
|
||||
break;
|
||||
if (input.Eof())
|
||||
break;
|
||||
if (c == '\n')
|
||||
break;
|
||||
|
||||
input.Ungetch(c);
|
||||
break;
|
||||
}
|
||||
dest += c;
|
||||
if (c & 0x80)
|
||||
isUTF8 = true;
|
||||
}
|
||||
input.Ungetch(c);
|
||||
break;
|
||||
}
|
||||
dest += c;
|
||||
if (c & 0x80)
|
||||
isUTF8 = true;
|
||||
}
|
||||
|
||||
return isUTF8;
|
||||
return isUTF8;
|
||||
}
|
||||
|
||||
void pxReadLine(wxInputStream &input, wxString &dest, std::string &intermed)
|
||||
void pxReadLine(wxInputStream& input, wxString& dest, std::string& intermed)
|
||||
{
|
||||
dest.clear();
|
||||
if (pxReadLine(input, intermed))
|
||||
dest = fromUTF8(intermed.c_str());
|
||||
else {
|
||||
// Optimized ToAscii conversion.
|
||||
// wx3.0 : NOT COMPATIBLE!! (on linux anyway)
|
||||
const char *ascii = intermed.c_str();
|
||||
while (*ascii != 0)
|
||||
dest += (wchar_t)(unsigned char)*ascii++;
|
||||
}
|
||||
dest.clear();
|
||||
if (pxReadLine(input, intermed))
|
||||
dest = fromUTF8(intermed.c_str());
|
||||
else
|
||||
{
|
||||
// Optimized ToAscii conversion.
|
||||
// wx3.0 : NOT COMPATIBLE!! (on linux anyway)
|
||||
const char* ascii = intermed.c_str();
|
||||
while (*ascii != 0)
|
||||
dest += (wchar_t)(unsigned char)*ascii++;
|
||||
}
|
||||
}
|
||||
|
||||
void pxReadLine(wxInputStream &input, wxString &dest)
|
||||
void pxReadLine(wxInputStream& input, wxString& dest)
|
||||
{
|
||||
std::string line;
|
||||
pxReadLine(input, dest, line);
|
||||
std::string line;
|
||||
pxReadLine(input, dest, line);
|
||||
}
|
||||
|
||||
wxString pxReadLine(wxInputStream &input)
|
||||
wxString pxReadLine(wxInputStream& input)
|
||||
{
|
||||
wxString result;
|
||||
pxReadLine(input, result);
|
||||
return result;
|
||||
wxString result;
|
||||
pxReadLine(input, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
void pxWriteLine(wxOutputStream &output)
|
||||
void pxWriteLine(wxOutputStream& output)
|
||||
{
|
||||
output.Write("\n", 1);
|
||||
output.Write("\n", 1);
|
||||
}
|
||||
|
||||
void pxWriteLine(wxOutputStream &output, const wxString &text)
|
||||
void pxWriteLine(wxOutputStream& output, const wxString& text)
|
||||
{
|
||||
if (!text.IsEmpty()) {
|
||||
pxToUTF8 utf8(text);
|
||||
output.Write(utf8, utf8.Length());
|
||||
}
|
||||
pxWriteLine(output);
|
||||
if (!text.IsEmpty())
|
||||
{
|
||||
pxToUTF8 utf8(text);
|
||||
output.Write(utf8, utf8.Length());
|
||||
}
|
||||
pxWriteLine(output);
|
||||
}
|
||||
|
||||
void pxWriteMultiline(wxOutputStream &output, const wxString &src)
|
||||
void pxWriteMultiline(wxOutputStream& output, const wxString& src)
|
||||
{
|
||||
if (src.IsEmpty())
|
||||
return;
|
||||
if (src.IsEmpty())
|
||||
return;
|
||||
|
||||
wxString result(src);
|
||||
result.Replace(L"\r\n", L"\n");
|
||||
result.Replace(L"\r", L"\n");
|
||||
wxString result(src);
|
||||
result.Replace(L"\r\n", L"\n");
|
||||
result.Replace(L"\r", L"\n");
|
||||
|
||||
pxToUTF8 utf8(result);
|
||||
output.Write(utf8, utf8.Length());
|
||||
pxToUTF8 utf8(result);
|
||||
output.Write(utf8, utf8.Length());
|
||||
}
|
||||
|
|
|
@ -25,28 +25,28 @@
|
|||
// --------------------------------------------------------------------------------------
|
||||
class pxStreamBase
|
||||
{
|
||||
DeclareNoncopyableObject(pxStreamBase);
|
||||
DeclareNoncopyableObject(pxStreamBase);
|
||||
|
||||
protected:
|
||||
// Filename of the stream, provided by the creator/caller. This is typically used *only*
|
||||
// for generating comprehensive error messages when an error occurs (the stream name is
|
||||
// passed to the exception handlers).
|
||||
wxString m_filename;
|
||||
// Filename of the stream, provided by the creator/caller. This is typically used *only*
|
||||
// for generating comprehensive error messages when an error occurs (the stream name is
|
||||
// passed to the exception handlers).
|
||||
wxString m_filename;
|
||||
|
||||
public:
|
||||
pxStreamBase(const wxString &filename);
|
||||
virtual ~pxStreamBase() = default;
|
||||
pxStreamBase(const wxString& filename);
|
||||
virtual ~pxStreamBase() = default;
|
||||
|
||||
// Implementing classes should return the base wxStream object (usually either a wxInputStream
|
||||
// or wxOputStream derivative).
|
||||
virtual wxStreamBase *GetWxStreamBase() const = 0;
|
||||
virtual void Close() = 0;
|
||||
virtual wxFileOffset Tell() const = 0;
|
||||
virtual wxFileOffset Seek(wxFileOffset ofs, wxSeekMode mode = wxFromStart) = 0;
|
||||
// Implementing classes should return the base wxStream object (usually either a wxInputStream
|
||||
// or wxOputStream derivative).
|
||||
virtual wxStreamBase* GetWxStreamBase() const = 0;
|
||||
virtual void Close() = 0;
|
||||
virtual wxFileOffset Tell() const = 0;
|
||||
virtual wxFileOffset Seek(wxFileOffset ofs, wxSeekMode mode = wxFromStart) = 0;
|
||||
|
||||
virtual wxFileOffset Length() const;
|
||||
bool IsOk() const;
|
||||
wxString GetStreamName() const { return m_filename; }
|
||||
virtual wxFileOffset Length() const;
|
||||
bool IsOk() const;
|
||||
wxString GetStreamName() const { return m_filename; }
|
||||
};
|
||||
|
||||
|
||||
|
@ -55,33 +55,33 @@ public:
|
|||
// --------------------------------------------------------------------------------------
|
||||
class pxOutputStream : public pxStreamBase
|
||||
{
|
||||
DeclareNoncopyableObject(pxOutputStream);
|
||||
DeclareNoncopyableObject(pxOutputStream);
|
||||
|
||||
protected:
|
||||
std::unique_ptr<wxOutputStream> m_stream_out;
|
||||
std::unique_ptr<wxOutputStream> m_stream_out;
|
||||
|
||||
public:
|
||||
pxOutputStream(const wxString &filename, std::unique_ptr<wxOutputStream> &output);
|
||||
pxOutputStream(const wxString &filename, wxOutputStream *output);
|
||||
pxOutputStream(const wxString& filename, std::unique_ptr<wxOutputStream>& output);
|
||||
pxOutputStream(const wxString& filename, wxOutputStream* output);
|
||||
|
||||
virtual ~pxOutputStream() = default;
|
||||
virtual void Write(const void *data, size_t size);
|
||||
virtual ~pxOutputStream() = default;
|
||||
virtual void Write(const void* data, size_t size);
|
||||
|
||||
void SetStream(const wxString &filename, std::unique_ptr<wxOutputStream> &stream);
|
||||
void SetStream(const wxString &filename, wxOutputStream *stream);
|
||||
void SetStream(const wxString& filename, std::unique_ptr<wxOutputStream>& stream);
|
||||
void SetStream(const wxString& filename, wxOutputStream* stream);
|
||||
|
||||
void Close() { m_stream_out = nullptr; }
|
||||
void Close() { m_stream_out = nullptr; }
|
||||
|
||||
virtual wxStreamBase *GetWxStreamBase() const;
|
||||
virtual wxStreamBase* GetWxStreamBase() const;
|
||||
|
||||
template <typename T>
|
||||
void Write(const T &data)
|
||||
{
|
||||
Write(&data, sizeof(data));
|
||||
}
|
||||
template <typename T>
|
||||
void Write(const T& data)
|
||||
{
|
||||
Write(&data, sizeof(data));
|
||||
}
|
||||
|
||||
wxFileOffset Tell() const;
|
||||
wxFileOffset Seek(wxFileOffset ofs, wxSeekMode mode = wxFromStart);
|
||||
wxFileOffset Tell() const;
|
||||
wxFileOffset Seek(wxFileOffset ofs, wxSeekMode mode = wxFromStart);
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -89,31 +89,31 @@ public:
|
|||
// --------------------------------------------------------------------------------------
|
||||
class pxInputStream : public pxStreamBase
|
||||
{
|
||||
DeclareNoncopyableObject(pxInputStream);
|
||||
DeclareNoncopyableObject(pxInputStream);
|
||||
|
||||
protected:
|
||||
std::unique_ptr<wxInputStream> m_stream_in;
|
||||
std::unique_ptr<wxInputStream> m_stream_in;
|
||||
|
||||
public:
|
||||
pxInputStream(const wxString &filename, std::unique_ptr<wxInputStream> &input);
|
||||
pxInputStream(const wxString &filename, wxInputStream *input);
|
||||
pxInputStream(const wxString& filename, std::unique_ptr<wxInputStream>& input);
|
||||
pxInputStream(const wxString& filename, wxInputStream* input);
|
||||
|
||||
virtual ~pxInputStream() = default;
|
||||
virtual void Read(void *dest, size_t size);
|
||||
virtual ~pxInputStream() = default;
|
||||
virtual void Read(void* dest, size_t size);
|
||||
|
||||
void SetStream(const wxString &filename, std::unique_ptr<wxInputStream> &stream);
|
||||
void SetStream(const wxString &filename, wxInputStream *stream);
|
||||
void SetStream(const wxString& filename, std::unique_ptr<wxInputStream>& stream);
|
||||
void SetStream(const wxString& filename, wxInputStream* stream);
|
||||
|
||||
void Close() { m_stream_in = nullptr; }
|
||||
void Close() { m_stream_in = nullptr; }
|
||||
|
||||
virtual wxStreamBase *GetWxStreamBase() const;
|
||||
virtual wxStreamBase* GetWxStreamBase() const;
|
||||
|
||||
template <typename T>
|
||||
void Read(T &dest)
|
||||
{
|
||||
Read(&dest, sizeof(dest));
|
||||
}
|
||||
template <typename T>
|
||||
void Read(T& dest)
|
||||
{
|
||||
Read(&dest, sizeof(dest));
|
||||
}
|
||||
|
||||
wxFileOffset Tell() const;
|
||||
wxFileOffset Seek(wxFileOffset ofs, wxSeekMode mode = wxFromStart);
|
||||
wxFileOffset Tell() const;
|
||||
wxFileOffset Seek(wxFileOffset ofs, wxSeekMode mode = wxFromStart);
|
||||
};
|
||||
|
|
|
@ -25,12 +25,12 @@ bool pxIsEnglish(int id)
|
|||
// pxExpandMsg -- an Iconized Text Translator
|
||||
// Was replaced by a standard implementation of wxGetTranslation
|
||||
// --------------------------------------------------------------------------------------
|
||||
const wxChar *__fastcall pxExpandMsg(const wxChar *message)
|
||||
const wxChar* __fastcall pxExpandMsg(const wxChar* message)
|
||||
{
|
||||
return wxGetTranslation(message).wc_str();
|
||||
}
|
||||
|
||||
const wxChar *__fastcall pxGetTranslation(const wxChar *message)
|
||||
const wxChar* __fastcall pxGetTranslation(const wxChar* message)
|
||||
{
|
||||
return wxGetTranslation(message).wc_str();
|
||||
}
|
||||
|
|
|
@ -20,137 +20,140 @@
|
|||
// --------------------------------------------------------------------------------------
|
||||
// pxWindowTextWriter Implementations
|
||||
// --------------------------------------------------------------------------------------
|
||||
pxWindowTextWriter::pxWindowTextWriter(wxDC &dc)
|
||||
: m_dc(dc)
|
||||
pxWindowTextWriter::pxWindowTextWriter(wxDC& dc)
|
||||
: m_dc(dc)
|
||||
{
|
||||
m_curpos = wxPoint();
|
||||
m_align = wxALIGN_CENTER;
|
||||
m_leading = 0;
|
||||
m_curpos = wxPoint();
|
||||
m_align = wxALIGN_CENTER;
|
||||
m_leading = 0;
|
||||
|
||||
OnFontChanged();
|
||||
OnFontChanged();
|
||||
}
|
||||
|
||||
void pxWindowTextWriter::OnFontChanged()
|
||||
{
|
||||
}
|
||||
|
||||
pxWindowTextWriter &pxWindowTextWriter::SetWeight(wxFontWeight weight)
|
||||
pxWindowTextWriter& pxWindowTextWriter::SetWeight(wxFontWeight weight)
|
||||
{
|
||||
wxFont curfont(m_dc.GetFont());
|
||||
curfont.SetWeight(weight);
|
||||
m_dc.SetFont(curfont);
|
||||
wxFont curfont(m_dc.GetFont());
|
||||
curfont.SetWeight(weight);
|
||||
m_dc.SetFont(curfont);
|
||||
|
||||
return *this;
|
||||
return *this;
|
||||
}
|
||||
|
||||
pxWindowTextWriter &pxWindowTextWriter::SetStyle(wxFontStyle style)
|
||||
pxWindowTextWriter& pxWindowTextWriter::SetStyle(wxFontStyle style)
|
||||
{
|
||||
wxFont curfont(m_dc.GetFont());
|
||||
curfont.SetStyle(style);
|
||||
m_dc.SetFont(curfont);
|
||||
return *this;
|
||||
wxFont curfont(m_dc.GetFont());
|
||||
curfont.SetStyle(style);
|
||||
m_dc.SetFont(curfont);
|
||||
return *this;
|
||||
}
|
||||
|
||||
pxWindowTextWriter &pxWindowTextWriter::Normal()
|
||||
pxWindowTextWriter& pxWindowTextWriter::Normal()
|
||||
{
|
||||
wxFont curfont(m_dc.GetFont());
|
||||
curfont.SetStyle(wxFONTSTYLE_NORMAL);
|
||||
curfont.SetWeight(wxFONTWEIGHT_NORMAL);
|
||||
m_dc.SetFont(curfont);
|
||||
wxFont curfont(m_dc.GetFont());
|
||||
curfont.SetStyle(wxFONTSTYLE_NORMAL);
|
||||
curfont.SetWeight(wxFONTWEIGHT_NORMAL);
|
||||
m_dc.SetFont(curfont);
|
||||
|
||||
return *this;
|
||||
return *this;
|
||||
}
|
||||
|
||||
pxWindowTextWriter &pxWindowTextWriter::SetPos(const wxPoint &pos)
|
||||
pxWindowTextWriter& pxWindowTextWriter::SetPos(const wxPoint& pos)
|
||||
{
|
||||
m_curpos = pos;
|
||||
return *this;
|
||||
m_curpos = pos;
|
||||
return *this;
|
||||
}
|
||||
|
||||
pxWindowTextWriter &pxWindowTextWriter::MovePos(const wxSize &delta)
|
||||
pxWindowTextWriter& pxWindowTextWriter::MovePos(const wxSize& delta)
|
||||
{
|
||||
m_curpos += delta;
|
||||
return *this;
|
||||
m_curpos += delta;
|
||||
return *this;
|
||||
}
|
||||
|
||||
pxWindowTextWriter &pxWindowTextWriter::SetY(int ypos)
|
||||
pxWindowTextWriter& pxWindowTextWriter::SetY(int ypos)
|
||||
{
|
||||
m_curpos.y = ypos;
|
||||
return *this;
|
||||
m_curpos.y = ypos;
|
||||
return *this;
|
||||
}
|
||||
|
||||
pxWindowTextWriter &pxWindowTextWriter::MoveY(int ydelta)
|
||||
pxWindowTextWriter& pxWindowTextWriter::MoveY(int ydelta)
|
||||
{
|
||||
m_curpos.y += ydelta;
|
||||
return *this;
|
||||
m_curpos.y += ydelta;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void pxWindowTextWriter::_DoWriteLn(const wxString &msg)
|
||||
void pxWindowTextWriter::_DoWriteLn(const wxString& msg)
|
||||
{
|
||||
int tWidth, tHeight;
|
||||
m_dc.GetMultiLineTextExtent(msg, &tWidth, &tHeight);
|
||||
int tWidth, tHeight;
|
||||
m_dc.GetMultiLineTextExtent(msg, &tWidth, &tHeight);
|
||||
|
||||
wxPoint dispos(m_curpos);
|
||||
wxPoint dispos(m_curpos);
|
||||
|
||||
if (m_align & wxALIGN_CENTER_HORIZONTAL) {
|
||||
dispos.x = (m_dc.GetSize().GetWidth() - tWidth) / 2;
|
||||
} else if (m_align & wxALIGN_RIGHT) {
|
||||
dispos.x = m_dc.GetSize().GetWidth() - tWidth;
|
||||
}
|
||||
if (m_align & wxALIGN_CENTER_HORIZONTAL)
|
||||
{
|
||||
dispos.x = (m_dc.GetSize().GetWidth() - tWidth) / 2;
|
||||
}
|
||||
else if (m_align & wxALIGN_RIGHT)
|
||||
{
|
||||
dispos.x = m_dc.GetSize().GetWidth() - tWidth;
|
||||
}
|
||||
|
||||
m_dc.DrawText(msg, dispos);
|
||||
m_curpos.y += tHeight + m_leading;
|
||||
m_dc.DrawText(msg, dispos);
|
||||
m_curpos.y += tHeight + m_leading;
|
||||
}
|
||||
|
||||
// Splits incoming multi-line strings into pieces, and dispatches each line individually
|
||||
// to the text writer.
|
||||
void pxWindowTextWriter::_DoWrite(const wxChar *msg)
|
||||
void pxWindowTextWriter::_DoWrite(const wxChar* msg)
|
||||
{
|
||||
pxAssert(msg);
|
||||
pxAssert(msg);
|
||||
|
||||
wxArrayString parts;
|
||||
SplitString(parts, msg, L'\n');
|
||||
wxArrayString parts;
|
||||
SplitString(parts, msg, L'\n');
|
||||
|
||||
for (size_t i = 0; i < parts.GetCount(); ++i)
|
||||
_DoWriteLn(parts[i]);
|
||||
for (size_t i = 0; i < parts.GetCount(); ++i)
|
||||
_DoWriteLn(parts[i]);
|
||||
}
|
||||
|
||||
pxWindowTextWriter &pxWindowTextWriter::SetFont(const wxFont &font)
|
||||
pxWindowTextWriter& pxWindowTextWriter::SetFont(const wxFont& font)
|
||||
{
|
||||
m_dc.SetFont(font);
|
||||
return *this;
|
||||
m_dc.SetFont(font);
|
||||
return *this;
|
||||
}
|
||||
|
||||
pxWindowTextWriter &pxWindowTextWriter::Align(const wxAlignment &align)
|
||||
pxWindowTextWriter& pxWindowTextWriter::Align(const wxAlignment& align)
|
||||
{
|
||||
m_align = align;
|
||||
m_curpos.x = 0;
|
||||
return *this;
|
||||
m_align = align;
|
||||
m_curpos.x = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
pxWindowTextWriter &pxWindowTextWriter::WriteLn()
|
||||
pxWindowTextWriter& pxWindowTextWriter::WriteLn()
|
||||
{
|
||||
_DoWriteLn(L"");
|
||||
return *this;
|
||||
_DoWriteLn(L"");
|
||||
return *this;
|
||||
}
|
||||
|
||||
pxWindowTextWriter &pxWindowTextWriter::WriteLn(const wxChar *fmt)
|
||||
pxWindowTextWriter& pxWindowTextWriter::WriteLn(const wxChar* fmt)
|
||||
{
|
||||
_DoWrite(fmt);
|
||||
return *this;
|
||||
_DoWrite(fmt);
|
||||
return *this;
|
||||
}
|
||||
|
||||
pxWindowTextWriter &pxWindowTextWriter::FormatLn(const wxChar *fmt, ...)
|
||||
pxWindowTextWriter& pxWindowTextWriter::FormatLn(const wxChar* fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
_DoWrite(pxsFmtV(fmt, args));
|
||||
va_end(args);
|
||||
return *this;
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
_DoWrite(pxsFmtV(fmt, args));
|
||||
va_end(args);
|
||||
return *this;
|
||||
}
|
||||
|
||||
pxWindowTextWriter &pxWindowTextWriter::WriteLn(const wxString fmt)
|
||||
pxWindowTextWriter& pxWindowTextWriter::WriteLn(const wxString fmt)
|
||||
{
|
||||
_DoWrite(fmt.wc_str());
|
||||
return *this;
|
||||
_DoWrite(fmt.wc_str());
|
||||
return *this;
|
||||
}
|
||||
|
|
|
@ -27,21 +27,21 @@ wxIMPLEMENT_DYNAMIC_CLASS(pxSimpleEvent, wxEvent);
|
|||
|
||||
ConsoleLogSource_App::ConsoleLogSource_App()
|
||||
{
|
||||
static const TraceLogDescriptor myDesc =
|
||||
{
|
||||
L"AppEvents", L"App Events",
|
||||
pxLt("Includes idle event processing and some other uncommon event usages.")};
|
||||
static const TraceLogDescriptor myDesc =
|
||||
{
|
||||
L"AppEvents", L"App Events",
|
||||
pxLt("Includes idle event processing and some other uncommon event usages.")};
|
||||
|
||||
m_Descriptor = &myDesc;
|
||||
m_Descriptor = &myDesc;
|
||||
}
|
||||
|
||||
ConsoleLogSource_App pxConLog_App;
|
||||
|
||||
void BaseDeletableObject::DoDeletion()
|
||||
{
|
||||
wxAppWithHelpers *app = wxDynamicCast(wxApp::GetInstance(), wxAppWithHelpers);
|
||||
pxAssert(app != NULL);
|
||||
app->DeleteObject(*this);
|
||||
wxAppWithHelpers* app = wxDynamicCast(wxApp::GetInstance(), wxAppWithHelpers);
|
||||
pxAssert(app != NULL);
|
||||
app->DeleteObject(*this);
|
||||
}
|
||||
|
||||
|
||||
|
@ -49,64 +49,67 @@ void BaseDeletableObject::DoDeletion()
|
|||
// SynchronousActionState Implementations
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
void SynchronousActionState::SetException(const BaseException &ex)
|
||||
void SynchronousActionState::SetException(const BaseException& ex)
|
||||
{
|
||||
m_exception = ScopedExcept(ex.Clone());
|
||||
m_exception = ScopedExcept(ex.Clone());
|
||||
}
|
||||
|
||||
void SynchronousActionState::SetException(BaseException *ex)
|
||||
void SynchronousActionState::SetException(BaseException* ex)
|
||||
{
|
||||
if (!m_posted) {
|
||||
m_exception = ScopedExcept(ex);
|
||||
} else if (wxTheApp) {
|
||||
// transport the exception to the main thread, since the message is fully
|
||||
// asynchronous, or has already entered an asynchronous state. Message is sent
|
||||
// as a non-blocking action since proper handling of user errors on async messages
|
||||
// is *usually* to log/ignore it (hah), or to suspend emulation and issue a dialog
|
||||
// box to the user.
|
||||
if (!m_posted)
|
||||
{
|
||||
m_exception = ScopedExcept(ex);
|
||||
}
|
||||
else if (wxTheApp)
|
||||
{
|
||||
// transport the exception to the main thread, since the message is fully
|
||||
// asynchronous, or has already entered an asynchronous state. Message is sent
|
||||
// as a non-blocking action since proper handling of user errors on async messages
|
||||
// is *usually* to log/ignore it (hah), or to suspend emulation and issue a dialog
|
||||
// box to the user.
|
||||
|
||||
pxExceptionEvent ev(ex);
|
||||
wxTheApp->AddPendingEvent(ev);
|
||||
}
|
||||
pxExceptionEvent ev(ex);
|
||||
wxTheApp->AddPendingEvent(ev);
|
||||
}
|
||||
}
|
||||
|
||||
void SynchronousActionState::RethrowException() const
|
||||
{
|
||||
if (m_exception)
|
||||
m_exception->Rethrow();
|
||||
if (m_exception)
|
||||
m_exception->Rethrow();
|
||||
}
|
||||
|
||||
int SynchronousActionState::WaitForResult()
|
||||
{
|
||||
m_sema.WaitNoCancel();
|
||||
RethrowException();
|
||||
return return_value;
|
||||
m_sema.WaitNoCancel();
|
||||
RethrowException();
|
||||
return return_value;
|
||||
}
|
||||
|
||||
int SynchronousActionState::WaitForResult_NoExceptions()
|
||||
{
|
||||
m_sema.WaitNoCancel();
|
||||
return return_value;
|
||||
m_sema.WaitNoCancel();
|
||||
return return_value;
|
||||
}
|
||||
|
||||
void SynchronousActionState::PostResult(int res)
|
||||
{
|
||||
return_value = res;
|
||||
PostResult();
|
||||
return_value = res;
|
||||
PostResult();
|
||||
}
|
||||
|
||||
void SynchronousActionState::ClearResult()
|
||||
{
|
||||
m_posted = false;
|
||||
m_exception = NULL;
|
||||
m_posted = false;
|
||||
m_exception = NULL;
|
||||
}
|
||||
|
||||
void SynchronousActionState::PostResult()
|
||||
{
|
||||
if (m_posted)
|
||||
return;
|
||||
m_posted = true;
|
||||
m_sema.Post();
|
||||
if (m_posted)
|
||||
return;
|
||||
m_posted = true;
|
||||
m_sema.Post();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -115,40 +118,41 @@ void SynchronousActionState::PostResult()
|
|||
|
||||
wxIMPLEMENT_DYNAMIC_CLASS(pxActionEvent, wxEvent);
|
||||
|
||||
pxActionEvent::pxActionEvent(SynchronousActionState *sema, int msgtype)
|
||||
: wxEvent(0, msgtype)
|
||||
pxActionEvent::pxActionEvent(SynchronousActionState* sema, int msgtype)
|
||||
: wxEvent(0, msgtype)
|
||||
{
|
||||
m_state = sema;
|
||||
m_state = sema;
|
||||
}
|
||||
|
||||
pxActionEvent::pxActionEvent(SynchronousActionState &sema, int msgtype)
|
||||
: wxEvent(0, msgtype)
|
||||
pxActionEvent::pxActionEvent(SynchronousActionState& sema, int msgtype)
|
||||
: wxEvent(0, msgtype)
|
||||
{
|
||||
m_state = &sema;
|
||||
m_state = &sema;
|
||||
}
|
||||
|
||||
pxActionEvent::pxActionEvent(const pxActionEvent &src)
|
||||
: wxEvent(src)
|
||||
pxActionEvent::pxActionEvent(const pxActionEvent& src)
|
||||
: wxEvent(src)
|
||||
{
|
||||
m_state = src.m_state;
|
||||
m_state = src.m_state;
|
||||
}
|
||||
|
||||
void pxActionEvent::SetException(const BaseException &ex)
|
||||
void pxActionEvent::SetException(const BaseException& ex)
|
||||
{
|
||||
SetException(ex.Clone());
|
||||
SetException(ex.Clone());
|
||||
}
|
||||
|
||||
void pxActionEvent::SetException(BaseException *ex)
|
||||
void pxActionEvent::SetException(BaseException* ex)
|
||||
{
|
||||
const wxString &prefix(pxsFmt(L"(%s) ", GetClassInfo()->GetClassName()));
|
||||
ex->DiagMsg() = prefix + ex->DiagMsg();
|
||||
const wxString& prefix(pxsFmt(L"(%s) ", GetClassInfo()->GetClassName()));
|
||||
ex->DiagMsg() = prefix + ex->DiagMsg();
|
||||
|
||||
if (!m_state) {
|
||||
ScopedExcept exptr(ex); // auto-delete it after handling.
|
||||
ex->Rethrow();
|
||||
}
|
||||
if (!m_state)
|
||||
{
|
||||
ScopedExcept exptr(ex); // auto-delete it after handling.
|
||||
ex->Rethrow();
|
||||
}
|
||||
|
||||
m_state->SetException(ex);
|
||||
m_state->SetException(ex);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -156,58 +160,59 @@ void pxActionEvent::SetException(BaseException *ex)
|
|||
// --------------------------------------------------------------------------------------
|
||||
wxIMPLEMENT_DYNAMIC_CLASS(pxSynchronousCommandEvent, wxCommandEvent);
|
||||
|
||||
pxSynchronousCommandEvent::pxSynchronousCommandEvent(SynchronousActionState *sema, wxEventType commandType, int winid)
|
||||
: wxCommandEvent(pxEvt_SynchronousCommand, winid)
|
||||
pxSynchronousCommandEvent::pxSynchronousCommandEvent(SynchronousActionState* sema, wxEventType commandType, int winid)
|
||||
: wxCommandEvent(pxEvt_SynchronousCommand, winid)
|
||||
{
|
||||
m_sync = sema;
|
||||
m_realEvent = commandType;
|
||||
m_sync = sema;
|
||||
m_realEvent = commandType;
|
||||
}
|
||||
|
||||
pxSynchronousCommandEvent::pxSynchronousCommandEvent(SynchronousActionState &sema, wxEventType commandType, int winid)
|
||||
: wxCommandEvent(pxEvt_SynchronousCommand)
|
||||
pxSynchronousCommandEvent::pxSynchronousCommandEvent(SynchronousActionState& sema, wxEventType commandType, int winid)
|
||||
: wxCommandEvent(pxEvt_SynchronousCommand)
|
||||
{
|
||||
m_sync = &sema;
|
||||
m_realEvent = commandType;
|
||||
m_sync = &sema;
|
||||
m_realEvent = commandType;
|
||||
}
|
||||
|
||||
pxSynchronousCommandEvent::pxSynchronousCommandEvent(SynchronousActionState *sema, const wxCommandEvent &evt)
|
||||
: wxCommandEvent(evt)
|
||||
pxSynchronousCommandEvent::pxSynchronousCommandEvent(SynchronousActionState* sema, const wxCommandEvent& evt)
|
||||
: wxCommandEvent(evt)
|
||||
{
|
||||
m_sync = sema;
|
||||
m_realEvent = evt.GetEventType();
|
||||
SetEventType(pxEvt_SynchronousCommand);
|
||||
m_sync = sema;
|
||||
m_realEvent = evt.GetEventType();
|
||||
SetEventType(pxEvt_SynchronousCommand);
|
||||
}
|
||||
|
||||
pxSynchronousCommandEvent::pxSynchronousCommandEvent(SynchronousActionState &sema, const wxCommandEvent &evt)
|
||||
: wxCommandEvent(evt)
|
||||
pxSynchronousCommandEvent::pxSynchronousCommandEvent(SynchronousActionState& sema, const wxCommandEvent& evt)
|
||||
: wxCommandEvent(evt)
|
||||
{
|
||||
m_sync = &sema;
|
||||
m_realEvent = evt.GetEventType();
|
||||
SetEventType(pxEvt_SynchronousCommand);
|
||||
m_sync = &sema;
|
||||
m_realEvent = evt.GetEventType();
|
||||
SetEventType(pxEvt_SynchronousCommand);
|
||||
}
|
||||
|
||||
pxSynchronousCommandEvent::pxSynchronousCommandEvent(const pxSynchronousCommandEvent &src)
|
||||
: wxCommandEvent(src)
|
||||
pxSynchronousCommandEvent::pxSynchronousCommandEvent(const pxSynchronousCommandEvent& src)
|
||||
: wxCommandEvent(src)
|
||||
{
|
||||
m_sync = src.m_sync;
|
||||
m_realEvent = src.m_realEvent;
|
||||
m_sync = src.m_sync;
|
||||
m_realEvent = src.m_realEvent;
|
||||
}
|
||||
|
||||
void pxSynchronousCommandEvent::SetException(const BaseException &ex)
|
||||
void pxSynchronousCommandEvent::SetException(const BaseException& ex)
|
||||
{
|
||||
if (!m_sync)
|
||||
ex.Rethrow();
|
||||
m_sync->SetException(ex);
|
||||
if (!m_sync)
|
||||
ex.Rethrow();
|
||||
m_sync->SetException(ex);
|
||||
}
|
||||
|
||||
void pxSynchronousCommandEvent::SetException(BaseException *ex)
|
||||
void pxSynchronousCommandEvent::SetException(BaseException* ex)
|
||||
{
|
||||
if (!m_sync) {
|
||||
ScopedExcept exptr(ex); // auto-delete it after handling.
|
||||
ex->Rethrow();
|
||||
}
|
||||
if (!m_sync)
|
||||
{
|
||||
ScopedExcept exptr(ex); // auto-delete it after handling.
|
||||
ex->Rethrow();
|
||||
}
|
||||
|
||||
m_sync->SetException(ex);
|
||||
m_sync->SetException(ex);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -219,46 +224,46 @@ void pxSynchronousCommandEvent::SetException(BaseException *ex)
|
|||
//
|
||||
class pxRpcEvent : public pxActionEvent
|
||||
{
|
||||
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxRpcEvent);
|
||||
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxRpcEvent);
|
||||
|
||||
typedef pxActionEvent _parent;
|
||||
typedef pxActionEvent _parent;
|
||||
|
||||
protected:
|
||||
void (*m_Method)();
|
||||
void (*m_Method)();
|
||||
|
||||
public:
|
||||
virtual ~pxRpcEvent() = default;
|
||||
virtual pxRpcEvent *Clone() const { return new pxRpcEvent(*this); }
|
||||
virtual ~pxRpcEvent() = default;
|
||||
virtual pxRpcEvent* Clone() const { return new pxRpcEvent(*this); }
|
||||
|
||||
explicit pxRpcEvent(void (*method)() = NULL, SynchronousActionState *sema = NULL)
|
||||
: pxActionEvent(sema)
|
||||
{
|
||||
m_Method = method;
|
||||
}
|
||||
explicit pxRpcEvent(void (*method)() = NULL, SynchronousActionState* sema = NULL)
|
||||
: pxActionEvent(sema)
|
||||
{
|
||||
m_Method = method;
|
||||
}
|
||||
|
||||
explicit pxRpcEvent(void (*method)(), SynchronousActionState &sema)
|
||||
: pxActionEvent(sema)
|
||||
{
|
||||
m_Method = method;
|
||||
}
|
||||
explicit pxRpcEvent(void (*method)(), SynchronousActionState& sema)
|
||||
: pxActionEvent(sema)
|
||||
{
|
||||
m_Method = method;
|
||||
}
|
||||
|
||||
pxRpcEvent(const pxRpcEvent &src)
|
||||
: pxActionEvent(src)
|
||||
{
|
||||
m_Method = src.m_Method;
|
||||
}
|
||||
pxRpcEvent(const pxRpcEvent& src)
|
||||
: pxActionEvent(src)
|
||||
{
|
||||
m_Method = src.m_Method;
|
||||
}
|
||||
|
||||
void SetMethod(void (*method)())
|
||||
{
|
||||
m_Method = method;
|
||||
}
|
||||
void SetMethod(void (*method)())
|
||||
{
|
||||
m_Method = method;
|
||||
}
|
||||
|
||||
protected:
|
||||
void InvokeEvent()
|
||||
{
|
||||
if (m_Method)
|
||||
m_Method();
|
||||
}
|
||||
void InvokeEvent()
|
||||
{
|
||||
if (m_Method)
|
||||
m_Method();
|
||||
}
|
||||
};
|
||||
|
||||
wxIMPLEMENT_DYNAMIC_CLASS(pxRpcEvent, pxActionEvent);
|
||||
|
@ -266,16 +271,16 @@ wxIMPLEMENT_DYNAMIC_CLASS(pxRpcEvent, pxActionEvent);
|
|||
// --------------------------------------------------------------------------------------
|
||||
// pxExceptionEvent implementations
|
||||
// --------------------------------------------------------------------------------------
|
||||
pxExceptionEvent::pxExceptionEvent(const BaseException &ex)
|
||||
pxExceptionEvent::pxExceptionEvent(const BaseException& ex)
|
||||
{
|
||||
m_except = ex.Clone();
|
||||
m_except = ex.Clone();
|
||||
}
|
||||
|
||||
void pxExceptionEvent::InvokeEvent()
|
||||
{
|
||||
ScopedExcept deleteMe(m_except);
|
||||
if (deleteMe)
|
||||
deleteMe->Rethrow();
|
||||
ScopedExcept deleteMe(m_except);
|
||||
if (deleteMe)
|
||||
deleteMe->Rethrow();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -291,17 +296,17 @@ wxIMPLEMENT_DYNAMIC_CLASS(wxAppWithHelpers, wxApp);
|
|||
|
||||
// Posts a method to the main thread; non-blocking. Post occurs even when called from the
|
||||
// main thread.
|
||||
void wxAppWithHelpers::PostMethod(FnType_Void *method)
|
||||
void wxAppWithHelpers::PostMethod(FnType_Void* method)
|
||||
{
|
||||
PostEvent(pxRpcEvent(method));
|
||||
PostEvent(pxRpcEvent(method));
|
||||
}
|
||||
|
||||
// Posts a method to the main thread; non-blocking. Post occurs even when called from the
|
||||
// main thread.
|
||||
void wxAppWithHelpers::PostIdleMethod(FnType_Void *method)
|
||||
void wxAppWithHelpers::PostIdleMethod(FnType_Void* method)
|
||||
{
|
||||
pxRpcEvent evt(method);
|
||||
AddIdleEvent(evt);
|
||||
pxRpcEvent evt(method);
|
||||
AddIdleEvent(evt);
|
||||
}
|
||||
|
||||
// Invokes the specified void method, or posts the method to the main thread if the calling
|
||||
|
@ -316,16 +321,16 @@ void wxAppWithHelpers::PostIdleMethod(FnType_Void *method)
|
|||
// TRUE if the method was invoked.
|
||||
//
|
||||
|
||||
bool wxAppWithHelpers::Rpc_TryInvoke(FnType_Void *method)
|
||||
bool wxAppWithHelpers::Rpc_TryInvoke(FnType_Void* method)
|
||||
{
|
||||
if (wxThread::IsMain())
|
||||
return false;
|
||||
if (wxThread::IsMain())
|
||||
return false;
|
||||
|
||||
SynchronousActionState sync;
|
||||
PostEvent(pxRpcEvent(method, sync));
|
||||
sync.WaitForResult();
|
||||
SynchronousActionState sync;
|
||||
PostEvent(pxRpcEvent(method, sync));
|
||||
sync.WaitForResult();
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Invokes the specified void method, or posts the method to the main thread if the calling
|
||||
|
@ -339,93 +344,98 @@ bool wxAppWithHelpers::Rpc_TryInvoke(FnType_Void *method)
|
|||
// FALSE if the method was not posted to the main thread (meaning this IS the main thread!)
|
||||
// TRUE if the method was posted.
|
||||
//
|
||||
bool wxAppWithHelpers::Rpc_TryInvokeAsync(FnType_Void *method)
|
||||
bool wxAppWithHelpers::Rpc_TryInvokeAsync(FnType_Void* method)
|
||||
{
|
||||
if (wxThread::IsMain())
|
||||
return false;
|
||||
PostEvent(pxRpcEvent(method));
|
||||
return true;
|
||||
if (wxThread::IsMain())
|
||||
return false;
|
||||
PostEvent(pxRpcEvent(method));
|
||||
return true;
|
||||
}
|
||||
|
||||
void wxAppWithHelpers::ProcessMethod(FnType_Void *method)
|
||||
void wxAppWithHelpers::ProcessMethod(FnType_Void* method)
|
||||
{
|
||||
if (wxThread::IsMain()) {
|
||||
method();
|
||||
return;
|
||||
}
|
||||
if (wxThread::IsMain())
|
||||
{
|
||||
method();
|
||||
return;
|
||||
}
|
||||
|
||||
SynchronousActionState sync;
|
||||
PostEvent(pxRpcEvent(method, sync));
|
||||
sync.WaitForResult();
|
||||
SynchronousActionState sync;
|
||||
PostEvent(pxRpcEvent(method, sync));
|
||||
sync.WaitForResult();
|
||||
}
|
||||
|
||||
void wxAppWithHelpers::PostEvent(const wxEvent &evt)
|
||||
void wxAppWithHelpers::PostEvent(const wxEvent& evt)
|
||||
{
|
||||
// Const Cast is OK!
|
||||
// Truth is, AddPendingEvent should be a const-qualified parameter, as
|
||||
// it makes an immediate clone copy of the event -- but wxWidgets
|
||||
// fails again in structured C/C++ design design. So I'm forcing it as such
|
||||
// here. -- air
|
||||
// Const Cast is OK!
|
||||
// Truth is, AddPendingEvent should be a const-qualified parameter, as
|
||||
// it makes an immediate clone copy of the event -- but wxWidgets
|
||||
// fails again in structured C/C++ design design. So I'm forcing it as such
|
||||
// here. -- air
|
||||
|
||||
_parent::AddPendingEvent(const_cast<wxEvent &>(evt));
|
||||
_parent::AddPendingEvent(const_cast<wxEvent&>(evt));
|
||||
}
|
||||
|
||||
bool wxAppWithHelpers::ProcessEvent(wxEvent &evt)
|
||||
bool wxAppWithHelpers::ProcessEvent(wxEvent& evt)
|
||||
{
|
||||
// Note: We can't do an automatic blocking post of the message here, because wxWidgets
|
||||
// isn't really designed for it (some events return data to the caller via the event
|
||||
// struct, and posting the event would require a temporary clone, where changes would
|
||||
// be lost).
|
||||
// Note: We can't do an automatic blocking post of the message here, because wxWidgets
|
||||
// isn't really designed for it (some events return data to the caller via the event
|
||||
// struct, and posting the event would require a temporary clone, where changes would
|
||||
// be lost).
|
||||
|
||||
AffinityAssert_AllowFrom_MainUI();
|
||||
return _parent::ProcessEvent(evt);
|
||||
AffinityAssert_AllowFrom_MainUI();
|
||||
return _parent::ProcessEvent(evt);
|
||||
}
|
||||
|
||||
bool wxAppWithHelpers::ProcessEvent(wxEvent *evt)
|
||||
bool wxAppWithHelpers::ProcessEvent(wxEvent* evt)
|
||||
{
|
||||
AffinityAssert_AllowFrom_MainUI();
|
||||
std::unique_ptr<wxEvent> deleteMe(evt);
|
||||
return _parent::ProcessEvent(*deleteMe);
|
||||
AffinityAssert_AllowFrom_MainUI();
|
||||
std::unique_ptr<wxEvent> deleteMe(evt);
|
||||
return _parent::ProcessEvent(*deleteMe);
|
||||
}
|
||||
|
||||
bool wxAppWithHelpers::ProcessEvent(pxActionEvent &evt)
|
||||
bool wxAppWithHelpers::ProcessEvent(pxActionEvent& evt)
|
||||
{
|
||||
if (wxThread::IsMain())
|
||||
return _parent::ProcessEvent(evt);
|
||||
else {
|
||||
SynchronousActionState sync;
|
||||
evt.SetSyncState(sync);
|
||||
AddPendingEvent(evt);
|
||||
sync.WaitForResult();
|
||||
return true;
|
||||
}
|
||||
if (wxThread::IsMain())
|
||||
return _parent::ProcessEvent(evt);
|
||||
else
|
||||
{
|
||||
SynchronousActionState sync;
|
||||
evt.SetSyncState(sync);
|
||||
AddPendingEvent(evt);
|
||||
sync.WaitForResult();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool wxAppWithHelpers::ProcessEvent(pxActionEvent *evt)
|
||||
bool wxAppWithHelpers::ProcessEvent(pxActionEvent* evt)
|
||||
{
|
||||
if (wxThread::IsMain()) {
|
||||
std::unique_ptr<wxEvent> deleteMe(evt);
|
||||
return _parent::ProcessEvent(*deleteMe);
|
||||
} else {
|
||||
SynchronousActionState sync;
|
||||
evt->SetSyncState(sync);
|
||||
AddPendingEvent(*evt);
|
||||
sync.WaitForResult();
|
||||
return true;
|
||||
}
|
||||
if (wxThread::IsMain())
|
||||
{
|
||||
std::unique_ptr<wxEvent> deleteMe(evt);
|
||||
return _parent::ProcessEvent(*deleteMe);
|
||||
}
|
||||
else
|
||||
{
|
||||
SynchronousActionState sync;
|
||||
evt->SetSyncState(sync);
|
||||
AddPendingEvent(*evt);
|
||||
sync.WaitForResult();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void wxAppWithHelpers::CleanUp()
|
||||
{
|
||||
// I'm pretty sure the message pump is dead by now, which means we need to run through
|
||||
// idle event list by hand and process the pending Deletion messages (all others can be
|
||||
// ignored -- it's only deletions we want handled, and really we *could* ignore those too
|
||||
// but I like to be tidy. -- air
|
||||
// I'm pretty sure the message pump is dead by now, which means we need to run through
|
||||
// idle event list by hand and process the pending Deletion messages (all others can be
|
||||
// ignored -- it's only deletions we want handled, and really we *could* ignore those too
|
||||
// but I like to be tidy. -- air
|
||||
|
||||
//IdleEventDispatcher( "CleanUp" );
|
||||
//DeletionDispatcher();
|
||||
_parent::CleanUp();
|
||||
//IdleEventDispatcher( "CleanUp" );
|
||||
//DeletionDispatcher();
|
||||
_parent::CleanUp();
|
||||
}
|
||||
|
||||
// Executes the event with exception handling. If the event throws an exception, the exception
|
||||
|
@ -434,211 +444,227 @@ void wxAppWithHelpers::CleanUp()
|
|||
// should overload InvokeEvent() instead.
|
||||
void pxActionEvent::_DoInvokeEvent()
|
||||
{
|
||||
AffinityAssert_AllowFrom_MainUI();
|
||||
AffinityAssert_AllowFrom_MainUI();
|
||||
|
||||
try {
|
||||
InvokeEvent();
|
||||
} catch (BaseException &ex) {
|
||||
SetException(ex);
|
||||
} catch (std::runtime_error &ex) {
|
||||
SetException(new Exception::RuntimeError(ex));
|
||||
}
|
||||
try
|
||||
{
|
||||
InvokeEvent();
|
||||
}
|
||||
catch (BaseException& ex)
|
||||
{
|
||||
SetException(ex);
|
||||
}
|
||||
catch (std::runtime_error& ex)
|
||||
{
|
||||
SetException(new Exception::RuntimeError(ex));
|
||||
}
|
||||
|
||||
if (m_state)
|
||||
m_state->PostResult();
|
||||
if (m_state)
|
||||
m_state->PostResult();
|
||||
}
|
||||
|
||||
void wxAppWithHelpers::OnSynchronousCommand(pxSynchronousCommandEvent &evt)
|
||||
void wxAppWithHelpers::OnSynchronousCommand(pxSynchronousCommandEvent& evt)
|
||||
{
|
||||
AffinityAssert_AllowFrom_MainUI();
|
||||
AffinityAssert_AllowFrom_MainUI();
|
||||
|
||||
pxAppLog.Write(L"(App) Executing command event synchronously...");
|
||||
evt.SetEventType(evt.GetRealEventType());
|
||||
pxAppLog.Write(L"(App) Executing command event synchronously...");
|
||||
evt.SetEventType(evt.GetRealEventType());
|
||||
|
||||
try {
|
||||
ProcessEvent(evt);
|
||||
} catch (BaseException &ex) {
|
||||
evt.SetException(ex);
|
||||
} catch (std::runtime_error &ex) {
|
||||
evt.SetException(new Exception::RuntimeError(ex, evt.GetClassInfo()->GetClassName()));
|
||||
}
|
||||
try
|
||||
{
|
||||
ProcessEvent(evt);
|
||||
}
|
||||
catch (BaseException& ex)
|
||||
{
|
||||
evt.SetException(ex);
|
||||
}
|
||||
catch (std::runtime_error& ex)
|
||||
{
|
||||
evt.SetException(new Exception::RuntimeError(ex, evt.GetClassInfo()->GetClassName()));
|
||||
}
|
||||
|
||||
if (Semaphore *sema = evt.GetSemaphore())
|
||||
sema->Post();
|
||||
if (Semaphore* sema = evt.GetSemaphore())
|
||||
sema->Post();
|
||||
}
|
||||
|
||||
void wxAppWithHelpers::AddIdleEvent(const wxEvent &evt)
|
||||
void wxAppWithHelpers::AddIdleEvent(const wxEvent& evt)
|
||||
{
|
||||
ScopedLock lock(m_IdleEventMutex);
|
||||
if (m_IdleEventQueue.empty())
|
||||
PostEvent(wxCommandEvent(pxEvt_StartIdleEventTimer));
|
||||
ScopedLock lock(m_IdleEventMutex);
|
||||
if (m_IdleEventQueue.empty())
|
||||
PostEvent(wxCommandEvent(pxEvt_StartIdleEventTimer));
|
||||
|
||||
m_IdleEventQueue.push_back(evt.Clone());
|
||||
m_IdleEventQueue.push_back(evt.Clone());
|
||||
}
|
||||
|
||||
void wxAppWithHelpers::OnStartIdleEventTimer(wxCommandEvent &evt)
|
||||
void wxAppWithHelpers::OnStartIdleEventTimer(wxCommandEvent& evt)
|
||||
{
|
||||
ScopedLock lock(m_IdleEventMutex);
|
||||
if (!m_IdleEventQueue.empty())
|
||||
m_IdleEventTimer.Start(100, true);
|
||||
ScopedLock lock(m_IdleEventMutex);
|
||||
if (!m_IdleEventQueue.empty())
|
||||
m_IdleEventTimer.Start(100, true);
|
||||
}
|
||||
|
||||
void wxAppWithHelpers::IdleEventDispatcher(const wxChar *action)
|
||||
void wxAppWithHelpers::IdleEventDispatcher(const wxChar* action)
|
||||
{
|
||||
// Recursion is possible thanks to modal dialogs being issued from the idle event handler.
|
||||
// (recursion shouldn't hurt anything anyway, since the node system re-creates the iterator
|
||||
// on each pass)
|
||||
// Recursion is possible thanks to modal dialogs being issued from the idle event handler.
|
||||
// (recursion shouldn't hurt anything anyway, since the node system re-creates the iterator
|
||||
// on each pass)
|
||||
|
||||
//static int __guard=0;
|
||||
//RecursionGuard guard(__guard);
|
||||
//if( !pxAssertDev(!guard.IsReentrant(), "Re-entrant call to IdleEventdispatcher caught on camera!") ) return;
|
||||
//static int __guard=0;
|
||||
//RecursionGuard guard(__guard);
|
||||
//if( !pxAssertDev(!guard.IsReentrant(), "Re-entrant call to IdleEventdispatcher caught on camera!") ) return;
|
||||
|
||||
wxEventList postponed;
|
||||
wxEventList::iterator node;
|
||||
wxEventList postponed;
|
||||
wxEventList::iterator node;
|
||||
|
||||
ScopedLock lock(m_IdleEventMutex);
|
||||
ScopedLock lock(m_IdleEventMutex);
|
||||
|
||||
while (node = m_IdleEventQueue.begin(), node != m_IdleEventQueue.end()) {
|
||||
std::unique_ptr<wxEvent> deleteMe(*node);
|
||||
m_IdleEventQueue.erase(node);
|
||||
while (node = m_IdleEventQueue.begin(), node != m_IdleEventQueue.end())
|
||||
{
|
||||
std::unique_ptr<wxEvent> deleteMe(*node);
|
||||
m_IdleEventQueue.erase(node);
|
||||
|
||||
lock.Release();
|
||||
if (!Threading::AllowDeletions() && (deleteMe->GetEventType() == pxEvt_DeleteThread)) {
|
||||
// Threads that have active semaphores or mutexes (other threads are waiting on them) cannot
|
||||
// be deleted because those mutex/sema objects will become invalid and cause the pending
|
||||
// thread to crash. So we disallow deletions when those waits are in action, and continue
|
||||
// to postpone the deletion of the thread until such time that it is safe.
|
||||
lock.Release();
|
||||
if (!Threading::AllowDeletions() && (deleteMe->GetEventType() == pxEvt_DeleteThread))
|
||||
{
|
||||
// Threads that have active semaphores or mutexes (other threads are waiting on them) cannot
|
||||
// be deleted because those mutex/sema objects will become invalid and cause the pending
|
||||
// thread to crash. So we disallow deletions when those waits are in action, and continue
|
||||
// to postpone the deletion of the thread until such time that it is safe.
|
||||
|
||||
pxThreadLog.Write(((pxThread *)((wxCommandEvent *)deleteMe.get())->GetClientData())->GetName(), L"Deletion postponed due to mutex or semaphore dependency.");
|
||||
postponed.push_back(deleteMe.release());
|
||||
} else {
|
||||
pxAppLog.Write(L"(AppIdleQueue%s) Dispatching event '%s'", action, deleteMe->GetClassInfo()->GetClassName());
|
||||
ProcessEvent(*deleteMe); // dereference to prevent auto-deletion by ProcessEvent
|
||||
}
|
||||
lock.Acquire();
|
||||
}
|
||||
pxThreadLog.Write(((pxThread*)((wxCommandEvent*)deleteMe.get())->GetClientData())->GetName(), L"Deletion postponed due to mutex or semaphore dependency.");
|
||||
postponed.push_back(deleteMe.release());
|
||||
}
|
||||
else
|
||||
{
|
||||
pxAppLog.Write(L"(AppIdleQueue%s) Dispatching event '%s'", action, deleteMe->GetClassInfo()->GetClassName());
|
||||
ProcessEvent(*deleteMe); // dereference to prevent auto-deletion by ProcessEvent
|
||||
}
|
||||
lock.Acquire();
|
||||
}
|
||||
|
||||
m_IdleEventQueue = postponed;
|
||||
if (!m_IdleEventQueue.empty())
|
||||
pxAppLog.Write(L"(AppIdleQueue%s) %d events postponed due to dependencies.", action, m_IdleEventQueue.size());
|
||||
m_IdleEventQueue = postponed;
|
||||
if (!m_IdleEventQueue.empty())
|
||||
pxAppLog.Write(L"(AppIdleQueue%s) %d events postponed due to dependencies.", action, m_IdleEventQueue.size());
|
||||
}
|
||||
|
||||
void wxAppWithHelpers::OnIdleEvent(wxIdleEvent &evt)
|
||||
void wxAppWithHelpers::OnIdleEvent(wxIdleEvent& evt)
|
||||
{
|
||||
m_IdleEventTimer.Stop();
|
||||
IdleEventDispatcher();
|
||||
m_IdleEventTimer.Stop();
|
||||
IdleEventDispatcher();
|
||||
}
|
||||
|
||||
void wxAppWithHelpers::OnIdleEventTimeout(wxTimerEvent &evt)
|
||||
void wxAppWithHelpers::OnIdleEventTimeout(wxTimerEvent& evt)
|
||||
{
|
||||
IdleEventDispatcher(L"[Timeout]");
|
||||
IdleEventDispatcher(L"[Timeout]");
|
||||
}
|
||||
|
||||
void wxAppWithHelpers::Ping()
|
||||
{
|
||||
pxThreadLog.Write(pxGetCurrentThreadName().c_str(), L"App Event Ping Requested.");
|
||||
pxThreadLog.Write(pxGetCurrentThreadName().c_str(), L"App Event Ping Requested.");
|
||||
|
||||
SynchronousActionState sync;
|
||||
pxActionEvent evt(sync);
|
||||
AddIdleEvent(evt);
|
||||
sync.WaitForResult();
|
||||
SynchronousActionState sync;
|
||||
pxActionEvent evt(sync);
|
||||
AddIdleEvent(evt);
|
||||
sync.WaitForResult();
|
||||
}
|
||||
|
||||
void wxAppWithHelpers::PostCommand(void *clientData, int evtType, int intParam, long longParam, const wxString &stringParam)
|
||||
void wxAppWithHelpers::PostCommand(void* clientData, int evtType, int intParam, long longParam, const wxString& stringParam)
|
||||
{
|
||||
wxCommandEvent evt(evtType);
|
||||
evt.SetClientData(clientData);
|
||||
evt.SetInt(intParam);
|
||||
evt.SetExtraLong(longParam);
|
||||
evt.SetString(stringParam);
|
||||
AddPendingEvent(evt);
|
||||
wxCommandEvent evt(evtType);
|
||||
evt.SetClientData(clientData);
|
||||
evt.SetInt(intParam);
|
||||
evt.SetExtraLong(longParam);
|
||||
evt.SetString(stringParam);
|
||||
AddPendingEvent(evt);
|
||||
}
|
||||
|
||||
void wxAppWithHelpers::PostCommand(int evtType, int intParam, long longParam, const wxString &stringParam)
|
||||
void wxAppWithHelpers::PostCommand(int evtType, int intParam, long longParam, const wxString& stringParam)
|
||||
{
|
||||
PostCommand(NULL, evtType, intParam, longParam, stringParam);
|
||||
PostCommand(NULL, evtType, intParam, longParam, stringParam);
|
||||
}
|
||||
|
||||
sptr wxAppWithHelpers::ProcessCommand(void *clientData, int evtType, int intParam, long longParam, const wxString &stringParam)
|
||||
sptr wxAppWithHelpers::ProcessCommand(void* clientData, int evtType, int intParam, long longParam, const wxString& stringParam)
|
||||
{
|
||||
SynchronousActionState sync;
|
||||
pxSynchronousCommandEvent evt(sync, evtType);
|
||||
SynchronousActionState sync;
|
||||
pxSynchronousCommandEvent evt(sync, evtType);
|
||||
|
||||
evt.SetClientData(clientData);
|
||||
evt.SetInt(intParam);
|
||||
evt.SetExtraLong(longParam);
|
||||
evt.SetString(stringParam);
|
||||
AddPendingEvent(evt);
|
||||
sync.WaitForResult();
|
||||
evt.SetClientData(clientData);
|
||||
evt.SetInt(intParam);
|
||||
evt.SetExtraLong(longParam);
|
||||
evt.SetString(stringParam);
|
||||
AddPendingEvent(evt);
|
||||
sync.WaitForResult();
|
||||
|
||||
return sync.return_value;
|
||||
return sync.return_value;
|
||||
}
|
||||
|
||||
sptr wxAppWithHelpers::ProcessCommand(int evtType, int intParam, long longParam, const wxString &stringParam)
|
||||
sptr wxAppWithHelpers::ProcessCommand(int evtType, int intParam, long longParam, const wxString& stringParam)
|
||||
{
|
||||
return ProcessCommand(NULL, evtType, intParam, longParam, stringParam);
|
||||
return ProcessCommand(NULL, evtType, intParam, longParam, stringParam);
|
||||
}
|
||||
|
||||
void wxAppWithHelpers::PostAction(const pxActionEvent &evt)
|
||||
void wxAppWithHelpers::PostAction(const pxActionEvent& evt)
|
||||
{
|
||||
PostEvent(evt);
|
||||
PostEvent(evt);
|
||||
}
|
||||
|
||||
void wxAppWithHelpers::ProcessAction(pxActionEvent &evt)
|
||||
void wxAppWithHelpers::ProcessAction(pxActionEvent& evt)
|
||||
{
|
||||
if (!wxThread::IsMain()) {
|
||||
SynchronousActionState sync;
|
||||
evt.SetSyncState(sync);
|
||||
AddPendingEvent(evt);
|
||||
sync.WaitForResult();
|
||||
} else
|
||||
evt._DoInvokeEvent();
|
||||
if (!wxThread::IsMain())
|
||||
{
|
||||
SynchronousActionState sync;
|
||||
evt.SetSyncState(sync);
|
||||
AddPendingEvent(evt);
|
||||
sync.WaitForResult();
|
||||
}
|
||||
else
|
||||
evt._DoInvokeEvent();
|
||||
}
|
||||
|
||||
|
||||
void wxAppWithHelpers::DeleteObject(BaseDeletableObject &obj)
|
||||
void wxAppWithHelpers::DeleteObject(BaseDeletableObject& obj)
|
||||
{
|
||||
pxAssert(!obj.IsBeingDeleted());
|
||||
wxCommandEvent evt(pxEvt_DeleteObject);
|
||||
evt.SetClientData((void *)&obj);
|
||||
AddIdleEvent(evt);
|
||||
pxAssert(!obj.IsBeingDeleted());
|
||||
wxCommandEvent evt(pxEvt_DeleteObject);
|
||||
evt.SetClientData((void*)&obj);
|
||||
AddIdleEvent(evt);
|
||||
}
|
||||
|
||||
void wxAppWithHelpers::DeleteThread(pxThread &obj)
|
||||
void wxAppWithHelpers::DeleteThread(pxThread& obj)
|
||||
{
|
||||
pxThreadLog.Write(obj.GetName(), L"Scheduling for deletion...");
|
||||
wxCommandEvent evt(pxEvt_DeleteThread);
|
||||
evt.SetClientData((void *)&obj);
|
||||
AddIdleEvent(evt);
|
||||
pxThreadLog.Write(obj.GetName(), L"Scheduling for deletion...");
|
||||
wxCommandEvent evt(pxEvt_DeleteThread);
|
||||
evt.SetClientData((void*)&obj);
|
||||
AddIdleEvent(evt);
|
||||
}
|
||||
|
||||
bool wxAppWithHelpers::OnInit()
|
||||
{
|
||||
Bind(pxEvt_SynchronousCommand, &wxAppWithHelpers::OnSynchronousCommand, this);
|
||||
Bind(pxEvt_InvokeAction, &wxAppWithHelpers::OnInvokeAction, this);
|
||||
Bind(pxEvt_SynchronousCommand, &wxAppWithHelpers::OnSynchronousCommand, this);
|
||||
Bind(pxEvt_InvokeAction, &wxAppWithHelpers::OnInvokeAction, this);
|
||||
|
||||
Bind(pxEvt_StartIdleEventTimer, &wxAppWithHelpers::OnStartIdleEventTimer, this);
|
||||
Bind(pxEvt_StartIdleEventTimer, &wxAppWithHelpers::OnStartIdleEventTimer, this);
|
||||
|
||||
Bind(pxEvt_DeleteObject, &wxAppWithHelpers::OnDeleteObject, this);
|
||||
Bind(pxEvt_DeleteThread, &wxAppWithHelpers::OnDeleteThread, this);
|
||||
Bind(pxEvt_DeleteObject, &wxAppWithHelpers::OnDeleteObject, this);
|
||||
Bind(pxEvt_DeleteThread, &wxAppWithHelpers::OnDeleteThread, this);
|
||||
|
||||
Bind(wxEVT_IDLE, &wxAppWithHelpers::OnIdleEvent, this);
|
||||
Bind(wxEVT_IDLE, &wxAppWithHelpers::OnIdleEvent, this);
|
||||
|
||||
Bind(wxEVT_TIMER, &wxAppWithHelpers::OnIdleEventTimeout, this, m_IdleEventTimer.GetId());
|
||||
Bind(wxEVT_TIMER, &wxAppWithHelpers::OnIdleEventTimeout, this, m_IdleEventTimer.GetId());
|
||||
|
||||
return _parent::OnInit();
|
||||
return _parent::OnInit();
|
||||
}
|
||||
|
||||
void wxAppWithHelpers::OnInvokeAction(pxActionEvent &evt)
|
||||
void wxAppWithHelpers::OnInvokeAction(pxActionEvent& evt)
|
||||
{
|
||||
evt._DoInvokeEvent(); // wow this is easy!
|
||||
evt._DoInvokeEvent(); // wow this is easy!
|
||||
}
|
||||
|
||||
void wxAppWithHelpers::OnDeleteObject(wxCommandEvent &evt)
|
||||
void wxAppWithHelpers::OnDeleteObject(wxCommandEvent& evt)
|
||||
{
|
||||
if (evt.GetClientData() == NULL)
|
||||
return;
|
||||
delete (BaseDeletableObject *)evt.GetClientData();
|
||||
if (evt.GetClientData() == NULL)
|
||||
return;
|
||||
delete (BaseDeletableObject*)evt.GetClientData();
|
||||
}
|
||||
|
||||
// In theory we create a Pcsx2App object which inherit from wxAppWithHelpers,
|
||||
|
@ -648,35 +674,36 @@ void wxAppWithHelpers::OnDeleteObject(wxCommandEvent &evt)
|
|||
// be called first. This constructor will build some wx objects (here wxTimer)
|
||||
// that require a trait. In others word, wxAppWithHelpers::CreateTraits will be
|
||||
// called instead
|
||||
wxAppTraits *wxAppWithHelpers::CreateTraits()
|
||||
wxAppTraits* wxAppWithHelpers::CreateTraits()
|
||||
{
|
||||
return new Pcsx2AppTraits;
|
||||
return new Pcsx2AppTraits;
|
||||
}
|
||||
|
||||
// Threads have their own deletion handler that propagates exceptions thrown by the thread to the UI.
|
||||
// (thus we have a fairly automatic threaded exception system!)
|
||||
void wxAppWithHelpers::OnDeleteThread(wxCommandEvent &evt)
|
||||
void wxAppWithHelpers::OnDeleteThread(wxCommandEvent& evt)
|
||||
{
|
||||
std::unique_ptr<pxThread> thr((pxThread *)evt.GetClientData());
|
||||
if (!thr) {
|
||||
pxThreadLog.Write(L"null", L"OnDeleteThread: NULL thread object received (and ignored).");
|
||||
return;
|
||||
}
|
||||
std::unique_ptr<pxThread> thr((pxThread*)evt.GetClientData());
|
||||
if (!thr)
|
||||
{
|
||||
pxThreadLog.Write(L"null", L"OnDeleteThread: NULL thread object received (and ignored).");
|
||||
return;
|
||||
}
|
||||
|
||||
pxThreadLog.Write(thr->GetName(), wxString(wxString(L"Thread object deleted successfully") + (thr->HasPendingException() ? L" [exception pending!]" : L"")).wc_str());
|
||||
thr->RethrowException();
|
||||
pxThreadLog.Write(thr->GetName(), wxString(wxString(L"Thread object deleted successfully") + (thr->HasPendingException() ? L" [exception pending!]" : L"")).wc_str());
|
||||
thr->RethrowException();
|
||||
}
|
||||
|
||||
wxAppWithHelpers::wxAppWithHelpers()
|
||||
: m_IdleEventTimer(this)
|
||||
: m_IdleEventTimer(this)
|
||||
{
|
||||
#ifdef __WXMSW__
|
||||
// This variable assignment ensures that MSVC links in the TLS setup stubs even in
|
||||
// full optimization builds. Without it, DLLs that use TLS won't work because the
|
||||
// FS segment register won't have been initialized by the main exe, due to tls_insurance
|
||||
// being optimized away >_< --air
|
||||
// This variable assignment ensures that MSVC links in the TLS setup stubs even in
|
||||
// full optimization builds. Without it, DLLs that use TLS won't work because the
|
||||
// FS segment register won't have been initialized by the main exe, due to tls_insurance
|
||||
// being optimized away >_< --air
|
||||
|
||||
static thread_local int tls_insurance = 0;
|
||||
tls_insurance = 1;
|
||||
static thread_local int tls_insurance = 0;
|
||||
tls_insurance = 1;
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -32,10 +32,10 @@ class pxSynchronousCommandEvent;
|
|||
|
||||
class ConsoleLogSource_App : public ConsoleLogSource
|
||||
{
|
||||
typedef ConsoleLogSource _parent;
|
||||
typedef ConsoleLogSource _parent;
|
||||
|
||||
public:
|
||||
ConsoleLogSource_App();
|
||||
ConsoleLogSource_App();
|
||||
};
|
||||
|
||||
extern ConsoleLogSource_App pxConLog_App;
|
||||
|
@ -49,97 +49,97 @@ extern ConsoleLogSource_App pxConLog_App;
|
|||
class ModalButtonPanel : public wxPanelWithHelpers
|
||||
{
|
||||
public:
|
||||
ModalButtonPanel(wxWindow *window, const MsgButtons &buttons);
|
||||
virtual ~ModalButtonPanel() = default;
|
||||
ModalButtonPanel(wxWindow* window, const MsgButtons& buttons);
|
||||
virtual ~ModalButtonPanel() = default;
|
||||
|
||||
virtual void AddActionButton(wxWindowID id);
|
||||
virtual void AddCustomButton(wxWindowID id, const wxString &label);
|
||||
virtual void AddActionButton(wxWindowID id);
|
||||
virtual void AddCustomButton(wxWindowID id, const wxString& label);
|
||||
|
||||
virtual void OnActionButtonClicked(wxCommandEvent &evt);
|
||||
virtual void OnActionButtonClicked(wxCommandEvent& evt);
|
||||
};
|
||||
|
||||
typedef std::list<wxEvent *> wxEventList;
|
||||
typedef std::list<wxEvent*> wxEventList;
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// wxAppWithHelpers
|
||||
// --------------------------------------------------------------------------------------
|
||||
class wxAppWithHelpers : public wxApp
|
||||
{
|
||||
typedef wxApp _parent;
|
||||
typedef wxApp _parent;
|
||||
|
||||
wxDECLARE_DYNAMIC_CLASS(wxAppWithHelpers);
|
||||
wxDECLARE_DYNAMIC_CLASS(wxAppWithHelpers);
|
||||
|
||||
protected:
|
||||
wxEventList m_IdleEventQueue;
|
||||
Threading::MutexRecursive m_IdleEventMutex;
|
||||
wxTimer m_IdleEventTimer;
|
||||
wxEventList m_IdleEventQueue;
|
||||
Threading::MutexRecursive m_IdleEventMutex;
|
||||
wxTimer m_IdleEventTimer;
|
||||
|
||||
public:
|
||||
wxAppWithHelpers();
|
||||
virtual ~wxAppWithHelpers() {}
|
||||
wxAppWithHelpers();
|
||||
virtual ~wxAppWithHelpers() {}
|
||||
|
||||
wxAppTraits *CreateTraits();
|
||||
wxAppTraits* CreateTraits();
|
||||
|
||||
void CleanUp();
|
||||
void CleanUp();
|
||||
|
||||
void DeleteObject(BaseDeletableObject &obj);
|
||||
void DeleteObject(BaseDeletableObject *obj)
|
||||
{
|
||||
if (obj == NULL)
|
||||
return;
|
||||
DeleteObject(*obj);
|
||||
}
|
||||
void DeleteObject(BaseDeletableObject& obj);
|
||||
void DeleteObject(BaseDeletableObject* obj)
|
||||
{
|
||||
if (obj == NULL)
|
||||
return;
|
||||
DeleteObject(*obj);
|
||||
}
|
||||
|
||||
void DeleteThread(Threading::pxThread &obj);
|
||||
void DeleteThread(Threading::pxThread *obj)
|
||||
{
|
||||
if (obj == NULL)
|
||||
return;
|
||||
DeleteThread(*obj);
|
||||
}
|
||||
void DeleteThread(Threading::pxThread& obj);
|
||||
void DeleteThread(Threading::pxThread* obj)
|
||||
{
|
||||
if (obj == NULL)
|
||||
return;
|
||||
DeleteThread(*obj);
|
||||
}
|
||||
|
||||
void PostCommand(void *clientData, int evtType, int intParam = 0, long longParam = 0, const wxString &stringParam = wxEmptyString);
|
||||
void PostCommand(int evtType, int intParam = 0, long longParam = 0, const wxString &stringParam = wxEmptyString);
|
||||
void PostMethod(FnType_Void *method);
|
||||
void PostIdleMethod(FnType_Void *method);
|
||||
void ProcessMethod(FnType_Void *method);
|
||||
void PostCommand(void* clientData, int evtType, int intParam = 0, long longParam = 0, const wxString& stringParam = wxEmptyString);
|
||||
void PostCommand(int evtType, int intParam = 0, long longParam = 0, const wxString& stringParam = wxEmptyString);
|
||||
void PostMethod(FnType_Void* method);
|
||||
void PostIdleMethod(FnType_Void* method);
|
||||
void ProcessMethod(FnType_Void* method);
|
||||
|
||||
bool Rpc_TryInvoke(FnType_Void *method);
|
||||
bool Rpc_TryInvokeAsync(FnType_Void *method);
|
||||
bool Rpc_TryInvoke(FnType_Void* method);
|
||||
bool Rpc_TryInvokeAsync(FnType_Void* method);
|
||||
|
||||
sptr ProcessCommand(void *clientData, int evtType, int intParam = 0, long longParam = 0, const wxString &stringParam = wxEmptyString);
|
||||
sptr ProcessCommand(int evtType, int intParam = 0, long longParam = 0, const wxString &stringParam = wxEmptyString);
|
||||
sptr ProcessCommand(void* clientData, int evtType, int intParam = 0, long longParam = 0, const wxString& stringParam = wxEmptyString);
|
||||
sptr ProcessCommand(int evtType, int intParam = 0, long longParam = 0, const wxString& stringParam = wxEmptyString);
|
||||
|
||||
void ProcessAction(pxActionEvent &evt);
|
||||
void PostAction(const pxActionEvent &evt);
|
||||
void ProcessAction(pxActionEvent& evt);
|
||||
void PostAction(const pxActionEvent& evt);
|
||||
|
||||
void Ping();
|
||||
bool OnInit();
|
||||
//int OnExit();
|
||||
void Ping();
|
||||
bool OnInit();
|
||||
//int OnExit();
|
||||
|
||||
void AddIdleEvent(const wxEvent &evt);
|
||||
void AddIdleEvent(const wxEvent& evt);
|
||||
|
||||
void PostEvent(const wxEvent &evt);
|
||||
bool ProcessEvent(wxEvent &evt);
|
||||
bool ProcessEvent(wxEvent *evt);
|
||||
void PostEvent(const wxEvent& evt);
|
||||
bool ProcessEvent(wxEvent& evt);
|
||||
bool ProcessEvent(wxEvent* evt);
|
||||
|
||||
bool ProcessEvent(pxActionEvent &evt);
|
||||
bool ProcessEvent(pxActionEvent *evt);
|
||||
bool ProcessEvent(pxActionEvent& evt);
|
||||
bool ProcessEvent(pxActionEvent* evt);
|
||||
|
||||
protected:
|
||||
void IdleEventDispatcher(const wxChar *action = wxEmptyString);
|
||||
void IdleEventDispatcher(const wxChar* action = wxEmptyString);
|
||||
|
||||
void OnIdleEvent(wxIdleEvent &evt);
|
||||
void OnStartIdleEventTimer(wxCommandEvent &evt);
|
||||
void OnIdleEventTimeout(wxTimerEvent &evt);
|
||||
void OnDeleteObject(wxCommandEvent &evt);
|
||||
void OnDeleteThread(wxCommandEvent &evt);
|
||||
void OnSynchronousCommand(pxSynchronousCommandEvent &evt);
|
||||
void OnInvokeAction(pxActionEvent &evt);
|
||||
void OnIdleEvent(wxIdleEvent& evt);
|
||||
void OnStartIdleEventTimer(wxCommandEvent& evt);
|
||||
void OnIdleEventTimeout(wxTimerEvent& evt);
|
||||
void OnDeleteObject(wxCommandEvent& evt);
|
||||
void OnDeleteThread(wxCommandEvent& evt);
|
||||
void OnSynchronousCommand(pxSynchronousCommandEvent& evt);
|
||||
void OnInvokeAction(pxActionEvent& evt);
|
||||
};
|
||||
|
||||
namespace Msgbox
|
||||
{
|
||||
extern int ShowModal(BaseMessageBoxEvent &evt);
|
||||
extern int ShowModal(const wxString &title, const wxString &content, const MsgButtons &buttons);
|
||||
}
|
||||
extern int ShowModal(BaseMessageBoxEvent& evt);
|
||||
extern int ShowModal(const wxString& title, const wxString& content, const MsgButtons& buttons);
|
||||
} // namespace Msgbox
|
||||
|
|
|
@ -26,11 +26,11 @@
|
|||
// which require wxCore, see wxGuiTools.h
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
extern void pxExplore(const wxString &path);
|
||||
extern void pxExplore(const char *path);
|
||||
extern void pxExplore(const wxString& path);
|
||||
extern void pxExplore(const char* path);
|
||||
|
||||
extern void pxLaunch(const wxString &path);
|
||||
extern void pxLaunch(const char *path);
|
||||
extern void pxLaunch(const wxString& path);
|
||||
extern void pxLaunch(const char* path);
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// wxDoNotLogInThisScope
|
||||
|
@ -44,28 +44,28 @@ extern void pxLaunch(const char *path);
|
|||
//
|
||||
class wxDoNotLogInThisScope
|
||||
{
|
||||
DeclareNoncopyableObject(wxDoNotLogInThisScope);
|
||||
DeclareNoncopyableObject(wxDoNotLogInThisScope);
|
||||
|
||||
protected:
|
||||
bool m_prev;
|
||||
bool m_prev;
|
||||
|
||||
public:
|
||||
wxDoNotLogInThisScope()
|
||||
{
|
||||
m_prev = wxLog::EnableLogging(false);
|
||||
}
|
||||
wxDoNotLogInThisScope()
|
||||
{
|
||||
m_prev = wxLog::EnableLogging(false);
|
||||
}
|
||||
|
||||
virtual ~wxDoNotLogInThisScope()
|
||||
{
|
||||
wxLog::EnableLogging(m_prev);
|
||||
}
|
||||
virtual ~wxDoNotLogInThisScope()
|
||||
{
|
||||
wxLog::EnableLogging(m_prev);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
extern wxString pxReadLine(wxInputStream &input);
|
||||
extern void pxReadLine(wxInputStream &input, wxString &dest);
|
||||
extern void pxReadLine(wxInputStream &input, wxString &dest, std::string &intermed);
|
||||
extern bool pxReadLine(wxInputStream &input, std::string &dest);
|
||||
extern void pxWriteLine(wxOutputStream &output);
|
||||
extern void pxWriteLine(wxOutputStream &output, const wxString &text);
|
||||
extern void pxWriteMultiline(wxOutputStream &output, const wxString &src);
|
||||
extern wxString pxReadLine(wxInputStream& input);
|
||||
extern void pxReadLine(wxInputStream& input, wxString& dest);
|
||||
extern void pxReadLine(wxInputStream& input, wxString& dest, std::string& intermed);
|
||||
extern bool pxReadLine(wxInputStream& input, std::string& dest);
|
||||
extern void pxWriteLine(wxOutputStream& output);
|
||||
extern void pxWriteLine(wxOutputStream& output, const wxString& text);
|
||||
extern void pxWriteMultiline(wxOutputStream& output, const wxString& src);
|
||||
|
|
|
@ -22,171 +22,173 @@
|
|||
#include <wx/display.h>
|
||||
|
||||
const pxAlignmentType
|
||||
pxCentre = {pxAlignmentType::Center}, // Horizontal centered alignment
|
||||
pxCenter = pxCentre,
|
||||
pxMiddle = {pxAlignmentType::Middle}, // vertical centered alignment
|
||||
pxCentre = {pxAlignmentType::Center}, // Horizontal centered alignment
|
||||
pxCenter = pxCentre,
|
||||
pxMiddle = {pxAlignmentType::Middle}, // vertical centered alignment
|
||||
|
||||
pxAlignLeft = {pxAlignmentType::Left},
|
||||
pxAlignRight = {pxAlignmentType::Right},
|
||||
pxAlignTop = {pxAlignmentType::Top},
|
||||
pxAlignBottom = {pxAlignmentType::Bottom};
|
||||
pxAlignLeft = {pxAlignmentType::Left},
|
||||
pxAlignRight = {pxAlignmentType::Right},
|
||||
pxAlignTop = {pxAlignmentType::Top},
|
||||
pxAlignBottom = {pxAlignmentType::Bottom};
|
||||
|
||||
const pxStretchType
|
||||
pxShrink = {pxStretchType::Shrink},
|
||||
pxExpand = {pxStretchType::Expand},
|
||||
pxShaped = {pxStretchType::Shaped},
|
||||
pxReserveHidden = {pxStretchType::ReserveHidden},
|
||||
pxFixedMinimum = {pxStretchType::FixedMinimum};
|
||||
pxShrink = {pxStretchType::Shrink},
|
||||
pxExpand = {pxStretchType::Expand},
|
||||
pxShaped = {pxStretchType::Shaped},
|
||||
pxReserveHidden = {pxStretchType::ReserveHidden},
|
||||
pxFixedMinimum = {pxStretchType::FixedMinimum};
|
||||
|
||||
wxSizerFlags pxAlignmentType::Apply(wxSizerFlags flags) const
|
||||
{
|
||||
switch (intval) {
|
||||
case Centre:
|
||||
flags.Align(flags.GetFlags() | wxALIGN_CENTRE_HORIZONTAL);
|
||||
break;
|
||||
switch (intval)
|
||||
{
|
||||
case Centre:
|
||||
flags.Align(flags.GetFlags() | wxALIGN_CENTRE_HORIZONTAL);
|
||||
break;
|
||||
|
||||
case Middle:
|
||||
flags.Align(flags.GetFlags() | wxALIGN_CENTRE_VERTICAL);
|
||||
break;
|
||||
case Middle:
|
||||
flags.Align(flags.GetFlags() | wxALIGN_CENTRE_VERTICAL);
|
||||
break;
|
||||
|
||||
case Left:
|
||||
flags.Left();
|
||||
break;
|
||||
case Left:
|
||||
flags.Left();
|
||||
break;
|
||||
|
||||
case Right:
|
||||
flags.Right();
|
||||
break;
|
||||
case Right:
|
||||
flags.Right();
|
||||
break;
|
||||
|
||||
case Top:
|
||||
flags.Top();
|
||||
break;
|
||||
case Top:
|
||||
flags.Top();
|
||||
break;
|
||||
|
||||
case Bottom:
|
||||
flags.Bottom();
|
||||
break;
|
||||
}
|
||||
return flags;
|
||||
case Bottom:
|
||||
flags.Bottom();
|
||||
break;
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
wxSizerFlags pxStretchType::Apply(wxSizerFlags flags) const
|
||||
{
|
||||
switch (intval) {
|
||||
case Shrink:
|
||||
//pxFail( "wxSHRINK is an ignored stretch flag." );
|
||||
break;
|
||||
switch (intval)
|
||||
{
|
||||
case Shrink:
|
||||
//pxFail( "wxSHRINK is an ignored stretch flag." );
|
||||
break;
|
||||
|
||||
case Expand:
|
||||
flags.Expand();
|
||||
break;
|
||||
case Expand:
|
||||
flags.Expand();
|
||||
break;
|
||||
|
||||
case Shaped:
|
||||
flags.Shaped();
|
||||
break;
|
||||
case Shaped:
|
||||
flags.Shaped();
|
||||
break;
|
||||
|
||||
case ReserveHidden:
|
||||
flags.ReserveSpaceEvenIfHidden();
|
||||
break;
|
||||
case ReserveHidden:
|
||||
flags.ReserveSpaceEvenIfHidden();
|
||||
break;
|
||||
|
||||
case FixedMinimum:
|
||||
flags.FixedMinSize();
|
||||
break;
|
||||
case FixedMinimum:
|
||||
flags.FixedMinSize();
|
||||
break;
|
||||
|
||||
//case Tile:
|
||||
// pxAssert( "pxTile is an unsupported stretch tag (ignored)." );
|
||||
//break;
|
||||
}
|
||||
return flags;
|
||||
//case Tile:
|
||||
// pxAssert( "pxTile is an unsupported stretch tag (ignored)." );
|
||||
//break;
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
wxSizerFlags operator&(const wxSizerFlags &_flgs, const wxSizerFlags &_flgs2)
|
||||
wxSizerFlags operator&(const wxSizerFlags& _flgs, const wxSizerFlags& _flgs2)
|
||||
{
|
||||
//return align.Apply( _flgs );
|
||||
wxSizerFlags retval;
|
||||
//return align.Apply( _flgs );
|
||||
wxSizerFlags retval;
|
||||
|
||||
uint allflags = (_flgs.GetFlags() | _flgs2.GetFlags());
|
||||
uint allflags = (_flgs.GetFlags() | _flgs2.GetFlags());
|
||||
|
||||
retval.Align(allflags & wxALIGN_MASK);
|
||||
if (allflags & wxEXPAND)
|
||||
retval.Expand();
|
||||
if (allflags & wxSHAPED)
|
||||
retval.Shaped();
|
||||
if (allflags & wxFIXED_MINSIZE)
|
||||
retval.FixedMinSize();
|
||||
if (allflags & wxRESERVE_SPACE_EVEN_IF_HIDDEN)
|
||||
retval.ReserveSpaceEvenIfHidden();
|
||||
retval.Align(allflags & wxALIGN_MASK);
|
||||
if (allflags & wxEXPAND)
|
||||
retval.Expand();
|
||||
if (allflags & wxSHAPED)
|
||||
retval.Shaped();
|
||||
if (allflags & wxFIXED_MINSIZE)
|
||||
retval.FixedMinSize();
|
||||
if (allflags & wxRESERVE_SPACE_EVEN_IF_HIDDEN)
|
||||
retval.ReserveSpaceEvenIfHidden();
|
||||
|
||||
// Compounding borders is probably a fair approach:
|
||||
retval.Border(allflags & wxALL, _flgs.GetBorderInPixels() + _flgs2.GetBorderInPixels());
|
||||
// Compounding borders is probably a fair approach:
|
||||
retval.Border(allflags & wxALL, _flgs.GetBorderInPixels() + _flgs2.GetBorderInPixels());
|
||||
|
||||
// Compounding proportions works as well, I figure.
|
||||
retval.Proportion(_flgs.GetProportion() + _flgs2.GetProportion());
|
||||
// Compounding proportions works as well, I figure.
|
||||
retval.Proportion(_flgs.GetProportion() + _flgs2.GetProportion());
|
||||
|
||||
return retval;
|
||||
return retval;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Reference/Handle versions!
|
||||
|
||||
void operator+=(wxSizer &target, wxWindow *src)
|
||||
void operator+=(wxSizer& target, wxWindow* src)
|
||||
{
|
||||
target.Add(src);
|
||||
target.Add(src);
|
||||
}
|
||||
|
||||
void operator+=(wxSizer &target, wxSizer *src)
|
||||
void operator+=(wxSizer& target, wxSizer* src)
|
||||
{
|
||||
target.Add(src);
|
||||
target.Add(src);
|
||||
}
|
||||
|
||||
void operator+=(wxSizer &target, wxWindow &src)
|
||||
void operator+=(wxSizer& target, wxWindow& src)
|
||||
{
|
||||
target.Add(&src);
|
||||
target.Add(&src);
|
||||
}
|
||||
|
||||
void operator+=(wxSizer &target, wxSizer &src)
|
||||
void operator+=(wxSizer& target, wxSizer& src)
|
||||
{
|
||||
target.Add(&src);
|
||||
target.Add(&src);
|
||||
}
|
||||
|
||||
void operator+=(wxSizer &target, int spacer)
|
||||
void operator+=(wxSizer& target, int spacer)
|
||||
{
|
||||
target.AddSpacer(spacer);
|
||||
target.AddSpacer(spacer);
|
||||
}
|
||||
|
||||
void operator+=(wxSizer &target, const pxStretchSpacer &spacer)
|
||||
void operator+=(wxSizer& target, const pxStretchSpacer& spacer)
|
||||
{
|
||||
target.AddStretchSpacer(spacer.proportion);
|
||||
target.AddStretchSpacer(spacer.proportion);
|
||||
}
|
||||
|
||||
void operator+=(wxWindow &target, int spacer)
|
||||
void operator+=(wxWindow& target, int spacer)
|
||||
{
|
||||
if (!pxAssert(target.GetSizer() != NULL))
|
||||
return;
|
||||
target.GetSizer()->AddSpacer(spacer);
|
||||
if (!pxAssert(target.GetSizer() != NULL))
|
||||
return;
|
||||
target.GetSizer()->AddSpacer(spacer);
|
||||
}
|
||||
|
||||
void operator+=(wxWindow &target, const pxStretchSpacer &spacer)
|
||||
void operator+=(wxWindow& target, const pxStretchSpacer& spacer)
|
||||
{
|
||||
if (!pxAssert(target.GetSizer() != NULL))
|
||||
return;
|
||||
target.GetSizer()->AddStretchSpacer(spacer.proportion);
|
||||
if (!pxAssert(target.GetSizer() != NULL))
|
||||
return;
|
||||
target.GetSizer()->AddStretchSpacer(spacer.proportion);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Pointer versions! (note that C++ requires one of the two operator params be a
|
||||
// "poper" object type (non-pointer), so that's why there's only a couple of these.
|
||||
|
||||
void operator+=(wxSizer *target, wxWindow &src)
|
||||
void operator+=(wxSizer* target, wxWindow& src)
|
||||
{
|
||||
if (!pxAssert(target != NULL))
|
||||
return;
|
||||
target->Add(&src);
|
||||
if (!pxAssert(target != NULL))
|
||||
return;
|
||||
target->Add(&src);
|
||||
}
|
||||
|
||||
void operator+=(wxSizer *target, wxSizer &src)
|
||||
void operator+=(wxSizer* target, wxSizer& src)
|
||||
{
|
||||
if (!pxAssert(target != NULL))
|
||||
return;
|
||||
target->Add(&src);
|
||||
if (!pxAssert(target != NULL))
|
||||
return;
|
||||
target->Add(&src);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -194,23 +196,23 @@ void operator+=(wxSizer *target, wxSizer &src)
|
|||
// Returns FALSE if the window position is considered invalid, which means that it's title
|
||||
// bar is most likely not easily grabble. Such a window should be moved to a valid or
|
||||
// default position.
|
||||
bool pxIsValidWindowPosition(const wxWindow &window, const wxPoint &windowPos)
|
||||
bool pxIsValidWindowPosition(const wxWindow& window, const wxPoint& windowPos)
|
||||
{
|
||||
// The height of the window is only revlevant to the height of a title bar, which is
|
||||
// all we need visible for the user to be able to drag the window into view. But
|
||||
// there's no way to get that info from wx, so we'll just have to guesstimate...
|
||||
// The height of the window is only revlevant to the height of a title bar, which is
|
||||
// all we need visible for the user to be able to drag the window into view. But
|
||||
// there's no way to get that info from wx, so we'll just have to guesstimate...
|
||||
|
||||
const wxSize sizeMatters(window.GetSize().GetWidth(), 32);
|
||||
const wxSize sizeMatters(window.GetSize().GetWidth(), 32);
|
||||
|
||||
for (unsigned int i = 0; i < wxDisplay::GetCount(); i++)
|
||||
{
|
||||
const auto rect = wxDisplay(i).GetGeometry();
|
||||
for (unsigned int i = 0; i < wxDisplay::GetCount(); i++)
|
||||
{
|
||||
const auto rect = wxDisplay(i).GetGeometry();
|
||||
|
||||
if (rect.Contains(wxRect(windowPos, sizeMatters)))
|
||||
return true;
|
||||
}
|
||||
if (rect.Contains(wxRect(windowPos, sizeMatters)))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Retrieves the area of the screen, which can be used to enforce a valid zone for
|
||||
|
@ -218,7 +220,7 @@ bool pxIsValidWindowPosition(const wxWindow &window, const wxPoint &windowPos)
|
|||
// is the resolution of the desktop).
|
||||
wxRect wxGetDisplayArea()
|
||||
{
|
||||
return wxRect(wxPoint(), wxGetDisplaySize());
|
||||
return wxRect(wxPoint(), wxGetDisplaySize());
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -234,17 +236,17 @@ wxRect wxGetDisplayArea()
|
|||
//
|
||||
wxSizerFlags pxSizerFlags::StdSpace()
|
||||
{
|
||||
return wxSizerFlags().Border(wxALL, StdPadding);
|
||||
return wxSizerFlags().Border(wxALL, StdPadding);
|
||||
}
|
||||
|
||||
wxSizerFlags pxSizerFlags::StdCenter()
|
||||
{
|
||||
return wxSizerFlags().Align(wxALIGN_CENTER).DoubleBorder();
|
||||
return wxSizerFlags().Align(wxALIGN_CENTER).DoubleBorder();
|
||||
}
|
||||
|
||||
wxSizerFlags pxSizerFlags::StdExpand()
|
||||
{
|
||||
return StdSpace().Expand();
|
||||
return StdSpace().Expand();
|
||||
}
|
||||
|
||||
// A good sizer flags setting for top-level static boxes or top-level picture boxes.
|
||||
|
@ -252,7 +254,7 @@ wxSizerFlags pxSizerFlags::StdExpand()
|
|||
// manually by using a spacer.
|
||||
wxSizerFlags pxSizerFlags::TopLevelBox()
|
||||
{
|
||||
return pxBorder(wxLEFT | wxBOTTOM | wxRIGHT, StdPadding).Expand();
|
||||
return pxBorder(wxLEFT | wxBOTTOM | wxRIGHT, StdPadding).Expand();
|
||||
}
|
||||
|
||||
// Flags intended for use on grouped StaticBox controls. These flags are ideal for
|
||||
|
@ -261,9 +263,9 @@ wxSizerFlags pxSizerFlags::TopLevelBox()
|
|||
// "tight").
|
||||
wxSizerFlags pxSizerFlags::SubGroup()
|
||||
{
|
||||
// Groups look better with a slightly smaller margin than standard.
|
||||
// (basically this accounts for the group's frame)
|
||||
return pxBorder(wxLEFT | wxBOTTOM | wxRIGHT, StdPadding - 2).Expand();
|
||||
// Groups look better with a slightly smaller margin than standard.
|
||||
// (basically this accounts for the group's frame)
|
||||
return pxBorder(wxLEFT | wxBOTTOM | wxRIGHT, StdPadding - 2).Expand();
|
||||
}
|
||||
|
||||
// This force-aligns the std button sizer to the right, where (at least) us win32 platform
|
||||
|
@ -271,20 +273,20 @@ wxSizerFlags pxSizerFlags::SubGroup()
|
|||
// just because it's *not* where win32 sticks it. Too bad!
|
||||
wxSizerFlags pxSizerFlags::StdButton()
|
||||
{
|
||||
return pxBorder().Align(wxALIGN_RIGHT);
|
||||
return pxBorder().Align(wxALIGN_RIGHT);
|
||||
}
|
||||
|
||||
wxSizerFlags pxSizerFlags::Checkbox()
|
||||
{
|
||||
return StdExpand();
|
||||
return StdExpand();
|
||||
}
|
||||
|
||||
void pxSizerFlags::SetBestPadding()
|
||||
{
|
||||
if (wxSystemSettings::GetMetric(wxSYS_SCREEN_X) > 1024 && wxSystemSettings::GetMetric(wxSYS_SCREEN_Y) > 864)
|
||||
StdPadding = 4;
|
||||
else
|
||||
StdPadding = 1;
|
||||
if (wxSystemSettings::GetMetric(wxSYS_SCREEN_X) > 1024 && wxSystemSettings::GetMetric(wxSYS_SCREEN_Y) > 864)
|
||||
StdPadding = 4;
|
||||
else
|
||||
StdPadding = 1;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -293,44 +295,44 @@ void pxSizerFlags::SetBestPadding()
|
|||
|
||||
static bool is_cjk_char(const uint ch)
|
||||
{
|
||||
/**
|
||||
/**
|
||||
* You can check these range at http://unicode.org/charts/
|
||||
* see the "East Asian Scripts" part.
|
||||
* Notice that not all characters in that part is still in use today, so don't list them all here.
|
||||
*/
|
||||
|
||||
// FIXME: add range from Japanese-specific and Korean-specific section if you know the
|
||||
// characters are used today.
|
||||
// FIXME: add range from Japanese-specific and Korean-specific section if you know the
|
||||
// characters are used today.
|
||||
|
||||
if (ch < 0x2e80)
|
||||
return false; // shortcut for common non-CJK
|
||||
if (ch < 0x2e80)
|
||||
return false; // shortcut for common non-CJK
|
||||
|
||||
return
|
||||
// Han Ideographs: all except Supplement
|
||||
(ch >= 0x4e00 && ch < 0x9fcf) ||
|
||||
(ch >= 0x3400 && ch < 0x4dbf) ||
|
||||
(ch >= 0x20000 && ch < 0x2a6df) ||
|
||||
(ch >= 0xf900 && ch < 0xfaff) ||
|
||||
(ch >= 0x3190 && ch < 0x319f) ||
|
||||
return
|
||||
// Han Ideographs: all except Supplement
|
||||
(ch >= 0x4e00 && ch < 0x9fcf) ||
|
||||
(ch >= 0x3400 && ch < 0x4dbf) ||
|
||||
(ch >= 0x20000 && ch < 0x2a6df) ||
|
||||
(ch >= 0xf900 && ch < 0xfaff) ||
|
||||
(ch >= 0x3190 && ch < 0x319f) ||
|
||||
|
||||
// Radicals: all except Ideographic Description
|
||||
(ch >= 0x2e80 && ch < 0x2eff) ||
|
||||
(ch >= 0x2f00 && ch < 0x2fdf) ||
|
||||
(ch >= 0x31c0 && ch < 0x31ef) ||
|
||||
// Radicals: all except Ideographic Description
|
||||
(ch >= 0x2e80 && ch < 0x2eff) ||
|
||||
(ch >= 0x2f00 && ch < 0x2fdf) ||
|
||||
(ch >= 0x31c0 && ch < 0x31ef) ||
|
||||
|
||||
// Chinese-specific: Bopomofo
|
||||
(ch >= 0x3000 && ch < 0x303f) ||
|
||||
// Chinese-specific: Bopomofo
|
||||
(ch >= 0x3000 && ch < 0x303f) ||
|
||||
|
||||
// Japanese-specific: Halfwidth Katakana
|
||||
(ch >= 0xff00 && ch < 0xffef) ||
|
||||
// Japanese-specific: Halfwidth Katakana
|
||||
(ch >= 0xff00 && ch < 0xffef) ||
|
||||
|
||||
// Japanese-specific: Hiragana, Katakana
|
||||
(ch >= 0x3040 && ch <= 0x309f) ||
|
||||
(ch >= 0x30a0 && ch <= 0x30ff) ||
|
||||
// Japanese-specific: Hiragana, Katakana
|
||||
(ch >= 0x3040 && ch <= 0x309f) ||
|
||||
(ch >= 0x30a0 && ch <= 0x30ff) ||
|
||||
|
||||
// Korean-specific: Hangul Syllables, Halfwidth Jamo
|
||||
(ch >= 0xac00 && ch < 0xd7af) ||
|
||||
(ch >= 0xff00 && ch < 0xffef);
|
||||
// Korean-specific: Hangul Syllables, Halfwidth Jamo
|
||||
(ch >= 0xac00 && ch < 0xd7af) ||
|
||||
(ch >= 0xff00 && ch < 0xffef);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -350,7 +352,7 @@ static bool is_cjk_char(const uint ch)
|
|||
*/
|
||||
static bool no_break_after(const uint ch)
|
||||
{
|
||||
// clang-format off
|
||||
// clang-format off
|
||||
switch (ch) {
|
||||
/**
|
||||
* don't break after these Japanese/Chinese characters
|
||||
|
@ -366,14 +368,14 @@ static bool no_break_after(const uint ch)
|
|||
|
||||
return true;
|
||||
}
|
||||
// clang-format on
|
||||
// clang-format on
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool no_break_before(const uint ch)
|
||||
{
|
||||
// clang-format off
|
||||
// clang-format off
|
||||
switch (ch) {
|
||||
/**
|
||||
* don't break before these Japanese characters
|
||||
|
@ -403,84 +405,94 @@ static bool no_break_before(const uint ch)
|
|||
|
||||
return true;
|
||||
}
|
||||
// clang-format on
|
||||
// clang-format on
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
pxTextWrapperBase &pxTextWrapperBase::Wrap(const wxWindow &win, const wxString &text, int widthMax)
|
||||
pxTextWrapperBase& pxTextWrapperBase::Wrap(const wxWindow& win, const wxString& text, int widthMax)
|
||||
{
|
||||
if (text.empty())
|
||||
return *this;
|
||||
if (text.empty())
|
||||
return *this;
|
||||
|
||||
bool wasWrapped = false;
|
||||
bool wasWrapped = false;
|
||||
|
||||
wxString line;
|
||||
line.reserve(text.length() + 12);
|
||||
wxString line;
|
||||
line.reserve(text.length() + 12);
|
||||
|
||||
wxString::const_iterator lastSpace = text.end();
|
||||
wxString::const_iterator lineStart = text.begin();
|
||||
for (wxString::const_iterator p = lineStart;; ++p) {
|
||||
if (IsStartOfNewLine()) {
|
||||
OnNewLine();
|
||||
wxString::const_iterator lastSpace = text.end();
|
||||
wxString::const_iterator lineStart = text.begin();
|
||||
for (wxString::const_iterator p = lineStart;; ++p)
|
||||
{
|
||||
if (IsStartOfNewLine())
|
||||
{
|
||||
OnNewLine();
|
||||
|
||||
lastSpace = text.end();
|
||||
lineStart = p;
|
||||
lastSpace = text.end();
|
||||
lineStart = p;
|
||||
|
||||
if (wasWrapped)
|
||||
line = m_indent;
|
||||
else
|
||||
line.clear();
|
||||
}
|
||||
if (wasWrapped)
|
||||
line = m_indent;
|
||||
else
|
||||
line.clear();
|
||||
}
|
||||
|
||||
if (p == text.end() || *p == L'\n') {
|
||||
wasWrapped = false;
|
||||
DoOutputLine(line);
|
||||
if (p == text.end() || *p == L'\n')
|
||||
{
|
||||
wasWrapped = false;
|
||||
DoOutputLine(line);
|
||||
|
||||
if (p == text.end())
|
||||
break;
|
||||
} else { // not EOL
|
||||
if (is_cjk_char(*p)) {
|
||||
if (!no_break_before(*p)) {
|
||||
if (p == lineStart || !no_break_after(*(p - 1)))
|
||||
lastSpace = p;
|
||||
}
|
||||
} else if (*p == L' ' || *p == L',' || *p == L'/')
|
||||
lastSpace = p;
|
||||
if (p == text.end())
|
||||
break;
|
||||
}
|
||||
else
|
||||
{ // not EOL
|
||||
if (is_cjk_char(*p))
|
||||
{
|
||||
if (!no_break_before(*p))
|
||||
{
|
||||
if (p == lineStart || !no_break_after(*(p - 1)))
|
||||
lastSpace = p;
|
||||
}
|
||||
}
|
||||
else if (*p == L' ' || *p == L',' || *p == L'/')
|
||||
lastSpace = p;
|
||||
|
||||
line += *p;
|
||||
line += *p;
|
||||
|
||||
if (widthMax >= 0 && lastSpace != text.end()) {
|
||||
int width;
|
||||
win.GetTextExtent(line, &width, NULL);
|
||||
if (widthMax >= 0 && lastSpace != text.end())
|
||||
{
|
||||
int width;
|
||||
win.GetTextExtent(line, &width, NULL);
|
||||
|
||||
if (width > widthMax) {
|
||||
wasWrapped = true;
|
||||
if (width > widthMax)
|
||||
{
|
||||
wasWrapped = true;
|
||||
|
||||
// remove the last word from this line
|
||||
line.erase(lastSpace - lineStart, p + 1 - lineStart);
|
||||
DoOutputLine(line);
|
||||
// remove the last word from this line
|
||||
line.erase(lastSpace - lineStart, p + 1 - lineStart);
|
||||
DoOutputLine(line);
|
||||
|
||||
// go back to the last word of this line which we didn't
|
||||
// output yet
|
||||
p = lastSpace;
|
||||
// go back to the last word of this line which we didn't
|
||||
// output yet
|
||||
p = lastSpace;
|
||||
|
||||
if (*p != L' ')
|
||||
p--;
|
||||
}
|
||||
}
|
||||
//else: no wrapping at all or impossible to wrap
|
||||
}
|
||||
}
|
||||
if (*p != L' ')
|
||||
p--;
|
||||
}
|
||||
}
|
||||
//else: no wrapping at all or impossible to wrap
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void pxTextWrapperBase::DoOutputLine(const wxString &line)
|
||||
void pxTextWrapperBase::DoOutputLine(const wxString& line)
|
||||
{
|
||||
OnOutputLine(line);
|
||||
m_linecount++;
|
||||
m_eol = true;
|
||||
OnOutputLine(line);
|
||||
m_linecount++;
|
||||
m_eol = true;
|
||||
}
|
||||
|
||||
// this function is a destructive inspector: when it returns true it also
|
||||
|
@ -488,34 +500,34 @@ void pxTextWrapperBase::DoOutputLine(const wxString &line)
|
|||
// more
|
||||
bool pxTextWrapperBase::IsStartOfNewLine()
|
||||
{
|
||||
if (!m_eol)
|
||||
return false;
|
||||
if (!m_eol)
|
||||
return false;
|
||||
|
||||
m_eol = false;
|
||||
return true;
|
||||
m_eol = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
pxTextWrapper &pxTextWrapper::Wrap(const wxWindow &win, const wxString &text, int widthMax)
|
||||
pxTextWrapper& pxTextWrapper::Wrap(const wxWindow& win, const wxString& text, int widthMax)
|
||||
{
|
||||
_parent::Wrap(win, text, widthMax);
|
||||
return *this;
|
||||
_parent::Wrap(win, text, widthMax);
|
||||
return *this;
|
||||
}
|
||||
|
||||
pxTextWrapper &pxTextWrapper::Wrap(const wxWindow *win, const wxString &text, int widthMax)
|
||||
pxTextWrapper& pxTextWrapper::Wrap(const wxWindow* win, const wxString& text, int widthMax)
|
||||
{
|
||||
if (win)
|
||||
_parent::Wrap(*win, text, widthMax);
|
||||
return *this;
|
||||
if (win)
|
||||
_parent::Wrap(*win, text, widthMax);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void pxTextWrapper::OnOutputLine(const wxString &line)
|
||||
void pxTextWrapper::OnOutputLine(const wxString& line)
|
||||
{
|
||||
m_text += line;
|
||||
m_text += line;
|
||||
}
|
||||
|
||||
void pxTextWrapper::OnNewLine()
|
||||
{
|
||||
m_text += L'\n';
|
||||
m_text += L'\n';
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -527,67 +539,69 @@ BusyCursorType ScopedBusyCursor::m_defBusyType;
|
|||
|
||||
ScopedBusyCursor::ScopedBusyCursor(BusyCursorType busytype)
|
||||
{
|
||||
pxAssert(wxTheApp != NULL);
|
||||
pxAssert(wxTheApp != NULL);
|
||||
|
||||
BusyCursorType curtype = Cursor_NotBusy;
|
||||
if (!m_cursorStack.empty())
|
||||
curtype = m_cursorStack.top();
|
||||
BusyCursorType curtype = Cursor_NotBusy;
|
||||
if (!m_cursorStack.empty())
|
||||
curtype = m_cursorStack.top();
|
||||
|
||||
if (curtype < busytype)
|
||||
SetManualBusyCursor(curtype = busytype);
|
||||
if (curtype < busytype)
|
||||
SetManualBusyCursor(curtype = busytype);
|
||||
|
||||
m_cursorStack.push(curtype);
|
||||
m_cursorStack.push(curtype);
|
||||
}
|
||||
|
||||
ScopedBusyCursor::~ScopedBusyCursor()
|
||||
{
|
||||
if (!pxAssert(wxTheApp != NULL))
|
||||
return;
|
||||
if (!pxAssert(wxTheApp != NULL))
|
||||
return;
|
||||
|
||||
if (!pxAssert(!m_cursorStack.empty())) {
|
||||
SetManualBusyCursor(m_defBusyType);
|
||||
return;
|
||||
}
|
||||
if (!pxAssert(!m_cursorStack.empty()))
|
||||
{
|
||||
SetManualBusyCursor(m_defBusyType);
|
||||
return;
|
||||
}
|
||||
|
||||
BusyCursorType curtype = m_cursorStack.top();
|
||||
m_cursorStack.pop();
|
||||
BusyCursorType curtype = m_cursorStack.top();
|
||||
m_cursorStack.pop();
|
||||
|
||||
if (m_cursorStack.empty())
|
||||
SetManualBusyCursor(m_defBusyType);
|
||||
else if (m_cursorStack.top() != curtype)
|
||||
SetManualBusyCursor(m_cursorStack.top());
|
||||
if (m_cursorStack.empty())
|
||||
SetManualBusyCursor(m_defBusyType);
|
||||
else if (m_cursorStack.top() != curtype)
|
||||
SetManualBusyCursor(m_cursorStack.top());
|
||||
}
|
||||
|
||||
void ScopedBusyCursor::SetDefault(BusyCursorType busytype)
|
||||
{
|
||||
if (busytype == m_defBusyType)
|
||||
return;
|
||||
m_defBusyType = busytype;
|
||||
if (busytype == m_defBusyType)
|
||||
return;
|
||||
m_defBusyType = busytype;
|
||||
|
||||
if (m_cursorStack.empty())
|
||||
SetManualBusyCursor(busytype);
|
||||
if (m_cursorStack.empty())
|
||||
SetManualBusyCursor(busytype);
|
||||
}
|
||||
|
||||
void ScopedBusyCursor::SetManualBusyCursor(BusyCursorType busytype)
|
||||
{
|
||||
switch (busytype) {
|
||||
case Cursor_NotBusy:
|
||||
wxSetCursor(wxNullCursor);
|
||||
break;
|
||||
case Cursor_KindaBusy:
|
||||
wxSetCursor(StockCursors.GetArrowWait());
|
||||
break;
|
||||
case Cursor_ReallyBusy:
|
||||
wxSetCursor(*wxHOURGLASS_CURSOR);
|
||||
break;
|
||||
}
|
||||
switch (busytype)
|
||||
{
|
||||
case Cursor_NotBusy:
|
||||
wxSetCursor(wxNullCursor);
|
||||
break;
|
||||
case Cursor_KindaBusy:
|
||||
wxSetCursor(StockCursors.GetArrowWait());
|
||||
break;
|
||||
case Cursor_ReallyBusy:
|
||||
wxSetCursor(*wxHOURGLASS_CURSOR);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const wxCursor &MoreStockCursors::GetArrowWait()
|
||||
const wxCursor& MoreStockCursors::GetArrowWait()
|
||||
{
|
||||
if (!m_arrowWait)
|
||||
m_arrowWait = std::make_unique<wxCursor>(wxCURSOR_ARROWWAIT);
|
||||
return *m_arrowWait;
|
||||
if (!m_arrowWait)
|
||||
m_arrowWait = std::make_unique<wxCursor>(wxCURSOR_ARROWWAIT);
|
||||
return *m_arrowWait;
|
||||
}
|
||||
|
||||
MoreStockCursors StockCursors;
|
||||
|
@ -599,39 +613,39 @@ MoreStockCursors StockCursors;
|
|||
// extends the tooltip time to the maximum possible. GTK seems to have indefinite
|
||||
// tooltips, I don't know about OS X.
|
||||
|
||||
void pxSetToolTip(wxWindow *wind, const wxString &src)
|
||||
void pxSetToolTip(wxWindow* wind, const wxString& src)
|
||||
{
|
||||
if (wind == NULL)
|
||||
return; // Silently ignore nulls
|
||||
wind->SetToolTip(src);
|
||||
if (wind == NULL)
|
||||
return; // Silently ignore nulls
|
||||
wind->SetToolTip(src);
|
||||
|
||||
// Make tooltips show for as long as possible on Windows. Linux (GTK) can
|
||||
// show tooltips indefinitely.
|
||||
#ifdef __WXMSW__
|
||||
wind->GetToolTip()->SetAutoPop(32767);
|
||||
wind->GetToolTip()->SetAutoPop(32767);
|
||||
#endif
|
||||
}
|
||||
|
||||
void pxSetToolTip(wxWindow &wind, const wxString &src)
|
||||
void pxSetToolTip(wxWindow& wind, const wxString& src)
|
||||
{
|
||||
pxSetToolTip(&wind, src);
|
||||
pxSetToolTip(&wind, src);
|
||||
}
|
||||
|
||||
|
||||
wxFont pxGetFixedFont(int ptsize, wxFontWeight weight, bool underline)
|
||||
{
|
||||
return wxFont(
|
||||
ptsize, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, weight, underline
|
||||
return wxFont(
|
||||
ptsize, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, weight, underline
|
||||
#ifdef __WXMSW__
|
||||
,
|
||||
L"Lucida Console" // better than courier new (win32 only)
|
||||
,
|
||||
L"Lucida Console" // better than courier new (win32 only)
|
||||
#endif
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
wxString pxGetAppName()
|
||||
{
|
||||
pxAssert(wxTheApp);
|
||||
return wxTheApp->GetAppName();
|
||||
pxAssert(wxTheApp);
|
||||
return wxTheApp->GetAppName();
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue