2009-09-08 12:08:10 +00:00
|
|
|
/* PCSX2 - PS2 Emulator for PCs
|
|
|
|
* Copyright (C) 2002-2009 PCSX2 Dev Team
|
2009-09-17 02:12:32 +00:00
|
|
|
*
|
2009-09-08 12:08:10 +00:00
|
|
|
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
|
|
|
* of the GNU Lesser General Public License as published by the Free Software Found-
|
|
|
|
* ation, either version 3 of the License, or (at your option) any later version.
|
2009-02-09 21:15:56 +00:00
|
|
|
*
|
2009-09-08 12:08:10 +00:00
|
|
|
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
|
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
|
|
* PURPOSE. See the GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along with PCSX2.
|
|
|
|
* If not, see <http://www.gnu.org/licenses/>.
|
2009-02-09 21:15:56 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "PrecompiledHeader.h"
|
|
|
|
#include "Common.h"
|
2009-09-23 09:53:21 +00:00
|
|
|
|
2009-11-14 12:02:56 +00:00
|
|
|
#include <list>
|
|
|
|
#include <wx/datetime.h>
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2009-11-14 12:02:56 +00:00
|
|
|
#include "GS.h"
|
|
|
|
#include "Elfheader.h"
|
2009-02-09 21:15:56 +00:00
|
|
|
#include "SamplProf.h"
|
|
|
|
|
2009-09-23 09:53:21 +00:00
|
|
|
|
2009-02-09 21:15:56 +00:00
|
|
|
// Uncomment this to enable profiling of the GS RingBufferCopy function.
|
|
|
|
//#define PCSX2_GSRING_SAMPLING_STATS
|
|
|
|
|
|
|
|
using namespace Threading;
|
|
|
|
|
2009-11-21 07:56:29 +00:00
|
|
|
#if 0 // PCSX2_DEBUG
|
|
|
|
# define MTGS_LOG Console.WriteLn
|
2009-02-09 21:15:56 +00:00
|
|
|
#else
|
2009-11-21 07:56:29 +00:00
|
|
|
# define MTGS_LOG 0&&
|
2009-02-09 21:15:56 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
// forces the compiler to treat a non-volatile value as volatile.
|
|
|
|
// This allows us to declare the vars as non-volatile and only use
|
|
|
|
// them as volatile when appropriate (more optimized).
|
|
|
|
|
|
|
|
#define volatize(x) (*reinterpret_cast<volatile uint*>(&(x)))
|
|
|
|
|
2009-09-19 09:45:26 +00:00
|
|
|
|
2009-09-23 09:53:21 +00:00
|
|
|
// =====================================================================================================
|
|
|
|
// MTGS Threaded Class Implementation
|
|
|
|
// =====================================================================================================
|
2009-09-19 09:45:26 +00:00
|
|
|
|
2009-09-23 09:53:21 +00:00
|
|
|
// Size of the ringbuffer as a power of 2 -- size is a multiple of simd128s.
|
|
|
|
// (actual size is 1<<m_RingBufferSizeFactor simd vectors [128-bit values])
|
|
|
|
// A value of 19 is a 8meg ring buffer. 18 would be 4 megs, and 20 would be 16 megs.
|
|
|
|
// Default was 2mb, but some games with lots of MTGS activity want 8mb to run fast (rama)
|
|
|
|
static const uint RingBufferSizeFactor = 19;
|
2009-09-21 09:48:31 +00:00
|
|
|
|
2009-09-23 09:53:21 +00:00
|
|
|
// size of the ringbuffer in simd128's.
|
|
|
|
static const uint RingBufferSize = 1<<RingBufferSizeFactor;
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2009-09-23 09:53:21 +00:00
|
|
|
// Mask to apply to ring buffer indices to wrap the pointer from end to
|
|
|
|
// start (the wrapping is what makes it a ringbuffer, yo!)
|
|
|
|
static const uint RingBufferMask = RingBufferSize - 1;
|
2009-09-19 09:45:26 +00:00
|
|
|
|
2009-09-23 09:53:21 +00:00
|
|
|
struct MTGS_BufferedData
|
2009-02-09 21:15:56 +00:00
|
|
|
{
|
2009-09-23 09:53:21 +00:00
|
|
|
u128 m_Ring[RingBufferSize];
|
|
|
|
u8 Regs[Ps2MemSize::GSregs];
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2009-09-23 09:53:21 +00:00
|
|
|
MTGS_BufferedData() {}
|
2009-06-20 13:26:52 +00:00
|
|
|
|
2009-09-23 09:53:21 +00:00
|
|
|
u128& operator[]( uint idx )
|
2009-06-19 03:13:03 +00:00
|
|
|
{
|
2009-10-18 12:30:00 +00:00
|
|
|
pxAssert( idx < RingBufferSize );
|
2009-09-23 09:53:21 +00:00
|
|
|
return m_Ring[idx];
|
2009-06-19 03:13:03 +00:00
|
|
|
}
|
2009-09-23 09:53:21 +00:00
|
|
|
};
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2009-10-05 02:15:49 +00:00
|
|
|
static __aligned(32) MTGS_BufferedData RingBuffer;
|
Lots of new code maintenance stuffs:
* Completely new assertion macros: pxAssert, pxAssertMsg, and pxFail, pxAssertDev (both which default to using a message). These replace *all* wxASSERT, DevAssert, and jASSUME varieties of macros. New macros borrow the best of all assertion worlds: MSVCRT, wxASSERT, and AtlAssume. :)
* Rewrote the Console namespace as a structure called IConsoleWriter, and created several varieties of ConsoleWriters for handling different states of log and console availability (should help reduce overhead of console logging nicely).
* More improvements to the PersistentThread model, using safely interlocked "Do*" style callbacks for starting and cleaning up threads.
* Fixed console logs so that they're readable in Win32 notepad again (the log writer adds CRs to naked LFs).
* Added AppInit.cpp -- contains constructor, destructor, OnInit, and command line parsing mess.
git-svn-id: http://pcsx2.googlecode.com/svn/trunk@1950 96395faa-99c1-11dd-bbfe-3dabce05a288
2009-10-04 08:27:27 +00:00
|
|
|
extern bool renderswitch;
|
2009-02-09 21:15:56 +00:00
|
|
|
|
|
|
|
|
|
|
|
#ifdef RINGBUF_DEBUG_STACK
|
|
|
|
#include <list>
|
|
|
|
std::list<uint> ringposStack;
|
|
|
|
#endif
|
|
|
|
|
2009-11-23 06:54:24 +00:00
|
|
|
static __threadlocal SysMtgsThread* tls_mtgsThread = NULL;
|
2009-10-23 20:24:59 +00:00
|
|
|
|
2009-11-23 06:54:24 +00:00
|
|
|
SysMtgsThread& SysMtgsThread::Get()
|
2009-10-23 20:24:59 +00:00
|
|
|
{
|
2009-11-23 06:54:24 +00:00
|
|
|
pxAssertMsg( tls_mtgsThread != NULL, L"This function must be called from the context of a running SysMtgsThread." );
|
2009-10-23 20:24:59 +00:00
|
|
|
return *tls_mtgsThread;
|
|
|
|
}
|
|
|
|
|
2009-11-23 06:54:24 +00:00
|
|
|
SysMtgsThread::SysMtgsThread() :
|
User Interface:
* Fixed and added better Emulation/System menu updating. Suspend/Resume is more consistent, and Reset grays itself out after being used.
* Entering plugin configurations auto-suspends the emulator.
* Changing plugins in the Configuration PAnel takes effect now without a restart.
* Added preliminary support for an ExtensibleConfirmation Dialog box (contains a sizer you can add content to, and also has an optional "[x] Do not show this again" checkbox).
Bugfixes:
* Added some mutex protection to cdvdNewDiskCB; "just in case."
* Resolved several recursion and deadlock scenarios when (very!) rapidly suspending, resuming, and resetting the emu.
Developments / Code Cleanups:
* Renamed SysCoreThread ExecutionModes: Suspend/Resume are now Opened/Closed (which more accurately reflects the fact they opena nd close the plugins, and helps avoid ambiguity with the "Paused" state).
* Added Exception::ThreadTimedOut, which is now thrown from Semaphore::Wait when recursive wxApp::Yield() calls are detected, and a deadlock occurs (basically cancels the current action which, most of the time, allows for full recovery).
* Major Threading namespace cleanups, documentations, etc.
* Removed wxScopedArray (scopedarray.h) and replaced it with a better implemeneted ScopedArray class.
* Removed toUTF8 class, which I only added a couple weeks ago because I didn't realize wxCharBuffer had an implicit typecast to (char*).
* Implemented more Source/Listener events for Pcsx2App. CoreThread events are sourced properly now, and added SettingsApplied and SettingsLoadSave Sources.
git-svn-id: http://pcsx2.googlecode.com/svn/trunk@2010 96395faa-99c1-11dd-bbfe-3dabce05a288
2009-10-16 03:58:29 +00:00
|
|
|
SysThreadBase()
|
2009-02-09 21:15:56 +00:00
|
|
|
#ifdef RINGBUF_DEBUG_STACK
|
|
|
|
, m_lock_Stack()
|
|
|
|
#endif
|
|
|
|
{
|
2009-09-29 19:16:00 +00:00
|
|
|
m_name = L"MTGS";
|
2009-11-21 07:56:29 +00:00
|
|
|
|
|
|
|
// All other state vars are initialized by OnStart().
|
2009-02-17 01:38:02 +00:00
|
|
|
}
|
|
|
|
|
2009-11-23 06:54:24 +00:00
|
|
|
void SysMtgsThread::OnStart()
|
Lots of new code maintenance stuffs:
* Completely new assertion macros: pxAssert, pxAssertMsg, and pxFail, pxAssertDev (both which default to using a message). These replace *all* wxASSERT, DevAssert, and jASSUME varieties of macros. New macros borrow the best of all assertion worlds: MSVCRT, wxASSERT, and AtlAssume. :)
* Rewrote the Console namespace as a structure called IConsoleWriter, and created several varieties of ConsoleWriters for handling different states of log and console availability (should help reduce overhead of console logging nicely).
* More improvements to the PersistentThread model, using safely interlocked "Do*" style callbacks for starting and cleaning up threads.
* Fixed console logs so that they're readable in Win32 notepad again (the log writer adds CRs to naked LFs).
* Added AppInit.cpp -- contains constructor, destructor, OnInit, and command line parsing mess.
git-svn-id: http://pcsx2.googlecode.com/svn/trunk@1950 96395faa-99c1-11dd-bbfe-3dabce05a288
2009-10-04 08:27:27 +00:00
|
|
|
{
|
2009-11-24 08:43:36 +00:00
|
|
|
m_PluginOpened = false;
|
Lots of new code maintenance stuffs:
* Completely new assertion macros: pxAssert, pxAssertMsg, and pxFail, pxAssertDev (both which default to using a message). These replace *all* wxASSERT, DevAssert, and jASSUME varieties of macros. New macros borrow the best of all assertion worlds: MSVCRT, wxASSERT, and AtlAssume. :)
* Rewrote the Console namespace as a structure called IConsoleWriter, and created several varieties of ConsoleWriters for handling different states of log and console availability (should help reduce overhead of console logging nicely).
* More improvements to the PersistentThread model, using safely interlocked "Do*" style callbacks for starting and cleaning up threads.
* Fixed console logs so that they're readable in Win32 notepad again (the log writer adds CRs to naked LFs).
* Added AppInit.cpp -- contains constructor, destructor, OnInit, and command line parsing mess.
git-svn-id: http://pcsx2.googlecode.com/svn/trunk@1950 96395faa-99c1-11dd-bbfe-3dabce05a288
2009-10-04 08:27:27 +00:00
|
|
|
|
2009-11-24 08:43:36 +00:00
|
|
|
m_RingPos = 0;
|
|
|
|
m_WritePos = 0;
|
|
|
|
m_RingBufferIsBusy = false;
|
2009-09-23 09:53:21 +00:00
|
|
|
m_packet_size = 0;
|
|
|
|
m_packet_ringpos = 0;
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2009-11-24 22:49:05 +00:00
|
|
|
m_QueuedFrameCount = 0;
|
2009-11-24 08:43:36 +00:00
|
|
|
m_SignalRingEnable = 0;
|
|
|
|
m_SignalRingPosition= 0;
|
|
|
|
m_RingWrapSpot = 0;
|
|
|
|
|
2009-10-09 15:17:53 +00:00
|
|
|
m_CopyDataTally = 0;
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2009-10-09 15:17:53 +00:00
|
|
|
_parent::OnStart();
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
|
|
|
|
2009-11-23 06:54:24 +00:00
|
|
|
SysMtgsThread::~SysMtgsThread() throw()
|
2009-02-09 21:15:56 +00:00
|
|
|
{
|
2009-09-29 19:16:00 +00:00
|
|
|
_parent::Cancel();
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
|
|
|
|
2009-11-23 06:54:24 +00:00
|
|
|
void SysMtgsThread::OnResumeReady()
|
2009-02-09 21:15:56 +00:00
|
|
|
{
|
2009-09-23 09:53:21 +00:00
|
|
|
m_sem_OpenDone.Reset();
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
|
|
|
|
2009-11-23 06:54:24 +00:00
|
|
|
void SysMtgsThread::ResetGS()
|
2009-02-09 21:15:56 +00:00
|
|
|
{
|
|
|
|
// MTGS Reset process:
|
|
|
|
// * clear the ringbuffer.
|
|
|
|
// * Signal a reset.
|
|
|
|
// * clear the path and byRegs structs (used by GIFtagDummy)
|
|
|
|
|
2009-10-18 12:30:00 +00:00
|
|
|
m_RingPos = m_WritePos;
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2009-09-07 21:16:12 +00:00
|
|
|
MTGS_LOG( "MTGS: Sending Reset..." );
|
2009-02-09 21:15:56 +00:00
|
|
|
SendSimplePacket( GS_RINGTYPE_RESET, 0, 0, 0 );
|
|
|
|
SendSimplePacket( GS_RINGTYPE_FRAMESKIP, 0, 0, 0 );
|
2009-09-23 09:53:21 +00:00
|
|
|
SetEvent();
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2009-09-23 09:53:21 +00:00
|
|
|
GIFPath_Reset();
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
|
|
|
|
2009-12-03 15:51:39 +00:00
|
|
|
void SysMtgsThread::PostVsyncEnd()
|
2009-02-20 04:36:55 +00:00
|
|
|
{
|
2009-12-03 15:51:39 +00:00
|
|
|
SendSimplePacket( GS_RINGTYPE_VSYNC, (*(u32*)(PS2MEM_GS+0x1000)&0x2000), 0, 0 );
|
2009-11-24 08:43:36 +00:00
|
|
|
|
2009-11-24 22:49:05 +00:00
|
|
|
// Alter-frame flushing! Restarts the ringbuffer (wraps) on every other frame. This is a
|
2009-11-24 08:43:36 +00:00
|
|
|
// mandatory feature that prevents the MTGS from queuing more than 2 frames at any time.
|
2009-11-24 22:49:05 +00:00
|
|
|
// (queued frames cause input lag and desynced audio -- bad!). Ring restarts work for this
|
|
|
|
// because they act as sync points where the EE must stall to wait for the GS to catch-up,
|
|
|
|
// and they also allow us to reuse the front of the ringbuffer more often, which should improve
|
|
|
|
// L2 cache performance.
|
2009-11-24 08:43:36 +00:00
|
|
|
|
2009-11-24 22:49:05 +00:00
|
|
|
if( m_QueuedFrameCount > 0 )
|
2009-11-21 07:56:29 +00:00
|
|
|
RestartRingbuffer();
|
2009-11-22 09:51:00 +00:00
|
|
|
else
|
2009-11-24 22:49:05 +00:00
|
|
|
{
|
|
|
|
m_QueuedFrameCount++;
|
2009-11-22 09:51:00 +00:00
|
|
|
SetEvent();
|
2009-11-24 22:49:05 +00:00
|
|
|
}
|
2009-02-20 04:36:55 +00:00
|
|
|
}
|
|
|
|
|
2009-02-09 21:15:56 +00:00
|
|
|
struct PacketTagType
|
|
|
|
{
|
|
|
|
u32 command;
|
|
|
|
u32 data[3];
|
|
|
|
};
|
2009-08-25 15:38:48 +00:00
|
|
|
|
2009-09-23 09:53:21 +00:00
|
|
|
static void dummyIrqCallback()
|
|
|
|
{
|
|
|
|
// dummy, because MTGS doesn't need this mess!
|
|
|
|
// (and zerogs does >_<)
|
|
|
|
}
|
|
|
|
|
2009-11-23 06:54:24 +00:00
|
|
|
void SysMtgsThread::OpenPlugin()
|
2009-09-23 09:53:21 +00:00
|
|
|
{
|
2009-10-19 01:50:52 +00:00
|
|
|
if( m_PluginOpened ) return;
|
2009-09-23 09:53:21 +00:00
|
|
|
|
|
|
|
memcpy_aligned( RingBuffer.Regs, PS2MEM_GS, sizeof(PS2MEM_GS) );
|
|
|
|
GSsetBaseMem( RingBuffer.Regs );
|
|
|
|
GSirqCallback( dummyIrqCallback );
|
|
|
|
|
|
|
|
if( renderswitch )
|
2009-11-22 09:51:00 +00:00
|
|
|
Console.Indent(2).WriteLn( "Forced software switch enabled." );
|
Lots of new code maintenance stuffs:
* Completely new assertion macros: pxAssert, pxAssertMsg, and pxFail, pxAssertDev (both which default to using a message). These replace *all* wxASSERT, DevAssert, and jASSUME varieties of macros. New macros borrow the best of all assertion worlds: MSVCRT, wxASSERT, and AtlAssume. :)
* Rewrote the Console namespace as a structure called IConsoleWriter, and created several varieties of ConsoleWriters for handling different states of log and console availability (should help reduce overhead of console logging nicely).
* More improvements to the PersistentThread model, using safely interlocked "Do*" style callbacks for starting and cleaning up threads.
* Fixed console logs so that they're readable in Win32 notepad again (the log writer adds CRs to naked LFs).
* Added AppInit.cpp -- contains constructor, destructor, OnInit, and command line parsing mess.
git-svn-id: http://pcsx2.googlecode.com/svn/trunk@1950 96395faa-99c1-11dd-bbfe-3dabce05a288
2009-10-04 08:27:27 +00:00
|
|
|
|
|
|
|
int result;
|
2009-09-23 09:53:21 +00:00
|
|
|
|
|
|
|
if( GSopen2 != NULL )
|
Lots of new code maintenance stuffs:
* Completely new assertion macros: pxAssert, pxAssertMsg, and pxFail, pxAssertDev (both which default to using a message). These replace *all* wxASSERT, DevAssert, and jASSUME varieties of macros. New macros borrow the best of all assertion worlds: MSVCRT, wxASSERT, and AtlAssume. :)
* Rewrote the Console namespace as a structure called IConsoleWriter, and created several varieties of ConsoleWriters for handling different states of log and console availability (should help reduce overhead of console logging nicely).
* More improvements to the PersistentThread model, using safely interlocked "Do*" style callbacks for starting and cleaning up threads.
* Fixed console logs so that they're readable in Win32 notepad again (the log writer adds CRs to naked LFs).
* Added AppInit.cpp -- contains constructor, destructor, OnInit, and command line parsing mess.
git-svn-id: http://pcsx2.googlecode.com/svn/trunk@1950 96395faa-99c1-11dd-bbfe-3dabce05a288
2009-10-04 08:27:27 +00:00
|
|
|
result = GSopen2( (void*)&pDsp, 1 | (renderswitch ? 4 : 0) );
|
2009-09-23 09:53:21 +00:00
|
|
|
else
|
Lots of new code maintenance stuffs:
* Completely new assertion macros: pxAssert, pxAssertMsg, and pxFail, pxAssertDev (both which default to using a message). These replace *all* wxASSERT, DevAssert, and jASSUME varieties of macros. New macros borrow the best of all assertion worlds: MSVCRT, wxASSERT, and AtlAssume. :)
* Rewrote the Console namespace as a structure called IConsoleWriter, and created several varieties of ConsoleWriters for handling different states of log and console availability (should help reduce overhead of console logging nicely).
* More improvements to the PersistentThread model, using safely interlocked "Do*" style callbacks for starting and cleaning up threads.
* Fixed console logs so that they're readable in Win32 notepad again (the log writer adds CRs to naked LFs).
* Added AppInit.cpp -- contains constructor, destructor, OnInit, and command line parsing mess.
git-svn-id: http://pcsx2.googlecode.com/svn/trunk@1950 96395faa-99c1-11dd-bbfe-3dabce05a288
2009-10-04 08:27:27 +00:00
|
|
|
result = GSopen( (void*)&pDsp, "PCSX2", renderswitch ? 2 : 1 );
|
2009-09-23 09:53:21 +00:00
|
|
|
|
2009-12-03 15:51:39 +00:00
|
|
|
GSsetVsync( EmuConfig.GS.FrameLimitEnable && EmuConfig.GS.VsyncEnable );
|
|
|
|
|
Lots of new code maintenance stuffs:
* Completely new assertion macros: pxAssert, pxAssertMsg, and pxFail, pxAssertDev (both which default to using a message). These replace *all* wxASSERT, DevAssert, and jASSUME varieties of macros. New macros borrow the best of all assertion worlds: MSVCRT, wxASSERT, and AtlAssume. :)
* Rewrote the Console namespace as a structure called IConsoleWriter, and created several varieties of ConsoleWriters for handling different states of log and console availability (should help reduce overhead of console logging nicely).
* More improvements to the PersistentThread model, using safely interlocked "Do*" style callbacks for starting and cleaning up threads.
* Fixed console logs so that they're readable in Win32 notepad again (the log writer adds CRs to naked LFs).
* Added AppInit.cpp -- contains constructor, destructor, OnInit, and command line parsing mess.
git-svn-id: http://pcsx2.googlecode.com/svn/trunk@1950 96395faa-99c1-11dd-bbfe-3dabce05a288
2009-10-04 08:27:27 +00:00
|
|
|
if( result != 0 )
|
2009-09-23 09:53:21 +00:00
|
|
|
{
|
Lots of new code maintenance stuffs:
* Completely new assertion macros: pxAssert, pxAssertMsg, and pxFail, pxAssertDev (both which default to using a message). These replace *all* wxASSERT, DevAssert, and jASSUME varieties of macros. New macros borrow the best of all assertion worlds: MSVCRT, wxASSERT, and AtlAssume. :)
* Rewrote the Console namespace as a structure called IConsoleWriter, and created several varieties of ConsoleWriters for handling different states of log and console availability (should help reduce overhead of console logging nicely).
* More improvements to the PersistentThread model, using safely interlocked "Do*" style callbacks for starting and cleaning up threads.
* Fixed console logs so that they're readable in Win32 notepad again (the log writer adds CRs to naked LFs).
* Added AppInit.cpp -- contains constructor, destructor, OnInit, and command line parsing mess.
git-svn-id: http://pcsx2.googlecode.com/svn/trunk@1950 96395faa-99c1-11dd-bbfe-3dabce05a288
2009-10-04 08:27:27 +00:00
|
|
|
DevCon.WriteLn( "GSopen Failed: return code: 0x%x", result );
|
|
|
|
throw Exception::PluginOpenError( PluginId_GS );
|
2009-09-23 09:53:21 +00:00
|
|
|
}
|
|
|
|
|
2009-12-01 15:33:56 +00:00
|
|
|
// This is the preferred place to implement DXGI fullscreen overrides, using LoadLibrary.
|
|
|
|
// But I hate COM, I don't know to make this work, and I don't have DX10, so I give up
|
|
|
|
// and enjoy my working DX9 alt-enter instead. Someone else can fix this mess. --air
|
|
|
|
|
|
|
|
// Also: Prolly needs some DX10 header includes? Which ones? Too many, I gave up.
|
|
|
|
|
|
|
|
#if 0 // defined(__WXMSW__) && defined(_MSC_VER)
|
|
|
|
wxDynamicLibrary dynlib( L"dxgi.dll" );
|
|
|
|
SomeFuncTypeIDunno isThisEvenTheRightFunctionNameIDunno = dynlib.GetSymbol("CreateDXGIFactory");
|
|
|
|
if( isThisEvenTheRightFunctionNameIDunno )
|
|
|
|
{
|
|
|
|
// Is this how LoadLibrary for COM works? I dunno. I dont care.
|
|
|
|
|
|
|
|
IDXGIFactory* pFactory;
|
|
|
|
hr = isThisEvenTheRightFunctionNameIDunno(__uuidof(IDXGIFactory), (void**)(&pFactory) );
|
|
|
|
pFactory->MakeWindowAssociation((HWND)&pDsp, DXGI_MWA_NO_WINDOW_CHANGES);
|
|
|
|
pFactory->Release();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2009-10-19 01:50:52 +00:00
|
|
|
m_PluginOpened = true;
|
Lots of new code maintenance stuffs:
* Completely new assertion macros: pxAssert, pxAssertMsg, and pxFail, pxAssertDev (both which default to using a message). These replace *all* wxASSERT, DevAssert, and jASSUME varieties of macros. New macros borrow the best of all assertion worlds: MSVCRT, wxASSERT, and AtlAssume. :)
* Rewrote the Console namespace as a structure called IConsoleWriter, and created several varieties of ConsoleWriters for handling different states of log and console availability (should help reduce overhead of console logging nicely).
* More improvements to the PersistentThread model, using safely interlocked "Do*" style callbacks for starting and cleaning up threads.
* Fixed console logs so that they're readable in Win32 notepad again (the log writer adds CRs to naked LFs).
* Added AppInit.cpp -- contains constructor, destructor, OnInit, and command line parsing mess.
git-svn-id: http://pcsx2.googlecode.com/svn/trunk@1950 96395faa-99c1-11dd-bbfe-3dabce05a288
2009-10-04 08:27:27 +00:00
|
|
|
m_sem_OpenDone.Post();
|
|
|
|
|
2009-09-23 09:53:21 +00:00
|
|
|
GSCSRr = 0x551B4000; // 0x55190000
|
|
|
|
GSsetGameCRC( ElfCRC, 0 );
|
|
|
|
}
|
|
|
|
|
2009-11-24 08:43:36 +00:00
|
|
|
class RingBufferLock : public ScopedLock
|
|
|
|
{
|
|
|
|
protected:
|
|
|
|
SysMtgsThread& m_mtgs;
|
|
|
|
|
|
|
|
public:
|
|
|
|
RingBufferLock( SysMtgsThread& mtgs )
|
|
|
|
: ScopedLock( mtgs.m_lock_RingBufferBusy )
|
|
|
|
, m_mtgs( mtgs )
|
|
|
|
{
|
|
|
|
m_mtgs.m_RingBufferIsBusy = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual ~RingBufferLock() throw()
|
|
|
|
{
|
|
|
|
m_mtgs.m_RingBufferIsBusy = false;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2009-11-23 06:54:24 +00:00
|
|
|
void SysMtgsThread::ExecuteTaskInThread()
|
2009-09-08 03:44:35 +00:00
|
|
|
{
|
2009-10-23 20:24:59 +00:00
|
|
|
tls_mtgsThread = this;
|
|
|
|
|
2009-09-23 09:53:21 +00:00
|
|
|
#ifdef RINGBUF_DEBUG_STACK
|
|
|
|
PacketTagType prevCmd;
|
|
|
|
#endif
|
|
|
|
|
2009-02-09 21:15:56 +00:00
|
|
|
while( true )
|
|
|
|
{
|
2009-10-23 20:24:59 +00:00
|
|
|
// Performance note: Both of these perform cancellation tests, but pthread_testcancel
|
|
|
|
// is very optimized (only 1 instruction test in most cases), so no point in trying
|
|
|
|
// to avoid it.
|
|
|
|
|
2009-11-01 09:27:16 +00:00
|
|
|
m_sem_event.WaitWithoutYield();
|
2009-10-23 20:24:59 +00:00
|
|
|
StateCheckInThread();
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2009-11-24 20:11:43 +00:00
|
|
|
{
|
2009-11-24 08:43:36 +00:00
|
|
|
RingBufferLock busy( *this );
|
2009-02-09 21:15:56 +00:00
|
|
|
|
|
|
|
// note: m_RingPos is intentionally not volatile, because it should only
|
|
|
|
// ever be modified by this thread.
|
|
|
|
while( m_RingPos != volatize(m_WritePos))
|
|
|
|
{
|
Lots of new code maintenance stuffs:
* Completely new assertion macros: pxAssert, pxAssertMsg, and pxFail, pxAssertDev (both which default to using a message). These replace *all* wxASSERT, DevAssert, and jASSUME varieties of macros. New macros borrow the best of all assertion worlds: MSVCRT, wxASSERT, and AtlAssume. :)
* Rewrote the Console namespace as a structure called IConsoleWriter, and created several varieties of ConsoleWriters for handling different states of log and console availability (should help reduce overhead of console logging nicely).
* More improvements to the PersistentThread model, using safely interlocked "Do*" style callbacks for starting and cleaning up threads.
* Fixed console logs so that they're readable in Win32 notepad again (the log writer adds CRs to naked LFs).
* Added AppInit.cpp -- contains constructor, destructor, OnInit, and command line parsing mess.
git-svn-id: http://pcsx2.googlecode.com/svn/trunk@1950 96395faa-99c1-11dd-bbfe-3dabce05a288
2009-10-04 08:27:27 +00:00
|
|
|
pxAssert( m_RingPos < RingBufferSize );
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2009-09-23 09:53:21 +00:00
|
|
|
const PacketTagType& tag = (PacketTagType&)RingBuffer[m_RingPos];
|
2009-02-09 21:15:56 +00:00
|
|
|
u32 ringposinc = 1;
|
|
|
|
|
|
|
|
#ifdef RINGBUF_DEBUG_STACK
|
|
|
|
// pop a ringpos off the stack. It should match this one!
|
|
|
|
|
|
|
|
m_lock_Stack.Lock();
|
|
|
|
uptr stackpos = ringposStack.back();
|
|
|
|
if( stackpos != m_RingPos )
|
|
|
|
{
|
Lots of new code maintenance stuffs:
* Completely new assertion macros: pxAssert, pxAssertMsg, and pxFail, pxAssertDev (both which default to using a message). These replace *all* wxASSERT, DevAssert, and jASSUME varieties of macros. New macros borrow the best of all assertion worlds: MSVCRT, wxASSERT, and AtlAssume. :)
* Rewrote the Console namespace as a structure called IConsoleWriter, and created several varieties of ConsoleWriters for handling different states of log and console availability (should help reduce overhead of console logging nicely).
* More improvements to the PersistentThread model, using safely interlocked "Do*" style callbacks for starting and cleaning up threads.
* Fixed console logs so that they're readable in Win32 notepad again (the log writer adds CRs to naked LFs).
* Added AppInit.cpp -- contains constructor, destructor, OnInit, and command line parsing mess.
git-svn-id: http://pcsx2.googlecode.com/svn/trunk@1950 96395faa-99c1-11dd-bbfe-3dabce05a288
2009-10-04 08:27:27 +00:00
|
|
|
Console.Error( "MTGS Ringbuffer Critical Failure ---> %x to %x (prevCmd: %x)\n", stackpos, m_RingPos, prevCmd.command );
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
Lots of new code maintenance stuffs:
* Completely new assertion macros: pxAssert, pxAssertMsg, and pxFail, pxAssertDev (both which default to using a message). These replace *all* wxASSERT, DevAssert, and jASSUME varieties of macros. New macros borrow the best of all assertion worlds: MSVCRT, wxASSERT, and AtlAssume. :)
* Rewrote the Console namespace as a structure called IConsoleWriter, and created several varieties of ConsoleWriters for handling different states of log and console availability (should help reduce overhead of console logging nicely).
* More improvements to the PersistentThread model, using safely interlocked "Do*" style callbacks for starting and cleaning up threads.
* Fixed console logs so that they're readable in Win32 notepad again (the log writer adds CRs to naked LFs).
* Added AppInit.cpp -- contains constructor, destructor, OnInit, and command line parsing mess.
git-svn-id: http://pcsx2.googlecode.com/svn/trunk@1950 96395faa-99c1-11dd-bbfe-3dabce05a288
2009-10-04 08:27:27 +00:00
|
|
|
pxAssert( stackpos == m_RingPos );
|
2009-02-09 21:15:56 +00:00
|
|
|
prevCmd = tag;
|
|
|
|
ringposStack.pop_back();
|
2009-10-31 19:18:29 +00:00
|
|
|
m_lock_Stack.Release();
|
2009-02-09 21:15:56 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
switch( tag.command )
|
|
|
|
{
|
|
|
|
case GS_RINGTYPE_P1:
|
|
|
|
{
|
|
|
|
const int qsize = tag.data[0];
|
2009-09-23 09:53:21 +00:00
|
|
|
const u128* data = &RingBuffer[m_RingPos+1];
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2009-11-21 07:56:29 +00:00
|
|
|
MTGS_LOG( "(MTGS Packet Read) ringtype=P1, qwc=%u", qsize );
|
|
|
|
|
2009-02-09 21:15:56 +00:00
|
|
|
// make sure that tag>>16 is the MAX size readable
|
|
|
|
GSgifTransfer1((u32*)(data - 0x400 + qsize), 0x4000-qsize*16);
|
2009-05-29 18:44:42 +00:00
|
|
|
//GSgifTransfer1((u32*)data, qsize);
|
2009-02-09 21:15:56 +00:00
|
|
|
ringposinc += qsize;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GS_RINGTYPE_P2:
|
|
|
|
{
|
|
|
|
const int qsize = tag.data[0];
|
2009-09-23 09:53:21 +00:00
|
|
|
const u128* data = &RingBuffer[m_RingPos+1];
|
2009-11-21 07:56:29 +00:00
|
|
|
|
|
|
|
MTGS_LOG( "(MTGS Packet Read) ringtype=P2, qwc=%u", qsize );
|
|
|
|
|
2009-02-09 21:15:56 +00:00
|
|
|
GSgifTransfer2((u32*)data, qsize);
|
|
|
|
ringposinc += qsize;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GS_RINGTYPE_P3:
|
|
|
|
{
|
|
|
|
const int qsize = tag.data[0];
|
2009-09-23 09:53:21 +00:00
|
|
|
const u128* data = &RingBuffer[m_RingPos+1];
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2009-11-21 07:56:29 +00:00
|
|
|
MTGS_LOG( "(MTGS Packet Read) ringtype=P3, qwc=%u", qsize );
|
2009-02-20 04:36:55 +00:00
|
|
|
|
2009-11-21 07:56:29 +00:00
|
|
|
GSgifTransfer3((u32*)data, qsize);
|
|
|
|
ringposinc += qsize;
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GS_RINGTYPE_MEMWRITE64:
|
2009-11-21 07:56:29 +00:00
|
|
|
MTGS_LOG( "(MTGS Packet Read) ringtype=Write64, data=%lu", *(u64*)&tag.data[1] );
|
2009-09-23 09:53:21 +00:00
|
|
|
*(u64*)(RingBuffer.Regs+tag.data[0]) = *(u64*)&tag.data[1];
|
2009-02-09 21:15:56 +00:00
|
|
|
break;
|
|
|
|
|
2009-11-21 07:56:29 +00:00
|
|
|
default:
|
2009-02-09 21:15:56 +00:00
|
|
|
{
|
2009-11-21 07:56:29 +00:00
|
|
|
switch( tag.command )
|
|
|
|
{
|
|
|
|
case GS_RINGTYPE_RESTART:
|
2009-11-24 20:11:43 +00:00
|
|
|
//MTGS_LOG( "(MTGS Packet Read) ringtype=Restart" );
|
2009-11-21 07:56:29 +00:00
|
|
|
m_RingPos = 0;
|
2009-11-24 08:43:36 +00:00
|
|
|
continue;
|
2009-11-21 07:56:29 +00:00
|
|
|
|
|
|
|
case GS_RINGTYPE_VSYNC:
|
|
|
|
{
|
|
|
|
MTGS_LOG( "(MTGS Packet Read) ringtype=Vsync, field=%u, skip=%s", tag.data[0], tag.data[1] ? "true" : "false" );
|
|
|
|
GSvsync(tag.data[0]);
|
2009-12-03 15:51:39 +00:00
|
|
|
gsFrameSkip();
|
2009-11-21 07:56:29 +00:00
|
|
|
|
|
|
|
if( PADupdate != NULL )
|
|
|
|
PADupdate(0);
|
|
|
|
|
|
|
|
StateCheckInThread();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GS_RINGTYPE_FRAMESKIP:
|
|
|
|
MTGS_LOG( "(MTGS Packet Read) ringtype=Frameskip" );
|
|
|
|
_gs_ResetFrameskip();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GS_RINGTYPE_MEMWRITE8:
|
|
|
|
MTGS_LOG( "(MTGS Packet Read) ringtype=Write8, addr=0x%08x, data=0x%02x", tag.data[0], (u8)tag.data[1] );
|
|
|
|
RingBuffer.Regs[tag.data[0]] = (u8)tag.data[1];
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GS_RINGTYPE_MEMWRITE16:
|
|
|
|
MTGS_LOG( "(MTGS Packet Read) ringtype=Write8, addr=0x%08x, data=0x%04x", tag.data[0], (u16)tag.data[1] );
|
|
|
|
*(u16*)(RingBuffer.Regs+tag.data[0]) = (u16)tag.data[1];
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GS_RINGTYPE_MEMWRITE32:
|
|
|
|
MTGS_LOG( "(MTGS Packet Read) ringtype=Write8, addr=0x%08x, data=0x%08x", tag.data[0], (u32)tag.data[1] );
|
|
|
|
*(u32*)(RingBuffer.Regs+tag.data[0]) = tag.data[1];
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GS_RINGTYPE_FREEZE:
|
|
|
|
{
|
|
|
|
MTGS_FreezeData* data = (MTGS_FreezeData*)(*(uptr*)&tag.data[1]);
|
|
|
|
int mode = tag.data[0];
|
|
|
|
data->retval = GetPluginManager().DoFreeze( PluginId_GS, mode, data->fdata );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case GS_RINGTYPE_RECORD:
|
|
|
|
{
|
|
|
|
int record = tag.data[0];
|
|
|
|
if( GSsetupRecording != NULL ) GSsetupRecording(record, NULL);
|
|
|
|
if( SPU2setupRecording != NULL ) SPU2setupRecording(record, NULL);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GS_RINGTYPE_RESET:
|
|
|
|
MTGS_LOG( "(MTGS Packet Read) ringtype=Reset" );
|
|
|
|
if( GSreset != NULL ) GSreset();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GS_RINGTYPE_SOFTRESET:
|
|
|
|
{
|
|
|
|
int mask = tag.data[0];
|
|
|
|
MTGS_LOG( "(MTGS Packet Read) ringtype=SoftReset" );
|
|
|
|
GSgifSoftReset( mask );
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GS_RINGTYPE_WRITECSR:
|
|
|
|
MTGS_LOG( "(MTGS Packet Read) ringtype=WriteCSR, value=%08x", tag.data[0] );
|
|
|
|
GSwriteCSR( tag.data[0] );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GS_RINGTYPE_MODECHANGE:
|
2009-12-03 15:51:39 +00:00
|
|
|
// [TODO] some frameskip sync logic might be needed here!
|
2009-11-21 07:56:29 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case GS_RINGTYPE_CRC:
|
|
|
|
GSsetGameCRC( tag.data[0], 0 );
|
|
|
|
break;
|
|
|
|
|
2009-02-09 21:15:56 +00:00
|
|
|
#ifdef PCSX2_DEVBUILD
|
2009-11-21 07:56:29 +00:00
|
|
|
default:
|
|
|
|
Console.Error("GSThreadProc, bad packet (%x) at m_RingPos: %x, m_WritePos: %x", tag.command, m_RingPos, m_WritePos);
|
|
|
|
pxFail( "Bad packet encountered in the MTGS Ringbuffer." );
|
|
|
|
m_RingPos = m_WritePos;
|
|
|
|
continue;
|
2009-02-09 21:15:56 +00:00
|
|
|
#else
|
2009-11-21 07:56:29 +00:00
|
|
|
// Optimized performance in non-Dev builds.
|
|
|
|
jNO_DEFAULT;
|
2009-02-09 21:15:56 +00:00
|
|
|
#endif
|
2009-11-21 07:56:29 +00:00
|
|
|
}
|
|
|
|
}
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
uint newringpos = m_RingPos + ringposinc;
|
Lots of new code maintenance stuffs:
* Completely new assertion macros: pxAssert, pxAssertMsg, and pxFail, pxAssertDev (both which default to using a message). These replace *all* wxASSERT, DevAssert, and jASSUME varieties of macros. New macros borrow the best of all assertion worlds: MSVCRT, wxASSERT, and AtlAssume. :)
* Rewrote the Console namespace as a structure called IConsoleWriter, and created several varieties of ConsoleWriters for handling different states of log and console availability (should help reduce overhead of console logging nicely).
* More improvements to the PersistentThread model, using safely interlocked "Do*" style callbacks for starting and cleaning up threads.
* Fixed console logs so that they're readable in Win32 notepad again (the log writer adds CRs to naked LFs).
* Added AppInit.cpp -- contains constructor, destructor, OnInit, and command line parsing mess.
git-svn-id: http://pcsx2.googlecode.com/svn/trunk@1950 96395faa-99c1-11dd-bbfe-3dabce05a288
2009-10-04 08:27:27 +00:00
|
|
|
pxAssert( newringpos <= RingBufferSize );
|
2009-11-24 08:43:36 +00:00
|
|
|
m_RingPos = newringpos & RingBufferMask;
|
|
|
|
|
|
|
|
if( m_SignalRingEnable != 0 )
|
|
|
|
{
|
|
|
|
// The EEcore has requested a signal after some amount of processed data.
|
2009-11-24 20:11:43 +00:00
|
|
|
if( AtomicExchangeSub( m_SignalRingPosition, ringposinc ) <= 0 )
|
2009-11-24 08:43:36 +00:00
|
|
|
{
|
|
|
|
// Make sure to post the signal after the m_RingPos has been updated...
|
|
|
|
AtomicExchange( m_SignalRingEnable, 0 );
|
|
|
|
m_sem_OnRingReset.Post();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-11-24 20:11:43 +00:00
|
|
|
}
|
2009-11-24 08:43:36 +00:00
|
|
|
|
|
|
|
// Safety valve in case standard signals fail for some reason -- this ensures the EEcore
|
|
|
|
// won't sleep the eternity, even if SignalRingPosition didn't reach 0 for some reason.
|
2009-11-24 20:11:43 +00:00
|
|
|
// Important: Need to unlock the MTGS busy signal PRIOR, so that EEcore SetEvent() calls
|
|
|
|
// parallel to this handler aren't accidentally blocked.
|
2009-11-24 08:43:36 +00:00
|
|
|
if( AtomicExchange( m_SignalRingEnable, 0 ) != 0 )
|
|
|
|
{
|
2009-11-24 20:11:43 +00:00
|
|
|
//Console.Warning( "(MTGS Thread) Dangling RingSignal on empty buffer! signalpos=0x%06x", AtomicExchange( m_SignalRingPosition, 0 ) );
|
2009-11-24 08:43:36 +00:00
|
|
|
AtomicExchange( m_SignalRingPosition, 0 );
|
|
|
|
m_sem_OnRingReset.Post();
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
2009-11-24 20:11:43 +00:00
|
|
|
|
2009-11-24 22:49:05 +00:00
|
|
|
//Console.Warning( "(MTGS Thread) Nothing to do! ringpos=0x%06x", m_RingPos );
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
2009-10-19 01:50:52 +00:00
|
|
|
}
|
|
|
|
|
2009-11-23 06:54:24 +00:00
|
|
|
void SysMtgsThread::ClosePlugin()
|
2009-10-19 01:50:52 +00:00
|
|
|
{
|
|
|
|
if( !m_PluginOpened ) return;
|
|
|
|
m_PluginOpened = false;
|
|
|
|
if( g_plugins != NULL )
|
|
|
|
g_plugins->m_info[PluginId_GS].CommonBindings.Close();
|
2009-09-08 03:44:35 +00:00
|
|
|
}
|
|
|
|
|
2009-11-23 06:54:24 +00:00
|
|
|
void SysMtgsThread::OnSuspendInThread()
|
2009-09-16 17:23:02 +00:00
|
|
|
{
|
2009-10-19 01:50:52 +00:00
|
|
|
ClosePlugin();
|
|
|
|
_parent::OnSuspendInThread();
|
2009-09-16 17:23:02 +00:00
|
|
|
}
|
|
|
|
|
2009-11-23 06:54:24 +00:00
|
|
|
void SysMtgsThread::OnResumeInThread( bool isSuspended )
|
2009-09-08 03:44:35 +00:00
|
|
|
{
|
2009-10-07 19:20:11 +00:00
|
|
|
if( isSuspended )
|
2009-09-23 09:53:21 +00:00
|
|
|
OpenPlugin();
|
2009-10-19 01:50:52 +00:00
|
|
|
|
|
|
|
_parent::OnResumeInThread( isSuspended );
|
|
|
|
}
|
|
|
|
|
2009-11-23 06:54:24 +00:00
|
|
|
void SysMtgsThread::OnCleanupInThread()
|
2009-10-19 01:50:52 +00:00
|
|
|
{
|
|
|
|
ClosePlugin();
|
2009-10-23 20:24:59 +00:00
|
|
|
tls_mtgsThread = NULL;
|
2009-10-19 01:50:52 +00:00
|
|
|
_parent::OnCleanupInThread();
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Waits for the GS to empty out the entire ring buffer contents.
|
|
|
|
// Used primarily for plugin startup/shutdown.
|
2009-11-23 06:54:24 +00:00
|
|
|
void SysMtgsThread::WaitGS()
|
2009-02-09 21:15:56 +00:00
|
|
|
{
|
Lots of new code maintenance stuffs:
* Completely new assertion macros: pxAssert, pxAssertMsg, and pxFail, pxAssertDev (both which default to using a message). These replace *all* wxASSERT, DevAssert, and jASSUME varieties of macros. New macros borrow the best of all assertion worlds: MSVCRT, wxASSERT, and AtlAssume. :)
* Rewrote the Console namespace as a structure called IConsoleWriter, and created several varieties of ConsoleWriters for handling different states of log and console availability (should help reduce overhead of console logging nicely).
* More improvements to the PersistentThread model, using safely interlocked "Do*" style callbacks for starting and cleaning up threads.
* Fixed console logs so that they're readable in Win32 notepad again (the log writer adds CRs to naked LFs).
* Added AppInit.cpp -- contains constructor, destructor, OnInit, and command line parsing mess.
git-svn-id: http://pcsx2.googlecode.com/svn/trunk@1950 96395faa-99c1-11dd-bbfe-3dabce05a288
2009-10-04 08:27:27 +00:00
|
|
|
pxAssertDev( !IsSelf(), "This method is only allowed from threads *not* named MTGS." );
|
2009-09-23 09:53:21 +00:00
|
|
|
|
User Interface:
* Fixed and added better Emulation/System menu updating. Suspend/Resume is more consistent, and Reset grays itself out after being used.
* Entering plugin configurations auto-suspends the emulator.
* Changing plugins in the Configuration PAnel takes effect now without a restart.
* Added preliminary support for an ExtensibleConfirmation Dialog box (contains a sizer you can add content to, and also has an optional "[x] Do not show this again" checkbox).
Bugfixes:
* Added some mutex protection to cdvdNewDiskCB; "just in case."
* Resolved several recursion and deadlock scenarios when (very!) rapidly suspending, resuming, and resetting the emu.
Developments / Code Cleanups:
* Renamed SysCoreThread ExecutionModes: Suspend/Resume are now Opened/Closed (which more accurately reflects the fact they opena nd close the plugins, and helps avoid ambiguity with the "Paused" state).
* Added Exception::ThreadTimedOut, which is now thrown from Semaphore::Wait when recursive wxApp::Yield() calls are detected, and a deadlock occurs (basically cancels the current action which, most of the time, allows for full recovery).
* Major Threading namespace cleanups, documentations, etc.
* Removed wxScopedArray (scopedarray.h) and replaced it with a better implemeneted ScopedArray class.
* Removed toUTF8 class, which I only added a couple weeks ago because I didn't realize wxCharBuffer had an implicit typecast to (char*).
* Implemented more Source/Listener events for Pcsx2App. CoreThread events are sourced properly now, and added SettingsApplied and SettingsLoadSave Sources.
git-svn-id: http://pcsx2.googlecode.com/svn/trunk@2010 96395faa-99c1-11dd-bbfe-3dabce05a288
2009-10-16 03:58:29 +00:00
|
|
|
if( m_ExecMode == ExecMode_NoThreadYet || !IsRunning() ) return;
|
|
|
|
if( !pxAssertDev( IsOpen(), "MTGS Warning! WaitGS issued on a closed thread." ) ) return;
|
2009-09-23 09:53:21 +00:00
|
|
|
|
2009-11-22 09:51:00 +00:00
|
|
|
if( volatize(m_RingPos) != m_WritePos )
|
|
|
|
{
|
2009-11-24 08:43:36 +00:00
|
|
|
SetEvent();
|
2009-11-22 09:51:00 +00:00
|
|
|
do {
|
|
|
|
m_lock_RingBufferBusy.Wait();
|
|
|
|
} while( volatize(m_RingPos) != m_WritePos );
|
|
|
|
}
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Sets the gsEvent flag and releases a timeslice.
|
|
|
|
// For use in loops that wait on the GS thread to do certain things.
|
2009-11-23 06:54:24 +00:00
|
|
|
void SysMtgsThread::SetEvent()
|
2009-02-09 21:15:56 +00:00
|
|
|
{
|
2009-11-24 08:43:36 +00:00
|
|
|
if( !m_RingBufferIsBusy )
|
|
|
|
m_sem_event.Post();
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2009-11-24 08:43:36 +00:00
|
|
|
m_CopyDataTally = 0;
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
|
|
|
|
2009-11-23 06:54:24 +00:00
|
|
|
u8* SysMtgsThread::GetDataPacketPtr() const
|
2009-02-09 21:15:56 +00:00
|
|
|
{
|
2009-09-23 09:53:21 +00:00
|
|
|
return (u8*)&RingBuffer[m_packet_ringpos];
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Closes the data packet send command, and initiates the gs thread (if needed).
|
2009-11-23 06:54:24 +00:00
|
|
|
void SysMtgsThread::SendDataPacket()
|
2009-02-09 21:15:56 +00:00
|
|
|
{
|
|
|
|
// make sure a previous copy block has been started somewhere.
|
2009-10-18 12:30:00 +00:00
|
|
|
pxAssert( m_packet_size != 0 );
|
2009-02-09 21:15:56 +00:00
|
|
|
|
|
|
|
uint temp = m_packet_ringpos + m_packet_size;
|
2009-10-18 12:30:00 +00:00
|
|
|
pxAssert( temp <= RingBufferSize );
|
2009-09-23 09:53:21 +00:00
|
|
|
temp &= RingBufferMask;
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2009-06-18 08:20:19 +00:00
|
|
|
if( IsDebugBuild )
|
2009-02-09 21:15:56 +00:00
|
|
|
{
|
2009-09-23 09:53:21 +00:00
|
|
|
if( m_packet_ringpos + m_packet_size < RingBufferSize )
|
2009-02-09 21:15:56 +00:00
|
|
|
{
|
2009-06-18 08:20:19 +00:00
|
|
|
uint readpos = volatize(m_RingPos);
|
|
|
|
if( readpos != m_WritePos )
|
|
|
|
{
|
|
|
|
// The writepos should never leapfrog the readpos
|
|
|
|
// since that indicates a bad write.
|
|
|
|
if( m_packet_ringpos < readpos )
|
2009-10-18 12:30:00 +00:00
|
|
|
pxAssert( temp < readpos );
|
2009-06-18 08:20:19 +00:00
|
|
|
}
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2009-06-18 08:20:19 +00:00
|
|
|
// Updating the writepos should never make it equal the readpos, since
|
|
|
|
// that would stop the buffer prematurely (and indicates bad code in the
|
|
|
|
// ringbuffer manager)
|
2009-10-18 12:30:00 +00:00
|
|
|
pxAssert( readpos != temp );
|
2009-06-18 08:20:19 +00:00
|
|
|
}
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
|
|
|
|
2009-10-18 12:30:00 +00:00
|
|
|
m_WritePos = temp;
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2009-12-03 15:51:39 +00:00
|
|
|
if( EmuConfig.GS.SynchronousMTGS )
|
2009-02-09 21:15:56 +00:00
|
|
|
{
|
2009-11-21 07:56:29 +00:00
|
|
|
WaitGS();
|
|
|
|
}
|
2009-11-24 22:49:05 +00:00
|
|
|
else if( !m_RingBufferIsBusy )
|
2009-11-24 08:43:36 +00:00
|
|
|
{
|
|
|
|
m_CopyDataTally += m_packet_size;
|
|
|
|
if( m_CopyDataTally > 0x2000 ) SetEvent();
|
|
|
|
}
|
|
|
|
|
|
|
|
m_packet_size = 0;
|
2009-11-21 07:56:29 +00:00
|
|
|
|
2009-10-31 19:18:29 +00:00
|
|
|
//m_PacketLocker.Release();
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
|
|
|
|
2009-11-23 06:54:24 +00:00
|
|
|
int SysMtgsThread::PrepDataPacket( GIF_PATH pathidx, const u32* srcdata, u32 size )
|
2009-02-09 21:15:56 +00:00
|
|
|
{
|
|
|
|
return PrepDataPacket( pathidx, (u8*)srcdata, size );
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef PCSX2_GSRING_TX_STATS
|
|
|
|
static u32 ringtx_s=0;
|
|
|
|
static u32 ringtx_s_ulg=0;
|
|
|
|
static u32 ringtx_s_min=0xFFFFFFFF;
|
|
|
|
static u32 ringtx_s_max=0;
|
|
|
|
static u32 ringtx_c=0;
|
|
|
|
static u32 ringtx_inf[32][32];
|
|
|
|
static u32 ringtx_inf_s[32];
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// returns the amount of giftag data not processed (in simd128 values).
|
|
|
|
// Return value is used by VU1 XGKICK to hack-fix data packets which are too
|
|
|
|
// large for VU1 memory.
|
|
|
|
// Parameters:
|
|
|
|
// size - size of the packet data, in smd128's
|
2009-11-23 06:54:24 +00:00
|
|
|
int SysMtgsThread::PrepDataPacket( GIF_PATH pathidx, const u8* srcdata, u32 size )
|
2009-02-09 21:15:56 +00:00
|
|
|
{
|
2009-10-31 19:25:46 +00:00
|
|
|
//m_PacketLocker.Acquire();
|
2009-07-03 06:05:48 +00:00
|
|
|
|
2009-02-09 21:15:56 +00:00
|
|
|
#ifdef PCSX2_GSRING_TX_STATS
|
2009-05-21 21:12:01 +00:00
|
|
|
ringtx_s += size;
|
|
|
|
ringtx_s_ulg += size&0x7F;
|
|
|
|
ringtx_s_min = min(ringtx_s_min,size);
|
|
|
|
ringtx_s_max = max(ringtx_s_max,size);
|
2009-02-09 21:15:56 +00:00
|
|
|
ringtx_c++;
|
2009-05-21 21:12:01 +00:00
|
|
|
u32 tx_sz;
|
2009-09-17 02:12:32 +00:00
|
|
|
|
2009-02-09 21:15:56 +00:00
|
|
|
if (_BitScanReverse(&tx_sz,size))
|
|
|
|
{
|
2009-05-21 21:12:01 +00:00
|
|
|
u32 tx_algn;
|
2009-02-09 21:15:56 +00:00
|
|
|
_BitScanForward(&tx_algn,size);
|
|
|
|
ringtx_inf[tx_sz][tx_algn]++;
|
|
|
|
ringtx_inf_s[tx_sz]+=size;
|
|
|
|
}
|
|
|
|
if (ringtx_s>=128*1024*1024)
|
|
|
|
{
|
Lots of new code maintenance stuffs:
* Completely new assertion macros: pxAssert, pxAssertMsg, and pxFail, pxAssertDev (both which default to using a message). These replace *all* wxASSERT, DevAssert, and jASSUME varieties of macros. New macros borrow the best of all assertion worlds: MSVCRT, wxASSERT, and AtlAssume. :)
* Rewrote the Console namespace as a structure called IConsoleWriter, and created several varieties of ConsoleWriters for handling different states of log and console availability (should help reduce overhead of console logging nicely).
* More improvements to the PersistentThread model, using safely interlocked "Do*" style callbacks for starting and cleaning up threads.
* Fixed console logs so that they're readable in Win32 notepad again (the log writer adds CRs to naked LFs).
* Added AppInit.cpp -- contains constructor, destructor, OnInit, and command line parsing mess.
git-svn-id: http://pcsx2.googlecode.com/svn/trunk@1950 96395faa-99c1-11dd-bbfe-3dabce05a288
2009-10-04 08:27:27 +00:00
|
|
|
Console.Status("GSRingBufCopy:128MB in %d tx -> b/tx: AVG = %.2f , max = %d, min = %d",ringtx_c,ringtx_s/(float)ringtx_c,ringtx_s_max,ringtx_s_min);
|
2009-02-09 21:15:56 +00:00
|
|
|
for (int i=0;i<32;i++)
|
|
|
|
{
|
|
|
|
u32 total_bucket=0;
|
|
|
|
u32 bucket_subitems=0;
|
|
|
|
for (int j=0;j<32;j++)
|
|
|
|
{
|
|
|
|
if (ringtx_inf[i][j])
|
|
|
|
{
|
|
|
|
total_bucket+=ringtx_inf[i][j];
|
|
|
|
bucket_subitems++;
|
2009-10-29 13:32:40 +00:00
|
|
|
Console.Warning("GSRingBufCopy :tx [%d,%d] algn %d : count= %d [%.2f%%]",1<<i,(1<<(i+1))-16,1<<j,ringtx_inf[i][j],ringtx_inf[i][j]/(float)ringtx_c*100);
|
2009-02-09 21:15:56 +00:00
|
|
|
ringtx_inf[i][j]=0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (total_bucket)
|
2009-10-29 13:32:40 +00:00
|
|
|
Console.Warning("GSRingBufCopy :tx [%d,%d] total : count= %d [%.2f%%] [%.2f%%]",1<<i,(1<<(i+1))-16,total_bucket,total_bucket/(float)ringtx_c*100,ringtx_inf_s[i]/(float)ringtx_s*100);
|
2009-02-09 21:15:56 +00:00
|
|
|
ringtx_inf_s[i]=0;
|
|
|
|
}
|
2009-10-29 13:32:40 +00:00
|
|
|
Console.Warning("GSRingBufCopy :tx ulg count =%d [%.2f%%]",ringtx_s_ulg,ringtx_s_ulg/(float)ringtx_s*100);
|
2009-02-09 21:15:56 +00:00
|
|
|
ringtx_s_ulg=0;
|
|
|
|
ringtx_c=0;
|
|
|
|
ringtx_s=0;
|
|
|
|
ringtx_s_min=0xFFFFFFFF;
|
|
|
|
ringtx_s_max=0;
|
|
|
|
}
|
|
|
|
#endif
|
2009-11-24 08:43:36 +00:00
|
|
|
// Note on volatiles: m_WritePos is not modified by the GS thread, so there's no need
|
|
|
|
// to use volatile reads here. We do cache it though, since we know it never changes,
|
|
|
|
// except for calls to RingbufferRestert() -- handled below.
|
2009-02-09 21:15:56 +00:00
|
|
|
uint writepos = m_WritePos;
|
2009-09-17 02:12:32 +00:00
|
|
|
|
2009-02-09 21:15:56 +00:00
|
|
|
// Checks if a previous copy was started without an accompanying call to GSRINGBUF_DONECOPY
|
2009-10-18 12:30:00 +00:00
|
|
|
pxAssert( m_packet_size == 0 );
|
2009-02-09 21:15:56 +00:00
|
|
|
|
|
|
|
// Sanity checks! (within the confines of our ringbuffer please!)
|
2009-10-18 12:30:00 +00:00
|
|
|
pxAssert( size < RingBufferSize );
|
|
|
|
pxAssert( writepos < RingBufferSize );
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2009-09-23 09:53:21 +00:00
|
|
|
m_packet_size = GIFPath_ParseTag(pathidx, srcdata, size);
|
2009-09-15 06:24:41 +00:00
|
|
|
size = m_packet_size + 1; // takes into account our command qword.
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2009-09-23 09:53:21 +00:00
|
|
|
if( writepos + size < RingBufferSize )
|
2009-02-09 21:15:56 +00:00
|
|
|
{
|
|
|
|
// generic gs wait/stall.
|
|
|
|
// if the writepos is past the readpos then we're safe.
|
|
|
|
// But if not then we need to make sure the readpos is outside the scope of
|
|
|
|
// the block about to be written (writepos + size)
|
|
|
|
|
2009-11-24 08:43:36 +00:00
|
|
|
uint readpos = volatize(m_RingPos);
|
|
|
|
if( (writepos < readpos) && (writepos+size >= readpos) )
|
2009-02-09 21:15:56 +00:00
|
|
|
{
|
2009-11-24 08:43:36 +00:00
|
|
|
// writepos is behind the readpos and will overlap it if we commit the data,
|
|
|
|
// so we need to wait until readpos is out past the end of the future write pos,
|
|
|
|
// or until it wraps around (in which case writepos will be >= readpos).
|
|
|
|
|
|
|
|
// Ideally though we want to wait longer, because if we just toss in this packet
|
|
|
|
// the next packet will likely stall up too. So lets set a condition for the MTGS
|
|
|
|
// thread to wake up the EE once there's a sizable chunk of the ringbuffer emptied.
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2009-11-24 08:43:36 +00:00
|
|
|
uint totalAccum = (m_RingWrapSpot - readpos) + writepos;
|
2009-11-24 20:11:43 +00:00
|
|
|
uint somedone = totalAccum / 4;
|
2009-11-24 08:43:36 +00:00
|
|
|
if( somedone < size+1 ) somedone = size + 1;
|
|
|
|
|
|
|
|
// FMV Optimization: FMVs typically send *very* little data to the GS, in some cases
|
|
|
|
// every other frame is nothing more than a page swap. Sleeping the EEcore is a
|
|
|
|
// waste of time, and we get better results using a spinwait.
|
|
|
|
|
|
|
|
if( somedone > 0x80 )
|
2009-02-09 21:15:56 +00:00
|
|
|
{
|
2009-11-24 20:11:43 +00:00
|
|
|
pxAssertDev( m_SignalRingEnable == 0, "MTGS Thread Synchronization Error" );
|
2009-11-24 08:43:36 +00:00
|
|
|
m_SignalRingPosition = somedone;
|
|
|
|
|
2009-11-24 22:49:05 +00:00
|
|
|
//Console.WriteLn( Color_Blue, "(EEcore Sleep) GenStall \tringpos=0x%06x, writepos=0x%06x, wrapspot=0x%06x, signalpos=0x%06x", readpos, writepos, m_RingWrapSpot, m_SignalRingPosition );
|
2009-11-24 08:43:36 +00:00
|
|
|
|
|
|
|
do {
|
|
|
|
AtomicExchange( m_SignalRingEnable, 1 );
|
|
|
|
SetEvent();
|
|
|
|
m_sem_OnRingReset.WaitWithoutYield();
|
|
|
|
readpos = volatize(m_RingPos);
|
2009-11-24 22:49:05 +00:00
|
|
|
//Console.WriteLn( Color_Blue, "(EEcore Awake) Report!\tringpos=0x%06x", readpos );
|
2009-11-24 08:43:36 +00:00
|
|
|
} while( (writepos < readpos) && (writepos+size >= readpos) );
|
|
|
|
|
|
|
|
pxAssertDev( m_SignalRingPosition <= 0, "MTGS Thread Synchronization Error" );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SetEvent();
|
|
|
|
do {
|
|
|
|
SpinWait();
|
|
|
|
readpos = volatize(m_RingPos);
|
|
|
|
} while( (writepos < readpos) && (writepos+size >= readpos) );
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-09-23 09:53:21 +00:00
|
|
|
else if( writepos + size > RingBufferSize )
|
2009-02-09 21:15:56 +00:00
|
|
|
{
|
2009-11-21 07:56:29 +00:00
|
|
|
pxAssert( writepos != 0 );
|
|
|
|
|
2009-11-24 08:43:36 +00:00
|
|
|
// If the incoming packet doesn't fit, then start over from the start of the ring
|
|
|
|
// buffer (it's a lot easier than trying to wrap the packet around the end of the
|
|
|
|
// buffer).
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2009-11-24 17:13:07 +00:00
|
|
|
//Console.WriteLn( "MTGS > Ringbuffer Got Filled!");
|
2009-11-24 08:43:36 +00:00
|
|
|
RestartRingbuffer( size );
|
2009-11-21 07:56:29 +00:00
|
|
|
writepos = m_WritePos;
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
|
|
|
else // always true - if( writepos + size == MTGS_RINGBUFFEREND )
|
|
|
|
{
|
|
|
|
// Yay. Perfect fit. What are the odds?
|
2009-11-24 08:43:36 +00:00
|
|
|
// Copy is ready so long as readpos is less than writepos and *not* equal to the
|
|
|
|
// base of the ringbuffer (otherwise the buffer will stop when the writepos is
|
|
|
|
// wrapped around to zero later-on in SendDataPacket).
|
|
|
|
|
|
|
|
uint readpos = volatize(m_RingPos);
|
2009-11-24 17:13:07 +00:00
|
|
|
//Console.WriteLn( "MTGS > Perfect Fit!\tringpos=0x%06x, writepos=0x%06x", readpos, writepos );
|
|
|
|
if( readpos > writepos || readpos == 0 )
|
2009-02-09 21:15:56 +00:00
|
|
|
{
|
2009-11-24 22:49:05 +00:00
|
|
|
uint totalAccum = (readpos == 0) ? RingBufferSize : ((m_RingWrapSpot - readpos) + writepos);
|
2009-11-24 08:43:36 +00:00
|
|
|
uint somedone = totalAccum / 4;
|
|
|
|
if( somedone < size+1 ) somedone = size + 1;
|
|
|
|
|
|
|
|
// FMV Optimization: (see above) This condition of a perfect fit is so rare that optimizing
|
|
|
|
// for it is pointless -- but it was also mindlessly simple copy-paste. So there. :p
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2009-11-24 08:43:36 +00:00
|
|
|
if( somedone > 0x80 )
|
|
|
|
{
|
|
|
|
m_SignalRingPosition = somedone;
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2009-11-24 08:43:36 +00:00
|
|
|
//Console.WriteLn( Color_Blue, "(MTGS Sync) EEcore Perfect Sleep!\twrapspot=0x%06x, ringpos=0x%06x, writepos=0x%06x, signalpos=0x%06x", m_RingWrapSpot, readpos, writepos, m_SignalRingPosition );
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2009-11-24 08:43:36 +00:00
|
|
|
do {
|
|
|
|
AtomicExchange( m_SignalRingEnable, 1 );
|
|
|
|
SetEvent();
|
|
|
|
m_sem_OnRingReset.WaitWithoutYield();
|
|
|
|
readpos = volatize(m_RingPos);
|
2009-11-24 20:11:43 +00:00
|
|
|
//Console.WriteLn( Color_Blue, "(MTGS Sync) EEcore Perfect Post-sleep Report!\tringpos=0x%06x", readpos );
|
2009-11-24 08:43:36 +00:00
|
|
|
} while( (writepos < readpos) || (readpos==0) );
|
|
|
|
|
|
|
|
pxAssertDev( m_SignalRingPosition <= 0, "MTGS Thread Synchronization Error" );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-11-24 17:13:07 +00:00
|
|
|
//Console.WriteLn( Color_Blue, "(MTGS Sync) EEcore Perfect Spin!" );
|
2009-11-24 08:43:36 +00:00
|
|
|
SetEvent();
|
|
|
|
do {
|
|
|
|
SpinWait();
|
|
|
|
readpos = volatize(m_RingPos);
|
|
|
|
} while( (writepos < readpos) || (readpos==0) );
|
|
|
|
}
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
2009-11-24 20:11:43 +00:00
|
|
|
|
2009-11-24 22:49:05 +00:00
|
|
|
m_QueuedFrameCount = 0;
|
2009-11-24 20:11:43 +00:00
|
|
|
m_RingWrapSpot = RingBufferSize;
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef RINGBUF_DEBUG_STACK
|
|
|
|
m_lock_Stack.Lock();
|
|
|
|
ringposStack.push_front( writepos );
|
2009-10-31 19:18:29 +00:00
|
|
|
m_lock_Stack.Release();
|
2009-02-09 21:15:56 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
// Command qword: Low word is the command, and the high word is the packet
|
|
|
|
// length in SIMDs (128 bits).
|
|
|
|
|
2009-09-23 09:53:21 +00:00
|
|
|
PacketTagType& tag = (PacketTagType&)RingBuffer[m_WritePos];
|
2009-11-21 07:56:29 +00:00
|
|
|
tag.command = pathidx;
|
2009-02-09 21:15:56 +00:00
|
|
|
tag.data[0] = m_packet_size;
|
|
|
|
m_packet_ringpos = m_WritePos + 1;
|
|
|
|
|
|
|
|
return m_packet_size;
|
|
|
|
}
|
|
|
|
|
2009-11-24 08:43:36 +00:00
|
|
|
void SysMtgsThread::RestartRingbuffer( uint packsize )
|
|
|
|
{
|
|
|
|
if( m_WritePos == 0 ) return;
|
2009-11-24 17:13:07 +00:00
|
|
|
const uint thefuture = packsize;
|
2009-11-24 08:43:36 +00:00
|
|
|
|
2009-11-24 16:08:59 +00:00
|
|
|
//Console.WriteLn( Color_Magenta, "**** Ringbuffer Restart!!" );
|
2009-11-24 08:43:36 +00:00
|
|
|
// Always kick the MTGS into action for a ringbuffer restart.
|
|
|
|
SetEvent();
|
|
|
|
|
|
|
|
uint readpos = volatize(m_RingPos);
|
2009-11-24 16:08:59 +00:00
|
|
|
|
2009-11-24 17:13:07 +00:00
|
|
|
if( (readpos > m_WritePos) || (readpos <= thefuture) )
|
2009-11-24 08:43:36 +00:00
|
|
|
{
|
|
|
|
// We have to be careful not to leapfrog our read-position, which would happen if
|
|
|
|
// it's greater than the current write position (since wrapping writepos to 0 would
|
|
|
|
// be the act of skipping PAST readpos). Stall until it loops around to the
|
2009-11-24 17:13:07 +00:00
|
|
|
// beginning of the buffer, and past the size of our packet allocation.
|
2009-11-24 08:43:36 +00:00
|
|
|
|
2009-11-24 22:49:05 +00:00
|
|
|
uint somedone;
|
|
|
|
|
|
|
|
if( readpos > m_WritePos )
|
|
|
|
somedone = (m_RingWrapSpot - readpos) + packsize + 1;
|
|
|
|
else
|
|
|
|
somedone = (packsize + 1) - readpos;
|
2009-11-24 08:43:36 +00:00
|
|
|
|
2009-11-24 20:11:43 +00:00
|
|
|
if( somedone > 0x80 )
|
|
|
|
{
|
|
|
|
m_SignalRingPosition = somedone;
|
2009-11-24 22:49:05 +00:00
|
|
|
//Console.WriteLn( Color_Blue, "(EEcore Sleep) Restart!\tringpos=0x%06x, writepos=0x%06x, wrapspot=0x%06x, signalpos=0x%06x",
|
|
|
|
// readpos, m_WritePos, m_RingWrapSpot, m_SignalRingPosition );
|
2009-11-24 20:11:43 +00:00
|
|
|
|
|
|
|
do {
|
|
|
|
AtomicExchange( m_SignalRingEnable, 1 );
|
|
|
|
SetEvent();
|
|
|
|
m_sem_OnRingReset.WaitWithoutYield();
|
|
|
|
readpos = volatize(m_RingPos);
|
2009-11-24 22:49:05 +00:00
|
|
|
//Console.WriteLn( Color_Blue, "(EEcore Awake) Report!\tringpos=0x%06x", readpos );
|
2009-11-24 20:11:43 +00:00
|
|
|
} while( (readpos > m_WritePos) || (readpos <= thefuture) );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-11-24 08:43:36 +00:00
|
|
|
SetEvent();
|
2009-11-24 20:11:43 +00:00
|
|
|
do {
|
|
|
|
SpinWait();
|
|
|
|
readpos = volatize(m_RingPos);
|
|
|
|
} while( (readpos > m_WritePos) || (readpos <= thefuture) );
|
|
|
|
}
|
2009-11-24 08:43:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PacketTagType& tag = (PacketTagType&)RingBuffer[m_WritePos];
|
|
|
|
|
|
|
|
tag.command = GS_RINGTYPE_RESTART;
|
|
|
|
|
|
|
|
m_RingWrapSpot = m_WritePos;
|
|
|
|
m_WritePos = 0;
|
2009-11-24 22:49:05 +00:00
|
|
|
m_QueuedFrameCount = 0;
|
2009-11-24 08:43:36 +00:00
|
|
|
|
2009-12-03 15:51:39 +00:00
|
|
|
if( EmuConfig.GS.SynchronousMTGS )
|
2009-11-24 08:43:36 +00:00
|
|
|
WaitGS();
|
|
|
|
}
|
|
|
|
|
2009-11-23 06:54:24 +00:00
|
|
|
__forceinline uint SysMtgsThread::_PrepForSimplePacket()
|
2009-02-09 21:15:56 +00:00
|
|
|
{
|
|
|
|
#ifdef RINGBUF_DEBUG_STACK
|
|
|
|
m_lock_Stack.Lock();
|
|
|
|
ringposStack.push_front( m_WritePos );
|
2009-10-31 19:18:29 +00:00
|
|
|
m_lock_Stack.Release();
|
2009-02-09 21:15:56 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
uint future_writepos = m_WritePos+1;
|
2009-10-18 12:30:00 +00:00
|
|
|
pxAssert( future_writepos <= RingBufferSize );
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2009-09-23 09:53:21 +00:00
|
|
|
future_writepos &= RingBufferMask;
|
2009-11-24 08:43:36 +00:00
|
|
|
if( future_writepos == 0 )
|
2009-11-24 20:11:43 +00:00
|
|
|
{
|
2009-11-24 22:49:05 +00:00
|
|
|
m_QueuedFrameCount = 0;
|
2009-11-24 20:11:43 +00:00
|
|
|
m_RingWrapSpot = RingBufferSize;
|
|
|
|
}
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2009-11-24 20:11:43 +00:00
|
|
|
uint readpos = volatize(m_RingPos);
|
|
|
|
if( future_writepos == readpos )
|
2009-02-09 21:15:56 +00:00
|
|
|
{
|
2009-11-24 20:11:43 +00:00
|
|
|
// The ringbuffer read pos is blocking the future write position, so stall out
|
|
|
|
// until the read position has moved.
|
|
|
|
|
|
|
|
uint totalAccum = (m_RingWrapSpot - readpos) + future_writepos;
|
|
|
|
uint somedone = totalAccum / 4;
|
|
|
|
|
|
|
|
if( somedone > 0x80 )
|
|
|
|
{
|
|
|
|
m_SignalRingPosition = somedone;
|
|
|
|
|
|
|
|
//Console.WriteLn( Color_Blue, "(MTGS Sync) EEcore Simple Sleep!\t\twrapspot=0x%06x, ringpos=0x%06x, writepos=0x%06x, signalpos=0x%06x", m_RingWrapSpot, readpos, writepos, m_SignalRingPosition );
|
|
|
|
|
|
|
|
do {
|
|
|
|
AtomicExchange( m_SignalRingEnable, 1 );
|
|
|
|
SetEvent();
|
|
|
|
m_sem_OnRingReset.WaitWithoutYield();
|
|
|
|
readpos = volatize(m_RingPos);
|
|
|
|
//Console.WriteLn( Color_Blue, "(MTGS Sync) EEcore Simple Post-sleep Report!\tringpos=0x%06x", readpos );
|
|
|
|
} while( future_writepos == readpos );
|
|
|
|
|
|
|
|
pxAssertDev( m_SignalRingPosition <= 0, "MTGS Thread Synchronization Error" );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SetEvent();
|
|
|
|
do {
|
|
|
|
SpinWait();
|
|
|
|
} while( future_writepos == volatize(m_RingPos) );
|
|
|
|
}
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return future_writepos;
|
|
|
|
}
|
|
|
|
|
2009-11-23 06:54:24 +00:00
|
|
|
__forceinline void SysMtgsThread::_FinishSimplePacket( uint future_writepos )
|
2009-02-09 21:15:56 +00:00
|
|
|
{
|
2009-10-18 12:30:00 +00:00
|
|
|
pxAssert( future_writepos != volatize(m_RingPos) );
|
|
|
|
m_WritePos = future_writepos;
|
2009-11-21 07:56:29 +00:00
|
|
|
|
2009-12-03 15:51:39 +00:00
|
|
|
if( EmuConfig.GS.SynchronousMTGS )
|
2009-11-21 07:56:29 +00:00
|
|
|
WaitGS();
|
2009-11-24 08:43:36 +00:00
|
|
|
else
|
|
|
|
++m_CopyDataTally;
|
2009-11-21 07:56:29 +00:00
|
|
|
}
|
|
|
|
|
2009-11-23 06:54:24 +00:00
|
|
|
void SysMtgsThread::SendSimplePacket( MTGS_RingCommand type, int data0, int data1, int data2 )
|
2009-02-09 21:15:56 +00:00
|
|
|
{
|
2009-07-03 06:05:48 +00:00
|
|
|
//ScopedLock locker( m_PacketLocker );
|
|
|
|
|
2009-02-09 21:15:56 +00:00
|
|
|
const uint thefuture = _PrepForSimplePacket();
|
2009-09-23 09:53:21 +00:00
|
|
|
PacketTagType& tag = (PacketTagType&)RingBuffer[m_WritePos];
|
2009-02-09 21:15:56 +00:00
|
|
|
|
|
|
|
tag.command = type;
|
|
|
|
tag.data[0] = data0;
|
|
|
|
tag.data[1] = data1;
|
|
|
|
tag.data[2] = data2;
|
|
|
|
|
2009-07-03 06:05:48 +00:00
|
|
|
_FinishSimplePacket( thefuture );
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
|
|
|
|
2009-11-23 06:54:24 +00:00
|
|
|
void SysMtgsThread::SendPointerPacket( MTGS_RingCommand type, u32 data0, void* data1 )
|
2009-02-09 21:15:56 +00:00
|
|
|
{
|
2009-07-03 06:05:48 +00:00
|
|
|
//ScopedLock locker( m_PacketLocker );
|
|
|
|
|
2009-02-09 21:15:56 +00:00
|
|
|
const uint thefuture = _PrepForSimplePacket();
|
2009-09-23 09:53:21 +00:00
|
|
|
PacketTagType& tag = (PacketTagType&)RingBuffer[m_WritePos];
|
2009-02-09 21:15:56 +00:00
|
|
|
|
|
|
|
tag.command = type;
|
|
|
|
tag.data[0] = data0;
|
|
|
|
*(uptr*)&tag.data[1] = (uptr)data1;
|
|
|
|
|
2009-09-17 02:12:32 +00:00
|
|
|
_FinishSimplePacket( thefuture );
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
|
|
|
|
2009-11-23 06:54:24 +00:00
|
|
|
void SysMtgsThread::SendGameCRC( u32 crc )
|
2009-02-09 21:15:56 +00:00
|
|
|
{
|
2009-09-23 09:53:21 +00:00
|
|
|
SendSimplePacket( GS_RINGTYPE_CRC, crc, 0, 0 );
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
|
|
|
|
2009-11-23 06:54:24 +00:00
|
|
|
void SysMtgsThread::WaitForOpen()
|
2009-02-09 21:15:56 +00:00
|
|
|
{
|
2009-10-19 01:50:52 +00:00
|
|
|
if( m_PluginOpened ) return;
|
2009-10-17 18:21:30 +00:00
|
|
|
Resume();
|
2009-10-18 12:30:00 +00:00
|
|
|
|
|
|
|
// Two-phase timeout on MTGS opening, so that possible errors are handled
|
|
|
|
// in a timely fashion. We check for errors after 2 seconds, and then give it
|
|
|
|
// another 4 seconds if no errors occurred (this might seem long, but sometimes a
|
|
|
|
// GS plugin can be very stubborned, especially in debug mode builds).
|
|
|
|
|
|
|
|
if( !m_sem_OpenDone.Wait( wxTimeSpan(0, 0, 2, 0) ) )
|
|
|
|
{
|
|
|
|
RethrowException();
|
|
|
|
|
|
|
|
if( !m_sem_OpenDone.Wait( wxTimeSpan(0, 0, 4, 0) ) )
|
|
|
|
{
|
|
|
|
RethrowException();
|
2009-10-19 01:50:52 +00:00
|
|
|
|
2009-10-18 12:30:00 +00:00
|
|
|
// Not opened yet, and no exceptions. Weird? You decide!
|
|
|
|
// TODO : implement a user confirmation to cancel the action and exit the
|
|
|
|
// emulator forcefully, or to continue waiting on the GS.
|
2009-10-19 01:50:52 +00:00
|
|
|
|
2009-10-18 12:30:00 +00:00
|
|
|
throw Exception::PluginOpenError( PluginId_GS, "The MTGS thread has become unresponsive while waiting for the GS plugin to open." );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-11-23 06:54:24 +00:00
|
|
|
RethrowException();
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
|
|
|
|
2009-11-23 06:54:24 +00:00
|
|
|
void SysMtgsThread::Freeze( int mode, MTGS_FreezeData& data )
|
2009-02-09 21:15:56 +00:00
|
|
|
{
|
2009-11-04 09:30:22 +00:00
|
|
|
SendPointerPacket( GS_RINGTYPE_FREEZE, mode, &data );
|
|
|
|
Resume();
|
|
|
|
WaitGS();
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|