#include #include #include #include "GSHandler.h" #include "INTC.h" #include "PtrMacro.h" #include "Log.h" #include "MemoryStateFile.h" #include "RegisterStateFile.h" #define R_REG(a, v, r) \ if((a) & 0x4) \ { \ v = (uint32)(r >> 32); \ } \ else \ { \ v = (uint32)(r & 0xFFFFFFFF); \ } #define W_REG(a, v, r) \ if((a) & 0x4) \ { \ (r) &= 0x00000000FFFFFFFFULL; \ (r) |= (uint64)(v) << 32; \ } \ else \ { \ (r) &= 0xFFFFFFFF00000000ULL; \ (r) |= (v); \ } #define STATE_RAM ("gs/ram") #define STATE_REGS ("gs/regs") #define STATE_TRXCTX ("gs/trxcontext") #define STATE_PRIVREGS ("gs/privregs.xml") #define STATE_PRIVREGS_PMODE ("PMODE") #define STATE_PRIVREGS_DISPFB1 ("DISPFB1") #define STATE_PRIVREGS_DISPLAY1 ("DISPLAY1") #define STATE_PRIVREGS_DISPFB2 ("DISPFB2") #define STATE_PRIVREGS_DISPLAY2 ("DISPLAY2") #define STATE_PRIVREGS_CSR ("CSR") #define STATE_PRIVREGS_IMR ("IMR") #define STATE_PRIVREGS_CRTINTERLACED ("CrtInterlated") #define STATE_PRIVREGS_CRTMODE ("CrtMode") #define STATE_PRIVREGS_CRTFRAMEMODE ("CrtFrameMode") #define LOG_NAME ("gs") using namespace Framework; using namespace std; using namespace std::tr1; int CGSHandler::STORAGEPSMCT32::m_nBlockSwizzleTable[4][8] = { { 0, 1, 4, 5, 16, 17, 20, 21 }, { 2, 3, 6, 7, 18, 19, 22, 23 }, { 8, 9, 12, 13, 24, 25, 28, 29 }, { 10, 11, 14, 15, 26, 27, 30, 31 }, }; int CGSHandler::STORAGEPSMCT32::m_nColumnSwizzleTable[2][8] = { { 0, 1, 4, 5, 8, 9, 12, 13, }, { 2, 3, 6, 7, 10, 11, 14, 15, }, }; int CGSHandler::STORAGEPSMCT16::m_nBlockSwizzleTable[8][4] = { { 0, 2, 8, 10, }, { 1, 3, 9, 11, }, { 4, 6, 12, 14, }, { 5, 7, 13, 15, }, { 16, 18, 24, 26, }, { 17, 19, 25, 27, }, { 20, 22, 28, 30, }, { 21, 23, 29, 31, }, }; int CGSHandler::STORAGEPSMCT16::m_nColumnSwizzleTable[2][16] = { { 0, 2, 8, 10, 16, 18, 24, 26, 1, 3, 9, 11, 17, 19, 25, 27, }, { 4, 6, 12, 14, 20, 22, 28, 30, 5, 7, 13, 15, 21, 23, 29, 31, }, }; int CGSHandler::STORAGEPSMCT16S::m_nBlockSwizzleTable[8][4] = { { 0, 2, 16, 18, }, { 1, 3, 17, 19, }, { 8, 10, 24, 26, }, { 9, 11, 25, 27, }, { 4, 6, 20, 22, }, { 5, 7, 21, 23, }, { 12, 14, 28, 30, }, { 13, 15, 29, 31, }, }; int CGSHandler::STORAGEPSMCT16S::m_nColumnSwizzleTable[2][16] = { { 0, 2, 8, 10, 16, 18, 24, 26, 1, 3, 9, 11, 17, 19, 25, 27, }, { 4, 6, 12, 14, 20, 22, 28, 30, 5, 7, 13, 15, 21, 23, 29, 31, }, }; int CGSHandler::STORAGEPSMT8::m_nBlockSwizzleTable[4][8] = { { 0, 1, 4, 5, 16, 17, 20, 21 }, { 2, 3, 6, 7, 18, 19, 22, 23 }, { 8, 9, 12, 13, 24, 25, 28, 29 }, { 10, 11, 14, 15, 26, 27, 30, 31 }, }; int CGSHandler::STORAGEPSMT8::m_nColumnWordTable[2][2][8] = { { { 0, 1, 4, 5, 8, 9, 12, 13, }, { 2, 3, 6, 7, 10, 11, 14, 15, }, }, { { 8, 9, 12, 13, 0, 1, 4, 5, }, { 10, 11, 14, 15, 2, 3, 6, 7, }, }, }; int CGSHandler::STORAGEPSMT4::m_nBlockSwizzleTable[8][4] = { { 0, 2, 8, 10, }, { 1, 3, 9, 11, }, { 4, 6, 12, 14, }, { 5, 7, 13, 15, }, { 16, 18, 24, 26, }, { 17, 19, 25, 27, }, { 20, 22, 28, 30, }, { 21, 23, 29, 31, } }; int CGSHandler::STORAGEPSMT4::m_nColumnWordTable[2][2][8] = { { { 0, 1, 4, 5, 8, 9, 12, 13, }, { 2, 3, 6, 7, 10, 11, 14, 15, }, }, { { 8, 9, 12, 13, 0, 1, 4, 5, }, { 10, 11, 14, 15, 2, 3, 6, 7, }, }, }; CGSHandler::CGSHandler() : m_thread(NULL), m_enabled(true), m_renderDone(false), m_threadDone(false) { m_pRAM = (uint8*)malloc(RAMSIZE); for(int i = 0; i < PSM_MAX; i++) { m_pTransferHandler[i] = &CGSHandler::TrxHandlerInvalid; } m_pTransferHandler[PSMCT32] = &CGSHandler::TrxHandlerCopy; m_pTransferHandler[PSMCT24] = &CGSHandler::TrxHandlerPSMCT24; m_pTransferHandler[PSMCT16] = &CGSHandler::TrxHandlerCopy; m_pTransferHandler[PSMT8] = &CGSHandler::TrxHandlerCopy; m_pTransferHandler[PSMT4] = &CGSHandler::TrxHandlerPSMT4; m_pTransferHandler[PSMT8H] = &CGSHandler::TrxHandlerPSMT8H; m_pTransferHandler[PSMT4HL] = &CGSHandler::TrxHandlerPSMT4H<24, 0x0F000000>; m_pTransferHandler[PSMT4HH] = &CGSHandler::TrxHandlerPSMT4H<28, 0xF0000000>; Reset(); m_thread = new boost::thread(bind(&CGSHandler::ThreadProc, this)); } CGSHandler::~CGSHandler() { m_threadDone = true; m_thread->join(); delete m_thread; FREEPTR(m_pRAM); } void CGSHandler::Reset() { memset(m_nReg, 0, sizeof(uint64) * 0x80); m_nReg[GS_REG_PRMODECONT] = 1; memset(m_pRAM, 0, RAMSIZE); m_nPMODE = 0; m_nDISPFB1 = 0; m_nDISPLAY1 = 0; m_nDISPFB2 = 0; m_nDISPLAY2 = 0; m_nCSR = 0; m_nIMR = 0; m_nCrtIsInterlaced = false; m_nCrtMode = 0; m_nCrtIsFrameMode = false; m_enabled = true; m_renderDone = false; } void CGSHandler::SetEnabled(bool enabled) { m_enabled = enabled; } bool CGSHandler::IsRenderDone() const { return m_renderDone; } void CGSHandler::SaveState(CZipArchiveWriter& archive) { archive.InsertFile(new CMemoryStateFile(STATE_RAM, m_pRAM, RAMSIZE)); archive.InsertFile(new CMemoryStateFile(STATE_REGS, m_nReg, sizeof(uint64) * 0x80)); archive.InsertFile(new CMemoryStateFile(STATE_TRXCTX, &m_TrxCtx, sizeof(TRXCONTEXT))); { CRegisterStateFile* registerFile = new CRegisterStateFile(STATE_PRIVREGS); registerFile->SetRegister64(STATE_PRIVREGS_PMODE, m_nPMODE); registerFile->SetRegister64(STATE_PRIVREGS_DISPFB1, m_nDISPFB1); registerFile->SetRegister64(STATE_PRIVREGS_DISPLAY1, m_nDISPLAY1); registerFile->SetRegister64(STATE_PRIVREGS_DISPFB2, m_nDISPFB2); registerFile->SetRegister64(STATE_PRIVREGS_DISPLAY2, m_nDISPLAY2); registerFile->SetRegister64(STATE_PRIVREGS_CSR, m_nCSR); registerFile->SetRegister64(STATE_PRIVREGS_IMR, m_nIMR); registerFile->SetRegister32(STATE_PRIVREGS_CRTINTERLACED, m_nCrtIsInterlaced); registerFile->SetRegister32(STATE_PRIVREGS_CRTMODE, m_nCrtMode); registerFile->SetRegister32(STATE_PRIVREGS_CRTFRAMEMODE, m_nCrtIsFrameMode); archive.InsertFile(registerFile); } } void CGSHandler::LoadState(CZipArchiveReader& archive) { archive.BeginReadFile(STATE_RAM )->Read(m_pRAM, RAMSIZE); archive.BeginReadFile(STATE_REGS )->Read(m_nReg, sizeof(uint64) * 0x80); archive.BeginReadFile(STATE_TRXCTX )->Read(&m_TrxCtx, sizeof(TRXCONTEXT)); { CRegisterStateFile registerFile(*archive.BeginReadFile(STATE_PRIVREGS)); m_nPMODE = registerFile.GetRegister64(STATE_PRIVREGS_PMODE); m_nDISPFB1 = registerFile.GetRegister64(STATE_PRIVREGS_DISPFB1); m_nDISPLAY1 = registerFile.GetRegister64(STATE_PRIVREGS_DISPLAY1); m_nDISPFB2 = registerFile.GetRegister64(STATE_PRIVREGS_DISPFB2); m_nDISPLAY2 = registerFile.GetRegister64(STATE_PRIVREGS_DISPLAY2); m_nCSR = registerFile.GetRegister64(STATE_PRIVREGS_CSR); m_nIMR = registerFile.GetRegister64(STATE_PRIVREGS_IMR); m_nCrtIsInterlaced = registerFile.GetRegister32(STATE_PRIVREGS_CRTINTERLACED) != 0; m_nCrtMode = registerFile.GetRegister32(STATE_PRIVREGS_CRTMODE); m_nCrtIsFrameMode = registerFile.GetRegister32(STATE_PRIVREGS_CRTFRAMEMODE) != 0; } UpdateViewport(); } void CGSHandler::SetVBlank() { m_nCSR |= 0x08; // CINTC::AssertLine(CINTC::INTC_LINE_VBLANK_START); } void CGSHandler::ResetVBlank() { m_nCSR &= ~0x08; //Alternate current field m_nCSR ^= 0x2000; // CINTC::AssertLine(CINTC::INTC_LINE_VBLANK_END); } uint32 CGSHandler::ReadPrivRegister(uint32 nAddress) { uint32 nData; switch(nAddress >> 4) { case 0x1200100: //Force CSR to have the H-Blank bit set. m_nCSR |= 0x04; R_REG(nAddress, nData, m_nCSR); break; default: CLog::GetInstance().Print(LOG_NAME, "Read an unhandled priviledged register (0x%0.8X).\r\n", nAddress); nData = 0xCCCCCCCC; break; } return nData; } void CGSHandler::WritePrivRegister(uint32 nAddress, uint32 nData) { switch(nAddress >> 4) { case 0x1200000: W_REG(nAddress, nData, m_nPMODE); if(!(nAddress & 0x4)) { if((m_nPMODE & 0x01) && (m_nPMODE & 0x02)) { CLog::GetInstance().Print(LOG_NAME, "Warning. Both read circuits were enabled. Using RC1 for display.\r\n"); m_nPMODE &= ~0x02; } } break; case 0x1200007: W_REG(nAddress, nData, m_nDISPFB1); if(nAddress & 0x04) { #ifdef _DEBUG DISPFB* dispfb; dispfb = GetDispFb(0); CLog::GetInstance().Print(LOG_NAME, "DISPFB1(FBP: 0x%0.8X, FBW: %i, PSM: %i, DBX: %i, DBY: %i);\r\n", \ dispfb->GetBufPtr(), \ dispfb->GetBufWidth(), \ dispfb->nPSM, \ dispfb->nX, \ dispfb->nY); #endif } break; case 0x1200008: W_REG(nAddress, nData, m_nDISPLAY1); if(nAddress & 0x04) { UpdateViewport(); } break; case 0x1200009: W_REG(nAddress, nData, m_nDISPFB2); if(nAddress & 0x04) { #ifdef _DEBUG DISPFB* dispfb; dispfb = GetDispFb(1); CLog::GetInstance().Print(LOG_NAME, "DISPFB2(FBP: 0x%0.8X, FBW: %i, PSM: %i, DBX: %i, DBY: %i);\r\n", \ dispfb->GetBufPtr(), \ dispfb->GetBufWidth(), \ dispfb->nPSM, \ dispfb->nX, \ dispfb->nY); #endif //Speed hack for Atelier Iris Flip(); } break; case 0x120000A: W_REG(nAddress, nData, m_nDISPLAY2); if(nAddress & 0x04) { UpdateViewport(); } break; case 0x1200100: W_REG(nAddress, nData, m_nCSR); if(!(nAddress & 0x04)) { SetVBlank(); //Flip(); if(nData & 0x08) { ResetVBlank(); } } break; case 0x1200101: W_REG(nAddress, nData, m_nIMR); break; default: CLog::GetInstance().Print(LOG_NAME, "Wrote to an unhandled priviledged register (0x%0.8X, 0x%0.8X).\r\n", nAddress, nData); break; } } void CGSHandler::Initialize() { m_mailBox.SendCall(bind(&CGSHandler::InitializeImpl, this)); } void CGSHandler::Release() { m_mailBox.SendCall(bind(&CGSHandler::ReleaseImpl, this), true); } void CGSHandler::Flip() { OnNewFrame(); if(!m_enabled) return; while(m_mailBox.IsPending()) { //Flush all commands boost::thread::yield(); } m_mailBox.SendCall(bind(&CGSHandler::FlipImpl, this)); #ifdef _DEBUG CLog::GetInstance().Print(LOG_NAME, "Frame Done.\r\n---------------------------------------------------------------------------------\r\n"); #endif } void CGSHandler::ForcedFlip() { } void CGSHandler::WriteRegister(uint8 registerId, uint64 value) { m_mailBox.SendCall(bind(&CGSHandler::WriteRegisterImpl, this, registerId, value)); } void CGSHandler::FeedImageData(void* data, uint32 length) { uint8* buffer = new uint8[length]; memcpy(buffer, data, length); m_mailBox.SendCall(bind(&CGSHandler::FeedImageDataImpl, this, buffer, length)); } void CGSHandler::WriteRegisterMassively(const RegisterWrite* writeList, unsigned int count) { m_mailBox.SendCall(bind(&CGSHandler::WriteRegisterMassivelyImpl, this, writeList, count)); } void CGSHandler::UpdateViewport() { m_mailBox.SendCall(bind(&CGSHandler::UpdateViewportImpl, this)); } void CGSHandler::WriteRegisterImpl(uint8 nRegister, uint64 nData) { m_nReg[nRegister] = nData; switch(nRegister) { case GS_REG_TRXDIR: BITBLTBUF* pBuf; TRXREG* pReg; unsigned int nPixelSize; pBuf = GetBitBltBuf(); pReg = GetTrxReg(); //We need to figure out the pixel size of the source stream switch(pBuf->nDstPsm) { case PSMCT32: nPixelSize = 32; break; case PSMCT24: nPixelSize = 24; break; case PSMCT16: nPixelSize = 16; break; case PSMT8: case PSMT8H: nPixelSize = 8; break; case PSMT4: case PSMT4HH: case PSMT4HL: nPixelSize = 4; break; default: assert(0); break; } m_TrxCtx.nSize = (pReg->nRRW * pReg->nRRH * nPixelSize) / 8; m_TrxCtx.nRRX = 0; m_TrxCtx.nRRY = 0; m_TrxCtx.nDirty = false; break; } #ifdef _DEBUG DisassembleWrite(nRegister, nData); #endif } void CGSHandler::FeedImageDataImpl(void* pData, uint32 nLength) { boost::scoped_array dataPtr(reinterpret_cast(pData)); if(m_TrxCtx.nSize == 0) { #ifdef _DEBUG CLog::GetInstance().Print(LOG_NAME, "Warning. Received image data when no transfer was expected.\r\n"); #endif return; } if(m_TrxCtx.nSize < nLength) { nLength = m_TrxCtx.nSize; //assert(0); //return; } BITBLTBUF* pBuf(GetBitBltBuf()); if(pBuf->nDstPsm == 1) return; m_TrxCtx.nDirty |= ((this)->*(m_pTransferHandler[pBuf->nDstPsm]))(pData, nLength); m_TrxCtx.nSize -= nLength; if(m_TrxCtx.nSize == 0) { if(m_TrxCtx.nDirty) { BITBLTBUF* pBuf = GetBitBltBuf(); TRXREG* pReg = GetTrxReg(); uint32 nSize = (pBuf->GetDstWidth() * pReg->nRRH * GetPsmPixelSize(pBuf->nDstPsm)) / 8; ProcessImageTransfer(pBuf->GetDstPtr(), nSize); #ifdef _DEBUG CLog::GetInstance().Print(LOG_NAME, "Dirty image transfer at 0x%0.8X.\r\n", pBuf->GetDstPtr()); #endif } } } void CGSHandler::WriteRegisterMassivelyImpl(const RegisterWrite* writeList, unsigned int count) { const RegisterWrite* writeIterator = writeList; for(unsigned int i = 0; i < count; i++) { WriteRegisterImpl(writeIterator->first, writeIterator->second); writeIterator++; } delete [] writeList; } void CGSHandler::FetchImagePSMCT16(uint16* pDst, uint32 nBufPos, uint32 nBufWidth, uint32 nWidth, uint32 nHeight) { CPixelIndexorPSMCT16 Indexor(m_pRAM, nBufPos, nBufWidth); for(unsigned int j = 0; j < nHeight; j++) { for(unsigned int i = 0; i < nWidth; i++) { pDst[i] = Indexor.GetPixel(i, j); } pDst += (nWidth); } } void CGSHandler::FetchImagePSMCT16S(uint16* pDst, uint32 nBufPos, uint32 nBufWidth, uint32 nWidth, uint32 nHeight) { CPixelIndexorPSMCT16S Indexor(m_pRAM, nBufPos, nBufWidth); for(unsigned int j = 0; j < nHeight; j++) { for(unsigned int i = 0; i < nWidth; i++) { pDst[i] = Indexor.GetPixel(i, j); } pDst += (nWidth); } } void CGSHandler::FetchImagePSMCT32(uint32* pDst, uint32 nBufPos, uint32 nBufWidth, uint32 nWidth, uint32 nHeight) { CPixelIndexorPSMCT32 Indexor(m_pRAM, nBufPos, nBufWidth); for(unsigned int j = 0; j < nHeight; j++) { for(unsigned int i = 0; i < nWidth; i++) { pDst[i] = Indexor.GetPixel(i, j); } pDst += (nWidth); } } bool CGSHandler::TrxHandlerInvalid(void* pData, uint32 nLength) { assert(0); return false; } template bool CGSHandler::TrxHandlerCopy(void* pData, uint32 nLength) { typename Storage::Unit* pSrc; uint32 nX, nY; TRXPOS* pTrxPos; TRXREG* pTrxReg; BITBLTBUF* pTrxBuf; bool nDirty = false; nLength /= sizeof(typename Storage::Unit); pTrxPos = GetTrxPos(); pTrxReg = GetTrxReg(); pTrxBuf = GetBitBltBuf(); CPixelIndexor Indexor(m_pRAM, pTrxBuf->GetDstPtr(), pTrxBuf->nDstWidth); pSrc = (typename Storage::Unit*)pData; for(unsigned int i = 0; i < nLength; i++) { typename Storage::Unit* pPixel; nX = (m_TrxCtx.nRRX + pTrxPos->nDSAX) % 2048; nY = (m_TrxCtx.nRRY + pTrxPos->nDSAY) % 2048; pPixel = Indexor.GetPixelAddress(nX, nY); if((*pPixel) != pSrc[i]) { (*pPixel) = pSrc[i]; nDirty = true; } m_TrxCtx.nRRX++; if(m_TrxCtx.nRRX == pTrxReg->nRRW) { m_TrxCtx.nRRX = 0; m_TrxCtx.nRRY++; } } return nDirty; } bool CGSHandler::TrxHandlerPSMCT24(void* pData, uint32 nLength) { uint8* pSrc; uint32* pDstPixel; uint32 nSrcPixel; uint32 nX, nY; TRXPOS* pTrxPos; TRXREG* pTrxReg; BITBLTBUF* pTrxBuf; pTrxPos = GetTrxPos(); pTrxReg = GetTrxReg(); pTrxBuf = GetBitBltBuf(); CPixelIndexorPSMCT32 Indexor(m_pRAM, pTrxBuf->GetDstPtr(), pTrxBuf->nDstWidth); pSrc = (uint8*)pData; for(unsigned int i = 0; i < nLength; i += 3) { nX = (m_TrxCtx.nRRX + pTrxPos->nDSAX) % 2048; nY = (m_TrxCtx.nRRY + pTrxPos->nDSAY) % 2048; pDstPixel = Indexor.GetPixelAddress(nX, nY); nSrcPixel = (*(uint32*)&pSrc[i]) & 0x00FFFFFF; (*pDstPixel) &= 0xFF000000; (*pDstPixel) |= nSrcPixel; m_TrxCtx.nRRX++; if(m_TrxCtx.nRRX == pTrxReg->nRRW) { m_TrxCtx.nRRX = 0; m_TrxCtx.nRRY++; } } return true; } bool CGSHandler::TrxHandlerPSMT4(void* pData, uint32 nLength) { //Gotta rewrite this bool dirty = false; TRXPOS* pTrxPos = GetTrxPos(); TRXREG* pTrxReg = GetTrxReg(); BITBLTBUF* pTrxBuf = GetBitBltBuf(); CPixelIndexorPSMT4 Indexor(m_pRAM, pTrxBuf->GetDstPtr(), pTrxBuf->nDstWidth); // assert(0); uint8* pSrc = (uint8*)pData; for(unsigned int i = 0; i < nLength; i++) { uint8 nPixel[2]; nPixel[0] = (pSrc[i] >> 0) & 0x0F; nPixel[1] = (pSrc[i] >> 4) & 0x0F; for(unsigned int j = 0; j < 2; j++) { uint32 nX = (m_TrxCtx.nRRX + pTrxPos->nDSAX) % 2048; uint32 nY = (m_TrxCtx.nRRY + pTrxPos->nDSAY) % 2048; uint8 currentPixel = Indexor.GetPixel(nX, nY); if(currentPixel != nPixel[j]) { Indexor.SetPixel(nX, nY, nPixel[j]); dirty = true; } m_TrxCtx.nRRX++; if(m_TrxCtx.nRRX == pTrxReg->nRRW) { m_TrxCtx.nRRX = 0; m_TrxCtx.nRRY++; } } } return dirty; } template bool CGSHandler::TrxHandlerPSMT4H(void* pData, uint32 nLength) { uint8* pSrc; uint8 nSrcPixel; uint32 nX, nY; uint32* pDstPixel; TRXPOS* pTrxPos; TRXREG* pTrxReg; BITBLTBUF* pTrxBuf; pTrxPos = GetTrxPos(); pTrxReg = GetTrxReg(); pTrxBuf = GetBitBltBuf(); CPixelIndexorPSMCT32 Indexor(m_pRAM, pTrxBuf->GetDstPtr(), pTrxBuf->nDstWidth); pSrc = (uint8*)pData; for(unsigned int i = 0; i < nLength; i++) { //Pixel 1 nX = (m_TrxCtx.nRRX + pTrxPos->nDSAX) % 2048; nY = (m_TrxCtx.nRRY + pTrxPos->nDSAY) % 2048; nSrcPixel = pSrc[i] & 0x0F; pDstPixel = Indexor.GetPixelAddress(nX, nY); (*pDstPixel) &= ~nMask; (*pDstPixel) |= (nSrcPixel << nShift); m_TrxCtx.nRRX++; if(m_TrxCtx.nRRX == pTrxReg->nRRW) { m_TrxCtx.nRRX = 0; m_TrxCtx.nRRY++; } //Pixel 2 nX = (m_TrxCtx.nRRX + pTrxPos->nDSAX) % 2048; nY = (m_TrxCtx.nRRY + pTrxPos->nDSAY) % 2048; nSrcPixel = (pSrc[i] & 0xF0); pDstPixel = Indexor.GetPixelAddress(nX, nY); (*pDstPixel) &= ~nMask; (*pDstPixel) |= (nSrcPixel << (nShift - 4)); m_TrxCtx.nRRX++; if(m_TrxCtx.nRRX == pTrxReg->nRRW) { m_TrxCtx.nRRX = 0; m_TrxCtx.nRRY++; } } return true; } bool CGSHandler::TrxHandlerPSMT8H(void* pData, uint32 nLength) { uint8* pSrc; uint8 nSrcPixel; uint32 nX, nY; uint32* pDstPixel; TRXPOS* pTrxPos; TRXREG* pTrxReg; BITBLTBUF* pTrxBuf; pTrxPos = GetTrxPos(); pTrxReg = GetTrxReg(); pTrxBuf = GetBitBltBuf(); CPixelIndexorPSMCT32 Indexor(m_pRAM, pTrxBuf->GetDstPtr(), pTrxBuf->nDstWidth); pSrc = (uint8*)pData; for(unsigned int i = 0; i < nLength; i++) { nX = (m_TrxCtx.nRRX + pTrxPos->nDSAX) % 2048; nY = (m_TrxCtx.nRRY + pTrxPos->nDSAY) % 2048; nSrcPixel = pSrc[i]; pDstPixel = Indexor.GetPixelAddress(nX, nY); (*pDstPixel) &= ~0xFF000000; (*pDstPixel) |= (nSrcPixel << 24); m_TrxCtx.nRRX++; if(m_TrxCtx.nRRX == pTrxReg->nRRW) { m_TrxCtx.nRRX = 0; m_TrxCtx.nRRY++; } } return true; } void CGSHandler::SetCrt(bool nIsInterlaced, unsigned int nMode, bool nIsFrameMode) { m_nCrtMode = nMode; m_nCrtIsInterlaced = nIsInterlaced; m_nCrtIsFrameMode = nIsFrameMode; UpdateViewport(); } CGSHandler::DISPFB* CGSHandler::GetDispFb(unsigned int nUnit) { switch(nUnit) { case 0: return (DISPFB*)&m_nDISPFB1; break; case 1: return (DISPFB*)&m_nDISPFB2; break; default: assert(0); return NULL; break; } } CGSHandler::TEXCLUT* CGSHandler::GetTexClut() { return (TEXCLUT*)&m_nReg[GS_REG_TEXCLUT]; } CGSHandler::FOGCOL* CGSHandler::GetFogCol() { return (FOGCOL*)&m_nReg[GS_REG_FOGCOL]; } CGSHandler::FRAME* CGSHandler::GetFrame(unsigned int nUnit) { assert(nUnit < 2); return (FRAME*)&m_nReg[GS_REG_FRAME_1 + nUnit]; } CGSHandler::TRXREG* CGSHandler::GetTrxReg() { return (TRXREG*)&m_nReg[GS_REG_TRXREG]; } CGSHandler::TRXPOS* CGSHandler::GetTrxPos() { return (TRXPOS*)&m_nReg[GS_REG_TRXPOS]; } CGSHandler::BITBLTBUF* CGSHandler::GetBitBltBuf() { return (BITBLTBUF*)&m_nReg[GS_REG_BITBLTBUF]; } unsigned int CGSHandler::GetCrtWidth() { switch(m_nCrtMode) { case 0x02: case 0x03: case 0x1C: return 640; break; default: assert(0); return 640; break; } } unsigned int CGSHandler::GetCrtHeight() { switch(m_nCrtMode) { case 0x02: return 448; break; case 0x03: return 512; break; case 0x1C: return 480; break; default: assert(0); return 448; break; } } bool CGSHandler::GetCrtIsInterlaced() { return m_nCrtIsInterlaced; } bool CGSHandler::GetCrtIsFrameMode() { return m_nCrtIsFrameMode; } unsigned int CGSHandler::GetPsmPixelSize(unsigned int nPSM) { switch(nPSM) { case PSMCT32: case PSMT4HH: case PSMT4HL: case PSMT8H: return 32; break; case PSMCT24: return 24; break; case PSMCT16: case PSMCT16S: return 16; break; case PSMT8: return 8; break; case PSMT4: return 4; break; default: assert(0); return 0; break; } } void CGSHandler::DisassembleWrite(uint8 nRegister, uint64 nData) { GSPRIM pr; double nX, nY, nZ; double nU, nV; double nS, nT; //Filtering //if(!((nRegister == GS_REG_FRAME_1) || (nRegister == GS_REG_FRAME_2))) return; //if(!((nRegister == GS_REG_TEST_1) || (nRegister == GS_REG_TEST_2))) return; switch(nRegister) { case GS_REG_PRIM: DECODE_PRIM(nData, pr); CLog::GetInstance().Print(LOG_NAME, "PRIM(PRI: %i, IIP: %i, TME: %i, FGE: %i, ABE: %i, AA1: %i, FST: %i, CTXT: %i, FIX: %i);\r\n", \ pr.nType, \ pr.nShading, \ pr.nTexture, \ pr.nFog, \ pr.nAlpha, \ pr.nAntiAliasing, \ pr.nUseUV, \ pr.nContext, \ pr.nUseFloat); break; case GS_REG_RGBAQ: GSRGBAQ rgbaq; DECODE_RGBAQ(nData, rgbaq); CLog::GetInstance().Print(LOG_NAME, "RGBAQ(R: 0x%0.2X, G: 0x%0.2X, B: 0x%0.2X, A: 0x%0.2X, Q: %f);\r\n", \ rgbaq.nR, rgbaq.nG, rgbaq.nB, rgbaq.nA, rgbaq.nQ); break; case GS_REG_ST: DECODE_ST(nData, nS, nT); CLog::GetInstance().Print(LOG_NAME, "ST(S: %f, T: %f);\r\n", \ nS, \ nT); break; case GS_REG_UV: DECODE_UV(nData, nU, nV); CLog::GetInstance().Print(LOG_NAME, "UV(U: %f, V: %f);\r\n", \ nU, \ nV); break; case GS_REG_XYZ2: DECODE_XYZ2(nData, nX, nY, nZ); CLog::GetInstance().Print(LOG_NAME, "XYZ2(%f, %f, %f);\r\n", \ nX, \ nY, \ nZ); break; case GS_REG_XYZF2: case GS_REG_XYZF3: { XYZF xyzf; xyzf = *reinterpret_cast(&nData); CLog::GetInstance().Print(LOG_NAME, "%s(%f, %f, %i, %i);\r\n", \ (nRegister == GS_REG_XYZF2) ? "XYZF2" : "XYZF3", xyzf.GetX(), xyzf.GetY(), xyzf.nZ, xyzf.nF); } break; case GS_REG_XYZ3: DECODE_XYZ2(nData, nX, nY, nZ); CLog::GetInstance().Print(LOG_NAME, "XYZ3(%f, %f, %f);\r\n", \ nX, \ nY, \ nZ); break; case GS_REG_TEX0_1: case GS_REG_TEX0_2: { GSTEX0 tex; DECODE_TEX0(nData, tex); CLog::GetInstance().Print(LOG_NAME, "TEX0_%i(TBP: 0x%0.8X, TBW: %i, PSM: %i, TW: %i, TH: %i, TCC: %i, TFX: %i, CBP: 0x%0.8X, CPSM: %i, CSM: %i, CSA: %i, CLD: %i);\r\n", \ nRegister == GS_REG_TEX0_1 ? 1 : 2, \ tex.GetBufPtr(), \ tex.GetBufWidth(), \ tex.nPsm, \ tex.GetWidth(), \ tex.GetHeight(), \ tex.nColorComp, \ tex.nFunction, \ tex.GetCLUTPtr(), \ tex.nCPSM, \ tex.nCSM, \ tex.nCSA, \ tex.nCLD); } break; case GS_REG_CLAMP_1: case GS_REG_CLAMP_2: { CLAMP clamp; clamp = *(CLAMP*)&nData; CLog::GetInstance().Print(LOG_NAME, "CLAMP_%i(WMS: %i, WMT: %i, MINU: %i, MAXU: %i, MINV: %i, MAXV: %i);\r\n", \ nRegister == GS_REG_CLAMP_1 ? 1 : 2, \ clamp.nWMS, \ clamp.nWMT, \ clamp.GetMinU(), \ clamp.GetMaxU(), \ clamp.GetMinV(), \ clamp.GetMaxV()); } break; case GS_REG_TEX1_1: case GS_REG_TEX1_2: { GSTEX1 tex1; DECODE_TEX1(nData, tex1); CLog::GetInstance().Print(LOG_NAME, "TEX1_%i(LCM: %i, MXL: %i, MMAG: %i, MMIN: %i, MTBA: %i, L: %i, K: %i);\r\n", \ nRegister == GS_REG_TEX1_1 ? 1 : 2, \ tex1.nLODMethod, \ tex1.nMaxMip, \ tex1.nMagFilter, \ tex1.nMinFilter, \ tex1.nMipBaseAddr, \ tex1.nLODL, \ tex1.nLODK); } break; case GS_REG_TEX2_1: case GS_REG_TEX2_2: TEX2 tex2; tex2 = *(TEX2*)&nData; CLog::GetInstance().Print(LOG_NAME, "TEX2_%i(PSM: %i, CBP: 0x%0.8X, CPSM: %i, CSM: %i, CSA: %i, CLD: %i);\r\n", \ nRegister == GS_REG_TEX2_1 ? 1 : 2, \ tex2.nPsm, \ tex2.GetCLUTPtr(), \ tex2.nCPSM, \ tex2.nCSM, \ tex2.nCSA, \ tex2.nCLD); break; case GS_REG_XYOFFSET_1: case GS_REG_XYOFFSET_2: CLog::GetInstance().Print(LOG_NAME, "XYOFFSET_%i(%i, %i);\r\n", \ nRegister == GS_REG_XYOFFSET_1 ? 1 : 2, \ (uint32)((nData >> 0) & 0xFFFFFFFF), \ (uint32)((nData >> 32) & 0xFFFFFFFF)); break; case GS_REG_PRMODECONT: CLog::GetInstance().Print(LOG_NAME, "PRMODECONT(AC = %i);\r\n", \ nData & 1); break; case GS_REG_PRMODE: GSPRMODE prm; DECODE_PRMODE(nData, prm); CLog::GetInstance().Print(LOG_NAME, "PRMODE(IIP: %i, TME: %i, FGE: %i, ABE: %i, AA1: %i, FST: %i, CTXT: %i, FIX: %i);\r\n", \ prm.nShading, \ prm.nTexture, \ prm.nFog, \ prm.nAlpha, \ prm.nAntiAliasing, \ prm.nUseUV, \ prm.nContext, \ prm.nUseFloat); break; case GS_REG_TEXCLUT: TEXCLUT clut; clut = *(TEXCLUT*)&nData; CLog::GetInstance().Print(LOG_NAME, "TEXCLUT(CBW: %i, COU: %i, COV: %i);\r\n", \ clut.nCBW, clut.nCOU, clut.nCOV); break; case GS_REG_FOGCOL: FOGCOL fogcol; fogcol = *(FOGCOL*)&nData; CLog::GetInstance().Print(LOG_NAME, "FOGCOL(R: 0x%0.2X, G: 0x%0.2X, B: 0x%0.2X);\r\n", \ fogcol.nFCR, fogcol.nFCG, fogcol.nFCB); break; case GS_REG_TEXA: GSTEXA TexA; DECODE_TEXA(nData, TexA); CLog::GetInstance().Print(LOG_NAME, "TEXA(TA0: 0x%0.2X, AEM: %i, TA1: 0x%0.2X);\r\n", \ TexA.nTA0, TexA.nAEM, TexA.nTA1); break; case GS_REG_TEXFLUSH: CLog::GetInstance().Print(LOG_NAME, "TEXFLUSH();\r\n"); break; case GS_REG_ALPHA_1: case GS_REG_ALPHA_2: GSALPHA alpha; DECODE_ALPHA(nData, alpha); CLog::GetInstance().Print(LOG_NAME, "ALPHA_%i(A: %i, B: %i, C: %i, D: %i, FIX: 0x%0.2X);\r\n", \ nRegister == GS_REG_ALPHA_1 ? 1 : 2, \ alpha.nA, \ alpha.nB, \ alpha.nC, \ alpha.nD, \ alpha.nFix); break; case GS_REG_SCISSOR_1: CLog::GetInstance().Print(LOG_NAME, "SCISSOR_1(%i, %i, %i, %i);\r\n", \ (uint32)((nData >> 0) & 0xFFFF), \ (uint32)((nData >> 16) & 0xFFFF), \ (uint32)((nData >> 32) & 0xFFFF), \ (uint32)((nData >> 48) & 0xFFFF)); break; case GS_REG_TEST_1: case GS_REG_TEST_2: TEST tst; tst <<= nData; CLog::GetInstance().Print(LOG_NAME, "TEST_%i(ATE: %i, ATST: %i, AREF: 0x%0.2X, AFAIL: %i, DATE: %i, DATM: %i, ZTE: %i, ZTST: %i);\r\n", \ nRegister == GS_REG_TEST_1 ? 1 : 2, \ tst.nAlphaEnabled, \ tst.nAlphaMethod, \ tst.nAlphaRef, \ tst.nAlphaFail, \ tst.nDestAlphaEnabled, \ tst.nDestAlphaMode, \ tst.nDepthEnabled, \ tst.nDepthMethod); break; case GS_REG_FRAME_1: case GS_REG_FRAME_2: FRAME fr; fr = *(FRAME*)&nData; CLog::GetInstance().Print(LOG_NAME, "FRAME_%i(FBP: 0x%0.8X, FBW: %i, PSM: %i, FBMSK: %i);\r\n", \ nRegister == GS_REG_FRAME_1 ? 1 : 2, \ fr.GetBasePtr(), \ fr.GetWidth(), \ fr.nPsm, \ fr.nMask); break; case GS_REG_ZBUF_1: case GS_REG_ZBUF_2: ZBUF zbuf; zbuf = *(ZBUF*)&nData; CLog::GetInstance().Print(LOG_NAME, "ZBUF_%i(ZBP: 0x%0.8X, PSM: %i, ZMSK: %i);\r\n", \ nRegister == GS_REG_ZBUF_1 ? 1 : 2, \ zbuf.GetBasePtr(), \ zbuf.nPsm, \ zbuf.nMask); break; case GS_REG_BITBLTBUF: BITBLTBUF buf; buf = *(BITBLTBUF*)&nData; CLog::GetInstance().Print(LOG_NAME, "BITBLTBUF(0x%0.8X, %i, %i, 0x%0.8X, %i, %i);\r\n", \ buf.GetSrcPtr(), \ buf.GetSrcWidth(), \ buf.nSrcPsm, \ buf.GetDstPtr(), \ buf.GetDstWidth(), \ buf.nDstPsm); break; case GS_REG_TRXPOS: CLog::GetInstance().Print(LOG_NAME, "TRXPOS(%i, %i, %i, %i, %i);\r\n", \ (uint32)((nData >> 0) & 0xFFFF), \ (uint32)((nData >> 16) & 0xFFFF), \ (uint32)((nData >> 32) & 0xFFFF), \ (uint32)((nData >> 48) & 0xFF), \ (uint32)((nData >> 59) & 0x1)); break; case GS_REG_TRXREG: CLog::GetInstance().Print(LOG_NAME, "TRXREG(%i, %i);\r\n", \ (uint32)((nData >> 0) & 0xFFFFFFFF), (uint32)((nData >> 32) & 0xFFFFFFFF)); break; case GS_REG_TRXDIR: CLog::GetInstance().Print(LOG_NAME, "TRXDIR(%i);\r\n", \ (uint32)((nData >> 0) & 0xFFFFFFFF)); break; default: CLog::GetInstance().Print(LOG_NAME, "Unknown command (0x%X).\r\n", nRegister); break; } } void CGSHandler::ThreadProc() { while(!m_threadDone) { m_mailBox.WaitForCall(100); while(m_mailBox.IsPending()) { m_mailBox.ReceiveCall(); } } }