diff --git a/pcsx2/GS.h b/pcsx2/GS.h index 9f6f8f70f2..f70509cb8c 100644 --- a/pcsx2/GS.h +++ b/pcsx2/GS.h @@ -111,7 +111,7 @@ struct GIFPath return false; } } - + return true; } }; @@ -265,7 +265,7 @@ protected: // Processes a GIFtag & packet, and throws out some gsIRQs as needed. // Used to keep interrupts in sync with the EE, while the GS itself // runs potentially several frames behind. - u32 _gifTransferDummy( GIF_PATH pathidx, const u8 *pMem, u32 size ); + int _gifTransferDummy( GIF_PATH pathidx, const u8 *pMem, u32 size ); // Used internally by SendSimplePacket type functions uint _PrepForSimplePacket(); diff --git a/pcsx2/Gif.cpp b/pcsx2/Gif.cpp index 892441607d..a30a2ad414 100644 --- a/pcsx2/Gif.cpp +++ b/pcsx2/Gif.cpp @@ -58,8 +58,6 @@ __forceinline void gsInterrupt() { return; } - if(Path3progress == 2) vif1Regs->stat &= ~VIF1_STAT_VGW; - if (gif->qwc > 0 || gspath3done == 0) { if (!(psHu32(DMAC_CTRL) & 0x1)) { Console::Notice("gs dma masked, re-scheduling..."); @@ -72,12 +70,14 @@ __forceinline void gsInterrupt() { return; } + vif1Regs->stat &= ~VIF1_STAT_VGW; gspath3done = 0; gscycles = 0; gif->chcr &= ~0x100; GSCSRr &= ~0xC000; //Clear FIFO stuff GSCSRr |= 0x4000; //FIFO empty - psHu32(GIF_STAT)&= ~0xE00; // OPH=0 | APATH=0 + psHu32(GIF_STAT) &= ~GIF_STAT_P3Q; + //psHu32(GIF_STAT)&= ~0xE00; // OPH=0 | APATH=0 psHu32(GIF_STAT)&= ~0x1F000000; // QFC=0 hwDmacIrq(DMAC_GIF); GIF_LOG("GIF DMA end"); @@ -86,7 +86,7 @@ __forceinline void gsInterrupt() { static u32 WRITERING_DMA(u32 *pMem, u32 qwc) { - psHu32(GIF_STAT) |= 0xE00; + psHu32(GIF_STAT) |= GIF_STAT_APATH3 | GIF_STAT_OPH; if( mtgsThread != NULL ) @@ -107,6 +107,7 @@ static u32 WRITERING_DMA(u32 *pMem, u32 qwc) memcpy_aligned(pgsmem, pMem, sizetoread<<4); mtgsThread->SendDataPacket(); + if(Path3progress == 2) psHu32(GIF_STAT)&= ~(GIF_STAT_APATH3 | GIF_STAT_OPH); // OPH=0 | APATH=0 return sizetoread; } else @@ -243,6 +244,7 @@ void GIFdma() if(Path3progress == 2/* && gif->qwc != 0*/) { + vif1Regs->stat &= ~VIF1_STAT_VGW; dmaGIFend(); return; } @@ -347,8 +349,9 @@ void dmaGIF() { return; } - gspath3done = 0; // For some reason this doesnt clear? So when the system starts the thread, we will clear it :) + gspath3done = 0; // For some reason this doesnt clear? So when the system starts the thread, we will clear it :) + psHu32(GIF_STAT) |= GIF_STAT_P3Q; GSCSRr &= ~0xC000; //Clear FIFO stuff GSCSRr |= 0x8000; //FIFO full psHu32(GIF_STAT)|= 0x10000000; // FQC=31, hack ;) [used to be 0xE00; // OPH=1 | APATH=3] @@ -376,7 +379,7 @@ void dmaGIF() { } //Halflife sets a QWC amount in chain mode, no tadr set. - if((gif->qwc > 0) && ((gif->chcr & 0x4) == 0x4)) gspath3done = 1; + if(gif->qwc > 0) gspath3done = 1; GIFdma(); } @@ -391,7 +394,7 @@ static __forceinline int mfifoGIFrbTransfer() { if ((gif->madr+mfifoqwc*16) > (psHu32(DMAC_RBOR) + psHu32(DMAC_RBSR)+16)) { int s1 = ((psHu32(DMAC_RBOR) + psHu32(DMAC_RBSR)+16) - gif->madr) >> 4; - + int s2 = (mfifoqwc - s1); // fixme - I don't think these should use WRITERING_DMA, since our source // isn't the DmaGetAddr(gif->madr) address that WRITERING_DMA expects. @@ -400,13 +403,14 @@ static __forceinline int mfifoGIFrbTransfer() { if (src == NULL) return -1; s1 = WRITERING_DMA(src, s1); - if(s1 == (((psHu32(DMAC_RBOR) + psHu32(DMAC_RBSR)+16) - gif->madr) >> 4)) + if(s1 == (mfifoqwc - s2)) { /* and second copy 's2' bytes from 'maddr' to '&data[s1]' */ src = (u32*)PSM(psHu32(DMAC_RBOR)); if (src == NULL) return -1; - mfifoqwc = WRITERING_DMA(src, (mfifoqwc - s1)) + s1; - } + s2 = WRITERING_DMA(src, s2); + } else s2 = 0; + mfifoqwc = s1 + s2; } else @@ -579,10 +583,10 @@ void gifMFIFOInterrupt() if (!gifmfifoirq) gifqwc = 0; gifstate = GIF_STATE_READY; gif->chcr &= ~0x100; + vif1Regs->stat &= ~VIF1_STAT_VGW; hwDmacIrq(DMAC_GIF); GSCSRr &= ~0xC000; //Clear FIFO stuff GSCSRr |= 0x4000; //FIFO empty - psHu32(GIF_STAT)&= ~0xE00; // OPH=0 | APATH=0 psHu32(GIF_STAT)&= ~0x1F000000; // QFC=0 } diff --git a/pcsx2/Hw.h b/pcsx2/Hw.h index 9a915ce5ba..480a22ef37 100644 --- a/pcsx2/Hw.h +++ b/pcsx2/Hw.h @@ -288,6 +288,23 @@ enum DMACIrqs #define VIF_STAT_ER1 (1<<13) #define VIF_STAT_FDR (1<<23) +//GIF_STAT + +#define GIF_STAT_M3R (1) //GIF_MODE Mask +#define GIF_STAT_M3P (1<<1) //VIF PATH3 Mask +#define GIF_STAT_IMT (1<<2) //Intermittent Transfer Mode +#define GIF_STAT_PSE (1<<3) //Temporary Transfer Stop +#define GIF_STAT_IP3 (1<<5) //Interrupted PATH3 +#define GIF_STAT_P3Q (1<<6) //PATH3 request Queued +#define GIF_STAT_P2Q (1<<7) //PATH2 request Queued +#define GIF_STAT_P1Q (1<<8) //PATH1 request Queued +#define GIF_STAT_OPH (1<<9) //Output Path (Outputting Data) +#define GIF_STAT_APATH1 (1<<10) //Data Transfer Path 1 (In progress) +#define GIF_STAT_APATH2 (2<<10) //Data Transfer Path 2 (In progress) +#define GIF_STAT_APATH3 (3<<10) //Data Transfer Path 3 (In progress) (Mask too) +#define GIF_STAT_DIR (1<<12) //Transfer Direction +#define GIF_STAT_FQC (31<<24) //QWC in GIF-FIFO + //DMA interrupts & masks enum DMAInter { diff --git a/pcsx2/MTGS.cpp b/pcsx2/MTGS.cpp index 25560e85b0..659e517967 100644 --- a/pcsx2/MTGS.cpp +++ b/pcsx2/MTGS.cpp @@ -259,10 +259,11 @@ void mtgsThreadObject::Reset() // Used to keep interrupts in sync with the EE, while the GS itself // runs potentially several frames behind. // size - size of the packet in simd128's -__forceinline u32 mtgsThreadObject::_gifTransferDummy( GIF_PATH pathidx, const u8* pMem, u32 size ) +__forceinline int mtgsThreadObject::_gifTransferDummy( GIF_PATH pathidx, const u8* pMem, u32 size ) { GIFPath& path = m_path[pathidx]; - + /* bool path1loop = false; + int startval = size;*/ #ifdef PCSX2_GSRING_SAMPLING_STATS static uptr profStartPtr = 0; static uptr profEndPtr = 0; @@ -295,10 +296,25 @@ __forceinline u32 mtgsThreadObject::_gifTransferDummy( GIF_PATH pathidx, const u } if( pathidx == 0 ) - { + { + // int transize = 0; // hack: if too much data for VU1, just ignore. // The GIF is evil : if nreg is 0, it's really 16. Otherwise it's the value in nreg. + /*const int numregs = path.tag.nreg ? path.tag.nreg : 16; + if(path.tag.flg < 2) + { + transize = (path.tag.nloop * numregs); + } + else transize = path.tag.nloop; + + if(transize > (path.tag.flg == 1 ? 0x800 : 0x400)) + { + //DevCon::Notice("Too much data"); + path.tag.nloop = 0; + if(path1loop == true)return ++size - 0x400; + else return ++size; + }*/ const int numregs = ((path.tag.nreg-1)&15)+1; if((path.tag.nloop * numregs) > (size * ((path.tag.flg == 1) ? 2 : 1))) @@ -374,7 +390,22 @@ __forceinline u32 mtgsThreadObject::_gifTransferDummy( GIF_PATH pathidx, const u } } - if(pathidx == 0 || pathidx == 2) + if(pathidx == 0) + { + if(path.tag.eop && path.tag.nloop == 0) + { + break; + } + /*if((path.tag.nloop > 0 || (!path.tag.eop && path.tag.nloop == 0)) && size == 0) + { + if(path1loop == true) return size - 0x400; + //DevCon::Notice("Looping Nloop %x, Eop %x, FLG %x", params path.tag.nloop, path.tag.eop, path.tag.flg); + size = 0x400; + pMem -= 0x4000; + path1loop = true; + }*/ + } + if(pathidx == 2) { if(path.tag.eop && path.tag.nloop == 0) { @@ -386,6 +417,11 @@ __forceinline u32 mtgsThreadObject::_gifTransferDummy( GIF_PATH pathidx, const u if(pathidx == 0) { + //If the XGKick has spun around the VU memory end address, we need to INCREASE the size sent. + /*if(path1loop == true) + { + return (size - 0x400); //This will cause a negative making eg. size(20) - retval(-30) = 50; + }*/ if(size == 0 && path.tag.nloop > 0) { path.tag.nloop = 0; @@ -533,8 +569,8 @@ int mtgsThreadObject::Callback() const u128* data = m_RingBuffer.GetPtr( m_RingPos+1 ); // make sure that tag>>16 is the MAX size readable - //GSgifTransfer1(((u32*)data) - 0x1000 + 4*qsize, 0x4000-qsize*16); GSgifTransfer1((u32*)(data - 0x400 + qsize), 0x4000-qsize*16); + //GSgifTransfer1((u32*)data, qsize); ringposinc += qsize; } break; @@ -863,6 +899,7 @@ int mtgsThreadObject::PrepDataPacket( GIF_PATH pathidx, const u8* srcdata, u32 s gif->madr += (size - retval) * 16; gif->qwc -= size - retval; } + //if(retval < 0) DevCon::Notice("Increasing size from %x to %x path %x", params size, size-retval, pathidx+1); size = size - retval; m_packet_size = size; size++; // takes into account our command qword. diff --git a/pcsx2/VUops.cpp b/pcsx2/VUops.cpp index 76a25daae6..dfcd5e5f1a 100644 --- a/pcsx2/VUops.cpp +++ b/pcsx2/VUops.cpp @@ -2061,7 +2061,33 @@ void _vuXGKICK(VURegs * VU) ptr = (u32*)GET_VU_MEM(VU, 0); memcpy(&tempmem[temp], ptr, ((VU->VI[_Is_].US[0]*16) & 0x3fff)); GSGIFTRANSFER1((u32*)&tempmem[0], 0); - } else*/ GSGIFTRANSFER1((u32*)VU->Mem, (VU->VI[_Is_].US[0]*16) & 0x3fff); + } else*/ + //DevCon::Notice("Addr %x", params VU->VI[_Is_].US[0] & 0x3fff); + if( mtgsThread != NULL ) + { + u32* data = (u32*)((u8*)VU->Mem + ((VU->VI[_Is_].US[0]*16) & 0x3fff)); + u32 size; + size = mtgsThread->PrepDataPacket( GIF_PATH_1, data, (0x4000-((VU->VI[_Is_].US[0]*16) & 0x3fff)) >> 4); + { + u8* pmem = mtgsThread->GetDataPacketPtr(); + + if((size << 4) > (u32)(0x4000-((VU->VI[_Is_].US[0]*16) & 0x3fff))) + { + //DevCon::Notice("addr + Size = 0x%x, transferring %x then doing %x", params ((VU->VI[_Is_].US[0]*16) & 0x3fff) + (size << 4), (0x4000-((VU->VI[_Is_].US[0]*16) & 0x3fff)) >> 4, size - (0x4000-((VU->VI[_Is_].US[0]*16) & 0x3fff) >> 4)); + memcpy_aligned(pmem, (u8*)VU->Mem+((VU->VI[_Is_].US[0]*16) & 0x3fff), 0x4000-((VU->VI[_Is_].US[0]*16) & 0x3fff)); + size -= (0x4000-((VU->VI[_Is_].US[0]*16) & 0x3fff)) >> 4; + //DevCon::Notice("Size left %x", params size); + pmem += 0x4000-((VU->VI[_Is_].US[0]*16) & 0x3fff); + memcpy_aligned(pmem, (u8*)VU->Mem, size<<4); + } + else + { + memcpy_aligned(pmem, (u8*)VU->Mem+((VU->VI[_Is_].US[0]*16) & 0x3fff), size<<4); + } + mtgsThread->SendDataPacket(); + } + + }else GSGIFTRANSFER1((u32*)VU->Mem, (VU->VI[_Is_].US[0]*16) & 0x3fff); } void _vuXTOP(VURegs * VU) { diff --git a/pcsx2/VifDma.cpp b/pcsx2/VifDma.cpp index d1604902ae..8b249cfdf6 100644 --- a/pcsx2/VifDma.cpp +++ b/pcsx2/VifDma.cpp @@ -623,8 +623,8 @@ static void VIFunpack(u32 *data, vifCode *v, unsigned int size, const unsigned i if(tempsize > (u32)(VIFdmanum ? 0x4000 : 0x1000)) { - //DevCon::Notice("VIF%x Unpack ending %x > %x", params VIFdmanum, tempsize, VIFdmanum ? 0x4000 : 0x1000); - if(vifRegs->cycle.cl == 1 && ((u32)(VIFdmanum ? 0x4000 : 0x1000) + ((vifRegs->cycle.cl - vifRegs->cycle.wl) * 16)) == tempsize + + if(((vifRegs->cycle.cl != vifRegs->cycle.wl) && ((u32)(VIFdmanum ? 0x4000 : 0x1000) + ((vifRegs->cycle.cl - vifRegs->cycle.wl) * 16)) == tempsize) || tempsize == (u32)(VIFdmanum ? 0x4000 : 0x1000)) { //Its a red herring! so ignore it! SSE unpacks will be much quicker @@ -632,6 +632,7 @@ static void VIFunpack(u32 *data, vifCode *v, unsigned int size, const unsigned i } else { + //DevCon::Notice("VIF%x Unpack ending %x > %x", params VIFdmanum, tempsize, VIFdmanum ? 0x4000 : 0x1000); tempsize = size; size = 0; } @@ -1678,7 +1679,7 @@ static __forceinline void vif1UNPACK(u32 *data) return; } } - vif1FLUSH(); + //vif1FLUSH(); vl = (vif1.cmd) & 0x3; vn = (vif1.cmd >> 2) & 0x3; @@ -1890,7 +1891,7 @@ static int __fastcall Vif1TransDirectHL(u32 *data) } else { - psHu32(GIF_STAT) &= ~0x80; + psHu32(GIF_STAT) &= ~GIF_STAT_APATH2; ret = vif1.tag.size; vif1.tag.size = 0; vif1.cmd = 0; @@ -2057,7 +2058,7 @@ static void Vif1CMDFlush() // FLUSH/E/A if((vif1.cmd & 0x7f) == 0x13) { - if(Path3progress != 2 && gif->chcr & 0x100) // Gif is already transferring so wait for it. + if((Path3progress != 2 || !vif1Regs->mskpath3) && gif->chcr & 0x100) // Gif is already transferring so wait for it. { vif1Regs->stat |= VIF1_STAT_VGW; } @@ -2089,7 +2090,7 @@ static void Vif1CMDSTRowCol() // STROW / STCOL static void Vif1CMDMPGTransfer() // MPG { int vifNum; - vif1FLUSH(); + //vif1FLUSH(); vifNum = (u8)(vif1Regs->code >> 16); if (vifNum == 0) vifNum = 256; @@ -2113,15 +2114,15 @@ static void Vif1CMDDirectHL() // DIRECT/HL //FIXME: This should have timing in both cases, see note below. if((vif1.cmd & 0x7f) == 0x51) { - if(gif->chcr & 0x100 /*&& Path3progress == 0*/) //PATH3 is in image mode, so wait for end of transfer + if(gif->chcr & 0x100 && (!vif1Regs->mskpath3 || Path3progress != 2)) //PATH3 is in image mode, so wait for end of transfer { //DevCon::Notice("DirectHL gif chcr %x gif qwc %x mskpth3 %x", params gif->chcr, gif->qwc, vif1Regs->mskpath3); - if(vif1Regs->mskpath3)vif1Regs->stat |= VIF1_STAT_VGW; - else while(gif->chcr & 0x100) gsInterrupt(); //Hacky as hell (no timing) but Soul Calibur 3 doesnt want timing :( + /*if(vif1Regs->mskpath3)*/vif1Regs->stat |= VIF1_STAT_VGW; + //else while(gif->chcr & 0x100) gsInterrupt(); //Hacky as hell (no timing) but Soul Calibur 3 doesnt want timing :( } } - psHu32(GIF_STAT) |= 0x80; + psHu32(GIF_STAT) |= GIF_STAT_APATH2; } static void Vif1CMDNull() // invalid opcode @@ -2193,6 +2194,17 @@ int VIF1transfer(u32 *data, int size, int istag) while (vif1.vifpacketsize > 0) { + if((vif1.cmd & 0x7f) == 0x51) + { + if(gif->chcr & 0x100 && (!vif1Regs->mskpath3 || Path3progress != 2)) //PATH3 is in image mode, so wait for end of transfer + { + //DevCon::Notice("DirectHL gif chcr %x gif qwc %x mskpth3 %x", params gif->chcr, gif->qwc, vif1Regs->mskpath3); + /*if(vif1Regs->mskpath3)*/vif1Regs->stat |= VIF1_STAT_VGW; + //else while(gif->chcr & 0x100) gsInterrupt(); //Hacky as hell (no timing) but Soul Calibur 3 doesnt want timing :( + } + + } + if(vif1Regs->stat & VIF1_STAT_VGW) break; if (vif1.cmd) { vif1Regs->stat |= VIF1_STAT_VPS_T; //Decompression has started @@ -2350,7 +2362,7 @@ void vif1TransferFromMemory() } FreezeXMMRegs(0); - if (vif1Regs->mskpath3 == 0)vif1Regs->stat &= ~0x1f000000; + g_vifCycles += vif1ch->qwc * 2; vif1ch->madr += vif1ch->qwc * 16; // mgs3 scene changes vif1ch->qwc = 0; @@ -2401,6 +2413,7 @@ __forceinline void vif1SetupTransfer() case 1: //Normal (From memory) vif1.inprogress = 1; vif1.done = true; + g_vifCycles = 2; break; case 2: //Chain @@ -2513,7 +2526,12 @@ __forceinline void vif1Interrupt() } } - if (vif1.inprogress) _VIF1chain(); + if (vif1.inprogress) + { + _VIF1chain(); + CPU_INT(1, g_vifCycles); + return; + } if ((!vif1.done) || (vif1.inprogress & 0x1)) { @@ -2543,7 +2561,7 @@ __forceinline void vif1Interrupt() vif1ch->chcr &= ~0x100; g_vifCycles = 0; hwDmacIrq(DMAC_VIF1); - vif1Regs->stat &= ~0x1F000000; // FQC=0 + if(vif1ch->chcr & 0x1)vif1Regs->stat &= ~0x1F000000; // FQC=0 } void dmaVIF1() @@ -2557,8 +2575,7 @@ void dmaVIF1() g_vifCycles = 0; vif1.inprogress = 0; - vif1Regs->stat |= 0x10000000; // FQC=16 - + if (((psHu32(DMAC_CTRL) & 0xC) == 0x8)) // VIF MFIFO { //Console::WriteLn("VIFMFIFO\n"); @@ -2591,6 +2608,9 @@ void dmaVIF1() vif1.dmamode = 2; } + if(vif1.dmamode != 1)vif1Regs->stat |= 0x10000000; // FQC=16 + else vif1Regs->stat |= min((u16)16, vif1ch->qwc) << 24; // FQC=16 + // Chain Mode vif1.done = false; vif1Interrupt(); @@ -2705,7 +2725,7 @@ void vif1Write32(u32 mem, u32 value) vif1Regs->stat = (vif1Regs->stat & ~VIF1_STAT_FDR) | (value & VIF1_STAT_FDR); if (vif1Regs->stat & VIF1_STAT_FDR) { - vif1Regs->stat |= 0x01000000; + vif1Regs->stat |= 0x01000000; // FQC=1 - hack but it checks this is true before tranfer? (fatal frame) } else { diff --git a/pcsx2/x86/iVUmicroLower.cpp b/pcsx2/x86/iVUmicroLower.cpp index 14d3479b42..fcae6ca866 100644 --- a/pcsx2/x86/iVUmicroLower.cpp +++ b/pcsx2/x86/iVUmicroLower.cpp @@ -1977,7 +1977,7 @@ void VU1XGKICK_MTGSTransfer(u32 *pMem, u32 addr) { u32 size; u32* data = (u32*)((u8*)pMem + (addr&0x3fff)); - + // fixme: The gifTagDummy function in the MTGS (called by PrepDataPacket) has a // hack that aborts the packet if it goes past the end of VU1 memory. // Chances are this should be a "loops around memory" situation, and the packet @@ -1989,7 +1989,20 @@ void VU1XGKICK_MTGSTransfer(u32 *pMem, u32 addr) //if( size > 0 ) { u8* pmem = mtgsThread->GetDataPacketPtr(); - memcpy_aligned(pmem, (u8*)pMem+addr, size<<4); + + /* if((size << 4) > (0x4000-(addr&0x3fff))) + { + //DevCon::Notice("addr + Size = 0x%x, transferring %x then doing %x", params (addr&0x3fff) + (size << 4), (0x4000-(addr&0x3fff)) >> 4, size - ((0x4000-(addr&0x3fff)) >> 4)); + memcpy_aligned(pmem, (u8*)pMem+addr, 0x4000-(addr&0x3fff)); + size -= (0x4000-(addr&0x3fff)) >> 4; + //DevCon::Notice("Size left %x", params size); + pmem += 0x4000-(addr&0x3fff); + memcpy_aligned(pmem, (u8*)pMem, size<<4); + } + else + {*/ + memcpy_aligned(pmem, (u8*)pMem+addr, size<<4); + // } mtgsThread->SendDataPacket(); } } diff --git a/pcsx2/x86/microVU_Lower.inl b/pcsx2/x86/microVU_Lower.inl index 38598be5b9..85bc94dce3 100644 --- a/pcsx2/x86/microVU_Lower.inl +++ b/pcsx2/x86/microVU_Lower.inl @@ -1103,7 +1103,22 @@ void __fastcall mVU_XGKICK_(u32 addr) { u32 *data = (u32*)(microVU1.regs->Mem + addr); u32 size = mtgsThread->PrepDataPacket(GIF_PATH_1, data, (0x4000-addr) >> 4); u8 *pDest = mtgsThread->GetDataPacketPtr(); - memcpy_aligned(pDest, microVU1.regs->Mem + addr, size<<4); +/* + if((size << 4) > (0x4000-(addr&0x3fff))) + { + //DevCon::Notice("addr + Size = 0x%x, transferring %x then doing %x", params (addr&0x3fff) + (size << 4), (0x4000-(addr&0x3fff)) >> 4, size - ((0x4000-(addr&0x3fff)) >> 4)); + memcpy_aligned(pDest, microVU1.regs->Mem + addr, 0x4000-(addr&0x3fff)); + size -= (0x4000-(addr&0x3fff)) >> 4; + //DevCon::Notice("Size left %x", params size); + pDest += 0x4000-(addr&0x3fff); + memcpy_aligned(pDest, microVU1.regs->Mem, size<<4); + } + else + { +*/ + memcpy_aligned(pDest, microVU1.regs->Mem + addr, size<<4); +// } + mtgsThread->SendDataPacket(); }