From 58f5f52eacef5b3a686fa0ea869daaba012bafe7 Mon Sep 17 00:00:00 2001 From: T_chan Date: Fri, 2 Feb 2024 20:08:04 +0000 Subject: [PATCH 01/15] avoid reading the flashrom if we know we are in VGA mode --- GL/platforms/sh4.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/GL/platforms/sh4.c b/GL/platforms/sh4.c index acaf692..85aaf7c 100644 --- a/GL/platforms/sh4.c +++ b/GL/platforms/sh4.c @@ -37,11 +37,13 @@ void InitGPU(_Bool autosort, _Bool fsaa) { that'll work... */ int cable = vid_check_cable(); - int region = flashrom_get_region(); - if(region == FLASHROM_REGION_EUROPE && cable != CT_VGA) { - printf("PAL region without VGA - enabling 50hz"); - vid_set_mode(DM_640x480_PAL_IL, PM_RGB565); + if(cable != CT_VGA) { + int region = flashrom_get_region(); + if (region == FLASHROM_REGION_EUROPE) { + printf("PAL region without VGA - enabling 50hz"); + vid_set_mode(DM_640x480_PAL_IL, PM_RGB565); + } } } From bd17c995eae7c79dfc2f99e4aabc2a185e4dd43f Mon Sep 17 00:00:00 2001 From: T_chan Date: Sat, 3 Feb 2024 11:42:39 +0000 Subject: [PATCH 02/15] Naomi: don't call flashrom_get_region, as KOS Naomi does not include flashrom functions --- GL/platforms/sh4.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/GL/platforms/sh4.c b/GL/platforms/sh4.c index 85aaf7c..67c6a28 100644 --- a/GL/platforms/sh4.c +++ b/GL/platforms/sh4.c @@ -32,6 +32,7 @@ void InitGPU(_Bool autosort, _Bool fsaa) { pvr_init(¶ms); +#ifndef _arch_sub_naomi /* If we're PAL and we're NOT VGA, then use 50hz by default. This is the safest thing to do. If someone wants to force 60hz then they can call vid_set_mode later and hopefully that'll work... */ @@ -45,6 +46,7 @@ void InitGPU(_Bool autosort, _Bool fsaa) { vid_set_mode(DM_640x480_PAL_IL, PM_RGB565); } } +#endif } void SceneBegin() { From d92a5b1b07bc8323ed233b5524e7335cab6c963e Mon Sep 17 00:00:00 2001 From: darc Date: Sat, 17 Feb 2024 02:45:37 -0600 Subject: [PATCH 03/15] Fix GL/matrix.c to work properly on -m4-single --- GL/matrix.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/GL/matrix.c b/GL/matrix.c index d95cd49..bfa2f12 100644 --- a/GL/matrix.c +++ b/GL/matrix.c @@ -6,7 +6,7 @@ #include "../containers/stack.h" -#define DEG2RAD (0.01745329251994329576923690768489) +#define DEG2RAD (0.01745329251994329576923690768489f) /* Depth range */ @@ -174,8 +174,8 @@ void APIENTRY glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) { }; float r = DEG2RAD * angle; - float c = cos(r); - float s = sin(r); + float c = fcos(r); + float s = fsin(r); VEC3_NORMALIZE(x, y, z); From eef1548914098cec3b78ee4f3af777abfa252da8 Mon Sep 17 00:00:00 2001 From: darcagn Date: Sun, 18 Feb 2024 23:34:59 +0000 Subject: [PATCH 04/15] Update matrix.c --- GL/matrix.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GL/matrix.c b/GL/matrix.c index bfa2f12..2744cb9 100644 --- a/GL/matrix.c +++ b/GL/matrix.c @@ -174,8 +174,8 @@ void APIENTRY glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) { }; float r = DEG2RAD * angle; - float c = fcos(r); - float s = fsin(r); + float c = cosf(r); + float s = sinf(r); VEC3_NORMALIZE(x, y, z); From c85aed2d287920dfd60d4ac0f76b1300dde8e931 Mon Sep 17 00:00:00 2001 From: Luke Benstead Date: Mon, 11 Mar 2024 19:11:35 +0000 Subject: [PATCH 05/15] Set the opb counter --- GL/platform.h | 2 +- GL/platforms/sh4.c | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/GL/platform.h b/GL/platform.h index 4e1e65b..f0a2f14 100644 --- a/GL/platform.h +++ b/GL/platform.h @@ -445,7 +445,7 @@ static inline void CompilePolyHeader(PolyHeader *dst, const PolyContext *src) { dst->d3 = dst->d4 = 0xffffffff; } -#ifdef BACKEND_KOSPVR +#ifdef __DREAMCAST__ #include "platforms/sh4.h" #else #include "platforms/software.h" diff --git a/GL/platforms/sh4.c b/GL/platforms/sh4.c index 67c6a28..1b61722 100644 --- a/GL/platforms/sh4.c +++ b/GL/platforms/sh4.c @@ -30,6 +30,15 @@ void InitGPU(_Bool autosort, _Bool fsaa) { (autosort) ? 0 : 1 /* Disable translucent auto-sorting to match traditional GL */ }; + /* Newer versions of KOS add an extra parameter to pvr_init_params_t + * called opb_overflow_count. To remain compatible we set that last + * parameter to something only if it exists */ + const int opb_offset = offsetof(pvr_init_params_t, autosort_disabled) + 4; + if(sizeof(pvr_init_params_t) > opb_offset) { + int* opb_count = (int*)(((char*)¶ms) + opb_offset); + *opb_count = 2; // Two should be enough for anybody.. right? + } + pvr_init(¶ms); #ifndef _arch_sub_naomi From cf4a55748958dfc9f0376cc62d8950ef74f7c35c Mon Sep 17 00:00:00 2001 From: Luke Benstead Date: Mon, 18 Mar 2024 20:18:58 +0000 Subject: [PATCH 06/15] Fix CLIP_DEBUG --- GL/platforms/sh4.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/GL/platforms/sh4.c b/GL/platforms/sh4.c index 1b61722..e4526a1 100644 --- a/GL/platforms/sh4.c +++ b/GL/platforms/sh4.c @@ -106,6 +106,10 @@ static inline void _glFlushBuffer() { static inline void _glPushHeaderOrVertex(Vertex* v) { TRACE(); +#if CLIP_DEBUG + fprintf(stderr, "{%f, %f, %f, %f}, // %x (%x)\n", v->xyz[0], v->xyz[1], v->xyz[2], v->w, v->flags, v); +#endif + uint32_t* s = (uint32_t*) v; sq[0] = *(s++); sq[1] = *(s++); @@ -169,13 +173,14 @@ void SceneListSubmit(Vertex* v2, int n) { QACR[1] = QACR[0] = 0x11; #if CLIP_DEBUG - Vertex* vertex = (Vertex*) src; + Vertex* vertex = (Vertex*) v2; for(int i = 0; i < n; ++i) { - fprintf(stderr, "{%f, %f, %f, %f}, // %x (%x)\n", vertex[i].xyz[0], vertex[i].xyz[1], vertex[i].xyz[2], vertex[i].w, vertex[i].flags, &vertex[i]); + fprintf(stderr, ">> {%f, %f, %f, %f}, // %x (%x)\n", vertex[i].xyz[0], vertex[i].xyz[1], vertex[i].xyz[2], vertex[i].w, vertex[i].flags, &vertex[i]); } fprintf(stderr, "----\n"); #endif + uint8_t visible_mask = 0; uint8_t counter = 0; @@ -212,6 +217,10 @@ void SceneListSubmit(Vertex* v2, int n) { (counter == 0) << 3 ); +#if CLIP_DEBUG + fprintf(stderr, "0x%x 0x%x 0x%x -> %d\n", v0, v1, v2, visible_mask); +#endif + switch(visible_mask) { case 15: /* All visible, but final vertex in strip */ { From b353151dcadbab793d2b2d15b340eb208f586e3d Mon Sep 17 00:00:00 2001 From: Luke Benstead Date: Mon, 18 Mar 2024 20:56:15 +0000 Subject: [PATCH 07/15] Fix freeze due to bad clipping --- GL/platforms/sh4.c | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/GL/platforms/sh4.c b/GL/platforms/sh4.c index e4526a1..dbf4c08 100644 --- a/GL/platforms/sh4.c +++ b/GL/platforms/sh4.c @@ -181,6 +181,23 @@ void SceneListSubmit(Vertex* v2, int n) { fprintf(stderr, "----\n"); #endif + /* This is a bit cumbersome - in some cases (particularly case 2) + we finish the vertex submission with a duplicated final vertex so + that the tri-strip can be continued. However, if the next triangle in the + strip is not visible then the duplicated vertex would've been sent without + the EOL flag. We won't know if we need the EOL flag or not when processing + case 2. To workaround this we may queue a vertex temporarily here, in the normal + case it will be submitted by the next iteration with the same flags it had, but + in the invisible case it will be overridden to submit with EOL */ + static Vertex qv; + Vertex* queued_vertex = NULL; + +#define QUEUE_VERTEX(v) \ + do { queued_vertex = &qv; *queued_vertex = *(v); } while(0) + +#define SUBMIT_QUEUED_VERTEX(sflags) \ + do { if(queued_vertex) { queued_vertex->flags = (sflags); _glPushHeaderOrVertex(queued_vertex); queued_vertex = NULL; } } while(0) + uint8_t visible_mask = 0; uint8_t counter = 0; @@ -224,6 +241,8 @@ void SceneListSubmit(Vertex* v2, int n) { switch(visible_mask) { case 15: /* All visible, but final vertex in strip */ { + SUBMIT_QUEUED_VERTEX(qv.flags); + _glPerspectiveDivideVertex(v0, h); _glPushHeaderOrVertex(v0); @@ -235,6 +254,7 @@ void SceneListSubmit(Vertex* v2, int n) { } break; case 7: + SUBMIT_QUEUED_VERTEX(qv.flags); /* All visible, push the first vertex and move on */ _glPerspectiveDivideVertex(v0, h); _glPushHeaderOrVertex(v0); @@ -242,6 +262,8 @@ void SceneListSubmit(Vertex* v2, int n) { case 9: /* First vertex was visible, last in strip */ { + SUBMIT_QUEUED_VERTEX(qv.flags); + Vertex __attribute__((aligned(32))) scratch[2]; Vertex* a = &scratch[0]; Vertex* b = &scratch[1]; @@ -265,6 +287,8 @@ void SceneListSubmit(Vertex* v2, int n) { case 1: /* First vertex was visible, but not last in strip */ { + SUBMIT_QUEUED_VERTEX(qv.flags); + Vertex __attribute__((aligned(32))) scratch[2]; Vertex* a = &scratch[0]; Vertex* b = &scratch[1]; @@ -283,7 +307,8 @@ void SceneListSubmit(Vertex* v2, int n) { _glPerspectiveDivideVertex(b, h); _glPushHeaderOrVertex(b); - _glPushHeaderOrVertex(b); + + QUEUE_VERTEX(b); } break; case 10: @@ -291,6 +316,8 @@ void SceneListSubmit(Vertex* v2, int n) { /* Second vertex was visible. In self case we need to create a triangle and produce two new vertices: 1-2, and 2-3. */ { + SUBMIT_QUEUED_VERTEX(qv.flags); + Vertex __attribute__((aligned(32))) scratch[3]; Vertex* a = &scratch[0]; Vertex* b = &scratch[1]; @@ -317,6 +344,8 @@ void SceneListSubmit(Vertex* v2, int n) { case 11: case 3: /* First and second vertex were visible */ { + SUBMIT_QUEUED_VERTEX(qv.flags); + Vertex __attribute__((aligned(32))) scratch[3]; Vertex* a = &scratch[0]; Vertex* b = &scratch[1]; @@ -348,6 +377,8 @@ void SceneListSubmit(Vertex* v2, int n) { case 4: /* Third vertex was visible. */ { + SUBMIT_QUEUED_VERTEX(qv.flags); + Vertex __attribute__((aligned(32))) scratch[3]; Vertex* a = &scratch[0]; Vertex* b = &scratch[1]; @@ -377,6 +408,8 @@ void SceneListSubmit(Vertex* v2, int n) { break; case 13: { + SUBMIT_QUEUED_VERTEX(qv.flags); + Vertex __attribute__((aligned(32))) scratch[3]; Vertex* a = &scratch[0]; Vertex* b = &scratch[1]; @@ -408,6 +441,8 @@ void SceneListSubmit(Vertex* v2, int n) { break; case 5: /* First and third vertex were visible */ { + SUBMIT_QUEUED_VERTEX(qv.flags); + Vertex __attribute__((aligned(32))) scratch[3]; Vertex* a = &scratch[0]; Vertex* b = &scratch[1]; @@ -438,6 +473,8 @@ void SceneListSubmit(Vertex* v2, int n) { case 14: case 6: /* Second and third vertex were visible */ { + SUBMIT_QUEUED_VERTEX(qv.flags); + Vertex __attribute__((aligned(32))) scratch[4]; Vertex* a = &scratch[0]; Vertex* b = &scratch[1]; @@ -469,6 +506,9 @@ void SceneListSubmit(Vertex* v2, int n) { break; case 8: default: + // Not visible, if there was a queued vertex, submit it with + // the EOL flag + SUBMIT_QUEUED_VERTEX(GPU_CMD_VERTEX_EOL); break; } } From d6ac295d18ce22d12d798b0faa3288ba31f2cdc4 Mon Sep 17 00:00:00 2001 From: Luke Benstead Date: Tue, 19 Mar 2024 08:14:38 +0000 Subject: [PATCH 08/15] Fix more potential freezes --- GL/platforms/sh4.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/GL/platforms/sh4.c b/GL/platforms/sh4.c index dbf4c08..f8a79d5 100644 --- a/GL/platforms/sh4.c +++ b/GL/platforms/sh4.c @@ -338,7 +338,7 @@ void SceneListSubmit(Vertex* v2, int n) { _glPushHeaderOrVertex(c); _glPerspectiveDivideVertex(b, h); - _glPushHeaderOrVertex(b); + QUEUE_VERTEX(b); } break; case 11: @@ -370,7 +370,8 @@ void SceneListSubmit(Vertex* v2, int n) { _glPerspectiveDivideVertex(a, h); _glPushHeaderOrVertex(c); - _glPushHeaderOrVertex(a); + + QUEUE_VERTEX(a); } break; case 12: From d4f6a9636bbb3ac8bd8b726a1c3922a104fa18b9 Mon Sep 17 00:00:00 2001 From: Luke Benstead Date: Tue, 19 Mar 2024 20:14:01 +0000 Subject: [PATCH 09/15] Fix more freezes and clipping issues --- GL/platforms/sh4.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/GL/platforms/sh4.c b/GL/platforms/sh4.c index f8a79d5..0aec03a 100644 --- a/GL/platforms/sh4.c +++ b/GL/platforms/sh4.c @@ -127,7 +127,7 @@ static inline void _glClipEdge(const Vertex* const v1, const Vertex* const v2, V const static float o = 0.003921569f; // 1 / 255 const float d0 = v1->w + v1->xyz[2]; const float d1 = v2->w + v2->xyz[2]; - const float t = (fabs(d0) * (1.0f / sqrtf((d1 - d0) * (d1 - d0)))) + 0.000001f; + const float t = (fabs(d0) * (1.0f / sqrtf((d1 - d0) * (d1 - d0)))); const float invt = 1.0f - t; vout->xyz[0] = invt * v1->xyz[0] + t * v2->xyz[0]; @@ -184,8 +184,8 @@ void SceneListSubmit(Vertex* v2, int n) { /* This is a bit cumbersome - in some cases (particularly case 2) we finish the vertex submission with a duplicated final vertex so that the tri-strip can be continued. However, if the next triangle in the - strip is not visible then the duplicated vertex would've been sent without - the EOL flag. We won't know if we need the EOL flag or not when processing + strip is not visible then the duplicated vertex would've been sent without + the EOL flag. We won't know if we need the EOL flag or not when processing case 2. To workaround this we may queue a vertex temporarily here, in the normal case it will be submitted by the next iteration with the same flags it had, but in the invisible case it will be overridden to submit with EOL */ @@ -228,9 +228,9 @@ void SceneListSubmit(Vertex* v2, int n) { Vertex* const v1 = v2 - 1; visible_mask = ( - (v0->xyz[2] > -v0->w) << 0 | - (v1->xyz[2] > -v1->w) << 1 | - (v2->xyz[2] > -v2->w) << 2 | + (v0->xyz[2] >= -v0->w) << 0 | + (v1->xyz[2] >= -v1->w) << 1 | + (v2->xyz[2] >= -v2->w) << 2 | (counter == 0) << 3 ); @@ -468,7 +468,7 @@ void SceneListSubmit(Vertex* v2, int n) { _glPushHeaderOrVertex(c); _glPerspectiveDivideVertex(b, h); _glPushHeaderOrVertex(b); - _glPushHeaderOrVertex(c); + QUEUE_VERTEX(c); } break; case 14: @@ -514,6 +514,8 @@ void SceneListSubmit(Vertex* v2, int n) { } } + SUBMIT_QUEUED_VERTEX(GPU_CMD_VERTEX_EOL); + _glFlushBuffer(); } From a8f3d86705ef4c4d8adc32ad3e89814fdb6d6126 Mon Sep 17 00:00:00 2001 From: Luke Benstead Date: Tue, 2 Apr 2024 22:28:36 +0100 Subject: [PATCH 10/15] Start cleaning up the zclip code --- GL/platforms/sh4.c | 381 ++++++++++++++++----------------------------- 1 file changed, 133 insertions(+), 248 deletions(-) diff --git a/GL/platforms/sh4.c b/GL/platforms/sh4.c index 0aec03a..2a356f6 100644 --- a/GL/platforms/sh4.c +++ b/GL/platforms/sh4.c @@ -1,8 +1,10 @@ +#include + #include "../platform.h" #include "sh4.h" -#define CLIP_DEBUG 0 +#define CLIP_DEBUG 1 #define PVR_VERTEX_BUF_SIZE 2560 * 256 @@ -133,6 +135,7 @@ static inline void _glClipEdge(const Vertex* const v1, const Vertex* const v2, V vout->xyz[0] = invt * v1->xyz[0] + t * v2->xyz[0]; vout->xyz[1] = invt * v1->xyz[1] + t * v2->xyz[1]; vout->xyz[2] = invt * v1->xyz[2] + t * v2->xyz[2]; + vout->xyz[2] = (vout->xyz[2] < FLT_EPSILON) ? FLT_EPSILON : vout->xyz[2]; vout->uv[0] = invt * v1->uv[0] + t * v2->uv[0]; vout->uv[1] = invt * v1->uv[1] + t * v2->uv[1]; @@ -153,7 +156,22 @@ static volatile uint32_t* PVR_LMMODE0 = (uint32_t*) 0xA05F6884; static volatile uint32_t *PVR_LMMODE1 = (uint32_t*) 0xA05F6888; static volatile uint32_t *QACR = (uint32_t*) 0xFF000038; -void SceneListSubmit(Vertex* v2, int n) { +enum Visible { + NONE_VISIBLE = 0, + FIRST_VISIBLE = 1, + SECOND_VISIBLE = 2, + THIRD_VISIBLE = 4, + FIRST_AND_SECOND_VISIBLE = FIRST_VISIBLE | SECOND_VISIBLE, + SECOND_AND_THIRD_VISIBLE = SECOND_VISIBLE | THIRD_VISIBLE, + FIRST_AND_THIRD_VISIBLE = FIRST_VISIBLE | THIRD_VISIBLE, + ALL_VISIBLE = 7 +}; + +static inline bool is_header(Vertex* v) { + return !(v->flags == GPU_CMD_VERTEX || v->flags == GPU_CMD_VERTEX_EOL); +} + +void SceneListSubmit(Vertex* vertices, int n) { TRACE(); /* You need at least a header, and 3 vertices to render anything */ @@ -173,12 +191,12 @@ void SceneListSubmit(Vertex* v2, int n) { QACR[1] = QACR[0] = 0x11; #if CLIP_DEBUG - Vertex* vertex = (Vertex*) v2; - for(int i = 0; i < n; ++i) { - fprintf(stderr, ">> {%f, %f, %f, %f}, // %x (%x)\n", vertex[i].xyz[0], vertex[i].xyz[1], vertex[i].xyz[2], vertex[i].w, vertex[i].flags, &vertex[i]); - } - fprintf(stderr, "----\n"); + + Vertex* vertex = (Vertex*) vertices; + for(int i = 0; i < n; ++i) { + fprintf(stderr, "IN: {%f, %f, %f, %f}, // %x (%x)\n", vertex[i].xyz[0], vertex[i].xyz[1], vertex[i].xyz[2], vertex[i].w, vertex[i].flags, &vertex[i]); + } #endif /* This is a bit cumbersome - in some cases (particularly case 2) @@ -189,7 +207,7 @@ void SceneListSubmit(Vertex* v2, int n) { case 2. To workaround this we may queue a vertex temporarily here, in the normal case it will be submitted by the next iteration with the same flags it had, but in the invisible case it will be overridden to submit with EOL */ - static Vertex qv; + static Vertex __attribute__((aligned(32))) qv; Vertex* queued_vertex = NULL; #define QUEUE_VERTEX(v) \ @@ -199,100 +217,49 @@ void SceneListSubmit(Vertex* v2, int n) { do { if(queued_vertex) { queued_vertex->flags = (sflags); _glPushHeaderOrVertex(queued_vertex); queued_vertex = NULL; } } while(0) uint8_t visible_mask = 0; - uint8_t counter = 0; sq = SQ_BASE_ADDRESS; - for(int i = 0; i < n; ++i, ++v2) { - PREFETCH(v2 + 1); - switch(v2->flags) { - case GPU_CMD_VERTEX_EOL: - if(counter < 2) { - continue; - } - counter = 0; - break; - case GPU_CMD_VERTEX: - ++counter; - if(counter < 3) { - continue; - } - break; - default: - _glPushHeaderOrVertex(v2); - counter = 0; + Vertex* v0 = vertices; + for(int i = 0; i < n - 2; ++i, v0++) { + if(is_header(v0)) { + _glPushHeaderOrVertex(v0); continue; - }; + } - Vertex* const v0 = v2 - 2; - Vertex* const v1 = v2 - 1; + Vertex* v1 = v0 + 1; + Vertex* v2 = v0 + 2; - visible_mask = ( + int visible_mask = ( (v0->xyz[2] >= -v0->w) << 0 | (v1->xyz[2] >= -v1->w) << 1 | - (v2->xyz[2] >= -v2->w) << 2 | - (counter == 0) << 3 + (v2->xyz[2] >= -v2->w) << 2 ); -#if CLIP_DEBUG - fprintf(stderr, "0x%x 0x%x 0x%x -> %d\n", v0, v1, v2, visible_mask); -#endif + /* If we've gone behind the plane, we finish the strip + otherwise we submit however it was */ + if(visible_mask == NONE_VISIBLE) { + SUBMIT_QUEUED_VERTEX(GPU_CMD_VERTEX_EOL); + } else { + SUBMIT_QUEUED_VERTEX(qv.flags); + } + + #if CLIP_DEBUG + fprintf(stderr, "0x%x 0x%x 0x%x -> %d\n", v0, v1, v2, visible_mask); + #endif + + Vertex __attribute__((aligned(32))) scratch[4]; + Vertex* a = &scratch[0], *b = &scratch[1], *c = &scratch[2], *d = &scratch[3]; switch(visible_mask) { - case 15: /* All visible, but final vertex in strip */ - { - SUBMIT_QUEUED_VERTEX(qv.flags); - - _glPerspectiveDivideVertex(v0, h); - _glPushHeaderOrVertex(v0); - - _glPerspectiveDivideVertex(v1, h); - _glPushHeaderOrVertex(v1); - - _glPerspectiveDivideVertex(v2, h); - _glPushHeaderOrVertex(v2); - } - break; - case 7: - SUBMIT_QUEUED_VERTEX(qv.flags); - /* All visible, push the first vertex and move on */ - _glPerspectiveDivideVertex(v0, h); - _glPushHeaderOrVertex(v0); - break; - case 9: - /* First vertex was visible, last in strip */ - { - SUBMIT_QUEUED_VERTEX(qv.flags); - - Vertex __attribute__((aligned(32))) scratch[2]; - Vertex* a = &scratch[0]; - Vertex* b = &scratch[1]; - - _glClipEdge(v0, v1, a); - a->flags = GPU_CMD_VERTEX; - - _glClipEdge(v2, v0, b); - b->flags = GPU_CMD_VERTEX_EOL; - + case ALL_VISIBLE: _glPerspectiveDivideVertex(v0, h); - _glPushHeaderOrVertex(v0); - - _glPerspectiveDivideVertex(a, h); - _glPushHeaderOrVertex(a); - - _glPerspectiveDivideVertex(b, h); - _glPushHeaderOrVertex(b); - } + QUEUE_VERTEX(v0); break; - case 1: - /* First vertex was visible, but not last in strip */ - { - SUBMIT_QUEUED_VERTEX(qv.flags); - - Vertex __attribute__((aligned(32))) scratch[2]; - Vertex* a = &scratch[0]; - Vertex* b = &scratch[1]; - + case NONE_VISIBLE: + break; + break; + case FIRST_VISIBLE: _glClipEdge(v0, v1, a); a->flags = GPU_CMD_VERTEX; @@ -309,20 +276,8 @@ void SceneListSubmit(Vertex* v2, int n) { _glPushHeaderOrVertex(b); QUEUE_VERTEX(b); - } break; - case 10: - case 2: - /* Second vertex was visible. In self case we need to create a triangle and produce - two new vertices: 1-2, and 2-3. */ - { - SUBMIT_QUEUED_VERTEX(qv.flags); - - Vertex __attribute__((aligned(32))) scratch[3]; - Vertex* a = &scratch[0]; - Vertex* b = &scratch[1]; - Vertex* c = &scratch[2]; - + case SECOND_VISIBLE: memcpy_vertex(c, v1); _glClipEdge(v0, v1, a); @@ -339,52 +294,8 @@ void SceneListSubmit(Vertex* v2, int n) { _glPerspectiveDivideVertex(b, h); QUEUE_VERTEX(b); - } break; - case 11: - case 3: /* First and second vertex were visible */ - { - SUBMIT_QUEUED_VERTEX(qv.flags); - - Vertex __attribute__((aligned(32))) scratch[3]; - Vertex* a = &scratch[0]; - Vertex* b = &scratch[1]; - Vertex* c = &scratch[2]; - - memcpy_vertex(c, v1); - - _glClipEdge(v2, v0, b); - b->flags = GPU_CMD_VERTEX; - - _glPerspectiveDivideVertex(v0, h); - _glPushHeaderOrVertex(v0); - - _glClipEdge(v1, v2, a); - a->flags = v2->flags; - - _glPerspectiveDivideVertex(c, h); - _glPushHeaderOrVertex(c); - - _glPerspectiveDivideVertex(b, h); - _glPushHeaderOrVertex(b); - - _glPerspectiveDivideVertex(a, h); - _glPushHeaderOrVertex(c); - - QUEUE_VERTEX(a); - } - break; - case 12: - case 4: - /* Third vertex was visible. */ - { - SUBMIT_QUEUED_VERTEX(qv.flags); - - Vertex __attribute__((aligned(32))) scratch[3]; - Vertex* a = &scratch[0]; - Vertex* b = &scratch[1]; - Vertex* c = &scratch[2]; - + case THIRD_VISIBLE: memcpy_vertex(c, v2); _glClipEdge(v2, v0, a); @@ -394,123 +305,97 @@ void SceneListSubmit(Vertex* v2, int n) { b->flags = GPU_CMD_VERTEX; _glPerspectiveDivideVertex(a, h); + //_glPushHeaderOrVertex(a); _glPushHeaderOrVertex(a); - if(counter % 2 == 1) { - _glPushHeaderOrVertex(a); - } - _glPerspectiveDivideVertex(b, h); _glPushHeaderOrVertex(b); + _glPerspectiveDivideVertex(c, h); + QUEUE_VERTEX(c); + break; + case FIRST_AND_SECOND_VISIBLE: + memcpy_vertex(c, v1); + + _glClipEdge(v2, v0, b); + b->flags = GPU_CMD_VERTEX; + + _glPerspectiveDivideVertex(v0, h); + _glPushHeaderOrVertex(v0); + + _glClipEdge(v1, v2, a); + a->flags = v2->flags; + _glPerspectiveDivideVertex(c, h); _glPushHeaderOrVertex(c); - } + + _glPerspectiveDivideVertex(b, h); + _glPushHeaderOrVertex(b); + + _glPerspectiveDivideVertex(a, h); + _glPushHeaderOrVertex(c); + + QUEUE_VERTEX(a); break; - case 13: - { - SUBMIT_QUEUED_VERTEX(qv.flags); + case SECOND_AND_THIRD_VISIBLE: + memcpy_vertex(c, v1); + memcpy_vertex(d, v2); - Vertex __attribute__((aligned(32))) scratch[3]; - Vertex* a = &scratch[0]; - Vertex* b = &scratch[1]; - Vertex* c = &scratch[2]; + _glClipEdge(v0, v1, a); + a->flags = GPU_CMD_VERTEX; - memcpy_vertex(c, v2); - c->flags = GPU_CMD_VERTEX; + _glClipEdge(v2, v0, b); + b->flags = GPU_CMD_VERTEX; - _glClipEdge(v0, v1, a); - a->flags = GPU_CMD_VERTEX; + _glPerspectiveDivideVertex(a, h); + _glPushHeaderOrVertex(a); - _glClipEdge(v1, v2, b); - b->flags = GPU_CMD_VERTEX; + _glPerspectiveDivideVertex(c, h); + _glPushHeaderOrVertex(c); - _glPerspectiveDivideVertex(v0, h); - _glPushHeaderOrVertex(v0); + _glPerspectiveDivideVertex(b, h); + _glPushHeaderOrVertex(b); + _glPushHeaderOrVertex(c); - _glPerspectiveDivideVertex(a, h); - _glPushHeaderOrVertex(a); - - _glPerspectiveDivideVertex(c, h); - _glPushHeaderOrVertex(c); - _glPerspectiveDivideVertex(b, h); - _glPushHeaderOrVertex(b); - - c->flags = GPU_CMD_VERTEX_EOL; - _glPushHeaderOrVertex(c); - } - break; - case 5: /* First and third vertex were visible */ - { - SUBMIT_QUEUED_VERTEX(qv.flags); - - Vertex __attribute__((aligned(32))) scratch[3]; - Vertex* a = &scratch[0]; - Vertex* b = &scratch[1]; - Vertex* c = &scratch[2]; - - memcpy_vertex(c, v2); - c->flags = GPU_CMD_VERTEX; - - _glClipEdge(v0, v1, a); - a->flags = GPU_CMD_VERTEX; - - _glClipEdge(v1, v2, b); - b->flags = GPU_CMD_VERTEX; - - _glPerspectiveDivideVertex(v0, h); - _glPushHeaderOrVertex(v0); - - _glPerspectiveDivideVertex(a, h); - _glPushHeaderOrVertex(a); - - _glPerspectiveDivideVertex(c, h); - _glPushHeaderOrVertex(c); - _glPerspectiveDivideVertex(b, h); - _glPushHeaderOrVertex(b); - QUEUE_VERTEX(c); - } - break; - case 14: - case 6: /* Second and third vertex were visible */ - { - SUBMIT_QUEUED_VERTEX(qv.flags); - - Vertex __attribute__((aligned(32))) scratch[4]; - Vertex* a = &scratch[0]; - Vertex* b = &scratch[1]; - Vertex* c = &scratch[2]; - Vertex* d = &scratch[3]; - - memcpy_vertex(c, v1); - memcpy_vertex(d, v2); - - _glClipEdge(v0, v1, a); - a->flags = GPU_CMD_VERTEX; - - _glClipEdge(v2, v0, b); - b->flags = GPU_CMD_VERTEX; - - _glPerspectiveDivideVertex(a, h); - _glPushHeaderOrVertex(a); - - _glPerspectiveDivideVertex(c, h); - _glPushHeaderOrVertex(c); - - _glPerspectiveDivideVertex(b, h); - _glPushHeaderOrVertex(b); - _glPushHeaderOrVertex(c); - - _glPerspectiveDivideVertex(d, h); - _glPushHeaderOrVertex(d); - } - break; - case 8: - default: - // Not visible, if there was a queued vertex, submit it with - // the EOL flag - SUBMIT_QUEUED_VERTEX(GPU_CMD_VERTEX_EOL); + _glPerspectiveDivideVertex(d, h); + QUEUE_VERTEX(d); break; + case FIRST_AND_THIRD_VISIBLE: + memcpy_vertex(c, v2); + c->flags = GPU_CMD_VERTEX; + + _glClipEdge(v0, v1, a); + a->flags = GPU_CMD_VERTEX; + + _glClipEdge(v1, v2, b); + b->flags = GPU_CMD_VERTEX; + + _glPerspectiveDivideVertex(v0, h); + _glPushHeaderOrVertex(v0); + + _glPerspectiveDivideVertex(a, h); + _glPushHeaderOrVertex(a); + + _glPerspectiveDivideVertex(c, h); + _glPushHeaderOrVertex(c); + _glPerspectiveDivideVertex(b, h); + _glPushHeaderOrVertex(b); + QUEUE_VERTEX(c); + break; + default: + fprintf(stderr, "ERROR\n"); + } + + if(v2->flags == GPU_CMD_VERTEX_EOL && visible_mask == ALL_VISIBLE) { + SUBMIT_QUEUED_VERTEX(qv.flags); + + _glPerspectiveDivideVertex(v1, h); + _glPushHeaderOrVertex(v1); + + _glPerspectiveDivideVertex(v2, h); + _glPushHeaderOrVertex(v2); + + i += 2; } } From f8d1fa34399c25ea42068524aad2132fbc2e1496 Mon Sep 17 00:00:00 2001 From: Luke Benstead Date: Wed, 3 Apr 2024 21:19:36 +0100 Subject: [PATCH 11/15] Fix some issues with clipping --- GL/platforms/sh4.c | 45 +++++++----- samples/zclip_trianglestrip/main.c | 112 ++++++++++++++++++++--------- 2 files changed, 105 insertions(+), 52 deletions(-) diff --git a/GL/platforms/sh4.c b/GL/platforms/sh4.c index 2a356f6..8503136 100644 --- a/GL/platforms/sh4.c +++ b/GL/platforms/sh4.c @@ -4,7 +4,7 @@ #include "sh4.h" -#define CLIP_DEBUG 1 +#define CLIP_DEBUG 0 #define PVR_VERTEX_BUF_SIZE 2560 * 256 @@ -192,7 +192,7 @@ void SceneListSubmit(Vertex* vertices, int n) { #if CLIP_DEBUG fprintf(stderr, "----\n"); - + Vertex* vertex = (Vertex*) vertices; for(int i = 0; i < n; ++i) { fprintf(stderr, "IN: {%f, %f, %f, %f}, // %x (%x)\n", vertex[i].xyz[0], vertex[i].xyz[1], vertex[i].xyz[2], vertex[i].w, vertex[i].flags, &vertex[i]); @@ -230,6 +230,27 @@ void SceneListSubmit(Vertex* vertices, int n) { Vertex* v1 = v0 + 1; Vertex* v2 = v0 + 2; + assert(!is_header(v1)); + + if(is_header(v2)) { + // OK so we've hit a new context header + // we need to finalize this strip and move on + SUBMIT_QUEUED_VERTEX(qv.flags); + + _glPerspectiveDivideVertex(v0, h); + _glPushHeaderOrVertex(v0); + + _glPerspectiveDivideVertex(v1, h); + _glPushHeaderOrVertex(v1); + i += 2; + continue; + } + + assert(!is_header(v2)); + + // FIXME: What if v1 or v2 are headers? Should we handle that or just + // assume the user has done something weird and all bets are off? + int visible_mask = ( (v0->xyz[2] >= -v0->w) << 0 | (v1->xyz[2] >= -v1->w) << 1 | @@ -244,9 +265,9 @@ void SceneListSubmit(Vertex* vertices, int n) { SUBMIT_QUEUED_VERTEX(qv.flags); } - #if CLIP_DEBUG - fprintf(stderr, "0x%x 0x%x 0x%x -> %d\n", v0, v1, v2, visible_mask); - #endif +#if CLIP_DEBUG + fprintf(stderr, "0x%x 0x%x 0x%x -> %d\n", v0, v1, v2, visible_mask); +#endif Vertex __attribute__((aligned(32))) scratch[4]; Vertex* a = &scratch[0], *b = &scratch[1], *c = &scratch[2], *d = &scratch[3]; @@ -277,7 +298,7 @@ void SceneListSubmit(Vertex* vertices, int n) { QUEUE_VERTEX(b); break; - case SECOND_VISIBLE: + case SECOND_VISIBLE: memcpy_vertex(c, v1); _glClipEdge(v0, v1, a); @@ -385,18 +406,6 @@ void SceneListSubmit(Vertex* vertices, int n) { default: fprintf(stderr, "ERROR\n"); } - - if(v2->flags == GPU_CMD_VERTEX_EOL && visible_mask == ALL_VISIBLE) { - SUBMIT_QUEUED_VERTEX(qv.flags); - - _glPerspectiveDivideVertex(v1, h); - _glPushHeaderOrVertex(v1); - - _glPerspectiveDivideVertex(v2, h); - _glPushHeaderOrVertex(v2); - - i += 2; - } } SUBMIT_QUEUED_VERTEX(GPU_CMD_VERTEX_EOL); diff --git a/samples/zclip_trianglestrip/main.c b/samples/zclip_trianglestrip/main.c index 7d4b698..4960c1c 100644 --- a/samples/zclip_trianglestrip/main.c +++ b/samples/zclip_trianglestrip/main.c @@ -20,7 +20,7 @@ void InitGL(int Width, int Height) // We call this right after our OpenG glEnable(GL_DEPTH_TEST); // Enables Depth Testing glShadeModel(GL_SMOOTH); // Enables Smooth Color Shading glEnable(GL_TEXTURE_2D); - glEnable(GL_CULL_FACE); + glDisable(GL_CULL_FACE); glMatrixMode(GL_PROJECTION); glLoadIdentity(); // Reset The Projection Matrix @@ -64,30 +64,38 @@ int check_start() { return 0; } +static GLfloat movement = 0.0f; +static GLfloat rotation = 0.0f; + +void update_movement() { +#ifdef __DREAMCAST__ + maple_device_t *cont; + cont_state_t *state; + + cont = maple_enum_type(0, MAPLE_FUNC_CONTROLLER); + + if(cont) { + state = (cont_state_t *)maple_dev_status(cont); + if(state) { + if(state->buttons & CONT_DPAD_UP) { + movement += 0.5f; + } else if(state->buttons & CONT_DPAD_DOWN) { + movement -= 0.5f; + } + + if(state->buttons & CONT_DPAD_LEFT) { + rotation += 0.5f; + } else if(state->buttons & CONT_DPAD_RIGHT) { + rotation -= 0.5f; + } + } + } +#endif +} + /* The main drawing function. */ void DrawGLScene() { - static GLfloat movement = 0.0f; - static GLfloat rotation = 0.0f; - static GLboolean increasing = GL_TRUE; - - if(movement > 10.0) { - increasing = GL_FALSE; - } else if(movement < -10.0f) { - increasing = GL_TRUE; - } - - if(increasing) { - movement += 0.05f; - } else { - movement -= 0.05f; - } - - rotation += 0.1f; - if(rotation > 360.0f) { - rotation -= 360.0f; - } - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer glLoadIdentity(); // Reset The View @@ -95,24 +103,58 @@ void DrawGLScene() glTranslatef(0.0f, -1.0f, movement); glRotatef(rotation, 0.0f, 1.0, 0.0f); - glBegin(GL_TRIANGLE_STRIP); - glColor3f(1.0f, 1.0f, 0.0f); - glVertex3f(-2.5f, 0.0f, 5.0f); + /* We create a horseshoe shape tri-strip here because that allows for situations where a strip + leaves and re-enters the viewport */ - glColor3f(1.0f, 0.0f, 0.0f); - glVertex3f(2.5f, 0.0f, 5.0f); + glBegin(GL_TRIANGLE_STRIP); + // Left side + glColor3f(1.0f, 1.0f, 0.0f); + glVertex3f(-2.0f, 0.0f, 5.0f); + + glColor3f(1.0f, 1.0f, 0.0f); + glVertex3f(-1.0f, 0.0f, 5.0f); + + glColor3f(1.0f, 1.0f, 0.0f); + glVertex3f(-2.0f, 0.0f, 3.0f); + + glColor3f(1.0f, 1.0f, 0.0f); + glVertex3f(-1.0f, 0.0f, 3.0f); + + glColor3f(1.0f, 1.0f, 0.0f); + glVertex3f(-2.0f, 0.0f, 1.0f); + + glColor3f(1.0f, 1.0f, 0.0f); + glVertex3f(-1.0f, 0.0f, 1.0f); + + // Curve + glColor3f(0.0f, 1.0f, 0.0f); + glVertex3f(-1.0f, 0.0f, -1.0f); glColor3f(0.0f, 1.0f, 0.0f); - glVertex3f(-2.5f, 0.0f, -5.0f); + glVertex3f(1.0f, 0.0f, 1.0f); - glColor3f(0.0f, 0.0f, 1.0f); - glVertex3f(2.5f, 0.0f, -5.0f); + glColor3f(0.0f, 1.0f, 0.0f); + glVertex3f(1.0f, 0.0f, -1.0f); - glColor3f(0.0f, 1.0f, 1.0f); - glVertex3f(-2.5f, 0.0f, -10.0f); + // Right side + // Degenerate to reverse ordering + glColor3f(1.0f, 0.0f, 0.0f); + glVertex3f(2.0f, 0.0f, 1.0f); - glColor3f(1.0f, 0.0f, 1.0f); - glVertex3f(2.5f, 0.0f, -10.0f); + glColor3f(0.0f, 1.0f, 0.0f); + glVertex3f(1.0f, 0.0f, 1.0f); + + glColor3f(1.0f, 0.0f, 0.0f); + glVertex3f(1.0f, 0.0f, 3.0f); + + glColor3f(1.0f, 0.0f, 0.0f); + glVertex3f(2.0f, 0.0f, 3.0f); + + glColor3f(1.0f, 0.0f, 0.0f); + glVertex3f(1.0f, 0.0f, 5.0f); + + glColor3f(1.0f, 0.0f, 0.0f); + glVertex3f(2.0f, 0.0f, 5.0f); glEnd(); glPopMatrix(); @@ -131,6 +173,8 @@ int main(int argc, char **argv) if(check_start()) break; + update_movement(); + DrawGLScene(); } From 5299badf58fdc199d353e8f8070812df3e8b24ad Mon Sep 17 00:00:00 2001 From: Luke Benstead Date: Wed, 3 Apr 2024 22:09:35 +0100 Subject: [PATCH 12/15] Only submit trailing vertices if the previous triangle was visible --- GL/platforms/sh4.c | 24 ++++++++++++------------ samples/zclip_trianglestrip/main.c | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/GL/platforms/sh4.c b/GL/platforms/sh4.c index 8503136..53227e4 100644 --- a/GL/platforms/sh4.c +++ b/GL/platforms/sh4.c @@ -216,7 +216,7 @@ void SceneListSubmit(Vertex* vertices, int n) { #define SUBMIT_QUEUED_VERTEX(sflags) \ do { if(queued_vertex) { queued_vertex->flags = (sflags); _glPushHeaderOrVertex(queued_vertex); queued_vertex = NULL; } } while(0) - uint8_t visible_mask = 0; + int visible_mask = 0; sq = SQ_BASE_ADDRESS; @@ -237,21 +237,21 @@ void SceneListSubmit(Vertex* vertices, int n) { // we need to finalize this strip and move on SUBMIT_QUEUED_VERTEX(qv.flags); - _glPerspectiveDivideVertex(v0, h); - _glPushHeaderOrVertex(v0); + // If the last triangle was all visible, we need + // to submit the last two vertices, any clipped triangles + // would've + if(visible_mask == ALL_VISIBLE) { + _glPerspectiveDivideVertex(v0, h); + _glPushHeaderOrVertex(v0); - _glPerspectiveDivideVertex(v1, h); - _glPushHeaderOrVertex(v1); - i += 2; + _glPerspectiveDivideVertex(v1, h); + _glPushHeaderOrVertex(v1); + i += 2; + } continue; } - assert(!is_header(v2)); - - // FIXME: What if v1 or v2 are headers? Should we handle that or just - // assume the user has done something weird and all bets are off? - - int visible_mask = ( + visible_mask = ( (v0->xyz[2] >= -v0->w) << 0 | (v1->xyz[2] >= -v1->w) << 1 | (v2->xyz[2] >= -v2->w) << 2 diff --git a/samples/zclip_trianglestrip/main.c b/samples/zclip_trianglestrip/main.c index 4960c1c..064add8 100644 --- a/samples/zclip_trianglestrip/main.c +++ b/samples/zclip_trianglestrip/main.c @@ -64,7 +64,7 @@ int check_start() { return 0; } -static GLfloat movement = 0.0f; +static GLfloat movement = -10.0f; static GLfloat rotation = 0.0f; void update_movement() { From 77f4b59aeaec744f61ba13ff78c4eeebaea201f6 Mon Sep 17 00:00:00 2001 From: Luke Benstead Date: Wed, 3 Apr 2024 22:30:41 +0100 Subject: [PATCH 13/15] Fix off-by-one --- GL/platforms/sh4.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/GL/platforms/sh4.c b/GL/platforms/sh4.c index 53227e4..ae19d8e 100644 --- a/GL/platforms/sh4.c +++ b/GL/platforms/sh4.c @@ -221,9 +221,10 @@ void SceneListSubmit(Vertex* vertices, int n) { sq = SQ_BASE_ADDRESS; Vertex* v0 = vertices; - for(int i = 0; i < n - 2; ++i, v0++) { + for(int i = 0; i < n - 2; ++i, ++v0) { if(is_header(v0)) { _glPushHeaderOrVertex(v0); + visible_mask = 0; continue; } @@ -235,19 +236,29 @@ void SceneListSubmit(Vertex* vertices, int n) { if(is_header(v2)) { // OK so we've hit a new context header // we need to finalize this strip and move on - SUBMIT_QUEUED_VERTEX(qv.flags); // If the last triangle was all visible, we need // to submit the last two vertices, any clipped triangles // would've if(visible_mask == ALL_VISIBLE) { + SUBMIT_QUEUED_VERTEX(qv.flags); + _glPerspectiveDivideVertex(v0, h); _glPushHeaderOrVertex(v0); + v1->flags = GPU_CMD_VERTEX_EOL; + _glPerspectiveDivideVertex(v1, h); _glPushHeaderOrVertex(v1); - i += 2; + } else { + // If the previous triangle wasn't all visible, and we + // queued a vertex - we force it to be EOL and submit + SUBMIT_QUEUED_VERTEX(GPU_CMD_VERTEX_EOL); } + + i++; + v0++; + visible_mask = 0; continue; } From 6a6d229e4c9caa4696a83afe4b8d8d0627b5cc05 Mon Sep 17 00:00:00 2001 From: Luke Benstead Date: Thu, 4 Apr 2024 06:30:37 +0100 Subject: [PATCH 14/15] Fix bug with multiple strips --- GL/platforms/sh4.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/GL/platforms/sh4.c b/GL/platforms/sh4.c index ae19d8e..bfa8415 100644 --- a/GL/platforms/sh4.c +++ b/GL/platforms/sh4.c @@ -233,7 +233,9 @@ void SceneListSubmit(Vertex* vertices, int n) { assert(!is_header(v1)); - if(is_header(v2)) { + bool is_trailing = (v1->flags == GPU_CMD_VERTEX_EOL) || is_header(v2); + + if(is_trailing) { // OK so we've hit a new context header // we need to finalize this strip and move on From 572fa01b03b070e8911db43ca1fb55e3a4f8bdd5 Mon Sep 17 00:00:00 2001 From: Luke Benstead Date: Sat, 6 Apr 2024 21:13:17 +0100 Subject: [PATCH 15/15] Fix edge case --- GL/platforms/sh4.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/GL/platforms/sh4.c b/GL/platforms/sh4.c index bfa8415..ba00148 100644 --- a/GL/platforms/sh4.c +++ b/GL/platforms/sh4.c @@ -221,7 +221,7 @@ void SceneListSubmit(Vertex* vertices, int n) { sq = SQ_BASE_ADDRESS; Vertex* v0 = vertices; - for(int i = 0; i < n - 2; ++i, ++v0) { + for(int i = 0; i < n - 1; ++i, ++v0) { if(is_header(v0)) { _glPushHeaderOrVertex(v0); visible_mask = 0; @@ -229,11 +229,13 @@ void SceneListSubmit(Vertex* vertices, int n) { } Vertex* v1 = v0 + 1; - Vertex* v2 = v0 + 2; + Vertex* v2 = (i < n - 2) ? v0 + 2 : NULL; assert(!is_header(v1)); - bool is_trailing = (v1->flags == GPU_CMD_VERTEX_EOL) || is_header(v2); + // We are trailing if we're on the penultimate vertex, or the next but one vertex is + // an EOL, or v1 is an EOL (FIXME: possibly unnecessary and coverted by the other case?) + bool is_trailing = (v1->flags == GPU_CMD_VERTEX_EOL) || ((v2) ? is_header(v2) : true); if(is_trailing) { // OK so we've hit a new context header