mirror of https://github.com/PCSX2/pcsx2.git
aligned_stack: synced with trunk, to bring in the new console code for additional testing under a (properly working!) linux.
git-svn-id: http://pcsx2.googlecode.com/svn/branches/aligned_stack@2046 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
commit
00461fdac6
|
@ -1970,8 +1970,17 @@ int wxString::PrintfV(const wxChar* pszFormat, va_list argptr)
|
|||
}
|
||||
|
||||
// we could have overshot
|
||||
Shrink();
|
||||
// PCSX2: And we could have 4gb of ram and not really give a hoot if we overshoot
|
||||
// the length of a temporary string by 0.5kb, which itself will likely be free'd a few
|
||||
// instructions later. Also, this defeats the purpose of even using the 1kb "overshot"
|
||||
// starting buffer size at the top of the function. Ideally if you are really concerned
|
||||
// about memory, the 1024 should be a 512, and this should only shrink if the allocated
|
||||
// length of the string is more than 128 bytes past the end of the actual string content.
|
||||
// -- Jake Stine (air)
|
||||
|
||||
//if( capacity() - 128 >= length() ) // this line added by air, as proposed above.
|
||||
// Shrink();
|
||||
|
||||
return length();
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
:: application debugging (however these files are by no means required by any software).
|
||||
|
||||
del /s "%~dp0\*.ncb"
|
||||
del /s "%~dp0\*.ilk"
|
||||
del /s "%~dp0\bin\*.ilk"
|
||||
del /s "%~dp0\*.idb"
|
||||
del /s "%~dp0\*.bsc"
|
||||
del /s "%~dp0\*.sbr"
|
||||
|
|
|
@ -58,7 +58,17 @@
|
|||
</Target>
|
||||
</Build>
|
||||
<Compiler>
|
||||
<Add option="-march=native" />
|
||||
<Add option="-march=i486" />
|
||||
<Add option="-Wno-format" />
|
||||
<Add option="-Wno-unused-parameter" />
|
||||
<Add option="-Wno-unused-value" />
|
||||
<Add option="-Wunused-variable" />
|
||||
<Add option="-fno-guess-branch-probability" />
|
||||
<Add option="-fno-dse" />
|
||||
<Add option="-fno-tree-dse" />
|
||||
<Add option="-pipe -msse -msse2" />
|
||||
<Add option="-mpreferred-stack-boundary=2" />
|
||||
<Add option="-m32" />
|
||||
<Add directory="../../include/Utilities" />
|
||||
<Add directory="../../include" />
|
||||
<Add directory="../../../3rdparty" />
|
||||
|
|
|
@ -59,6 +59,7 @@
|
|||
</Target>
|
||||
</Build>
|
||||
<Compiler>
|
||||
<Add option="-march=i486" />
|
||||
<Add option="-Wno-format" />
|
||||
<Add option="-Wno-unused-parameter" />
|
||||
<Add option="-Wno-unused-value" />
|
||||
|
@ -67,6 +68,8 @@
|
|||
<Add option="-fno-dse" />
|
||||
<Add option="-fno-tree-dse" />
|
||||
<Add option="-pipe -msse -msse2" />
|
||||
<Add option="-mpreferred-stack-boundary=2" />
|
||||
<Add option="-m32" />
|
||||
<Add directory="../../include/x86emitter" />
|
||||
<Add directory="../../include" />
|
||||
</Compiler>
|
||||
|
|
|
@ -189,7 +189,6 @@
|
|||
# define PCSX2_ALIGNED16_EXTERN(x) extern __declspec(align(16)) x
|
||||
|
||||
# define __naked __declspec(naked)
|
||||
# define __unused /*unused*/
|
||||
# define __noinline __declspec(noinline)
|
||||
# define __threadlocal __declspec(thread)
|
||||
|
||||
|
@ -244,7 +243,6 @@ This theoretically unoptimizes. Not having much luck so far.
|
|||
// happens *by design* like all the friggen time >_<)
|
||||
|
||||
# define __fastcall __attribute__((fastcall))
|
||||
# define __unused __attribute__((unused))
|
||||
# define _inline __inline__ __attribute__((unused))
|
||||
# ifdef NDEBUG
|
||||
# define __forceinline __attribute__((always_inline,unused))
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
|
||||
enum ConsoleColors
|
||||
{
|
||||
Color_Current = -1,
|
||||
|
||||
Color_Black = 0,
|
||||
Color_Red,
|
||||
Color_Green,
|
||||
|
@ -27,7 +29,7 @@ enum ConsoleColors
|
|||
Color_Blue,
|
||||
Color_Magenta,
|
||||
Color_Cyan,
|
||||
Color_White
|
||||
Color_White,
|
||||
};
|
||||
|
||||
// Use fastcall for the console; should be helpful in most cases
|
||||
|
|
|
@ -73,6 +73,11 @@ namespace Threading
|
|||
// 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();
|
||||
|
||||
// sleeps the current thread for the given number of milliseconds.
|
||||
extern void Sleep( int ms );
|
||||
|
||||
|
@ -314,7 +319,7 @@ namespace Threading
|
|||
// Section of methods for internal use only.
|
||||
|
||||
void _DoSetThreadName( const wxString& name );
|
||||
void _DoSetThreadName( __unused const char* name );
|
||||
void _DoSetThreadName( const char* name );
|
||||
void _internal_execute();
|
||||
void _try_virtual_invoke( void (PersistentThread::*method)() );
|
||||
void _ThreadCleanup();
|
||||
|
|
|
@ -32,17 +32,17 @@ class DwordShiftImplAll
|
|||
|
||||
public:
|
||||
// ---------- 32 Bit Interface -----------
|
||||
__forceinline void operator()( const xRegister32& to, const xRegister32& from, __unused const xRegisterCL& clreg ) const { xOpWrite0F( 0xa5 | m_shiftop, to, from ); }
|
||||
__forceinline void operator()( void* dest, const xRegister32& from, __unused const xRegisterCL& clreg ) const { xOpWrite0F( 0xa5 | m_shiftop, from, dest ); }
|
||||
__forceinline void operator()( const ModSibBase& dest, const xRegister32& from, __unused const xRegisterCL& clreg ) const { xOpWrite0F( 0xa5 | m_shiftop, from, dest ); }
|
||||
__forceinline void operator()( const xRegister32& to, const xRegister32& from, const xRegisterCL& /* clreg */ ) const { xOpWrite0F( 0xa5 | m_shiftop, to, from ); }
|
||||
__forceinline void operator()( void* dest, const xRegister32& from, const xRegisterCL& /* clreg */ ) const { xOpWrite0F( 0xa5 | m_shiftop, from, dest ); }
|
||||
__forceinline void operator()( const ModSibBase& dest, const xRegister32& from, const xRegisterCL& /* clreg */ ) const { xOpWrite0F( 0xa5 | m_shiftop, from, dest ); }
|
||||
__forceinline void operator()( const xRegister32& to, const xRegister32& from, u8 shiftcnt ) const { if( shiftcnt != 0 ) xOpWrite0F( 0xa4 | m_shiftop, to, from ); }
|
||||
__forceinline void operator()( void* dest, const xRegister32& from, u8 shiftcnt ) const { if( shiftcnt != 0 ) xOpWrite0F( 0xa4 | m_shiftop, from, dest, shiftcnt ); }
|
||||
__forceinline void operator()( const ModSibBase& dest, const xRegister32& from, u8 shiftcnt ) const { if( shiftcnt != 0 ) xOpWrite0F( 0xa4 | m_shiftop, from, dest, shiftcnt ); }
|
||||
|
||||
// ---------- 16 Bit Interface -----------
|
||||
__forceinline void operator()( const xRegister16& to, const xRegister16& from, __unused const xRegisterCL& clreg ) const { xOpWrite0F( 0x66, 0xa5 | m_shiftop, to, from ); }
|
||||
__forceinline void operator()( void* dest, const xRegister16& from, __unused const xRegisterCL& clreg ) const { xOpWrite0F( 0x66, 0xa5 | m_shiftop, from, dest ); }
|
||||
__forceinline void operator()( const ModSibBase& dest, const xRegister16& from, __unused const xRegisterCL& clreg ) const { xOpWrite0F( 0x66, 0xa5 | m_shiftop, from, dest ); }
|
||||
__forceinline void operator()( const xRegister16& to, const xRegister16& from, const xRegisterCL& /* clreg */ ) const { xOpWrite0F( 0x66, 0xa5 | m_shiftop, to, from ); }
|
||||
__forceinline void operator()( void* dest, const xRegister16& from, const xRegisterCL& /* clreg */ ) const { xOpWrite0F( 0x66, 0xa5 | m_shiftop, from, dest ); }
|
||||
__forceinline void operator()( const ModSibBase& dest, const xRegister16& from, const xRegisterCL& /* clreg */ ) const { xOpWrite0F( 0x66, 0xa5 | m_shiftop, from, dest ); }
|
||||
__forceinline void operator()( const xRegister16& to, const xRegister16& from, u8 shiftcnt ) const { if( shiftcnt != 0 ) xOpWrite0F( 0x66, 0xa4 | m_shiftop, to, from ); }
|
||||
__forceinline void operator()( void* dest, const xRegister16& from, u8 shiftcnt ) const { if( shiftcnt != 0 ) xOpWrite0F( 0x66, 0xa4 | m_shiftop, from, dest, shiftcnt ); }
|
||||
__forceinline void operator()( const ModSibBase& dest, const xRegister16& from, u8 shiftcnt ) const { if( shiftcnt != 0 ) xOpWrite0F( 0x66, 0xa4 | m_shiftop, from, dest, shiftcnt ); }
|
||||
|
|
|
@ -39,14 +39,14 @@ template< G2Type InstType >
|
|||
class Group2ImplAll
|
||||
{
|
||||
public:
|
||||
template< typename T > __forceinline void operator()( const xRegister<T>& to, __unused const xRegisterCL& from ) const
|
||||
template< typename T > __forceinline void operator()( const xRegister<T>& to, const xRegisterCL& /* from */ ) const
|
||||
{
|
||||
prefix16<T>();
|
||||
xWrite8( Is8BitOp<T>() ? 0xd2 : 0xd3 );
|
||||
EmitSibMagic( InstType, to );
|
||||
}
|
||||
|
||||
template< typename T > __noinline void operator()( const ModSibStrict<T>& sibdest, __unused const xRegisterCL& from ) const
|
||||
template< typename T > __noinline void operator()( const ModSibStrict<T>& sibdest, const xRegisterCL& /* from */ ) const
|
||||
{
|
||||
prefix16<T>();
|
||||
xWrite8( Is8BitOp<T>() ? 0xd2 : 0xd3 );
|
||||
|
|
|
@ -24,38 +24,44 @@
|
|||
|
||||
static bool isMultiCore = true; // assume more than one CPU (safer)
|
||||
|
||||
namespace Threading
|
||||
// Note: Apparently this solution is Linux/Solaris only.
|
||||
// FreeBSD/OsX need something far more complicated (apparently)
|
||||
void Threading::CountLogicalCores( int LogicalCoresPerPhysicalCPU, int PhysicalCoresPerPhysicalCPU )
|
||||
{
|
||||
// Note: Apparently this solution is Linux/Solaris only.
|
||||
// FreeBSD/OsX need something far more complicated (apparently)
|
||||
void CountLogicalCores( int LogicalCoresPerPhysicalCPU, int PhysicalCoresPerPhysicalCPU )
|
||||
const uint numCPU = sysconf( _SC_NPROCESSORS_ONLN );
|
||||
if( numCPU > 0 )
|
||||
{
|
||||
const uint numCPU = sysconf( _SC_NPROCESSORS_ONLN );
|
||||
if( numCPU > 0 )
|
||||
{
|
||||
isMultiCore = numCPU > 1;
|
||||
x86caps.LogicalCores = numCPU;
|
||||
x86caps.PhysicalCores = ( numCPU / LogicalCoresPerPhysicalCPU ) * PhysicalCoresPerPhysicalCPU;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Indeterminate?
|
||||
x86caps.LogicalCores = 1;
|
||||
x86caps.PhysicalCores = 1;
|
||||
}
|
||||
isMultiCore = numCPU > 1;
|
||||
x86caps.LogicalCores = numCPU;
|
||||
x86caps.PhysicalCores = ( numCPU / LogicalCoresPerPhysicalCPU ) * PhysicalCoresPerPhysicalCPU;
|
||||
}
|
||||
|
||||
__forceinline void Sleep( int ms )
|
||||
else
|
||||
{
|
||||
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 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" );
|
||||
// Indeterminate?
|
||||
x86caps.LogicalCores = 1;
|
||||
x86caps.PhysicalCores = 1;
|
||||
}
|
||||
}
|
||||
|
||||
__forceinline void Threading::Sleep( int 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" );
|
||||
}
|
||||
|
||||
__forceinline void Threading::EnableHiresScheduler()
|
||||
{
|
||||
// Don't know if linux has a customizable scheduler resolution like Windows (doubtful)
|
||||
}
|
||||
|
||||
__forceinline void Threading::DisableHiresScheduler()
|
||||
{
|
||||
}
|
||||
|
|
|
@ -144,8 +144,6 @@ void Threading::PersistentThread::Start()
|
|||
|
||||
if( pthread_create( &m_thread, NULL, _internal_callback, this ) != 0 )
|
||||
throw Exception::ThreadCreationError();
|
||||
|
||||
m_detached = false;
|
||||
}
|
||||
|
||||
// Returns: TRUE if the detachment was performed, or FALSE if the thread was
|
||||
|
@ -384,7 +382,8 @@ wxString Threading::PersistentThread::GetName() const
|
|||
// private member, and provide a new Task executor by a different name).
|
||||
void Threading::PersistentThread::OnStartInThread()
|
||||
{
|
||||
m_running = true;
|
||||
m_running = true;
|
||||
m_detached = false;
|
||||
}
|
||||
|
||||
void Threading::PersistentThread::_internal_execute()
|
||||
|
@ -426,7 +425,7 @@ void Threading::PersistentThread::_DoSetThreadName( const wxString& name )
|
|||
_DoSetThreadName( name.ToUTF8() );
|
||||
}
|
||||
|
||||
void Threading::PersistentThread::_DoSetThreadName( __unused const char* name )
|
||||
void Threading::PersistentThread::_DoSetThreadName( const char* name )
|
||||
{
|
||||
pxAssertMsg( IsSelf(), "Thread affinity error." ); // only allowed from our own thread, thanks.
|
||||
|
||||
|
@ -435,7 +434,7 @@ void Threading::PersistentThread::_DoSetThreadName( __unused const char* name )
|
|||
#if defined(_WINDOWS_) && defined (_MSC_VER)
|
||||
|
||||
// This code sample was borrowed form some obscure MSDN article.
|
||||
// In a rare bout of sanity, it's an actual Micrsoft-published hack
|
||||
// In a rare bout of sanity, it's an actual Microsoft-published hack
|
||||
// that actually works!
|
||||
|
||||
static const int MS_VC_EXCEPTION = 0x406D1388;
|
||||
|
@ -443,10 +442,10 @@ void Threading::PersistentThread::_DoSetThreadName( __unused const char* name )
|
|||
#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.
|
||||
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)
|
||||
|
||||
|
@ -456,13 +455,9 @@ void Threading::PersistentThread::_DoSetThreadName( __unused const char* name )
|
|||
info.dwThreadID = GetCurrentThreadId();
|
||||
info.dwFlags = 0;
|
||||
|
||||
__try
|
||||
{
|
||||
__try {
|
||||
RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info );
|
||||
}
|
||||
__except(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
}
|
||||
} __except(EXCEPTION_EXECUTE_HANDLER) { }
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -22,45 +22,58 @@
|
|||
#include "implement.h" // win32 pthreads implementations.
|
||||
#endif
|
||||
|
||||
namespace Threading
|
||||
void Threading::CountLogicalCores( int LogicalCoresPerPhysicalCPU, int PhysicalCoresPerPhysicalCPU )
|
||||
{
|
||||
void CountLogicalCores( int LogicalCoresPerPhysicalCPU, int PhysicalCoresPerPhysicalCPU )
|
||||
DWORD vProcessCPUs;
|
||||
DWORD vSystemCPUs;
|
||||
|
||||
x86caps.LogicalCores = 1;
|
||||
|
||||
if( !GetProcessAffinityMask (GetCurrentProcess (),
|
||||
&vProcessCPUs, &vSystemCPUs) ) return;
|
||||
|
||||
int CPUs = 0;
|
||||
DWORD bit;
|
||||
|
||||
for (bit = 1; bit != 0; bit <<= 1)
|
||||
{
|
||||
DWORD vProcessCPUs;
|
||||
DWORD vSystemCPUs;
|
||||
|
||||
x86caps.LogicalCores = 1;
|
||||
|
||||
if( !GetProcessAffinityMask (GetCurrentProcess (),
|
||||
&vProcessCPUs, &vSystemCPUs) ) return;
|
||||
|
||||
int CPUs = 0;
|
||||
DWORD bit;
|
||||
|
||||
for (bit = 1; bit != 0; bit <<= 1)
|
||||
{
|
||||
if (vSystemCPUs & bit)
|
||||
CPUs++;
|
||||
}
|
||||
|
||||
x86caps.LogicalCores = CPUs;
|
||||
if( LogicalCoresPerPhysicalCPU > CPUs) // for 1-socket HTT-disabled machines
|
||||
LogicalCoresPerPhysicalCPU = CPUs;
|
||||
|
||||
x86caps.PhysicalCores = ( CPUs / LogicalCoresPerPhysicalCPU ) * PhysicalCoresPerPhysicalCPU;
|
||||
//ptw32_smp_system = ( x86caps.LogicalCores > 1 ) ? TRUE : FALSE;
|
||||
if (vSystemCPUs & bit)
|
||||
CPUs++;
|
||||
}
|
||||
|
||||
__forceinline void Sleep( int ms )
|
||||
{
|
||||
::Sleep( ms );
|
||||
}
|
||||
x86caps.LogicalCores = CPUs;
|
||||
if( LogicalCoresPerPhysicalCPU > CPUs) // for 1-socket HTT-disabled machines
|
||||
LogicalCoresPerPhysicalCPU = CPUs;
|
||||
|
||||
// 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 SpinWait()
|
||||
{
|
||||
__asm { pause };
|
||||
}
|
||||
x86caps.PhysicalCores = ( CPUs / LogicalCoresPerPhysicalCPU ) * PhysicalCoresPerPhysicalCPU;
|
||||
//ptw32_smp_system = ( x86caps.LogicalCores > 1 ) ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
__forceinline void Threading::Sleep( int 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.
|
||||
__forceinline void Threading::SpinWait()
|
||||
{
|
||||
__asm pause;
|
||||
}
|
||||
|
||||
__forceinline void Threading::EnableHiresScheduler()
|
||||
{
|
||||
// This improves accuracy of Sleep() by some amount, and only adds a negligable 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)
|
||||
|
||||
timeBeginPeriod( 1 );
|
||||
}
|
||||
|
||||
__forceinline void Threading::DisableHiresScheduler()
|
||||
{
|
||||
timeEndPeriod( 1 );
|
||||
}
|
||||
|
||||
|
|
|
@ -129,9 +129,9 @@ static const uint PSX_DVD_READSPEED = 1382400 + 256000; // normal is 1 Byte Time
|
|||
static const uint Cdvd_FullSeek_Cycles = (PSXCLK*100) / 1000; // average number of cycles per fullseek (100ms)
|
||||
static const uint Cdvd_FastSeek_Cycles = (PSXCLK*30) / 1000; // average number of cycles per fastseek (37ms)
|
||||
|
||||
static const __unused char *mg_zones[8] = {"Japan", "USA", "Europe", "Oceania", "Asia", "Russia", "China", "Mexico"};
|
||||
static const char *mg_zones[8] = {"Japan", "USA", "Europe", "Oceania", "Asia", "Russia", "China", "Mexico"};
|
||||
|
||||
static const __unused char *nCmdName[0x100]= {
|
||||
static const char *nCmdName[0x100]= {
|
||||
"CdSync",
|
||||
"CdNop",
|
||||
"CdStandby",
|
||||
|
@ -168,7 +168,7 @@ enum nCmds
|
|||
N_CD_CHG_SPDL_CTRL = 0x0F, // CdChgSpdlCtrl
|
||||
};
|
||||
|
||||
static const __unused char *sCmdName[0x100]= {
|
||||
static const char *sCmdName[0x100]= {
|
||||
"", "sceCdGetDiscType", "sceCdReadSubQ", "subcommands",//sceCdGetMecaconVersion, read/write console id, read renewal date
|
||||
"", "sceCdTrayState", "sceCdTrayCtrl", "",
|
||||
"sceCdReadClock", "sceCdWriteClock", "sceCdReadNVM", "sceCdWriteNVM",
|
||||
|
@ -232,4 +232,4 @@ static NVMLayout nvmlayouts[NVM_FORMAT_MAX] =
|
|||
{0x146, 0x270, 0x2B0, 0x200, 0x1C8, 0x1E0, 0x1B0, 0x180, 0x198}, // eeproms from bios v1.70 and up
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -497,7 +497,7 @@ s32 CALLBACK NODISCdummyS32()
|
|||
return 0;
|
||||
}
|
||||
|
||||
void CALLBACK NODISCnewDiskCB(__unused void (*callback)())
|
||||
void CALLBACK NODISCnewDiskCB(void (* /* callback */)())
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -396,7 +396,7 @@ s32 CALLBACK ISOdummyS32()
|
|||
return 0;
|
||||
}
|
||||
|
||||
void CALLBACK ISOnewDiskCB(__unused void(*callback)())
|
||||
void CALLBACK ISOnewDiskCB(void(* /* callback */)())
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -322,12 +322,21 @@ static __forceinline void frameLimit()
|
|||
|
||||
m_iStart = uExpectedEnd;
|
||||
|
||||
while( sDeltaTime < 0 )
|
||||
{
|
||||
Timeslice();
|
||||
iEnd = GetCPUTicks();
|
||||
sDeltaTime = iEnd - uExpectedEnd;
|
||||
}
|
||||
// Shortcut for cases where no waiting is needed (they're running slow already,
|
||||
// so don't bog 'em down with extra math...)
|
||||
if( sDeltaTime >= 0 ) return;
|
||||
|
||||
// If we're way ahead then we can afford to sleep the thread a bit.
|
||||
// (note, sleep(1) thru sleep(2) tend to be the least accurate sleeps, and longer
|
||||
// sleeps tend to be pretty reliable, so that's why the convoluted if/else below)
|
||||
|
||||
s32 msec = (int)((sDeltaTime*-1000) / (s64)GetTickFrequency());
|
||||
if( msec > 4 ) Threading::Sleep( msec );
|
||||
else if( msec > 2 ) Threading::Sleep( 1 );
|
||||
|
||||
// Sleep is not picture-perfect accurate, but it's actually not necessary to
|
||||
// maintain a "perfect" lock to uExpectedEnd anyway. if we're a little ahead
|
||||
// starting this frame, it'll just sleep longer the next to make up for it. :)
|
||||
}
|
||||
|
||||
static __forceinline void VSyncStart(u32 sCycle)
|
||||
|
|
|
@ -30,15 +30,13 @@ using std::min;
|
|||
// A three-way toggle used to determine if the GIF is stalling (transferring) or done (finished).
|
||||
// Should be a gifstate_t rather then int, but I don't feel like possibly interfering with savestates right now.
|
||||
static int gifstate = GIF_STATE_READY;
|
||||
static bool gifempty = false;
|
||||
|
||||
//static u64 s_gstag = 0; // used for querying the last tag
|
||||
|
||||
// This should be a bool. Next time I feel like breaking the save state, it will be. --arcum42
|
||||
static bool gspath3done = false;
|
||||
|
||||
static u32 gscycles = 0, prevcycles = 0, mfifocycles = 0;
|
||||
static u32 gifqwc = 0;
|
||||
bool gifmfifoirq = false;
|
||||
static bool gifmfifoirq = false;
|
||||
|
||||
static __forceinline void clearFIFOstuff(bool full)
|
||||
{
|
||||
|
@ -60,8 +58,9 @@ __forceinline void gsInterrupt()
|
|||
return;
|
||||
}
|
||||
|
||||
if ((vif1.cmd & 0x7f) == 0x51)
|
||||
if ((vif1.cmd & 0x7f) == 0x51) // DIRECTHL
|
||||
{
|
||||
// Not waiting for the end of the Gif transfer.
|
||||
if (Path3progress != IMAGE_MODE) vif1Regs->stat.VGW = 0;
|
||||
}
|
||||
|
||||
|
@ -141,7 +140,7 @@ static __forceinline void GIFchain()
|
|||
|
||||
static __forceinline bool checkTieBit(u32* &ptag)
|
||||
{
|
||||
if (gif->chcr.TIE && (Tag::IRQ(ptag))) //Check TIE bit of CHCR and IRQ bit of tag
|
||||
if (gif->chcr.TIE && (Tag::IRQ(ptag)))
|
||||
{
|
||||
GIF_LOG("dmaIrq Set");
|
||||
gspath3done = true;
|
||||
|
@ -151,28 +150,30 @@ static __forceinline bool checkTieBit(u32* &ptag)
|
|||
return false;
|
||||
}
|
||||
|
||||
static __forceinline bool ReadTag(u32* &ptag, u32 &id)
|
||||
static __forceinline u32* ReadTag(u32 &id)
|
||||
{
|
||||
ptag = (u32*)dmaGetAddr(gif->tadr); //Set memory pointer to TADR
|
||||
u32* ptag = (u32*)dmaGetAddr(gif->tadr); //Set memory pointer to TADR
|
||||
|
||||
if (!(Tag::Transfer("Gif", gif, ptag))) return NULL;
|
||||
|
||||
if (!(Tag::Transfer("Gif", gif, ptag))) return false;
|
||||
gif->madr = ptag[1]; //MADR = ADDR field
|
||||
|
||||
id = Tag::Id(ptag); //ID for DmaChain copied from bit 28 of the tag
|
||||
id = Tag::Id(ptag);
|
||||
gscycles += 2; // Add 1 cycles from the QW read for the tag
|
||||
|
||||
gspath3done = hwDmacSrcChainWithStack(gif, id);
|
||||
return true;
|
||||
return ptag;
|
||||
}
|
||||
|
||||
static __forceinline void ReadTag2(u32* &ptag)
|
||||
static __forceinline u32* ReadTag2()
|
||||
{
|
||||
ptag = (u32*)dmaGetAddr(gif->tadr); //Set memory pointer to TADR
|
||||
u32* ptag = (u32*)dmaGetAddr(gif->tadr); //Set memory pointer to TADR
|
||||
|
||||
Tag::UnsafeTransfer(gif, ptag);
|
||||
gif->madr = ptag[1];
|
||||
|
||||
gspath3done = hwDmacSrcChainWithStack(gif, Tag::Id(ptag));
|
||||
return ptag;
|
||||
}
|
||||
|
||||
void GIFdma()
|
||||
|
@ -209,6 +210,7 @@ void GIFdma()
|
|||
//Path2 gets priority in intermittent mode
|
||||
if ((gifRegs->stat.P1Q || (vif1.cmd & 0x7f) == 0x50) && gifRegs->mode.IMT && (Path3progress == IMAGE_MODE))
|
||||
{
|
||||
// We are in image mode doing DIRECTHL, Path 1 is in queue, and in intermittant mode.
|
||||
GIF_LOG("Waiting VU %x, PATH2 %x, GIFMODE %x Progress %x", gifRegs->stat.P1Q, (vif1.cmd & 0x7f), gifRegs->mode._u32, Path3progress);
|
||||
CPU_INT(2, 16);
|
||||
return;
|
||||
|
@ -220,7 +222,8 @@ void GIFdma()
|
|||
{
|
||||
if ((gif->chcr.MOD == CHAIN_MODE) && gif->chcr.STR)
|
||||
{
|
||||
if (!ReadTag(ptag, id)) return;
|
||||
ptag = ReadTag(id);
|
||||
if (ptag == NULL) return;
|
||||
GIF_LOG("PTH3 MASK gifdmaChain %8.8x_%8.8x size=%d, id=%d, addr=%lx", ptag[1], ptag[0], gif->qwc, id, gif->madr);
|
||||
|
||||
//Check TIE bit of CHCR and IRQ bit of tag
|
||||
|
@ -257,7 +260,8 @@ void GIFdma()
|
|||
|
||||
if ((gif->chcr.MOD == CHAIN_MODE) && (!gspath3done)) // Chain Mode
|
||||
{
|
||||
if (!ReadTag(ptag, id)) return;
|
||||
ptag = ReadTag(id);
|
||||
if (ptag == NULL) return;
|
||||
GIF_LOG("gifdmaChain %8.8x_%8.8x size=%d, id=%d, addr=%lx", ptag[1], ptag[0], gif->qwc, id, gif->madr);
|
||||
|
||||
if (dmacRegs->ctrl.STD == STD_GIF)
|
||||
|
@ -312,7 +316,7 @@ void dmaGIF()
|
|||
gspath3done = false; // For some reason this doesn't clear? So when the system starts the thread, we will clear it :)
|
||||
|
||||
gifRegs->stat.P3Q = 1;
|
||||
gifRegs->stat.FQC |= 0x10;// FQC=31, hack ;) ( 31? 16! arcum42) [used to be 0xE00; // OPH=1 | APATH=3]
|
||||
gifRegs->stat.FQC |= 0x10; // hack ;)
|
||||
|
||||
clearFIFOstuff(true);
|
||||
|
||||
|
@ -325,9 +329,7 @@ void dmaGIF()
|
|||
|
||||
if ((gif->qwc == 0) && (gif->chcr.MOD != NORMAL_MODE))
|
||||
{
|
||||
u32 *ptag;
|
||||
|
||||
ReadTag2(ptag);
|
||||
u32* ptag = ReadTag2();
|
||||
GIF_LOG("gifdmaChain %8.8x_%8.8x size=%d, id=%d, addr=%lx", ptag[1], ptag[0], gif->qwc, (ptag[0] >> 28), gif->madr);
|
||||
|
||||
checkTieBit(ptag);
|
||||
|
@ -401,10 +403,12 @@ static __forceinline int mfifoGIFchain()
|
|||
}
|
||||
else
|
||||
{
|
||||
int mfifoqwc = gif->qwc;
|
||||
int mfifoqwc;
|
||||
|
||||
u32 *pMem = (u32*)dmaGetAddr(gif->madr);
|
||||
if (pMem == NULL) return -1;
|
||||
mfifoqwc = WRITERING_DMA(pMem, mfifoqwc);
|
||||
|
||||
mfifoqwc = WRITERING_DMA(pMem, gif->qwc);
|
||||
mfifocycles += (mfifoqwc) * 2; /* guessing */
|
||||
}
|
||||
|
||||
|
@ -420,7 +424,6 @@ void mfifoGIFtransfer(int qwc)
|
|||
{
|
||||
u32 *ptag;
|
||||
int id;
|
||||
u32 temp = 0;
|
||||
|
||||
mfifocycles = 0;
|
||||
gifmfifoirq = false;
|
||||
|
@ -428,8 +431,11 @@ void mfifoGIFtransfer(int qwc)
|
|||
if(qwc > 0 )
|
||||
{
|
||||
gifqwc += qwc;
|
||||
if (gifstate != GIF_STATE_EMPTY) return;
|
||||
|
||||
if (!(gifstate & GIF_STATE_EMPTY)) return;
|
||||
// if (gifempty == false) return;
|
||||
gifstate &= ~GIF_STATE_EMPTY;
|
||||
gifempty = false;
|
||||
}
|
||||
|
||||
GIF_LOG("mfifoGIFtransfer %x madr %x, tadr %x", gif->chcr._u32, gif->madr, gif->tadr);
|
||||
|
@ -440,13 +446,14 @@ void mfifoGIFtransfer(int qwc)
|
|||
{
|
||||
//if( gifqwc > 1 ) DevCon.WriteLn("gif mfifo tadr==madr but qwc = %d", gifqwc);
|
||||
hwDmacIrq(DMAC_MFIFO_EMPTY);
|
||||
gifstate |= GIF_STATE_EMPTY;
|
||||
gifstate |= GIF_STATE_EMPTY;
|
||||
gifempty = true;
|
||||
return;
|
||||
}
|
||||
|
||||
gif->tadr = qwctag(gif->tadr);
|
||||
|
||||
ptag = (u32*)dmaGetAddr(gif->tadr);
|
||||
|
||||
Tag::UnsafeTransfer(gif, ptag);
|
||||
|
||||
gif->madr = ptag[1];
|
||||
|
@ -472,11 +479,13 @@ void mfifoGIFtransfer(int qwc)
|
|||
break;
|
||||
|
||||
case TAG_NEXT: // Next - Transfer QWC following tag. TADR = ADDR
|
||||
temp = gif->madr; //Temporarily Store ADDR
|
||||
{
|
||||
u32 temp = gif->madr; //Temporarily Store ADDR
|
||||
gif->madr = qwctag(gif->tadr + 16); //Set MADR to QW following the tag
|
||||
gif->tadr = temp; //Copy temporarily stored ADDR to Tag
|
||||
gifstate = GIF_STATE_READY;
|
||||
break;
|
||||
}
|
||||
|
||||
case TAG_REF: // Ref - Transfer QWC from ADDR field
|
||||
case TAG_REFS: // Refs - Transfer QWC from ADDR field (Stall Control)
|
||||
|
@ -507,7 +516,7 @@ void mfifoGIFtransfer(int qwc)
|
|||
}
|
||||
FreezeRegs(0);
|
||||
|
||||
if ((gif->qwc == 0) && (gifstate == GIF_STATE_DONE)) gifstate = GIF_STATE_STALL;
|
||||
if ((gif->qwc == 0) && (gifstate & GIF_STATE_DONE)) gifstate = GIF_STATE_STALL;
|
||||
CPU_INT(11,mfifocycles);
|
||||
|
||||
SPR_LOG("mfifoGIFtransfer end %x madr %x, tadr %x", gif->chcr._u32, gif->madr, gif->tadr);
|
||||
|
@ -515,6 +524,7 @@ void mfifoGIFtransfer(int qwc)
|
|||
|
||||
void gifMFIFOInterrupt()
|
||||
{
|
||||
Console.WriteLn("gifMFIFOInterrupt");
|
||||
mfifocycles = 0;
|
||||
|
||||
if (Path3progress == STOPPED_MODE)
|
||||
|
@ -543,13 +553,15 @@ void gifMFIFOInterrupt()
|
|||
return;
|
||||
}
|
||||
|
||||
if (gifstate != GIF_STATE_STALL)
|
||||
if (!(gifstate & GIF_STATE_STALL))
|
||||
{
|
||||
if (gifqwc <= 0)
|
||||
{
|
||||
//Console.WriteLn("Empty");
|
||||
hwDmacIrq(DMAC_MFIFO_EMPTY);
|
||||
gifstate |= GIF_STATE_EMPTY;
|
||||
gifempty = true;
|
||||
|
||||
gifRegs->stat.IMT = 0;
|
||||
return;
|
||||
}
|
||||
|
@ -558,7 +570,7 @@ void gifMFIFOInterrupt()
|
|||
}
|
||||
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
if (gifstate == GIF_STATE_READY || gif->qwc > 0)
|
||||
if ((gifstate & GIF_STATE_READY) || (gif->qwc > 0))
|
||||
{
|
||||
Console.Error("gifMFIFO Panic > Shouldn't go here!");
|
||||
return;
|
||||
|
@ -587,6 +599,6 @@ void SaveStateBase::gifFreeze()
|
|||
Freeze( gifqwc );
|
||||
Freeze( gspath3done );
|
||||
Freeze( gscycles );
|
||||
|
||||
//Freeze(gifempty);
|
||||
// Note: mfifocycles is not a persistent var, so no need to save it here.
|
||||
}
|
||||
|
|
16
pcsx2/Gif.h
16
pcsx2/Gif.h
|
@ -45,9 +45,9 @@ enum gif_stat_flags
|
|||
GIF_STAT_P2Q = (1<<7), // PATH2 request Queued
|
||||
GIF_STAT_P1Q = (1<<8), // PATH1 request Queued
|
||||
GIF_STAT_OPH = (1<<9), // Output Path (Outputting Data)
|
||||
GIF_STAT_APATH1 = (1<<10), // Data Transfer Path 1 (In progress)
|
||||
GIF_STAT_APATH2 = (2<<10), // Data Transfer Path 2 (In progress)
|
||||
GIF_STAT_APATH3 = (3<<10), // Data Transfer Path 3 (In progress) (Mask too)
|
||||
GIF_STAT_APATH1 = (1<<10), // Data Transfer Path 1 (In progress)
|
||||
GIF_STAT_APATH2 = (2<<10), // Data Transfer Path 2 (In progress)
|
||||
GIF_STAT_APATH3 = (3<<10), // Data Transfer Path 3 (In progress) (Mask too)
|
||||
GIF_STAT_DIR = (1<<12), // Transfer Direction
|
||||
GIF_STAT_FQC = (31<<24) // QWC in GIF-FIFO
|
||||
};
|
||||
|
@ -239,10 +239,10 @@ struct GIFregisters
|
|||
extern Path3Modes Path3progress;
|
||||
|
||||
extern void gsInterrupt();
|
||||
int _GIFchain();
|
||||
void GIFdma();
|
||||
void dmaGIF();
|
||||
void mfifoGIFtransfer(int qwc);
|
||||
void gifMFIFOInterrupt();
|
||||
extern int _GIFchain();
|
||||
extern void GIFdma();
|
||||
extern void dmaGIF();
|
||||
extern void mfifoGIFtransfer(int qwc);
|
||||
extern void gifMFIFOInterrupt();
|
||||
|
||||
#endif
|
||||
|
|
|
@ -134,10 +134,21 @@ enum DMAChcrAddresses
|
|||
|
||||
enum DMATadrAddresses
|
||||
{
|
||||
HWx_DMA0_TADR = 0x1f80108c,
|
||||
HWx_DMA1_TADR = 0x1f80109c,
|
||||
HWx_DMA2_TADR = 0x1f8010ac,
|
||||
HWx_DMA3_TADR = 0x1f8010bc,
|
||||
HWx_DMA4_TADR = 0x1f8010cc,
|
||||
HWx_DMA9_TADR = 0x1f80152c
|
||||
HWx_DMA5_TADR = 0x1f8010dc,
|
||||
HWx_DMA6_TADR = 0x1f8010ec,
|
||||
HWx_DMA7_TADR = 0x1f80150c,
|
||||
HWx_DMA8_TADR = 0x1f80151c,
|
||||
HWx_DMA9_TADR = 0x1f80152c,
|
||||
HWx_DMA10_TADR = 0x1f80153c,
|
||||
HWx_DMA11_TADR = 0x1f80154c,
|
||||
HWx_DMA12_TADR = 0x1f80155c
|
||||
};
|
||||
|
||||
/* Registers for the IOP Counters */
|
||||
enum IOPCountRegs
|
||||
{
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
<Option type="0" />
|
||||
<Option compiler="gcc" />
|
||||
<Compiler>
|
||||
<Add option="-march=i486" />
|
||||
<Add option="-g" />
|
||||
<Add option="`wx-config --version=2.8 --static=no --unicode=yes --debug=yes --cflags`" />
|
||||
<Add option="-DPCSX2_DEVBUILD" />
|
||||
|
@ -96,7 +97,8 @@
|
|||
<Add option="-fno-dse" />
|
||||
<Add option="-fno-tree-dse" />
|
||||
<Add option="-pipe -msse -msse2" />
|
||||
<Add option="-march=native" />
|
||||
<Add option="-mpreferred-stack-boundary=2" />
|
||||
<Add option="-m32" />
|
||||
<Add option="-DWX_PRECOMP" />
|
||||
<Add directory="$(SvnRootDir)/common/include/" />
|
||||
<Add directory="$(SvnRootDir)/3rdparty/" />
|
||||
|
|
|
@ -130,28 +130,31 @@ void memMapVUmicro()
|
|||
vtlb_MapHandler(vu0_micro_mem[CHECK_VU0REC ? 0 : 1],0x11000000,0x00004000);
|
||||
vtlb_MapHandler(vu1_micro_mem[CHECK_VU1REC ? 0 : 1],0x11008000,0x00004000);
|
||||
|
||||
// VU0/VU1 memory
|
||||
// (Like IOP memory, these are generally only used by the EE Bios kernel during
|
||||
// boot-up. Applications/games are "supposed" to use the thread-safe VIF
|
||||
// instead.)
|
||||
vtlb_MapBlock(VU0.Mem,0x11004000,0x00004000,0x1000);
|
||||
vtlb_MapBlock(VU1.Mem,0x1100c000,0x00004000);
|
||||
}
|
||||
|
||||
void memMapPhy()
|
||||
{
|
||||
//Main mem
|
||||
vtlb_MapBlock(psM,0x00000000,Ps2MemSize::Base);//mirrored on first 256 mb ?
|
||||
// Main memory
|
||||
vtlb_MapBlock(psM, 0x00000000,Ps2MemSize::Base);//mirrored on first 256 mb ?
|
||||
|
||||
//Rom
|
||||
vtlb_MapBlock(psR,0x1fc00000,Ps2MemSize::Rom);//Writable ?
|
||||
//Rom 1
|
||||
vtlb_MapBlock(psR1,0x1e000000,Ps2MemSize::Rom1);//Writable ?
|
||||
//Rom 2 ?
|
||||
vtlb_MapBlock(psR2,0x1e400000,Ps2MemSize::Rom2);//Writable ?
|
||||
//EEProm ?
|
||||
vtlb_MapBlock(psER,0x1e040000,Ps2MemSize::ERom);//Writable ?
|
||||
// Various ROMs (all read-only)
|
||||
vtlb_MapBlock(psR, 0x1fc00000,Ps2MemSize::Rom);
|
||||
vtlb_MapBlock(psR1, 0x1e000000,Ps2MemSize::Rom1);
|
||||
vtlb_MapBlock(psR2, 0x1e400000,Ps2MemSize::Rom2);
|
||||
vtlb_MapBlock(psER, 0x1e040000,Ps2MemSize::ERom);
|
||||
|
||||
//IOP mem
|
||||
// IOP memory
|
||||
// (used by the EE Bios Kernel during initial hardware initialization, Apps/Games
|
||||
// are "supposed" to use the thread-safe SIF instead.)
|
||||
vtlb_MapBlock(psxM,0x1c000000,0x00800000);
|
||||
|
||||
//These fallback to mem* stuff ...
|
||||
// Generic Handlers; These fallback to mem* stuff...
|
||||
vtlb_MapHandler(tlb_fallback_1,0x10000000,0x10000);
|
||||
vtlb_MapHandler(tlb_fallback_7,0x14000000,0x10000);
|
||||
vtlb_MapHandler(tlb_fallback_4,0x18000000,0x10000);
|
||||
|
@ -162,7 +165,8 @@ void memMapPhy()
|
|||
vtlb_MapHandler(tlb_fallback_2,0x1f800000,0x10000);
|
||||
vtlb_MapHandler(tlb_fallback_8,0x1f900000,0x10000);
|
||||
|
||||
// map specific optimized page handlers for HW accesses
|
||||
// Hardware Register Handlers : specialized/optimized per-page handling of HW register accesses
|
||||
// (note that hw_by_page handles are assigned in memReset prior to calling this function)
|
||||
vtlb_MapHandler(hw_by_page[0x0], 0x10000000, 0x01000);
|
||||
vtlb_MapHandler(hw_by_page[0x1], 0x10001000, 0x01000);
|
||||
vtlb_MapHandler(hw_by_page[0x2], 0x10002000, 0x01000);
|
||||
|
@ -177,6 +181,9 @@ void memMapPhy()
|
|||
|
||||
vtlb_MapHandler(gs_page_0, 0x12000000, 0x01000);
|
||||
vtlb_MapHandler(gs_page_1, 0x12001000, 0x01000);
|
||||
|
||||
// "Secret" IOP HW mappings - Used by EE Bios Kernel during boot and generally
|
||||
// left untouched after that, as per EE/IOP thread safety rules.
|
||||
|
||||
vtlb_MapHandler(hw_by_page[0x1], 0x1f801000, 0x01000);
|
||||
vtlb_MapHandler(hw_by_page[0x3], 0x1f803000, 0x01000);
|
||||
|
|
|
@ -66,14 +66,14 @@ int _SPR0chain()
|
|||
else
|
||||
mfifotransferred += spr0->qwc;
|
||||
|
||||
hwMFIFOWrite(spr0->madr, (u8*)&PS2MEM_SCRATCH[spr0->sadr & 0x3fff], spr0->qwc << 4);
|
||||
hwMFIFOWrite(spr0->madr, &psSu8(spr0->sadr), spr0->qwc << 4);
|
||||
spr0->madr += spr0->qwc << 4;
|
||||
spr0->madr = dmacRegs->rbor.ADDR + (spr0->madr & dmacRegs->rbsr.RMSK);
|
||||
break;
|
||||
|
||||
case NO_MFD:
|
||||
case MFD_RESERVED:
|
||||
memcpy_fast((u8*)pMem, &PS2MEM_SCRATCH[spr0->sadr & 0x3fff], spr0->qwc << 4);
|
||||
memcpy_fast((u8*)pMem, &psSu8(spr0->sadr), spr0->qwc << 4);
|
||||
|
||||
// clear VU mem also!
|
||||
TestClearVUs(spr0->madr, spr0->qwc << 2); // Wtf is going on here? AFAIK, only VIF should affect VU micromem (cottonvibes)
|
||||
|
@ -97,7 +97,7 @@ void _SPR0interleave()
|
|||
{
|
||||
int qwc = spr0->qwc;
|
||||
int sqwc = dmacRegs->sqwc.SQWC;
|
||||
int tqwc = dmacRegs->sqwc.TQWC;
|
||||
int tqwc = dmacRegs->sqwc.TQWC;
|
||||
u32 *pMem;
|
||||
|
||||
if (tqwc == 0) tqwc = qwc;
|
||||
|
@ -115,7 +115,7 @@ void _SPR0interleave()
|
|||
{
|
||||
case MFD_VIF1:
|
||||
case MFD_GIF:
|
||||
hwMFIFOWrite(spr0->madr, (u8*)&PS2MEM_SCRATCH[spr0->sadr & 0x3fff], spr0->qwc << 4);
|
||||
hwMFIFOWrite(spr0->madr, &psSu8(spr0->sadr), spr0->qwc << 4);
|
||||
mfifotransferred += spr0->qwc;
|
||||
break;
|
||||
|
||||
|
@ -123,7 +123,7 @@ void _SPR0interleave()
|
|||
case MFD_RESERVED:
|
||||
// clear VU mem also!
|
||||
TestClearVUs(spr0->madr, spr0->qwc << 2);
|
||||
memcpy_fast((u8*)pMem, &PS2MEM_SCRATCH[spr0->sadr & 0x3fff], spr0->qwc << 4);
|
||||
memcpy_fast((u8*)pMem, &psSu8(spr0->sadr), spr0->qwc << 4);
|
||||
break;
|
||||
}
|
||||
spr0->sadr += spr0->qwc * 16;
|
||||
|
@ -163,7 +163,7 @@ static __forceinline void _dmaSPR0()
|
|||
return;
|
||||
}
|
||||
// Destination Chain Mode
|
||||
ptag = (u32*) & PS2MEM_SCRATCH[spr0->sadr & 0x3fff];
|
||||
ptag = &psSu32(spr0->sadr);
|
||||
spr0->sadr += 16;
|
||||
|
||||
Tag::UnsafeTransfer(spr0, ptag);
|
||||
|
@ -186,25 +186,26 @@ static __forceinline void _dmaSPR0()
|
|||
break;
|
||||
|
||||
case TAG_CNT: // CNT - Transfer QWC following the tag.
|
||||
done = FALSE;
|
||||
done = false;
|
||||
break;
|
||||
|
||||
case TAG_END: // End - Transfer QWC following the tag
|
||||
done = TRUE;
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
|
||||
SPR0chain();
|
||||
if (spr0->chcr.TIE && Tag::IRQ(ptag)) //Check TIE bit of CHCR and IRQ bit of tag
|
||||
{
|
||||
//Console.WriteLn("SPR0 TIE");
|
||||
done = TRUE;
|
||||
done = true;
|
||||
}
|
||||
|
||||
spr0finished = done;
|
||||
|
||||
if (!done)
|
||||
{
|
||||
ptag = (u32*) & PS2MEM_SCRATCH[spr0->sadr & 0x3fff]; //Set memory pointer to SADR
|
||||
ptag = &psSu32(spr0->sadr); //Set memory pointer to SADR
|
||||
CPU_INT(8, ((u16)ptag[0]) / BIAS); // the lower 16bits of the tag / BIAS);
|
||||
return;
|
||||
}
|
||||
|
@ -227,8 +228,18 @@ void SPRFROMinterrupt()
|
|||
|
||||
if(mfifotransferred != 0)
|
||||
{
|
||||
switch (dmacRegs->ctrl.MFD)
|
||||
switch (dmacRegs->ctrl.MFD)
|
||||
{
|
||||
case MFD_VIF1: // Most common case.
|
||||
{
|
||||
if ((spr0->madr & ~dmacRegs->rbsr.RMSK) != dmacRegs->rbor.ADDR) Console.WriteLn("VIF MFIFO Write outside MFIFO area");
|
||||
spr0->madr = dmacRegs->rbor.ADDR + (spr0->madr & dmacRegs->rbsr.RMSK);
|
||||
//Console.WriteLn("mfifoVIF1transfer %x madr %x, tadr %x", vif1ch->chcr._u32, vif1ch->madr, vif1ch->tadr);
|
||||
mfifoVIF1transfer(mfifotransferred);
|
||||
mfifotransferred = 0;
|
||||
if (vif1ch->chcr.STR) return;
|
||||
break;
|
||||
}
|
||||
case MFD_GIF:
|
||||
{
|
||||
if ((spr0->madr & ~dmacRegs->rbsr.RMSK) != dmacRegs->rbor.ADDR) Console.WriteLn("GIF MFIFO Write outside MFIFO area");
|
||||
|
@ -239,16 +250,6 @@ void SPRFROMinterrupt()
|
|||
if (gif->chcr.STR) return;
|
||||
break;
|
||||
}
|
||||
case MFD_VIF1:
|
||||
{
|
||||
if ((spr0->madr & ~psHu32(DMAC_RBSR)) != psHu32(DMAC_RBOR)) Console.WriteLn("VIF MFIFO Write outside MFIFO area");
|
||||
spr0->madr = dmacRegs->rbor.ADDR + (spr0->madr & dmacRegs->rbsr.RMSK);
|
||||
//Console.WriteLn("mfifoVIF1transfer %x madr %x, tadr %x", vif1ch->chcr._u32, vif1ch->madr, vif1ch->tadr);
|
||||
mfifoVIF1transfer(mfifotransferred);
|
||||
mfifotransferred = 0;
|
||||
if (vif1ch->chcr.STR) return;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -258,7 +259,6 @@ void SPRFROMinterrupt()
|
|||
hwDmacIrq(DMAC_FROM_SPR);
|
||||
}
|
||||
|
||||
|
||||
void dmaSPR0() // fromSPR
|
||||
{
|
||||
SPR_LOG("dmaSPR0 chcr = %lx, madr = %lx, qwc = %lx, sadr = %lx",
|
||||
|
@ -267,7 +267,7 @@ void dmaSPR0() // fromSPR
|
|||
if ((spr0->chcr.MOD == CHAIN_MODE) && spr0->qwc == 0)
|
||||
{
|
||||
u32 *ptag;
|
||||
ptag = (u32*) & PS2MEM_SCRATCH[spr0->sadr & 0x3fff]; //Set memory pointer to SADR
|
||||
ptag = &psSu32(spr0->sadr); //Set memory pointer to SADR
|
||||
CPU_INT(8, (ptag[0] & 0xffff) / BIAS);
|
||||
return;
|
||||
}
|
||||
|
@ -279,7 +279,7 @@ void dmaSPR0() // fromSPR
|
|||
|
||||
__forceinline static void SPR1transfer(u32 *data, int size)
|
||||
{
|
||||
memcpy_fast(&PS2MEM_SCRATCH[spr1->sadr & 0x3fff], (u8*)data, size << 2);
|
||||
memcpy_fast(&psSu8(spr1->sadr), (u8*)data, size << 2);
|
||||
|
||||
spr1->sadr += size << 2;
|
||||
}
|
||||
|
@ -305,7 +305,6 @@ __forceinline void SPR1chain()
|
|||
spr1->qwc = 0;
|
||||
}
|
||||
|
||||
|
||||
void _SPR1interleave()
|
||||
{
|
||||
int qwc = spr1->qwc;
|
||||
|
@ -322,7 +321,7 @@ void _SPR1interleave()
|
|||
spr1->qwc = std::min(tqwc, qwc);
|
||||
qwc -= spr1->qwc;
|
||||
pMem = (u32*)dmaGetAddr(spr1->madr);
|
||||
memcpy_fast(&PS2MEM_SCRATCH[spr1->sadr & 0x3fff], (u8*)pMem, spr1->qwc << 4);
|
||||
memcpy_fast(&psSu8(spr1->sadr), (u8*)pMem, spr1->qwc << 4);
|
||||
spr1->sadr += spr1->qwc * 16;
|
||||
spr1->madr += (sqwc + spr1->qwc) * 16;
|
||||
}
|
||||
|
@ -405,11 +404,10 @@ void _dmaSPR1() // toSPR work function
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void dmaSPR1() // toSPR
|
||||
{
|
||||
|
||||
SPR_LOG("dmaSPR1 chcr = 0x%x, madr = 0x%x, qwc = 0x%x\n"
|
||||
" tadr = 0x%x, sadr = 0x%x",
|
||||
spr1->chcr._u32, spr1->madr, spr1->qwc,
|
||||
|
|
|
@ -365,7 +365,7 @@ void memSavingState::FreezeMem( void* data, int size )
|
|||
|
||||
void memSavingState::FreezeAll()
|
||||
{
|
||||
// 90% of all savestates fit in under 45 megs (and require more than 43 megs, so migght as well...)
|
||||
// 90% of all savestates fit in under 45 megs (and require more than 43 megs, so might as well...)
|
||||
m_memory.ChunkSize = ReallocThreshold;
|
||||
m_memory.MakeRoomFor( MemoryBaseAllocSize );
|
||||
|
||||
|
|
|
@ -201,8 +201,8 @@ __forceinline void SIF0Dma()
|
|||
else
|
||||
SIF_LOG(" EE SIF interrupt");
|
||||
|
||||
eesifbusy[0] = false;
|
||||
CPU_INT(5, cycles*BIAS);
|
||||
eesifbusy[0] = false;
|
||||
done = true;
|
||||
}
|
||||
else if (sif0.fifoSize >= 4) // Read a tag
|
||||
|
@ -216,7 +216,7 @@ __forceinline void SIF0Dma()
|
|||
sif0dma->madr = tag[1];
|
||||
|
||||
SIF_LOG(" EE SIF dest chain tag madr:%08X qwc:%04X id:%X irq:%d(%08X_%08X)", sif0dma->madr, sif0dma->qwc, (tag[0] >> 28)&3, (tag[0] >> 31)&1, tag[1], tag[0]);
|
||||
|
||||
|
||||
switch (Tag::Id(tag[0]))
|
||||
{
|
||||
case TAG_REFE:
|
||||
|
@ -277,9 +277,7 @@ __forceinline void SIF1Dma()
|
|||
ptag = _dmaGetAddr(sif1dma, sif1dma->tadr, DMAC_SIF1);
|
||||
if (ptag == NULL) return;
|
||||
|
||||
|
||||
sif1dma->chcr._u32 = (sif1dma->chcr._u32 & 0xFFFF) | ((*ptag) & 0xFFFF0000); // Copy the tag
|
||||
sif1dma->qwc = (u16)ptag[0];
|
||||
Tag::UnsafeTransfer(sif1dma, ptag);
|
||||
|
||||
if (sif1dma->chcr.TTE)
|
||||
{
|
||||
|
@ -287,6 +285,11 @@ __forceinline void SIF1Dma()
|
|||
SIF1write(ptag + 2, 2);
|
||||
}
|
||||
|
||||
if ((sif1dma->chcr.TIE) && (Tag::IRQ(ptag)))
|
||||
{
|
||||
Console.WriteLn("SIF1 TIE");
|
||||
sif1.end = 1;
|
||||
}
|
||||
//sif1.chain = 1;
|
||||
|
||||
switch (Tag::Id(ptag))
|
||||
|
@ -327,11 +330,6 @@ __forceinline void SIF1Dma()
|
|||
default:
|
||||
Console.WriteLn("Bad addr1 source chain");
|
||||
}
|
||||
if ((sif1dma->chcr.TIE) && (Tag::IRQ(ptag)))
|
||||
{
|
||||
Console.WriteLn("SIF1 TIE");
|
||||
sif1.end = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else // There's some data ready to transfer into the fifo..
|
||||
|
|
|
@ -70,7 +70,7 @@ extern void vSyncDebugStuff( uint frame );
|
|||
extern void SysPageFaultExceptionFilter( int signal, siginfo_t *info, void * );
|
||||
extern void __fastcall InstallLinuxExceptionHandler();
|
||||
extern void __fastcall ReleaseLinuxExceptionHandler();
|
||||
static void __unused NTFS_CompressFile( const wxString& file, bool compressStatus=true ) {}
|
||||
static void NTFS_CompressFile( const wxString& file, bool compressStatus=true ) {}
|
||||
|
||||
# define PCSX2_MEM_PROTECT_BEGIN() InstallLinuxExceptionHandler()
|
||||
# define PCSX2_MEM_PROTECT_END() ReleaseLinuxExceptionHandler()
|
||||
|
|
|
@ -128,7 +128,18 @@ bool SysThreadBase::Suspend( bool isBlocking )
|
|||
m_sem_event.Post();
|
||||
}
|
||||
|
||||
if( isBlocking ) m_RunningLock.Wait();
|
||||
if( isBlocking )
|
||||
{
|
||||
if( !m_RunningLock.Wait( wxTimeSpan( 0,0,3,0 ) ) )
|
||||
{
|
||||
// [TODO] : Implement proper deadlock handler here that lets the user continue
|
||||
// to wait, or issue a cancel to the thread.
|
||||
|
||||
throw Exception::ThreadTimedOut( L"Possible deadlock while suspending the " + m_name,
|
||||
m_name + L" is not responding to suspend requests. It may be deadlocked or just running *really* slow."
|
||||
);
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
@ -471,6 +482,8 @@ void SysCoreThread::CpuExecute()
|
|||
|
||||
void SysCoreThread::ExecuteTaskInThread()
|
||||
{
|
||||
Threading::EnableHiresScheduler();
|
||||
|
||||
tls_coreThread = this;
|
||||
|
||||
m_sem_event.WaitRaw();
|
||||
|
@ -497,6 +510,8 @@ void SysCoreThread::OnResumeInThread( bool isSuspended )
|
|||
// Invoked by the pthread_exit or pthread_cancel
|
||||
void SysCoreThread::OnCleanupInThread()
|
||||
{
|
||||
Threading::DisableHiresScheduler();
|
||||
|
||||
if( g_plugins != NULL )
|
||||
g_plugins->Close();
|
||||
|
||||
|
|
|
@ -403,7 +403,6 @@ public:
|
|||
// Console / Program Logging Helpers
|
||||
// ----------------------------------------------------------------------------
|
||||
ConsoleLogFrame* GetProgramLog();
|
||||
void ProgramLog_CountMsg();
|
||||
void ProgramLog_PostEvent( wxEvent& evt );
|
||||
void EnableAllLogging() const;
|
||||
void DisableWindowLogging() const;
|
||||
|
|
|
@ -273,15 +273,22 @@ bool Pcsx2App::PrepForExit( bool canCancel )
|
|||
throw Exception::CancelEvent( "Savestate in progress, cannot close program (close event delayed)" );
|
||||
}
|
||||
|
||||
/*
|
||||
if( canCancel )
|
||||
{
|
||||
// TODO: Confirm with the user?
|
||||
// Problem: Suspend is often slow because it needs to wait until the current EE frame
|
||||
// has finished processing (if the GS or logging has incurred severe overhead this makes
|
||||
// closing PCSX2 difficult). A non-blocking suspend with modal dialog might suffice
|
||||
// however. --air
|
||||
|
||||
bool resume = CoreThread.Suspend();
|
||||
if( /* TODO: Confirm with the user? */ false )
|
||||
if( false )
|
||||
{
|
||||
if(resume) CoreThread.Resume();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
m_evtsrc_AppStatus.Dispatch( AppStatus_Exiting );
|
||||
CleanupMess();
|
||||
|
|
|
@ -27,14 +27,14 @@ BEGIN_DECLARE_EVENT_TYPES()
|
|||
DECLARE_EVENT_TYPE(wxEVT_LOG_Write, -1)
|
||||
DECLARE_EVENT_TYPE(wxEVT_LOG_Newline, -1)
|
||||
DECLARE_EVENT_TYPE(wxEVT_SetTitleText, -1)
|
||||
DECLARE_EVENT_TYPE(wxEVT_SemaphoreWait, -1)
|
||||
DECLARE_EVENT_TYPE(wxEVT_FlushQueue, -1)
|
||||
END_DECLARE_EVENT_TYPES()
|
||||
|
||||
DEFINE_EVENT_TYPE(wxEVT_LOG_Write)
|
||||
DEFINE_EVENT_TYPE(wxEVT_LOG_Newline)
|
||||
DEFINE_EVENT_TYPE(wxEVT_SetTitleText)
|
||||
DEFINE_EVENT_TYPE(wxEVT_DockConsole)
|
||||
DEFINE_EVENT_TYPE(wxEVT_SemaphoreWait)
|
||||
DEFINE_EVENT_TYPE(wxEVT_FlushQueue)
|
||||
|
||||
// C++ requires abstract destructors to exist, even thought hey're abstract.
|
||||
PipeRedirectionBase::~PipeRedirectionBase() throw() {}
|
||||
|
@ -226,12 +226,23 @@ ConsoleLogFrame::ConsoleLogFrame( MainEmuFrame *parent, const wxString& title, A
|
|||
, m_TextCtrl( *new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
|
||||
wxTE_MULTILINE | wxHSCROLL | wxTE_READONLY | wxTE_RICH2 ) )
|
||||
, m_ColorTable( options.FontSize )
|
||||
, m_curcolor( DefaultConsoleColor )
|
||||
, m_msgcounter( 0 )
|
||||
|
||||
, m_pendingFlushes( 0 )
|
||||
, m_WaitingThreadsForFlush( 0 )
|
||||
|
||||
, m_ThawThrottle( 0 )
|
||||
, m_ThawNeeded( false )
|
||||
, m_ThawPending( false )
|
||||
|
||||
, m_QueueColorSection( L"ConsoleLog::QueueColorSection" )
|
||||
, m_QueueBuffer( L"ConsoleLog::QueueBuffer" )
|
||||
, m_CurQueuePos( false )
|
||||
|
||||
, m_threadlogger( EnableThreadedLoggingTest ? new ConsoleTestThread() : NULL )
|
||||
{
|
||||
m_TextCtrl.SetBackgroundColour( wxColor( 230, 235, 242 ) );
|
||||
|
||||
m_TextCtrl.SetDefaultStyle( m_ColorTable[DefaultConsoleColor] );
|
||||
|
||||
// create Log menu (contains most options)
|
||||
wxMenuBar *pMenuBar = new wxMenuBar();
|
||||
wxMenu& menuLog = *new wxMenu();
|
||||
|
@ -263,7 +274,6 @@ ConsoleLogFrame::ConsoleLogFrame( MainEmuFrame *parent, const wxString& title, A
|
|||
|
||||
// status bar for menu prompts
|
||||
CreateStatusBar();
|
||||
ClearColor();
|
||||
|
||||
SetSize( wxRect( options.DisplayPosition, options.DisplaySize ) );
|
||||
Show( options.Visible );
|
||||
|
@ -281,11 +291,10 @@ ConsoleLogFrame::ConsoleLogFrame( MainEmuFrame *parent, const wxString& title, A
|
|||
Connect( wxEVT_MOVE, wxMoveEventHandler(ConsoleLogFrame::OnMoveAround) );
|
||||
Connect( wxEVT_SIZE, wxSizeEventHandler(ConsoleLogFrame::OnResize) );
|
||||
|
||||
Connect( wxEVT_LOG_Write, wxCommandEventHandler(ConsoleLogFrame::OnWrite) );
|
||||
Connect( wxEVT_LOG_Newline, wxCommandEventHandler(ConsoleLogFrame::OnNewline) );
|
||||
Connect( wxEVT_SetTitleText, wxCommandEventHandler(ConsoleLogFrame::OnSetTitle) );
|
||||
Connect( wxEVT_DockConsole, wxCommandEventHandler(ConsoleLogFrame::OnDockedMove) );
|
||||
Connect( wxEVT_SemaphoreWait, wxCommandEventHandler(ConsoleLogFrame::OnSemaphoreWait) );
|
||||
|
||||
Connect( wxEVT_FlushQueue, wxCommandEventHandler(ConsoleLogFrame::OnFlushEvent) );
|
||||
|
||||
if( m_threadlogger != NULL )
|
||||
m_threadlogger->Start();
|
||||
|
@ -297,51 +306,74 @@ ConsoleLogFrame::~ConsoleLogFrame()
|
|||
wxGetApp().OnProgramLogClosed();
|
||||
}
|
||||
|
||||
void ConsoleLogFrame::SetColor( ConsoleColors color )
|
||||
{
|
||||
if( color != m_curcolor )
|
||||
m_TextCtrl.SetDefaultStyle( m_ColorTable[m_curcolor=color] );
|
||||
}
|
||||
|
||||
void ConsoleLogFrame::ClearColor()
|
||||
{
|
||||
if( DefaultConsoleColor != m_curcolor )
|
||||
m_TextCtrl.SetDefaultStyle( m_ColorTable[m_curcolor=DefaultConsoleColor] );
|
||||
}
|
||||
|
||||
void ConsoleLogFrame::Write( const wxString& text )
|
||||
{
|
||||
// remove selection (WriteText is in fact ReplaceSelection)
|
||||
// TODO : Optimize this to only replace selection if some selection
|
||||
// messages have been received since the last write.
|
||||
|
||||
#ifdef __WXMSW__
|
||||
wxTextPos nLen = m_TextCtrl.GetLastPosition();
|
||||
m_TextCtrl.SetSelection(nLen, nLen);
|
||||
#endif
|
||||
|
||||
m_TextCtrl.AppendText( text );
|
||||
|
||||
// cap at 256k for now...
|
||||
// fixme - 256k runs well on win32 but appears to be very sluggish on linux. Might
|
||||
// need platform dependent defaults here. - air
|
||||
if( m_TextCtrl.GetLastPosition() > 0x40000 )
|
||||
{
|
||||
m_TextCtrl.Remove( 0, 0x10000 );
|
||||
}
|
||||
}
|
||||
int m_pendingFlushes = 0;
|
||||
|
||||
// Implementation note: Calls SetColor and Write( text ). Override those virtuals
|
||||
// and this one will magically follow suite. :)
|
||||
void ConsoleLogFrame::Write( ConsoleColors color, const wxString& text )
|
||||
{
|
||||
SetColor( color );
|
||||
Write( text );
|
||||
//#ifdef PCSX2_SEH
|
||||
pthread_testcancel();
|
||||
//#endif
|
||||
|
||||
ScopedLock lock( m_QueueLock );
|
||||
|
||||
if( m_QueueColorSection.GetLength() == 0 )
|
||||
{
|
||||
pxAssertMsg( m_CurQueuePos == 0, "Queue's character position didn't get reset in sync with it's ColorSection table." );
|
||||
}
|
||||
|
||||
if( (m_QueueColorSection.GetLength() == 0) || ((color != Color_Current) && (m_QueueColorSection.GetLast().color != color)) )
|
||||
{
|
||||
++m_CurQueuePos; // Don't overwrite the NULL;
|
||||
m_QueueColorSection.Add( ColorSection(color, m_CurQueuePos) );
|
||||
}
|
||||
|
||||
int endpos = m_CurQueuePos + text.Length();
|
||||
m_QueueBuffer.MakeRoomFor( endpos + 1 ); // and the null!!
|
||||
memcpy_fast( &m_QueueBuffer[m_CurQueuePos], text.c_str(), sizeof(wxChar) * text.Length() );
|
||||
m_CurQueuePos = endpos;
|
||||
|
||||
// this NULL may be overwritten if the next message sent doesn't perform a color change.
|
||||
m_QueueBuffer[m_CurQueuePos] = 0;
|
||||
|
||||
// Idle events don't always pass (wx blocks them when moving windows or using menus, for
|
||||
// example). So let's hackfix it so that an alternate message is posted if the queue is
|
||||
// "piling up."
|
||||
|
||||
if( m_pendingFlushes == 0 )
|
||||
{
|
||||
wxCommandEvent evt( wxEVT_FlushQueue );
|
||||
evt.SetInt( 0 );
|
||||
GetEventHandler()->AddPendingEvent( evt );
|
||||
}
|
||||
|
||||
++m_pendingFlushes;
|
||||
|
||||
if( m_pendingFlushes > 32 && !wxThread::IsMain() )
|
||||
{
|
||||
++m_WaitingThreadsForFlush;
|
||||
lock.Unlock();
|
||||
|
||||
if( !m_sem_QueueFlushed.WaitRaw( wxTimeSpan( 0,0,0,500 ) ) )
|
||||
{
|
||||
// Necessary since the main thread could grab the lock and process before
|
||||
// the above function actually returns (gotta love threading!)
|
||||
lock.Lock();
|
||||
if( m_WaitingThreadsForFlush != 0 ) --m_WaitingThreadsForFlush;
|
||||
}
|
||||
else
|
||||
{
|
||||
// give gui thread time to repaint and handle other pending messages.
|
||||
// (those are prioritized lower than wxEvents, typically)
|
||||
Sleep(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ConsoleLogFrame::Newline()
|
||||
{
|
||||
Write( L"\n" );
|
||||
Write( Color_Current, L"\n" );
|
||||
}
|
||||
|
||||
void ConsoleLogFrame::DoClose()
|
||||
|
@ -364,7 +396,7 @@ void ConsoleLogFrame::DockedMove()
|
|||
// * Logging Events
|
||||
// =================================================================================
|
||||
|
||||
// Special event recieved from a window we're docked against.
|
||||
// Special event received from a window we're docked against.
|
||||
void ConsoleLogFrame::OnDockedMove( wxCommandEvent& event )
|
||||
{
|
||||
DockedMove();
|
||||
|
@ -466,7 +498,7 @@ void ConsoleLogFrame::OnFontSize( wxMenuEvent& evt )
|
|||
|
||||
m_conf.FontSize = ptsize;
|
||||
m_ColorTable.SetFont( ptsize );
|
||||
m_TextCtrl.SetDefaultStyle( m_ColorTable[m_curcolor] );
|
||||
m_TextCtrl.SetDefaultStyle( m_ColorTable[Color_White] );
|
||||
|
||||
// TODO: Process the attributes of each character and upgrade the font size,
|
||||
// while still retaining color and bold settings... (might be slow but then
|
||||
|
@ -478,102 +510,113 @@ void ConsoleLogFrame::OnFontSize( wxMenuEvent& evt )
|
|||
// Logging Events (typically received from Console class interfaces)
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void ConsoleLogFrame::OnWrite( wxCommandEvent& event )
|
||||
{
|
||||
Write( (ConsoleColors)event.GetExtraLong(), event.GetString() );
|
||||
DoMessage();
|
||||
}
|
||||
|
||||
void ConsoleLogFrame::OnNewline( wxCommandEvent& event )
|
||||
{
|
||||
Newline();
|
||||
DoMessage();
|
||||
}
|
||||
|
||||
void ConsoleLogFrame::OnSetTitle( wxCommandEvent& event )
|
||||
{
|
||||
SetTitle( event.GetString() );
|
||||
}
|
||||
|
||||
void ConsoleLogFrame::OnSemaphoreWait( wxCommandEvent& event )
|
||||
void ConsoleLogFrame::OnFlushEvent( wxCommandEvent& evt )
|
||||
{
|
||||
m_semaphore.Post();
|
||||
ScopedLock locker( m_QueueLock );
|
||||
|
||||
if( m_CurQueuePos != 0 )
|
||||
{
|
||||
DoFlushQueue();
|
||||
|
||||
#ifdef __WXMSW__
|
||||
// This nicely sets the scroll position to the end of our log window, regardless of if
|
||||
// the textctrl has focus or not. The wxWidgets AppendText() function uses EM_LINESCROLL
|
||||
// instead, which tends to be much faster for high-volume logs, but also ends up refreshing
|
||||
// the console in sloppy fashion for normal logging.
|
||||
|
||||
// (both are needed, the WM_VSCROLL makes the scrolling smooth, and the EM_LINESCROLL avoids
|
||||
// weird errors when the buffer reaches "max" and starts clearing old history)
|
||||
|
||||
::SendMessage((HWND)m_TextCtrl.GetHWND(), WM_VSCROLL, SB_BOTTOM, (LPARAM)NULL);
|
||||
::SendMessage((HWND)m_TextCtrl.GetHWND(), EM_LINESCROLL, 0, m_TextCtrl.GetNumberOfLines());
|
||||
#endif
|
||||
//m_TextCtrl.Thaw();
|
||||
}
|
||||
|
||||
// Implementation note: I tried desperately to move this into wxEVT_IDLE, on the theory that
|
||||
// we don't actually want to wake up pending threads until after the GUI's finished all its
|
||||
// paperwork. But wxEVT_IDLE doesn't work when you click menus or the title bar of a window,
|
||||
// making it pretty well annoyingly useless for just about anything. >_<
|
||||
|
||||
// Workaround: I added a Sleep(1) to the DoWrite method to give the GUI some time to
|
||||
// do its paperwork.
|
||||
|
||||
if( m_WaitingThreadsForFlush > 0 )
|
||||
{
|
||||
do {
|
||||
m_sem_QueueFlushed.Post();
|
||||
} while( --m_WaitingThreadsForFlush > 0 );
|
||||
|
||||
int count = m_sem_QueueFlushed.Count();
|
||||
while( count < 0 ) m_sem_QueueFlushed.Post();
|
||||
}
|
||||
}
|
||||
|
||||
static const wxTimeSpan high_volume_timeout( 0, 0, 0, 500 );
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Deadlock protection: High volume logs will over-tax our message pump and cause the
|
||||
// GUI to become inaccessible. The cool solution would be a threaded log window, but wx
|
||||
// is entirely un-safe for that kind of threading. So instead I use a message counter
|
||||
// that stalls non-GUI threads when they attempt to over-tax an already burdened log.
|
||||
// If too many messages get queued up, non-gui threads are stalled to allow the gui to
|
||||
// catch up.
|
||||
void ConsoleLogFrame::CountMessage()
|
||||
void ConsoleLogFrame::DoFlushQueue()
|
||||
{
|
||||
long result = _InterlockedIncrement( &m_msgcounter );
|
||||
int len = m_QueueColorSection.GetLength();
|
||||
pxAssert( len != 0 );
|
||||
|
||||
if( result > 0x20 ) // 0x20 -- arbitrary value that seems to work well (tested on P4 and C2D)
|
||||
// Note, freezing/thawing actually seems to cause more overhead than it solves.
|
||||
// It might be useful if we're posting like dozens of messages, but in our case
|
||||
// we only post 1-4 typically, so better to leave things enabled.
|
||||
//m_TextCtrl.Freeze();
|
||||
|
||||
// Manual InsertionPoint tracking avoids a lot of overhead in SetInsertionPointEnd()
|
||||
wxTextPos insertPoint = m_TextCtrl.GetLastPosition();
|
||||
|
||||
// cap at 256k for now...
|
||||
// fixme - 256k runs well on win32 but appears to be very sluggish on linux (but that could
|
||||
// be a result of my using Xming + CoLinux). Might need platform dependent defaults here. --air
|
||||
if( (insertPoint + m_CurQueuePos) > 0x40000 )
|
||||
{
|
||||
if( !wxThread::IsMain() )
|
||||
int toKeep = 0x40000 - m_CurQueuePos;
|
||||
if( toKeep <= 10 )
|
||||
{
|
||||
// Append an event that'll post up our semaphore. It'll typically get run "in
|
||||
// order" which means when it posts all queued messages will have been processed.
|
||||
|
||||
// GTK+ / Timeout: We need a timeout on our semaphore to avoid deadlocking in GTK+,
|
||||
// because for some reason it can't friggen process messages from a wxYield()
|
||||
// (which is used from mutex and semaphore locks on the main thread to handle
|
||||
// messages from child threads, like this one!).
|
||||
|
||||
// Leaving it enabled on Windows as well for now since it's probably a "good idea" to avoid
|
||||
// deadlocking in some totally unforseeably random happenstance sircumstance, and I don't
|
||||
// think it'll have an impact on performance. --air
|
||||
|
||||
wxCommandEvent evt( wxEVT_SemaphoreWait );
|
||||
GetEventHandler()->AddPendingEvent( evt );
|
||||
m_semaphore.WaitRaw( high_volume_timeout );
|
||||
m_TextCtrl.Clear();
|
||||
insertPoint = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
int toRemove = 0x40000 - toKeep;
|
||||
if( toRemove < 0x10000 ) toRemove = 0x10000;
|
||||
m_TextCtrl.Remove( 0, toRemove );
|
||||
insertPoint -= toRemove;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Thread Safety note: This function expects to be called from the Main GUI thread
|
||||
// only. If called from a thread other than Main, it will generate an assertion failure.
|
||||
//
|
||||
void ConsoleLogFrame::DoMessage()
|
||||
{
|
||||
AllowFromMainThreadOnly();
|
||||
m_TextCtrl.SetInsertionPoint( insertPoint );
|
||||
|
||||
int cur = _InterlockedDecrement( &m_msgcounter );
|
||||
|
||||
// We need to freeze the control if there are more than 2 pending messages,
|
||||
// otherwise the redraw of the console will prevent it from ever being able to
|
||||
// catch up with the rate the queue is being filled, and the whole app could
|
||||
// deadlock. >_<
|
||||
|
||||
if( m_TextCtrl.IsFrozen() )
|
||||
for( int i=0; i<len; ++i )
|
||||
{
|
||||
if( cur < 1 )
|
||||
m_TextCtrl.Thaw();
|
||||
}
|
||||
else if( cur >= 3 )
|
||||
{
|
||||
m_TextCtrl.Freeze();
|
||||
}
|
||||
}
|
||||
if( m_QueueColorSection[i].color != Color_Current )
|
||||
m_TextCtrl.SetDefaultStyle( m_ColorTable[m_QueueColorSection[i].color] );
|
||||
|
||||
const wxString passin( &m_QueueBuffer[m_QueueColorSection[i].startpoint] );
|
||||
|
||||
m_TextCtrl.WriteText( passin );
|
||||
insertPoint += passin.Length();
|
||||
}
|
||||
|
||||
m_TextCtrl.SetInsertionPoint( insertPoint );
|
||||
|
||||
m_CurQueuePos = 0;
|
||||
m_QueueColorSection.Clear();
|
||||
m_pendingFlushes = 0;
|
||||
|
||||
//m_TextCtrl.ShowPosition( insertPoint );
|
||||
}
|
||||
|
||||
ConsoleLogFrame* Pcsx2App::GetProgramLog()
|
||||
{
|
||||
return m_ProgramLogBox;
|
||||
}
|
||||
|
||||
void Pcsx2App::ProgramLog_CountMsg()
|
||||
{
|
||||
// New console log object model makes this check obsolete:
|
||||
//if( m_ProgramLogBox == NULL ) return;
|
||||
m_ProgramLogBox->CountMessage();
|
||||
}
|
||||
|
||||
void Pcsx2App::ProgramLog_PostEvent( wxEvent& evt )
|
||||
{
|
||||
// New console log object model makes this check obsolete:
|
||||
|
@ -655,37 +698,21 @@ template< const IConsoleWriter& secondary >
|
|||
static void __concall ConsoleToWindow_Newline()
|
||||
{
|
||||
secondary.Newline();
|
||||
|
||||
wxCommandEvent evt( wxEVT_LOG_Newline );
|
||||
((Pcsx2App&)*wxTheApp).ProgramLog_PostEvent( evt );
|
||||
((Pcsx2App&)*wxTheApp).ProgramLog_CountMsg();
|
||||
((Pcsx2App&)*wxTheApp).GetProgramLog()->Newline();
|
||||
}
|
||||
|
||||
template< const IConsoleWriter& secondary >
|
||||
static void __concall ConsoleToWindow_DoWrite( const wxString& fmt )
|
||||
{
|
||||
secondary.DoWrite( fmt );
|
||||
|
||||
wxCommandEvent evt( wxEVT_LOG_Write );
|
||||
evt.SetString( fmt );
|
||||
evt.SetExtraLong( th_CurrentColor );
|
||||
((Pcsx2App&)*wxTheApp).ProgramLog_PostEvent( evt );
|
||||
((Pcsx2App&)*wxTheApp).ProgramLog_CountMsg();
|
||||
((Pcsx2App&)*wxTheApp).GetProgramLog()->Write( th_CurrentColor, fmt );
|
||||
}
|
||||
|
||||
template< const IConsoleWriter& secondary >
|
||||
static void __concall ConsoleToWindow_DoWriteLn( const wxString& fmt )
|
||||
{
|
||||
secondary.DoWriteLn( fmt );
|
||||
|
||||
// Implementation note: I've duplicated Write+Newline behavior here to avoid polluting
|
||||
// the message pump with lots of erroneous messages (Newlines can be bound into Write message).
|
||||
|
||||
wxCommandEvent evt( wxEVT_LOG_Write );
|
||||
evt.SetString( fmt + L"\n" );
|
||||
evt.SetExtraLong( th_CurrentColor );
|
||||
((Pcsx2App&)*wxTheApp).ProgramLog_PostEvent( evt );
|
||||
((Pcsx2App&)*wxTheApp).ProgramLog_CountMsg();
|
||||
((Pcsx2App&)*wxTheApp).GetProgramLog()->Write( th_CurrentColor, fmt + L"\n" );
|
||||
}
|
||||
|
||||
typedef void __concall DoWriteFn(const wxString&);
|
||||
|
|
|
@ -121,26 +121,74 @@ protected:
|
|||
}
|
||||
};
|
||||
|
||||
class ColorSection
|
||||
{
|
||||
public:
|
||||
ConsoleColors color;
|
||||
int startpoint;
|
||||
|
||||
ColorSection() {}
|
||||
ColorSection( ConsoleColors _color, int msgptr ) : color(_color), startpoint(msgptr) { }
|
||||
};
|
||||
|
||||
protected:
|
||||
ConLogConfig& m_conf;
|
||||
wxTextCtrl& m_TextCtrl;
|
||||
ColorArray m_ColorTable;
|
||||
ConsoleColors m_curcolor;
|
||||
volatile long m_msgcounter; // used to track queued messages and throttle load placed on the gui message pump
|
||||
|
||||
Semaphore m_semaphore;
|
||||
// this int throttles freeze/thaw of the display, by cycling from -2 to 4, roughly.
|
||||
// (negative values force thaw, positive values indicate thaw is disabled. This is
|
||||
// needed because the wxWidgets Thaw implementation uses a belated paint message,
|
||||
// and if we Freeze on the very next queued message after thawing, the repaint
|
||||
// never happens)
|
||||
int m_ThawThrottle;
|
||||
|
||||
// If a freeze is executed, this is set true (without this, wx asserts)
|
||||
bool m_ThawNeeded;
|
||||
|
||||
// Set true when a Thaw message is sent (avoids cluttering the message pump with redundant
|
||||
// requests)
|
||||
bool m_ThawPending;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Queue State Management Vars
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// This is a counter of the total number of pending flushes across all threads.
|
||||
// If the value exceeds a threshold, threads begin throttling to avoid deadlocking
|
||||
// the GUI.
|
||||
volatile int m_pendingFlushes;
|
||||
|
||||
// This is a counter of the number of threads waiting for the Queue to flush.
|
||||
volatile int m_WaitingThreadsForFlush;
|
||||
|
||||
// Used by threads waiting on the queue to flush.
|
||||
Semaphore m_sem_QueueFlushed;
|
||||
|
||||
// Lock object for accessing or modifying the following three vars:
|
||||
// m_QueueBuffer, m_QueueColorSelection, m_CurQueuePos
|
||||
MutexLockRecursive m_QueueLock;
|
||||
|
||||
// Describes a series of colored text sections in the m_QueueBuffer.
|
||||
SafeList<ColorSection> m_QueueColorSection;
|
||||
|
||||
// Series of Null-terminated strings, each one has a corresponding entry in
|
||||
// m_QueueColorSelection.
|
||||
SafeArray<wxChar> m_QueueBuffer;
|
||||
|
||||
// Current write position into the m_QueueBuffer;
|
||||
int m_CurQueuePos;
|
||||
|
||||
// Threaded log spammer, useful for testing console logging performance.
|
||||
ConsoleTestThread* m_threadlogger;
|
||||
// (alternatively you can enable Disasm logging in any recompiler and achieve
|
||||
// a similar effect)
|
||||
ConsoleTestThread* m_threadlogger;
|
||||
|
||||
public:
|
||||
// ctor & dtor
|
||||
ConsoleLogFrame( MainEmuFrame *pParent, const wxString& szTitle, ConLogConfig& options );
|
||||
virtual ~ConsoleLogFrame();
|
||||
|
||||
virtual void Write( const wxString& text );
|
||||
virtual void SetColor( ConsoleColors color );
|
||||
virtual void ClearColor();
|
||||
virtual void DockedMove();
|
||||
|
||||
// Retrieves the current configuration options settings for this box.
|
||||
|
@ -149,11 +197,8 @@ public:
|
|||
|
||||
void Write( ConsoleColors color, const wxString& text );
|
||||
void Newline();
|
||||
void CountMessage();
|
||||
void DoMessage();
|
||||
|
||||
protected:
|
||||
|
||||
// menu callbacks
|
||||
virtual void OnOpen (wxMenuEvent& event);
|
||||
virtual void OnClose(wxMenuEvent& event);
|
||||
|
@ -164,14 +209,14 @@ protected:
|
|||
|
||||
virtual void OnCloseWindow(wxCloseEvent& event);
|
||||
|
||||
void OnWrite( wxCommandEvent& event );
|
||||
void OnNewline( wxCommandEvent& event );
|
||||
void OnSetTitle( wxCommandEvent& event );
|
||||
void OnDockedMove( wxCommandEvent& event );
|
||||
void OnSemaphoreWait( wxCommandEvent& event );
|
||||
void OnIdleEvent( wxIdleEvent& event );
|
||||
void OnFlushEvent( wxCommandEvent& event );
|
||||
|
||||
// common part of OnClose() and OnCloseWindow()
|
||||
virtual void DoClose();
|
||||
void DoFlushQueue();
|
||||
|
||||
void OnMoveAround( wxMoveEvent& evt );
|
||||
void OnResize( wxSizeEvent& evt );
|
||||
|
|
|
@ -53,14 +53,14 @@ Dialogs::ImportSettingsDialog::ImportSettingsDialog( wxWindow* parent ) :
|
|||
Connect( b_over->GetId(), wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(ImportSettingsDialog::OnOverwrite_Click) );
|
||||
}
|
||||
|
||||
void Dialogs::ImportSettingsDialog::OnImport_Click( __unused wxCommandEvent& evt )
|
||||
void Dialogs::ImportSettingsDialog::OnImport_Click( wxCommandEvent& /* evt */ )
|
||||
{
|
||||
AppConfig_OnChangedSettingsFolder( false ); // ... and import existing settings
|
||||
g_Conf->Folders.Bios.Mkdir();
|
||||
EndModal( wxID_OK );
|
||||
}
|
||||
|
||||
void Dialogs::ImportSettingsDialog::OnOverwrite_Click( __unused wxCommandEvent& evt )
|
||||
void Dialogs::ImportSettingsDialog::OnOverwrite_Click( wxCommandEvent& /* evt */ )
|
||||
{
|
||||
AppConfig_OnChangedSettingsFolder( true ); // ... and overwrite any existing settings
|
||||
g_Conf->Folders.Bios.Mkdir();
|
||||
|
|
|
@ -37,7 +37,7 @@ Panels::DirPickerPanel& Panels::BasePathsPanel::AddDirPicker( wxBoxSizer& sizer,
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
Panels::StandardPathsPanel::StandardPathsPanel( wxWindow& parent, __unused int idealWidth ) :
|
||||
Panels::StandardPathsPanel::StandardPathsPanel( wxWindow& parent, int /* idealWidth */ ) :
|
||||
BasePathsPanel( parent )
|
||||
{
|
||||
s_main.AddSpacer( BetweenFolderSpace );
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
// zerofrog(@gmail.com)
|
||||
.intel_syntax noprefix
|
||||
|
||||
.extern svudispfntemp
|
||||
.extern s_TotalVUCycles
|
||||
.extern s_callstack
|
||||
.extern s_vu1esp
|
||||
|
@ -49,23 +48,3 @@ SuperVUEndProgram:
|
|||
call SuperVUCleanupProgram
|
||||
jmp [s_callstack] // so returns correctly
|
||||
|
||||
|
||||
.globl svudispfn
|
||||
svudispfn:
|
||||
mov [g_curdebugvu], eax
|
||||
mov s_saveecx, ecx
|
||||
mov s_saveedx, edx
|
||||
mov s_saveebx, ebx
|
||||
mov s_saveesi, esi
|
||||
mov s_saveedi, edi
|
||||
mov s_saveebp, ebp
|
||||
|
||||
call svudispfntemp
|
||||
|
||||
mov ecx, s_saveecx
|
||||
mov edx, s_saveedx
|
||||
mov ebx, s_saveebx
|
||||
mov esi, s_saveesi
|
||||
mov edi, s_saveedi
|
||||
mov ebp, s_saveebp
|
||||
ret
|
|
@ -52,12 +52,17 @@ extern void iDumpVU1Registers();
|
|||
// SuperVURec optimization options, uncomment only for debugging purposes
|
||||
#define SUPERVU_CACHING // vu programs are saved and queried via memcompare (should be no reason to disable this)
|
||||
#define SUPERVU_WRITEBACKS // don't flush the writebacks after every block
|
||||
#define SUPERVU_X86CACHING // use x86reg caching (faster) (not really. rather lots slower :p (rama) )
|
||||
#define SUPERVU_VIBRANCHDELAY // when integers are modified right before a branch that uses the integer,
|
||||
// the old integer value is used in the branch, fixes kh2
|
||||
|
||||
#define SUPERVU_PROPAGATEFLAGS // the correct behavior of VUs, for some reason superman breaks gfx with it on...
|
||||
|
||||
// use x86reg caching (faster) (not really. rather lots slower :p (rama) )
|
||||
// ... and buggy too since we disabled EBP. Causes GoW2 to hang. Let's get rid of it,
|
||||
// sVU is only here to serve as a regression model for Nan/INF behavior anyway. (--air)
|
||||
//#define SUPERVU_X86CACHING
|
||||
|
||||
|
||||
// registers won't be flushed at block boundaries (faster) (nothing noticable speed-wise, causes SPS in Ratchet and clank (Nneeve) )
|
||||
#ifndef PCSX2_DEBUG
|
||||
//#define SUPERVU_INTERCACHING
|
||||
|
@ -2791,26 +2796,9 @@ u32 g_curdebugvu;
|
|||
|
||||
//float vuDouble(u32 f);
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
__declspec(naked) static void svudispfn()
|
||||
{
|
||||
__asm
|
||||
{
|
||||
mov g_curdebugvu, eax
|
||||
mov s_saveecx, ecx
|
||||
mov s_saveedx, edx
|
||||
mov s_saveebx, ebx
|
||||
mov s_saveesi, esi
|
||||
mov s_saveedi, edi
|
||||
mov s_saveebp, ebp
|
||||
}
|
||||
#else
|
||||
|
||||
void svudispfntemp()
|
||||
{
|
||||
#endif
|
||||
|
||||
#ifdef PCSX2_DEBUG
|
||||
static void __fastcall svudispfn( int g_curdebugvu )
|
||||
{
|
||||
static u32 i;
|
||||
|
||||
if (((vudump&8) && g_curdebugvu) || ((vudump&0x80) && !g_curdebugvu)) //&& g_vu1lastrec != g_vu1last ) {
|
||||
|
@ -2837,21 +2825,8 @@ void svudispfntemp()
|
|||
|
||||
g_vu1lastrec = s_svulast;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
__asm
|
||||
{
|
||||
mov ecx, s_saveecx
|
||||
mov edx, s_saveedx
|
||||
mov ebx, s_saveebx
|
||||
mov esi, s_saveesi
|
||||
mov edi, s_saveedi
|
||||
mov ebp, s_saveebp
|
||||
ret
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
// frees all regs taking into account the livevars
|
||||
void SuperVUFreeXMMregs(u32* livevars)
|
||||
|
@ -2946,8 +2921,8 @@ void VuBaseBlock::Recompile()
|
|||
|
||||
if (itparent == parents.end()) MOV32ItoM((uptr)&skipparent, -1);
|
||||
|
||||
MOV32ItoR(EAX, s_vu);
|
||||
CALLFunc((uptr)svudispfn);
|
||||
xMOV( ecx, s_vu );
|
||||
xCALL( svudispfn );
|
||||
#endif
|
||||
|
||||
s_pCurBlock = this;
|
||||
|
|
|
@ -68,9 +68,14 @@ bool GSDevice10::Create(GSWnd* wnd, bool vsync)
|
|||
scd.SampleDesc.Quality = 0;
|
||||
scd.Windowed = TRUE;
|
||||
|
||||
//Crashes when 2 threads work on the swapchain, as in pcsx2/wx.
|
||||
//Todo : Figure out a way to have this flag anyway
|
||||
uint32 flags = 0; //D3D10_CREATE_DEVICE_SINGLETHREADED;
|
||||
// Crashes when 2 threads work on the swapchain, as in pcsx2/wx when it provides us
|
||||
// an external window handle (which could be attached to any thread other than the GS one).
|
||||
// (but if we're managing our own window then it's safe to enable)
|
||||
|
||||
// FIXME : Figure out a way to have this flag anyway, since it's a measurable speedup (may
|
||||
// not be possible though).
|
||||
|
||||
uint32 flags = m_wnd->IsManaged() ? D3D10_CREATE_DEVICE_SINGLETHREADED : 0;
|
||||
|
||||
#ifdef DEBUG
|
||||
flags |= D3D10_CREATE_DEVICE_DEBUG;
|
||||
|
|
|
@ -39,6 +39,7 @@ protected:
|
|||
|
||||
public:
|
||||
GSRendererDX10();
|
||||
virtual ~GSRendererDX10() {}
|
||||
|
||||
bool CreateDevice(GSDevice* dev);
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@ protected:
|
|||
|
||||
public:
|
||||
GSRendererDX11();
|
||||
virtual ~GSRendererDX11() {}
|
||||
|
||||
bool CreateDevice(GSDevice* dev);
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@ protected:
|
|||
|
||||
public:
|
||||
GSRendererDX9();
|
||||
virtual ~GSRendererDX9() {}
|
||||
|
||||
bool CreateDevice(GSDevice* dev);
|
||||
|
||||
|
|
|
@ -43,6 +43,8 @@ public:
|
|||
InitVertexKick<GSRendererNull>();
|
||||
}
|
||||
|
||||
virtual ~GSRendererNull() {}
|
||||
|
||||
template<uint32 prim, uint32 tme, uint32 fst> void VertexKick(bool skip)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ protected:
|
|||
|
||||
public:
|
||||
GSRendererOGL();
|
||||
virtual ~GSRendererOGL() {}
|
||||
|
||||
bool CreateDevice(GSDevice* dev);
|
||||
|
||||
|
|
Loading…
Reference in New Issue