From 2a24b74c12c6d248409dc93b35edbc373d03b29c Mon Sep 17 00:00:00 2001 From: iCatButler Date: Sun, 15 May 2016 16:26:39 +0100 Subject: Implement vertex caching - Try using Blade_Arma's vertex cache to find untracked vertices - Fix GTE_LOG - Add more logging spew - Update debug mode to track cached vertices --- libpcsxcore/gte.c | 50 +++++---- libpcsxcore/pgxp_gte.c | 41 +++++++- libpcsxcore/pgxp_gte.h | 1 + libpcsxcore/plugins.c | 3 + libpcsxcore/plugins.h | 2 + plugins/peopsxgl/pgxp_gpu.c | 164 ++++++++++++++++++++++++++++-- win32/plugins/peopsxgl/gpuPeopsOpenGL.def | 4 +- 7 files changed, 230 insertions(+), 35 deletions(-) diff --git a/libpcsxcore/gte.c b/libpcsxcore/gte.c index 2938d170..a1f3a35a 100755 --- a/libpcsxcore/gte.c +++ b/libpcsxcore/gte.c @@ -258,6 +258,9 @@ void gteMFC2() { void gteCFC2() { if (!_Rt_) return; psxRegs.GPR.r[_Rt_] = psxRegs.CP2C.p[_Rd_].d; +#ifdef GTE_LOG + GTE_LOG("GTE_CFC2 [%x]<-[%x] %x (%u %u)|", _Rt_, _Rd_, psxRegs.CP2C.p[_Rd_].d); +#endif } void gteMTC2() { @@ -266,6 +269,9 @@ void gteMTC2() { } void gteCTC2() { +#ifdef GTE_LOG + GTE_LOG("GTE_CFC2 [%x]->[%x] %x (%u %u)|", _Rt_, _Rd_, psxRegs.GPR.r[_Rt_]); +#endif CTC2(psxRegs.GPR.r[_Rt_], _Rd_); } @@ -478,7 +484,7 @@ int docop2(int op) { case 0x00: case 0x01: #ifdef GTE_LOG - GTELOG("%08x RTPS", op); + GTE_LOG("%08x RTPS", op); #endif MAC1 = A1(/*int44*/(s64)((s64) TRX << 12) + (R11 * VX0) + (R12 * VY0) + (R13 * VZ0)); @@ -509,7 +515,7 @@ int docop2(int op) { case 0x06: #ifdef GTE_LOG - GTELOG("%08x NCLIP", op); + GTE_LOG("%08x NCLIP", op); #endif if (PGXP_NLCIP_valid()) MAC0 = F(PGXP_NCLIP()); @@ -519,7 +525,7 @@ int docop2(int op) { case 0x0c: #ifdef GTE_LOG - GTELOG("%08x OP", op); + GTE_LOG("%08x OP", op); #endif MAC1 = A1((s64) (R22 * IR3) - (R33 * IR2)); @@ -532,7 +538,7 @@ int docop2(int op) { case 0x10: #ifdef GTE_LOG - GTELOG("%08x DPCS", op); + GTE_LOG("%08x DPCS", op); #endif MAC1 = A1((R << 16) + (IR0 * Lm_B1(A1(((s64) RFC << 12) - (R << 16)), 0))); @@ -551,7 +557,7 @@ int docop2(int op) { case 0x11: #ifdef GTE_LOG - GTELOG("%08x INTPL", op); + GTE_LOG("%08x INTPL", op); #endif MAC1 = A1((IR1 << 12) + (IR0 * Lm_B1(A1(((s64) RFC << 12) - (IR1 << 12)), 0))); @@ -570,7 +576,7 @@ int docop2(int op) { case 0x12: #ifdef GTE_LOG - GTELOG("%08x MVMVA", op); + GTE_LOG("%08x MVMVA", op); #endif mx = GTE_MX(gteop); @@ -601,7 +607,7 @@ int docop2(int op) { case 0x13: #ifdef GTE_LOG - GTELOG("%08x NCDS", op); + GTE_LOG("%08x NCDS", op); #endif MAC1 = A1((s64) (L11 * VX0) + (L12 * VY0) + (L13 * VZ0)); @@ -632,7 +638,7 @@ int docop2(int op) { case 0x14: #ifdef GTE_LOG - GTELOG("%08x CDP", op); + GTE_LOG("%08x CDP", op); #endif MAC1 = A1(/*int44*/(s64)((s64) RBK << 12) + (LR1 * IR1) + (LR2 * IR2) + (LR3 * IR3)); @@ -657,7 +663,7 @@ int docop2(int op) { case 0x16: #ifdef GTE_LOG - GTELOG("%08x NCDT", op); + GTE_LOG("%08x NCDT", op); #endif for(v = 0; v < 3; v++) { @@ -690,7 +696,7 @@ int docop2(int op) { case 0x1b: #ifdef GTE_LOG - GTELOG("%08x NCCS", op); + GTE_LOG("%08x NCCS", op); #endif MAC1 = A1((s64) (L11 * VX0) + (L12 * VY0) + (L13 * VZ0)); @@ -721,7 +727,7 @@ int docop2(int op) { case 0x1c: #ifdef GTE_LOG - GTELOG("%08x CC", op); + GTE_LOG("%08x CC", op); #endif MAC1 = A1(/*int44*/(s64)(((s64) RBK) << 12) + (LR1 * IR1) + (LR2 * IR2) + (LR3 * IR3)); @@ -746,7 +752,7 @@ int docop2(int op) { case 0x1e: #ifdef GTE_LOG - GTELOG("%08x NCS", op); + GTE_LOG("%08x NCS", op); #endif MAC1 = A1((s64) (L11 * VX0) + (L12 * VY0) + (L13 * VZ0)); @@ -771,7 +777,7 @@ int docop2(int op) { case 0x20: #ifdef GTE_LOG - GTELOG("%08x NCT", op); + GTE_LOG("%08x NCT", op); #endif for(v = 0; v < 3; v++) { @@ -798,7 +804,7 @@ int docop2(int op) { case 0x28: #ifdef GTE_LOG - GTELOG("%08x SQR", op); + GTE_LOG("%08x SQR", op); #endif MAC1 = A1(IR1 * IR1); @@ -811,7 +817,7 @@ int docop2(int op) { case 0x29: #ifdef GTE_LOG - GTELOG("%08x DPCL", op); + GTE_LOG("%08x DPCL", op); #endif MAC1 = A1(((R << 4) * IR1) + (IR0 * Lm_B1(A1(((s64) RFC << 12) - ((R << 4) * IR1)), 0))); @@ -830,7 +836,7 @@ int docop2(int op) { case 0x2a: #ifdef GTE_LOG - GTELOG("%08x DPCT", op); + GTE_LOG("%08x DPCT", op); #endif for(v = 0; v < 3; v++) { @@ -851,7 +857,7 @@ int docop2(int op) { case 0x2d: #ifdef GTE_LOG - GTELOG("%08x AVSZ3", op); + GTE_LOG("%08x AVSZ3", op); #endif MAC0 = F((s64) (ZSF3 * SZ1) + (ZSF3 * SZ2) + (ZSF3 * SZ3)); @@ -860,7 +866,7 @@ int docop2(int op) { case 0x2e: #ifdef GTE_LOG - GTELOG("%08x AVSZ4", op); + GTE_LOG("%08x AVSZ4", op); #endif MAC0 = F((s64) (ZSF4 * SZ0) + (ZSF4 * SZ1) + (ZSF4 * SZ2) + (ZSF4 * SZ3)); @@ -869,7 +875,7 @@ int docop2(int op) { case 0x30: #ifdef GTE_LOG - GTELOG("%08x RTPT", op); + GTE_LOG("%08x RTPT", op); #endif for(v = 0; v < 3; v++) { @@ -909,7 +915,7 @@ int docop2(int op) { case 0x3d: #ifdef GTE_LOG - GTELOG("%08x GPF", op); + GTE_LOG("%08x GPF", op); #endif MAC1 = A1(IR0 * IR1); @@ -928,7 +934,7 @@ int docop2(int op) { case 0x3e: #ifdef GTE_LOG - GTELOG("%08x GPL", op); + GTE_LOG("%08x GPL", op); #endif MAC1 = A1(gte_shift(MAC1, -m_sf) + (IR0 * IR1)); @@ -947,7 +953,7 @@ int docop2(int op) { case 0x3f: #ifdef GTE_LOG - GTELOG("%08x NCCT", op); + GTE_LOG("%08x NCCT", op); #endif for(v = 0; v < 3; v++) { diff --git a/libpcsxcore/pgxp_gte.c b/libpcsxcore/pgxp_gte.c index 3844e6be..4334c38d 100644 --- a/libpcsxcore/pgxp_gte.c +++ b/libpcsxcore/pgxp_gte.c @@ -60,6 +60,8 @@ const u32 ScratchOffset = 2048 * 1024 / 4; const u32 RegisterOffset = 2 * 2048 * 1024 / 4; const u32 InvalidAddress = 3 * 2048 * 1024 / 4; +unsigned int pgxp_debug = 0; + //precise_value Scratch[2048 * 1024 / 4]; // mirror 2MB in 32-bit words //precise_value Registers[2048 * 1024 / 4]; // mirror 2MB in 32-bit words @@ -220,6 +222,7 @@ precise_value PGXP_validateXY(precise_value *high, u32 low) // high->x = temp.x; // high->y = temp.y; // high->valid = 1; + // high->value = low; //} return *high; @@ -243,10 +246,12 @@ precise_value PGXP_copyXY(u32 low) ret.valid = 0; temp.word = low; + ret.z= 1; ret.x = temp.x; ret.y = temp.y; ret.count = 0; ret.valid = 1; + ret.value = low; return ret; } @@ -254,6 +259,7 @@ precise_value PGXP_copyXY(u32 low) void PGXP_pushSXYZ2f(float _x, float _y, float _z, unsigned int _v) { static unsigned int uCount = 0; + low_value temp; // push values down FIFO SXY0 = SXY1; SXY1 = SXY2; @@ -265,6 +271,10 @@ void PGXP_pushSXYZ2f(float _x, float _y, float _z, unsigned int _v) SXY2.valid = 1; SXY2.count = uCount++; + // cache value in GPU plugin + temp.word = _v; + GPU_pgxpCacheVertex(temp.x, temp.y, &SXY2); + #ifdef GTE_LOG GTE_LOG("PGPR_PUSH (%f, %f) %u %u|", SXY2.x, SXY2.y, SXY2.valid, SXY2.count); #endif @@ -483,7 +493,7 @@ void PGPR_L32(u32 addr, u32 code, u32 value) case 35: //LW CPU_reg[reg] = PGXP_validateXY(ReadMem(addr), value); break; - case 37: //LWR + case 38: //LWR CPU_reg[reg] = PGXP_validateXY(ReadMem(addr), value); break; case 50: //LWC2 (GTE vertex reads) @@ -603,6 +613,10 @@ void PGXP_psxMemWrite32Trace(u32 mem, u32 value, u32 code) u16 PGXP_psxMemRead16Trace(u32 mem, u32 code) { u16 value = psxMemRead16(mem); +#ifdef GTE_LOG + u32 reg = ((code >> 16) & 0x1F); // The rt part of the instruction register + GTE_LOG("PGPR_L16 %x %x[%x %x]|", mem, value, code, reg); +#endif PGPR_InvalidLoad(mem, code, 116); return value; } @@ -610,12 +624,20 @@ u16 PGXP_psxMemRead16Trace(u32 mem, u32 code) void PGXP_psxMemWrite16Trace(u32 mem, u16 value, u32 code) { PGPR_InvalidStore(mem, code, 216); +#ifdef GTE_LOG + u32 reg = ((code >> 16) & 0x1F); // The rt part of the instruction register + GTE_LOG("PGPR_S16 %x %x[%x %x]|", mem, value, code, reg); +#endif psxMemWrite16(mem, value); } u8 PGXP_psxMemRead8Trace(u32 mem, u32 code) { u8 value = psxMemRead8(mem); +#ifdef GTE_LOG + u32 reg = ((code >> 16) & 0x1F); // The rt part of the instruction register + GTE_LOG("PGPR_L8 %x %x[%x %x]|", mem, value, code, reg); +#endif PGPR_InvalidLoad(mem, code, 18); return value; } @@ -623,5 +645,22 @@ u8 PGXP_psxMemRead8Trace(u32 mem, u32 code) void PGXP_psxMemWrite8Trace(u32 mem, u8 value, u32 code) { PGPR_InvalidStore(mem, code, 28); +#ifdef GTE_LOG + u32 reg = ((code >> 16) & 0x1F); // The rt part of the instruction register + GTE_LOG("PGPR_S8 %x %x[%x %x]|", mem, value, code, reg); +#endif psxMemWrite8(mem, value); +} + +void PGXP_psxTrace(u32 code, u32 rtv) +{ +#ifdef GTE_LOG +//u32 reg = ((code >> 16) & 0x1F); // The rt part of the instruction register + u32 op = ((code >> 26)); + u32 func = ((code ) & 0x3F); // The funct part of the instruction register + u32 rd = ((code >> 11) & 0x1F); // The rd part of the instruction register + u32 rt = ((code >> 16) & 0x1F); // The rt part of the instruction register + u32 rs = ((code >> 21) & 0x1F); // The rs part of the instruction register + GTE_LOG("PGPR_Trace op:%u func:%u [rt:%x (%x) rs:%x rd:%x] %x|", op, func, rt, rtv, rs, rd, code); +#endif } \ No newline at end of file diff --git a/libpcsxcore/pgxp_gte.h b/libpcsxcore/pgxp_gte.h index d10021c0..3a14c5b8 100644 --- a/libpcsxcore/pgxp_gte.h +++ b/libpcsxcore/pgxp_gte.h @@ -65,4 +65,5 @@ void PGXP_psxMemWrite16Trace(u32 mem, u16 value, u32 code); u8 PGXP_psxMemRead8Trace(u32 mem, u32 code); void PGXP_psxMemWrite8Trace(u32 mem, u8 value, u32 code); +void PGXP_psxTrace(u32 code, u32 rtv); #endif /* _PGXP_GTE_H_ */ diff --git a/libpcsxcore/plugins.c b/libpcsxcore/plugins.c index b42c5d1d..567630c8 100755 --- a/libpcsxcore/plugins.c +++ b/libpcsxcore/plugins.c @@ -57,6 +57,7 @@ GPUcursor GPU_cursor; GPUaddVertex GPU_addVertex; GPUsetSpeed GPU_setSpeed; GPUpgxpMemory GPU_pgxpMemory; +GPUpgxpCacheVertex GPU_pgxpCacheVertex; CDRinit CDR_init; CDRshutdown CDR_shutdown; @@ -220,6 +221,7 @@ void CALLBACK GPU__cursor(int player, int x, int y) {} void CALLBACK GPU__addVertex(short sx,short sy,s64 fx,s64 fy,s64 fz) {} void CALLBACK GPU__setSpeed(float newSpeed) {} void CALLBACK GPU__pgxpMemory(unsigned int addr, unsigned char* pVRAM) {} +void CALLBACK GPU__pgxpCacheVertex(short sx, short sy, const unsigned char* _pVertex) {} #define LoadGpuSym1(dest, name) \ LoadSym(GPU_##dest, GPU##dest, name, TRUE); @@ -268,6 +270,7 @@ static int LoadGPUplugin(const char *GPUdll) { LoadGpuSym0(addVertex, "GPUaddVertex"); LoadGpuSym0(setSpeed, "GPUsetSpeed"); LoadGpuSym0(pgxpMemory, "GPUpgxpMemory"); + LoadGpuSym0(pgxpCacheVertex, "GPUpgxpCacheVertex"); LoadGpuSym0(configure, "GPUconfigure"); LoadGpuSym0(test, "GPUtest"); LoadGpuSym0(about, "GPUabout"); diff --git a/libpcsxcore/plugins.h b/libpcsxcore/plugins.h index 07da50e3..b7ba4cd3 100755 --- a/libpcsxcore/plugins.h +++ b/libpcsxcore/plugins.h @@ -99,6 +99,7 @@ typedef void (CALLBACK* GPUcursor)(int, int, int); typedef void (CALLBACK* GPUaddVertex)(short,short,s64,s64,s64); typedef void (CALLBACK* GPUsetSpeed)(float); // 1.0 = natural speed typedef void (CALLBACK* GPUpgxpMemory)(unsigned int, unsigned char*); +typedef void (CALLBACK* GPUpgxpCacheVertex)(short sx, short sy, const unsigned char* _pVertex); // GPU function pointers extern GPUupdateLace GPU_updateLace; @@ -131,6 +132,7 @@ extern GPUcursor GPU_cursor; extern GPUaddVertex GPU_addVertex; extern GPUsetSpeed GPU_setSpeed; extern GPUpgxpMemory GPU_pgxpMemory; +extern GPUpgxpCacheVertex GPU_pgxpCacheVertex; // CD-ROM Functions typedef long (CALLBACK* CDRinit)(void); diff --git a/plugins/peopsxgl/pgxp_gpu.c b/plugins/peopsxgl/pgxp_gpu.c index ece50795..5cb5d5b3 100644 --- a/plugins/peopsxgl/pgxp_gpu.c +++ b/plugins/peopsxgl/pgxp_gpu.c @@ -41,6 +41,113 @@ typedef struct unsigned int value; } PGXP_vertex; +///////////////////////////////// +//// Blade_Arma's Vertex Cache (CatBlade?) +///////////////////////////////// +const unsigned int mode_init = 0; +const unsigned int mode_write = 1; +const unsigned int mode_read = 2; + +PGXP_vertex vertexCache[0x800 * 2][0x800 * 2]; + +unsigned int baseID = 0; +unsigned int lastID = 0; +unsigned int cacheMode = 0; + +unsigned int IsSessionID(unsigned int vertID) +{ + // No wrapping + if (lastID >= baseID) + return (vertID >= baseID); + + // If vertID is >= baseID it is pre-wrap and in session + if (vertID >= baseID) + return 1; + + // vertID is < baseID, If it is <= lastID it is post-wrap and in session + if (vertID <= lastID) + return 1; + + return 0; +} + +void CALLBACK GPUpgxpCacheVertex(short sx, short sy, const unsigned char* _pVertex) +{ + const PGXP_vertex* pNewVertex = (const PGXP_vertex*)_pVertex; + PGXP_vertex* pOldVertex = NULL; + + if (!pNewVertex) + return; + + //if (bGteAccuracy) + { + if (cacheMode != mode_write) + { + // Initialise cache on first use + if (cacheMode == mode_init) + memset(vertexCache, 0x00, sizeof(vertexCache)); + + // First vertex of write session (frame?) + cacheMode = mode_write; + baseID = pNewVertex->count; + } + + lastID = pNewVertex->count; + + if (sx >= -0x800 && sx <= 0x7ff && + sy >= -0x800 && sy <= 0x7ff) + { + pOldVertex = &vertexCache[sy + 0x800][sx + 0x800]; + + // To avoid ambiguity there can only be one valid entry per-session + if (IsSessionID(pOldVertex->count) && (pOldVertex->value == pNewVertex->value)) + { + // check to ensure this isn't identical + if ((fabsf(pOldVertex->x - pNewVertex->x) > 0.1f) || + (fabsf(pOldVertex->y - pNewVertex->y) > 0.1f) || + (fabsf(pOldVertex->z - pNewVertex->z) > 0.1f)) + { + pOldVertex->valid = 5; + return; + } + } + + // Write vertex into cache + *pOldVertex = *pNewVertex; + } + } +} + +PGXP_vertex* PGXP_GetCachedVertex(short sx, short sy) +{ + //if (bGteAccuracy) + { + if (cacheMode != mode_read) + { + // Initialise cache on first use + if (cacheMode == mode_init) + memset(vertexCache, 0x00, sizeof(vertexCache)); + + // First vertex of read session (frame?) + cacheMode = mode_read; + } + + if (sx >= -0x800 && sx <= 0x7ff && + sy >= -0x800 && sy <= 0x7ff) + { + // Return pointer to cache entry + return &vertexCache[sy + 0x800][sx + 0x800]; + } + } + + return NULL; +} + + +///////////////////////////////// +//// PGXP Implementation +///////////////////////////////// + const unsigned int primStrideTable[] = { 1, 2, 1, 2, 2, 3, 2, 3, 0 }; const unsigned int primCountTable[] = { 3, 3, 4, 4, 3, 3, 4, 4, 0 }; @@ -137,7 +244,9 @@ int PGXP_GetVertices(unsigned int* addr, void* pOutput, int xOffs, int yOffs) unsigned int count = primCountTable[primIdx]; // number of vertices PGXP_vertex* primStart = NULL; // pointer to first vertex char invalidVert = 0; // Number of vertices without valid PGXP values - float w = 0; // W coordinate of transformed vertex + + short* pPrimData = (short*)addr; // primitive data for cache lookups + PGXP_vertex* pCacheVert = NULL; if (PGXP_Mem == NULL) return 0; @@ -148,6 +257,7 @@ int PGXP_GetVertices(unsigned int* addr, void* pOutput, int xOffs, int yOffs) // Offset to start of primitive primStart = &PGXP_Mem[currentAddr + 1]; + pPrimData += 2; // Find any invalid vertices for (unsigned i = 0; i < count; ++i) @@ -158,24 +268,48 @@ int PGXP_GetVertices(unsigned int* addr, void* pOutput, int xOffs, int yOffs) for (unsigned i = 0; i < count; ++i) { - w = primStart[stride * i].z; - // If there are any invalid vertices set all w values to 1 - // iCB: Could use plane equation to find w for single invalid vertex in a quad - if (invalidVert > 0) - w = 1; - if (primStart[stride * i].valid) { pVertex[i].x = (primStart[stride * i].x + xOffs); pVertex[i].y = (primStart[stride * i].y + yOffs); pVertex[i].z = 0.95f; - pVertex[i].w = w; + pVertex[i].w = primStart[stride * i].z; pVertex[i].PGXP_flag = 1; } else + { + // Default to low precision vertex data pVertex[i].PGXP_flag = 2; + + // Look in cache for valid vertex + pCacheVert = PGXP_GetCachedVertex(pPrimData[stride * i * 2], pPrimData[(stride * i * 2) + 1]); + if (pCacheVert) + { + if (IsSessionID(pCacheVert->count)) + { + if (pCacheVert->valid == 1) + { + pVertex[i].x = (pCacheVert->x + xOffs); + pVertex[i].y = (pCacheVert->y + yOffs); + pVertex[i].z = 0.95f; + pVertex[i].w = pCacheVert->z; + pVertex[i].PGXP_flag = 3; + // reduce number of invalid vertices + invalidVert--; + } + else if(pCacheVert->valid > 1) + pVertex[i].PGXP_flag = 4; + } + } + } } + // If there are any invalid vertices set all w values to 1 + // iCB: Could use plane equation to find w for single invalid vertex in a quad + if (invalidVert > 0) + for (unsigned i = 0; i < count; ++i) + pVertex[i].w = 1; + return 1; } @@ -184,10 +318,14 @@ int PGXP_GetVertices(unsigned int* addr, void* pOutput, int xOffs, int yOffs) ///////////////////////////////// unsigned int PGXP_vDebug = 0; -const char blue[4] = { 0, 0, 255, 255 }; -const char red[4] = { 255, 0, 0, 255 }; -const char black[4] = { 0, 0, 0, 255 }; +const char red[4] = { 255, 0, 0, 255 }; +const char blue[4] = { 0, 0, 255, 255 }; +const char green[4] = { 0, 255, 0, 255 }; + const char yellow[4] = { 255, 255, 0, 255 }; +const char magenta[4] = { 255, 0, 255, 255 }; +const char black[4] = { 0, 0, 0, 255 }; + void CALLBACK GPUtoggleDebug(void) { @@ -207,6 +345,10 @@ const char* PGXP_colour(unsigned int flag) return blue; case 2: return red; + case 3: + return green; + case 4: + return magenta; default: return black; } diff --git a/win32/plugins/peopsxgl/gpuPeopsOpenGL.def b/win32/plugins/peopsxgl/gpuPeopsOpenGL.def index 88d121ff..a137b62c 100755 --- a/win32/plugins/peopsxgl/gpuPeopsOpenGL.def +++ b/win32/plugins/peopsxgl/gpuPeopsOpenGL.def @@ -34,6 +34,8 @@ EXPORTS GPUsetframelimit @27 GPUvisualVibration @28 GPUaddVertex @29 + GPUpgxpMemory @30 + GPUpgxpCacheVertex @31 - GPUtoggleDebug @31 + GPUtoggleDebug @32 -- cgit v1.2.3