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 --- plugins/peopsxgl/pgxp_gpu.c | 164 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 153 insertions(+), 11 deletions(-) (limited to 'plugins') 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; } -- cgit v1.2.3