diff --git a/pcsx2/FiFo.c b/pcsx2/FiFo.c index e408fa3060..2376a9bf4f 100644 --- a/pcsx2/FiFo.c +++ b/pcsx2/FiFo.c @@ -133,14 +133,6 @@ void WriteFIFO(u32 mem, u64 *value) { data[1] = value[1]; GSgifTransferDummy(2, (u32*)data, 1); GSRINGBUF_DONECOPY((u8*)data, 16); - - if( !CHECK_DUALCORE ) { -#if defined(_WIN32) && !defined(WIN32_PTHREADS) - SetEvent(g_hGsEvent); -#else - pthread_cond_signal(&g_condGsEvent); -#endif - } } else { FreezeXMMRegs(1); diff --git a/pcsx2/GS.cpp b/pcsx2/GS.cpp index 512e9cb848..b3fbba4b14 100644 --- a/pcsx2/GS.cpp +++ b/pcsx2/GS.cpp @@ -253,6 +253,19 @@ static __forceinline void gsSetEventWait() } } +// mem and size are the ones from GSRingBufCopy +void GSRINGBUF_DONECOPY(const u8 *mem, u32 size) +{ + u8* temp = (u8*)(mem) + (size); + + assert( temp <= GS_RINGBUFFEREND); + + if( temp == GS_RINGBUFFEREND ) temp = GS_RINGBUFFERBASE; + InterlockedExchangePointer((void**)&g_pGSWritePos, temp); + if( !CHECK_DUALCORE ) GS_SETEVENT(); +} + + void gsShutdown() { if( CHECK_MULTIGS ) { @@ -310,80 +323,88 @@ u8* GSRingBufCopy(void* mem, u32 size, u32 type) // is reading it. u8* writepos = g_pGSWritePos; - u8* tempbuf; assert( size < GS_RINGBUFFERSIZE ); assert( writepos < GS_RINGBUFFEREND ); assert( ((uptr)writepos & 15) == 0 ); assert( (size&15) == 0); size += 16; - tempbuf = *(volatile PU8*)&g_pGSRingPos; - if( writepos + size > GS_RINGBUFFEREND ) { - - // skip to beginning - while( writepos < tempbuf || tempbuf == GS_RINGBUFFERBASE ) { - gsSetEventWait(); - tempbuf = *(volatile PU8*)&g_pGSRingPos; - } + if( writepos + size > GS_RINGBUFFEREND ) + { + // 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). - // notify GS - if( writepos != GS_RINGBUFFEREND ) { - InterlockedExchangePointer((void**)writepos, GS_RINGTYPE_RESTART); - } + // We have to be careful not to leapfrog our readposition. If it's + // greater than the current write position then we need to stall + // until it loops around: + + //const u8* readps = *(volatile PU8*)&g_pGSRingPos; + while( *(volatile PU8*)&g_pGSRingPos > writepos ) // && readpos == GS_RINGBUFFERBASE ) + gsSetEventWait(); + + GSRingBufSimplePacket( GS_RINGTYPE_RESTART, 0, 0, 0 ); + + writepos = GS_RINGBUFFERBASE; + + // stall until the read position is past the end of our incoming block: + while( writepos+size >= *(volatile PU8*)&g_pGSRingPos ) + gsSetEventWait(); InterlockedExchangePointer((void**)&g_pGSWritePos, GS_RINGBUFFERBASE); - writepos = GS_RINGBUFFERBASE; } - else if( writepos + size == GS_RINGBUFFEREND ) { - while(tempbuf == GS_RINGBUFFERBASE && tempbuf != writepos) { - gsSetEventWait(); - tempbuf = *(volatile PU8*)&g_pGSRingPos; - } - } + else if( writepos + size == GS_RINGBUFFEREND ) + { + // Yay. Perfect fit. What are the odds? + // ... apparently very slim because the old code just performed the equivalent + // of a gsWaitGS (stalling the GS until the ring buffer emptied completely) and + // no one noticed enough to fix it. :) - while( writepos < tempbuf && (writepos+size >= tempbuf || (writepos+size == GS_RINGBUFFEREND && tempbuf == GS_RINGBUFFERBASE)) ) { - gsSetEventWait(); - tempbuf = *(volatile PU8*)&g_pGSRingPos; + while( writepos < *(volatile PU8*)&g_pGSRingPos ) + gsSetEventWait(); + } + else + { + // two conditionals in the following while() loop, so precache + // the readpos for more efficient behavior: + const u8* readpos = *(volatile PU8*)&g_pGSRingPos; + + // generic gs wait/stall. + // Waits until the readpos is outside the scope of the write area. + while( writepos < readpos && writepos+size >= readpos ) // || (writepos+size == GS_RINGBUFFEREND && readpos == GS_RINGBUFFERBASE)) ) { + { + gsSetEventWait(); + readpos = *(volatile PU8*)&g_pGSRingPos; + } } // just copy - *(u32*)writepos = type|(((size-16)>>4)<<16); + *(u32*)writepos = type | (((size-16)>>4)<<16); return writepos+16; } void GSRingBufSimplePacket(int type, int data0, int data1, int data2) { u8* writepos = g_pGSWritePos; - u8* tempbuf; + u8* future_writepos = writepos+16; - assert( writepos + 16 <= GS_RINGBUFFEREND ); + assert( future_writepos <= GS_RINGBUFFEREND ); - tempbuf = *(volatile PU8*)&g_pGSRingPos; - while(writepos < tempbuf && writepos+16 >= tempbuf ) { + if( future_writepos == GS_RINGBUFFEREND ) + future_writepos = GS_RINGBUFFERBASE; + + while( future_writepos == *(volatile PU8*)&g_pGSRingPos ) gsSetEventWait(); - tempbuf = *(volatile PU8*)&g_pGSRingPos; - } *(u32*)writepos = type; *(u32*)(writepos+4) = data0; *(u32*)(writepos+8) = data1; *(u32*)(writepos+12) = data2; - writepos += 16; - if( writepos == GS_RINGBUFFEREND ) { - - while(tempbuf == GS_RINGBUFFERBASE && tempbuf != g_pGSWritePos) { - gsSetEventWait(); - tempbuf = *(volatile PU8*)&g_pGSRingPos; - } + InterlockedExchangePointer((void**)&g_pGSWritePos, future_writepos); - writepos = GS_RINGBUFFERBASE; - } - InterlockedExchangePointer((void**)&g_pGSWritePos, writepos); - - if( !CHECK_DUALCORE ) { + if( !CHECK_DUALCORE ) GS_SETEVENT(); - } } void gsReset() @@ -939,8 +960,6 @@ static __forceinline void WRITERING_DMA(u32 *pMem, u32 qwc) { GSRINGBUF_DONECOPY(pgsmem, sizetoread); GSgifTransferDummy(2, pMem, qwc); } - - if( !CHECK_DUALCORE ) GS_SETEVENT(); } else { GSGIFTRANSFER3(pMem, qwc); @@ -1500,7 +1519,8 @@ void* GSThreadProc(void* lpParam) break; case GS_RINGTYPE_FRAMESKIP: - GSsetFrameSkip(*(int*)(g_pGSRingPos+4)); + if( GSsetFrameSkip != NULL ) + GSsetFrameSkip(*(int*)(g_pGSRingPos+4)); break; case GS_RINGTYPE_MEMWRITE8: g_MTGSMem[*(int*)(g_pGSRingPos+4)] = *(u8*)(g_pGSRingPos+8); diff --git a/pcsx2/GS.h b/pcsx2/GS.h index 19cf98def1..d3cbc1e208 100644 --- a/pcsx2/GS.h +++ b/pcsx2/GS.h @@ -97,15 +97,6 @@ extern u8* g_pGSWritePos; //#endif -// mem and size are the ones from GSRingBufCopy -static __forceinline void GSRINGBUF_DONECOPY(const u8 *mem, u32 size) { - u8* temp = (u8*)(mem) + (size); - assert( temp <= GS_RINGBUFFEREND); -// MTGS_RECWRITE(mem, size); - if( temp == GS_RINGBUFFEREND ) temp = GS_RINGBUFFERBASE; - InterlockedExchangePointer((void**)&g_pGSWritePos, temp); -} - #if defined(_WIN32) && !defined(WIN32_PTHREADS) #define GS_SETEVENT() SetEvent(g_hGsEvent) @@ -125,6 +116,8 @@ void gsInit(); void gsShutdown(); void gsReset(); +// mem and size are the ones from GSRingBufCopy +extern void GSRINGBUF_DONECOPY(const u8 *mem, u32 size); extern void gsWaitGS(); // used for resetting GIF fifo diff --git a/pcsx2/Misc.c b/pcsx2/Misc.c index 86d20d846b..1bcfce399e 100644 --- a/pcsx2/Misc.c +++ b/pcsx2/Misc.c @@ -863,7 +863,8 @@ void ProcessFKeys(int fkey, int shift) break; case 4: - + { + const char* limitMsg; #ifdef PCSX2_NORECBUILD SysPrintf("frame skipping only valid for recompiler build\n"); #else @@ -882,33 +883,37 @@ void ProcessFKeys(int fkey, int shift) if( CHECK_MULTIGS ) GSRingBufSimplePacket(GS_RINGTYPE_FRAMESKIP, 0, 0, 0); else GSsetFrameSkip(0); Cpu->ExecuteVU1Block = recExecuteVU1Block; - if(SPU2setTimeStretcher != NULL) - SPU2setTimeStretcher(1); - SysPrintf("Normal - Frame Limit Mode Changed\n"); + limitMsg = "None/Normal"; break; case PCSX2_FRAMELIMIT_LIMIT: if( CHECK_MULTIGS ) GSRingBufSimplePacket(GS_RINGTYPE_FRAMESKIP, 0, 0, 0); else GSsetFrameSkip(0); Cpu->ExecuteVU1Block = recExecuteVU1Block; //Quality option, turn off timestretching on the SPU2 plugin - if(SPU2setTimeStretcher != NULL) - SPU2setTimeStretcher(0); - SysPrintf("Limit - Frame Limit Mode Changed\n"); + limitMsg = "Limit"; break; case PCSX2_FRAMELIMIT_SKIP: Cpu->ExecuteVU1Block = recExecuteVU1Block; - if(SPU2setTimeStretcher != NULL) - SPU2setTimeStretcher(1); - SysPrintf("Frame Skip - Frame Limit Mode Changed\n"); - break; case PCSX2_FRAMELIMIT_VUSKIP: - if(SPU2setTimeStretcher != NULL) - SPU2setTimeStretcher(1); - SysPrintf("VU Skip - Frame Limit Mode Changed\n"); + if( GSsetFrameSkip == NULL ) + { + Config.Options &= ~PCSX2_FRAMELIMIT_MASK; + SysPrintf("Notice: GS Plugin does not support frameskipping.\n"); + limitMsg = "None/Normal"; + } + else + { + limitMsg = (CHECK_FRAMELIMIT == PCSX2_FRAMELIMIT_SKIP) ? "Skip" : "VUSkip"; + } + break; } + + SysPrintf("Frame Limit Mode Changed: %s\n", limitMsg ); + // [Air]: Do we really want to save runtime changes to frameskipping? - //SaveConfig(); + //SaveConfig(); + } #endif break; // note: VK_F5-VK_F7 are reserved for GS diff --git a/pcsx2/VifDma.c b/pcsx2/VifDma.c index 6a0970ca39..7074248a7b 100644 --- a/pcsx2/VifDma.c +++ b/pcsx2/VifDma.c @@ -1668,11 +1668,10 @@ static int Vif1TransDirectHL(u32 *data){ if( gsmem != NULL ) { FreezeMMXRegs(1); memcpy_fast(gsmem, (u32*)splittransfer[0], 16); + FreezeMMXRegs(0); GSRINGBUF_DONECOPY(gsmem, 16); GSgifTransferDummy(1, (u32*)splittransfer[0], 1); } - FreezeMMXRegs(0); - if( !CHECK_DUALCORE ) GS_SETEVENT(); } else { FreezeXMMRegs(1); @@ -1718,8 +1717,6 @@ static int Vif1TransDirectHL(u32 *data){ GSRINGBUF_DONECOPY(gsmem, ret<<2); GSgifTransferDummy(1, data, ret>>2); } - - if( !CHECK_DUALCORE ) GS_SETEVENT(); } else { @@ -2331,9 +2328,6 @@ void dmaVIF1() GSRINGBUF_DONECOPY(pMem, 0); - if( !CHECK_DUALCORE ) - GS_SETEVENT(); - g_MTGSVifStart = cpuRegs.cycle; g_MTGSVifCount = 4000000; // a little less than 1/60th of a second diff --git a/pcsx2/x86/iVUmicro.c b/pcsx2/x86/iVUmicro.c index ed530ca4a4..13e173de7a 100644 --- a/pcsx2/x86/iVUmicro.c +++ b/pcsx2/x86/iVUmicro.c @@ -5633,14 +5633,6 @@ void VU1XGKICK_MTGSTransfer(u32 *pMem, u32 addr) FreezeMMXRegs(0); GSRINGBUF_DONECOPY(pmem, size); - - if( !CHECK_DUALCORE ) { -#if defined(_WIN32) && !defined(WIN32_PTHREADS) - SetEvent(g_hGsEvent); -#else - pthread_cond_signal(&g_condGsEvent); -#endif - } } }