diff --git a/pcsx2/GS.h b/pcsx2/GS.h index c0cc05c07f..d7a982cc8e 100644 --- a/pcsx2/GS.h +++ b/pcsx2/GS.h @@ -97,6 +97,20 @@ struct GIFPath __forceinline void PrepRegs(bool doPrep); __forceinline void SetTag(const void* mem); + __forceinline bool StepReg() + { + u32 numRegs = ((tag.nreg-1)&0xf)+1; + if ((++curreg & 0xf) == numRegs) { + curreg = 0; + if (--tag.nloop == 0) { + return false; + } + } + return true; + } + __forceinline u8 GetReg() { + return regs[curreg&0xf]; + } }; diff --git a/pcsx2/MTGS.cpp b/pcsx2/MTGS.cpp index 32668eaf81..af76df3cc5 100644 --- a/pcsx2/MTGS.cpp +++ b/pcsx2/MTGS.cpp @@ -90,6 +90,7 @@ __forceinline void GIFPath::SetTag(const void* mem) { tag = *((GIFTAG*)mem); curreg = 0; + PrepRegs(); } static void _mtgsFreezeGIF( SaveStateBase& state, GIFPath (&paths)[3] ) @@ -242,101 +243,99 @@ void mtgsThreadObject::Reset() memzero_obj( s_path ); } -#define incPmem(x) { \ - pMem += (x) * 16; \ - size += (x) * 16; \ +#define incTag(x, y) { \ + pMem += (x); \ + size -= (y); \ if ((pathidx==GIF_PATH_1)&&(pMem>=vuMemEnd)) pMem -= 0x4000; \ } -#define subVal(x) ((x) ? (x-1) : 0) +#define aMin(x, y) ((x < y) ? (x) : (y)) +#define subVal(x, y) ((x > y) ? (x-y) : 0 ) + +__forceinline void gsHandler(const u8* pMem) { + const int handler = pMem[8]; + if (handler >= 0x60 && handler < 0x63) { + //DevCon::Status("GIF Tag Interrupt"); + s_GSHandlers[handler&0x3]((const u32*)pMem); + } +} __forceinline int mtgsThreadObject::_gifTransferDummy(GIF_PATH pathidx, const u8* pMem, u32 size) { - GIFPath& path = s_path[pathidx]; - u32 finish = (pathidx == GIF_PATH_1) ? 0x4000 : (size<<4); - u32 oldSize = 0; - u32 numRegs = 0; - const u8* vuMemEnd = pMem + (size<<4); // End of VU Mem - bool pathContinue = !!path.tag.nloop; // Continue From Last Transfer - bool EOP = 0; - bool hasRegAD = 0; - size = 0; + GIFPath& path = s_path[pathidx]; // Current Path + const u8* vuMemEnd = pMem + (size<<4); // End of VU1 Mem + if (pathidx==GIF_PATH_1) size = 0x4000; // VU1 mem size + u32 startSize = size; // Start Size - while(!EOP && size < finish) { + while (size > 0) { + if (!path.tag.nloop) { - if(!pathContinue) { path.SetTag(pMem); - path.PrepRegs(!path.tag.flg); - incPmem(1); + incTag(16, 1); + + if (pathidx == GIF_PATH_3) { + if (path.tag.flg&2) Path3progress = IMAGE_MODE; + else Path3progress = TRANSFER_MODE; + } } - pathContinue = 0; - oldSize = size; - numRegs = ((path.tag.nreg-1)&0xf)+1; - EOP = ((pathidx == GIF_PATH_2) ? 0 : path.tag.eop); - - if (!path.tag.nloop || size >= finish) continue; - - switch(path.tag.flg) { - case GIF_FLG_PACKED: - for (u32 i = 0; i < path.tag.nloop; i++) { - for (u32 j = path.curreg; j < numRegs; j++) { - if (path.regs[j] == 0x0e) { - const int handler = pMem[8]; - if (handler >= 0x60 && handler < 0x63) { - //DevCon::Status("GIF Tag Interrupt"); - s_GSHandlers[handler&0x3]((const u32*)pMem); - } - hasRegAD = 1; + else { + switch(path.tag.flg) { + case GIF_FLG_PACKED: + do { + if (path.GetReg() == 0xe) { + gsHandler(pMem); } - incPmem(1); - path.curreg = 0; - if (size >= finish) goto endLoop; + incTag(16, 1); + } while(path.StepReg() && size > 0); + break; + case GIF_FLG_REGLIST: + { + u32 numRegs = (((path.tag.nreg-1)&0xf)+2)/2; + if((numRegs * path.tag.nloop) <= size) { + u32 temp1 = (numRegs - path.curreg); + u32 temp2 = (numRegs * subVal(path.tag.nloop, 1)); + incTag((temp1*16), temp1); + incTag((temp2*16), temp2); + path.tag.nloop = 0; } - if (!hasRegAD) { // Optimization: No Need to Loop - incPmem(numRegs * subVal(path.tag.nloop)); - break; + else { + size *= 2; + do { incTag(8, 1); } + while(path.StepReg() && size > 0); + + if (size & 1) { incTag(8, 1); } + size /= 2; } } break; - case GIF_FLG_REGLIST: - numRegs = (numRegs + 1) / 2; - incPmem((numRegs - path.curreg) * path.tag.nloop); - incPmem((numRegs * subVal(path.tag.nloop))); + case GIF_FLG_IMAGE: + case GIF_FLG_IMAGE2: + { + int len = aMin(size, path.tag.nloop); + incTag((len * 16), len); + path.tag.nloop -= len; + } break; - case GIF_FLG_IMAGE: - case GIF_FLG_IMAGE2: - incPmem(path.tag.nloop); + } + } + + if (path.tag.eop && !path.tag.nloop) { + if (pathidx != GIF_PATH_2) { break; - } + } + } } -endLoop: - // This handles cases where we skipped too far ahead because of bulky IMAGE/REGLIST tags - // or PACKED tags w/o RegA+D (they don't compare 'size < finish' every qwc). - if (size > finish) size = finish; - - // Sets information to resume partial transfers - if (!EOP && path.tag.nloop && pathidx) { - int diff = (size - oldSize) / 16; - if (!(path.tag.flg&2)) { // PACKED/REGLIST - path.curreg = (diff % path.tag.nloop); - path.tag.nloop -= (diff / numRegs); - } - else path.tag.nloop -= diff; - } - else { - path.curreg = 0; - path.tag.nloop = 0; - } + size = (startSize - size); if (pathidx == GIF_PATH_3) { - gif->madr += size; - gif->qwc -= (size/16); - if (EOP) Path3progress = STOPPED_MODE; - else if (path.tag.flg&2) Path3progress = IMAGE_MODE; - else Path3progress = TRANSFER_MODE; + if (path.tag.eop && !path.tag.nloop) { + Path3progress = STOPPED_MODE; + } + gif->madr += size * 16; + gif->qwc -= size; } - return (size / 16); + return size; } // Processes a GIFtag & packet, and throws out some gsIRQs as needed.