diff --git a/plugins/zzogl-pg/opengl/GS.h b/plugins/zzogl-pg/opengl/GS.h index c6af7f9456..00875db5f1 100644 --- a/plugins/zzogl-pg/opengl/GS.h +++ b/plugins/zzogl-pg/opengl/GS.h @@ -471,14 +471,16 @@ typedef struct typedef struct { - Vertex gsvertex[3]; - u32 rgba; + Vertex gsvertex[4]; // circular buffer that contains the vertex + Vertex gsTriFanVertex; // Base of triangle fan primitive vertex + u32 rgba; // global color for flat shading texture float q; - Vertex vertexregs; + Vertex vertexregs; // accumulation buffer that collect current vertex data int primC; // number of verts current storing int primIndex; // current prim index - int nTriFanVert; + int nTriFanVert; // remember the index of the base of triangle fan + int new_tri_fan; // 1 if we process a new triangle fan primitive. 0 otherwise int prac; int dthe; @@ -512,12 +514,14 @@ typedef struct GSClut clut_buffer; int primNext(int inc = 1) { + // Note: ARRAY_SIZE(gsvertex) == 2^n => modulo is replaced by an and instruction return ((primIndex + inc) % ARRAY_SIZE(gsvertex)); } int primPrev(int dec = 1) { // Note: assert( dec <= ARRAY_SIZE(gsvertex) ); + // Note: ARRAY_SIZE(gsvertex) == 2^n => modulo is replaced by an and instruction return ((primIndex + (ARRAY_SIZE(gsvertex) - dec)) % ARRAY_SIZE(gsvertex)); } @@ -535,7 +539,12 @@ typedef struct vertexregs.y = y; vertexregs.z = z; vertexregs.f = f; - gsvertex[primIndex] = vertexregs; + if (likely(!new_tri_fan)) { + gsvertex[primIndex] = vertexregs; + } else { + gsTriFanVertex = vertexregs; + new_tri_fan = false; + } } inline void add_vertex(u16 x, u16 y, u32 z) @@ -543,7 +552,12 @@ typedef struct vertexregs.x = x; vertexregs.y = y; vertexregs.z = z; - gsvertex[primIndex] = vertexregs; + if (likely(!new_tri_fan)) { + gsvertex[primIndex] = vertexregs; + } else { + gsTriFanVertex = vertexregs; + new_tri_fan = false; + } } } GSinternal; diff --git a/plugins/zzogl-pg/opengl/GSmain.cpp b/plugins/zzogl-pg/opengl/GSmain.cpp index 17e279e799..583cb3d32b 100644 --- a/plugins/zzogl-pg/opengl/GSmain.cpp +++ b/plugins/zzogl-pg/opengl/GSmain.cpp @@ -309,7 +309,6 @@ void CALLBACK GSreset() gs.prac = 1; prim = &gs._prim[0]; - gs.nTriFanVert = -1; gs.imageTransfer = -1; gs.q = 1; } @@ -324,7 +323,6 @@ void CALLBACK GSgifSoftReset(u32 mask) gs.imageTransfer = -1; gs.q = 1; - gs.nTriFanVert = -1; } s32 CALLBACK GSinit() diff --git a/plugins/zzogl-pg/opengl/Regs.cpp b/plugins/zzogl-pg/opengl/Regs.cpp index a3e1cd3c31..2383ab5ceb 100644 --- a/plugins/zzogl-pg/opengl/Regs.cpp +++ b/plugins/zzogl-pg/opengl/Regs.cpp @@ -305,12 +305,14 @@ void __gifCall GIFRegHandlerPRIM(const u32 *data) gs.primC = 0; - prim->prim = (data[0]) & 0x7; - gs._prim[0].prim = (data[0]) & 0x7; - gs._prim[1].prim = (data[0]) & 0x7; + u16 prim_type = (data[0]) & 0x7; + prim->prim = prim_type; + gs._prim[0].prim = prim_type; + gs._prim[1].prim = prim_type; gs._prim[1]._val = (data[0] >> 3) & 0xff; - gs.nTriFanVert = gs.primIndex; + gs.new_tri_fan = !(prim_type ^ PRIM_TRIANGLE_FAN); + ZZKick->DirtyValidPrevPrim(); Prim(); } diff --git a/plugins/zzogl-pg/opengl/ZZKick.cpp b/plugins/zzogl-pg/opengl/ZZKick.cpp index 2425fd9e6e..d19a4bd3e0 100644 --- a/plugins/zzogl-pg/opengl/ZZKick.cpp +++ b/plugins/zzogl-pg/opengl/ZZKick.cpp @@ -57,18 +57,11 @@ void __forceinline Kick::KickVertex(bool adc) if (++gs.primC >= (int)g_primmult[prim->prim]) { if (!adc && NoHighlights(prim->ctxt)) DrawPrim(prim->prim); + else DirtyValidPrevPrim(); gs.primC -= g_primsub[prim->prim]; - - gs.primIndex = gs.primNext(); - if (prim->prim == 5) - { - /* tri fans need special processing */ - if (gs.nTriFanVert == gs.primIndex) gs.primIndex = gs.primNext(); } - } else { - gs.primIndex = gs.primNext(); - } + gs.primIndex = gs.primNext(); } template @@ -111,7 +104,7 @@ void Kick::Set_Vertex(VertexGPU *p, Vertex & gsvertex) __forceinline void Kick::Output_Vertex(VertexGPU vert, u32 id) { #ifdef WRITE_PRIM_LOGS - ZZLog::Prim_Log("%c%d(%d): xyzf=(%4d,%4d,0x%x,%3d), rgba=0x%8.8x, stq = (%2.5f,%2.5f,%2.5f)\n", + ZZLog::Prim_Log("%c%d(%d): xyzf=(%4d,%4d,0x%x,%3d), rgba=0x%8.8x, stq = (%2.5f,%2.5f,%2.5f)", id == 0 ? '*' : ' ', id, prim->prim, vert.x / 8, vert.y / 8, vert.z, vert.f / 128, vert.rgba, Clamp(vert.s, -10, 10), Clamp(vert.t, -10, 10), Clamp(vert.q, -10, 10)); #endif @@ -140,35 +133,70 @@ void Kick::DrawPrim(u32 prim_type) u32 last; switch(prim_type) { case PRIM_POINT: - assert(gs.primC >= 1); - Set_Vertex(&p[0], gs.gsvertex[gs.primIndex]); curvb.nCount ++; break; case PRIM_LINE: - case PRIM_LINE_STRIP: - assert(gs.primC >= 2); - Set_Vertex(&p[0], gs.gsvertex[gs.primPrev()]); Set_Vertex(&p[1], gs.gsvertex[gs.primIndex]); curvb.nCount += 2; break; - case PRIM_TRIANGLE: - case PRIM_TRIANGLE_STRIP: - case PRIM_TRIANGLE_FAN: - assert(gs.primC >= 3); + case PRIM_LINE_STRIP: + if (likely(ValidPrevPrim)) { + assert(curvb.nCount >= 1); + p[0] = p[-1]; + } else { + Set_Vertex(&p[0], gs.gsvertex[gs.primPrev()]); + ValidPrevPrim = true; + } - Set_Vertex(&p[0], gs.gsvertex[0]); - Set_Vertex(&p[1], gs.gsvertex[1]); - Set_Vertex(&p[2], gs.gsvertex[2]); + Set_Vertex(&p[1], gs.gsvertex[gs.primIndex]); + curvb.nCount += 2; + break; + + case PRIM_TRIANGLE: + Set_Vertex(&p[0], gs.gsvertex[gs.primPrev(2)]); + Set_Vertex(&p[1], gs.gsvertex[gs.primPrev()]); + Set_Vertex(&p[2], gs.gsvertex[gs.primIndex]); + curvb.nCount += 3; + break; + + case PRIM_TRIANGLE_STRIP: + if (likely(ValidPrevPrim)) { + assert(curvb.nCount >= 2); + p[0] = p[-2]; + p[1] = p[-1]; + } else { + Set_Vertex(&p[0], gs.gsvertex[gs.primPrev(2)]); + Set_Vertex(&p[1], gs.gsvertex[gs.primPrev()]); + ValidPrevPrim = true; + } + + Set_Vertex(&p[2], gs.gsvertex[gs.primIndex]); + curvb.nCount += 3; + break; + + case PRIM_TRIANGLE_FAN: + if (likely(ValidPrevPrim)) { + assert(curvb.nCount >= 2); + VertexGPU* TriFanVert = curvb.pBufferData + gs.nTriFanVert; + p[0] = TriFanVert[0]; + p[1] = p[-1]; + } else { + Set_Vertex(&p[0], gs.gsTriFanVertex); + Set_Vertex(&p[1], gs.gsvertex[gs.primPrev(1)]); + ValidPrevPrim = true; + // Remenber the base for future processing + gs.nTriFanVert = curvb.nCount; + } + + Set_Vertex(&p[2], gs.gsvertex[gs.primIndex]); curvb.nCount += 3; break; case PRIM_SPRITE: - assert(gs.primC >= 2); - prev = gs.primPrev(); last = gs.primIndex; @@ -206,17 +234,20 @@ void Kick::DrawPrim(u32 prim_type) default: break; } - // Print DEBUG info + // Print DEBUG info and code assertion switch(prim_type) { case PRIM_TRIANGLE: case PRIM_TRIANGLE_STRIP: case PRIM_TRIANGLE_FAN: + assert(gs.primC >= 3); Output_Vertex(p[2],2); case PRIM_LINE: case PRIM_LINE_STRIP: case PRIM_SPRITE: + assert(gs.primC >= 2); Output_Vertex(p[1],1); case PRIM_POINT: + assert(gs.primC >= 1); Output_Vertex(p[0],0); default: break; } diff --git a/plugins/zzogl-pg/opengl/ZZKick.h b/plugins/zzogl-pg/opengl/ZZKick.h index 00ef67c5a3..42b871f310 100644 --- a/plugins/zzogl-pg/opengl/ZZKick.h +++ b/plugins/zzogl-pg/opengl/ZZKick.h @@ -42,12 +42,17 @@ class Kick // template void Set_Vertex(VertexGPU *p, int i); template void Set_Vertex(VertexGPU *p, Vertex &gsvertex); void Output_Vertex(VertexGPU vert, u32 id); + bool ValidPrevPrim; public: Kick() { } ~Kick() { } void KickVertex(bool adc); void DrawPrim(u32 i); + + inline void DirtyValidPrevPrim() { + ValidPrevPrim = 0; + } }; extern Kick* ZZKick; diff --git a/plugins/zzogl-pg/opengl/targets.h b/plugins/zzogl-pg/opengl/targets.h index 486f891a90..d48fc59773 100644 --- a/plugins/zzogl-pg/opengl/targets.h +++ b/plugins/zzogl-pg/opengl/targets.h @@ -151,7 +151,7 @@ class CMemoryTarget int ref; }; - inline CMemoryTarget() : ptex(NULL), starty(0), height(0), realy(0), realheight(0), usedstamp(0), psm(0), cpsm(0), channels(0), clearminy(0), clearmaxy(0), validatecount(0), clutsize(0), clut(NULL) {} + inline CMemoryTarget() : ptex(NULL), starty(0), height(0), realy(0), realheight(0), usedstamp(0), psm(0), cpsm(0), channels(0), clearminy(0), clearmaxy(0), validatecount(0), clut(NULL), clutsize(0) {} inline CMemoryTarget(const CMemoryTarget& r) {