From 709942e69dde948e5f52fe3cfbaac3b9038904ca Mon Sep 17 00:00:00 2001 From: Falco Girgis Date: Tue, 30 Jan 2024 19:40:40 -0600 Subject: [PATCH 01/72] test. --- 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..6fa971c 100644 --- a/GL/platforms/sh4.c +++ b/GL/platforms/sh4.c @@ -1,6 +1,8 @@ #include "../platform.h" #include "sh4.h" +#include + #define CLIP_DEBUG 0 @@ -85,14 +87,12 @@ volatile uint32_t *sq = SQ_BASE_ADDRESS; static inline void _glFlushBuffer() { TRACE(); - /* Wait for both store queues to complete */ - sq = (uint32_t*) 0xe0000000; - sq[0] = sq[8] = 0; + sq_wait(); } static inline void _glPushHeaderOrVertex(Vertex* v) { TRACE(); - +#if 0 uint32_t* s = (uint32_t*) v; sq[0] = *(s++); sq[1] = *(s++); @@ -104,6 +104,8 @@ static inline void _glPushHeaderOrVertex(Vertex* v) { sq[7] = *(s++); __asm__("pref @%0" : : "r"(sq)); sq += 8; +#endif + pvr_sq_load(NULL, v, sizeof(Vertex), PVR_TA_INPUT); } static inline void _glClipEdge(const Vertex* const v1, const Vertex* const v2, Vertex* vout) { From 32ecb843a2efc657d39697a666eb128dcca0b001 Mon Sep 17 00:00:00 2001 From: Falco Girgis Date: Tue, 30 Jan 2024 19:44:40 -0600 Subject: [PATCH 02/72] next try. --- GL/platforms/sh4.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/GL/platforms/sh4.c b/GL/platforms/sh4.c index 6fa971c..19947ef 100644 --- a/GL/platforms/sh4.c +++ b/GL/platforms/sh4.c @@ -11,7 +11,7 @@ #define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0) -#define SQ_BASE_ADDRESS (void*) 0xe0000000 +//#define SQ_BASE_ADDRESS (void*) 0xe0000000 GL_FORCE_INLINE bool glIsVertex(const float flags) { @@ -105,7 +105,7 @@ static inline void _glPushHeaderOrVertex(Vertex* v) { __asm__("pref @%0" : : "r"(sq)); sq += 8; #endif - pvr_sq_load(NULL, v, sizeof(Vertex), PVR_TA_INPUT); + pvr_sq_load(NULL, v, sizeof(Vertex), PVR_DMA_TA); } static inline void _glClipEdge(const Vertex* const v1, const Vertex* const v2, Vertex* vout) { @@ -136,7 +136,7 @@ static inline void _glClipEdge(const Vertex* const v1, const Vertex* const v2, V #define SPAN_SORT_CFG 0x005F8030 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; +//static volatile uint32_t *QACR = (uint32_t*) 0xFF000038; void SceneListSubmit(Vertex* v2, int n) { TRACE(); @@ -155,7 +155,7 @@ void SceneListSubmit(Vertex* v2, int n) { *PVR_LMMODE1 = 0; //Set QACR registers - QACR[1] = QACR[0] = 0x11; + // QACR[1] = QACR[0] = 0x11; #if CLIP_DEBUG Vertex* vertex = (Vertex*) src; @@ -168,7 +168,7 @@ void SceneListSubmit(Vertex* v2, int n) { uint8_t visible_mask = 0; uint8_t counter = 0; - sq = SQ_BASE_ADDRESS; + //sq = SQ_BASE_ADDRESS; for(int i = 0; i < n; ++i, ++v2) { PREFETCH(v2 + 1); From b9cdfb2e35446ad9e4b967087a287afadaa195be Mon Sep 17 00:00:00 2001 From: Falco Girgis Date: Tue, 30 Jan 2024 19:45:17 -0600 Subject: [PATCH 03/72] next try --- GL/platforms/sh4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GL/platforms/sh4.c b/GL/platforms/sh4.c index 19947ef..c21f799 100644 --- a/GL/platforms/sh4.c +++ b/GL/platforms/sh4.c @@ -82,7 +82,7 @@ GL_FORCE_INLINE void _glPerspectiveDivideVertex(Vertex* vertex, const float h) { } -volatile uint32_t *sq = SQ_BASE_ADDRESS; +//volatile uint32_t *sq = SQ_BASE_ADDRESS; static inline void _glFlushBuffer() { TRACE(); From c25a5cddcb8e62a19049f03d85c6eec7b063e5b5 Mon Sep 17 00:00:00 2001 From: Falco Girgis Date: Tue, 30 Jan 2024 19:52:56 -0600 Subject: [PATCH 04/72] Next attempt. --- GL/platforms/sh4.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/GL/platforms/sh4.c b/GL/platforms/sh4.c index c21f799..feaa930 100644 --- a/GL/platforms/sh4.c +++ b/GL/platforms/sh4.c @@ -11,7 +11,7 @@ #define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0) -//#define SQ_BASE_ADDRESS (void*) 0xe0000000 +#define SQ_BASE_ADDRESS (void*) 0xe0000000 GL_FORCE_INLINE bool glIsVertex(const float flags) { @@ -82,7 +82,7 @@ GL_FORCE_INLINE void _glPerspectiveDivideVertex(Vertex* vertex, const float h) { } -//volatile uint32_t *sq = SQ_BASE_ADDRESS; +volatile uint32_t *sq = SQ_BASE_ADDRESS; static inline void _glFlushBuffer() { TRACE(); @@ -105,7 +105,7 @@ static inline void _glPushHeaderOrVertex(Vertex* v) { __asm__("pref @%0" : : "r"(sq)); sq += 8; #endif - pvr_sq_load(NULL, v, sizeof(Vertex), PVR_DMA_TA); + sq_fast_cpy(SQ_MASK_DEST(PVR_TA_INPUT), v, 1); } static inline void _glClipEdge(const Vertex* const v1, const Vertex* const v2, Vertex* vout) { @@ -136,7 +136,7 @@ static inline void _glClipEdge(const Vertex* const v1, const Vertex* const v2, V #define SPAN_SORT_CFG 0x005F8030 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; +static volatile uint32_t *QACR = (uint32_t*) 0xFF000038; void SceneListSubmit(Vertex* v2, int n) { TRACE(); @@ -155,7 +155,7 @@ void SceneListSubmit(Vertex* v2, int n) { *PVR_LMMODE1 = 0; //Set QACR registers - // QACR[1] = QACR[0] = 0x11; + QACR[1] = QACR[0] = 0x11; #if CLIP_DEBUG Vertex* vertex = (Vertex*) src; @@ -168,7 +168,8 @@ void SceneListSubmit(Vertex* v2, int n) { uint8_t visible_mask = 0; uint8_t counter = 0; - //sq = SQ_BASE_ADDRESS; + sq = SQ_BASE_ADDRESS; + sq_lock(); for(int i = 0; i < n; ++i, ++v2) { PREFETCH(v2 + 1); @@ -454,6 +455,8 @@ void SceneListSubmit(Vertex* v2, int n) { } _glFlushBuffer(); + + sq_unlock(); } void SceneListFinish() { From 9586eefee991c7e7b335668fd4f72520859d3735 Mon Sep 17 00:00:00 2001 From: Falco Girgis Date: Tue, 30 Jan 2024 19:55:05 -0600 Subject: [PATCH 05/72] Next attempt. --- GL/platforms/sh4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GL/platforms/sh4.c b/GL/platforms/sh4.c index feaa930..da6c544 100644 --- a/GL/platforms/sh4.c +++ b/GL/platforms/sh4.c @@ -169,7 +169,7 @@ void SceneListSubmit(Vertex* v2, int n) { uint8_t counter = 0; sq = SQ_BASE_ADDRESS; - sq_lock(); + sq_lock((void*)PVR_TA_INPUT); for(int i = 0; i < n; ++i, ++v2) { PREFETCH(v2 + 1); From 0be2911e0b4969b45f259af6263f39e2f896f3b2 Mon Sep 17 00:00:00 2001 From: Falco Girgis Date: Tue, 30 Jan 2024 20:41:34 -0600 Subject: [PATCH 06/72] Trying to batch shit better. --- GL/platforms/sh4.c | 112 ++++++++++++++++++++++----------------------- 1 file changed, 54 insertions(+), 58 deletions(-) diff --git a/GL/platforms/sh4.c b/GL/platforms/sh4.c index da6c544..2ac192b 100644 --- a/GL/platforms/sh4.c +++ b/GL/platforms/sh4.c @@ -90,8 +90,9 @@ static inline void _glFlushBuffer() { sq_wait(); } -static inline void _glPushHeaderOrVertex(Vertex* v) { - TRACE(); +static uintptr_t sq_dest_addr = 0; + +static inline void _glPushHeaderOrVertex(Vertex* v, size_t count) { #if 0 uint32_t* s = (uint32_t*) v; sq[0] = *(s++); @@ -105,7 +106,7 @@ static inline void _glPushHeaderOrVertex(Vertex* v) { __asm__("pref @%0" : : "r"(sq)); sq += 8; #endif - sq_fast_cpy(SQ_MASK_DEST(PVR_TA_INPUT), v, 1); + sq_fast_cpy((void*)sq_dest_addr, v, count * sizeof(Vertex));; } static inline void _glClipEdge(const Vertex* const v1, const Vertex* const v2, Vertex* vout) { @@ -169,6 +170,7 @@ void SceneListSubmit(Vertex* v2, int n) { uint8_t counter = 0; sq = SQ_BASE_ADDRESS; + sq_dest_addr = SQ_MASK_DEST(PVR_TA_INPUT) sq_lock((void*)PVR_TA_INPUT); for(int i = 0; i < n; ++i, ++v2) { @@ -206,19 +208,15 @@ void SceneListSubmit(Vertex* v2, int n) { case 15: /* All visible, but final vertex in strip */ { _glPerspectiveDivideVertex(v0, h); - _glPushHeaderOrVertex(v0); - _glPerspectiveDivideVertex(v1, h); - _glPushHeaderOrVertex(v1); - _glPerspectiveDivideVertex(v2, h); - _glPushHeaderOrVertex(v2); + _glPushHeaderOrVertex(v0, 3); } break; case 7: /* All visible, push the first vertex and move on */ _glPerspectiveDivideVertex(v0, h); - _glPushHeaderOrVertex(v0); + _glPushHeaderOrVertex(v0, 1); break; case 9: /* First vertex was visible, last in strip */ @@ -234,13 +232,12 @@ void SceneListSubmit(Vertex* v2, int n) { b->flags = GPU_CMD_VERTEX_EOL; _glPerspectiveDivideVertex(v0, h); - _glPushHeaderOrVertex(v0); + _glPushHeaderOrVertex(v0, 1); _glPerspectiveDivideVertex(a, h); - _glPushHeaderOrVertex(a); - _glPerspectiveDivideVertex(b, h); - _glPushHeaderOrVertex(b); + _glPushHeaderOrVertex(a, 2); + // _glPushHeaderOrVertex(b); } break; case 1: @@ -257,13 +254,12 @@ void SceneListSubmit(Vertex* v2, int n) { b->flags = GPU_CMD_VERTEX; _glPerspectiveDivideVertex(v0, h); - _glPushHeaderOrVertex(v0); + _glPushHeaderOrVertex(v0, 1); _glPerspectiveDivideVertex(a, h); - _glPushHeaderOrVertex(a); - _glPerspectiveDivideVertex(b, h); - _glPushHeaderOrVertex(b); + + _glPushHeaderOrVertex(a, 2); _glPushHeaderOrVertex(b); } break; @@ -274,8 +270,8 @@ void SceneListSubmit(Vertex* v2, int n) { { Vertex __attribute__((aligned(32))) scratch[3]; Vertex* a = &scratch[0]; - Vertex* b = &scratch[1]; - Vertex* c = &scratch[2]; + Vertex* c = &scratch[1]; + Vertex* b = &scratch[2]; memcpy_vertex(c, v1); @@ -286,13 +282,13 @@ void SceneListSubmit(Vertex* v2, int n) { b->flags = v2->flags; _glPerspectiveDivideVertex(a, h); - _glPushHeaderOrVertex(a); - _glPerspectiveDivideVertex(c, h); - _glPushHeaderOrVertex(c); - _glPerspectiveDivideVertex(b, h); - _glPushHeaderOrVertex(b); + + + _glPushHeaderOrVertex(a, 3); + //_glPushHeaderOrVertex(c); + //_glPushHeaderOrVertex(b); } break; case 11: @@ -309,20 +305,20 @@ void SceneListSubmit(Vertex* v2, int n) { b->flags = GPU_CMD_VERTEX; _glPerspectiveDivideVertex(v0, h); - _glPushHeaderOrVertex(v0); + _glPushHeaderOrVertex(v0, 1); _glClipEdge(v1, v2, a); a->flags = v2->flags; _glPerspectiveDivideVertex(c, h); - _glPushHeaderOrVertex(c); + _glPushHeaderOrVertex(c, 1); _glPerspectiveDivideVertex(b, h); - _glPushHeaderOrVertex(b); + _glPushHeaderOrVertex(b, 1); _glPerspectiveDivideVertex(a, h); - _glPushHeaderOrVertex(c); - _glPushHeaderOrVertex(a); + _glPushHeaderOrVertex(c, 1); + _glPushHeaderOrVertex(a, 1); } break; case 12: @@ -342,26 +338,25 @@ void SceneListSubmit(Vertex* v2, int n) { _glClipEdge(v1, v2, b); b->flags = GPU_CMD_VERTEX; - _glPerspectiveDivideVertex(a, h); - _glPushHeaderOrVertex(a); + _glPerspectiveDivideVertex(a, h); + _glPerspectiveDivideVertex(b, h); + _glPerspectiveDivideVertex(c, h); if(counter % 2 == 1) { _glPushHeaderOrVertex(a); } + _glPushHeaderOrVertex(a, 3); - _glPerspectiveDivideVertex(b, h); - _glPushHeaderOrVertex(b); - - _glPerspectiveDivideVertex(c, h); - _glPushHeaderOrVertex(c); + // _glPushHeaderOrVertex(b); + //_glPushHeaderOrVertex(c); } break; case 13: { Vertex __attribute__((aligned(32))) scratch[3]; Vertex* a = &scratch[0]; - Vertex* b = &scratch[1]; - Vertex* c = &scratch[2]; + Vertex* c = &scratch[1]; + Vertex* b = &scratch[2]; memcpy_vertex(c, v2); c->flags = GPU_CMD_VERTEX; @@ -373,26 +368,25 @@ void SceneListSubmit(Vertex* v2, int n) { b->flags = GPU_CMD_VERTEX; _glPerspectiveDivideVertex(v0, h); - _glPushHeaderOrVertex(v0); + _glPushHeaderOrVertex(v0, 1); _glPerspectiveDivideVertex(a, h); - _glPushHeaderOrVertex(a); - _glPerspectiveDivideVertex(c, h); - _glPushHeaderOrVertex(c); _glPerspectiveDivideVertex(b, h); - _glPushHeaderOrVertex(b); + _glPushHeaderOrVertex(a, 3); + //_glPushHeaderOrVertex(c); + //_glPushHeaderOrVertex(b); c->flags = GPU_CMD_VERTEX_EOL; - _glPushHeaderOrVertex(c); + _glPushHeaderOrVertex(c, 1); } break; case 5: /* First and third vertex were visible */ { Vertex __attribute__((aligned(32))) scratch[3]; Vertex* a = &scratch[0]; - Vertex* b = &scratch[1]; - Vertex* c = &scratch[2]; + Vertex* c = &scratch[1]; + Vertex* b = &scratch[2]; memcpy_vertex(c, v2); c->flags = GPU_CMD_VERTEX; @@ -404,16 +398,17 @@ void SceneListSubmit(Vertex* v2, int n) { b->flags = GPU_CMD_VERTEX; _glPerspectiveDivideVertex(v0, h); - _glPushHeaderOrVertex(v0); + _glPushHeaderOrVertex(v0, 1); _glPerspectiveDivideVertex(a, h); - _glPushHeaderOrVertex(a); - _glPerspectiveDivideVertex(c, h); - _glPushHeaderOrVertex(c); _glPerspectiveDivideVertex(b, h); - _glPushHeaderOrVertex(b); - _glPushHeaderOrVertex(c); + _glPushHeaderOrVertex(a, 3); + + //_glPushHeaderOrVertex(c); + + //_glPushHeaderOrVertex(b); + _glPushHeaderOrVertex(c, 1); } break; case 14: @@ -435,17 +430,18 @@ void SceneListSubmit(Vertex* v2, int n) { b->flags = GPU_CMD_VERTEX; _glPerspectiveDivideVertex(a, h); - _glPushHeaderOrVertex(a); + _glPushHeaderOrVertex(a, 1); _glPerspectiveDivideVertex(c, h); - _glPushHeaderOrVertex(c); + _glPushHeaderOrVertex(c, 1); _glPerspectiveDivideVertex(b, h); - _glPushHeaderOrVertex(b); - _glPushHeaderOrVertex(c); - _glPerspectiveDivideVertex(d, h); - _glPushHeaderOrVertex(d); + _glPushHeaderOrVertex(b, 3); + //_glPushHeaderOrVertex(c); + + + //_glPushHeaderOrVertex(d); } break; case 8: From e8a60bc94ac340f1b5dec3cfb3d588127ce69443 Mon Sep 17 00:00:00 2001 From: Falco Girgis Date: Tue, 30 Jan 2024 20:43:30 -0600 Subject: [PATCH 07/72] Fixing build issues --- GL/platforms/sh4.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/GL/platforms/sh4.c b/GL/platforms/sh4.c index 2ac192b..06058b4 100644 --- a/GL/platforms/sh4.c +++ b/GL/platforms/sh4.c @@ -170,7 +170,7 @@ void SceneListSubmit(Vertex* v2, int n) { uint8_t counter = 0; sq = SQ_BASE_ADDRESS; - sq_dest_addr = SQ_MASK_DEST(PVR_TA_INPUT) + sq_dest_addr = SQ_MASK_DEST(PVR_TA_INPUT); sq_lock((void*)PVR_TA_INPUT); for(int i = 0; i < n; ++i, ++v2) { @@ -189,7 +189,7 @@ void SceneListSubmit(Vertex* v2, int n) { } break; default: - _glPushHeaderOrVertex(v2); + _glPushHeaderOrVertex(v2, 1); counter = 0; continue; }; @@ -260,7 +260,7 @@ void SceneListSubmit(Vertex* v2, int n) { _glPerspectiveDivideVertex(b, h); _glPushHeaderOrVertex(a, 2); - _glPushHeaderOrVertex(b); + //_glPushHeaderOrVertex(b); } break; case 10: @@ -343,7 +343,7 @@ void SceneListSubmit(Vertex* v2, int n) { _glPerspectiveDivideVertex(c, h); if(counter % 2 == 1) { - _glPushHeaderOrVertex(a); + _glPushHeaderOrVertex(a, 1); } _glPushHeaderOrVertex(a, 3); From 3420f0d0c6619a7403dd37f64aa4caaef7ab20c2 Mon Sep 17 00:00:00 2001 From: Falco Girgis Date: Wed, 31 Jan 2024 01:56:01 -0600 Subject: [PATCH 08/72] Adjusting vertex buffers. --- 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 06058b4..f145173 100644 --- a/GL/platforms/sh4.c +++ b/GL/platforms/sh4.c @@ -6,7 +6,7 @@ #define CLIP_DEBUG 0 -#define PVR_VERTEX_BUF_SIZE 2560 * 256 +#define PVR_VERTEX_BUF_SIZE 2048 * 256 * 2 #define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0) @@ -29,7 +29,8 @@ void InitGPU(_Bool autosort, _Bool fsaa) { PVR_VERTEX_BUF_SIZE, /* Vertex buffer size */ 0, /* No DMA */ fsaa, /* No FSAA */ - (autosort) ? 0 : 1 /* Disable translucent auto-sorting to match traditional GL */ + (autosort) ? 0 : 1 /* Disable translucent auto-sorting to match traditional GL */, + .opb_overflow_count = 1 }; pvr_init(¶ms); From 4033e9c23aba17949c8b65ae6af1ff1a5824ce11 Mon Sep 17 00:00:00 2001 From: Falco Girgis Date: Wed, 31 Jan 2024 01:59:46 -0600 Subject: [PATCH 09/72] Submitted wrong size to sq_fast_cpy() --- GL/platforms/sh4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GL/platforms/sh4.c b/GL/platforms/sh4.c index f145173..4cdfc25 100644 --- a/GL/platforms/sh4.c +++ b/GL/platforms/sh4.c @@ -107,7 +107,7 @@ static inline void _glPushHeaderOrVertex(Vertex* v, size_t count) { __asm__("pref @%0" : : "r"(sq)); sq += 8; #endif - sq_fast_cpy((void*)sq_dest_addr, v, count * sizeof(Vertex));; + sq_fast_cpy((void*)sq_dest_addr, v, count); } static inline void _glClipEdge(const Vertex* const v1, const Vertex* const v2, Vertex* vout) { From 313341f93df64c7b9a396db2c1a0f4596451bc1e Mon Sep 17 00:00:00 2001 From: Falco Girgis Date: Wed, 31 Jan 2024 02:50:01 -0600 Subject: [PATCH 10/72] Trying without prefetching. --- GL/platforms/sh4.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GL/platforms/sh4.h b/GL/platforms/sh4.h index 46c3513..698a8c9 100644 --- a/GL/platforms/sh4.h +++ b/GL/platforms/sh4.h @@ -24,7 +24,7 @@ #define GL_FORCE_INLINE static GL_INLINE_DEBUG #endif -#define PREFETCH(addr) __builtin_prefetch((addr)) +#define PREFETCH(addr) ((void)addr)//__builtin_prefetch((addr)) GL_FORCE_INLINE void* memcpy_fast(void *dest, const void *src, size_t len) { if(!len) { From 8d1ce547f562162f6115c1ee66a0147a65ae1d27 Mon Sep 17 00:00:00 2001 From: Falco Girgis Date: Wed, 31 Jan 2024 02:51:51 -0600 Subject: [PATCH 11/72] Screwed up prefetch macro. --- GL/platforms/sh4.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/GL/platforms/sh4.h b/GL/platforms/sh4.h index 698a8c9..9e51f78 100644 --- a/GL/platforms/sh4.h +++ b/GL/platforms/sh4.h @@ -24,7 +24,8 @@ #define GL_FORCE_INLINE static GL_INLINE_DEBUG #endif -#define PREFETCH(addr) ((void)addr)//__builtin_prefetch((addr)) +#define PREFETCH(addr) (void)0 +//((void)addr)//__builtin_prefetch((addr)) GL_FORCE_INLINE void* memcpy_fast(void *dest, const void *src, size_t len) { if(!len) { From d4a83ff23501559d489d35e42c27e4c6836909f5 Mon Sep 17 00:00:00 2001 From: Falco Girgis Date: Wed, 31 Jan 2024 14:46:49 -0600 Subject: [PATCH 12/72] Fixed a double promotion, put back prefetching. --- GL/matrix.c | 6 +++--- GL/platforms/sh4.h | 3 +-- 2 files changed, 4 insertions(+), 5 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); diff --git a/GL/platforms/sh4.h b/GL/platforms/sh4.h index 9e51f78..46c3513 100644 --- a/GL/platforms/sh4.h +++ b/GL/platforms/sh4.h @@ -24,8 +24,7 @@ #define GL_FORCE_INLINE static GL_INLINE_DEBUG #endif -#define PREFETCH(addr) (void)0 -//((void)addr)//__builtin_prefetch((addr)) +#define PREFETCH(addr) __builtin_prefetch((addr)) GL_FORCE_INLINE void* memcpy_fast(void *dest, const void *src, size_t len) { if(!len) { From 04c2fcceaee4b02f8e4896422bf512b2e5e9d96a Mon Sep 17 00:00:00 2001 From: Falco Girgis Date: Wed, 31 Jan 2024 14:59:58 -0600 Subject: [PATCH 13/72] Getting rid of prefetching. --- GL/platforms/sh4.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/GL/platforms/sh4.h b/GL/platforms/sh4.h index 46c3513..4cdf85a 100644 --- a/GL/platforms/sh4.h +++ b/GL/platforms/sh4.h @@ -24,7 +24,8 @@ #define GL_FORCE_INLINE static GL_INLINE_DEBUG #endif -#define PREFETCH(addr) __builtin_prefetch((addr)) +#define PREFETCH(addr) (void) 0 +//__builtin_prefetch((addr)) GL_FORCE_INLINE void* memcpy_fast(void *dest, const void *src, size_t len) { if(!len) { From 5fd6e510286c9cc55ea2a2b5784f5d000dc95d2e Mon Sep 17 00:00:00 2001 From: Falco Girgis Date: Wed, 10 Apr 2024 01:09:29 -0500 Subject: [PATCH 14/72] Readded prefetching. --- GL/platforms/sh4.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/GL/platforms/sh4.h b/GL/platforms/sh4.h index 4cdf85a..46c3513 100644 --- a/GL/platforms/sh4.h +++ b/GL/platforms/sh4.h @@ -24,8 +24,7 @@ #define GL_FORCE_INLINE static GL_INLINE_DEBUG #endif -#define PREFETCH(addr) (void) 0 -//__builtin_prefetch((addr)) +#define PREFETCH(addr) __builtin_prefetch((addr)) GL_FORCE_INLINE void* memcpy_fast(void *dest, const void *src, size_t len) { if(!len) { From 60773e9db89692f9096178414e60bdbc642ec679 Mon Sep 17 00:00:00 2001 From: Luke Benstead Date: Sun, 21 Jul 2024 10:28:13 +0000 Subject: [PATCH 15/72] Fix alpha values --- GL/draw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GL/draw.c b/GL/draw.c index 01d9cf7..3d2d082 100644 --- a/GL/draw.c +++ b/GL/draw.c @@ -210,14 +210,14 @@ static void _readVertexData3fARGB(const GLubyte* in, GLubyte* output) { output[R8IDX] = (GLubyte) clamp(input[0] * 255.0f, 0, 255); output[G8IDX] = (GLubyte) clamp(input[1] * 255.0f, 0, 255); output[B8IDX] = (GLubyte) clamp(input[2] * 255.0f, 0, 255); - output[A8IDX] = 1.0f; + output[A8IDX] = 255; } static void _readVertexData3ubARGB(const GLubyte* __restrict__ input, GLubyte* __restrict__ output) { output[R8IDX] = input[0]; output[G8IDX] = input[1]; output[B8IDX] = input[2]; - output[A8IDX] = 1.0f; + output[A8IDX] = 255; } static void _readVertexData4ubRevARGB(const GLubyte* __restrict__ input, GLubyte* __restrict__ output) { From 49f2f0917bc95a279d5822c14b7b7e530ffc7129 Mon Sep 17 00:00:00 2001 From: Falco Girgis Date: Wed, 31 Jul 2024 15:36:19 -0500 Subject: [PATCH 16/72] Nehe20 Build Fix + Warnings cleanup for GCC14.1.0. Newest toolchain is bitchier, so I wanted to go ahead and clear up all of the warnings from building GLdc and the various examples... 1) Set CMake CXX standard to 14 instead of 11, since CXXFLAGS were enforcing that language standard anyway. 2) Fixed a bunch of strict aliasing violations in immediate.c: glVertex3f. 3) Removed or commented out lots of unused variables. 4) Fixed some "suggested inner braces on initializer" crap. 5) Fixed a bunch of signed vs unsigned pointer assignments. 6) Fixed several printf() warnings from using %d with int32_t (needs to be %ld for long int). 7) Fixed build issue with Nehe20 from not including kos.h for the KOS_ROMDISK macro. 8) Fixed some signed vs unsigned comparison mismatches in C++ template instantiations within clipping tests. 9) --- CMakeLists.txt | 2 +- GL/immediate.c | 32 ++++++++++++++-------- GL/state.c | 2 -- samples/blend_test/main.c | 1 - samples/depth_funcs_alpha_testing/gl_png.c | 1 - samples/lerabot01/main.c | 16 +++-------- samples/lights/main.c | 3 +- samples/loadbmp.c | 4 +-- samples/mipmap/main.c | 4 +-- samples/nehe06_4444twid/main.c | 6 ++-- samples/nehe06_vq/main.c | 8 +++--- samples/nehe20/main.c | 7 +++-- samples/paletted/main.c | 3 +- samples/paletted_pcx/main.c | 8 +++--- samples/profiler.c | 2 +- tests/zclip/main.cpp | 14 +++++----- 16 files changed, 54 insertions(+), 59 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0f7f87a..048f894 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,7 +22,7 @@ string(TOUPPER ${BACKEND} BACKEND_UPPER) add_definitions(-DBACKEND_${BACKEND_UPPER}) set(CMAKE_C_STANDARD 99) -set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD 14) include_directories(include) diff --git a/GL/immediate.c b/GL/immediate.c index afe80c5..d80e194 100644 --- a/GL/immediate.c +++ b/GL/immediate.c @@ -158,6 +158,14 @@ void APIENTRY glColor3fv(const GLfloat* v) { COLOR[B8IDX] = (GLubyte)(v[2] * 255); } +typedef union punned { + GLubyte* byte; + GLfloat* flt; + uint32_t* u32; + void* vptr; + uintptr_t uptr; +} punned_t; + void APIENTRY glVertex3f(GLfloat x, GLfloat y, GLfloat z) { IM_ENABLED_VERTEX_ATTRIBUTES |= VERTEX_ENABLED_FLAG; @@ -170,18 +178,18 @@ void APIENTRY glVertex3f(GLfloat x, GLfloat y, GLfloat z) { IM_ATTRIBS.colour.ptr = IM_ATTRIBS.st.ptr + 8; IM_ATTRIBS.normal.ptr = IM_ATTRIBS.colour.ptr + 4; - uint32_t* dest = (uint32_t*) &vert->x; - *(dest++) = *((uint32_t*) &x); - *(dest++) = *((uint32_t*) &y); - *(dest++) = *((uint32_t*) &z); - *(dest++) = *((uint32_t*) &UV_COORD[0]); - *(dest++) = *((uint32_t*) &UV_COORD[1]); - *(dest++) = *((uint32_t*) &ST_COORD[0]); - *(dest++) = *((uint32_t*) &ST_COORD[1]); - *(dest++) = *((uint32_t*) COLOR); - *(dest++) = *((uint32_t*) &NORMAL[0]); - *(dest++) = *((uint32_t*) &NORMAL[1]); - *(dest++) = *((uint32_t*) &NORMAL[2]); + punned_t dest = { .flt = &vert->x }; + *(dest.flt++) = x; + *(dest.flt++) = y; + *(dest.flt++) = z; + *(dest.flt++) = UV_COORD[0]; + *(dest.flt++) = UV_COORD[1]; + *(dest.flt++) = ST_COORD[0]; + *(dest.flt++) = ST_COORD[1]; + *(dest.u32++) = *((uint32_t*)(void*) COLOR); + *(dest.flt++) = NORMAL[0]; + *(dest.flt++) = NORMAL[1]; + *(dest.flt++) = NORMAL[2]; } void APIENTRY glVertex3fv(const GLfloat* v) { diff --git a/GL/state.c b/GL/state.c index 52f2656..d8b89f2 100644 --- a/GL/state.c +++ b/GL/state.c @@ -80,9 +80,7 @@ static struct { .color_control = GL_SINGLE_COLOR, .color_material_mode = GL_AMBIENT_AND_DIFFUSE, .color_material_mask = AMBIENT_MASK | DIFFUSE_MASK, - .lights = {0}, .enabled_light_count = 0, - .material = {0}, .shade_model = GL_SMOOTH }; diff --git a/samples/blend_test/main.c b/samples/blend_test/main.c index 6fbb795..1303f7f 100644 --- a/samples/blend_test/main.c +++ b/samples/blend_test/main.c @@ -80,7 +80,6 @@ void DrawGLScene() { const float RED [] = {1.0, 0, 0, 0.5}; const float BLUE [] = {0.0, 0, 1, 0.5}; - const float NONE [] = {0, 0, 0, 0}; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer diff --git a/samples/depth_funcs_alpha_testing/gl_png.c b/samples/depth_funcs_alpha_testing/gl_png.c index 686035c..5415638 100644 --- a/samples/depth_funcs_alpha_testing/gl_png.c +++ b/samples/depth_funcs_alpha_testing/gl_png.c @@ -48,7 +48,6 @@ int dtex_to_gl_texture(texture *tex, char* filename) { GLboolean twiddled = (header.type & (1 << 26)) < 1; GLboolean compressed = (header.type & (1 << 30)) > 0; GLboolean mipmapped = (header.type & (1 << 31)) > 0; - GLboolean strided = (header.type & (1 << 25)) > 0; GLuint format = (header.type >> 27) & 0b111; image->data = (char *) malloc (header.size); diff --git a/samples/lerabot01/main.c b/samples/lerabot01/main.c index 71ca463..d16c0a5 100644 --- a/samples/lerabot01/main.c +++ b/samples/lerabot01/main.c @@ -26,7 +26,7 @@ KOS_INIT_ROMDISK(romdisk); float xrot, yrot, zrot; /* storage for one texture */ -int texture[1]; +GLuint texture[1]; // Load Bitmaps And Convert To Textures void LoadGLTextures() { @@ -81,7 +81,7 @@ void InitGL(int Width, int Height) // We call this right after our OpenG GLfloat l1_pos[] = {5.0, 0.0, 1.0, 1.0}; GLfloat l1_diff[] = {1.0, 0.0, 0.0, 1.0}; - GLfloat l1_amb[] = {0.5, 0.5, 0.5, 1.0}; + //GLfloat l1_amb[] = {0.5, 0.5, 0.5, 1.0}; //glLightfv(GL_LIGHT1, GL_AMBIENT, l1_amb); glLightfv(GL_LIGHT1, GL_DIFFUSE, l1_diff); @@ -93,7 +93,7 @@ void InitGL(int Width, int Height) // We call this right after our OpenG GLfloat l2_pos[] = {0.0, 15.0, 1.0, 1.0}; GLfloat l2_dir[] = {0.0, -1.0, 0.0}; GLfloat l2_diff[] = {0.5, 0.5, 0.0, 1.0}; - GLfloat l2_amb[] = {0.5, 0.5, 0.5, 1.0}; + //GLfloat l2_amb[] = {0.5, 0.5, 0.5, 1.0}; glEnable(GL_LIGHT2); glLightfv(GL_LIGHT2, GL_DIFFUSE, l2_diff); @@ -145,7 +145,7 @@ void DrawTexturedQuad(int tex, float x, float y, float z) GLfloat y0 = y - texH / 2; GLfloat x1 = x + texW / 2; GLfloat y1 = y + texH / 2; - GLfloat color[] = {1.0f, 1.0f, 1.0f, 1.0f}; + //GLfloat color[] = {1.0f, 1.0f, 1.0f, 1.0f}; GLfloat mat_ambient[] = {1.0f, 1.0f, 1.0f, 1.0f}; GLfloat vertex_data[] = { @@ -172,14 +172,6 @@ void DrawTexturedQuad(int tex, float x, float y, float z) 0.0, 0.0, 1.0 }; - GLfloat color_data[] = { - /* 2D Coordinate, texture coordinate */ - color[0], color[1], color[2], color[3], - color[0], color[1], color[2], color[3], - color[0], color[1], color[2], color[3], - color[0], color[1], color[2], color[3] - }; - //GLint indices[] = {0,1,2,3,2,3}; glEnable(GL_TEXTURE_2D); diff --git a/samples/lights/main.c b/samples/lights/main.c index afd048d..223bd86 100644 --- a/samples/lights/main.c +++ b/samples/lights/main.c @@ -24,8 +24,7 @@ KOS_INIT_ROMDISK(romdisk); #include "../loadbmp.h" float xrot, yrot, zrot; - -int texture[1]; +GLuint texture[1]; void LoadGLTextures() { diff --git a/samples/loadbmp.c b/samples/loadbmp.c index 65bd571..936ba06 100644 --- a/samples/loadbmp.c +++ b/samples/loadbmp.c @@ -35,7 +35,7 @@ int ImageLoad(char *filename, Image *image) { return 0; } image->sizeX = sizeX; - printf("Width of %s: %d\n", filename, sizeX); + printf("Width of %s: %ld\n", filename, sizeX); // read the height if ((i = fread(&sizeY, 4, 1, file)) != 1) { @@ -43,7 +43,7 @@ int ImageLoad(char *filename, Image *image) { return 0; } image->sizeY = sizeY; - printf("Height of %s: %d\n", filename, sizeY); + printf("Height of %s: %ld\n", filename, sizeY); // calculate the size (assuming 24 bits or 3 bytes per pixel). size = image->sizeX * image->sizeY * 3; diff --git a/samples/mipmap/main.c b/samples/mipmap/main.c index ba65d5f..8dc5fca 100644 --- a/samples/mipmap/main.c +++ b/samples/mipmap/main.c @@ -20,9 +20,7 @@ KOS_INIT_ROMDISK(romdisk); #endif #include "../loadbmp.h" - -/* storage for one texture */ -int texture[1]; +GLuint texture[1]; // Load Bitmaps And Convert To Textures void LoadGLTextures() { diff --git a/samples/nehe06_4444twid/main.c b/samples/nehe06_4444twid/main.c index 3cc58d5..f290c6f 100644 --- a/samples/nehe06_4444twid/main.c +++ b/samples/nehe06_4444twid/main.c @@ -62,7 +62,7 @@ int ImageLoad(char *filename, Image *image) { GLboolean twiddled = (header.type & (1 << 26)) < 1; GLboolean compressed = (header.type & (1 << 30)) > 0; GLboolean mipmapped = (header.type & (1 << 31)) > 0; - GLboolean strided = (header.type & (1 << 25)) > 0; + //GLboolean strided = (header.type & (1 << 25)) > 0; GLuint format = (header.type >> 27) & 0b111; image->data = (char *) malloc (header.size); @@ -70,8 +70,8 @@ int ImageLoad(char *filename, Image *image) { image->sizeY = header.height; image->dataSize = header.size; - GLuint expected = 2 * header.width * header.height; - GLuint ratio = (GLuint) (((GLfloat) expected) / ((GLfloat) header.size)); + //GLuint expected = 2 * header.width * header.height; + //GLuint ratio = (GLuint) (((GLfloat) expected) / ((GLfloat) header.size)); fread(image->data, image->dataSize, 1, file); fclose(file); diff --git a/samples/nehe06_vq/main.c b/samples/nehe06_vq/main.c index cf2156e..754f458 100644 --- a/samples/nehe06_vq/main.c +++ b/samples/nehe06_vq/main.c @@ -22,7 +22,7 @@ KOS_INIT_ROMDISK(romdisk); float xrot, yrot, zrot; /* storage for one texture */ -int texture[1]; +GLuint texture[1]; /* Image type - contains height, width, and data */ struct Image { @@ -59,7 +59,7 @@ int ImageLoad(char *filename, Image *image) { GLboolean twiddled = (header.type & (1 << 26)) < 1; GLboolean compressed = (header.type & (1 << 30)) > 0; GLboolean mipmapped = (header.type & (1 << 31)) > 0; - GLboolean strided = (header.type & (1 << 25)) > 0; + //GLboolean strided = (header.type & (1 << 25)) > 0; GLuint format = (header.type >> 27) & 0b111; image->data = (char *) malloc (header.size); @@ -67,8 +67,8 @@ int ImageLoad(char *filename, Image *image) { image->sizeY = header.height; image->dataSize = header.size; - GLuint expected = 2 * header.width * header.height; - GLuint ratio = (GLuint) (((GLfloat) expected) / ((GLfloat) header.size)); + //GLuint expected = 2 * header.width * header.height; + //GLuint ratio = (GLuint) (((GLfloat) expected) / ((GLfloat) header.size)); fread(image->data, image->dataSize, 1, file); fclose(file); diff --git a/samples/nehe20/main.c b/samples/nehe20/main.c index 8050dbd..54c7825 100644 --- a/samples/nehe20/main.c +++ b/samples/nehe20/main.c @@ -11,6 +11,11 @@ #include #include + +#ifdef __DREAMCAST__ +#include +#endif + #define FPS 60 uint32_t waittime = 1000.0f/FPS; uint32_t framestarttime = 0; @@ -227,8 +232,6 @@ int DrawGLScene(GLvoid) // Here's Where We Do All The Drawing int main(int argc, char *argv[]) { - BOOL done=FALSE; // Bool Variable To Exit Loop - glKosInit(); InitGL(); diff --git a/samples/paletted/main.c b/samples/paletted/main.c index 7b88cf3..50fbdf3 100644 --- a/samples/paletted/main.c +++ b/samples/paletted/main.c @@ -22,8 +22,7 @@ KOS_INIT_ROMDISK(romdisk); /* floats for x rotation, y rotation, z rotation */ float xrot, yrot, zrot; -/* storage for one texture */ -int texture[1]; +GLuint texture[1]; typedef struct { unsigned int height; diff --git a/samples/paletted_pcx/main.c b/samples/paletted_pcx/main.c index e397ab7..a01744a 100644 --- a/samples/paletted_pcx/main.c +++ b/samples/paletted_pcx/main.c @@ -41,7 +41,7 @@ /* floats for x rotation, y rotation, z rotation */ float xrot, yrot, zrot; -int textures[3]; +GLuint textures[3]; typedef struct { uint32_t height; @@ -272,7 +272,7 @@ int BMP_GetPalette(FILE *pFile) bitCount = BmpInfoHeader.ClrImportant * sizeof(RGB_QUAD); if (fread(BmpRgbQuad, 1, bitCount, pFile) != bitCount){ - fprintf(stderr, "Failed to read palette: %d\n", bitCount); + fprintf(stderr, "Failed to read palette: %ld\n", bitCount); return 0; } @@ -293,7 +293,7 @@ int BMP_GetPalette(FILE *pFile) int BMP_Depack(FILE *pFile,char *pZone) { char PadRead[4]; - int32_t i, j, Offset, PadSize, pix, c; + int32_t i, j, Offset, PadSize, c; if (BmpInfoHeader.Compression != BMP_BI_RGB) return 0; @@ -356,7 +356,7 @@ int LoadPalettedBMP(const char* filename, Image* image) } /* store palette information */ - image->palette = BmpPal; + image->palette = (char*)BmpPal; image->palette_width = 16; diff --git a/samples/profiler.c b/samples/profiler.c index c44c3c9..cefc81a 100644 --- a/samples/profiler.c +++ b/samples/profiler.c @@ -287,7 +287,7 @@ static bool write_samples(const char* path) { root = ARCS; for(int i = 0; i < BUCKET_SIZE; ++i) { if(root->pc) { - printf("Incrementing %d for %x. ", (root->pc - lowest_address) / bin_size, (unsigned int) root->pc); + printf("Incrementing %ld for %x. ", (root->pc - lowest_address) / bin_size, (unsigned int) root->pc); bins[(root->pc - lowest_address) / bin_size]++; printf("Now: %d\n", (int) bins[(root->pc - lowest_address) / bin_size]); diff --git a/tests/zclip/main.cpp b/tests/zclip/main.cpp index adada72..42febee 100644 --- a/tests/zclip/main.cpp +++ b/tests/zclip/main.cpp @@ -435,7 +435,7 @@ bool test_clip_case_001() { SceneListSubmit(&data[0], data.size()); - check_equal(sent.size(), 5); + check_equal(sent.size(), 5u); check_equal(sent[0].flags, GPU_CMD_POLYHDR); check_equal(sent[1].flags, GPU_CMD_VERTEX); check_equal(sent[2].flags, GPU_CMD_VERTEX); @@ -461,7 +461,7 @@ bool test_clip_case_010() { SceneListSubmit(&data[0], data.size()); - check_equal(sent.size(), 4); + check_equal(sent.size(), 4u); check_equal(sent[0].flags, GPU_CMD_POLYHDR); check_equal(sent[1].flags, GPU_CMD_VERTEX); check_equal(sent[2].flags, GPU_CMD_VERTEX); @@ -481,7 +481,7 @@ bool test_clip_case_100() { SceneListSubmit(&data[0], data.size()); - check_equal(sent.size(), 5); + check_equal(sent.size(), 5u); check_equal(sent[0].flags, GPU_CMD_POLYHDR); check_equal(sent[1].flags, GPU_CMD_VERTEX); check_equal(sent[2].flags, GPU_CMD_VERTEX); @@ -507,7 +507,7 @@ bool test_clip_case_110() { SceneListSubmit(&data[0], data.size()); - check_equal(sent.size(), 6); + check_equal(sent.size(), 6u); check_equal(sent[0].flags, GPU_CMD_POLYHDR); check_equal(sent[1].flags, GPU_CMD_VERTEX); check_equal(sent[2].flags, GPU_CMD_VERTEX); @@ -530,7 +530,7 @@ bool test_clip_case_011() { SceneListSubmit(&data[0], data.size()); - check_equal(sent.size(), 6); + check_equal(sent.size(), 6u); check_equal(sent[0].flags, GPU_CMD_POLYHDR); check_equal(sent[1].flags, GPU_CMD_VERTEX); check_equal(sent[2].flags, GPU_CMD_VERTEX); @@ -553,7 +553,7 @@ bool test_clip_case_101() { SceneListSubmit(&data[0], data.size()); - check_equal(sent.size(), 6); + check_equal(sent.size(), 6u); check_equal(sent[0].flags, GPU_CMD_POLYHDR); check_equal(sent[1].flags, GPU_CMD_VERTEX); check_equal(sent[2].flags, GPU_CMD_VERTEX); @@ -576,7 +576,7 @@ bool test_clip_case_111() { SceneListSubmit(&data[0], data.size()); - check_equal(sent.size(), 4); + check_equal(sent.size(), 4u); check_equal(sent[0].flags, GPU_CMD_POLYHDR); check_equal(sent[1].flags, GPU_CMD_VERTEX); check_equal(sent[2].flags, GPU_CMD_VERTEX); From 873372995a8433723b3d174022f588d2ec8660ab Mon Sep 17 00:00:00 2001 From: Falco Girgis Date: Wed, 31 Jul 2024 22:59:43 -0500 Subject: [PATCH 17/72] More cleanup. --- GL/platforms/sh4.c | 95 +++++++++++++++------------------------------- 1 file changed, 30 insertions(+), 65 deletions(-) diff --git a/GL/platforms/sh4.c b/GL/platforms/sh4.c index 13bb99d..d7c19de 100644 --- a/GL/platforms/sh4.c +++ b/GL/platforms/sh4.c @@ -13,8 +13,6 @@ #define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0) -#define SQ_BASE_ADDRESS (void*) 0xe0000000 - GL_FORCE_INLINE bool glIsVertex(const float flags) { return flags == GPU_CMD_VERTEX_EOL || flags == GPU_CMD_VERTEX; @@ -75,30 +73,29 @@ GL_FORCE_INLINE float _glFastInvert(float x) { return (1.0f / __builtin_sqrtf(x * x)); } -GL_FORCE_INLINE void _glPerspectiveDivideVertex(Vertex* vertex, const float h) { +GL_FORCE_INLINE void _glPerspectiveDivideVertex(Vertex* vertex, const float h, int count) { TRACE(); - const float f = _glFastInvert(vertex->w); + for(int v = 0; v < count; ++v) { + const float f = _glFastInvert(vertex[v].w); - /* Convert to NDC and apply viewport */ - vertex->xyz[0] = (vertex->xyz[0] * f * 320) + 320; - vertex->xyz[1] = (vertex->xyz[1] * f * -240) + 240; + /* Convert to NDC and apply viewport */ + vertex[v].xyz[0] = (vertex[v].xyz[0] * f * 320) + 320; + vertex[v].xyz[1] = (vertex[v].xyz[1] * f * -240) + 240; - /* Orthographic projections need to use invZ otherwise we lose - the depth information. As w == 1, and clip-space range is -w to +w - we add 1.0 to the Z to bring it into range. We add a little extra to - avoid a divide by zero. - */ - if(vertex->w == 1.0f) { - vertex->xyz[2] = _glFastInvert(1.0001f + vertex->xyz[2]); - } else { - vertex->xyz[2] = f; + /* Orthographic projections need to use invZ otherwise we lose + the depth information. As w == 1, and clip-space range is -w to +w + we add 1.0 to the Z to bring it into range. We add a little extra to + avoid a divide by zero. + */ + if(vertex[v].w == 1.0f) { + vertex[v].xyz[2] = _glFastInvert(1.0001f + vertex[v].xyz[2]); + } else { + vertex[v].xyz[2] = f; + } } } - -volatile uint32_t *sq = SQ_BASE_ADDRESS; - static inline void _glFlushBuffer() { TRACE(); @@ -142,7 +139,6 @@ static inline void _glClipEdge(const Vertex* const v1, const Vertex* const v2, V #define SPAN_SORT_CFG 0x005F8030 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; enum Visible { NONE_VISIBLE = 0, @@ -175,9 +171,6 @@ void SceneListSubmit(Vertex* vertices, int n) { *PVR_LMMODE0 = 0; *PVR_LMMODE1 = 0; - //Set QACR registers - QACR[1] = QACR[0] = 0x11; - #if CLIP_DEBUG fprintf(stderr, "----\n"); @@ -206,7 +199,6 @@ void SceneListSubmit(Vertex* vertices, int n) { int visible_mask = 0; - sq = SQ_BASE_ADDRESS; sq_dest_addr = (uintptr_t)SQ_MASK_DEST(PVR_TA_INPUT); sq_lock((void *)PVR_TA_INPUT); @@ -237,13 +229,8 @@ void SceneListSubmit(Vertex* vertices, int n) { if(visible_mask == ALL_VISIBLE) { SUBMIT_QUEUED_VERTEX(qv.flags); - _glPerspectiveDivideVertex(v0, h); - //_glPushHeaderOrVertex(v0); - + _glPerspectiveDivideVertex(v0, h, 2); v1->flags = GPU_CMD_VERTEX_EOL; - - _glPerspectiveDivideVertex(v1, h); - //_glPushHeaderOrVertex(v1); _glPushHeaderOrVertex(v0, 2); } else { // If the previous triangle wasn't all visible, and we @@ -280,7 +267,7 @@ void SceneListSubmit(Vertex* vertices, int n) { switch(visible_mask) { case ALL_VISIBLE: - _glPerspectiveDivideVertex(v0, h); + _glPerspectiveDivideVertex(v0, h, 1); QUEUE_VERTEX(v0); break; case NONE_VISIBLE: @@ -293,14 +280,10 @@ void SceneListSubmit(Vertex* vertices, int n) { _glClipEdge(v2, v0, b); b->flags = GPU_CMD_VERTEX; - _glPerspectiveDivideVertex(v0, h); + _glPerspectiveDivideVertex(v0, h, 1); _glPushHeaderOrVertex(v0, 1); - _glPerspectiveDivideVertex(a, h); - //_glPushHeaderOrVertex(a); - - _glPerspectiveDivideVertex(b, h); - //_glPushHeaderOrVertex(b); + _glPerspectiveDivideVertex(a, h, 2); _glPushHeaderOrVertex(a, 2); QUEUE_VERTEX(b); @@ -314,13 +297,11 @@ void SceneListSubmit(Vertex* vertices, int n) { _glClipEdge(v1, v2, b); b->flags = v2->flags; - _glPerspectiveDivideVertex(a, h); + _glPerspectiveDivideVertex(a, h, 3); _glPushHeaderOrVertex(a, 1); - _glPerspectiveDivideVertex(c, h); _glPushHeaderOrVertex(c, 1); - _glPerspectiveDivideVertex(b, h); QUEUE_VERTEX(b); break; case THIRD_VISIBLE: @@ -332,15 +313,9 @@ void SceneListSubmit(Vertex* vertices, int n) { _glClipEdge(v1, v2, b); b->flags = GPU_CMD_VERTEX; - _glPerspectiveDivideVertex(a, h); - //_glPushHeaderOrVertex(a); - //_glPushHeaderOrVertex(a); - - _glPerspectiveDivideVertex(b, h); - //_glPushHeaderOrVertex(b); + _glPerspectiveDivideVertex(a, h, 3); _glPushHeaderOrVertex(a, 2); - _glPerspectiveDivideVertex(c, h); QUEUE_VERTEX(c); break; case FIRST_AND_SECOND_VISIBLE: @@ -349,20 +324,16 @@ void SceneListSubmit(Vertex* vertices, int n) { _glClipEdge(v2, v0, b); b->flags = GPU_CMD_VERTEX; - _glPerspectiveDivideVertex(v0, h); + _glPerspectiveDivideVertex(v0, h, 1); _glPushHeaderOrVertex(v0, 1); _glClipEdge(v1, v2, a); a->flags = v2->flags; - _glPerspectiveDivideVertex(c, h); + _glPerspectiveDivideVertex(a, h, 3); + _glPushHeaderOrVertex(c, 1); - _glPerspectiveDivideVertex(b, h); - //_glPushHeaderOrVertex(b); - - _glPerspectiveDivideVertex(a, h); - //_glPushHeaderOrVertex(c); _glPushHeaderOrVertex(b, 2); QUEUE_VERTEX(a); @@ -377,18 +348,13 @@ void SceneListSubmit(Vertex* vertices, int n) { _glClipEdge(v2, v0, b); b->flags = GPU_CMD_VERTEX; - _glPerspectiveDivideVertex(a, h); + _glPerspectiveDivideVertex(a, h, 4); _glPushHeaderOrVertex(a, 1); - _glPerspectiveDivideVertex(c, h); _glPushHeaderOrVertex(c, 1); - _glPerspectiveDivideVertex(b, h); - //_glPushHeaderOrVertex(b); - //_glPushHeaderOrVertex(c); _glPushHeaderOrVertex(b, 2); - _glPerspectiveDivideVertex(d, h); QUEUE_VERTEX(d); break; case FIRST_AND_THIRD_VISIBLE: @@ -401,16 +367,16 @@ void SceneListSubmit(Vertex* vertices, int n) { _glClipEdge(v1, v2, b); b->flags = GPU_CMD_VERTEX; - _glPerspectiveDivideVertex(v0, h); + _glPerspectiveDivideVertex(v0, h, 1); _glPushHeaderOrVertex(v0, 1); - _glPerspectiveDivideVertex(a, h); + _glPerspectiveDivideVertex(a, h, 3); _glPushHeaderOrVertex(a, 1); - _glPerspectiveDivideVertex(c, h); _glPushHeaderOrVertex(c, 1); - _glPerspectiveDivideVertex(b, h); + _glPushHeaderOrVertex(b, 1); + QUEUE_VERTEX(c); break; default: @@ -421,7 +387,6 @@ void SceneListSubmit(Vertex* vertices, int n) { SUBMIT_QUEUED_VERTEX(GPU_CMD_VERTEX_EOL); _glFlushBuffer(); - sq_unlock(); } From b920855b572f84bb6c282b258b3d0532661d6fd7 Mon Sep 17 00:00:00 2001 From: Falco Girgis Date: Wed, 31 Jul 2024 23:08:37 -0500 Subject: [PATCH 18/72] Micro optimizations and clean-up. --- GL/platforms/sh4.c | 95 +++++++++++++++------------------------------- 1 file changed, 30 insertions(+), 65 deletions(-) diff --git a/GL/platforms/sh4.c b/GL/platforms/sh4.c index 13bb99d..d7c19de 100644 --- a/GL/platforms/sh4.c +++ b/GL/platforms/sh4.c @@ -13,8 +13,6 @@ #define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0) -#define SQ_BASE_ADDRESS (void*) 0xe0000000 - GL_FORCE_INLINE bool glIsVertex(const float flags) { return flags == GPU_CMD_VERTEX_EOL || flags == GPU_CMD_VERTEX; @@ -75,30 +73,29 @@ GL_FORCE_INLINE float _glFastInvert(float x) { return (1.0f / __builtin_sqrtf(x * x)); } -GL_FORCE_INLINE void _glPerspectiveDivideVertex(Vertex* vertex, const float h) { +GL_FORCE_INLINE void _glPerspectiveDivideVertex(Vertex* vertex, const float h, int count) { TRACE(); - const float f = _glFastInvert(vertex->w); + for(int v = 0; v < count; ++v) { + const float f = _glFastInvert(vertex[v].w); - /* Convert to NDC and apply viewport */ - vertex->xyz[0] = (vertex->xyz[0] * f * 320) + 320; - vertex->xyz[1] = (vertex->xyz[1] * f * -240) + 240; + /* Convert to NDC and apply viewport */ + vertex[v].xyz[0] = (vertex[v].xyz[0] * f * 320) + 320; + vertex[v].xyz[1] = (vertex[v].xyz[1] * f * -240) + 240; - /* Orthographic projections need to use invZ otherwise we lose - the depth information. As w == 1, and clip-space range is -w to +w - we add 1.0 to the Z to bring it into range. We add a little extra to - avoid a divide by zero. - */ - if(vertex->w == 1.0f) { - vertex->xyz[2] = _glFastInvert(1.0001f + vertex->xyz[2]); - } else { - vertex->xyz[2] = f; + /* Orthographic projections need to use invZ otherwise we lose + the depth information. As w == 1, and clip-space range is -w to +w + we add 1.0 to the Z to bring it into range. We add a little extra to + avoid a divide by zero. + */ + if(vertex[v].w == 1.0f) { + vertex[v].xyz[2] = _glFastInvert(1.0001f + vertex[v].xyz[2]); + } else { + vertex[v].xyz[2] = f; + } } } - -volatile uint32_t *sq = SQ_BASE_ADDRESS; - static inline void _glFlushBuffer() { TRACE(); @@ -142,7 +139,6 @@ static inline void _glClipEdge(const Vertex* const v1, const Vertex* const v2, V #define SPAN_SORT_CFG 0x005F8030 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; enum Visible { NONE_VISIBLE = 0, @@ -175,9 +171,6 @@ void SceneListSubmit(Vertex* vertices, int n) { *PVR_LMMODE0 = 0; *PVR_LMMODE1 = 0; - //Set QACR registers - QACR[1] = QACR[0] = 0x11; - #if CLIP_DEBUG fprintf(stderr, "----\n"); @@ -206,7 +199,6 @@ void SceneListSubmit(Vertex* vertices, int n) { int visible_mask = 0; - sq = SQ_BASE_ADDRESS; sq_dest_addr = (uintptr_t)SQ_MASK_DEST(PVR_TA_INPUT); sq_lock((void *)PVR_TA_INPUT); @@ -237,13 +229,8 @@ void SceneListSubmit(Vertex* vertices, int n) { if(visible_mask == ALL_VISIBLE) { SUBMIT_QUEUED_VERTEX(qv.flags); - _glPerspectiveDivideVertex(v0, h); - //_glPushHeaderOrVertex(v0); - + _glPerspectiveDivideVertex(v0, h, 2); v1->flags = GPU_CMD_VERTEX_EOL; - - _glPerspectiveDivideVertex(v1, h); - //_glPushHeaderOrVertex(v1); _glPushHeaderOrVertex(v0, 2); } else { // If the previous triangle wasn't all visible, and we @@ -280,7 +267,7 @@ void SceneListSubmit(Vertex* vertices, int n) { switch(visible_mask) { case ALL_VISIBLE: - _glPerspectiveDivideVertex(v0, h); + _glPerspectiveDivideVertex(v0, h, 1); QUEUE_VERTEX(v0); break; case NONE_VISIBLE: @@ -293,14 +280,10 @@ void SceneListSubmit(Vertex* vertices, int n) { _glClipEdge(v2, v0, b); b->flags = GPU_CMD_VERTEX; - _glPerspectiveDivideVertex(v0, h); + _glPerspectiveDivideVertex(v0, h, 1); _glPushHeaderOrVertex(v0, 1); - _glPerspectiveDivideVertex(a, h); - //_glPushHeaderOrVertex(a); - - _glPerspectiveDivideVertex(b, h); - //_glPushHeaderOrVertex(b); + _glPerspectiveDivideVertex(a, h, 2); _glPushHeaderOrVertex(a, 2); QUEUE_VERTEX(b); @@ -314,13 +297,11 @@ void SceneListSubmit(Vertex* vertices, int n) { _glClipEdge(v1, v2, b); b->flags = v2->flags; - _glPerspectiveDivideVertex(a, h); + _glPerspectiveDivideVertex(a, h, 3); _glPushHeaderOrVertex(a, 1); - _glPerspectiveDivideVertex(c, h); _glPushHeaderOrVertex(c, 1); - _glPerspectiveDivideVertex(b, h); QUEUE_VERTEX(b); break; case THIRD_VISIBLE: @@ -332,15 +313,9 @@ void SceneListSubmit(Vertex* vertices, int n) { _glClipEdge(v1, v2, b); b->flags = GPU_CMD_VERTEX; - _glPerspectiveDivideVertex(a, h); - //_glPushHeaderOrVertex(a); - //_glPushHeaderOrVertex(a); - - _glPerspectiveDivideVertex(b, h); - //_glPushHeaderOrVertex(b); + _glPerspectiveDivideVertex(a, h, 3); _glPushHeaderOrVertex(a, 2); - _glPerspectiveDivideVertex(c, h); QUEUE_VERTEX(c); break; case FIRST_AND_SECOND_VISIBLE: @@ -349,20 +324,16 @@ void SceneListSubmit(Vertex* vertices, int n) { _glClipEdge(v2, v0, b); b->flags = GPU_CMD_VERTEX; - _glPerspectiveDivideVertex(v0, h); + _glPerspectiveDivideVertex(v0, h, 1); _glPushHeaderOrVertex(v0, 1); _glClipEdge(v1, v2, a); a->flags = v2->flags; - _glPerspectiveDivideVertex(c, h); + _glPerspectiveDivideVertex(a, h, 3); + _glPushHeaderOrVertex(c, 1); - _glPerspectiveDivideVertex(b, h); - //_glPushHeaderOrVertex(b); - - _glPerspectiveDivideVertex(a, h); - //_glPushHeaderOrVertex(c); _glPushHeaderOrVertex(b, 2); QUEUE_VERTEX(a); @@ -377,18 +348,13 @@ void SceneListSubmit(Vertex* vertices, int n) { _glClipEdge(v2, v0, b); b->flags = GPU_CMD_VERTEX; - _glPerspectiveDivideVertex(a, h); + _glPerspectiveDivideVertex(a, h, 4); _glPushHeaderOrVertex(a, 1); - _glPerspectiveDivideVertex(c, h); _glPushHeaderOrVertex(c, 1); - _glPerspectiveDivideVertex(b, h); - //_glPushHeaderOrVertex(b); - //_glPushHeaderOrVertex(c); _glPushHeaderOrVertex(b, 2); - _glPerspectiveDivideVertex(d, h); QUEUE_VERTEX(d); break; case FIRST_AND_THIRD_VISIBLE: @@ -401,16 +367,16 @@ void SceneListSubmit(Vertex* vertices, int n) { _glClipEdge(v1, v2, b); b->flags = GPU_CMD_VERTEX; - _glPerspectiveDivideVertex(v0, h); + _glPerspectiveDivideVertex(v0, h, 1); _glPushHeaderOrVertex(v0, 1); - _glPerspectiveDivideVertex(a, h); + _glPerspectiveDivideVertex(a, h, 3); _glPushHeaderOrVertex(a, 1); - _glPerspectiveDivideVertex(c, h); _glPushHeaderOrVertex(c, 1); - _glPerspectiveDivideVertex(b, h); + _glPushHeaderOrVertex(b, 1); + QUEUE_VERTEX(c); break; default: @@ -421,7 +387,6 @@ void SceneListSubmit(Vertex* vertices, int n) { SUBMIT_QUEUED_VERTEX(GPU_CMD_VERTEX_EOL); _glFlushBuffer(); - sq_unlock(); } From 812ed4a1ee58fecf12013e0f1194a728fada51f8 Mon Sep 17 00:00:00 2001 From: Falco Girgis Date: Wed, 31 Jul 2024 23:29:09 -0500 Subject: [PATCH 19/72] Fixing PC build. --- GL/matrix.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/GL/matrix.c b/GL/matrix.c index bfa2f12..d70a104 100644 --- a/GL/matrix.c +++ b/GL/matrix.c @@ -174,8 +174,13 @@ void APIENTRY glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) { }; float r = DEG2RAD * angle; - float c = fcos(r); - float s = fsin(r); +#ifdef __DREAMCAST__ + float s, c; + fsincos(r, &s, &c); +#else + float c = cosf(r); + float s = sinf(r); +#endif VEC3_NORMALIZE(x, y, z); From 2f26574a4476bd1c57926ac853ecdf3ce08e25b6 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sat, 3 Aug 2024 15:52:56 +1000 Subject: [PATCH 20/72] Combine projection transform and viewport transform together --- GL/matrix.c | 80 ++++++++++++++++++++--------------------- GL/platforms/sh4.c | 7 ++-- GL/platforms/software.c | 80 +++++++++++++++++++---------------------- GL/private.h | 14 -------- 4 files changed, 79 insertions(+), 102 deletions(-) diff --git a/GL/matrix.c b/GL/matrix.c index 2744cb9..5c1fac3 100644 --- a/GL/matrix.c +++ b/GL/matrix.c @@ -15,10 +15,7 @@ GLfloat DEPTH_RANGE_MULTIPLIER_H = (0 + 1) / 2; static Stack __attribute__((aligned(32))) MATRIX_STACKS[4]; // modelview, projection, texture static Matrix4x4 __attribute__((aligned(32))) NORMAL_MATRIX; - -Viewport VIEWPORT = { - 0, 0, 640, 480, 320.0f, 240.0f, 320.0f, 240.0f -}; +static Matrix4x4 __attribute__((aligned(32))) VIEWPORT_MATRIX; static GLenum MATRIX_MODE = GL_MODELVIEW; static GLubyte MATRIX_IDX = 0; @@ -94,12 +91,29 @@ static void transpose(GLfloat* m) { swap(m[11], m[14]); } -static void recalculateNormalMatrix() { +/* When projection matrix changes, need to pre-multiply with viewport transform matrix */ +static void OnProjectionChanged() { + UploadMatrix4x4(&VIEWPORT_MATRIX); + MultiplyMatrix4x4(stack_top(MATRIX_STACKS + (GL_PROJECTION & 0xF))); + DownloadMatrix4x4(stack_top(MATRIX_STACKS + (GL_PROJECTION & 0xF))); +} + +/* When modelview matrix changes, need to re-compute normal matrix */ +static void OnModelviewChanged() { MEMCPY4(NORMAL_MATRIX, stack_top(MATRIX_STACKS + (GL_MODELVIEW & 0xF)), sizeof(Matrix4x4)); inverse((GLfloat*) NORMAL_MATRIX); transpose((GLfloat*) NORMAL_MATRIX); } +static void OnMatrixChanged() { + if(MATRIX_MODE == GL_MODELVIEW) { + OnModelviewChanged(); + } else if(MATRIX_MODE == GL_PROJECTION) { + OnProjectionChanged(); + } +} + + void APIENTRY glMatrixMode(GLenum mode) { MATRIX_MODE = mode; MATRIX_IDX = mode & 0xF; @@ -116,12 +130,13 @@ void APIENTRY glPushMatrix() { void APIENTRY glPopMatrix() { stack_pop(MATRIX_STACKS + MATRIX_IDX); if(MATRIX_MODE == GL_MODELVIEW) { - recalculateNormalMatrix(); + OnModelviewChanged(); } } void APIENTRY glLoadIdentity() { stack_replace(MATRIX_STACKS + MATRIX_IDX, IDENTITY); + OnMatrixChanged(); } void APIENTRY glTranslatef(GLfloat x, GLfloat y, GLfloat z) { @@ -141,10 +156,7 @@ void APIENTRY glTranslatef(GLfloat x, GLfloat y, GLfloat z) { assert(top); DownloadMatrix4x4(top); - - if(MATRIX_MODE == GL_MODELVIEW) { - recalculateNormalMatrix(); - } + OnMatrixChanged(); } @@ -159,10 +171,7 @@ void APIENTRY glScalef(GLfloat x, GLfloat y, GLfloat z) { UploadMatrix4x4(stack_top(MATRIX_STACKS + MATRIX_IDX)); MultiplyMatrix4x4(&scale); DownloadMatrix4x4(stack_top(MATRIX_STACKS + MATRIX_IDX)); - - if(MATRIX_MODE == GL_MODELVIEW) { - recalculateNormalMatrix(); - } + OnMatrixChanged(); } void APIENTRY glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) { @@ -202,10 +211,7 @@ void APIENTRY glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) { UploadMatrix4x4(stack_top(MATRIX_STACKS + MATRIX_IDX)); MultiplyMatrix4x4((const Matrix4x4*) &rotate); DownloadMatrix4x4(stack_top(MATRIX_STACKS + MATRIX_IDX)); - - if(MATRIX_MODE == GL_MODELVIEW) { - recalculateNormalMatrix(); - } + OnMatrixChanged(); } /* Load an arbitrary matrix */ @@ -214,10 +220,7 @@ void APIENTRY glLoadMatrixf(const GLfloat *m) { memcpy(TEMP, m, sizeof(float) * 16); stack_replace(MATRIX_STACKS + MATRIX_IDX, TEMP); - - if(MATRIX_MODE == GL_MODELVIEW) { - recalculateNormalMatrix(); - } + OnMatrixChanged(); } /* Ortho */ @@ -243,6 +246,7 @@ void APIENTRY glOrtho(GLfloat left, GLfloat right, UploadMatrix4x4(stack_top(MATRIX_STACKS + MATRIX_IDX)); MultiplyMatrix4x4((const Matrix4x4*) &OrthoMatrix); DownloadMatrix4x4(stack_top(MATRIX_STACKS + MATRIX_IDX)); + OnMatrixChanged(); } @@ -274,6 +278,7 @@ void APIENTRY glFrustum(GLfloat left, GLfloat right, UploadMatrix4x4(stack_top(MATRIX_STACKS + MATRIX_IDX)); MultiplyMatrix4x4((const Matrix4x4*) &FrustumMatrix); DownloadMatrix4x4(stack_top(MATRIX_STACKS + MATRIX_IDX)); + OnMatrixChanged(); } @@ -285,10 +290,7 @@ void glMultMatrixf(const GLfloat *m) { UploadMatrix4x4(stack_top(MATRIX_STACKS + MATRIX_IDX)); MultiplyMatrix4x4(&TEMP); DownloadMatrix4x4(stack_top(MATRIX_STACKS + MATRIX_IDX)); - - if(MATRIX_MODE == GL_MODELVIEW) { - recalculateNormalMatrix(); - } + OnMatrixChanged(); } /* Load an arbitrary transposed matrix */ @@ -319,10 +321,7 @@ void glLoadTransposeMatrixf(const GLfloat *m) { TEMP[M15] = m[15]; stack_replace(MATRIX_STACKS + MATRIX_IDX, TEMP); - - if(MATRIX_MODE == GL_MODELVIEW) { - recalculateNormalMatrix(); - } + OnMatrixChanged(); } /* Multiply the current matrix by an arbitrary transposed matrix */ @@ -352,22 +351,19 @@ void glMultTransposeMatrixf(const GLfloat *m) { UploadMatrix4x4(stack_top(MATRIX_STACKS + MATRIX_IDX)); MultiplyMatrix4x4((const Matrix4x4*) &TEMP); DownloadMatrix4x4(stack_top(MATRIX_STACKS + MATRIX_IDX)); - - if(MATRIX_MODE == GL_MODELVIEW) { - recalculateNormalMatrix(); - } + OnMatrixChanged(); } /* Set the GL viewport */ void APIENTRY glViewport(GLint x, GLint y, GLsizei width, GLsizei height) { - VIEWPORT.x = x; - VIEWPORT.y = y; - VIEWPORT.width = width; - VIEWPORT.height = height; - VIEWPORT.hwidth = ((GLfloat) VIEWPORT.width) * 0.5f; - VIEWPORT.hheight = ((GLfloat) VIEWPORT.height) * 0.5f; - VIEWPORT.x_plus_hwidth = VIEWPORT.x + VIEWPORT.hwidth; - VIEWPORT.y_plus_hheight = VIEWPORT.y + VIEWPORT.hheight; + VIEWPORT_MATRIX[0][0] = width * 0.5f; + VIEWPORT_MATRIX[1][1] = -height * 0.5f; + VIEWPORT_MATRIX[2][2] = 1.0f; + VIEWPORT_MATRIX[3][3] = 1.0f; + + VIEWPORT_MATRIX[3][0] = x + width * 0.5f; + VIEWPORT_MATRIX[3][1] = GetVideoMode()->height - (y + height * 0.5f); + OnProjectionChanged(); } /* Set the depth range */ diff --git a/GL/platforms/sh4.c b/GL/platforms/sh4.c index ba00148..cceab78 100644 --- a/GL/platforms/sh4.c +++ b/GL/platforms/sh4.c @@ -78,9 +78,10 @@ GL_FORCE_INLINE void _glPerspectiveDivideVertex(Vertex* vertex, const float h) { const float f = _glFastInvert(vertex->w); - /* Convert to NDC and apply viewport */ - vertex->xyz[0] = (vertex->xyz[0] * f * 320) + 320; - vertex->xyz[1] = (vertex->xyz[1] * f * -240) + 240; + /* Convert to screenspace */ + /* (note that vertices have already been viewport transformed) */ + vertex->xyz[0] = vertex->xyz[0] * f; + vertex->xyz[1] = vertex->xyz[1] * f; /* Orthographic projections need to use invZ otherwise we lose the depth information. As w == 1, and clip-space range is -w to +w diff --git a/GL/platforms/software.c b/GL/platforms/software.c index 4245930..bf9ba47 100644 --- a/GL/platforms/software.c +++ b/GL/platforms/software.c @@ -75,17 +75,13 @@ void SceneListBegin(GPUList list) { vertex_counter = 0; } -GL_FORCE_INLINE void _glPerspectiveDivideVertex(Vertex* vertex, const float h) { +GL_FORCE_INLINE void _glPerspectiveDivideVertex(Vertex* vertex) { const float f = 1.0f / (vertex->w); - /* Convert to NDC and apply viewport */ - vertex->xyz[0] = __builtin_fmaf( - VIEWPORT.hwidth, vertex->xyz[0] * f, VIEWPORT.x_plus_hwidth - ); - - vertex->xyz[1] = h - __builtin_fmaf( - VIEWPORT.hheight, vertex->xyz[1] * f, VIEWPORT.y_plus_hheight - ); + /* Convert to screenspace */ + /* (note that vertices have already been viewport transformed) */ + vertex->xyz[0] = vertex->xyz[0] * f; + vertex->xyz[1] = vertex->xyz[1] * f; if(vertex->w == 1.0f) { vertex->xyz[2] = 1.0f / (1.0001f + vertex->xyz[2]); @@ -143,8 +139,6 @@ void SceneListSubmit(Vertex* v2, int n) { return; } - const float h = GetVideoMode()->height; - uint8_t visible_mask = 0; uint8_t counter = 0; @@ -182,19 +176,19 @@ void SceneListSubmit(Vertex* v2, int n) { switch(visible_mask) { case 15: /* All visible, but final vertex in strip */ { - _glPerspectiveDivideVertex(v0, h); + _glPerspectiveDivideVertex(v0); _glPushHeaderOrVertex(v0); - _glPerspectiveDivideVertex(v1, h); + _glPerspectiveDivideVertex(v1); _glPushHeaderOrVertex(v1); - _glPerspectiveDivideVertex(v2, h); + _glPerspectiveDivideVertex(v2); _glPushHeaderOrVertex(v2); } break; case 7: /* All visible, push the first vertex and move on */ - _glPerspectiveDivideVertex(v0, h); + _glPerspectiveDivideVertex(v0); _glPushHeaderOrVertex(v0); break; case 9: @@ -210,13 +204,13 @@ void SceneListSubmit(Vertex* v2, int n) { _glClipEdge(v2, v0, b); b->flags = GPU_CMD_VERTEX_EOL; - _glPerspectiveDivideVertex(v0, h); + _glPerspectiveDivideVertex(v0); _glPushHeaderOrVertex(v0); - _glPerspectiveDivideVertex(a, h); + _glPerspectiveDivideVertex(a); _glPushHeaderOrVertex(a); - _glPerspectiveDivideVertex(b, h); + _glPerspectiveDivideVertex(b); _glPushHeaderOrVertex(b); } break; @@ -233,13 +227,13 @@ void SceneListSubmit(Vertex* v2, int n) { _glClipEdge(v2, v0, b); b->flags = GPU_CMD_VERTEX; - _glPerspectiveDivideVertex(v0, h); + _glPerspectiveDivideVertex(v0); _glPushHeaderOrVertex(v0); - _glPerspectiveDivideVertex(a, h); + _glPerspectiveDivideVertex(a); _glPushHeaderOrVertex(a); - _glPerspectiveDivideVertex(b, h); + _glPerspectiveDivideVertex(b); _glPushHeaderOrVertex(b); _glPushHeaderOrVertex(b); } @@ -262,13 +256,13 @@ void SceneListSubmit(Vertex* v2, int n) { _glClipEdge(v1, v2, b); b->flags = v2->flags; - _glPerspectiveDivideVertex(a, h); + _glPerspectiveDivideVertex(a); _glPushHeaderOrVertex(a); - _glPerspectiveDivideVertex(c, h); + _glPerspectiveDivideVertex(c); _glPushHeaderOrVertex(c); - _glPerspectiveDivideVertex(b, h); + _glPerspectiveDivideVertex(b); _glPushHeaderOrVertex(b); } break; @@ -285,19 +279,19 @@ void SceneListSubmit(Vertex* v2, int n) { _glClipEdge(v2, v0, b); b->flags = GPU_CMD_VERTEX; - _glPerspectiveDivideVertex(v0, h); + _glPerspectiveDivideVertex(v0); _glPushHeaderOrVertex(v0); _glClipEdge(v1, v2, a); a->flags = v2->flags; - _glPerspectiveDivideVertex(c, h); + _glPerspectiveDivideVertex(c); _glPushHeaderOrVertex(c); - _glPerspectiveDivideVertex(b, h); + _glPerspectiveDivideVertex(b); _glPushHeaderOrVertex(b); - _glPerspectiveDivideVertex(a, h); + _glPerspectiveDivideVertex(a); _glPushHeaderOrVertex(c); _glPushHeaderOrVertex(a); } @@ -319,17 +313,17 @@ void SceneListSubmit(Vertex* v2, int n) { _glClipEdge(v1, v2, b); b->flags = GPU_CMD_VERTEX; - _glPerspectiveDivideVertex(a, h); + _glPerspectiveDivideVertex(a); _glPushHeaderOrVertex(a); if(counter % 2 == 1) { _glPushHeaderOrVertex(a); } - _glPerspectiveDivideVertex(b, h); + _glPerspectiveDivideVertex(b); _glPushHeaderOrVertex(b); - _glPerspectiveDivideVertex(c, h); + _glPerspectiveDivideVertex(c); _glPushHeaderOrVertex(c); } break; @@ -349,15 +343,15 @@ void SceneListSubmit(Vertex* v2, int n) { _glClipEdge(v1, v2, b); b->flags = GPU_CMD_VERTEX; - _glPerspectiveDivideVertex(v0, h); + _glPerspectiveDivideVertex(v0); _glPushHeaderOrVertex(v0); - _glPerspectiveDivideVertex(a, h); + _glPerspectiveDivideVertex(a); _glPushHeaderOrVertex(a); - _glPerspectiveDivideVertex(c, h); + _glPerspectiveDivideVertex(c); _glPushHeaderOrVertex(c); - _glPerspectiveDivideVertex(b, h); + _glPerspectiveDivideVertex(b); _glPushHeaderOrVertex(b); c->flags = GPU_CMD_VERTEX_EOL; @@ -380,15 +374,15 @@ void SceneListSubmit(Vertex* v2, int n) { _glClipEdge(v1, v2, b); b->flags = GPU_CMD_VERTEX; - _glPerspectiveDivideVertex(v0, h); + _glPerspectiveDivideVertex(v0); _glPushHeaderOrVertex(v0); - _glPerspectiveDivideVertex(a, h); + _glPerspectiveDivideVertex(a); _glPushHeaderOrVertex(a); - _glPerspectiveDivideVertex(c, h); + _glPerspectiveDivideVertex(c); _glPushHeaderOrVertex(c); - _glPerspectiveDivideVertex(b, h); + _glPerspectiveDivideVertex(b); _glPushHeaderOrVertex(b); _glPushHeaderOrVertex(c); } @@ -411,17 +405,17 @@ void SceneListSubmit(Vertex* v2, int n) { _glClipEdge(v2, v0, b); b->flags = GPU_CMD_VERTEX; - _glPerspectiveDivideVertex(a, h); + _glPerspectiveDivideVertex(a); _glPushHeaderOrVertex(a); - _glPerspectiveDivideVertex(c, h); + _glPerspectiveDivideVertex(c); _glPushHeaderOrVertex(c); - _glPerspectiveDivideVertex(b, h); + _glPerspectiveDivideVertex(b); _glPushHeaderOrVertex(b); _glPushHeaderOrVertex(c); - _glPerspectiveDivideVertex(d, h); + _glPerspectiveDivideVertex(d); _glPushHeaderOrVertex(d); } break; diff --git a/GL/private.h b/GL/private.h index 5b11c52..758c636 100644 --- a/GL/private.h +++ b/GL/private.h @@ -104,20 +104,6 @@ typedef struct { AlignedVector vector; } PolyList; -typedef struct { - GLint x; - GLint y; - GLint width; - GLint height; - - float x_plus_hwidth; - float y_plus_hheight; - float hwidth; /* width * 0.5f */ - float hheight; /* height * 0.5f */ -} Viewport; - -extern Viewport VIEWPORT; - typedef struct { /* Palette data is always stored in RAM as RGBA8888 and packed as ARGB8888 * when uploaded to the PVR */ From d4fc57cab2894b35113d2e9a57fa1f9dbe4aa60b Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sat, 3 Aug 2024 16:40:23 +1000 Subject: [PATCH 21/72] Fix not working properly, defer matrix calculation until needed --- GL/draw.c | 29 ----------------------------- GL/matrix.c | 43 +++++++++++++++++++++++-------------------- 2 files changed, 23 insertions(+), 49 deletions(-) diff --git a/GL/draw.c b/GL/draw.c index 01d9cf7..4e7d6ce 100644 --- a/GL/draw.c +++ b/GL/draw.c @@ -946,35 +946,6 @@ static void light(SubmissionTarget* target) { _glPerformLighting(vertex, ES, target->count); } -GL_FORCE_INLINE void divide(SubmissionTarget* target) { - TRACE(); - - /* Perform perspective divide on each vertex */ - Vertex* vertex = _glSubmissionTargetStart(target); - - const float h = GetVideoMode()->height; - - ITERATE(target->count) { - const float f = MATH_Fast_Invert(vertex->w); - - /* Convert to NDC and apply viewport */ - vertex->xyz[0] = MATH_fmac( - VIEWPORT.hwidth, vertex->xyz[0] * f, VIEWPORT.x_plus_hwidth - ); - vertex->xyz[1] = h - MATH_fmac( - VIEWPORT.hheight, vertex->xyz[1] * f, VIEWPORT.y_plus_hheight - ); - - /* Apply depth range */ - vertex->xyz[2] = MAX( - 1.0f - MATH_fmac(vertex->xyz[2] * f, 0.5f, 0.5f), - PVR_MIN_Z - ); - - ++vertex; - } -} - GL_FORCE_INLINE int _calc_pvr_face_culling() { if(!_glIsCullingEnabled()) { return GPU_CULLING_SMALL; diff --git a/GL/matrix.c b/GL/matrix.c index 5c1fac3..6863258 100644 --- a/GL/matrix.c +++ b/GL/matrix.c @@ -16,9 +16,11 @@ GLfloat DEPTH_RANGE_MULTIPLIER_H = (0 + 1) / 2; static Stack __attribute__((aligned(32))) MATRIX_STACKS[4]; // modelview, projection, texture static Matrix4x4 __attribute__((aligned(32))) NORMAL_MATRIX; static Matrix4x4 __attribute__((aligned(32))) VIEWPORT_MATRIX; +static Matrix4x4 __attribute__((aligned(32))) PROJECTION_MATRIX; static GLenum MATRIX_MODE = GL_MODELVIEW; static GLubyte MATRIX_IDX = 0; +static GLboolean NORMAL_DIRTY, PROJECTION_DIRTY; static const Matrix4x4 __attribute__((aligned(32))) IDENTITY = { 1.0f, 0.0f, 0.0f, 0.0f, @@ -92,25 +94,24 @@ static void transpose(GLfloat* m) { } /* When projection matrix changes, need to pre-multiply with viewport transform matrix */ -static void OnProjectionChanged() { +static void UpdateProjectionMatrix() { + PROJECTION_DIRTY = false; UploadMatrix4x4(&VIEWPORT_MATRIX); MultiplyMatrix4x4(stack_top(MATRIX_STACKS + (GL_PROJECTION & 0xF))); - DownloadMatrix4x4(stack_top(MATRIX_STACKS + (GL_PROJECTION & 0xF))); + DownloadMatrix4x4(&PROJECTION_MATRIX); } /* When modelview matrix changes, need to re-compute normal matrix */ -static void OnModelviewChanged() { +static void UpdateNormalMatrix() { + NORMAL_DIRTY = false; MEMCPY4(NORMAL_MATRIX, stack_top(MATRIX_STACKS + (GL_MODELVIEW & 0xF)), sizeof(Matrix4x4)); inverse((GLfloat*) NORMAL_MATRIX); transpose((GLfloat*) NORMAL_MATRIX); } static void OnMatrixChanged() { - if(MATRIX_MODE == GL_MODELVIEW) { - OnModelviewChanged(); - } else if(MATRIX_MODE == GL_PROJECTION) { - OnProjectionChanged(); - } + if(MATRIX_MODE == GL_MODELVIEW) NORMAL_DIRTY = true; + if(MATRIX_MODE == GL_PROJECTION) PROJECTION_DIRTY = true; } @@ -125,13 +126,12 @@ void APIENTRY glPushMatrix() { void* ret = stack_push(MATRIX_STACKS + MATRIX_IDX, top); (void) ret; assert(ret); + OnMatrixChanged(); } void APIENTRY glPopMatrix() { stack_pop(MATRIX_STACKS + MATRIX_IDX); - if(MATRIX_MODE == GL_MODELVIEW) { - OnModelviewChanged(); - } + OnMatrixChanged(); } void APIENTRY glLoadIdentity() { @@ -356,14 +356,14 @@ void glMultTransposeMatrixf(const GLfloat *m) { /* Set the GL viewport */ void APIENTRY glViewport(GLint x, GLint y, GLsizei width, GLsizei height) { - VIEWPORT_MATRIX[0][0] = width * 0.5f; - VIEWPORT_MATRIX[1][1] = -height * 0.5f; - VIEWPORT_MATRIX[2][2] = 1.0f; - VIEWPORT_MATRIX[3][3] = 1.0f; + VIEWPORT_MATRIX[M0] = width * 0.5f; + VIEWPORT_MATRIX[M5] = height * -0.5f; + VIEWPORT_MATRIX[M10] = 1.0f; + VIEWPORT_MATRIX[M15] = 1.0f; - VIEWPORT_MATRIX[3][0] = x + width * 0.5f; - VIEWPORT_MATRIX[3][1] = GetVideoMode()->height - (y + height * 0.5f); - OnProjectionChanged(); + VIEWPORT_MATRIX[M12] = x + width * 0.5f; + VIEWPORT_MATRIX[M13] = GetVideoMode()->height - (y + height * 0.5f); + PROJECTION_DIRTY = true; } /* Set the depth range */ @@ -455,14 +455,17 @@ void _glMatrixLoadModelView() { } void _glMatrixLoadProjection() { - UploadMatrix4x4((const Matrix4x4*) stack_top(MATRIX_STACKS + (GL_PROJECTION & 0xF))); + if (PROJECTION_DIRTY) UpdateProjectionMatrix(); + UploadMatrix4x4(&PROJECTION_MATRIX); } void _glMatrixLoadModelViewProjection() { - UploadMatrix4x4((const Matrix4x4*) stack_top(MATRIX_STACKS + (GL_PROJECTION & 0xF))); + if (PROJECTION_DIRTY) UpdateProjectionMatrix(); + UploadMatrix4x4(&PROJECTION_MATRIX); MultiplyMatrix4x4((const Matrix4x4*) stack_top(MATRIX_STACKS + (GL_MODELVIEW & 0xF))); } void _glMatrixLoadNormal() { + if (NORMAL_DIRTY) UpdateNormalMatrix(); UploadMatrix4x4((const Matrix4x4*) &NORMAL_MATRIX); } From 92ec1db6431701e42f8e72307b75fcf389463cbe Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sun, 11 Aug 2024 19:39:27 +1000 Subject: [PATCH 22/72] Only update attribute pointers at end instead of per vertex --- GL/immediate.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/GL/immediate.c b/GL/immediate.c index afe80c5..fd32f82 100644 --- a/GL/immediate.c +++ b/GL/immediate.c @@ -163,13 +163,6 @@ void APIENTRY glVertex3f(GLfloat x, GLfloat y, GLfloat z) { IMVertex* vert = aligned_vector_extend(&VERTICES, 1); - /* Resizing could've invalidated the pointers */ - IM_ATTRIBS.vertex.ptr = VERTICES.data; - IM_ATTRIBS.uv.ptr = IM_ATTRIBS.vertex.ptr + 12; - IM_ATTRIBS.st.ptr = IM_ATTRIBS.uv.ptr + 8; - IM_ATTRIBS.colour.ptr = IM_ATTRIBS.st.ptr + 8; - IM_ATTRIBS.normal.ptr = IM_ATTRIBS.colour.ptr + 4; - uint32_t* dest = (uint32_t*) &vert->x; *(dest++) = *((uint32_t*) &x); *(dest++) = *((uint32_t*) &y); @@ -254,6 +247,13 @@ void APIENTRY glNormal3fv(const GLfloat* v) { void APIENTRY glEnd() { IMMEDIATE_MODE_ACTIVE = GL_FALSE; + /* Resizing could've invalidated the pointers */ + IM_ATTRIBS.vertex.ptr = VERTICES.data; + IM_ATTRIBS.uv.ptr = IM_ATTRIBS.vertex.ptr + 12; + IM_ATTRIBS.st.ptr = IM_ATTRIBS.uv.ptr + 8; + IM_ATTRIBS.colour.ptr = IM_ATTRIBS.st.ptr + 8; + IM_ATTRIBS.normal.ptr = IM_ATTRIBS.colour.ptr + 4; + GLuint* attrs = &ENABLED_VERTEX_ATTRIBUTES; /* Redirect attrib pointers */ From 82bfe8d935e16f99b70150577b580cc65cf19345 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Tue, 27 Aug 2024 07:23:19 +1000 Subject: [PATCH 23/72] Change some constant values to match standard OpenGL values --- include/GL/gl.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/GL/gl.h b/include/GL/gl.h index 028f900..59402bc 100644 --- a/include/GL/gl.h +++ b/include/GL/gl.h @@ -55,7 +55,7 @@ __BEGIN_DECLS #define GL_FRONT_FACE 0x0B46 /* Scissor box */ -#define GL_SCISSOR_TEST 0x0008 /* capability bit */ +#define GL_SCISSOR_TEST 0x0C11 #define GL_SCISSOR_BOX 0x0C10 /* Stencil actions */ @@ -109,7 +109,7 @@ __BEGIN_DECLS #define GL_SRC_ALPHA_SATURATE 0x0308 /* Misc texture constants */ -#define GL_TEXTURE_2D 0x0001 /* capability bit */ +#define GL_TEXTURE_2D 0x0DE1 #define GL_TEXTURE_WRAP_S 0x2802 #define GL_TEXTURE_WRAP_T 0x2803 #define GL_TEXTURE_MAG_FILTER 0x2800 @@ -204,7 +204,7 @@ __BEGIN_DECLS #define GL_CLIP_PLANE5 0x3005 /* Fog */ -#define GL_FOG 0x0004 /* capability bit */ +#define GL_FOG 0x0B60 #define GL_FOG_MODE 0x0B65 #define GL_FOG_DENSITY 0x0B62 #define GL_FOG_COLOR 0x0B66 @@ -226,7 +226,7 @@ __BEGIN_DECLS #define GL_FOG_HINT 0x0C54 /* Lighting constants */ -#define GL_LIGHTING 0x0b50 +#define GL_LIGHTING 0x0b50 #define GL_LIGHT0 0x4000 #define GL_LIGHT1 0x4001 From 8594684f93368c58347c1a33a84f9419499de50c Mon Sep 17 00:00:00 2001 From: Luke Benstead Date: Wed, 28 Aug 2024 22:37:01 +0100 Subject: [PATCH 24/72] Make ARB_multisample core It was made core in 1.3, there's no reason for us to ARB suffix it (we can't support it but at least let's use the core defines) --- include/GL/gl.h | 10 ++++++++++ include/GL/glext.h | 10 ---------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/include/GL/gl.h b/include/GL/gl.h index 59402bc..61d434b 100644 --- a/include/GL/gl.h +++ b/include/GL/gl.h @@ -481,6 +481,16 @@ __BEGIN_DECLS #define GL_PACK_SKIP_PIXELS 0x0D04 #define GL_PACK_ALIGNMENT 0x0D05 +#define GL_MULTISAMPLE 0x809D +#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E +#define GL_SAMPLE_ALPHA_TO_ONE 0x809F +#define GL_SAMPLE_COVERAGE 0x80A0 +#define GL_SAMPLE_BUFFERS 0x80A8 +#define GL_SAMPLES 0x80A9 +#define GL_SAMPLE_COVERAGE_VALUE 0x80AA +#define GL_SAMPLE_COVERAGE_INVERT 0x80AB +#define GL_MULTISAMPLE_BIT 0x20000000 + #define GLAPI extern #define APIENTRY diff --git a/include/GL/glext.h b/include/GL/glext.h index acd7763..565ed40 100644 --- a/include/GL/glext.h +++ b/include/GL/glext.h @@ -54,16 +54,6 @@ __BEGIN_DECLS #define GL_TRANSPOSE_TEXTURE_MATRIX_ARB 0x84E5 #define GL_TRANSPOSE_COLOR_MATRIX_ARB 0x84E6 -#define GL_MULTISAMPLE_ARB 0x809D -#define GL_SAMPLE_ALPHA_TO_COVERAGE_ARB 0x809E -#define GL_SAMPLE_ALPHA_TO_ONE_ARB 0x809F -#define GL_SAMPLE_COVERAGE_ARB 0x80A0 -#define GL_SAMPLE_BUFFERS_ARB 0x80A8 -#define GL_SAMPLES_ARB 0x80A9 -#define GL_SAMPLE_COVERAGE_VALUE_ARB 0x80AA -#define GL_SAMPLE_COVERAGE_INVERT_ARB 0x80AB -#define GL_MULTISAMPLE_BIT_ARB 0x20000000 - #define GL_NORMAL_MAP_ARB 0x8511 #define GL_REFLECTION_MAP_ARB 0x8512 #define GL_TEXTURE_CUBE_MAP_ARB 0x8513 From ab24e2db35841ccee5f888c7554459ea7481d8d9 Mon Sep 17 00:00:00 2001 From: Luke Benstead Date: Wed, 28 Aug 2024 22:39:05 +0100 Subject: [PATCH 25/72] Make GL_MULTISAMPLE not throw an error --- GL/state.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/GL/state.c b/GL/state.c index d8b89f2..3f6c24d 100644 --- a/GL/state.c +++ b/GL/state.c @@ -495,9 +495,12 @@ GLAPI void APIENTRY glEnable(GLenum cap) { case GL_TEXTURE_TWIDDLE_KOS: _glSetTextureTwiddle(GL_TRUE); break; - default: - _glKosThrowError(GL_INVALID_VALUE, __func__); - break; + case GL_MULTISAMPLE: + // Not supported, but not an error + break; + default: + _glKosThrowError(GL_INVALID_VALUE, __func__); + break; } } @@ -601,9 +604,12 @@ GLAPI void APIENTRY glDisable(GLenum cap) { case GL_TEXTURE_TWIDDLE_KOS: _glSetTextureTwiddle(GL_FALSE); break; - default: - _glKosThrowError(GL_INVALID_VALUE, __func__); - break; + case GL_MULTISAMPLE: + // Not supported, but not an error + break; + default: + _glKosThrowError(GL_INVALID_VALUE, __func__); + break; } } From 5f28cae804aafa8a4272e65bb8004a10cea804cd Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Wed, 4 Sep 2024 21:26:46 +1000 Subject: [PATCH 26/72] Tidy up textures table and add some missing formats --- GL/texture.c | 100 +++++++++++++++++++++++++++++---------------------- 1 file changed, 57 insertions(+), 43 deletions(-) diff --git a/GL/texture.c b/GL/texture.c index 35ad164..5d70419 100644 --- a/GL/texture.c +++ b/GL/texture.c @@ -1228,55 +1228,69 @@ static int _determineConversion(GLint internalFormat, GLenum format, GLenum type bool twiddle; bool pack; // If true, each value is packed after conversion into half-bytes } conversions [] = { - {_a8_to_argb4444, GL_ARGB4444_KOS, GL_ALPHA, GL_UNSIGNED_BYTE, false, false}, - {_rgba8888_to_argb4444, GL_ARGB4444_KOS, GL_RGBA, GL_UNSIGNED_BYTE, false, false}, - {_rgba4444_to_argb4444, GL_ARGB4444_KOS, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, false, false}, - {_rgba4444_to_argb4444, GL_ARGB4444_TWID_KOS, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, true, false}, - {NULL, GL_ARGB4444_KOS, GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4_REV, false, false}, - {NULL, GL_ARGB4444_TWID_KOS, GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4_REV_TWID_KOS, false, false}, - {_rgba8888_to_argb4444, GL_ARGB4444_TWID_KOS, GL_RGBA, GL_UNSIGNED_BYTE, true, false}, - {NULL, GL_ARGB1555_KOS, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, false, false}, - {_argb1555_to_argb4444, GL_ARGB4444_TWID_KOS, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, true, false}, - {NULL, GL_ARGB1555_TWID_KOS, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV_TWID_KOS, false, false}, - {_rgba8888_to_rgb565, GL_RGB565_KOS, GL_RGBA, GL_UNSIGNED_BYTE, false, false}, - {_r8_to_rgb565, GL_RGB565_KOS, GL_RED, GL_UNSIGNED_BYTE, false, false}, - {_rgb888_to_rgb565, GL_RGB565_KOS, GL_RGB, GL_UNSIGNED_BYTE, false, false}, - {_rgba8888_to_rgb565, GL_RGB565_KOS, GL_RGBA, GL_UNSIGNED_BYTE, false, false}, - {_r8_to_rgb565, GL_RGB565_KOS, GL_RED, GL_UNSIGNED_BYTE, false, false}, - {NULL, GL_RGB565_KOS, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, false, false}, - {NULL, GL_RGB565_TWID_KOS, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_TWID_KOS, false, false}, - {NULL, GL_RGB565_TWID_KOS, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, true, false}, - {_rgb888_to_rgb565, GL_RGB565_TWID_KOS, GL_RGB, GL_UNSIGNED_BYTE, true, false}, - {NULL, GL_COLOR_INDEX8_EXT, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, false, false}, - {NULL, GL_COLOR_INDEX8_EXT, GL_COLOR_INDEX, GL_BYTE, false, false}, - {NULL, GL_COLOR_INDEX8_TWID_KOS, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, true, false}, - {NULL, GL_COLOR_INDEX8_TWID_KOS, GL_COLOR_INDEX, GL_BYTE, true, false}, - {NULL, GL_COLOR_INDEX4_EXT, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, false, true}, - {NULL, GL_COLOR_INDEX4_EXT, GL_COLOR_INDEX, GL_BYTE, false, true}, + {_rgba8888_to_argb4444, GL_ARGB4444_KOS, GL_RGBA, GL_UNSIGNED_BYTE, false, false}, + {_rgba8888_to_argb4444, GL_ARGB4444_TWID_KOS, GL_RGBA, GL_UNSIGNED_BYTE, true, false}, + {_a8_to_argb4444, GL_ARGB4444_KOS, GL_ALPHA, GL_UNSIGNED_BYTE, false, false}, + {_a8_to_argb4444, GL_ARGB4444_TWID_KOS, GL_ALPHA, GL_UNSIGNED_BYTE, true, false}, - {NULL, GL_COLOR_INDEX4_EXT, GL_COLOR_INDEX4_EXT, GL_UNSIGNED_BYTE, false, false}, - {NULL, GL_COLOR_INDEX4_EXT, GL_COLOR_INDEX4_EXT, GL_BYTE, false, false}, - {NULL, GL_COLOR_INDEX4_TWID_KOS, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, true, true}, - {NULL, GL_COLOR_INDEX4_TWID_KOS, GL_COLOR_INDEX, GL_BYTE, true, true}, + {_rgba4444_to_argb4444, GL_ARGB4444_KOS, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, false, false}, + {_rgba4444_to_argb4444, GL_ARGB4444_TWID_KOS, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, true, false}, + {NULL, GL_ARGB4444_KOS, GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4_REV, false, false}, + {NULL, GL_ARGB4444_TWID_KOS, GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4_REV, true, false}, - {NULL, GL_COLOR_INDEX4_TWID_KOS, GL_COLOR_INDEX4_EXT, GL_UNSIGNED_BYTE, true, false}, - {NULL, GL_COLOR_INDEX4_TWID_KOS, GL_COLOR_INDEX4_EXT, GL_BYTE, true, false}, + {NULL, GL_ARGB4444_TWID_KOS, GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4_REV_TWID_KOS, false, false}, + + {_argb1555_to_argb4444, GL_ARGB4444_KOS, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, false, false}, + {_argb1555_to_argb4444, GL_ARGB4444_TWID_KOS, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, true, false}, + + {NULL, GL_ARGB1555_KOS, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, false, false}, + {NULL, GL_ARGB1555_TWID_KOS, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, true, false}, + + {NULL, GL_ARGB1555_TWID_KOS, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV_TWID_KOS, false, false}, + + {_r8_to_rgb565, GL_RGB565_KOS, GL_RED, GL_UNSIGNED_BYTE, false, false}, + {_r8_to_rgb565, GL_RGB565_TWID_KOS, GL_RED, GL_UNSIGNED_BYTE, true, false}, + {_rgb888_to_rgb565, GL_RGB565_KOS, GL_RGB, GL_UNSIGNED_BYTE, false, false}, + {_rgb888_to_rgb565, GL_RGB565_TWID_KOS, GL_RGB, GL_UNSIGNED_BYTE, true, false}, + {_rgba8888_to_rgb565, GL_RGB565_KOS, GL_RGBA, GL_UNSIGNED_BYTE, false, false}, + {_rgba8888_to_rgb565, GL_RGB565_TWID_KOS, GL_RGBA, GL_UNSIGNED_BYTE, true, false}, + + {NULL, GL_RGB565_KOS, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, false, false}, + {NULL, GL_RGB565_TWID_KOS, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, true, false}, + {NULL, GL_RGB565_TWID_KOS, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_TWID_KOS, false, false}, + + {NULL, GL_COLOR_INDEX8_EXT, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, false, false}, + {NULL, GL_COLOR_INDEX8_EXT, GL_COLOR_INDEX, GL_BYTE, false, false}, + {NULL, GL_COLOR_INDEX8_TWID_KOS, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, true, false}, + {NULL, GL_COLOR_INDEX8_TWID_KOS, GL_COLOR_INDEX, GL_BYTE, true, false}, + + {NULL, GL_COLOR_INDEX8_EXT, GL_COLOR_INDEX8_EXT, GL_UNSIGNED_BYTE, false, false}, + {NULL, GL_COLOR_INDEX8_EXT, GL_COLOR_INDEX8_EXT, GL_BYTE, false, false}, + {NULL, GL_COLOR_INDEX8_TWID_KOS, GL_COLOR_INDEX8_EXT, GL_UNSIGNED_BYTE, true, false}, + {NULL, GL_COLOR_INDEX8_TWID_KOS, GL_COLOR_INDEX8_EXT, GL_BYTE, true, false}, - {NULL, GL_COLOR_INDEX8_EXT, GL_COLOR_INDEX8_EXT, GL_UNSIGNED_BYTE, false, false}, - {NULL, GL_COLOR_INDEX8_EXT, GL_COLOR_INDEX8_EXT, GL_BYTE, false, false}, {NULL, GL_COLOR_INDEX8_TWID_KOS, GL_COLOR_INDEX8_TWID_KOS, GL_UNSIGNED_BYTE, false, false}, - {NULL, GL_COLOR_INDEX8_TWID_KOS, GL_COLOR_INDEX8_TWID_KOS, GL_BYTE, false, false}, - {NULL, GL_COLOR_INDEX8_TWID_KOS, GL_COLOR_INDEX8_EXT, GL_UNSIGNED_BYTE, true, false}, - {NULL, GL_COLOR_INDEX8_TWID_KOS, GL_COLOR_INDEX8_EXT, GL_BYTE, true, false}, + {NULL, GL_COLOR_INDEX8_TWID_KOS, GL_COLOR_INDEX8_TWID_KOS, GL_BYTE, false, false}, - {NULL, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, false, false}, - {NULL, GL_RGBA8, GL_RGBA, GL_BYTE, false, false}, - {_rgb888_to_rgba8888, GL_RGBA8, GL_RGB, GL_UNSIGNED_BYTE, false, false}, - {_rgb888_to_rgba8888, GL_RGBA8, GL_RGB, GL_BYTE, false, false}, - {_rgb888_to_argb4444, GL_RGBA4, GL_RGB, GL_UNSIGNED_BYTE, false, false}, - {_rgb888_to_argb4444, GL_RGBA4, GL_RGB, GL_BYTE, false, false}, + {NULL, GL_COLOR_INDEX4_EXT, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, false, true}, + {NULL, GL_COLOR_INDEX4_EXT, GL_COLOR_INDEX, GL_BYTE, false, true}, + {NULL, GL_COLOR_INDEX4_TWID_KOS, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, true, true}, + {NULL, GL_COLOR_INDEX4_TWID_KOS, GL_COLOR_INDEX, GL_BYTE, true, true}, + + {NULL, GL_COLOR_INDEX4_EXT, GL_COLOR_INDEX4_EXT, GL_UNSIGNED_BYTE, false, false}, + {NULL, GL_COLOR_INDEX4_EXT, GL_COLOR_INDEX4_EXT, GL_BYTE, false, false}, + {NULL, GL_COLOR_INDEX4_TWID_KOS, GL_COLOR_INDEX4_EXT, GL_UNSIGNED_BYTE, true, false}, + {NULL, GL_COLOR_INDEX4_TWID_KOS, GL_COLOR_INDEX4_EXT, GL_BYTE, true, false}, + + {NULL, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, false, false}, + {NULL, GL_RGBA8, GL_RGBA, GL_BYTE, false, false}, + {_rgb888_to_rgba8888, GL_RGBA8, GL_RGB, GL_UNSIGNED_BYTE, false, false}, + {_rgb888_to_rgba8888, GL_RGBA8, GL_RGB, GL_BYTE, false, false}, + + {_rgb888_to_argb4444, GL_RGBA4, GL_RGB, GL_UNSIGNED_BYTE, false, false}, + {_rgb888_to_argb4444, GL_RGBA4, GL_RGB, GL_BYTE, false, false}, {_rgba8888_to_argb4444, GL_RGBA4, GL_RGBA, GL_UNSIGNED_BYTE, false, false}, - {_rgba8888_to_argb4444, GL_RGBA4, GL_RGBA, GL_BYTE, false, false}, + {_rgba8888_to_argb4444, GL_RGBA4, GL_RGBA, GL_BYTE, false, false}, }; for(size_t i = 0; i < sizeof(conversions) / sizeof(struct Entry); ++i) { From d570030070a6d66688862f1a799773eafa023de9 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Fri, 6 Sep 2024 22:13:31 +1000 Subject: [PATCH 27/72] Try to fix not being able to use GL_SRC_COLOR and GL_ONE_MINUS_SRC_COLOR as destination blend factor --- GL/draw.c | 53 +++++++++++++--------------------------------------- GL/private.h | 4 ++-- GL/state.c | 50 +++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 61 insertions(+), 46 deletions(-) diff --git a/GL/draw.c b/GL/draw.c index 47ce853..e7d1409 100644 --- a/GL/draw.c +++ b/GL/draw.c @@ -985,42 +985,6 @@ GL_FORCE_INLINE int _calc_pvr_depth_test() { } } -GL_FORCE_INLINE int _calcPVRBlendFactor(GLenum factor) { - switch(factor) { - case GL_ZERO: - return GPU_BLEND_ZERO; - case GL_SRC_ALPHA: - return GPU_BLEND_SRCALPHA; - case GL_DST_COLOR: - return GPU_BLEND_DESTCOLOR; - case GL_DST_ALPHA: - return GPU_BLEND_DESTALPHA; - case GL_ONE_MINUS_DST_COLOR: - return GPU_BLEND_INVDESTCOLOR; - case GL_ONE_MINUS_SRC_ALPHA: - return GPU_BLEND_INVSRCALPHA; - case GL_ONE_MINUS_DST_ALPHA: - return GPU_BLEND_INVDESTALPHA; - case GL_ONE: - return GPU_BLEND_ONE; - default: - fprintf(stderr, "Invalid blend mode: %u\n", (unsigned int) factor); - return GPU_BLEND_ONE; - } -} - - -GL_FORCE_INLINE void _updatePVRBlend(PolyContext* context) { - if(_glIsBlendingEnabled() || _glIsAlphaTestEnabled()) { - context->gen.alpha = GPU_ALPHA_ENABLE; - } else { - context->gen.alpha = GPU_ALPHA_DISABLE; - } - - context->blend.src = _calcPVRBlendFactor(_glGetBlendSourceFactor()); - context->blend.dst = _calcPVRBlendFactor(_glGetBlendDestFactor()); -} - GL_FORCE_INLINE void apply_poly_header(PolyHeader* header, GLboolean multiTextureHeader, PolyList* activePolyList, GLshort textureUnit) { TRACE(); @@ -1051,7 +1015,11 @@ GL_FORCE_INLINE void apply_poly_header(PolyHeader* header, GLboolean multiTextur ctx.gen.fog_type = GPU_FOG_DISABLE; } - _updatePVRBlend(&ctx); + if(_glIsBlendingEnabled() || _glIsAlphaTestEnabled()) { + ctx.gen.alpha = GPU_ALPHA_ENABLE; + } else { + ctx.gen.alpha = GPU_ALPHA_DISABLE; + } if(ctx.list_type == GPU_LIST_OP_POLY) { /* Opaque polys are always one/zero */ @@ -1062,9 +1030,14 @@ GL_FORCE_INLINE void apply_poly_header(PolyHeader* header, GLboolean multiTextur ctx.blend.src = GPU_BLEND_SRCALPHA; ctx.blend.dst = GPU_BLEND_INVSRCALPHA; ctx.depth.comparison = GPU_DEPTHCMP_LEQUAL; - } else if(ctx.list_type == GPU_LIST_TR_POLY && AUTOSORT_ENABLED) { - /* Autosort mode requires this mode for transparent polys */ - ctx.depth.comparison = GPU_DEPTHCMP_GEQUAL; + } else { + ctx.blend.src = _glGetGpuBlendSrcFactor(); + ctx.blend.dst = _glGetGpuBlendDstFactor(); + + if(ctx.list_type == GPU_LIST_TR_POLY && AUTOSORT_ENABLED) { + /* Autosort mode requires this mode for transparent polys */ + ctx.depth.comparison = GPU_DEPTHCMP_GEQUAL; + } } _glUpdatePVRTextureContext(&ctx, textureUnit); diff --git a/GL/private.h b/GL/private.h index 758c636..31a7872 100644 --- a/GL/private.h +++ b/GL/private.h @@ -385,8 +385,8 @@ GLboolean _glIsFogEnabled(); GLenum _glGetDepthFunc(); GLenum _glGetCullFace(); GLenum _glGetFrontFace(); -GLenum _glGetBlendSourceFactor(); -GLenum _glGetBlendDestFactor(); +GLenum _glGetGpuBlendSrcFactor(); +GLenum _glGetGpuBlendDstFactor(); extern PolyList OP_LIST; extern PolyList PT_LIST; diff --git a/GL/state.c b/GL/state.c index 3f6c24d..ef7780f 100644 --- a/GL/state.c +++ b/GL/state.c @@ -216,12 +216,54 @@ GLboolean _glIsNormalizeEnabled() { return GPUState.normalize_enabled; } -GLenum _glGetBlendSourceFactor() { - return GPUState.blend_sfactor; +GLenum _glGetGpuBlendSrcFactor() { + switch(GPUState.blend_sfactor) { + case GL_ZERO: + return GPU_BLEND_ZERO; + case GL_SRC_ALPHA: + return GPU_BLEND_SRCALPHA; + case GL_DST_COLOR: + return GPU_BLEND_DESTCOLOR; + case GL_DST_ALPHA: + return GPU_BLEND_DESTALPHA; + case GL_ONE_MINUS_DST_COLOR: + return GPU_BLEND_INVDESTCOLOR; + case GL_ONE_MINUS_SRC_ALPHA: + return GPU_BLEND_INVSRCALPHA; + case GL_ONE_MINUS_DST_ALPHA: + return GPU_BLEND_INVDESTALPHA; + case GL_ONE: + return GPU_BLEND_ONE; + default: + fprintf(stderr, "Invalid src blend mode: %u\n", (unsigned int)GPUState.blend_sfactor); + return GPU_BLEND_ONE; + } } -GLenum _glGetBlendDestFactor() { - return GPUState.blend_dfactor; +GLenum _glGetGpuBlendDstFactor() { + switch(GPUState.blend_dfactor) { + case GL_ZERO: + return GPU_BLEND_ZERO; + case GL_SRC_ALPHA: + return GPU_BLEND_SRCALPHA; + case GL_SRC_COLOR: + // actually 'src' color in PVR2 when used as dst blend factor + return GPU_BLEND_DESTCOLOR; + case GL_DST_ALPHA: + return GPU_BLEND_DESTALPHA; + case GL_ONE_MINUS_SRC_COLOR: + // actually 'src' color in PVR2 when used as dst blend factor + return GPU_BLEND_INVDESTCOLOR; + case GL_ONE_MINUS_SRC_ALPHA: + return GPU_BLEND_INVSRCALPHA; + case GL_ONE_MINUS_DST_ALPHA: + return GPU_BLEND_INVDESTALPHA; + case GL_ONE: + return GPU_BLEND_ONE; + default: + fprintf(stderr, "Invalid dst blend mode: %u\n", (unsigned int)GPUState.blend_dfactor); + return GPU_BLEND_ONE; + } } From 42786f775eac016a383a266dca233cb952e3f912 Mon Sep 17 00:00:00 2001 From: Luke Benstead Date: Sat, 14 Sep 2024 07:45:52 +0100 Subject: [PATCH 28/72] Fix a bug in the allocator# --- GL/alloc/alloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GL/alloc/alloc.c b/GL/alloc/alloc.c index 6760ff4..cde5588 100644 --- a/GL/alloc/alloc.c +++ b/GL/alloc/alloc.c @@ -456,7 +456,7 @@ void alloc_run_defrag(void* pool, defrag_address_move callback, int max_iteratio while(it) { void* potential_dest = alloc_next_available(pool, it->size); - if(potential_dest < it->pointer) { + if(potential_dest && potential_dest < it->pointer) { potential_dest = alloc_malloc(pool, it->size); memcpy(potential_dest, it->pointer, it->size); From 75b992f52e5e40f14765b0ce80e94a405aed90a2 Mon Sep 17 00:00:00 2001 From: Luke Benstead Date: Sat, 14 Sep 2024 07:51:13 +0100 Subject: [PATCH 29/72] Fix multiple bugs in the allocator --- GL/alloc/alloc.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/GL/alloc/alloc.c b/GL/alloc/alloc.c index cde5588..0058baf 100644 --- a/GL/alloc/alloc.c +++ b/GL/alloc/alloc.c @@ -244,13 +244,17 @@ int alloc_init(void* pool, size_t size) { memset(pool_header.block_usage, 0, BLOCK_COUNT); pool_header.pool = pool; - pool_header.pool_size = size; intptr_t base_address = (intptr_t) pool_header.pool; base_address = round_up(base_address, 2048); pool_header.base_address = (uint8_t*) base_address; pool_header.block_count = ((p + size) - pool_header.base_address) / 2048; + + /* The pool size might be less than the passed size if the memory + * wasn't aligned to 2048 */ + pool_header.pool_size = pool_header.block_count * 2048; + pool_header.allocations = NULL; assert(((uintptr_t) pool_header.base_address) % 2048 == 0); @@ -490,30 +494,24 @@ static inline uint8_t count_ones(uint8_t byte) { size_t alloc_count_free(void* pool) { (void) pool; - uint8_t* it = pool_header.block_usage; - uint8_t* end = it + pool_header.block_count; + size_t total_used = 0; - size_t total_free = 0; - - while(it < end) { - total_free += count_ones(*it) * 256; - ++it; + for(size_t i = 0; i < pool_header.block_count; ++i) { + total_used += count_ones(pool_header.block_usage[i]) * 256; } - return total_free; + return pool_header.pool_size - total_used; } size_t alloc_count_continuous(void* pool) { (void) pool; size_t largest_block = 0; - - uint8_t* it = pool_header.block_usage; - uint8_t* end = it + pool_header.block_count; - size_t current_block = 0; - while(it < end) { - uint8_t t = *it++; + + for(size_t i = 0; i < pool_header.block_count; ++i) { + uint8_t t = pool_header.block_usage[i]; + if(!t) { current_block += 2048; } else { @@ -530,5 +528,9 @@ size_t alloc_count_continuous(void* pool) { } } + if(largest_block < current_block) { + largest_block = current_block; + } + return largest_block; } From d978e3187c45ff3292eb4f177b07346933f0444f Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Tue, 1 Oct 2024 07:13:02 +1000 Subject: [PATCH 30/72] Fix array drawing mode not rendering properly in non-fast mode. Also move vertex transform to be done inline in non-fast path, instead of all entirely at the end --- GL/draw.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/GL/draw.c b/GL/draw.c index e7d1409..0a3a1bd 100644 --- a/GL/draw.c +++ b/GL/draw.c @@ -585,12 +585,13 @@ static void _readPositionData(ReadDiffuseFunc func, const GLuint first, const GL const GLsizei vstride = ATTRIB_POINTERS.vertex.stride; const GLubyte* vptr = ((GLubyte*) ATTRIB_POINTERS.vertex.ptr + (first * vstride)); - float pos[3]; + float pos[3], w = 1.0f; ITERATE(count) { PREFETCH(vptr + vstride); func(vptr, (GLubyte*) pos); it->flags = GPU_CMD_VERTEX; + TransformVertex(pos, &w, it->xyz, &it->w); vptr += vstride; ++it; @@ -678,6 +679,7 @@ static void generateElements( Vertex* output = _glSubmissionTargetStart(target); VertexExtra* ve = aligned_vector_at(target->extras, 0); + float pos[3], w = 1.0f; uint32_t i = first; uint32_t idx = 0; @@ -705,7 +707,8 @@ static void generateElements( st = (GLubyte*) ATTRIB_POINTERS.st.ptr + (idx * ststride); nxyz = (GLubyte*) ATTRIB_POINTERS.normal.ptr + (idx * nstride); - pos_func(xyz, (GLubyte*) output->xyz); + pos_func(xyz, (GLubyte*) pos); + TransformVertex((const float*) pos, &w, output->xyz, &output->w); uv_func(uv, (GLubyte*) output->uv); diffuse_func(bgra, output->bgra); st_func(st, (GLubyte*) ve->st); @@ -1178,12 +1181,6 @@ GL_FORCE_INLINE void submitVertices(GLenum mode, GLsizei first, GLuint count, GL /* If we're FAST_PATH_ENABLED, then this will do the transform for us */ generate(target, mode, first, count, (GLubyte*) indices, type); - /* No fast path, then we have to do another iteration :( */ - if(!FAST_PATH_ENABLED) { - /* Multiply by modelview */ - transform(target); - } - if(_glIsLightingEnabled()){ light(target); From a47f331ceea3bd1df9a232a54bbdc7e66d61c455 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Wed, 2 Oct 2024 07:48:44 +1000 Subject: [PATCH 31/72] Initial work on supporting missing primitive modes --- GL/draw.c | 189 +++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 167 insertions(+), 22 deletions(-) diff --git a/GL/draw.c b/GL/draw.c index 0a3a1bd..0e426d4 100644 --- a/GL/draw.c +++ b/GL/draw.c @@ -435,21 +435,129 @@ GL_FORCE_INLINE void genTriangleStrip(Vertex* output, GLuint count) { output[count - 1].flags = GPU_CMD_VERTEX_EOL; } -static void genTriangleFan(Vertex* output, GLuint count) { - gl_assert(count <= 255); +static void genQuadStrip(Vertex* output, GLuint count) { + Vertex* dst = output + (((count - 2) * 2) - 1); + Vertex* src = output + count;//(count - 1); + for (; count > 2; count -= 2) { + *dst = src[-1]; + (*dst--).flags = GPU_CMD_VERTEX_EOL; + *dst-- = src[-2]; + *dst-- = src[-3]; + *dst-- = src[-4]; + src -= 2; + } +} + +static void genTriangleFan(Vertex* output, GLuint count) { Vertex* dst = output + (((count - 2) * 3) - 1); Vertex* src = output + (count - 1); - GLubyte i = count - 2; - while(i--) { - *dst = *src--; + for (; count > 2; count--) { + *dst = *src--; (*dst--).flags = GPU_CMD_VERTEX_EOL; *dst-- = *src; *dst-- = *output; } } +#define POINTS_COUNT(count) ((count) * 4) +#define POINT_SIZE 0.5f +static void genPoints(Vertex* output, GLuint count) { + Vertex* dst = output + POINTS_COUNT(count) - 1; + Vertex* src = output + count - 1; + + // Expands v to { v + (-S/2,S/2), v + (S/2,S/2), v + (S/2,-S/2), (-S/2,-S/2) } + for (; count > 0; count--, src--) { + *dst = *src; + dst->flags = GPU_CMD_VERTEX_EOL; + dst->xyz[0] -= POINT_SIZE; dst->xyz[1] -= POINT_SIZE; + dst--; + + *dst = *src; + dst->xyz[0] += POINT_SIZE; dst->xyz[1] -= POINT_SIZE; + dst--; + + *dst = *src; + dst->xyz[0] += POINT_SIZE; dst->xyz[1] += POINT_SIZE; + dst--; + + *dst = *src; + dst->xyz[0] -= POINT_SIZE; dst->xyz[1] += POINT_SIZE; + dst--; + } +} + +static void genLines(Vertex* output, GLuint count) { + Vertex* dst = output + ((count/2) * 3) - 1; + Vertex* src = output + (count ) - 1; + + for (; count > 0; count -= 2) { + *dst = *src; + dst->flags = GPU_CMD_VERTEX_EOL; + dst--; src--; + + *dst = *src; + dst--; + + *dst = *src; + dst->xyz[1] += 5; + dst--; src--; + } +} + +static void genLineStrip(Vertex* output, GLuint count) { + Vertex* dst = output + (((count - 1) * 3) - 1); + Vertex* src = output + (count - 1); + + for (; count > 1; count--) { + *dst = *src; + dst->flags = GPU_CMD_VERTEX_EOL; + dst--; src--; + + *dst = *src; + dst--; + + *dst = *src; + dst->xyz[0] += 5; + dst->xyz[1] += 5; + dst--; + } +} + +static void genLineLoop(Vertex* output, GLuint count) { + Vertex* dst = output + ((count * 3) - 1); + Vertex* src = output + (count - 1); + Vertex last = *src; + + for (; count > 1; count--) { + *dst = *src; + dst->flags = GPU_CMD_VERTEX_EOL; + dst--; src--; + + *dst = *src; + dst--; + + *dst = *src; + dst->xyz[0] += 5; + dst->xyz[1] += 5; + dst--; + } + + // Connect first and last points + *dst = last; + dst->flags = GPU_CMD_VERTEX_EOL; + dst--; + + *dst = *output; + dst--; + + *dst = *output; + dst->xyz[0] += 5; + dst->xyz[1] += 5; + dst--; +} + typedef void (*ReadPositionFunc)(const GLubyte*, GLubyte*); typedef void (*ReadDiffuseFunc)(const GLubyte*, GLubyte*); typedef void (*ReadUVFunc)(const GLubyte*, GLubyte*); @@ -891,11 +999,28 @@ static void generate(SubmissionTarget* target, const GLenum mode, const GLsizei case GL_QUADS: genQuads(it, count); break; + case GL_TRIANGLE_STRIP: + genTriangleStrip(it, count); + break; + + case GL_QUAD_STRIP: + genQuadStrip(it, count); + break; case GL_TRIANGLE_FAN: genTriangleFan(it, count); break; - case GL_TRIANGLE_STRIP: - genTriangleStrip(it, count); + + case GL_POINTS: + genPoints(it, count); + break; + case GL_LINES: + genLines(it, count); + break; + case GL_LINE_STRIP: + genLineStrip(it, count); + break; + case GL_LINE_LOOP: + genLineLoop(it, count); break; default: gl_assert(0 && "Not Implemented"); @@ -1093,6 +1218,38 @@ void _glInitSubmissionTarget() { target->extras = &VERTEX_EXTRAS; } +GL_FORCE_INLINE GLuint calcFinalVertices(GLenum mode, GLuint count) { + switch (mode) { + case GL_POINTS: + return POINTS_COUNT(count); + + case GL_LINE_LOOP: + // Triangles generated as {prior vertex, current vertex, current vertex} + // plus one triangle to connect final and initial vertex + // e.g. {v1, v2, v3, v4} produces {v1, v1, v2}, {v2, v2, v3}, {v3, v3, v4}, {v4, v4, v1} + return count * 3; + + case GL_LINE_STRIP: + // Triangles generated as {prior vertex, prior vertex, current vertex} + // e.g. {v1, v2, v3, v4} produces {v1, v1, v2}, {v2, v2, v3}, {v3, v3, v4} + return (count - 1) * 3; + + case GL_LINES: + // Triangles generated as {first vertex, first vertex, second vertex} + // e.g. {v1, v2, v3, v4} produces {v1, v1, v2}, {v3, v3, v4} + return (count / 2) * 3; + + case GL_TRIANGLE_FAN: + // Triangles generated as {first vertex, prior vertex, current vertex} + // e.g. {v1, v2, v3, v4} produces {v1, v2, v3}, {v1, v3, v4} + return (count - 2) * 3; + + case GL_QUAD_STRIP: + //return ((count - 2) / 2) * 4; + return (count - 2) * 2; + } + return count; +} GL_FORCE_INLINE void submitVertices(GLenum mode, GLsizei first, GLuint count, GLenum type, const GLvoid* indices) { @@ -1102,14 +1259,10 @@ GL_FORCE_INLINE void submitVertices(GLenum mode, GLsizei first, GLuint count, GL TRACE(); /* Do nothing if vertices aren't enabled */ - if(!(ENABLED_VERTEX_ATTRIBUTES & VERTEX_ENABLED_FLAG)) { - return; - } + if(!(ENABLED_VERTEX_ATTRIBUTES & VERTEX_ENABLED_FLAG)) return; /* No vertices? Do nothing */ - if(!count) { - return; - } + if(!count) return; /* Polygons are treated as triangle fans, the only time this would be a * problem is if we supported glPolygonMode(..., GL_LINE) but we don't. @@ -1131,14 +1284,6 @@ GL_FORCE_INLINE void submitVertices(GLenum mode, GLsizei first, GLuint count, GL } } - if(mode == GL_LINE_STRIP || mode == GL_LINES) { - fprintf(stderr, "Line drawing is currently unsupported\n"); - return; - } - - // We don't handle this any further, so just make sure we never pass it down */ - gl_assert(mode != GL_POLYGON); - target->output = _glActivePolyList(); gl_assert(target->output); gl_assert(extras); @@ -1147,7 +1292,7 @@ GL_FORCE_INLINE void submitVertices(GLenum mode, GLsizei first, GLuint count, GL GLboolean header_required = (vector_size == 0) || _glGPUStateIsDirty(); - target->count = (mode == GL_TRIANGLE_FAN) ? ((count - 2) * 3) : count; + target->count = calcFinalVertices(mode, count); target->header_offset = vector_size; target->start_offset = target->header_offset + (header_required ? 1 : 0); From 19a76cbefd1bcc0273e232203859b1b7d6d4751d Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Wed, 2 Oct 2024 19:00:05 +1000 Subject: [PATCH 32/72] Fix lines --- GL/draw.c | 171 ++++++++++++++++++++++++------------------------ GL/private.h | 3 + GL/state.c | 9 ++- include/GL/gl.h | 5 +- 4 files changed, 100 insertions(+), 88 deletions(-) diff --git a/GL/draw.c b/GL/draw.c index 0e426d4..6071542 100644 --- a/GL/draw.c +++ b/GL/draw.c @@ -442,17 +442,20 @@ static void genQuadStrip(Vertex* output, GLuint count) { for (; count > 2; count -= 2) { *dst = src[-1]; (*dst--).flags = GPU_CMD_VERTEX_EOL; - *dst-- = src[-2]; *dst-- = src[-3]; + *dst-- = src[-2]; *dst-- = src[-4]; src -= 2; } } +#define TRIFAN_COUNT(count) (((count) - 2) * 3) static void genTriangleFan(Vertex* output, GLuint count) { - Vertex* dst = output + (((count - 2) * 3) - 1); - Vertex* src = output + (count - 1); + Vertex* dst = output + TRIFAN_COUNT(count) - 1; + Vertex* src = output + count - 1; + // Triangles generated as {first vertex, prior vertex, current vertex} + // e.g. {v1, v2, v3, v4} produces {v1, v2, v3}, {v1, v3, v4} for (; count > 2; count--) { *dst = *src--; (*dst--).flags = GPU_CMD_VERTEX_EOL; @@ -462,100 +465,111 @@ static void genTriangleFan(Vertex* output, GLuint count) { } #define POINTS_COUNT(count) ((count) * 4) -#define POINT_SIZE 0.5f static void genPoints(Vertex* output, GLuint count) { Vertex* dst = output + POINTS_COUNT(count) - 1; Vertex* src = output + count - 1; + float half_size = HALF_POINT_SIZE; - // Expands v to { v + (-S/2,S/2), v + (S/2,S/2), v + (S/2,-S/2), (-S/2,-S/2) } + // Expands v to { v + (-S/2,S/2), v + (S/2,S/2), v + (-S/2,S/2), (S/2,-S/2) } for (; count > 0; count--, src--) { *dst = *src; dst->flags = GPU_CMD_VERTEX_EOL; - dst->xyz[0] -= POINT_SIZE; dst->xyz[1] -= POINT_SIZE; + dst->xyz[0] -= half_size; dst->xyz[1] -= half_size; dst--; *dst = *src; - dst->xyz[0] += POINT_SIZE; dst->xyz[1] -= POINT_SIZE; + dst->xyz[0] += half_size; dst->xyz[1] -= half_size; dst--; *dst = *src; - dst->xyz[0] += POINT_SIZE; dst->xyz[1] += POINT_SIZE; + dst->xyz[0] -= half_size; dst->xyz[1] += half_size; dst--; *dst = *src; - dst->xyz[0] -= POINT_SIZE; dst->xyz[1] += POINT_SIZE; + dst->xyz[0] += half_size; dst->xyz[1] += half_size; dst--; } } -static void genLines(Vertex* output, GLuint count) { - Vertex* dst = output + ((count/2) * 3) - 1; - Vertex* src = output + (count ) - 1; +// Heavily based on the pvrline example by jnmartin84 +// Which is based on https://devcry.heiho.net/html/2017/20170820-opengl-line-drawing.html +static Vertex* draw_line(Vertex* dst, Vertex* v1, Vertex* v2) { + Vertex ov1 = *v1; + Vertex ov2 = *v2; + // TODO don't copy unless dst might overlap v1/v2 - for (; count > 0; count -= 2) { - *dst = *src; - dst->flags = GPU_CMD_VERTEX_EOL; - dst--; src--; + // Essentially "expands" a line into a quad by + // 1) Calculating normal of the line from v1 to v2 + // 2) Scaling normal by the line width + // 3) Offseting the endpoints wrt the scaled normal + float dx = ov2.xyz[0] - ov1.xyz[0]; + float dy = ov2.xyz[1] - ov1.xyz[1]; - *dst = *src; - dst--; + float inverse_mag = frsqrt((dx*dx) + (dy*dy)) * HALF_LINE_WIDTH; + float nx = -dy * inverse_mag; + float ny = dx * inverse_mag; - *dst = *src; - dst->xyz[1] += 5; - dst--; src--; - } -} - -static void genLineStrip(Vertex* output, GLuint count) { - Vertex* dst = output + (((count - 1) * 3) - 1); - Vertex* src = output + (count - 1); - - for (; count > 1; count--) { - *dst = *src; - dst->flags = GPU_CMD_VERTEX_EOL; - dst--; src--; - - *dst = *src; - dst--; - - *dst = *src; - dst->xyz[0] += 5; - dst->xyz[1] += 5; - dst--; - } -} - -static void genLineLoop(Vertex* output, GLuint count) { - Vertex* dst = output + ((count * 3) - 1); - Vertex* src = output + (count - 1); - Vertex last = *src; - - for (; count > 1; count--) { - *dst = *src; - dst->flags = GPU_CMD_VERTEX_EOL; - dst--; src--; - - *dst = *src; - dst--; - - *dst = *src; - dst->xyz[0] += 5; - dst->xyz[1] += 5; - dst--; - } - - // Connect first and last points - *dst = last; + // Expand first endpoint both "up" and "down" + *dst = ov1; dst->flags = GPU_CMD_VERTEX_EOL; + dst->xyz[0] += nx; + dst->xyz[1] += ny; dst--; - *dst = *output; + *dst = ov1; + dst->xyz[0] -= nx; + dst->xyz[1] -= ny; dst--; - *dst = *output; - dst->xyz[0] += 5; - dst->xyz[1] += 5; + // Expand second endpoint both "up" and "down" + *dst = ov2; + dst->xyz[0] += nx; + dst->xyz[1] += ny; dst--; + + *dst = ov2; + dst->xyz[0] -= nx; + dst->xyz[1] -= ny; + dst--; + + return dst; +} + +#define LINES_COUNT(count) (((count) / 2) * 4) +static void genLines(Vertex* output, GLuint count) { + Vertex* dst = output + LINES_COUNT(count) - 1; + Vertex* src = output + count - 1; + + // Draws line using two vertices + for (; count >= 2; count -= 2, src -= 2) { + dst = draw_line(dst, src, src - 1); + } +} + +#define LINE_STRIP_COUNT(count) (((count) - 1) * 4) +static void genLineStrip(Vertex* output, GLuint count) { + Vertex* dst = output + LINE_STRIP_COUNT(count) - 1; + Vertex* src = output + count - 1; + + // Draws line using current and prior vertex + for (; count > 1; count--, src--) { + dst = draw_line(dst, src, src - 1); + } +} + +#define LINE_LOOP_COUNT(count) ((count) * 4) +static void genLineLoop(Vertex* output, GLuint count) { + Vertex* dst = output + LINE_LOOP_COUNT(count) - 1; + Vertex* src = output + count - 1; + Vertex last = *src, first = *output; + + // Draws line using current and prior vertex + for (; count > 1; count--, src--) { + dst = draw_line(dst, src, src - 1); + } + + // Connect first and last vertex + draw_line(dst, &first, &last); } typedef void (*ReadPositionFunc)(const GLubyte*, GLubyte*); @@ -1222,27 +1236,14 @@ GL_FORCE_INLINE GLuint calcFinalVertices(GLenum mode, GLuint count) { switch (mode) { case GL_POINTS: return POINTS_COUNT(count); - case GL_LINE_LOOP: - // Triangles generated as {prior vertex, current vertex, current vertex} - // plus one triangle to connect final and initial vertex - // e.g. {v1, v2, v3, v4} produces {v1, v1, v2}, {v2, v2, v3}, {v3, v3, v4}, {v4, v4, v1} - return count * 3; - + return LINE_LOOP_COUNT(count); case GL_LINE_STRIP: - // Triangles generated as {prior vertex, prior vertex, current vertex} - // e.g. {v1, v2, v3, v4} produces {v1, v1, v2}, {v2, v2, v3}, {v3, v3, v4} - return (count - 1) * 3; - + return LINE_STRIP_COUNT(count); case GL_LINES: - // Triangles generated as {first vertex, first vertex, second vertex} - // e.g. {v1, v2, v3, v4} produces {v1, v1, v2}, {v3, v3, v4} - return (count / 2) * 3; - + return LINES_COUNT(count); case GL_TRIANGLE_FAN: - // Triangles generated as {first vertex, prior vertex, current vertex} - // e.g. {v1, v2, v3, v4} produces {v1, v2, v3}, {v1, v3, v4} - return (count - 2) * 3; + return TRIFAN_COUNT(count); case GL_QUAD_STRIP: //return ((count - 2) / 2) * 4; diff --git a/GL/private.h b/GL/private.h index 31a7872..6424e5d 100644 --- a/GL/private.h +++ b/GL/private.h @@ -320,6 +320,9 @@ void _glMatrixLoadModelViewProjection(); extern GLfloat DEPTH_RANGE_MULTIPLIER_L; extern GLfloat DEPTH_RANGE_MULTIPLIER_H; +extern GLfloat HALF_LINE_WIDTH; +extern GLfloat HALF_POINT_SIZE; + Matrix4x4* _glGetProjectionMatrix(); Matrix4x4* _glGetModelViewMatrix(); diff --git a/GL/state.c b/GL/state.c index ef7780f..fd28b2a 100644 --- a/GL/state.c +++ b/GL/state.c @@ -3,7 +3,8 @@ #include #include "private.h" - +GLfloat HALF_LINE_WIDTH = 1.0f / 2.0f; +GLfloat HALF_POINT_SIZE = 1.0f / 2.0f; static struct { GLboolean is_dirty; @@ -773,7 +774,11 @@ GLAPI void APIENTRY glAlphaFunc(GLenum func, GLclampf ref) { } void glLineWidth(GLfloat width) { - _GL_UNUSED(width); + HALF_LINE_WIDTH = width / 2.0f; +} + +void glPointSize(GLfloat size) { + HALF_POINT_SIZE = size / 2.0f; } void glPolygonOffset(GLfloat factor, GLfloat units) { diff --git a/include/GL/gl.h b/include/GL/gl.h index 61d434b..d3914de 100644 --- a/include/GL/gl.h +++ b/include/GL/gl.h @@ -552,6 +552,10 @@ GLAPI GLvoid APIENTRY glRecti(GLint x1, GLint y1, GLint x2, GLint y2); GLAPI GLvoid APIENTRY glRectiv(const GLint *v1, const GLint *v2); #define glRectsv glRectiv +/* Primitive configuration */ +GLAPI void APIENTRY glLineWidth(GLfloat width); +GLAPI void APIENTRY glPointSize(GLfloat size); + /* Enable / Disable Capability */ /* Currently Supported Capabilities: GL_TEXTURE_2D @@ -742,7 +746,6 @@ GLAPI GLenum APIENTRY glGetError(void); /* Non Operational Stubs for portability */ GLAPI void APIENTRY glAlphaFunc(GLenum func, GLclampf ref); -GLAPI void APIENTRY glLineWidth(GLfloat width); GLAPI void APIENTRY glPolygonMode(GLenum face, GLenum mode); GLAPI void APIENTRY glPolygonOffset(GLfloat factor, GLfloat units); GLAPI void APIENTRY glGetTexParameterfv(GLenum target, GLenum pname, GLfloat *params); From 165eb9d5c852bb0454b80638c0a9129929b43833 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Wed, 2 Oct 2024 19:28:02 +1000 Subject: [PATCH 33/72] Add primitive modes sample, quad strips partially work Although the second triangle is wrongly culled --- CMakeLists.txt | 1 + GL/draw.c | 18 ++-- samples/primitive_modes/main.c | 189 +++++++++++++++++++++++++++++++++ 3 files changed, 200 insertions(+), 8 deletions(-) create mode 100644 samples/primitive_modes/main.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 048f894..e51c14d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -209,6 +209,7 @@ gen_sample(scissor samples/scissor/main.c) gen_sample(polymark samples/polymark/main.c) gen_sample(cubes samples/cubes/main.cpp) gen_sample(zclip_test tests/zclip/main.cpp) +gen_sample(primitive_modes samples/primitive_modes/main.c) if(PLATFORM_DREAMCAST) gen_sample(trimark samples/trimark/main.c) diff --git a/GL/draw.c b/GL/draw.c index 6071542..a08be59 100644 --- a/GL/draw.c +++ b/GL/draw.c @@ -435,16 +435,20 @@ GL_FORCE_INLINE void genTriangleStrip(Vertex* output, GLuint count) { output[count - 1].flags = GPU_CMD_VERTEX_EOL; } +#define QUADSTRIP_COUNT(count) (((count) - 2) * 2) static void genQuadStrip(Vertex* output, GLuint count) { - Vertex* dst = output + (((count - 2) * 2) - 1); + Vertex* dst = output + QUADSTRIP_COUNT(count) - 1; Vertex* src = output + count;//(count - 1); for (; count > 2; count -= 2) { - *dst = src[-1]; + // Have to copy because of src/dst overlapping on first quad + Vertex src1 = src[-1], src2 = src[-2], src3 = src[-3], src4 = src[-4]; + + *dst = src3; (*dst--).flags = GPU_CMD_VERTEX_EOL; - *dst-- = src[-3]; - *dst-- = src[-2]; - *dst-- = src[-4]; + *dst-- = src4; + *dst-- = src1; + *dst-- = src2; src -= 2; } } @@ -1244,10 +1248,8 @@ GL_FORCE_INLINE GLuint calcFinalVertices(GLenum mode, GLuint count) { return LINES_COUNT(count); case GL_TRIANGLE_FAN: return TRIFAN_COUNT(count); - case GL_QUAD_STRIP: - //return ((count - 2) / 2) * 4; - return (count - 2) * 2; + return QUADSTRIP_COUNT(count); } return count; } diff --git a/samples/primitive_modes/main.c b/samples/primitive_modes/main.c new file mode 100644 index 0000000..db793cc --- /dev/null +++ b/samples/primitive_modes/main.c @@ -0,0 +1,189 @@ +#include +#include +#include + +#ifdef SDL2_BUILD +#include +static SDL_Window* win_handle; +#else +#include +#endif + +static void DrawLineLoop(float y) { + glBegin(GL_LINE_LOOP); + glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(410.0f, y + 10.0f); + glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(490.0f, y + 10.0f); + glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(490.0f, y + 90.0f); + glColor3f(1.0f, 1.0f, 1.0f); glVertex2f(410.0f, y + 90.0f); + glEnd(); +} + +static void DrawLineStrip(float y) { + glBegin(GL_LINE_STRIP); + glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(310.0f, y + 10.0f); + glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(390.0f, y + 10.0f); + glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(390.0f, y + 90.0f); + glColor3f(1.0f, 1.0f, 1.0f); glVertex2f(310.0f, y + 90.0f); + glEnd(); +} + +static void DrawLine(float y) { + glBegin(GL_LINES); + glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(210.0f, y + 10.0f); + glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(290.0f, y + 10.0f); + glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(290.0f, y + 90.0f); + glColor3f(1.0f, 1.0f, 1.0f); glVertex2f(210.0f, y + 90.0f); + + glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(230.0f, y + 25.0f); + glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(250.0f, y + 75.0f); + glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(260.0f, y + 75.0f); + glColor3f(1.0f, 1.0f, 1.0f); glVertex2f(280.0f, y + 45.0f); + glEnd(); +} + +static void DrawPoint(float y) { + glBegin(GL_POINTS); + glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(110.0f, y + 10.0f); + glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(190.0f, y + 10.0f); + glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(190.0f, y + 90.0f); + glColor3f(1.0f, 1.0f, 1.0f); glVertex2f(110.0f, y + 90.0f); + glEnd(); +} + +static void DrawQuad(float y) { + glBegin(GL_QUADS); + glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(10.0f, y + 10.0f); + glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(90.0f, y + 10.0f); + glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(90.0f, y + 90.0f); + glColor3f(1.0f, 1.0f, 1.0f); glVertex2f(10.0f, y + 90.0f); + + glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(110.0f, y + 10.0f); + glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(190.0f, y + 10.0f); + glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(190.0f, y + 90.0f); + glColor3f(1.0f, 1.0f, 1.0f); glVertex2f(110.0f, y + 90.0f); + glEnd(); +} + +static void DrawQuadStrip(float y) { + glBegin(GL_QUAD_STRIP); + glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(210.0f, y + 10.0f); + glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(290.0f, y + 10.0f); + glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(290.0f, y + 90.0f); + glColor3f(1.0f, 1.0f, 1.0f); glVertex2f(210.0f, y + 90.0f); + + glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(310.0f, y + 10.0f); + glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(390.0f, y + 10.0f); + glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(390.0f, y + 90.0f); + glColor3f(1.0f, 1.0f, 1.0f); glVertex2f(310.0f, y + 90.0f); + glEnd(); +} + +static void DrawTriList(float y) { + glBegin(GL_TRIANGLES); + glColor3f(1.0f, 0.0f, 0.0f); glVertex2f( 10.0f, y + 10.0f); + glColor3f(0.0f, 1.0f, 0.0f); glVertex2f( 90.0f, y + 10.0f); + glColor3f(0.0f, 0.0f, 1.0f); glVertex2f( 90.0f, y + 90.0f); + + glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(110.0f, y + 10.0f); + glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(190.0f, y + 10.0f); + glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(190.0f, y + 90.0f); + glEnd(); +} + +static void DrawTriStrip(float y) { + glBegin(GL_TRIANGLE_STRIP); + glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(210.0f, y + 10.0f); + glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(290.0f, y + 10.0f); + glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(290.0f, y + 90.0f); + glColor3f(1.0f, 1.0f, 1.0f); glVertex2f(210.0f, y + 90.0f); + + glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(310.0f, y + 10.0f); + glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(390.0f, y + 10.0f); + glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(390.0f, y + 90.0f); + glColor3f(1.0f, 1.0f, 1.0f); glVertex2f(310.0f, y + 90.0f); + glEnd(); +} + + +static void DrawTriFan(float y) { + glBegin(GL_TRIANGLE_FAN); + glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(410.0f, y + 10.0f); + glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(490.0f, y + 10.0f); + glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(445.0f, y + 90.0f); + + glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(590.0f, y + 10.0f); + glColor3f(1.0f, 1.0f, 1.0f); glVertex2f(510.0f, y + 45.0f); + glEnd(); +} + +int main(int argc, char *argv[]) { +#ifdef SDL2_BUILD + SDL_Init(SDL_INIT_EVERYTHING); + win_handle = SDL_CreateWindow("Shapes", 0, 0, 640, 480, SDL_WINDOW_OPENGL); + SDL_GL_CreateContext(win_handle); +#else + glKosInit(); +#endif + + glClearColor(0.5f, 0.5f, 0.5f, 1); + glViewport(0, 0, 640, 480); + + float mat[4][4] = { 0 }; + float L = 0, T = 0, R = 640, B = 480, N = -100, F = 100; + mat[0][0] = 2.0f / (R - L); + mat[1][1] = 2.0f / (T - B); + mat[2][2] = -2.0f / (F - N); + mat[3][0] = -(R + L) / (R - L); + mat[3][1] = -(T + B) / (T - B); + mat[3][2] = -(F + N) / (F - N); + mat[3][3] = 1; + glLoadMatrixf(mat); + + int running = 1; + + while (running) { + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + +#ifdef SDL2_BUILD + SDL_Event event; + while (SDL_PollEvent(&event)) { + if(event.type == SDL_QUIT) running = 0; + } +#endif + + DrawTriStrip(300); + DrawTriFan(300); + DrawTriList(300); + + DrawQuadStrip(200); + DrawQuad(200); + + glPointSize(5); + DrawPoint(100); + glLineWidth(0.5f); + DrawLineLoop(100); + glLineWidth(2); + DrawLineStrip(100); + glLineWidth(10); + DrawLine(100); + + glPointSize(1); + glLineWidth(1); + DrawPoint(0); + DrawLineLoop(0); + DrawLineStrip(0); + DrawLine(0); + + glShadeModel(GL_FLAT); + DrawQuad(400); + DrawTriStrip(400); + glShadeModel(GL_SMOOTH); + +#ifdef SDL2_BUILD + SDL_GL_SwapWindow(win_handle); +#else + glKosSwapBuffers(); +#endif + } + return 0; +} From 4513b040e2b1e73a6ca4f8369a48836f1627bd96 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Wed, 2 Oct 2024 20:07:36 +1000 Subject: [PATCH 34/72] Don't inline less optimal primitive modes --- GL/draw.c | 12 ++++++------ GL/private.h | 1 + 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/GL/draw.c b/GL/draw.c index a08be59..07dd976 100644 --- a/GL/draw.c +++ b/GL/draw.c @@ -436,7 +436,7 @@ GL_FORCE_INLINE void genTriangleStrip(Vertex* output, GLuint count) { } #define QUADSTRIP_COUNT(count) (((count) - 2) * 2) -static void genQuadStrip(Vertex* output, GLuint count) { +static GL_NO_INLINE void genQuadStrip(Vertex* output, GLuint count) { Vertex* dst = output + QUADSTRIP_COUNT(count) - 1; Vertex* src = output + count;//(count - 1); @@ -454,7 +454,7 @@ static void genQuadStrip(Vertex* output, GLuint count) { } #define TRIFAN_COUNT(count) (((count) - 2) * 3) -static void genTriangleFan(Vertex* output, GLuint count) { +static GL_NO_INLINE void genTriangleFan(Vertex* output, GLuint count) { Vertex* dst = output + TRIFAN_COUNT(count) - 1; Vertex* src = output + count - 1; @@ -469,7 +469,7 @@ static void genTriangleFan(Vertex* output, GLuint count) { } #define POINTS_COUNT(count) ((count) * 4) -static void genPoints(Vertex* output, GLuint count) { +static GL_NO_INLINE void genPoints(Vertex* output, GLuint count) { Vertex* dst = output + POINTS_COUNT(count) - 1; Vertex* src = output + count - 1; float half_size = HALF_POINT_SIZE; @@ -540,7 +540,7 @@ static Vertex* draw_line(Vertex* dst, Vertex* v1, Vertex* v2) { } #define LINES_COUNT(count) (((count) / 2) * 4) -static void genLines(Vertex* output, GLuint count) { +static GL_NO_INLINE void genLines(Vertex* output, GLuint count) { Vertex* dst = output + LINES_COUNT(count) - 1; Vertex* src = output + count - 1; @@ -551,7 +551,7 @@ static void genLines(Vertex* output, GLuint count) { } #define LINE_STRIP_COUNT(count) (((count) - 1) * 4) -static void genLineStrip(Vertex* output, GLuint count) { +static GL_NO_INLINE void genLineStrip(Vertex* output, GLuint count) { Vertex* dst = output + LINE_STRIP_COUNT(count) - 1; Vertex* src = output + count - 1; @@ -562,7 +562,7 @@ static void genLineStrip(Vertex* output, GLuint count) { } #define LINE_LOOP_COUNT(count) ((count) * 4) -static void genLineLoop(Vertex* output, GLuint count) { +static GL_NO_INLINE void genLineLoop(Vertex* output, GLuint count) { Vertex* dst = output + LINE_LOOP_COUNT(count) - 1; Vertex* src = output + count - 1; Vertex last = *src, first = *output; diff --git a/GL/private.h b/GL/private.h index 6424e5d..266af80 100644 --- a/GL/private.h +++ b/GL/private.h @@ -25,6 +25,7 @@ extern void* memcpy4 (void *dest, const void *src, size_t count); #define GL_NO_INSTRUMENT inline __attribute__((no_instrument_function)) #define GL_INLINE_DEBUG GL_NO_INSTRUMENT __attribute__((always_inline)) #define GL_FORCE_INLINE static GL_INLINE_DEBUG +#define GL_NO_INLINE __attribute__((noinline)) #define _GL_UNUSED(x) (void)(x) #define _PACK4(v) ((v * 0xF) / 0xFF) From 2b06418fedffa9ef81539bc1236ac3b7608429f4 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Wed, 2 Oct 2024 20:27:28 +1000 Subject: [PATCH 35/72] Fix not compiling on desktop due to relying on KOS specific frsqrt --- GL/draw.c | 2 +- GL/private.h | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/GL/draw.c b/GL/draw.c index 07dd976..d54e775 100644 --- a/GL/draw.c +++ b/GL/draw.c @@ -509,7 +509,7 @@ static Vertex* draw_line(Vertex* dst, Vertex* v1, Vertex* v2) { float dx = ov2.xyz[0] - ov1.xyz[0]; float dy = ov2.xyz[1] - ov1.xyz[1]; - float inverse_mag = frsqrt((dx*dx) + (dy*dy)) * HALF_LINE_WIDTH; + float inverse_mag = fast_rsqrt((dx*dx) + (dy*dy)) * HALF_LINE_WIDTH; float nx = -dy * inverse_mag; float ny = dx * inverse_mag; diff --git a/GL/private.h b/GL/private.h index 266af80..8230f01 100644 --- a/GL/private.h +++ b/GL/private.h @@ -260,6 +260,12 @@ do { \ memcpy_vertex(b, &c); \ } while(0) +#ifdef __DREAMCAST__ +#define fast_rsqrt(x) frsqrt(x) +#else +#define fast_rsqrt(x) (1.0f / __builtin_sqrtf(x)) +#endif + /* ClipVertex doesn't have room for these, so we need to parse them * out separately. Potentially 'w' will be housed here if we support oargb */ typedef struct { From c30b16b97ba5a05566b0234b79d89256b5063f57 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Thu, 3 Oct 2024 08:08:33 +1000 Subject: [PATCH 36/72] Fix points/lines being improperly culled --- GL/draw.c | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/GL/draw.c b/GL/draw.c index d54e775..cd4dc91 100644 --- a/GL/draw.c +++ b/GL/draw.c @@ -474,24 +474,24 @@ static GL_NO_INLINE void genPoints(Vertex* output, GLuint count) { Vertex* src = output + count - 1; float half_size = HALF_POINT_SIZE; - // Expands v to { v + (-S/2,S/2), v + (S/2,S/2), v + (-S/2,S/2), (S/2,-S/2) } + // Expands v to { v + (S/2,-S/2), v + (S/2,S/2), v + (-S/2,-S/2), (-S/2,S/2) } for (; count > 0; count--, src--) { *dst = *src; dst->flags = GPU_CMD_VERTEX_EOL; - dst->xyz[0] -= half_size; dst->xyz[1] -= half_size; - dst--; - - *dst = *src; - dst->xyz[0] += half_size; dst->xyz[1] -= half_size; - dst--; - - *dst = *src; dst->xyz[0] -= half_size; dst->xyz[1] += half_size; dst--; *dst = *src; dst->xyz[0] += half_size; dst->xyz[1] += half_size; dst--; + + *dst = *src; + dst->xyz[0] -= half_size; dst->xyz[1] -= half_size; + dst--; + + *dst = *src; + dst->xyz[0] += half_size; dst->xyz[1] -= half_size; + dst--; } } @@ -513,11 +513,10 @@ static Vertex* draw_line(Vertex* dst, Vertex* v1, Vertex* v2) { float nx = -dy * inverse_mag; float ny = dx * inverse_mag; - // Expand first endpoint both "up" and "down" - *dst = ov1; + *dst = ov2; dst->flags = GPU_CMD_VERTEX_EOL; - dst->xyz[0] += nx; - dst->xyz[1] += ny; + dst->xyz[0] -= nx; + dst->xyz[1] -= ny; dst--; *dst = ov1; @@ -525,15 +524,14 @@ static Vertex* draw_line(Vertex* dst, Vertex* v1, Vertex* v2) { dst->xyz[1] -= ny; dst--; - // Expand second endpoint both "up" and "down" *dst = ov2; dst->xyz[0] += nx; dst->xyz[1] += ny; dst--; - *dst = ov2; - dst->xyz[0] -= nx; - dst->xyz[1] -= ny; + *dst = ov1; + dst->xyz[0] += nx; + dst->xyz[1] += ny; dst--; return dst; From ea56577ca9d9314bed20561e2ae134e40dde4fbe Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Fri, 4 Oct 2024 19:51:33 +1000 Subject: [PATCH 37/72] Use direct render APIs instead of manually locking/unlocking store queues This ensures that GLdc works in both 2.1.0 and latest matter --- GL/platforms/sh4.c | 58 ++++++++++++++++++++-------------------------- 1 file changed, 25 insertions(+), 33 deletions(-) diff --git a/GL/platforms/sh4.c b/GL/platforms/sh4.c index 409c94b..a8f133a 100644 --- a/GL/platforms/sh4.c +++ b/GL/platforms/sh4.c @@ -60,20 +60,11 @@ void InitGPU(_Bool autosort, _Bool fsaa) { #endif } -void SceneBegin() { - pvr_wait_ready(); - pvr_scene_begin(); -} - -void SceneListBegin(GPUList list) { - pvr_list_begin(list); -} - GL_FORCE_INLINE float _glFastInvert(float x) { return (1.0f / __builtin_sqrtf(x * x)); } -GL_FORCE_INLINE void _glPerspectiveDivideVertex(Vertex* vertex, const float h, int count) { +GL_FORCE_INLINE void _glPerspectiveDivideVertex(Vertex* vertex, int count) { TRACE(); for(int v = 0; v < count; ++v) { @@ -97,12 +88,6 @@ GL_FORCE_INLINE void _glPerspectiveDivideVertex(Vertex* vertex, const float h, i } } -static inline void _glFlushBuffer() { - TRACE(); - - sq_wait(); -} - static uintptr_t sq_dest_addr = 0; static inline void _glPushHeaderOrVertex(Vertex* v, size_t count) { @@ -164,8 +149,6 @@ void SceneListSubmit(Vertex* vertices, int n) { return; } - const float h = GetVideoMode()->height; - PVR_SET(SPAN_SORT_CFG, 0x0); //Set PVR DMA registers @@ -199,9 +182,7 @@ void SceneListSubmit(Vertex* vertices, int n) { do { if(queued_vertex) { queued_vertex->flags = (sflags); _glPushHeaderOrVertex(queued_vertex, 1); queued_vertex = NULL; } } while(0) int visible_mask = 0; - sq_dest_addr = (uintptr_t)SQ_MASK_DEST(PVR_TA_INPUT); - sq_lock((void *)PVR_TA_INPUT); Vertex* v0 = vertices; for(int i = 0; i < n - 1; ++i, ++v0) { @@ -230,7 +211,7 @@ void SceneListSubmit(Vertex* vertices, int n) { if(visible_mask == ALL_VISIBLE) { SUBMIT_QUEUED_VERTEX(qv.flags); - _glPerspectiveDivideVertex(v0, h, 2); + _glPerspectiveDivideVertex(v0, 2); v1->flags = GPU_CMD_VERTEX_EOL; _glPushHeaderOrVertex(v0, 2); } else { @@ -268,7 +249,7 @@ void SceneListSubmit(Vertex* vertices, int n) { switch(visible_mask) { case ALL_VISIBLE: - _glPerspectiveDivideVertex(v0, h, 1); + _glPerspectiveDivideVertex(v0, 1); QUEUE_VERTEX(v0); break; case NONE_VISIBLE: @@ -281,10 +262,10 @@ void SceneListSubmit(Vertex* vertices, int n) { _glClipEdge(v2, v0, b); b->flags = GPU_CMD_VERTEX; - _glPerspectiveDivideVertex(v0, h, 1); + _glPerspectiveDivideVertex(v0, 1); _glPushHeaderOrVertex(v0, 1); - _glPerspectiveDivideVertex(a, h, 2); + _glPerspectiveDivideVertex(a, 2); _glPushHeaderOrVertex(a, 2); QUEUE_VERTEX(b); @@ -298,7 +279,7 @@ void SceneListSubmit(Vertex* vertices, int n) { _glClipEdge(v1, v2, b); b->flags = v2->flags; - _glPerspectiveDivideVertex(a, h, 3); + _glPerspectiveDivideVertex(a, 3); _glPushHeaderOrVertex(a, 1); _glPushHeaderOrVertex(c, 1); @@ -314,7 +295,7 @@ void SceneListSubmit(Vertex* vertices, int n) { _glClipEdge(v1, v2, b); b->flags = GPU_CMD_VERTEX; - _glPerspectiveDivideVertex(a, h, 3); + _glPerspectiveDivideVertex(a, 3); _glPushHeaderOrVertex(a, 2); QUEUE_VERTEX(c); @@ -325,13 +306,13 @@ void SceneListSubmit(Vertex* vertices, int n) { _glClipEdge(v2, v0, b); b->flags = GPU_CMD_VERTEX; - _glPerspectiveDivideVertex(v0, h, 1); + _glPerspectiveDivideVertex(v0, 1); _glPushHeaderOrVertex(v0, 1); _glClipEdge(v1, v2, a); a->flags = v2->flags; - _glPerspectiveDivideVertex(a, h, 3); + _glPerspectiveDivideVertex(a, 3); _glPushHeaderOrVertex(c, 1); @@ -349,7 +330,7 @@ void SceneListSubmit(Vertex* vertices, int n) { _glClipEdge(v2, v0, b); b->flags = GPU_CMD_VERTEX; - _glPerspectiveDivideVertex(a, h, 4); + _glPerspectiveDivideVertex(a, 4); _glPushHeaderOrVertex(a, 1); _glPushHeaderOrVertex(c, 1); @@ -368,10 +349,10 @@ void SceneListSubmit(Vertex* vertices, int n) { _glClipEdge(v1, v2, b); b->flags = GPU_CMD_VERTEX; - _glPerspectiveDivideVertex(v0, h, 1); + _glPerspectiveDivideVertex(v0, 1); _glPushHeaderOrVertex(v0, 1); - _glPerspectiveDivideVertex(a, h, 3); + _glPerspectiveDivideVertex(a, 3); _glPushHeaderOrVertex(a, 1); _glPushHeaderOrVertex(c, 1); @@ -387,8 +368,19 @@ void SceneListSubmit(Vertex* vertices, int n) { SUBMIT_QUEUED_VERTEX(GPU_CMD_VERTEX_EOL); - _glFlushBuffer(); - sq_unlock(); + sq_wait(); +} + +void SceneBegin() { + pvr_wait_ready(); + pvr_scene_begin(); +} + +static pvr_dr_state_t dr_state; +void SceneListBegin(GPUList list) { + pvr_list_begin(list); + /* Direct rendering auto acquires/releases store queue */ + pvr_dr_init(&dr_state); } void SceneListFinish() { From 6f0acd5218e9cec5c7792fcfa4652ed266beaad6 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Fri, 4 Oct 2024 22:11:42 +1000 Subject: [PATCH 38/72] Only check whether twiddle table needs updating once instead of every pixel Based on checking disassembly output in Release mode --- GL/texture.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/GL/texture.c b/GL/texture.c index 5d70419..70f4258 100644 --- a/GL/texture.c +++ b/GL/texture.c @@ -78,15 +78,16 @@ void build_twiddle_table(int32_t w, int32_t h) { } } -/* Given a 0-based texel location, and an image width/height. Return the - * new 0-based texel location */ -GL_FORCE_INLINE uint32_t twid_location(uint32_t i, uint32_t w, uint32_t h) { +static void twid_prepare_table(uint32_t w, uint32_t h) { if(TWIDDLE_TABLE.width != w || TWIDDLE_TABLE.height != h || !TWIDDLE_TABLE.table) { build_twiddle_table(w, h); } +} - uint32_t ret = TWIDDLE_TABLE.table[i]; - return ret; +/* Given a 0-based texel location, returns new 0-based texel location */ +/* NOTE: twid_prepare_table must have been called beforehand for correct behaviour */ +GL_FORCE_INLINE uint32_t twid_location(uint32_t i) { + return TWIDDLE_TABLE.table[i]; } @@ -1634,8 +1635,10 @@ void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat, if(is4BPPFormat(internalFormat) && is4BPPFormat(format)) { // Special case twiddling. We have to unpack each src value // and repack into the right place + twid_prepare_table(width, height); + for(uint32_t i = 0; i < (width * height); ++i) { - uint32_t newLocation = twid_location(i, width, height); + uint32_t newLocation = twid_location(i); assert(newLocation < (width * height)); assert((newLocation / 2) < destBytes); @@ -1655,8 +1658,10 @@ void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat, } } } else { + twid_prepare_table(width, height); + for(uint32_t i = 0; i < (width * height); ++i) { - uint32_t newLocation = twid_location(i, width, height); + uint32_t newLocation = twid_location(i); dst = conversionBuffer + (destStride * newLocation); for(int j = 0; j < destStride; ++j) @@ -1667,8 +1672,10 @@ void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat, } } else if(needs_conversion == 3) { // Convert + twiddle + twid_prepare_table(width, height); + for(uint32_t i = 0; i < (width * height); ++i) { - uint32_t newLocation = twid_location(i, width, height); + uint32_t newLocation = twid_location(i); dst = conversionBuffer + (destStride * newLocation); src = data + (sourceStride * i); conversion(src, dst); From 82d64618f8e95d7248c4a31e9018619541b1c966 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sat, 5 Oct 2024 06:49:04 +1000 Subject: [PATCH 39/72] Primitive modes sample should let you press START to exit, like other samples --- samples/primitive_modes/main.c | 43 ++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/samples/primitive_modes/main.c b/samples/primitive_modes/main.c index db793cc..f1fa78e 100644 --- a/samples/primitive_modes/main.c +++ b/samples/primitive_modes/main.c @@ -2,10 +2,11 @@ #include #include -#ifdef SDL2_BUILD +#ifndef __DREAMCAST__ #include static SDL_Window* win_handle; #else +#include #include #endif @@ -116,15 +117,36 @@ static void DrawTriFan(float y) { glEnd(); } -int main(int argc, char *argv[]) { -#ifdef SDL2_BUILD +static void sample_init() { +#ifndef __DREAMCAST__ SDL_Init(SDL_INIT_EVERYTHING); win_handle = SDL_CreateWindow("Shapes", 0, 0, 640, 480, SDL_WINDOW_OPENGL); SDL_GL_CreateContext(win_handle); #else glKosInit(); #endif +} +static int sample_should_exit() { +#ifndef __DREAMCAST__ + SDL_Event event; + while (SDL_PollEvent(&event)) { + if(event.type == SDL_QUIT) return 1; + } + return 0; +#else + maple_device_t *cont = maple_enum_type(0, MAPLE_FUNC_CONTROLLER); + if (!cont) return 0; + + cont_state_t *state = (cont_state_t *)maple_dev_status(cont); + if (!state) return 0; + + return state->buttons & CONT_START; +#endif +} + +int main(int argc, char *argv[]) { + sample_init(); glClearColor(0.5f, 0.5f, 0.5f, 1); glViewport(0, 0, 640, 480); @@ -139,18 +161,9 @@ int main(int argc, char *argv[]) { mat[3][3] = 1; glLoadMatrixf(mat); - int running = 1; - - while (running) { + while (!sample_should_exit()) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); -#ifdef SDL2_BUILD - SDL_Event event; - while (SDL_PollEvent(&event)) { - if(event.type == SDL_QUIT) running = 0; - } -#endif - DrawTriStrip(300); DrawTriFan(300); DrawTriList(300); @@ -160,9 +173,9 @@ int main(int argc, char *argv[]) { glPointSize(5); DrawPoint(100); - glLineWidth(0.5f); - DrawLineLoop(100); glLineWidth(2); + DrawLineLoop(100); + glLineWidth(4); DrawLineStrip(100); glLineWidth(10); DrawLine(100); From a1b104c9182077379829d70438e2c2e22b4b4363 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sat, 5 Oct 2024 11:34:14 +1000 Subject: [PATCH 40/72] Move aligned_vector_reserve onto cold path since it should rarely be called E.g. with glVertex3f this means 3 less CPU registers are saved onto the stack --- containers/aligned_vector.c | 26 +++++++++++++++++++++++++- containers/aligned_vector.h | 30 +++++------------------------- 2 files changed, 30 insertions(+), 26 deletions(-) diff --git a/containers/aligned_vector.c b/containers/aligned_vector.c index f75459a..7048219 100644 --- a/containers/aligned_vector.c +++ b/containers/aligned_vector.c @@ -14,7 +14,6 @@ extern inline void* aligned_vector_resize(AlignedVector* vector, const uint32_t element_count); extern inline void* aligned_vector_extend(AlignedVector* vector, const uint32_t additional_count); -extern inline void* aligned_vector_reserve(AlignedVector* vector, uint32_t element_count); extern inline void* aligned_vector_push_back(AlignedVector* vector, const void* objs, uint32_t count); void aligned_vector_init(AlignedVector* vector, uint32_t element_size) { @@ -31,6 +30,31 @@ void aligned_vector_init(AlignedVector* vector, uint32_t element_size) { (void) ptr; } +void* aligned_vector_reserve(AlignedVector* vector, uint32_t element_count) { + AlignedVectorHeader* hdr = &vector->hdr; + + if(element_count < hdr->capacity) { + return aligned_vector_at(vector, element_count); + } + + uint32_t original_byte_size = (hdr->size * hdr->element_size); + + /* We overallocate so that we don't make small allocations during push backs */ + element_count = ROUND_TO_CHUNK_SIZE(element_count); + + uint32_t new_byte_size = (element_count * hdr->element_size); + uint8_t* original_data = vector->data; + + vector->data = (uint8_t*) memalign(0x20, new_byte_size); + assert(vector->data); + + AV_MEMCPY4(vector->data, original_data, original_byte_size); + free(original_data); + + hdr->capacity = element_count; + return vector->data + original_byte_size; +} + void aligned_vector_shrink_to_fit(AlignedVector* vector) { AlignedVectorHeader* const hdr = &vector->hdr; if(hdr->size == 0) { diff --git a/containers/aligned_vector.h b/containers/aligned_vector.h index d700b86..e58cf93 100644 --- a/containers/aligned_vector.h +++ b/containers/aligned_vector.h @@ -27,6 +27,7 @@ static inline void* memalign(size_t alignment, size_t size) { #define AV_INLINE_DEBUG AV_NO_INSTRUMENT __attribute__((always_inline)) #define AV_FORCE_INLINE static AV_INLINE_DEBUG #endif +#define AV_NO_INLINE __attribute__((noinline)) #ifdef __DREAMCAST__ @@ -86,37 +87,16 @@ typedef struct { void aligned_vector_init(AlignedVector* vector, uint32_t element_size); +/* Resizes the backing array if necessary so that element_count elements can fit in the array */ +/* (note that only capacity is potentially changed, size is never changed) */ +AV_NO_INLINE void* aligned_vector_reserve(AlignedVector* vector, uint32_t element_count); + AV_FORCE_INLINE void* aligned_vector_at(const AlignedVector* vector, const uint32_t index) { const AlignedVectorHeader* hdr = &vector->hdr; assert(index < hdr->size); return vector->data + (index * hdr->element_size); } -AV_FORCE_INLINE void* aligned_vector_reserve(AlignedVector* vector, uint32_t element_count) { - AlignedVectorHeader* hdr = &vector->hdr; - - if(element_count < hdr->capacity) { - return aligned_vector_at(vector, element_count); - } - - uint32_t original_byte_size = (hdr->size * hdr->element_size); - - /* We overallocate so that we don't make small allocations during push backs */ - element_count = ROUND_TO_CHUNK_SIZE(element_count); - - uint32_t new_byte_size = (element_count * hdr->element_size); - uint8_t* original_data = vector->data; - - vector->data = (uint8_t*) memalign(0x20, new_byte_size); - assert(vector->data); - - AV_MEMCPY4(vector->data, original_data, original_byte_size); - free(original_data); - - hdr->capacity = element_count; - return vector->data + original_byte_size; -} - AV_FORCE_INLINE AlignedVectorHeader* aligned_vector_header(const AlignedVector* vector) { return (AlignedVectorHeader*) &vector->hdr; } From 91b59ceca803b775d28ecfef567aa8cd33703759 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Mon, 7 Oct 2024 18:06:03 +1100 Subject: [PATCH 41/72] glXYZPointer methods now avoid recomputing state when only the data pointer changes It is relatively common to call glXYZPointer multiple times with a different pointer but the same type/size --- GL/draw.c | 64 ++++++++++++++++++++++--------------------------------- 1 file changed, 25 insertions(+), 39 deletions(-) diff --git a/GL/draw.c b/GL/draw.c index cd4dc91..b822c7f 100644 --- a/GL/draw.c +++ b/GL/draw.c @@ -1253,7 +1253,6 @@ GL_FORCE_INLINE GLuint calcFinalVertices(GLenum mode, GLuint count) { } GL_FORCE_INLINE void submitVertices(GLenum mode, GLsizei first, GLuint count, GLenum type, const GLvoid* indices) { - SubmissionTarget* const target = &SUBMISSION_TARGET; AlignedVector* const extras = target->extras; @@ -1324,7 +1323,6 @@ GL_FORCE_INLINE void submitVertices(GLenum mode, GLsizei first, GLuint count, GL _glMatrixLoadModelViewProjection(); } - /* If we're FAST_PATH_ENABLED, then this will do the transform for us */ generate(target, mode, first, count, (GLubyte*) indices, type); if(_glIsLightingEnabled()){ @@ -1468,28 +1466,25 @@ void APIENTRY glClientActiveTextureARB(GLenum texture) { ACTIVE_CLIENT_TEXTURE = (texture == GL_TEXTURE1_ARB) ? 1 : 0; } -GL_FORCE_INLINE GLboolean _glComparePointers(AttribPointer* p, GLint size, GLenum type, GLsizei stride, const GLvoid* pointer) { - return (p->size == size && p->type == type && p->stride == stride && p->ptr == pointer); +// Used to avoid checking and updating attribute related state unless necessary +GL_FORCE_INLINE GLboolean _glStateUnchanged(AttribPointer* p, GLint size, GLenum type, GLsizei stride) { + return (p->size == size && p->type == type && p->stride == stride); } void APIENTRY glTexCoordPointer(GLint size, GLenum type, GLsizei stride, const GLvoid * pointer) { TRACE(); + stride = (stride) ? stride : size * byte_size(type); + AttribPointer* tointer = (ACTIVE_CLIENT_TEXTURE == 0) ? &ATTRIB_POINTERS.uv : &ATTRIB_POINTERS.st; + tointer->ptr = pointer; + + if(_glStateUnchanged(tointer, size, type, stride)) return; + if(size < 1 || size > 4) { _glKosThrowError(GL_INVALID_VALUE, __func__); return; } - stride = (stride) ? stride : size * byte_size(type); - - AttribPointer* tointer = (ACTIVE_CLIENT_TEXTURE == 0) ? &ATTRIB_POINTERS.uv : &ATTRIB_POINTERS.st; - - if(_glComparePointers(tointer, size, type, stride, pointer)) { - // No Change - return; - } - - tointer->ptr = pointer; tointer->stride = stride; tointer->type = type; tointer->size = size; @@ -1497,22 +1492,19 @@ void APIENTRY glTexCoordPointer(GLint size, GLenum type, GLsizei stride, const G _glRecalcFastPath(); } -void APIENTRY glVertexPointer(GLint size, GLenum type, GLsizei stride, const GLvoid * pointer) { +void APIENTRY glVertexPointer(GLint size, GLenum type, GLsizei stride, const GLvoid * pointer) { TRACE(); + stride = (stride) ? stride : (size * byte_size(type)); + ATTRIB_POINTERS.vertex.ptr = pointer; + + if(_glStateUnchanged(&ATTRIB_POINTERS.vertex, size, type, stride)) return; + if(size < 2 || size > 4) { _glKosThrowError(GL_INVALID_VALUE, __func__); return; } - stride = (stride) ? stride : (size * byte_size(ATTRIB_POINTERS.vertex.type)); - - if(_glComparePointers(&ATTRIB_POINTERS.vertex, size, type, stride, pointer)) { - // No Change - return; - } - - ATTRIB_POINTERS.vertex.ptr = pointer; ATTRIB_POINTERS.vertex.stride = stride; ATTRIB_POINTERS.vertex.type = type; ATTRIB_POINTERS.vertex.size = size; @@ -1523,19 +1515,16 @@ void APIENTRY glVertexPointer(GLint size, GLenum type, GLsizei stride, const G void APIENTRY glColorPointer(GLint size, GLenum type, GLsizei stride, const GLvoid * pointer) { TRACE(); + stride = (stride) ? stride : ((size == GL_BGRA) ? 4 : size) * byte_size(type); + ATTRIB_POINTERS.colour.ptr = pointer; + + if(_glStateUnchanged(&ATTRIB_POINTERS.colour, size, type, stride)) return; + if(size != 3 && size != 4 && size != GL_BGRA) { _glKosThrowError(GL_INVALID_VALUE, __func__); return; } - stride = (stride) ? stride : ((size == GL_BGRA) ? 4 : size) * byte_size(type); - - if(_glComparePointers(&ATTRIB_POINTERS.colour, size, type, stride, pointer)) { - // No Change - return; - } - - ATTRIB_POINTERS.colour.ptr = pointer; ATTRIB_POINTERS.colour.type = type; ATTRIB_POINTERS.colour.size = size; ATTRIB_POINTERS.colour.stride = stride; @@ -1557,18 +1546,15 @@ void APIENTRY glNormalPointer(GLenum type, GLsizei stride, const GLvoid * poin 0 }; + stride = (stride) ? stride : ATTRIB_POINTERS.normal.size * byte_size(type); + ATTRIB_POINTERS.normal.ptr = pointer; + + if(_glStateUnchanged(&ATTRIB_POINTERS.normal, 3, type, stride)) return; + if(_glCheckValidEnum(type, validTypes, __func__) != 0) { return; } - stride = (stride) ? stride : ATTRIB_POINTERS.normal.size * byte_size(type); - - if(_glComparePointers(&ATTRIB_POINTERS.normal, 3, type, stride, pointer)) { - // No Change - return; - } - - ATTRIB_POINTERS.normal.ptr = pointer; ATTRIB_POINTERS.normal.size = (type == GL_UNSIGNED_INT_2_10_10_10_REV) ? 1 : 3; ATTRIB_POINTERS.normal.stride = stride; ATTRIB_POINTERS.normal.type = type; From 490bf3de6dd4f0be410f2376634741c79bb1b620 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Mon, 7 Oct 2024 18:06:42 +1100 Subject: [PATCH 42/72] Unify and slightly simplify specialised matrix multiply functions --- GL/matrix.c | 125 +++++++++++++++++++++------------------------------- 1 file changed, 51 insertions(+), 74 deletions(-) diff --git a/GL/matrix.c b/GL/matrix.c index 104f8a1..4d7ac5d 100644 --- a/GL/matrix.c +++ b/GL/matrix.c @@ -139,6 +139,15 @@ void APIENTRY glLoadIdentity() { OnMatrixChanged(); } +void GL_FORCE_INLINE _glMultMatrix(const Matrix4x4* mat) { + void* top = stack_top(MATRIX_STACKS + MATRIX_IDX); + + UploadMatrix4x4(top); + MultiplyMatrix4x4(mat); + DownloadMatrix4x4(top); + OnMatrixChanged(); +} + void APIENTRY glTranslatef(GLfloat x, GLfloat y, GLfloat z) { const Matrix4x4 trn __attribute__((aligned(32))) = { 1.0f, 0.0f, 0.0f, 0.0f, @@ -146,17 +155,7 @@ void APIENTRY glTranslatef(GLfloat x, GLfloat y, GLfloat z) { 0.0f, 0.0f, 1.0f, 0.0f, x, y, z, 1.0f }; - void* top = stack_top(MATRIX_STACKS + MATRIX_IDX); - assert(top); - - UploadMatrix4x4(top); - MultiplyMatrix4x4(&trn); - - top = stack_top(MATRIX_STACKS + MATRIX_IDX); - assert(top); - - DownloadMatrix4x4(top); - OnMatrixChanged(); + _glMultMatrix(&trn); } @@ -167,11 +166,7 @@ void APIENTRY glScalef(GLfloat x, GLfloat y, GLfloat z) { 0.0f, 0.0f, z, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f }; - - UploadMatrix4x4(stack_top(MATRIX_STACKS + MATRIX_IDX)); - MultiplyMatrix4x4(&scale); - DownloadMatrix4x4(stack_top(MATRIX_STACKS + MATRIX_IDX)); - OnMatrixChanged(); + _glMultMatrix(&scale); } void APIENTRY glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) { @@ -213,10 +208,7 @@ void APIENTRY glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) { rotate[M9] = yz * invc - xs; rotate[M10] = (z * z) * invc + c; - UploadMatrix4x4(stack_top(MATRIX_STACKS + MATRIX_IDX)); - MultiplyMatrix4x4((const Matrix4x4*) &rotate); - DownloadMatrix4x4(stack_top(MATRIX_STACKS + MATRIX_IDX)); - OnMatrixChanged(); + _glMultMatrix(&rotate); } /* Load an arbitrary matrix */ @@ -233,25 +225,21 @@ void APIENTRY glOrtho(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat znear, GLfloat zfar) { - /* Ortho Matrix */ - Matrix4x4 OrthoMatrix __attribute__((aligned(32))) = { + Matrix4x4 ortho __attribute__((aligned(32))) = { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f }; - OrthoMatrix[M0] = 2.0f / (right - left); - OrthoMatrix[M5] = 2.0f / (top - bottom); - OrthoMatrix[M10] = -2.0f / (zfar - znear); - OrthoMatrix[M12] = -(right + left) / (right - left); - OrthoMatrix[M13] = -(top + bottom) / (top - bottom); - OrthoMatrix[M14] = -(zfar + znear) / (zfar - znear); + ortho[M0] = 2.0f / (right - left); + ortho[M5] = 2.0f / (top - bottom); + ortho[M10] = -2.0f / (zfar - znear); + ortho[M12] = -(right + left) / (right - left); + ortho[M13] = -(top + bottom) / (top - bottom); + ortho[M14] = -(zfar + znear) / (zfar - znear); - UploadMatrix4x4(stack_top(MATRIX_STACKS + MATRIX_IDX)); - MultiplyMatrix4x4((const Matrix4x4*) &OrthoMatrix); - DownloadMatrix4x4(stack_top(MATRIX_STACKS + MATRIX_IDX)); - OnMatrixChanged(); + _glMultMatrix(&ortho); } @@ -260,10 +248,8 @@ void APIENTRY glFrustum(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat znear, GLfloat zfar) { - /* Frustum Matrix */ - Matrix4x4 FrustumMatrix __attribute__((aligned(32))); - - MEMSET(FrustumMatrix, 0, sizeof(float) * 16); + Matrix4x4 frustum __attribute__((aligned(32))); + MEMSET(frustum, 0, sizeof(float) * 16); const float near2 = 2.0f * znear; const float A = (right + left) / (right - left); @@ -271,31 +257,25 @@ void APIENTRY glFrustum(GLfloat left, GLfloat right, const float C = -((zfar + znear) / (zfar - znear)); const float D = -((2.0f * zfar * znear) / (zfar - znear)); - FrustumMatrix[M0] = near2 / (right - left); - FrustumMatrix[M5] = near2 / (top - bottom); + frustum[M0] = near2 / (right - left); + frustum[M5] = near2 / (top - bottom); - FrustumMatrix[M8] = A; - FrustumMatrix[M9] = B; - FrustumMatrix[M10] = C; - FrustumMatrix[M11] = -1.0f; - FrustumMatrix[M14] = D; + frustum[M8] = A; + frustum[M9] = B; + frustum[M10] = C; + frustum[M11] = -1.0f; + frustum[M14] = D; - UploadMatrix4x4(stack_top(MATRIX_STACKS + MATRIX_IDX)); - MultiplyMatrix4x4((const Matrix4x4*) &FrustumMatrix); - DownloadMatrix4x4(stack_top(MATRIX_STACKS + MATRIX_IDX)); - OnMatrixChanged(); + _glMultMatrix(&frustum); } /* Multiply the current matrix by an arbitrary matrix */ void glMultMatrixf(const GLfloat *m) { - Matrix4x4 TEMP __attribute__((aligned(32))); - MEMCPY4(TEMP, m, sizeof(Matrix4x4)); + Matrix4x4 tmp __attribute__((aligned(32))); + MEMCPY4(tmp, m, sizeof(Matrix4x4)); - UploadMatrix4x4(stack_top(MATRIX_STACKS + MATRIX_IDX)); - MultiplyMatrix4x4(&TEMP); - DownloadMatrix4x4(stack_top(MATRIX_STACKS + MATRIX_IDX)); - OnMatrixChanged(); + _glMultMatrix(&tmp); } /* Load an arbitrary transposed matrix */ @@ -331,32 +311,29 @@ void glLoadTransposeMatrixf(const GLfloat *m) { /* Multiply the current matrix by an arbitrary transposed matrix */ void glMultTransposeMatrixf(const GLfloat *m) { - static Matrix4x4 TEMP __attribute__((aligned(32))); + static Matrix4x4 tmp __attribute__((aligned(32))); - TEMP[M0] = m[0]; - TEMP[M1] = m[4]; - TEMP[M2] = m[8]; - TEMP[M3] = m[12]; + tmp[M0] = m[0]; + tmp[M1] = m[4]; + tmp[M2] = m[8]; + tmp[M3] = m[12]; - TEMP[M4] = m[1]; - TEMP[M5] = m[5]; - TEMP[M6] = m[9]; - TEMP[M7] = m[13]; + tmp[M4] = m[1]; + tmp[M5] = m[5]; + tmp[M6] = m[9]; + tmp[M7] = m[13]; - TEMP[M8] = m[3]; - TEMP[M9] = m[6]; - TEMP[M10] = m[10]; - TEMP[M11] = m[14]; + tmp[M8] = m[3]; + tmp[M9] = m[6]; + tmp[M10] = m[10]; + tmp[M11] = m[14]; - TEMP[M12] = m[4]; - TEMP[M13] = m[7]; - TEMP[M14] = m[11]; - TEMP[M15] = m[15]; + tmp[M12] = m[4]; + tmp[M13] = m[7]; + tmp[M14] = m[11]; + tmp[M15] = m[15]; - UploadMatrix4x4(stack_top(MATRIX_STACKS + MATRIX_IDX)); - MultiplyMatrix4x4((const Matrix4x4*) &TEMP); - DownloadMatrix4x4(stack_top(MATRIX_STACKS + MATRIX_IDX)); - OnMatrixChanged(); + _glMultMatrix(&tmp); } /* Set the GL viewport */ From 64073531214cf84680c39a85e53e1b315772875b Mon Sep 17 00:00:00 2001 From: Falco Girgis Date: Wed, 9 Oct 2024 22:20:32 -0500 Subject: [PATCH 43/72] Removed opb_count hack for older KOS versions --- GL/platforms/sh4.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/GL/platforms/sh4.c b/GL/platforms/sh4.c index a8f133a..26d7f88 100644 --- a/GL/platforms/sh4.c +++ b/GL/platforms/sh4.c @@ -9,6 +9,7 @@ #define CLIP_DEBUG 0 #define PVR_VERTEX_BUF_SIZE 2560 * 256 +#define PVR_OPB_COUNT 2 #define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0) @@ -29,18 +30,10 @@ void InitGPU(_Bool autosort, _Bool fsaa) { PVR_VERTEX_BUF_SIZE, /* Vertex buffer size */ 0, /* No DMA */ fsaa, /* No FSAA */ - (autosort) ? 0 : 1 /* Disable translucent auto-sorting to match traditional GL */ + (autosort) ? 0 : 1, /* Disable translucent auto-sorting to match traditional GL */ + PVR_OPB_COUNT /* Number of tile object pointer overflow bins. */ }; - /* 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 72136bb7f5002287235fe251a19213aac7bd7a63 Mon Sep 17 00:00:00 2001 From: GPF Date: Sun, 13 Oct 2024 12:58:09 -0700 Subject: [PATCH 44/72] quick implementation of glTexSubImage2D/_glTexSubImage2DValidate, update to nehe06 example to show usage of glTexSubImage2D, and a compile issue to primitive_modes fixed. --- GL/texture.c | 265 +++++++++++++++++++++++++++++++-- samples/nehe06/main.c | 5 +- samples/primitive_modes/main.c | 2 +- 3 files changed, 257 insertions(+), 15 deletions(-) diff --git a/GL/texture.c b/GL/texture.c index 70f4258..d4f639b 100644 --- a/GL/texture.c +++ b/GL/texture.c @@ -1480,6 +1480,100 @@ static bool _glTexImage2DValidate(GLenum target, GLint level, GLint internalForm return true; } +static bool _glTexSubImage2DValidate(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type) { + if (target != GL_TEXTURE_2D) { + INFO_MSG("Invalid target. Only GL_TEXTURE_2D is supported."); + _glKosThrowError(GL_INVALID_ENUM, __func__); + return false; + } + + if (width > 1024 || height > 1024) { + INFO_MSG("Invalid subimage size. Maximum 1024x1024."); + _glKosThrowError(GL_INVALID_VALUE, __func__); + return false; + } + + // Ensure format is valid + GLint validFormats[] = { + GL_ALPHA, + GL_LUMINANCE, + GL_INTENSITY, + GL_LUMINANCE_ALPHA, + GL_RED, + GL_RGB, + GL_RGBA, + GL_BGRA, + GL_COLOR_INDEX, + GL_COLOR_INDEX4_EXT, /* Extension, for glCompressedTexImage pass-thru */ + GL_COLOR_INDEX8_EXT, /* Extension, for glCompressedTexImage pass-thru */ + GL_COLOR_INDEX4_TWID_KOS, /* Extension, for glCompressedTexImage pass-thru */ + GL_COLOR_INDEX8_TWID_KOS, /* Extension, for glCompressedTexImage pass-thru */ + 0 + }; + + if (_glCheckValidEnum(format, validFormats, __func__) != 0) { + return false; + } + + // Validate type + if (format != GL_COLOR_INDEX4_EXT && format != GL_COLOR_INDEX4_TWID_KOS) { + /* Abuse determineStride to see if type is valid */ + if (_determineStride(GL_RGBA, type) == -1) { + INFO_MSG("Invalid pixel data type."); + _glKosThrowError(GL_INVALID_ENUM, __func__); + return false; + } + } + + // Validate offsets and dimensions + GLint maxTextureWidth = 1024; // Assuming maximum texture size + GLint maxTextureHeight = 1024; + + if (xoffset < 0 || yoffset < 0 || (xoffset + width) > maxTextureWidth || (yoffset + height) > maxTextureHeight) { + INFO_MSG("Subimage exceeds the dimensions of the texture."); + _glKosThrowError(GL_INVALID_VALUE, __func__); + return false; + } + + if (level < 0) { + INFO_MSG("Invalid mipmap level."); + _glKosThrowError(GL_INVALID_VALUE, __func__); + return false; + } + + // Check for the power-of-two requirement + if (level == 0) { + if ((width < 8 || (width & -width) != width)) { + INFO_MSG("Width must be a power of two and at least 8."); + _glKosThrowError(GL_INVALID_VALUE, __func__); + return false; + } + + if ((height < 8 || (height & -height) != height)) { + INFO_MSG("Height must be a power of two and at least 8."); + _glKosThrowError(GL_INVALID_VALUE, __func__); + return false; + } + } else { + // Mipmap level should not be 1x1 + if ((width < 2) || (height < 2)) { + INFO_MSG("Mipmap level must be at least 2x2."); + _glKosThrowError(GL_INVALID_VALUE, __func__); + return false; + } + } + + // Ensure no border (since glTexSubImage2D doesn't allow it) + GLint border = 0; // No border allowed + if (border != 0) { + INFO_MSG("Border must be zero for glTexSubImage2D."); + _glKosThrowError(GL_INVALID_VALUE, __func__); + return false; + } + + return true; +} + static inline GLboolean is4BPPFormat(GLenum format) { return format == GL_COLOR_INDEX4_EXT || format == GL_COLOR_INDEX4_TWID_KOS; } @@ -1998,19 +2092,164 @@ GLAPI void APIENTRY glGetColorTableParameterfvEXT(GLenum target, GLenum pname, G _glKosThrowError(GL_INVALID_OPERATION, __func__); } -GLAPI void APIENTRY glTexSubImage2D( - GLenum target, GLint level, GLint xoffset, GLint yoffset, - GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels) { - _GL_UNUSED(target); - _GL_UNUSED(level); - _GL_UNUSED(xoffset); - _GL_UNUSED(yoffset); - _GL_UNUSED(width); - _GL_UNUSED(height); - _GL_UNUSED(format); - _GL_UNUSED(type); - _GL_UNUSED(pixels); - gl_assert(0 && "Not Implemented"); +void APIENTRY glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, + GLsizei width, GLsizei height, GLenum format, + GLenum type, const GLvoid *data) { + TRACE(); + + if (!_glTexSubImage2DValidate(target, level, xoffset, yoffset, width, height, format, type)) { + return; + } + + gl_assert(ACTIVE_TEXTURE < MAX_GLDC_TEXTURE_UNITS); + TextureObject* active = TEXTURE_UNITS[ACTIVE_TEXTURE]; + + if (!active || !active->data) { + INFO_MSG("Called glTexSubImage2D on unbound or uninitialized texture"); + _glKosThrowError(GL_INVALID_OPERATION, __func__); + return; + } + + // Ensure the subregion fits within the existing texture + if (xoffset < 0 || yoffset < 0 || + xoffset + width > active->width || + yoffset + height > active->height) { + _glKosThrowError(GL_INVALID_VALUE, __func__); + return; + } + + GLboolean isPaletted = ( + active->internalFormat == GL_COLOR_INDEX8_EXT || + active->internalFormat == GL_COLOR_INDEX4_EXT || + active->internalFormat == GL_COLOR_INDEX4_TWID_KOS || + active->internalFormat == GL_COLOR_INDEX8_TWID_KOS + ) ? GL_TRUE : GL_FALSE; + + GLenum cleanInternalFormat = _cleanInternalFormat(active->internalFormat); + GLint destStride = _determineStrideInternal(cleanInternalFormat); + GLint sourceStride = _determineStride(format, type); + GLuint srcBytes = (width * height * sourceStride); + GLuint destBytes = (width * height * destStride); + + TextureConversionFunc conversion; + int needs_conversion = _determineConversion(cleanInternalFormat, format, type, &conversion); + + // Handle 4bpp formats + if (format == GL_COLOR_INDEX4_EXT || format == GL_COLOR_INDEX4_TWID_KOS) { + srcBytes /= 2; + } + + if ((needs_conversion & CONVERSION_TYPE_PACK) == CONVERSION_TYPE_PACK) { + destBytes /= 2; + } else if (active->internalFormat == GL_COLOR_INDEX4_EXT || active->internalFormat == GL_COLOR_INDEX4_TWID_KOS) { + destBytes /= 2; + } + + if (needs_conversion < 0) { + _glKosThrowError(GL_INVALID_VALUE, __func__); + INFO_MSG("Couldn't find necessary texture conversion\n"); + return; + } + + // Calculate the starting point for the subregion in the texture data + GLubyte* targetData = active->data + (yoffset * active->width + xoffset) * destStride; + + if (needs_conversion > 0) { + GLubyte* conversionBuffer = (GLubyte*) memalign(32, srcBytes); + const GLubyte* src = data; + GLubyte* dst = conversionBuffer; + + bool pack = (needs_conversion & CONVERSION_TYPE_PACK) == CONVERSION_TYPE_PACK; + needs_conversion &= ~CONVERSION_TYPE_PACK; + + if (needs_conversion == CONVERSION_TYPE_CONVERT) { + for (uint32_t i = 0; i < (width * height); ++i) { + conversion(src, dst); + dst += destStride; + src += sourceStride; + } + } else if (needs_conversion == 2) { + // Twiddle + if (is4BPPFormat(active->internalFormat) && is4BPPFormat(format)) { + // Special case twiddling for 4BPP formats + twid_prepare_table(width, height); + + for (uint32_t i = 0; i < (width * height); ++i) { + uint32_t newLocation = twid_location(i); + + assert(newLocation < (width * height)); + assert((newLocation / 2) < destBytes); + assert((i / 2) < srcBytes); + + src = &((uint8_t*) data)[i / 2]; + dst = &conversionBuffer[newLocation / 2]; + + uint8_t src_value = (i % 2) == 0 ? (*src >> 4) : (*src & 0xF); + + if (newLocation % 2 == 1) { + *dst = (*dst & 0xF) | (src_value << 4); + } else { + *dst = (*dst & 0xF0) | (src_value & 0xF); + } + } + } else { + twid_prepare_table(width, height); + + for (uint32_t i = 0; i < (width * height); ++i) { + uint32_t newLocation = twid_location(i); + dst = conversionBuffer + (destStride * newLocation); + + for (int j = 0; j < destStride; ++j) + *dst++ = *(src + j); + + src += sourceStride; + } + } + } else if (needs_conversion == 3) { + // Convert + twiddle + twid_prepare_table(width, height); + + for (uint32_t i = 0; i < (width * height); ++i) { + uint32_t newLocation = twid_location(i); + dst = conversionBuffer + (destStride * newLocation); + src = data + (sourceStride * i); + conversion(src, dst); + } + } else if (pack) { + FASTCPY(conversionBuffer, data, srcBytes); + } + + if (pack) { + assert(isPaletted); + size_t dst_byte = 0; + for (size_t src_byte = 0; src_byte < srcBytes; ++src_byte) { + uint8_t v = conversionBuffer[src_byte]; + + if (src_byte % 2 == 0) { + conversionBuffer[dst_byte] = (conversionBuffer[dst_byte] & 0xF) | ((v & 0xF) << 4); + } else { + conversionBuffer[dst_byte] = (conversionBuffer[dst_byte] & 0xF0) | (v & 0xF); + dst_byte++; + } + } + } + + // Copy the converted data to the texture, respecting the subimage dimensions + for (GLsizei y = 0; y < height; ++y) { + FASTCPY(targetData, conversionBuffer + y * width * destStride, width * destStride); + targetData += active->width * destStride; // Move to next row in target + } + + free(conversionBuffer); + } else { + // No conversion necessary, we can update data directly + for (GLsizei y = 0; y < height; ++y) { + FASTCPY(targetData, (GLubyte*)data + y * width * sourceStride, width * sourceStride); + targetData += active->width * destStride; // Move to next row in target + } + } + + _glGPUStateMarkDirty(); } GLAPI void APIENTRY glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) { diff --git a/samples/nehe06/main.c b/samples/nehe06/main.c index 543c3a2..d726289 100644 --- a/samples/nehe06/main.c +++ b/samples/nehe06/main.c @@ -53,8 +53,11 @@ void LoadGLTextures() { // 2d texture, level of detail 0 (normal), 3 components (red, green, blue), x size from image, y size from image, // border 0 (normal), rgb color data, unsigned byte data, and finally the data itself. - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image1->sizeX, image1->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, image1->data); + // Create an empty texture first + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image1->sizeX, image1->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + // Update the texture with the image data + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, image1->sizeX, image1->sizeY, GL_RGB, GL_UNSIGNED_BYTE, image1->data); free(image1); } diff --git a/samples/primitive_modes/main.c b/samples/primitive_modes/main.c index f1fa78e..09e9ab3 100644 --- a/samples/primitive_modes/main.c +++ b/samples/primitive_modes/main.c @@ -159,7 +159,7 @@ int main(int argc, char *argv[]) { mat[3][1] = -(T + B) / (T - B); mat[3][2] = -(F + N) / (F - N); mat[3][3] = 1; - glLoadMatrixf(mat); + glLoadMatrixf(*mat); while (!sample_should_exit()) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); From a11847e513d84097f5f6efa0d44f0c782d4f13bc Mon Sep 17 00:00:00 2001 From: GPF Date: Mon, 14 Oct 2024 13:26:17 -0700 Subject: [PATCH 45/72] update for glTexSubImage2D, now checks the active texture size and not the subimage size to draw the glTexSubImage2D pixelas into drawing with the xoffset and yoffset into the existing POT2 texture, so subimage size doesn't need to be a POT2. --- GL/texture.c | 220 ++++++++++++++++++++++++++++----------------------- 1 file changed, 120 insertions(+), 100 deletions(-) diff --git a/GL/texture.c b/GL/texture.c index d4f639b..36340c2 100644 --- a/GL/texture.c +++ b/GL/texture.c @@ -1480,7 +1480,9 @@ static bool _glTexImage2DValidate(GLenum target, GLint level, GLint internalForm return true; } -static bool _glTexSubImage2DValidate(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type) { +static bool _glTexSubImage2DValidate(GLenum target, GLint level, GLint xoffset, GLint yoffset, + GLsizei width, GLsizei height, GLenum format, GLenum type, + GLsizei textureWidth, GLsizei textureHeight) { if (target != GL_TEXTURE_2D) { INFO_MSG("Invalid target. Only GL_TEXTURE_2D is supported."); _glKosThrowError(GL_INVALID_ENUM, __func__); @@ -1517,7 +1519,7 @@ static bool _glTexSubImage2DValidate(GLenum target, GLint level, GLint xoffset, // Validate type if (format != GL_COLOR_INDEX4_EXT && format != GL_COLOR_INDEX4_TWID_KOS) { - /* Abuse determineStride to see if type is valid */ + /* Use determineStride to see if type is valid */ if (_determineStride(GL_RGBA, type) == -1) { INFO_MSG("Invalid pixel data type."); _glKosThrowError(GL_INVALID_ENUM, __func__); @@ -1525,11 +1527,10 @@ static bool _glTexSubImage2DValidate(GLenum target, GLint level, GLint xoffset, } } - // Validate offsets and dimensions - GLint maxTextureWidth = 1024; // Assuming maximum texture size - GLint maxTextureHeight = 1024; - - if (xoffset < 0 || yoffset < 0 || (xoffset + width) > maxTextureWidth || (yoffset + height) > maxTextureHeight) { + // Validate offsets and dimensions using the underlying texture size + if (xoffset < 0 || yoffset < 0 || + (xoffset + width) > textureWidth || + (yoffset + height) > textureHeight) { INFO_MSG("Subimage exceeds the dimensions of the texture."); _glKosThrowError(GL_INVALID_VALUE, __func__); return false; @@ -1541,28 +1542,6 @@ static bool _glTexSubImage2DValidate(GLenum target, GLint level, GLint xoffset, return false; } - // Check for the power-of-two requirement - if (level == 0) { - if ((width < 8 || (width & -width) != width)) { - INFO_MSG("Width must be a power of two and at least 8."); - _glKosThrowError(GL_INVALID_VALUE, __func__); - return false; - } - - if ((height < 8 || (height & -height) != height)) { - INFO_MSG("Height must be a power of two and at least 8."); - _glKosThrowError(GL_INVALID_VALUE, __func__); - return false; - } - } else { - // Mipmap level should not be 1x1 - if ((width < 2) || (height < 2)) { - INFO_MSG("Mipmap level must be at least 2x2."); - _glKosThrowError(GL_INVALID_VALUE, __func__); - return false; - } - } - // Ensure no border (since glTexSubImage2D doesn't allow it) GLint border = 0; // No border allowed if (border != 0) { @@ -2097,9 +2076,8 @@ void APIENTRY glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint y GLenum type, const GLvoid *data) { TRACE(); - if (!_glTexSubImage2DValidate(target, level, xoffset, yoffset, width, height, format, type)) { - return; - } + // printf("glTexSubImage2D called with: target=%d, level=%d, xoffset=%d, yoffset=%d, width=%d, height=%d, format=%d, type=%d\n", + // target, level, xoffset, yoffset, width, height, format, type); gl_assert(ACTIVE_TEXTURE < MAX_GLDC_TEXTURE_UNITS); TextureObject* active = TEXTURE_UNITS[ACTIVE_TEXTURE]; @@ -2110,11 +2088,31 @@ void APIENTRY glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint y return; } - // Ensure the subregion fits within the existing texture - if (xoffset < 0 || yoffset < 0 || - xoffset + width > active->width || - yoffset + height > active->height) { - _glKosThrowError(GL_INVALID_VALUE, __func__); + // Retrieve the dimensions of the currently bound texture + GLsizei textureWidth = active->width; + GLsizei textureHeight = active->height; + + // printf("Texture dimensions: width=%d, height=%d\n", textureWidth, textureHeight); + // printf("Subimage dimensions: width=%d, height=%d\n", width, height); + + // Check if the texture has been resized + GLboolean isResized = (width != textureWidth || height != textureHeight); + // if (isResized) { + // printf("Texture has been resized. Adjusting copy strategy.\n"); + // } + + // Validate the subregion fits within the existing texture dimensions + // if (xoffset < 0 || yoffset < 0 || + // xoffset + width > textureWidth || + // yoffset + height > textureHeight) { + // INFO_MSG("Error: Subregion does not fit within texture dimensions\n"); + // _glKosThrowError(GL_INVALID_VALUE, __func__); + // return; + // } + + // Pass the texture dimensions to the validation function + if (!_glTexSubImage2DValidate(target, level, xoffset, yoffset, width, height, format, type, textureWidth, textureHeight)) { + INFO_MSG("Error: _glTexSubImage2DValidate failed\n"); return; } @@ -2125,24 +2123,40 @@ void APIENTRY glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint y active->internalFormat == GL_COLOR_INDEX8_TWID_KOS ) ? GL_TRUE : GL_FALSE; + // printf("isPaletted: %s\n", isPaletted ? "true" : "false"); + GLenum cleanInternalFormat = _cleanInternalFormat(active->internalFormat); - GLint destStride = _determineStrideInternal(cleanInternalFormat); + // printf("cleanInternalFormat: %d\n", cleanInternalFormat); + + // Determine source stride GLint sourceStride = _determineStride(format, type); GLuint srcBytes = (width * height * sourceStride); - GLuint destBytes = (width * height * destStride); + + // Calculate destination stride (this accounts for both POT and NPOT) + GLint destStride = _determineStrideInternal(cleanInternalFormat); + + // printf("sourceStride: %d, destStride: %d, srcBytes: %u\n", sourceStride, destStride, srcBytes); + + // Calculate destBytes using the texture's full dimensions + GLuint destBytes = (textureWidth * textureHeight * destStride); TextureConversionFunc conversion; int needs_conversion = _determineConversion(cleanInternalFormat, format, type, &conversion); - // Handle 4bpp formats + // printf("needs_conversion: %d\n", needs_conversion); + + // Adjust source bytes for 4bpp formats if (format == GL_COLOR_INDEX4_EXT || format == GL_COLOR_INDEX4_TWID_KOS) { srcBytes /= 2; + // printf("Adjusted srcBytes for 4bpp format: %u\n", srcBytes); } if ((needs_conversion & CONVERSION_TYPE_PACK) == CONVERSION_TYPE_PACK) { destBytes /= 2; + // printf("Adjusted destBytes for CONVERSION_TYPE_PACK: %u\n", destBytes); } else if (active->internalFormat == GL_COLOR_INDEX4_EXT || active->internalFormat == GL_COLOR_INDEX4_TWID_KOS) { destBytes /= 2; + // printf("Adjusted destBytes for 4bpp internal format: %u\n", destBytes); } if (needs_conversion < 0) { @@ -2152,77 +2166,67 @@ void APIENTRY glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint y } // Calculate the starting point for the subregion in the texture data - GLubyte* targetData = active->data + (yoffset * active->width + xoffset) * destStride; - + GLubyte* targetData = active->data + (yoffset * textureWidth + xoffset) * destStride; + // printf("targetData offset: %td bytes\n", (ptrdiff_t)((uintptr_t)targetData - (uintptr_t)active->data)); + if (needs_conversion > 0) { - GLubyte* conversionBuffer = (GLubyte*) memalign(32, srcBytes); + GLubyte* conversionBuffer = (GLubyte*) memalign(32, textureWidth * textureHeight * destStride); + // printf("Allocated conversionBuffer of size %u at %p\n", textureWidth * textureHeight * destStride, (void*)conversionBuffer); + const GLubyte* src = data; GLubyte* dst = conversionBuffer; bool pack = (needs_conversion & CONVERSION_TYPE_PACK) == CONVERSION_TYPE_PACK; needs_conversion &= ~CONVERSION_TYPE_PACK; + // printf("Conversion type: %d, pack: %s\n", needs_conversion, pack ? "true" : "false"); + if (needs_conversion == CONVERSION_TYPE_CONVERT) { - for (uint32_t i = 0; i < (width * height); ++i) { - conversion(src, dst); - dst += destStride; - src += sourceStride; - } - } else if (needs_conversion == 2) { - // Twiddle - if (is4BPPFormat(active->internalFormat) && is4BPPFormat(format)) { - // Special case twiddling for 4BPP formats - twid_prepare_table(width, height); - - for (uint32_t i = 0; i < (width * height); ++i) { - uint32_t newLocation = twid_location(i); - - assert(newLocation < (width * height)); - assert((newLocation / 2) < destBytes); - assert((i / 2) < srcBytes); - - src = &((uint8_t*) data)[i / 2]; - dst = &conversionBuffer[newLocation / 2]; - - uint8_t src_value = (i % 2) == 0 ? (*src >> 4) : (*src & 0xF); - - if (newLocation % 2 == 1) { - *dst = (*dst & 0xF) | (src_value << 4); - } else { - *dst = (*dst & 0xF0) | (src_value & 0xF); - } - } - } else { - twid_prepare_table(width, height); - - for (uint32_t i = 0; i < (width * height); ++i) { - uint32_t newLocation = twid_location(i); - dst = conversionBuffer + (destStride * newLocation); - - for (int j = 0; j < destStride; ++j) - *dst++ = *(src + j); - + // printf("Performing conversion\n"); + for (uint32_t y = 0; y < height; ++y) { + for (uint32_t x = 0; x < width; ++x) { + conversion(src, dst); + dst += destStride; src += sourceStride; } + // Clear the remaining part of the row if resized + if (isResized) { + memset(dst, 0, (textureWidth - width) * destStride); + dst += (textureWidth - width) * destStride; + } } - } else if (needs_conversion == 3) { - // Convert + twiddle - twid_prepare_table(width, height); + // Clear remaining rows if resized + if (isResized) { + memset(dst, 0, (textureHeight - height) * textureWidth * destStride); + } + } else if (needs_conversion == 2 || needs_conversion == 3) { + // printf("Performing twiddling %s\n", needs_conversion == 3 ? "with conversion" : ""); + twid_prepare_table(textureWidth, textureHeight); - for (uint32_t i = 0; i < (width * height); ++i) { - uint32_t newLocation = twid_location(i); - dst = conversionBuffer + (destStride * newLocation); - src = data + (sourceStride * i); - conversion(src, dst); + for (uint32_t y = 0; y < textureHeight; ++y) { + for (uint32_t x = 0; x < textureWidth; ++x) { + uint32_t srcIndex = y * width + x; + uint32_t newLocation = twid_location(y * textureWidth + x); + dst = conversionBuffer + (destStride * newLocation); + + if (x < width && y < height) { + if (needs_conversion == 3) { + conversion(src + srcIndex * sourceStride, dst); + } else { + memcpy(dst, src + srcIndex * sourceStride, destStride); + } + } else { + memset(dst, 0, destStride); + } + } } - } else if (pack) { - FASTCPY(conversionBuffer, data, srcBytes); } if (pack) { assert(isPaletted); + // printf("Packing paletted texture\n"); size_t dst_byte = 0; - for (size_t src_byte = 0; src_byte < srcBytes; ++src_byte) { + for (size_t src_byte = 0; src_byte < destBytes; ++src_byte) { uint8_t v = conversionBuffer[src_byte]; if (src_byte % 2 == 0) { @@ -2234,22 +2238,38 @@ void APIENTRY glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint y } } - // Copy the converted data to the texture, respecting the subimage dimensions - for (GLsizei y = 0; y < height; ++y) { - FASTCPY(targetData, conversionBuffer + y * width * destStride, width * destStride); - targetData += active->width * destStride; // Move to next row in target - } + // Copy the converted data to the texture + // printf("Copying converted data to texture\n"); + FASTCPY(targetData, conversionBuffer, destBytes); free(conversionBuffer); + // printf("Freed conversionBuffer\n"); } else { // No conversion necessary, we can update data directly + // printf("No conversion needed, copying data directly\n"); for (GLsizei y = 0; y < height; ++y) { - FASTCPY(targetData, (GLubyte*)data + y * width * sourceStride, width * sourceStride); - targetData += active->width * destStride; // Move to next row in target + GLsizei srcRowWidth = width * sourceStride; + GLsizei destRowWidth = textureWidth * destStride; + FASTCPY(targetData, (GLubyte*)data + y * srcRowWidth, srcRowWidth); + + // If resized, we need to clear the remaining part of the row + if (isResized && width < textureWidth) { + memset(targetData + srcRowWidth, 0, destRowWidth - srcRowWidth); + } + + targetData += destRowWidth; // Move to next row in target + } + + // If resized, we need to clear the remaining rows + if (isResized && height < textureHeight) { + GLsizei remainingRows = textureHeight - height; + GLsizei rowSize = textureWidth * destStride; + memset(targetData, 0, remainingRows * rowSize); } } _glGPUStateMarkDirty(); + // printf("glTexSubImage2D completed\n"); } GLAPI void APIENTRY glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) { From 4adf11543be2531281533070588ee38862acdc09 Mon Sep 17 00:00:00 2001 From: GPF Date: Tue, 15 Oct 2024 11:25:56 -0700 Subject: [PATCH 46/72] fixed the case where xoffset and yoffset !=0 in glTexSubImage2D --- GL/texture.c | 111 ++++++++++++++++++++++++--------------------------- 1 file changed, 52 insertions(+), 59 deletions(-) diff --git a/GL/texture.c b/GL/texture.c index 36340c2..49be522 100644 --- a/GL/texture.c +++ b/GL/texture.c @@ -2094,23 +2094,6 @@ void APIENTRY glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint y // printf("Texture dimensions: width=%d, height=%d\n", textureWidth, textureHeight); // printf("Subimage dimensions: width=%d, height=%d\n", width, height); - - // Check if the texture has been resized - GLboolean isResized = (width != textureWidth || height != textureHeight); - // if (isResized) { - // printf("Texture has been resized. Adjusting copy strategy.\n"); - // } - - // Validate the subregion fits within the existing texture dimensions - // if (xoffset < 0 || yoffset < 0 || - // xoffset + width > textureWidth || - // yoffset + height > textureHeight) { - // INFO_MSG("Error: Subregion does not fit within texture dimensions\n"); - // _glKosThrowError(GL_INVALID_VALUE, __func__); - // return; - // } - - // Pass the texture dimensions to the validation function if (!_glTexSubImage2DValidate(target, level, xoffset, yoffset, width, height, format, type, textureWidth, textureHeight)) { INFO_MSG("Error: _glTexSubImage2DValidate failed\n"); return; @@ -2166,12 +2149,10 @@ void APIENTRY glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint y } // Calculate the starting point for the subregion in the texture data - GLubyte* targetData = active->data + (yoffset * textureWidth + xoffset) * destStride; - // printf("targetData offset: %td bytes\n", (ptrdiff_t)((uintptr_t)targetData - (uintptr_t)active->data)); - + GLubyte* targetData = active->data; if (needs_conversion > 0) { - GLubyte* conversionBuffer = (GLubyte*) memalign(32, textureWidth * textureHeight * destStride); - // printf("Allocated conversionBuffer of size %u at %p\n", textureWidth * textureHeight * destStride, (void*)conversionBuffer); + GLubyte* conversionBuffer = (GLubyte*) memalign(32, destBytes); + // printf("Allocated conversionBuffer of size %u at %p\n", textureWidth * textureHeight * destStride, (void*)conversionBuffer); const GLubyte* src = data; GLubyte* dst = conversionBuffer; @@ -2179,44 +2160,33 @@ void APIENTRY glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint y bool pack = (needs_conversion & CONVERSION_TYPE_PACK) == CONVERSION_TYPE_PACK; needs_conversion &= ~CONVERSION_TYPE_PACK; - // printf("Conversion type: %d, pack: %s\n", needs_conversion, pack ? "true" : "false"); + // Initialize the entire buffer with zeros + memset(conversionBuffer, 0, destBytes); if (needs_conversion == CONVERSION_TYPE_CONVERT) { // printf("Performing conversion\n"); for (uint32_t y = 0; y < height; ++y) { + dst = conversionBuffer + ((y + yoffset) * textureWidth + xoffset) * destStride; for (uint32_t x = 0; x < width; ++x) { conversion(src, dst); dst += destStride; src += sourceStride; } - // Clear the remaining part of the row if resized - if (isResized) { - memset(dst, 0, (textureWidth - width) * destStride); - dst += (textureWidth - width) * destStride; - } - } - // Clear remaining rows if resized - if (isResized) { - memset(dst, 0, (textureHeight - height) * textureWidth * destStride); } } else if (needs_conversion == 2 || needs_conversion == 3) { // printf("Performing twiddling %s\n", needs_conversion == 3 ? "with conversion" : ""); twid_prepare_table(textureWidth, textureHeight); - for (uint32_t y = 0; y < textureHeight; ++y) { - for (uint32_t x = 0; x < textureWidth; ++x) { - uint32_t srcIndex = y * width + x; + for (uint32_t y = yoffset; y < yoffset + height; ++y) { + for (uint32_t x = xoffset; x < xoffset + width; ++x) { + uint32_t srcIndex = (y - yoffset) * width + (x - xoffset); uint32_t newLocation = twid_location(y * textureWidth + x); dst = conversionBuffer + (destStride * newLocation); - if (x < width && y < height) { - if (needs_conversion == 3) { - conversion(src + srcIndex * sourceStride, dst); - } else { - memcpy(dst, src + srcIndex * sourceStride, destStride); - } + if (needs_conversion == 3) { + conversion(src + srcIndex * sourceStride, dst); } else { - memset(dst, 0, destStride); + memcpy(dst, src + srcIndex * sourceStride, destStride); } } } @@ -2246,25 +2216,48 @@ void APIENTRY glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint y // printf("Freed conversionBuffer\n"); } else { // No conversion necessary, we can update data directly - // printf("No conversion needed, copying data directly\n"); - for (GLsizei y = 0; y < height; ++y) { - GLsizei srcRowWidth = width * sourceStride; - GLsizei destRowWidth = textureWidth * destStride; - FASTCPY(targetData, (GLubyte*)data + y * srcRowWidth, srcRowWidth); - - // If resized, we need to clear the remaining part of the row - if (isResized && width < textureWidth) { - memset(targetData + srcRowWidth, 0, destRowWidth - srcRowWidth); + GLboolean fullUpdate = (xoffset == 0 && yoffset == 0 && width == textureWidth && height == textureHeight); + + if (fullUpdate) { + // If it's a full texture update, we can simply copy all the data at once + FASTCPY(targetData, data, srcBytes); + } else { + // For partial updates, copy row by row + for (GLsizei y = 0; y < height; ++y) { + GLsizei srcRowWidth = width * sourceStride; + GLubyte* destRow = targetData + ((y + yoffset) * textureWidth + xoffset) * destStride; + FASTCPY(destRow, (GLubyte*)data + y * srcRowWidth, srcRowWidth); } - targetData += destRowWidth; // Move to next row in target - } - - // If resized, we need to clear the remaining rows - if (isResized && height < textureHeight) { - GLsizei remainingRows = textureHeight - height; - GLsizei rowSize = textureWidth * destStride; - memset(targetData, 0, remainingRows * rowSize); + // Clear any remaining parts of the texture + if (xoffset > 0 || yoffset > 0 || width < textureWidth || height < textureHeight) { + GLubyte* clearBuffer = (GLubyte*) memalign(32, destBytes); + memset(clearBuffer, 0, destBytes); + + // Clear left and right sides + for (GLsizei y = 0; y < textureHeight; ++y) { + if (xoffset > 0) { + FASTCPY(targetData + y * textureWidth * destStride, clearBuffer, xoffset * destStride); + } + if (xoffset + width < textureWidth) { + FASTCPY(targetData + (y * textureWidth + xoffset + width) * destStride, + clearBuffer, + (textureWidth - (xoffset + width)) * destStride); + } + } + + // Clear top and bottom + if (yoffset > 0) { + FASTCPY(targetData, clearBuffer, yoffset * textureWidth * destStride); + } + if (yoffset + height < textureHeight) { + FASTCPY(targetData + ((yoffset + height) * textureWidth) * destStride, + clearBuffer, + (textureHeight - (yoffset + height)) * textureWidth * destStride); + } + + free(clearBuffer); + } } } From b44dddbaff78bc4680670826c1633b123158fa2b Mon Sep 17 00:00:00 2001 From: GPF Date: Tue, 15 Oct 2024 12:04:17 -0700 Subject: [PATCH 47/72] removed some unneeded code --- GL/texture.c | 47 ++++------------------------------------------- 1 file changed, 4 insertions(+), 43 deletions(-) diff --git a/GL/texture.c b/GL/texture.c index 49be522..f84ac4d 100644 --- a/GL/texture.c +++ b/GL/texture.c @@ -2213,51 +2213,12 @@ void APIENTRY glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint y FASTCPY(targetData, conversionBuffer, destBytes); free(conversionBuffer); - // printf("Freed conversionBuffer\n"); } else { // No conversion necessary, we can update data directly - GLboolean fullUpdate = (xoffset == 0 && yoffset == 0 && width == textureWidth && height == textureHeight); - - if (fullUpdate) { - // If it's a full texture update, we can simply copy all the data at once - FASTCPY(targetData, data, srcBytes); - } else { - // For partial updates, copy row by row - for (GLsizei y = 0; y < height; ++y) { - GLsizei srcRowWidth = width * sourceStride; - GLubyte* destRow = targetData + ((y + yoffset) * textureWidth + xoffset) * destStride; - FASTCPY(destRow, (GLubyte*)data + y * srcRowWidth, srcRowWidth); - } - - // Clear any remaining parts of the texture - if (xoffset > 0 || yoffset > 0 || width < textureWidth || height < textureHeight) { - GLubyte* clearBuffer = (GLubyte*) memalign(32, destBytes); - memset(clearBuffer, 0, destBytes); - - // Clear left and right sides - for (GLsizei y = 0; y < textureHeight; ++y) { - if (xoffset > 0) { - FASTCPY(targetData + y * textureWidth * destStride, clearBuffer, xoffset * destStride); - } - if (xoffset + width < textureWidth) { - FASTCPY(targetData + (y * textureWidth + xoffset + width) * destStride, - clearBuffer, - (textureWidth - (xoffset + width)) * destStride); - } - } - - // Clear top and bottom - if (yoffset > 0) { - FASTCPY(targetData, clearBuffer, yoffset * textureWidth * destStride); - } - if (yoffset + height < textureHeight) { - FASTCPY(targetData + ((yoffset + height) * textureWidth) * destStride, - clearBuffer, - (textureHeight - (yoffset + height)) * textureWidth * destStride); - } - - free(clearBuffer); - } + for (GLsizei y = 0; y < height; ++y) { + GLsizei srcRowWidth = width * sourceStride; + GLubyte* destRow = targetData + ((y + yoffset) * textureWidth + xoffset) * destStride; + FASTCPY(destRow, (GLubyte*)data + y * srcRowWidth, srcRowWidth); } } From 553f6016f33c2bd20058d226936b47568b282442 Mon Sep 17 00:00:00 2001 From: GPF Date: Tue, 15 Oct 2024 12:11:17 -0700 Subject: [PATCH 48/72] Only initialize the texture buffer with zeros if it's a partial update --- GL/texture.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/GL/texture.c b/GL/texture.c index f84ac4d..e7bd61d 100644 --- a/GL/texture.c +++ b/GL/texture.c @@ -2160,9 +2160,11 @@ void APIENTRY glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint y bool pack = (needs_conversion & CONVERSION_TYPE_PACK) == CONVERSION_TYPE_PACK; needs_conversion &= ~CONVERSION_TYPE_PACK; - // Initialize the entire buffer with zeros - memset(conversionBuffer, 0, destBytes); - + // Only initialize the buffer with zeros if it's a partial update + if (xoffset != 0 || yoffset != 0 || width != textureWidth || height != textureHeight) { + memset(conversionBuffer, 0, destBytes); + } + // printf("Conversion type: %d, pack: %s\n", needs_conversion, pack ? "true" : "false"); if (needs_conversion == CONVERSION_TYPE_CONVERT) { // printf("Performing conversion\n"); for (uint32_t y = 0; y < height; ++y) { From c4786a62e6906022db264312ff5569efde0e564f Mon Sep 17 00:00:00 2001 From: Luke Benstead Date: Sat, 7 Dec 2024 19:35:40 +0000 Subject: [PATCH 49/72] Fix bug in allocations (thanks @skmp) --- GL/alloc/alloc.c | 17 +++++++++++++---- samples/nehe08/main.c | 4 ++-- samples/nehe20/main.c | 5 +++-- samples/primitive_modes/main.c | 1 + 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/GL/alloc/alloc.c b/GL/alloc/alloc.c index 0058baf..3dfce8e 100644 --- a/GL/alloc/alloc.c +++ b/GL/alloc/alloc.c @@ -296,7 +296,7 @@ static inline void block_and_offset_from_subblock(size_t sb, size_t* b, uint8_t* *off = (sb % 8); } -void* alloc_malloc(void* pool, size_t size) { +static void* alloc_malloc_internal(void* pool, size_t size, bool for_defrag) { DBG_MSG("Allocating: %d\n", size); size_t start_subblock, required_subblocks; @@ -339,6 +339,11 @@ void* alloc_malloc(void* pool, size_t size) { pool_header.block_usage[block++] |= mask; } + // defrag allocations don't create new entries, they reuse old ones + if(for_defrag) { + return ret; + } + /* Insert allocations in the list by size descending so that when we * defrag we can move the larger blocks before the smaller ones without * much effort */ @@ -380,6 +385,10 @@ void* alloc_malloc(void* pool, size_t size) { return ret; } +void* alloc_malloc(void* pool, size_t size) { + return alloc_malloc_internal(pool, size, false); +} + static void alloc_release_blocks(struct AllocEntry* it) { size_t used_subblocks = size_to_subblock_count(it->size); size_t subblock = subblock_from_pointer(it->pointer); @@ -437,14 +446,14 @@ void alloc_free(void* pool, void* p) { DBG_MSG("Freed: size: %d, us: %d, sb: %d, off: %d\n", it->size, used_subblocks, block, offset); free(it); - break; + return; } last = it; it = it->next; } - DBG_MSG("Free done\n"); + assert("Freed pointer not found, heap corruption?" && 0); } void alloc_run_defrag(void* pool, defrag_address_move callback, int max_iterations, void* user_data) { @@ -461,7 +470,7 @@ void alloc_run_defrag(void* pool, defrag_address_move callback, int max_iteratio while(it) { void* potential_dest = alloc_next_available(pool, it->size); if(potential_dest && potential_dest < it->pointer) { - potential_dest = alloc_malloc(pool, it->size); + potential_dest = alloc_malloc_internal(pool, it->size, true); memcpy(potential_dest, it->pointer, it->size); /* Mark this block as now free, but don't fiddle with the diff --git a/samples/nehe08/main.c b/samples/nehe08/main.c index 8d6814d..4048b59 100644 --- a/samples/nehe08/main.c +++ b/samples/nehe08/main.c @@ -11,10 +11,10 @@ #ifdef __DREAMCAST__ #include #endif - #include -#include #include +#include +#include /* Simple OpenGL example to demonstrate blending and lighting. diff --git a/samples/nehe20/main.c b/samples/nehe20/main.c index 54c7825..bce9182 100644 --- a/samples/nehe20/main.c +++ b/samples/nehe20/main.c @@ -63,8 +63,9 @@ KOS_INIT_ROMDISK(romdisk); #include // Header File For The GLu32 Library #include #else -#include // Header File For The OpenGL32 Library -#include // Header File For The GLu32 Library +#include // Header File For The OpenGL32 Library +#include +#include // Header File For The GLu32 Library #endif #define BOOL int diff --git a/samples/primitive_modes/main.c b/samples/primitive_modes/main.c index 09e9ab3..5f7acab 100644 --- a/samples/primitive_modes/main.c +++ b/samples/primitive_modes/main.c @@ -1,4 +1,5 @@ #include +#include #include #include From 55a912b6210d765744967e774f2d3aef28afc512 Mon Sep 17 00:00:00 2001 From: Luke Benstead Date: Sat, 7 Dec 2024 19:54:16 +0000 Subject: [PATCH 50/72] Fix continuous free count --- GL/alloc/alloc.c | 26 ++++++++++++-------------- tests/test_allocator.h | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 14 deletions(-) diff --git a/GL/alloc/alloc.c b/GL/alloc/alloc.c index 3dfce8e..15207c1 100644 --- a/GL/alloc/alloc.c +++ b/GL/alloc/alloc.c @@ -516,29 +516,27 @@ size_t alloc_count_continuous(void* pool) { (void) pool; size_t largest_block = 0; - size_t current_block = 0; + size_t free_bits = 0; for(size_t i = 0; i < pool_header.block_count; ++i) { uint8_t t = pool_header.block_usage[i]; - if(!t) { - current_block += 2048; - } else { - for(int i = 7; i >= 0; --i) { - bool bitset = (t & (1 << i)); - if(bitset) { - current_block += (7 - i) * 256; - if(largest_block < current_block) { - largest_block = current_block; - current_block = 0; - } + for(int i = 7; i >= 0; --i) { + bool bitset = (t & (1 << i)); + if(!bitset) { + ++free_bits; + } else { + free_bits = 0; + size_t free_size = free_bits * 256; + if(free_size > largest_block) { + largest_block = free_size; } } } } - if(largest_block < current_block) { - largest_block = current_block; + if(free_bits && (free_bits * 256) > largest_block) { + largest_block = (free_bits * 256); } return largest_block; diff --git a/tests/test_allocator.h b/tests/test_allocator.h index 5967983..8aa146f 100644 --- a/tests/test_allocator.h +++ b/tests/test_allocator.h @@ -39,6 +39,42 @@ public: self->defrag_moves.push_back(std::make_pair(src, dst)); } + void test_count_free() { + alloc_init(pool, POOL_SIZE); + + assert_equal(alloc_count_free(pool), POOL_SIZE); + + void* a1 = alloc_malloc(pool, 2048); + assert_equal(alloc_count_free(pool), POOL_SIZE - 2048); + + void* a2 = alloc_malloc(pool, 2048); + assert_equal(alloc_count_free(pool), POOL_SIZE - 4096); + + alloc_free(pool, a1); + assert_equal(alloc_count_free(pool), POOL_SIZE - 2048); + + alloc_free(pool, a2); + assert_equal(alloc_count_free(pool), POOL_SIZE); + } + + void test_count_contiguous() { + alloc_init(pool, POOL_SIZE); + + assert_equal(alloc_count_continuous(pool), POOL_SIZE); + + void* a1 = alloc_malloc(pool, 2048); + assert_equal(alloc_count_continuous(pool), POOL_SIZE - 2048); + + void* a2 = alloc_malloc(pool, 2048); + assert_equal(alloc_count_continuous(pool), POOL_SIZE - 4096); + + alloc_free(pool, a1); + assert_equal(alloc_count_continuous(pool), POOL_SIZE - 4096); + + alloc_free(pool, a2); + assert_equal(alloc_count_continuous(pool), POOL_SIZE); + } + void test_defrag() { alloc_init(pool, POOL_SIZE); From f7830df48049449ceedf5b781112882e0cd58a55 Mon Sep 17 00:00:00 2001 From: GPF Date: Sat, 7 Dec 2024 16:24:05 -0700 Subject: [PATCH 51/72] removed the commented out debug printing --- GL/texture.c | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/GL/texture.c b/GL/texture.c index e7bd61d..6bcfae1 100644 --- a/GL/texture.c +++ b/GL/texture.c @@ -2076,9 +2076,6 @@ void APIENTRY glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint y GLenum type, const GLvoid *data) { TRACE(); - // printf("glTexSubImage2D called with: target=%d, level=%d, xoffset=%d, yoffset=%d, width=%d, height=%d, format=%d, type=%d\n", - // target, level, xoffset, yoffset, width, height, format, type); - gl_assert(ACTIVE_TEXTURE < MAX_GLDC_TEXTURE_UNITS); TextureObject* active = TEXTURE_UNITS[ACTIVE_TEXTURE]; @@ -2092,8 +2089,6 @@ void APIENTRY glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint y GLsizei textureWidth = active->width; GLsizei textureHeight = active->height; - // printf("Texture dimensions: width=%d, height=%d\n", textureWidth, textureHeight); - // printf("Subimage dimensions: width=%d, height=%d\n", width, height); if (!_glTexSubImage2DValidate(target, level, xoffset, yoffset, width, height, format, type, textureWidth, textureHeight)) { INFO_MSG("Error: _glTexSubImage2DValidate failed\n"); return; @@ -2106,10 +2101,7 @@ void APIENTRY glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint y active->internalFormat == GL_COLOR_INDEX8_TWID_KOS ) ? GL_TRUE : GL_FALSE; - // printf("isPaletted: %s\n", isPaletted ? "true" : "false"); - GLenum cleanInternalFormat = _cleanInternalFormat(active->internalFormat); - // printf("cleanInternalFormat: %d\n", cleanInternalFormat); // Determine source stride GLint sourceStride = _determineStride(format, type); @@ -2118,28 +2110,21 @@ void APIENTRY glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint y // Calculate destination stride (this accounts for both POT and NPOT) GLint destStride = _determineStrideInternal(cleanInternalFormat); - // printf("sourceStride: %d, destStride: %d, srcBytes: %u\n", sourceStride, destStride, srcBytes); - // Calculate destBytes using the texture's full dimensions GLuint destBytes = (textureWidth * textureHeight * destStride); TextureConversionFunc conversion; int needs_conversion = _determineConversion(cleanInternalFormat, format, type, &conversion); - // printf("needs_conversion: %d\n", needs_conversion); - // Adjust source bytes for 4bpp formats if (format == GL_COLOR_INDEX4_EXT || format == GL_COLOR_INDEX4_TWID_KOS) { srcBytes /= 2; - // printf("Adjusted srcBytes for 4bpp format: %u\n", srcBytes); } if ((needs_conversion & CONVERSION_TYPE_PACK) == CONVERSION_TYPE_PACK) { destBytes /= 2; - // printf("Adjusted destBytes for CONVERSION_TYPE_PACK: %u\n", destBytes); } else if (active->internalFormat == GL_COLOR_INDEX4_EXT || active->internalFormat == GL_COLOR_INDEX4_TWID_KOS) { destBytes /= 2; - // printf("Adjusted destBytes for 4bpp internal format: %u\n", destBytes); } if (needs_conversion < 0) { @@ -2152,7 +2137,6 @@ void APIENTRY glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint y GLubyte* targetData = active->data; if (needs_conversion > 0) { GLubyte* conversionBuffer = (GLubyte*) memalign(32, destBytes); - // printf("Allocated conversionBuffer of size %u at %p\n", textureWidth * textureHeight * destStride, (void*)conversionBuffer); const GLubyte* src = data; GLubyte* dst = conversionBuffer; @@ -2164,9 +2148,7 @@ void APIENTRY glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint y if (xoffset != 0 || yoffset != 0 || width != textureWidth || height != textureHeight) { memset(conversionBuffer, 0, destBytes); } - // printf("Conversion type: %d, pack: %s\n", needs_conversion, pack ? "true" : "false"); if (needs_conversion == CONVERSION_TYPE_CONVERT) { - // printf("Performing conversion\n"); for (uint32_t y = 0; y < height; ++y) { dst = conversionBuffer + ((y + yoffset) * textureWidth + xoffset) * destStride; for (uint32_t x = 0; x < width; ++x) { @@ -2176,7 +2158,6 @@ void APIENTRY glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint y } } } else if (needs_conversion == 2 || needs_conversion == 3) { - // printf("Performing twiddling %s\n", needs_conversion == 3 ? "with conversion" : ""); twid_prepare_table(textureWidth, textureHeight); for (uint32_t y = yoffset; y < yoffset + height; ++y) { @@ -2196,7 +2177,6 @@ void APIENTRY glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint y if (pack) { assert(isPaletted); - // printf("Packing paletted texture\n"); size_t dst_byte = 0; for (size_t src_byte = 0; src_byte < destBytes; ++src_byte) { uint8_t v = conversionBuffer[src_byte]; @@ -2211,7 +2191,6 @@ void APIENTRY glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint y } // Copy the converted data to the texture - // printf("Copying converted data to texture\n"); FASTCPY(targetData, conversionBuffer, destBytes); free(conversionBuffer); @@ -2225,7 +2204,6 @@ void APIENTRY glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint y } _glGPUStateMarkDirty(); - // printf("glTexSubImage2D completed\n"); } GLAPI void APIENTRY glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) { From a13d8a180b6c0fe610820936de2d045aa0633fa0 Mon Sep 17 00:00:00 2001 From: Falco Girgis Date: Thu, 23 Jan 2025 21:24:06 -0600 Subject: [PATCH 52/72] Removed kos/string.h dependency. --- containers/aligned_vector.h | 1 - 1 file changed, 1 deletion(-) diff --git a/containers/aligned_vector.h b/containers/aligned_vector.h index e58cf93..5d50956 100644 --- a/containers/aligned_vector.h +++ b/containers/aligned_vector.h @@ -31,7 +31,6 @@ static inline void* memalign(size_t alignment, size_t size) { #ifdef __DREAMCAST__ -#include AV_FORCE_INLINE void *AV_MEMCPY4(void *dest, const void *src, size_t len) { From 9653bf8c1237e313bc754dd53e3179de237a5cd1 Mon Sep 17 00:00:00 2001 From: Falco Girgis Date: Thu, 23 Jan 2025 21:27:34 -0600 Subject: [PATCH 53/72] Got rid of a memset4() call from KOS. --- GL/platforms/sh4.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GL/platforms/sh4.h b/GL/platforms/sh4.h index 46c3513..5cbcc08 100644 --- a/GL/platforms/sh4.h +++ b/GL/platforms/sh4.h @@ -69,7 +69,7 @@ GL_FORCE_INLINE void* memcpy_fast(void *dest, const void *src, size_t len) { #define MEMCPY4(dst, src, bytes) memcpy_fast(dst, src, bytes) -#define MEMSET4(dst, v, size) memset4((dst), (v), (size)) +#define MEMSET4(dst, v, size) memset((dst), (v), (size)) #define VEC3_NORMALIZE(x, y, z) vec3f_normalize((x), (y), (z)) #define VEC3_LENGTH(x, y, z, l) vec3f_length((x), (y), (z), (l)) From dc0c8148cbb17d796a2c714ca8e746a1dc5621e3 Mon Sep 17 00:00:00 2001 From: Falco Girgis Date: Mon, 27 Jan 2025 00:53:23 -0600 Subject: [PATCH 54/72] API FP ABI conformity fixes. --- GL/glu.c | 4 ++-- GL/matrix.c | 20 ++++++++++---------- GL/state.c | 8 ++++---- include/GL/gl.h | 22 +++++++++++----------- include/GL/glu.h | 6 +++--- 5 files changed, 30 insertions(+), 30 deletions(-) diff --git a/GL/glu.c b/GL/glu.c index 717b273..2ed4444 100644 --- a/GL/glu.c +++ b/GL/glu.c @@ -2,8 +2,8 @@ #include "private.h" /* Set the Perspective */ -void APIENTRY gluPerspective(GLfloat angle, GLfloat aspect, - GLfloat znear, GLfloat zfar) { +void APIENTRY gluPerspective(GLdouble angle, GLdouble aspect, + GLdouble znear, GLdouble zfar) { GLfloat fW, fH; fH = tanf(angle * (M_PI / 360.0f)) * znear; diff --git a/GL/matrix.c b/GL/matrix.c index 4d7ac5d..1aa713a 100644 --- a/GL/matrix.c +++ b/GL/matrix.c @@ -221,9 +221,9 @@ void APIENTRY glLoadMatrixf(const GLfloat *m) { } /* Ortho */ -void APIENTRY glOrtho(GLfloat left, GLfloat right, - GLfloat bottom, GLfloat top, - GLfloat znear, GLfloat zfar) { +void APIENTRY glOrtho(GLdouble left, GLdouble right, + GLdouble bottom, GLdouble top, + GLdouble znear, GLdouble zfar) { Matrix4x4 ortho __attribute__((aligned(32))) = { 1.0f, 0.0f, 0.0f, 0.0f, @@ -244,9 +244,9 @@ void APIENTRY glOrtho(GLfloat left, GLfloat right, /* Set the GL frustum */ -void APIENTRY glFrustum(GLfloat left, GLfloat right, - GLfloat bottom, GLfloat top, - GLfloat znear, GLfloat zfar) { +void APIENTRY glFrustum(GLdouble left, GLdouble right, + GLdouble bottom, GLdouble top, + GLdouble znear, GLdouble zfar) { Matrix4x4 frustum __attribute__((aligned(32))); MEMSET(frustum, 0, sizeof(float) * 16); @@ -360,7 +360,7 @@ void APIENTRY glDepthRangef(GLclampf n, GLclampf f) { DEPTH_RANGE_MULTIPLIER_H = (n + f) / 2.0f; } -void APIENTRY glDepthRange(GLclampf n, GLclampf f){ +void APIENTRY glDepthRange(GLdouble n, GLdouble f){ glDepthRangef(n,f); } @@ -384,9 +384,9 @@ GL_FORCE_INLINE void vec3f_normalize_sh4(float *v){ } } -void gluLookAt(GLfloat eyex, GLfloat eyey, GLfloat eyez, GLfloat centerx, - GLfloat centery, GLfloat centerz, GLfloat upx, GLfloat upy, - GLfloat upz) { +void gluLookAt(GLdouble eyex, GLdouble eyey, GLdouble eyez, GLdouble centerx, + GLdouble centery, GLdouble centerz, GLdouble upx, GLdouble upy, + GLdouble upz) { GLfloat m [16] __attribute__((aligned(32))); GLfloat f [3]; GLfloat u [3]; diff --git a/GL/state.c b/GL/state.c index fd28b2a..04003f4 100644 --- a/GL/state.c +++ b/GL/state.c @@ -679,14 +679,14 @@ GLAPI void APIENTRY glClearColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a) { /* Depth Testing */ GLAPI void APIENTRY glClearDepthf(GLfloat depth) { - glClearDepth(depth); -} - -GLAPI void APIENTRY glClearDepth(GLfloat depth) { /* We reverse because using invW means that farther Z == lower number */ GPUSetClearDepth(MIN(1.0f - depth, PVR_MIN_Z)); } +GLAPI void APIENTRY glClearDepth(GLdouble depth) { + glClearDepthf(depth); +} + GLAPI void APIENTRY glDrawBuffer(GLenum mode) { _GL_UNUSED(mode); diff --git a/include/GL/gl.h b/include/GL/gl.h index d3914de..c26f456 100644 --- a/include/GL/gl.h +++ b/include/GL/gl.h @@ -446,7 +446,7 @@ __BEGIN_DECLS #define GLshort short #define GLint int #define GLfloat float -#define GLdouble float +#define GLdouble double #define GLvoid void #define GLushort unsigned short #define GLuint unsigned int @@ -454,7 +454,7 @@ __BEGIN_DECLS #define GLsizei unsigned int #define GLfixed const unsigned int #define GLclampf float -#define GLclampd float +#define GLclampd double #define GLubyte unsigned char #define GLbitfield unsigned int #define GLboolean unsigned char @@ -579,12 +579,12 @@ GLAPI void APIENTRY glReadBuffer(GLenum mode); GLAPI void APIENTRY glDrawBuffer(GLenum mode); /* Depth Testing */ -GLAPI void APIENTRY glClearDepth(GLfloat depth); +GLAPI void APIENTRY glClearDepth(GLdouble depth); GLAPI void APIENTRY glClearDepthf(GLfloat depth); GLAPI void APIENTRY glDepthMask(GLboolean flag); GLAPI void APIENTRY glDepthFunc(GLenum func); -GLAPI void APIENTRY glDepthRange(GLclampf n, GLclampf f); -GLAPI void APIENTRY glDepthRangef(GLclampf n, GLclampf f); +GLAPI void APIENTRY glDepthRange(GLdouble n, GLdouble f); +GLAPI void APIENTRY glDepthRangef(GLfloat n, GLfloat f); /* Hints */ /* Currently Supported Capabilities: @@ -696,9 +696,9 @@ GLAPI void APIENTRY glScalef(GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z); #define glRotated glRotatef -GLAPI void APIENTRY glOrtho(GLfloat left, GLfloat right, - GLfloat bottom, GLfloat top, - GLfloat znear, GLfloat zfar); +GLAPI void APIENTRY glOrtho(GLdouble left, GLdouble right, + GLdouble bottom, GLdouble top, + GLdouble znear, GLdouble zfar); GLAPI void APIENTRY glViewport(GLint x, GLint y, GLsizei width, GLsizei height); @@ -706,9 +706,9 @@ GLAPI void APIENTRY glScissor(GLint x, GLint y, GLsizei width, GLsizei height); GLAPI void APIENTRY glKosGetMatrix(GLenum mode, GLfloat *params); -GLAPI void APIENTRY glFrustum(GLfloat left, GLfloat right, - GLfloat bottom, GLfloat top, - GLfloat znear, GLfloat zfar); +GLAPI void APIENTRY glFrustum(GLdouble left, GLdouble right, + GLdouble bottom, GLdouble top, + GLdouble znear, GLdouble zfar); /* Fog Functions - client must enable GL_FOG for this to take effect */ GLAPI void APIENTRY glFogi(GLenum pname, GLint param); diff --git a/include/GL/glu.h b/include/GL/glu.h index 87842ae..7a7c4b5 100644 --- a/include/GL/glu.h +++ b/include/GL/glu.h @@ -30,9 +30,9 @@ GLAPI void APIENTRY gluPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar); /* gluLookAt - Set Camera Position for Rendering. */ -GLAPI void APIENTRY gluLookAt(GLfloat eyex, GLfloat eyey, GLfloat eyez, - GLfloat centerx, GLfloat centery, GLfloat centerz, - GLfloat upx, GLfloat upy, GLfloat upz); +GLAPI void APIENTRY gluLookAt(GLdouble eyex, GLdouble eyey, GLdouble eyez, + GLdouble centerx, GLdouble centery, GLdouble centerz, + GLdouble upx, GLdouble upy, GLdouble upz); /* generate mipmaps for any image provided by the user and then pass them to OpenGL */ GLAPI GLint APIENTRY gluBuild2DMipmaps(GLenum target, GLint internalFormat, From 71d0094ac42ea6ab57934424f0d856b49e3eb387 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sat, 1 Feb 2025 13:06:37 +1100 Subject: [PATCH 55/72] Prefer relying on built in codegen rather than relying on sh4_math.h --- GL/alloc/alloc.c | 2 +- GL/draw.c | 4 +- GL/lighting.c | 8 +- GL/matrix.c | 9 +- GL/platforms/sh4.h | 36 +- GL/platforms/sh4_math.h | 2139 --------------------------------------- GL/platforms/software.h | 3 - 7 files changed, 46 insertions(+), 2155 deletions(-) delete mode 100644 GL/platforms/sh4_math.h diff --git a/GL/alloc/alloc.c b/GL/alloc/alloc.c index 15207c1..fe9aed1 100644 --- a/GL/alloc/alloc.c +++ b/GL/alloc/alloc.c @@ -538,6 +538,6 @@ size_t alloc_count_continuous(void* pool) { if(free_bits && (free_bits * 256) > largest_block) { largest_block = (free_bits * 256); } - +printf("LARGEST: %d\n", largest_block); return largest_block; } diff --git a/GL/draw.c b/GL/draw.c index b822c7f..9d5d817 100644 --- a/GL/draw.c +++ b/GL/draw.c @@ -757,9 +757,7 @@ static void _readNormalData(ReadNormalFunc func, const GLuint first, const GLuin if(_glIsNormalizeEnabled()) { GLfloat* n = (GLfloat*) it->nxyz; - float temp = n[0] * n[0]; - temp = MATH_fmac(n[1], n[1], temp); - temp = MATH_fmac(n[2], n[2], temp); + float temp = n[0] * n[0] + n[1] * n[1] + n[2] * n[2]; float ilength = MATH_fsrra(temp); n[0] *= ilength; diff --git a/GL/lighting.c b/GL/lighting.c index b675a92..fc61a1c 100644 --- a/GL/lighting.c +++ b/GL/lighting.c @@ -58,10 +58,10 @@ void _glPrecalcLightingValues(GLuint mask) { if((mask & AMBIENT_MASK) || (mask & EMISSION_MASK) || (mask & SCENE_AMBIENT_MASK)) { GLfloat* scene_ambient = _glLightModelSceneAmbient(); - material->baseColour[0] = MATH_fmac(scene_ambient[0], material->ambient[0], material->emissive[0]); - material->baseColour[1] = MATH_fmac(scene_ambient[1], material->ambient[1], material->emissive[1]); - material->baseColour[2] = MATH_fmac(scene_ambient[2], material->ambient[2], material->emissive[2]); - material->baseColour[3] = MATH_fmac(scene_ambient[3], material->ambient[3], material->emissive[3]); + material->baseColour[0] = scene_ambient[0] * material->ambient[0] + material->emissive[0]; + material->baseColour[1] = scene_ambient[1] * material->ambient[1] + material->emissive[1]; + material->baseColour[2] = scene_ambient[2] * material->ambient[2] + material->emissive[2]; + material->baseColour[3] = scene_ambient[3] * material->ambient[3] + material->emissive[3]; } } diff --git a/GL/matrix.c b/GL/matrix.c index 1aa713a..683d83f 100644 --- a/GL/matrix.c +++ b/GL/matrix.c @@ -372,11 +372,12 @@ static inline void vec3f_cross(const GLfloat* v1, const GLfloat* v2, GLfloat* re } GL_FORCE_INLINE void vec3f_normalize_sh4(float *v){ - float length, ilength; + float lengthSq, ilength; - ilength = MATH_fsrra(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]); - length = MATH_Fast_Invert(ilength); - if (length) + lengthSq = v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; + ilength = MATH_fsrra(lengthSq); + + if (lengthSq) { v[0] *= ilength; v[1] *= ilength; diff --git a/GL/platforms/sh4.h b/GL/platforms/sh4.h index 5cbcc08..336cd9e 100644 --- a/GL/platforms/sh4.h +++ b/GL/platforms/sh4.h @@ -10,7 +10,41 @@ #include "../types.h" #include "../private.h" -#include "sh4_math.h" +// ---- sh4_math.h - SH7091 Math Module ---- +// +// This file is part of the DreamHAL project, a hardware abstraction library +// primarily intended for use on the SH7091 found in hardware such as the SEGA +// Dreamcast game console. +// +// This math module is hereby released into the public domain in the hope that it +// may prove useful. Now go hit 60 fps! :) +// +// --Moopthehedgehog + +// 1/sqrt(x) +GL_FORCE_INLINE float MATH_fsrra(float x) +{ + asm volatile ("fsrra %[one_div_sqrt]\n" + : [one_div_sqrt] "+f" (x) // outputs, "+" means r/w + : // no inputs + : // no clobbers + ); + + return x; +} + +// 1/x = 1 / sqrt(x^2) +GL_FORCE_INLINE float MATH_Fast_Invert(float x) +{ + int neg = x < 0.0f; + + x = MATH_fsrra(x * x); + + if (neg) x = -x; + return x; +} +// end of ---- sh4_math.h ---- + #ifndef NDEBUG #define PERF_WARNING(msg) printf("[PERF] %s\n", msg) diff --git a/GL/platforms/sh4_math.h b/GL/platforms/sh4_math.h deleted file mode 100644 index 4dbf727..0000000 --- a/GL/platforms/sh4_math.h +++ /dev/null @@ -1,2139 +0,0 @@ -// ---- sh4_math.h - SH7091 Math Module ---- -// -// Version 1.1.3 -// -// This file is part of the DreamHAL project, a hardware abstraction library -// primarily intended for use on the SH7091 found in hardware such as the SEGA -// Dreamcast game console. -// -// This math module is hereby released into the public domain in the hope that it -// may prove useful. Now go hit 60 fps! :) -// -// --Moopthehedgehog -// - -// Notes: -// - GCC 4 users have a different return type for the fsca functions due to an -// internal compiler error regarding complex numbers; no issue under GCC 9.2.0 -// - Using -m4 instead of -m4-single-only completely breaks the matrix and -// vector operations -// - Function inlining must be enabled and not blocked by compiler options such -// as -ffunction-sections, as blocking inlining will result in significant -// performance degradation for the vector and matrix functions employing a -// RETURN_VECTOR_STRUCT return type. I have added compiler hints and attributes -// "static inline __attribute__((always_inline))" to mitigate this, so in most -// cases the functions should be inlined regardless. If in doubt, check the -// compiler asm output! -// - -#ifndef __SH4_MATH_H_ -#define __SH4_MATH_H_ - -#define GNUC_FSCA_ERROR_VERSION 4 - -// -// Fast SH4 hardware math functions -// -// -// High-accuracy users beware, the fsrra functions have an error of +/- 2^-21 -// per http://www.shared-ptr.com/sh_insns.html -// - -//============================================================================== -// Definitions -//============================================================================== -// -// Structures, useful definitions, and reference comments -// - -// Front matrix format: -// -// FV0 FV4 FV8 FV12 -// --- --- --- ---- -// [ fr0 fr4 fr8 fr12 ] -// [ fr1 fr5 fr9 fr13 ] -// [ fr2 fr6 fr10 fr14 ] -// [ fr3 fr7 fr11 fr15 ] -// -// Back matrix, XMTRX, is similar, although it has no FVn vector groups: -// -// [ xf0 xf4 xf8 xf12 ] -// [ xf1 xf5 xf9 xf13 ] -// [ xf2 xf6 xf10 xf14 ] -// [ xf3 xf7 xf11 xf15 ] -// - -typedef struct __attribute__((aligned(32))) { - float fr0; - float fr1; - float fr2; - float fr3; - float fr4; - float fr5; - float fr6; - float fr7; - float fr8; - float fr9; - float fr10; - float fr11; - float fr12; - float fr13; - float fr14; - float fr15; -} ALL_FLOATS_STRUCT; - -// Return structs should be defined locally so that GCC optimizes them into -// register usage instead of memory accesses. -typedef struct { - float z1; - float z2; - float z3; - float z4; -} RETURN_VECTOR_STRUCT; - -#if __GNUC__ <= GNUC_FSCA_ERROR_VERSION -typedef struct { - float sine; - float cosine; -} RETURN_FSCA_STRUCT; -#endif - -// Identity Matrix -// -// FV0 FV4 FV8 FV12 -// --- --- --- ---- -// [ 1 0 0 0 ] -// [ 0 1 0 0 ] -// [ 0 0 1 0 ] -// [ 0 0 0 1 ] -// - -static const ALL_FLOATS_STRUCT MATH_identity_matrix = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; - -// Constants -#define MATH_pi 3.14159265358979323846264338327950288419716939937510f -#define MATH_e 2.71828182845904523536028747135266249775724709369995f -#define MATH_phi 1.61803398874989484820458683436563811772030917980576f - -//============================================================================== -// Basic math functions -//============================================================================== -// -// The following functions are available. -// Please see their definitions for other usage info, otherwise they may not -// work for you. -// -/* - // |x| - float MATH_fabs(float x) - - // sqrt(x) - float MATH_fsqrt(float x) - - // a*b+c - float MATH_fmac(float a, float b, float c) - - // a*b-c - float MATH_fmac_Dec(float a, float b, float c) - - // fminf() - return the min of two floats - // This doesn't check for NaN - float MATH_Fast_Fminf(float a, float b) - - // fmaxf() - return the max of two floats - // This doesn't check for NaN - float MATH_Fast_Fmaxf(float a, float b) - - // Fast floorf() - return the nearest integer <= x as a float - // This doesn't check for NaN - float MATH_Fast_Floorf(float x) - - // Fast ceilf() - return the nearest integer >= x as a float - // This doesn't check for NaN - float MATH_Fast_Ceilf(float x) - - // Very fast floorf() - return the nearest integer <= x as a float - // Inspired by a cool trick I came across here: - // https://www.codeproject.com/Tips/700780/Fast-floor-ceiling-functions - // This doesn't check for NaN - float MATH_Very_Fast_Floorf(float x) - - // Very fast ceilf() - return the nearest integer >= x as a float - // Inspired by a cool trick I came across here: - // https://www.codeproject.com/Tips/700780/Fast-floor-ceiling-functions - // This doesn't check for NaN - float MATH_Very_Fast_Ceilf(float x) -*/ - -// |x| -// This one works on ARM and x86, too! -static inline __attribute__((always_inline)) float MATH_fabs(float x) -{ - asm volatile ("fabs %[floatx]\n" - : [floatx] "+f" (x) // outputs, "+" means r/w - : // no inputs - : // no clobbers - ); - - return x; -} - -// sqrt(x) -// This one works on ARM and x86, too! -// NOTE: There is a much faster version (MATH_Fast_Sqrt()) in the fsrra section of -// this file. Chances are you probably want that one. -static inline __attribute__((always_inline)) float MATH_fsqrt(float x) -{ - asm volatile ("fsqrt %[floatx]\n" - : [floatx] "+f" (x) // outputs, "+" means r/w - : // no inputs - : // no clobbers - ); - - return x; -} - -// a*b+c -static inline __attribute__((always_inline)) float MATH_fmac(float a, float b, float c) -{ - asm volatile ("fmac fr0, %[floatb], %[floatc]\n" - : [floatc] "+f" (c) // outputs, "+" means r/w - : "w" (a), [floatb] "f" (b) // inputs - : // no clobbers - ); - - return c; -} - -// a*b-c -static inline __attribute__((always_inline)) float MATH_fmac_Dec(float a, float b, float c) -{ - asm volatile ("fneg %[floatc]\n\t" - "fmac fr0, %[floatb], %[floatc]\n" - : [floatc] "+&f" (c) // outputs, "+" means r/w, "&" means it's written to before all inputs are consumed - : "w" (a), [floatb] "f" (b) // inputs - : // no clobbers - ); - - return c; -} - -// Fast fminf() - return the min of two floats -// This doesn't check for NaN -static inline __attribute__((always_inline)) float MATH_Fast_Fminf(float a, float b) -{ - float output_float; - - asm volatile ( - "fcmp/gt %[floata], %[floatb]\n\t" // b > a (NaN evaluates to !GT; 0 -> T) - "bt.s 1f\n\t" // yes, a is smaller - " fmov %[floata], %[float_out]\n\t" // so return a - "fmov %[floatb], %[float_out]\n" // no, either b is smaller or they're equal and it doesn't matter - "1:\n" - : [float_out] "=&f" (output_float) // outputs - : [floata] "f" (a), [floatb] "f" (b) // inputs - : "t" // clobbers - ); - - return output_float; -} - -// Fast fmaxf() - return the max of two floats -// This doesn't check for NaN -static inline __attribute__((always_inline)) float MATH_Fast_Fmaxf(float a, float b) -{ - float output_float; - - asm volatile ( - "fcmp/gt %[floata], %[floatb]\n\t" // b > a (NaN evaluates to !GT; 0 -> T) - "bt.s 1f\n\t" // yes, a is smaller - " fmov %[floatb], %[float_out]\n\t" // so return b - "fmov %[floata], %[float_out]\n" // no, either a is bigger or they're equal and it doesn't matter - "1:\n" - : [float_out] "=&f" (output_float) // outputs - : [floata] "f" (a), [floatb] "f" (b) // inputs - : "t" // clobbers - ); - - return output_float; -} - -// Fast floorf() - return the nearest integer <= x as a float -// This doesn't check for NaN -static inline __attribute__((always_inline)) float MATH_Fast_Floorf(float x) -{ - float output_float; - - // To hold -1.0f - float minus_one; - - asm volatile ( - "fldi1 %[minus_1]\n\t" - "fneg %[minus_1]\n\t" - "fcmp/gt %[minus_1], %[floatx]\n\t" // x >= 0 - "ftrc %[floatx], fpul\n\t" // convert float to int - "bt.s 1f\n\t" - " float fpul, %[float_out]\n\t" // convert int to float - "fadd %[minus_1], %[float_out]\n" // if input x < 0, subtract 1.0 - "1:\n" - : [minus_1] "=&f" (minus_one), [float_out] "=f" (output_float) - : [floatx] "f" (x) - : "fpul", "t" - ); - - return output_float; -} - -// Fast ceilf() - return the nearest integer >= x as a float -// This doesn't check for NaN -static inline __attribute__((always_inline)) float MATH_Fast_Ceilf(float x) -{ - float output_float; - - // To hold 0.0f and 1.0f - float zero_one; - - asm volatile ( - "fldi0 %[zero_1]\n\t" - "fcmp/gt %[zero_1], %[floatx]\n\t" // x > 0 - "ftrc %[floatx], fpul\n\t" // convert float to int - "bf.s 1f\n\t" - " float fpul, %[float_out]\n\t" // convert int to float - "fldi1 %[zero_1]\n\t" - "fadd %[zero_1], %[float_out]\n" // if input x > 0, add 1.0 - "1:\n" - : [zero_1] "=&f" (zero_one), [float_out] "=f" (output_float) - : [floatx] "f" (x) - : "fpul", "t" - ); - - return output_float; -} - -// Very fast floorf() - return the nearest integer <= x as a float -// Inspired by a cool trick I came across here: -// https://www.codeproject.com/Tips/700780/Fast-floor-ceiling-functions -// This doesn't check for NaN -static inline __attribute__((always_inline)) float MATH_Very_Fast_Floorf(float x) -{ - float output_float; - unsigned int scratch_reg; - unsigned int scratch_reg2; - - // 0x4f000000 == 2^31 in float -- 0x4f << 24 is INT_MAX + 1.0f - // 0x80000000 == -2^31 == INT_MIN == -(INT_MAX + 1.0f) - - // floor = (float)( (int)(x + (float)2^31) - 2^31) - - asm volatile ( - "mov #0x4f, %[scratch]\n\t" // Build float INT_MAX + 1 as a float using only regs (EX) - "shll16 %[scratch]\n\t" // (EX) - "shll8 %[scratch]\n\t" // (EX) - "lds %[scratch], fpul\n\t" // move float INT_MAX + 1 to float regs (LS) - "mov #1, %[scratch2]\n\t" // Build INT_MIN from scratch in parallel (EX) - "fsts fpul, %[float_out]\n\t" // (LS) - "fadd %[floatx], %[float_out]\n\t" // float-add float INT_MAX + 1 to x (FE) - "rotr %[scratch2]\n\t" // rotate the 1 in bit 0 from LSB to MSB for INT_MIN, clobber T (EX) - "ftrc %[float_out], fpul\n\t" // convert float to int (FE) -- ftrc -> sts is special combo - "sts fpul, %[scratch]\n\t" // move back to int regs (LS) - "add %[scratch2], %[scratch]\n\t" // Add INT_MIN to int (EX) - "lds %[scratch], fpul\n\t" // (LS) -- lds -> float is a special combo - "float fpul, %[float_out]\n" // convert back to float (FE) - : [scratch] "=&r" (scratch_reg), [scratch2] "=&r" (scratch_reg2), [float_out] "=&f" (output_float) - : [floatx] "f" (x) - : "fpul", "t" - ); - - return output_float; -} - -// Very fast ceilf() - return the nearest integer >= x as a float -// Inspired by a cool trick I came across here: -// https://www.codeproject.com/Tips/700780/Fast-floor-ceiling-functions -// This doesn't check for NaN -static inline __attribute__((always_inline)) float MATH_Very_Fast_Ceilf(float x) -{ - float output_float; - unsigned int scratch_reg; - unsigned int scratch_reg2; - - // 0x4f000000 == 2^31 in float -- 0x4f << 24 is INT_MAX + 1.0f - // 0x80000000 == -2^31 == INT_MIN == -(INT_MAX + 1.0f) - - // Ceiling is the inverse of floor such that f^-1(x) = -f(-x) - // To make very fast ceiling have as wide a range as very fast floor, - // use this property to subtract x from INT_MAX + 1 and get the negative of the - // ceiling, and then negate the final output. This allows ceiling to use - // -2^31 and have the same range as very fast floor. - - // Given: - // floor = (float)( (int)(x + (float)2^31) - 2^31 ) - // We can do: - // ceiling = -( (float)( (int)((float)2^31 - x) - 2^31 ) ) - // or (slower on SH4 since 'fneg' is faster than 'neg'): - // ceiling = (float) -( (int)((float)2^31 - x) - 2^31 ) - // Since mathematically these functions are related by f^-1(x) = -f(-x). - - asm volatile ( - "mov #0x4f, %[scratch]\n\t" // Build float INT_MAX + 1 as a float using only regs (EX) - "shll16 %[scratch]\n\t" // (EX) - "shll8 %[scratch]\n\t" // (EX) - "lds %[scratch], fpul\n\t" // move float INT_MAX + 1 to float regs (LS) - "mov #1, %[scratch2]\n\t" // Build INT_MIN from scratch in parallel (EX) - "fsts fpul, %[float_out]\n\t" // (LS) - "fsub %[floatx], %[float_out]\n\t" // float-sub x from float INT_MAX + 1 (FE) - "rotr %[scratch2]\n\t" // rotate the 1 in bit 0 from LSB to MSB for INT_MIN, clobber T (EX) - "ftrc %[float_out], fpul\n\t" // convert float to int (FE) -- ftrc -> sts is special combo - "sts fpul, %[scratch]\n\t" // move back to int regs (LS) - "add %[scratch2], %[scratch]\n\t" // Add INT_MIN to int (EX) - "lds %[scratch], fpul\n\t" // (LS) -- lds -> float is a special combo - "float fpul, %[float_out]\n\t" // convert back to float (FE) - "fneg %[float_out]\n" - : [scratch] "=&r" (scratch_reg), [scratch2] "=&r" (scratch_reg2), [float_out] "=&f" (output_float) - : [floatx] "f" (x) - : "fpul", "t" - ); - - return output_float; -} - -//============================================================================== -// Fun with fsrra, which does 1/sqrt(x) in one cycle -//============================================================================== -// -// Error of 'fsrra' is +/- 2^-21 per http://www.shared-ptr.com/sh_insns.html -// -// The following functions are available. -// Please see their definitions for other usage info, otherwise they may not -// work for you. -// -/* - // 1/sqrt(x) - float MATH_fsrra(float x) - - // 1/x - float MATH_Fast_Invert(float x) - - // A faster divide than the 'fdiv' instruction - float MATH_Fast_Divide(float numerator, float denominator) - - // A faster square root then the 'fsqrt' instruction - float MATH_Fast_Sqrt(float x) - - // Standard, accurate, and slow float divide. Use this if MATH_Fast_Divide() gives you issues. - float MATH_Slow_Divide(float numerator, float denominator) -*/ - -// 1/sqrt(x) -static inline __attribute__((always_inline)) float MATH_fsrra(float x) -{ - asm volatile ("fsrra %[one_div_sqrt]\n" - : [one_div_sqrt] "+f" (x) // outputs, "+" means r/w - : // no inputs - : // no clobbers - ); - - return x; -} - -// 1/x -// 1.0f / sqrt(x^2) -static inline __attribute__((always_inline)) float MATH_Fast_Invert(float x) -{ - int neg = 0; - - if(x < 0.0f) - { - neg = 1; - } - - x = MATH_fsrra(x*x); // 1.0f / sqrt(x^2) - - if(neg) - { - return -x; - } - else - { - return x; - } -} - -// It's faster to do this than to use 'fdiv'. -// Only fdiv can do doubles, however. -// Of course, not having to divide at all is generally the best way to go. :P -static inline __attribute__((always_inline)) float MATH_Fast_Divide(float numerator, float denominator) -{ - denominator = MATH_Fast_Invert(denominator); - return numerator * denominator; -} - -// fast sqrt(x) -// Crazy thing: invert(fsrra(x)) is actually about 3x faster than fsqrt. -static inline __attribute__((always_inline)) float MATH_Fast_Sqrt(float x) -{ - return MATH_Fast_Invert(MATH_fsrra(x)); -} - -// Standard, accurate, and slow float divide. Use this if MATH_Fast_Divide() gives you issues. -// This DOES work on negatives. -static inline __attribute__((always_inline)) float MATH_Slow_Divide(float numerator, float denominator) -{ - asm volatile ("fdiv %[div_denom], %[div_numer]\n" - : [div_numer] "+f" (numerator) // outputs, "+" means r/w - : [div_denom] "f" (denominator) // inputs - : // clobbers - ); - - return numerator; -} - -//============================================================================== -// Fun with fsca, which does simultaneous sine and cosine in 3 cycles -//============================================================================== -// -// NOTE: GCC 4.7 has a bug that prevents it from working with fsca and complex -// numbers in m4-single-only mode, so GCC 4 users will get a RETURN_FSCA_STRUCT -// instead of a _Complex float. This may be much slower in some instances. -// -// VERY IMPORTANT USAGE INFORMATION (sine and cosine functions): -// -// Due to the nature in which the fsca instruction behaves, you MUST do the -// following in your code to get sine and cosine from these functions: -// -// _Complex float sine_cosine = [Call the fsca function here] -// float sine_value = __real__ sine_cosine; -// float cosine_value = __imag__ sine_cosine; -// Your output is now in sine_value and cosine_value. -// -// This is necessary because fsca outputs both sine and cosine simultaneously -// and uses a double register to do so. The fsca functions do not actually -// return a double--they return two floats--and using a complex float here is -// just a bit of hacking the C language to make GCC do something that's legal in -// assembly according to the SH4 calling convention (i.e. multiple return values -// stored in floating point registers FR0-FR3). This is better than using a -// struct of floats for optimization purposes--this will operate at peak -// performance even at -O0, whereas a struct will not be fast at low -// optimization levels due to memory accesses. -// -// Technically you may be able to use the complex return values as a complex -// number if you wanted to, but that's probably not what you're after and they'd -// be flipped anyways (in mathematical convention, sine is the imaginary part). -// - -// Notes: -// - From http://www.shared-ptr.com/sh_insns.html: -// The input angle is specified as a signed fraction in twos complement. -// The result of sin and cos is a single-precision floating-point number. -// 0x7FFFFFFF to 0x00000001: 360×2^15−360/2^16 to 360/2^16 degrees -// 0x00000000: 0 degree -// 0xFFFFFFFF to 0x80000000: −360/2^16 to −360×2^15 degrees -// - fsca format is 2^16 is 360 degrees, so a value of 1 is actually -// 1/182.044444444 of a degree or 1/10430.3783505 of a radian -// - fsca does a %360 automatically for values over 360 degrees -// -// Also: -// In order to make the best use of fsca units, a program must expect them from -// the outset and not "make them" by dividing radians or degrees to get them, -// otherwise it's just giving the 'fsca' instruction radians or degrees! -// - -// The following functions are available. -// Please see their definitions for other usage info, otherwise they may not -// work for you. -// -/* - // For integer input in native fsca units (fastest) - _Complex float MATH_fsca_Int(unsigned int input_int) - - // For integer input in degrees - _Complex float MATH_fsca_Int_Deg(unsigned int input_int) - - // For integer input in radians - _Complex float MATH_fsca_Int_Rad(unsigned int input_int) - - // For float input in native fsca units - _Complex float MATH_fsca_Float(float input_float) - - // For float input in degrees - _Complex float MATH_fsca_Float_Deg(float input_float) - - // For float input in radians - _Complex float MATH_fsca_Float_Rad(float input_float) -*/ - -//------------------------------------------------------------------------------ -#if __GNUC__ <= GNUC_FSCA_ERROR_VERSION -//------------------------------------------------------------------------------ -// -// This set of fsca functions is specifically for old versions of GCC. -// See later for functions for newer versions of GCC. -// - -// -// Integer input (faster) -// - -// For int input, input_int is in native fsca units (fastest) -static inline __attribute__((always_inline)) RETURN_FSCA_STRUCT MATH_fsca_Int(unsigned int input_int) -{ - register float __sine __asm__("fr0"); - register float __cosine __asm__("fr1"); - - asm volatile ("lds %[input_number], FPUL\n\t" // load int from register (1 cycle) - "fsca FPUL, DR0\n" // 3 cycle simultaneous sine/cosine - : "=w" (__sine), "=f" (__cosine) // outputs - : [input_number] "r" (input_int) // inputs - : "fpul" // clobbers - ); - - RETURN_FSCA_STRUCT output = {__sine, __cosine}; - return output; -} - -// For int input, input_int is in degrees -static inline __attribute__((always_inline)) RETURN_FSCA_STRUCT MATH_fsca_Int_Deg(unsigned int input_int) -{ - // normalize whole number input degrees to fsca format - input_int = ((1527099483ULL * input_int) >> 23); - - register float __sine __asm__("fr0"); - register float __cosine __asm__("fr1"); - - asm volatile ("lds %[input_number], FPUL\n\t" // load int from register (1 cycle) - "fsca FPUL, DR0\n" // 3 cycle simultaneous sine/cosine - : "=w" (__sine), "=f" (__cosine) // outputs - : [input_number] "r" (input_int) // inputs - : "fpul" // clobbers - ); - - RETURN_FSCA_STRUCT output = {__sine, __cosine}; - return output; -} - -// For int input, input_int is in radians -static inline __attribute__((always_inline)) RETURN_FSCA_STRUCT MATH_fsca_Int_Rad(unsigned int input_int) -{ - // normalize whole number input rads to fsca format - input_int = ((2734261102ULL * input_int) >> 18); - - register float __sine __asm__("fr0"); - register float __cosine __asm__("fr1"); - - asm volatile ("lds %[input_number], FPUL\n\t" // load int from register (1 cycle) - "fsca FPUL, DR0\n" // 3 cycle simultaneous sine/cosine - : "=w" (__sine), "=f" (__cosine) // outputs - : [input_number] "r" (input_int) // inputs - : "fpul" // clobbers - ); - - RETURN_FSCA_STRUCT output = {__sine, __cosine}; - return output; -} - -// -// Float input (slower) -// - -// For float input, input_float is in native fsca units -static inline __attribute__((always_inline)) RETURN_FSCA_STRUCT MATH_fsca_Float(float input_float) -{ - register float __sine __asm__("fr0"); - register float __cosine __asm__("fr1"); - - asm volatile ("ftrc %[input_number], FPUL\n\t" // convert float to int. takes 3 cycles - "fsca FPUL, DR0\n" // 3 cycle simultaneous sine/cosine - : "=w" (__sine), "=f" (__cosine) // outputs - : [input_number] "f" (input_float) // inputs - : "fpul" // clobbers - ); - - RETURN_FSCA_STRUCT output = {__sine, __cosine}; - return output; -} - -// For float input, input_float is in degrees -static inline __attribute__((always_inline)) RETURN_FSCA_STRUCT MATH_fsca_Float_Deg(float input_float) -{ - input_float *= 182.044444444f; - - register float __sine __asm__("fr0"); - register float __cosine __asm__("fr1"); - - asm volatile ("ftrc %[input_number], FPUL\n\t" // convert float to int. takes 3 cycles - "fsca FPUL, DR0\n" // 3 cycle simultaneous sine/cosine - : "=w" (__sine), "=f" (__cosine) // outputs - : [input_number] "f" (input_float) // inputs - : "fpul" // clobbers - ); - - RETURN_FSCA_STRUCT output = {__sine, __cosine}; - return output; -} - -// For float input, input_float is in radians -static inline __attribute__((always_inline)) RETURN_FSCA_STRUCT MATH_fsca_Float_Rad(float input_float) -{ - input_float *= 10430.3783505f; - - register float __sine __asm__("fr0"); - register float __cosine __asm__("fr1"); - - asm volatile ("ftrc %[input_number], FPUL\n\t" // convert float to int. takes 3 cycles - "fsca FPUL, DR0\n" // 3 cycle simultaneous sine/cosine - : "=w" (__sine), "=f" (__cosine) // outputs - : [input_number] "f" (input_float) // inputs - : "fpul" // clobbers - ); - - RETURN_FSCA_STRUCT output = {__sine, __cosine}; - return output; -} - -//------------------------------------------------------------------------------ -#else -//------------------------------------------------------------------------------ -// -// This set of fsca functions is specifically for newer versions of GCC. They -// work fine under GCC 9.2.0. -// - -// -// Integer input (faster) -// - -// For int input, input_int is in native fsca units (fastest) -static inline __attribute__((always_inline)) _Complex float MATH_fsca_Int(unsigned int input_int) -{ - _Complex float output; - - asm volatile ("lds %[input_number], FPUL\n\t" // load int from register (1 cycle) - "fsca FPUL, %[out]\n" // 3 cycle simultaneous sine/cosine - : [out] "=d" (output) // outputs - : [input_number] "r" (input_int) // inputs - : "fpul" // clobbers - ); - - return output; -} - -// For int input, input_int is in degrees -static inline __attribute__((always_inline)) _Complex float MATH_fsca_Int_Deg(unsigned int input_int) -{ - // normalize whole number input degrees to fsca format - input_int = ((1527099483ULL * input_int) >> 23); - - _Complex float output; - - asm volatile ("lds %[input_number], FPUL\n\t" // load int from register (1 cycle) - "fsca FPUL, %[out]\n" // 3 cycle simultaneous sine/cosine - : [out] "=d" (output) // outputs - : [input_number] "r" (input_int) // inputs - : "fpul" // clobbers - ); - - return output; -} - -// For int input, input_int is in radians -static inline __attribute__((always_inline)) _Complex float MATH_fsca_Int_Rad(unsigned int input_int) -{ - // normalize whole number input rads to fsca format - input_int = ((2734261102ULL * input_int) >> 18); - - _Complex float output; - - asm volatile ("lds %[input_number], FPUL\n\t" // load int from register (1 cycle) - "fsca FPUL, %[out]\n" // 3 cycle simultaneous sine/cosine - : [out] "=d" (output) // outputs - : [input_number] "r" (input_int) // inputs - : "fpul" // clobbers - ); - - return output; -} - -// -// Float input (slower) -// - -// For float input, input_float is in native fsca units -static inline __attribute__((always_inline)) _Complex float MATH_fsca_Float(float input_float) -{ - _Complex float output; - - asm volatile ("ftrc %[input_number], FPUL\n\t" // convert float to int. takes 3 cycles - "fsca FPUL, %[out]\n" // 3 cycle simultaneous sine/cosine - : [out] "=d" (output) // outputs - : [input_number] "f" (input_float) // inputs - : "fpul" // clobbers - ); - - return output; -} - -// For float input, input_float is in degrees -static inline __attribute__((always_inline)) _Complex float MATH_fsca_Float_Deg(float input_float) -{ - input_float *= 182.044444444f; - - _Complex float output; - - asm volatile ("ftrc %[input_number], FPUL\n\t" // convert float to int. takes 3 cycles - "fsca FPUL, %[out]\n" // 3 cycle simultaneous sine/cosine - : [out] "=d" (output) // outputs - : [input_number] "f" (input_float) // inputs - : "fpul" // clobbers - ); - - return output; -} - -// For float input, input_float is in radians -static inline __attribute__((always_inline)) _Complex float MATH_fsca_Float_Rad(float input_float) -{ - input_float *= 10430.3783505f; - - _Complex float output; - - asm volatile ("ftrc %[input_number], FPUL\n\t" // convert float to int. takes 3 cycles - "fsca FPUL, %[out]\n" // 3 cycle simultaneous sine/cosine - : [out] "=d" (output) // outputs - : [input_number] "f" (input_float) // inputs - : "fpul" // clobbers - ); - - return output; -} - -//------------------------------------------------------------------------------ -#endif -//------------------------------------------------------------------------------ - -//============================================================================== -// Hardware vector and matrix operations -//============================================================================== -// -// These functions each have very specific usage instructions. Please be sure to -// read them before use or else they won't seem to work right! -// -// The following functions are available. -// Please see their definitions for important usage info, otherwise they may not -// work for you. -// -/* - - //------------------------------------------------------------------------------ - // Vector and matrix math operations - //------------------------------------------------------------------------------ - - // Inner/dot product (4x1 vec . 4x1 vec = scalar) - float MATH_fipr(float x1, float x2, float x3, float x4, float y1, float y2, float y3, float y4) - - // Sum of Squares (w^2 + x^2 + y^2 + z^2) - float MATH_Sum_of_Squares(float w, float x, float y, float z) - - // Cross product with bonus multiply (vec X vec = orthogonal vec, with an extra a*b=c) - RETURN_VECTOR_STRUCT MATH_Cross_Product_with_Mult(float x1, float x2, float x3, float y1, float y2, float y3, float a, float b) - - // Cross product (vec X vec = orthogonal vec) - RETURN_VECTOR_STRUCT MATH_Cross_Product(float x1, float x2, float x3, float y1, float y2, float y3) - - // Outer product (vec (X) vec = 4x4 matrix) - void MATH_Outer_Product(float x1, float x2, float x3, float x4, float y1, float y2, float y3, float y4) - - // Matrix transform (4x4 matrix * 4x1 vec = 4x1 vec) - RETURN_VECTOR_STRUCT MATH_Matrix_Transform(float x1, float x2, float x3, float x4) - - // 4x4 Matrix transpose (XMTRX^T) - void MATH_Matrix_Transpose(void) - - // 4x4 Matrix product (XMTRX and one from memory) - void MATH_Matrix_Product(ALL_FLOATS_STRUCT * front_matrix) - - // 4x4 Matrix product (two from memory) - void MATH_Load_Matrix_Product(ALL_FLOATS_STRUCT * matrix1, ALL_FLOATS_STRUCT * matrix2) - - //------------------------------------------------------------------------------ - // Matrix load and store operations - //------------------------------------------------------------------------------ - - // Load 4x4 XMTRX from memory - void MATH_Load_XMTRX(ALL_FLOATS_STRUCT * back_matrix) - - // Store 4x4 XMTRX to memory - ALL_FLOATS_STRUCT * MATH_Store_XMTRX(ALL_FLOATS_STRUCT * destination) - - // Get 4x1 column vector from XMTRX - RETURN_VECTOR_STRUCT MATH_Get_XMTRX_Vector(unsigned int which) - - // Get 2x2 matrix from XMTRX quadrant - RETURN_VECTOR_STRUCT MATH_Get_XMTRX_2x2(unsigned int which) -*/ - -//------------------------------------------------------------------------------ -// Vector and matrix math operations -//------------------------------------------------------------------------------ - -// Inner/dot product: vec . vec = scalar -// _ _ -// | y1 | -// [ x1 x2 x3 x4 ] . | y2 | = scalar -// | y3 | -// |_ y4 _| -// -// SH4 calling convention states we get 8 float arguments. Perfect! -static inline __attribute__((always_inline)) float MATH_fipr(float x1, float x2, float x3, float x4, float y1, float y2, float y3, float y4) -{ - // FR4-FR11 are the regs that are passed in, aka vectors FV4 and FV8. - // Just need to make sure GCC doesn't modify anything, and these register vars do that job. - - // Temporary variables are necessary per GCC to avoid clobbering: - // https://gcc.gnu.org/onlinedocs/gcc/Local-Register-Variables.html#Local-Register-Variables - - float tx1 = x1; - float tx2 = x2; - float tx3 = x3; - float tx4 = x4; - - float ty1 = y1; - float ty2 = y2; - float ty3 = y3; - float ty4 = y4; - - // vector FV4 - register float __x1 __asm__("fr4") = tx1; - register float __x2 __asm__("fr5") = tx2; - register float __x3 __asm__("fr6") = tx3; - register float __x4 __asm__("fr7") = tx4; - - // vector FV8 - register float __y1 __asm__("fr8") = ty1; - register float __y2 __asm__("fr9") = ty2; - register float __y3 __asm__("fr10") = ty3; - register float __y4 __asm__("fr11") = ty4; - - // take care of all the floats in one fell swoop - asm volatile ("fipr FV4, FV8\n" - : "+f" (__y4) // output (gets written to FR11) - : "f" (__x1), "f" (__x2), "f" (__x3), "f" (__x4), "f" (__y1), "f" (__y2), "f" (__y3) // inputs - : // clobbers - ); - - return __y4; -} - -// Sum of Squares -// _ _ -// | w | -// [ w x y z ] . | x | = w^2 + x^2 + y^2 + z^2 = scalar -// | y | -// |_ z _| -// -static inline __attribute__((always_inline)) float MATH_Sum_of_Squares(float w, float x, float y, float z) -{ - // FR4-FR7 are the regs that are passed in, aka vector FV4. - // Just need to make sure GCC doesn't modify anything, and these register vars do that job. - - // Temporary variables are necessary per GCC to avoid clobbering: - // https://gcc.gnu.org/onlinedocs/gcc/Local-Register-Variables.html#Local-Register-Variables - - float tw = w; - float tx = x; - float ty = y; - float tz = z; - - // vector FV4 - register float __w __asm__("fr4") = tw; - register float __x __asm__("fr5") = tx; - register float __y __asm__("fr6") = ty; - register float __z __asm__("fr7") = tz; - - // take care of all the floats in one fell swoop - asm volatile ("fipr FV4, FV4\n" - : "+f" (__z) // output (gets written to FR7) - : "f" (__w), "f" (__x), "f" (__y) // inputs - : // clobbers - ); - - return __z; -} - -// Cross product: vec X vec = orthogonal vec -// _ _ _ _ _ _ -// | x1 | | y1 | | z1 | -// | x2 | X | y2 | = | z2 | -// |_ x3 _| |_ y3 _| |_ z3 _| -// -// With bonus multiply: -// -// a * b = c -// -// IMPORTANT USAGE INFORMATION (cross product): -// -// Return vector struct maps as below to the above diagram: -// -// typedef struct { -// float z1; -// float z2; -// float z3; -// float z4; // c is stored in z4, and c = a*b if using 'with mult' version (else c = 0) -// } RETURN_VECTOR_STRUCT; -// -// For people familiar with the unit vector notation, z1 == 'i', z2 == 'j', -// and z3 == 'k'. -// -// The cross product matrix will also be stored in XMTRX after this, so calling -// MATH_Matrix_Transform() on a vector after using this function will do a cross -// product with the same x1-x3 values and a multiply with the same 'a' value -// as used in this function. In this a situation, 'a' will be multiplied with -// the x4 parameter of MATH_Matrix_Transform(). a = 0 if not using the 'with mult' -// version of the cross product function. -// -// For reference, XMTRX will look like this: -// -// [ 0 -x3 x2 0 ] -// [ x3 0 -x1 0 ] -// [ -x2 x1 0 0 ] -// [ 0 0 0 a ] (<-- a = 0 if not using 'with mult') -// -// Similarly to how the sine and cosine functions use fsca and return 2 floats, -// the cross product functions actually return 4 floats. The first 3 are the -// cross product output, and the 4th is a*b. The SH4 only multiplies 4x4 -// matrices with 4x1 vectors, which is why the output is like that--but it means -// we also get a bonus float multiplication while we do our cross product! -// - -// Please do not call this function directly (notice the weird syntax); call -// MATH_Cross_Product() or MATH_Cross_Product_with_Mult() instead. -static inline __attribute__((always_inline)) RETURN_VECTOR_STRUCT xMATH_do_Cross_Product_with_Mult(float x3, float a, float y3, float b, float x2, float x1, float y1, float y2) -{ - // FR4-FR11 are the regs that are passed in, in that order. - // Just need to make sure GCC doesn't modify anything, and these register vars do that job. - - // Temporary variables are necessary per GCC to avoid clobbering: - // https://gcc.gnu.org/onlinedocs/gcc/Local-Register-Variables.html#Local-Register-Variables - - float tx1 = x1; - float tx2 = x2; - float tx3 = x3; - float ta = a; - - float ty1 = y1; - float ty2 = y2; - float ty3 = y3; - float tb = b; - - register float __x1 __asm__("fr9") = tx1; // need to negate (need to move to fr6, then negate fr9) - register float __x2 __asm__("fr8") = tx2; // in place for matrix (need to move to fr2 then negate fr2) - register float __x3 __asm__("fr4") = tx3; // need to negate (move to fr1 first, then negate fr4) - register float __a __asm__("fr5") = ta; - - register float __y1 __asm__("fr10") = ty1; - register float __y2 __asm__("fr11") = ty2; - register float __y3 __asm__("fr6") = ty3; - register float __b __asm__("fr7") = tb; - - register float __z1 __asm__("fr0") = 0.0f; // z1 - register float __z2 __asm__("fr1") = 0.0f; // z2 (not moving x3 here yet since a double 0 is needed) - register float __z3 __asm__("fr2") = tx2; // z3 (this handles putting x2 in fr2) - register float __c __asm__("fr3") = 0.0f; // c - - // This actually does a matrix transform to do the cross product. - // It's this: - // _ _ _ _ - // [ 0 -x3 x2 0 ] | y1 | | -x3y2 + x2y3 | - // [ x3 0 -x1 0 ] | y2 | = | x3y1 - x1y3 | - // [ -x2 x1 0 0 ] | y3 | | -x2y1 + x1y2 | - // [ 0 0 0 a ] |_ b _| |_ c _| - // - - asm volatile ( - // set up back bank's FV0 - "fschg\n\t" // switch fmov to paired moves (note: only paired moves can access XDn regs) - - // Save FR12-FR15, which are supposed to be preserved across functions calls. - // This stops them from getting clobbered and saves 4 stack pushes (memory accesses). - "fmov DR12, XD12\n\t" - "fmov DR14, XD14\n\t" - - "fmov DR10, XD0\n\t" // fmov 'y1' and 'y2' from FR10, FR11 into position (XF0, XF1) - "fmov DR6, XD2\n\t" // fmov 'y3' and 'b' from FR6, FR7 into position (XF2, XF3) - - // pair move zeros for some speed in setting up front bank for matrix - "fmov DR0, DR10\n\t" // clear FR10, FR11 - "fmov DR0, DR12\n\t" // clear FR12, FR13 - "fschg\n\t" // switch back to single moves - // prepare front bank for XMTRX - "fmov FR5, FR15\n\t" // fmov 'a' into position - "fmov FR0, FR14\n\t" // clear out FR14 - "fmov FR0, FR7\n\t" // clear out FR7 - "fmov FR0, FR5\n\t" // clear out FR5 - - "fneg FR2\n\t" // set up 'x2' - "fmov FR9, FR6\n\t" // set up 'x1' - "fneg FR9\n\t" - "fmov FR4, FR1\n\t" // set up 'x3' - "fneg FR4\n\t" - // flip banks and matrix multiply - "frchg\n\t" - "ftrv XMTRX, FV0\n" - : "+&w" (__z1), "+&f" (__z2), "+&f" (__z3), "+&f" (__c) // output (using FV0) - : "f" (__x1), "f" (__x2), "f" (__x3), "f" (__y1), "f" (__y2), "f" (__y3), "f" (__a), "f" (__b) // inputs - : // clobbers (all of the float regs get clobbered, except for FR12-FR15 which were specially preserved) - ); - - RETURN_VECTOR_STRUCT output = {__z1, __z2, __z3, __c}; - return output; -} - -// Please do not call this function directly (notice the weird syntax); call -// MATH_Cross_Product() or MATH_Cross_Product_with_Mult() instead. -static inline __attribute__((always_inline)) RETURN_VECTOR_STRUCT xMATH_do_Cross_Product(float x3, float zero, float x1, float y3, float x2, float x1_2, float y1, float y2) -{ - // FR4-FR11 are the regs that are passed in, in that order. - // Just need to make sure GCC doesn't modify anything, and these register vars do that job. - - // Temporary variables are necessary per GCC to avoid clobbering: - // https://gcc.gnu.org/onlinedocs/gcc/Local-Register-Variables.html#Local-Register-Variables - - float tx1 = x1; - float tx2 = x2; - float tx3 = x3; - float tx1_2 = x1_2; - - float ty1 = y1; - float ty2 = y2; - float ty3 = y3; - float tzero = zero; - - register float __x1 __asm__("fr6") = tx1; // in place - register float __x2 __asm__("fr8") = tx2; // in place (fmov to fr2, negate fr2) - register float __x3 __asm__("fr4") = tx3; // need to negate (fmov to fr1, negate fr4) - - register float __zero __asm__("fr5") = tzero; // in place - register float __x1_2 __asm__("fr9") = tx1_2; // need to negate - - register float __y1 __asm__("fr10") = ty1; - register float __y2 __asm__("fr11") = ty2; - // no __y3 needed in this function - - register float __z1 __asm__("fr0") = tzero; // z1 - register float __z2 __asm__("fr1") = tzero; // z2 - register float __z3 __asm__("fr2") = ty3; // z3 - register float __c __asm__("fr3") = tzero; // c - - // This actually does a matrix transform to do the cross product. - // It's this: - // _ _ _ _ - // [ 0 -x3 x2 0 ] | y1 | | -x3y2 + x2y3 | - // [ x3 0 -x1 0 ] | y2 | = | x3y1 - x1y3 | - // [ -x2 x1 0 0 ] | y3 | | -x2y1 + x1y2 | - // [ 0 0 0 0 ] |_ 0 _| |_ 0 _| - // - - asm volatile ( - // zero out FR7. For some reason, if this is done in C after __z3 is set: - // register float __y3 __asm__("fr7") = tzero; - // then GCC will emit a spurious stack push (pushing FR12). So just zero it here. - "fmov FR5, FR7\n\t" - // set up back bank's FV0 - "fschg\n\t" // switch fmov to paired moves (note: only paired moves can access XDn regs) - - // Save FR12-FR15, which are supposed to be preserved across functions calls. - // This stops them from getting clobbered and saves 4 stack pushes (memory accesses). - "fmov DR12, XD12\n\t" - "fmov DR14, XD14\n\t" - - "fmov DR10, XD0\n\t" // fmov 'y1' and 'y2' from FR10, FR11 into position (XF0, XF1) - "fmov DR2, XD2\n\t" // fmov 'y3' and '0' from FR2, FR3 into position (XF2, XF3) - - // pair move zeros for some speed in setting up front bank for matrix - "fmov DR0, DR10\n\t" // clear FR10, FR11 - "fmov DR0, DR12\n\t" // clear FR12, FR13 - "fmov DR0, DR14\n\t" // clear FR14, FR15 - "fschg\n\t" // switch back to single moves - // prepare front bank for XMTRX - "fneg FR9\n\t" // set up 'x1' - "fmov FR8, FR2\n\t" // set up 'x2' - "fneg FR2\n\t" - "fmov FR4, FR1\n\t" // set up 'x3' - "fneg FR4\n\t" - // flip banks and matrix multiply - "frchg\n\t" - "ftrv XMTRX, FV0\n" - : "+&w" (__z1), "+&f" (__z2), "+&f" (__z3), "+&f" (__c) // output (using FV0) - : "f" (__x1), "f" (__x2), "f" (__x3), "f" (__y1), "f" (__y2), "f" (__zero), "f" (__x1_2) // inputs - : "fr7" // clobbers (all of the float regs get clobbered, except for FR12-FR15 which were specially preserved) - ); - - RETURN_VECTOR_STRUCT output = {__z1, __z2, __z3, __c}; - return output; -} - -//------------------------------------------------------------------------------ -// Functions that wrap the xMATH_do_Cross_Product[_with_Mult]() functions to make -// it easier to organize parameters -//------------------------------------------------------------------------------ - -// Cross product with a bonus float multiply (c = a * b) -static inline __attribute__((always_inline)) RETURN_VECTOR_STRUCT MATH_Cross_Product_with_Mult(float x1, float x2, float x3, float y1, float y2, float y3, float a, float b) -{ - return xMATH_do_Cross_Product_with_Mult(x3, a, y3, b, x2, x1, y1, y2); -} - -// Plain cross product; does not use the bonus float multiply (c = 0 and a in the cross product matrix will be 0) -// This is a tiny bit faster than 'with_mult' (about 2 cycles faster) -static inline __attribute__((always_inline)) RETURN_VECTOR_STRUCT MATH_Cross_Product(float x1, float x2, float x3, float y1, float y2, float y3) -{ - return xMATH_do_Cross_Product(x3, 0.0f, x1, y3, x2, x1, y1, y2); -} - -// Outer product: vec (X) vec = matrix -// _ _ -// | x1 | -// | x2 | (X) [ y1 y2 y3 y4 ] = 4x4 matrix -// | x3 | -// |_ x4 _| -// -// This returns the floats in the back bank (XF0-15), which are inaccessible -// outside of using frchg or paired-move fmov. It's meant to set up a matrix for -// use with other matrix functions. GCC also does not touch the XFn bank. -// This will also wipe out anything stored in the float registers, as it uses the -// whole FPU register file (all 32 of the float registers). -static inline __attribute__((always_inline)) void MATH_Outer_Product(float x1, float x2, float x3, float x4, float y1, float y2, float y3, float y4) -{ - // FR4-FR11 are the regs that are passed in, in that order. - // Just need to make sure GCC doesn't modify anything, and these register vars do that job. - - // Temporary variables are necessary per GCC to avoid clobbering: - // https://gcc.gnu.org/onlinedocs/gcc/Local-Register-Variables.html#Local-Register-Variables - - float tx1 = x1; - float tx2 = x2; - float tx3 = x3; - float tx4 = x4; - - float ty1 = y1; - float ty2 = y2; - float ty3 = y3; - float ty4 = y4; - - // vector FV4 - register float __x1 __asm__("fr4") = tx1; - register float __x2 __asm__("fr5") = tx2; - register float __x3 __asm__("fr6") = tx3; - register float __x4 __asm__("fr7") = tx4; - - // vector FV8 - register float __y1 __asm__("fr8") = ty1; - register float __y2 __asm__("fr9") = ty2; - register float __y3 __asm__("fr10") = ty3; // in place already - register float __y4 __asm__("fr11") = ty4; - - // This actually does a 4x4 matrix multiply to do the outer product. - // It's this: - // - // [ x1 x1 x1 x1 ] [ y1 0 0 0 ] [ x1y1 x1y2 x1y3 x1y4 ] - // [ x2 x2 x2 x2 ] [ 0 y2 0 0 ] = [ x2y1 x2y2 x2y3 x2y4 ] - // [ x3 x3 x3 x3 ] [ 0 0 y3 0 ] [ x3y1 x3y2 x3y3 x3y4 ] - // [ x4 x4 x4 x4 ] [ 0 0 0 y4 ] [ x4y1 x4y2 x4y3 x4y4 ] - // - - asm volatile ( - // zero out unoccupied front floats to make a double 0 in DR2 - "fldi0 FR2\n\t" - "fmov FR2, FR3\n\t" - "fschg\n\t" // switch fmov to paired moves (note: only paired moves can access XDn regs) - // fmov 'x1' and 'x2' from FR4, FR5 into position (XF0,4,8,12, XF1,5,9,13) - "fmov DR4, XD0\n\t" - "fmov DR4, XD4\n\t" - "fmov DR4, XD8\n\t" - "fmov DR4, XD12\n\t" - // fmov 'x3' and 'x4' from FR6, FR7 into position (XF2,6,10,14, XF3,7,11,15) - "fmov DR6, XD2\n\t" - "fmov DR6, XD6\n\t" - "fmov DR6, XD10\n\t" - "fmov DR6, XD14\n\t" - // set up front floats (y1-y4) - "fmov DR8, DR0\n\t" - "fmov DR8, DR4\n\t" - "fmov DR10, DR14\n\t" - // finish zeroing out front floats - "fmov DR2, DR6\n\t" - "fmov DR2, DR8\n\t" - "fmov DR2, DR12\n\t" - "fschg\n\t" // switch back to single-move mode - // zero out remaining values and matrix multiply 4x4 - "fmov FR2, FR1\n\t" - "ftrv XMTRX, FV0\n\t" - - "fmov FR6, FR4\n\t" - "ftrv XMTRX, FV4\n\t" - - "fmov FR8, FR11\n\t" - "ftrv XMTRX, FV8\n\t" - - "fmov FR12, FR14\n\t" - "ftrv XMTRX, FV12\n\t" - // Save output in XF regs - "frchg\n" - : // no outputs - : "f" (__x1), "f" (__x2), "f" (__x3), "f" (__x4), "f" (__y1), "f" (__y2), "f" (__y3), "f" (__y4) // inputs - : "fr0", "fr1", "fr2", "fr3", "fr12", "fr13", "fr14", "fr15" // clobbers, can't avoid it - ); - // GCC will restore FR12-FR15 from the stack after this, so we really can't keep the output in the front bank. -} - -// Matrix transform: matrix * vector = vector -// _ _ _ _ -// [ ----------- ] | x1 | | z1 | -// [ ---XMTRX--- ] | x2 | = | z2 | -// [ ----------- ] | x3 | | z3 | -// [ ----------- ] |_ x4 _| |_ z4 _| -// -// IMPORTANT USAGE INFORMATION (matrix transform): -// -// Return vector struct maps 1:1 to the above diagram: -// -// typedef struct { -// float z1; -// float z2; -// float z3; -// float z4; -// } RETURN_VECTOR_STRUCT; -// -// Similarly to how the sine and cosine functions use fsca and return 2 floats, -// the matrix transform function actually returns 4 floats. The SH4 only multiplies -// 4x4 matrices with 4x1 vectors, which is why the output is like that. -// -// Multiply a matrix stored in the back bank (XMTRX) with an input vector -static inline __attribute__((always_inline)) RETURN_VECTOR_STRUCT MATH_Matrix_Transform(float x1, float x2, float x3, float x4) -{ - // The floats comprising FV4 are the regs that are passed in. - // Just need to make sure GCC doesn't modify anything, and these register vars do that job. - - // Temporary variables are necessary per GCC to avoid clobbering: - // https://gcc.gnu.org/onlinedocs/gcc/Local-Register-Variables.html#Local-Register-Variables - - float tx1 = x1; - float tx2 = x2; - float tx3 = x3; - float tx4 = x4; - - // output vector FV0 - register float __z1 __asm__("fr0") = tx1; - register float __z2 __asm__("fr1") = tx2; - register float __z3 __asm__("fr2") = tx3; - register float __z4 __asm__("fr3") = tx4; - - asm volatile ("ftrv XMTRX, FV0\n\t" - // have to do this to obey SH4 calling convention--output returned in FV0 - : "+w" (__z1), "+f" (__z2), "+f" (__z3), "+f" (__z4) // outputs, "+" means r/w - : // no inputs - : // no clobbers - ); - - RETURN_VECTOR_STRUCT output = {__z1, __z2, __z3, __z4}; - return output; -} - -// Matrix Transpose -// -// This does a matrix transpose on the matrix in XMTRX, which swaps rows with -// columns as follows (math notation is [XMTRX]^T): -// -// [ a b c d ] T [ a e i m ] -// [ e f g h ] = [ b f j n ] -// [ i j k l ] [ c g k o ] -// [ m n o p ] [ d h l p ] -// -// PLEASE NOTE: It is faster to avoid the need for a transpose altogether by -// structuring matrices and vectors accordingly. -static inline __attribute__((always_inline)) void MATH_Matrix_Transpose(void) -{ - asm volatile ( - "frchg\n\t" // fmov for singles only works on front bank - // FR0, FR5, FR10, and FR15 are already in place - // swap FR1 and FR4 - "flds FR1, FPUL\n\t" - "fmov FR4, FR1\n\t" - "fsts FPUL, FR4\n\t" - // swap FR2 and FR8 - "flds FR2, FPUL\n\t" - "fmov FR8, FR2\n\t" - "fsts FPUL, FR8\n\t" - // swap FR3 and FR12 - "flds FR3, FPUL\n\t" - "fmov FR12, FR3\n\t" - "fsts FPUL, FR12\n\t" - // swap FR6 and FR9 - "flds FR6, FPUL\n\t" - "fmov FR9, FR6\n\t" - "fsts FPUL, FR9\n\t" - // swap FR7 and FR13 - "flds FR7, FPUL\n\t" - "fmov FR13, FR7\n\t" - "fsts FPUL, FR13\n\t" - // swap FR11 and FR14 - "flds FR11, FPUL\n\t" - "fmov FR14, FR11\n\t" - "fsts FPUL, FR14\n\t" - // restore XMTRX to back bank - "frchg\n" - : // no outputs - : // no inputs - : "fpul" // clobbers - ); -} - -// Matrix product: matrix * matrix = matrix -// -// These use the whole dang floating point unit. -// -// [ ----------- ] [ ----------- ] [ ----------- ] -// [ ---Back---- ] [ ---Front--- ] = [ ---XMTRX--- ] -// [ ---Matrix-- ] [ ---Matrix-- ] [ ----------- ] -// [ --(XMTRX)-- ] [ ----------- ] [ ----------- ] -// -// Multiply a matrix stored in the back bank with a matrix loaded from memory -// Output is stored in the back bank (XMTRX) -static inline __attribute__((always_inline)) void MATH_Matrix_Product(ALL_FLOATS_STRUCT * front_matrix) -{ - /* - // This prefetching should help a bit if placed suitably far enough in advance (not here) - // Possibly right before this function call. Change the "front_matrix" variable appropriately. - // SH4 does not support r/w or temporal prefetch hints, so we only need to pass in an address. - __builtin_prefetch(front_matrix); - */ - - unsigned int prefetch_scratch; - - asm volatile ( - "mov %[fmtrx], %[pref_scratch]\n\t" // parallel-load address for prefetching (MT) - "add #32, %[pref_scratch]\n\t" // offset by 32 (EX - flow dependency, but 'add' is actually parallelized since 'mov Rm, Rn' is 0-cycle) - "fschg\n\t" // switch fmov to paired moves (FE) - "pref @%[pref_scratch]\n\t" // Get a head start prefetching the second half of the 64-byte data (LS) - // interleave loads and matrix multiply 4x4 - "fmov.d @%[fmtrx]+, DR0\n\t" // (LS) - "fmov.d @%[fmtrx]+, DR2\n\t" - "fmov.d @%[fmtrx]+, DR4\n\t" // (LS) want to issue the next one before 'ftrv' for parallel exec - "ftrv XMTRX, FV0\n\t" // (FE) - - "fmov.d @%[fmtrx]+, DR6\n\t" - "fmov.d @%[fmtrx]+, DR8\n\t" // prefetch should work for here - "ftrv XMTRX, FV4\n\t" - - "fmov.d @%[fmtrx]+, DR10\n\t" - "fmov.d @%[fmtrx]+, DR12\n\t" - "ftrv XMTRX, FV8\n\t" - - "fmov.d @%[fmtrx], DR14\n\t" // (LS, but this will stall 'ftrv' for 3 cycles) - "fschg\n\t" // switch back to single moves (and avoid stalling 'ftrv') (FE) - "ftrv XMTRX, FV12\n\t" // (FE) - // Save output in XF regs - "frchg\n" - : [fmtrx] "+r" ((unsigned int)front_matrix), [pref_scratch] "=&r" (prefetch_scratch) // outputs, "+" means r/w - : // no inputs - : "fr0", "fr1", "fr2", "fr3", "fr4", "fr5", "fr6", "fr7", "fr8", "fr9", "fr10", "fr11", "fr12", "fr13", "fr14", "fr15" // clobbers (GCC doesn't know about back bank, so writing to it isn't clobbered) - ); -} - -// Load two 4x4 matrices and multiply them, storing the output into the back bank (XMTRX) -// -// MATH_Load_Matrix_Product() is slightly faster than doing this: -// MATH_Load_XMTRX(matrix1) -// MATH_Matrix_Product(matrix2) -// as it saves having to do 2 extraneous 'fschg' instructions. -// -static inline __attribute__((always_inline)) void MATH_Load_Matrix_Product(ALL_FLOATS_STRUCT * matrix1, ALL_FLOATS_STRUCT * matrix2) -{ - /* - // This prefetching should help a bit if placed suitably far enough in advance (not here) - // Possibly right before this function call. Change the "matrix1" variable appropriately. - // SH4 does not support r/w or temporal prefetch hints, so we only need to pass in an address. - __builtin_prefetch(matrix1); - */ - - unsigned int prefetch_scratch; - - asm volatile ( - "mov %[bmtrx], %[pref_scratch]\n\t" // (MT) - "add #32, %[pref_scratch]\n\t" // offset by 32 (EX - flow dependency, but 'add' is actually parallelized since 'mov Rm, Rn' is 0-cycle) - "fschg\n\t" // switch fmov to paired moves (note: only paired moves can access XDn regs) (FE) - "pref @%[pref_scratch]\n\t" // Get a head start prefetching the second half of the 64-byte data (LS) - // back matrix - "fmov.d @%[bmtrx]+, XD0\n\t" // (LS) - "fmov.d @%[bmtrx]+, XD2\n\t" - "fmov.d @%[bmtrx]+, XD4\n\t" - "fmov.d @%[bmtrx]+, XD6\n\t" - "pref @%[fmtrx]\n\t" // prefetch fmtrx now while we wait (LS) - "fmov.d @%[bmtrx]+, XD8\n\t" // bmtrx prefetch should work for here - "fmov.d @%[bmtrx]+, XD10\n\t" - "fmov.d @%[bmtrx]+, XD12\n\t" - "mov %[fmtrx], %[pref_scratch]\n\t" // (MT) - "add #32, %[pref_scratch]\n\t" // store offset by 32 in r0 (EX - flow dependency, but 'add' is actually parallelized since 'mov Rm, Rn' is 0-cycle) - "fmov.d @%[bmtrx], XD14\n\t" - "pref @%[pref_scratch]\n\t" // Get a head start prefetching the second half of the 64-byte data (LS) - // front matrix - // interleave loads and matrix multiply 4x4 - "fmov.d @%[fmtrx]+, DR0\n\t" - "fmov.d @%[fmtrx]+, DR2\n\t" - "fmov.d @%[fmtrx]+, DR4\n\t" // (LS) want to issue the next one before 'ftrv' for parallel exec - "ftrv XMTRX, FV0\n\t" // (FE) - - "fmov.d @%[fmtrx]+, DR6\n\t" - "fmov.d @%[fmtrx]+, DR8\n\t" - "ftrv XMTRX, FV4\n\t" - - "fmov.d @%[fmtrx]+, DR10\n\t" - "fmov.d @%[fmtrx]+, DR12\n\t" - "ftrv XMTRX, FV8\n\t" - - "fmov.d @%[fmtrx], DR14\n\t" // (LS, but this will stall 'ftrv' for 3 cycles) - "fschg\n\t" // switch back to single moves (and avoid stalling 'ftrv') (FE) - "ftrv XMTRX, FV12\n\t" // (FE) - // Save output in XF regs - "frchg\n" - : [bmtrx] "+&r" ((unsigned int)matrix1), [fmtrx] "+r" ((unsigned int)matrix2), [pref_scratch] "=&r" (prefetch_scratch) // outputs, "+" means r/w, "&" means it's written to before all inputs are consumed - : // no inputs - : "fr0", "fr1", "fr2", "fr3", "fr4", "fr5", "fr6", "fr7", "fr8", "fr9", "fr10", "fr11", "fr12", "fr13", "fr14", "fr15" // clobbers (GCC doesn't know about back bank, so writing to it isn't clobbered) - ); -} - -//------------------------------------------------------------------------------ -// Matrix load and store operations -//------------------------------------------------------------------------------ - -// Load a matrix from memory into the back bank (XMTRX) -static inline __attribute__((always_inline)) void MATH_Load_XMTRX(ALL_FLOATS_STRUCT * back_matrix) -{ - /* - // This prefetching should help a bit if placed suitably far enough in advance (not here) - // Possibly right before this function call. Change the "back_matrix" variable appropriately. - // SH4 does not support r/w or temporal prefetch hints, so we only need to pass in an address. - __builtin_prefetch(back_matrix); - */ - - unsigned int prefetch_scratch; - - asm volatile ( - "mov %[bmtrx], %[pref_scratch]\n\t" // (MT) - "add #32, %[pref_scratch]\n\t" // offset by 32 (EX - flow dependency, but 'add' is actually parallelized since 'mov Rm, Rn' is 0-cycle) - "fschg\n\t" // switch fmov to paired moves (note: only paired moves can access XDn regs) (FE) - "pref @%[pref_scratch]\n\t" // Get a head start prefetching the second half of the 64-byte data (LS) - "fmov.d @%[bmtrx]+, XD0\n\t" - "fmov.d @%[bmtrx]+, XD2\n\t" - "fmov.d @%[bmtrx]+, XD4\n\t" - "fmov.d @%[bmtrx]+, XD6\n\t" - "fmov.d @%[bmtrx]+, XD8\n\t" - "fmov.d @%[bmtrx]+, XD10\n\t" - "fmov.d @%[bmtrx]+, XD12\n\t" - "fmov.d @%[bmtrx], XD14\n\t" - "fschg\n" // switch back to single moves - : [bmtrx] "+r" ((unsigned int)back_matrix), [pref_scratch] "=&r" (prefetch_scratch) // outputs, "+" means r/w - : // no inputs - : // clobbers (GCC doesn't know about back bank, so writing to it isn't clobbered) - ); -} - -// Store XMTRX to memory -static inline __attribute__((always_inline)) ALL_FLOATS_STRUCT * MATH_Store_XMTRX(ALL_FLOATS_STRUCT * destination) -{ - /* - // This prefetching should help a bit if placed suitably far enough in advance (not here) - // Possibly right before this function call. Change the "destination" variable appropriately. - // SH4 does not support r/w or temporal prefetch hints, so we only need to pass in an address. - __builtin_prefetch( (ALL_FLOATS_STRUCT*)((unsigned char*)destination + 32) ); // Store works backwards, so note the '+32' here - */ - - char * output = ((char*)destination) + sizeof(ALL_FLOATS_STRUCT) + 8; // ALL_FLOATS_STRUCT should be 64 bytes - - asm volatile ( - "fschg\n\t" // switch fmov to paired moves (note: only paired moves can access XDn regs) (FE) - "pref @%[dest_base]\n\t" // Get a head start prefetching the second half of the 64-byte data (LS) - "fmov.d XD0, @-%[out_mtrx]\n\t" // These do *(--output) = XDn (LS) - "fmov.d XD2, @-%[out_mtrx]\n\t" - "fmov.d XD4, @-%[out_mtrx]\n\t" - "fmov.d XD6, @-%[out_mtrx]\n\t" - "fmov.d XD8, @-%[out_mtrx]\n\t" - "fmov.d XD10, @-%[out_mtrx]\n\t" - "fmov.d XD12, @-%[out_mtrx]\n\t" - "fmov.d XD14, @-%[out_mtrx]\n\t" - "fschg\n" // switch back to single moves - : [out_mtrx] "+&r" ((unsigned int)output) // outputs, "+" means r/w, "&" means it's written to before all inputs are consumed - : [dest_base] "r" ((unsigned int)destination) // inputs - : "memory" // clobbers - ); - - return destination; -} - -// Returns FV0, 4, 8, or 12 from XMTRX -// -// Sorry, it has to be done 4 at a time like this due to calling convention -// limits; under optimal optimization conditions, we only get 4 float registers -// for return values; any more and they get pushed to memory. -// -// IMPORTANT USAGE INFORMATION (get XMTRX vector) -// -// XMTRX format, using the front bank's FVn notation: -// -// FV0 FV4 FV8 FV12 -// --- --- --- ---- -// [ xf0 xf4 xf8 xf12 ] -// [ xf1 xf5 xf9 xf13 ] -// [ xf2 xf6 xf10 xf14 ] -// [ xf3 xf7 xf11 xf15 ] -// -// Return vector maps to XMTRX as below depending on the FVn value passed in: -// -// typedef struct { -// float z1; // will contain xf0, 4, 8 or 12 -// float z2; // will contain xf1, 5, 9, or 13 -// float z3; // will contain xf2, 6, 10, or 14 -// float z4; // will contain xf3, 7, 11, or 15 -// } RETURN_VECTOR_STRUCT; -// -// Valid values of 'which' are 0, 4, 8, or 12, corresponding to FV0, FV4, FV8, -// or FV12, respectively. Other values will return 0 in all four return values. -static inline __attribute__((always_inline)) RETURN_VECTOR_STRUCT MATH_Get_XMTRX_Vector(unsigned int which) -{ - register float __z1 __asm__("fr0"); - register float __z2 __asm__("fr1"); - register float __z3 __asm__("fr2"); - register float __z4 __asm__("fr3"); - - // Note: only paired moves can access XDn regs - asm volatile ("cmp/eq #0, %[select]\n\t" // if(which == 0), 1 -> T else 0 -> T - "bt.s 0f\n\t" // do FV0 - " cmp/eq #4, %[select]\n\t" // if(which == 4), 1 -> T else 0 -> T - "bt.s 4f\n\t" // do FV4 - " cmp/eq #8, %[select]\n\t" // if(which == 8), 1 -> T else 0 -> T - "bt.s 8f\n\t" // do FV8 - " cmp/eq #12, %[select]\n\t" // if(which == 12), 1 -> T else 0 -> T - "bf.s 1f\n" // exit if not even FV12 was true, otherwise do FV12 - "12:\n\t" - " fschg\n\t" // paired moves for FV12 (and exit case) - "fmov XD14, DR2\n\t" - "fmov XD12, DR0\n\t" - "bt.s 2f\n" // done - "8:\n\t" - " fschg\n\t" // paired moves for FV8, back to singles for FV12 - "fmov XD10, DR2\n\t" - "fmov XD8, DR0\n\t" - "bf.s 2f\n" // done - "4:\n\t" - " fschg\n\t" // paired moves for FV4, back to singles for FV8 - "fmov XD6, DR2\n\t" - "fmov XD4, DR0\n\t" - "bf.s 2f\n" // done - "0:\n\t" - " fschg\n\t" // paired moves for FV0, back to singles for FV4 - "fmov XD2, DR2\n\t" - "fmov XD0, DR0\n\t" - "bf.s 2f\n" // done - "1:\n\t" - " fschg\n\t" // back to singles for FV0 and exit case - "fldi0 FR0\n\t" // FR0-3 get zeroed out, then - "fmov FR0, FR1\n\t" - "fmov FR0, FR2\n\t" - "fmov FR0, FR3\n" - "2:\n" - : "=w" (__z1), "=f" (__z2), "=f" (__z3), "=f" (__z4) // outputs - : [select] "z" (which) // inputs - : "t" // clobbers - ); - - RETURN_VECTOR_STRUCT output = {__z1, __z2, __z3, __z4}; - return output; -} - -// Returns a 2x2 matrix from a quadrant of XMTRX -// -// Sorry, it has to be done 4 at a time like this due to calling convention -// limits; under optimal optimization conditions, we only get 4 float registers -// for return values; any more and they get pushed to memory. -// -// IMPORTANT USAGE INFORMATION (get XMTRX 2x2) -// -// Each 2x2 quadrant is of the form: -// -// [ a b ] -// [ c d ] -// -// Return vector maps to the 2x2 matrix as below: -// -// typedef struct { -// float z1; // a -// float z2; // c -// float z3; // b -// float z4; // d -// } RETURN_VECTOR_STRUCT; -// -// (So the function does a 2x2 transpose in storing the values relative to the -// order stored in XMTRX.) -// -// Valid values of 'which' are 1, 2, 3, or 4, corresponding to the following -// quadrants of XMTRX: -// -// 1 2 -// [ xf0 xf4 ] | [ xf8 xf12 ] -// [ xf1 xf5 ] | [ xf9 xf13 ] -// -- 3 -- | -- 4 -- -// [ xf2 xf6 ] | [ xf10 xf14 ] -// [ xf3 xf7 ] | [ xf11 xf15 ] -// -// Other input values will return 0 in all four return floats. -static inline __attribute__((always_inline)) RETURN_VECTOR_STRUCT MATH_Get_XMTRX_2x2(unsigned int which) -{ - register float __z1 __asm__("fr0"); - register float __z2 __asm__("fr1"); - register float __z3 __asm__("fr2"); - register float __z4 __asm__("fr3"); - - // Note: only paired moves can access XDn regs - asm volatile ("cmp/eq #1, %[select]\n\t" // if(which == 1), 1 -> T else 0 -> T - "bt.s 1f\n\t" // do quadrant 1 - " cmp/eq #2, %[select]\n\t" // if(which == 2), 1 -> T else 0 -> T - "bt.s 2f\n\t" // do quadrant 2 - " cmp/eq #3, %[select]\n\t" // if(which == 3), 1 -> T else 0 -> T - "bt.s 3f\n\t" // do quadrant 3 - " cmp/eq #4, %[select]\n\t" // if(which == 4), 1 -> T else 0 -> T - "bf.s 0f\n" // exit if nothing was true, otherwise do quadrant 4 - "4:\n\t" - " fschg\n\t" // paired moves for quadrant 4 (and exit case) - "fmov XD14, DR2\n\t" - "fmov XD10, DR0\n\t" - "bt.s 5f\n" // done - "3:\n\t" - " fschg\n\t" // paired moves for quadrant 3, back to singles for 4 - "fmov XD6, DR2\n\t" - "fmov XD2, DR0\n\t" - "bf.s 5f\n" // done - "2:\n\t" - " fschg\n\t" // paired moves for quadrant 2, back to singles for 3 - "fmov XD12, DR2\n\t" - "fmov XD8, DR0\n\t" - "bf.s 5f\n" // done - "1:\n\t" - " fschg\n\t" // paired moves for quadrant 1, back to singles for 2 - "fmov XD4, DR2\n\t" - "fmov XD0, DR0\n\t" - "bf.s 5f\n" // done - "0:\n\t" - " fschg\n\t" // back to singles for quadrant 1 and exit case - "fldi0 FR0\n\t" // FR0-3 get zeroed out, then - "fmov FR0, FR1\n\t" - "fmov FR0, FR2\n\t" - "fmov FR0, FR3\n" - "5:\n" - : "=w" (__z1), "=f" (__z2), "=f" (__z3), "=f" (__z4) // outputs - : [select] "z" (which) // inputs - : "t" // clobbers - ); - - RETURN_VECTOR_STRUCT output = {__z1, __z2, __z3, __z4}; - return output; -} - -// It is not possible to return an entire 4x4 matrix in registers, as the only -// registers allowed for return values are R0-R3 and FR0-FR3. All others are -// marked caller save, which means they could be restored from stack and clobber -// anything returned in them. -// -// In general, writing the entire required math routine in one asm function is -// the best way to go for performance reasons anyways, and in that situation one -// can just throw calling convention to the wind until returning back to C. - -//============================================================================== -// Miscellaneous Functions -//============================================================================== -// -// The following functions are provided as examples of ways in which these math -// functions can be used. -// -// Reminder: 1 fsca unit = 1/182.044444444 of a degree or 1/10430.3783505 of a radian -// In order to make the best use of fsca units, a program must expect them from -// the outset and not "make them" by dividing radians or degrees to get them, -// otherwise it's just giving the 'fsca' instruction radians or degrees! -// -/* - - //------------------------------------------------------------------------------ - // Commonly useful functions - //------------------------------------------------------------------------------ - - // Returns 1 if point 't' is inside triangle with vertices 'v0', 'v1', and 'v2', and 0 if not - int MATH_Is_Point_In_Triangle(float v0x, float v0y, float v1x, float v1y, float v2x, float v2y, float ptx, float pty) - - //------------------------------------------------------------------------------ - // Interpolation - //------------------------------------------------------------------------------ - - // Linear interpolation - float MATH_Lerp(float a, float b, float t) - - // Speherical interpolation ('theta' in fsca units) - float MATH_Slerp(float a, float b, float t, float theta) - - //------------------------------------------------------------------------------ - // Fast Sinc functions (unnormalized, sin(x)/x version) - //------------------------------------------------------------------------------ - // Just pass in MATH_pi * x for normalized versions :) - - // Sinc function (fsca units) - float MATH_Fast_Sincf(float x) - - // Sinc function (degrees) - float MATH_Fast_Sincf_Deg(float x) - - // Sinc function (rads) - float MATH_Fast_Sincf_Rad(float x) - - //------------------------------------------------------------------------------ - // Kaiser Window - //------------------------------------------------------------------------------ - - // Generates mipmaps. Angle 'x' in radians. - float MATH_Kaiser_Window_Rad(float x, float alpha, float stretch, float m_width) - - // Generates mipmaps. Angle 'x' in fsca units. - float MATH_Kaiser_Window(float x, float alpha, float stretch, float m_width) - -*/ - -//------------------------------------------------------------------------------ -// Commonly useful functions -//------------------------------------------------------------------------------ - -// Returns 1 if point 'pt' is inside triangle with vertices 'v0', 'v1', and 'v2', and 0 if not -// Determines triangle center using barycentric coordinate transformation -// Adapted from: https://stackoverflow.com/questions/2049582/how-to-determine-if-a-point-is-in-a-2d-triangle -// Specifically the answer by user 'adreasdr' in addition to the comment by user 'urraka' on the answer from user 'Andreas Brinck' -// -// The notation here assumes v0x is the x-component of v0, v0y is the y-component of v0, etc. -// -static inline __attribute__((always_inline)) int MATH_Is_Point_In_Triangle(float v0x, float v0y, float v1x, float v1y, float v2x, float v2y, float ptx, float pty) -{ - float sdot = MATH_fipr(v0y, -v0x, v2y - v0y, v0x - v2x, v2x, v2y, ptx, pty); - float tdot = MATH_fipr(v0x, -v0y, v0y - v1y, v1x - v0x, v1y, v1x, ptx, pty); - - float areadot = MATH_fipr(-v1y, v0y, v0x, v1x, v2x, -v1x + v2x, v1y - v2y, v2y); - - // 'areadot' could be negative depending on the winding of the triangle - if(areadot < 0.0f) - { - sdot *= -1.0f; - tdot *= -1.0f; - areadot *= -1.0f; - } - - if( (sdot > 0.0f) && (tdot > 0.0f) && (areadot > (sdot + tdot)) ) - { - return 1; - } - - return 0; -} - -//------------------------------------------------------------------------------ -// Interpolation -//------------------------------------------------------------------------------ - -// Linear interpolation -static inline __attribute__((always_inline)) float MATH_Lerp(float a, float b, float t) -{ - return MATH_fmac(t, (b-a), a); -} - -// Speherical interpolation ('theta' in fsca units) -static inline __attribute__((always_inline)) float MATH_Slerp(float a, float b, float t, float theta) -{ - // a is an element of v0, b is an element of v1 - // v = ( v0 * sin(theta - t * theta) + v1 * sin(t * theta) ) / sin(theta) - // by using sine/cosine identities and properties, this can be optimized to: - // v = v0 * cos(-t * theta) + ( v0 * ( cos(theta) * sin(-t * theta) ) - sin(-t * theta) * v1 ) / sin(theta) - // which only requires two calls to fsca. - // Specifically, sin(a + b) = sin(a)cos(b) + cos(a)sin(b) & sin(-a) = -sin(a) - - // MATH_fsca_* functions return reverse-ordered complex numbers for speed reasons (i.e. normally sine is the imaginary part) - // This could be made even faster by using MATH_fsca_Int() with 'theta' and 't' as unsigned ints - -#if __GNUC__ <= GNUC_FSCA_ERROR_VERSION - - RETURN_FSCA_STRUCT sine_cosine = MATH_fsca_Float(theta); - float sine_value_theta = sine_cosine.sine; - float cosine_value_theta = sine_cosine.cosine; - - RETURN_FSCA_STRUCT sine_cosine2 = MATH_fsca_Float(-t * theta); - float sine_value_minus_t_theta = sine_cosine2.sine; - float cosine_value_minus_t_theta = sine_cosine2.cosine; - -#else - - _Complex float sine_cosine = MATH_fsca_Float(theta); - float sine_value_theta = __real__ sine_cosine; - float cosine_value_theta = __imag__ sine_cosine; - - _Complex float sine_cosine2 = MATH_fsca_Float(-t * theta); - float sine_value_minus_t_theta = __real__ sine_cosine2; - float cosine_value_minus_t_theta = __imag__ sine_cosine2; - -#endif - - float numer = a * cosine_value_theta * sine_value_minus_t_theta - sine_value_minus_t_theta * b; - float output_float = a * cosine_value_minus_t_theta + MATH_Fast_Divide(numer, sine_value_theta); - - return output_float; -} - -//------------------------------------------------------------------------------ -// Fast Sinc (unnormalized, sin(x)/x version) -//------------------------------------------------------------------------------ -// -// Just pass in MATH_pi * x for normalized versions :) -// - -// Sinc function (fsca units) -static inline __attribute__((always_inline)) float MATH_Fast_Sincf(float x) -{ - if(x == 0.0f) - { - return 1.0f; - } - -#if __GNUC__ <= GNUC_FSCA_ERROR_VERSION - - RETURN_FSCA_STRUCT sine_cosine = MATH_fsca_Float(x); - float sine_value = sine_cosine.sine; - -#else - - _Complex float sine_cosine = MATH_fsca_Float(x); - float sine_value = __real__ sine_cosine; - -#endif - - return MATH_Fast_Divide(sine_value, x); -} - -// Sinc function (degrees) -static inline __attribute__((always_inline)) float MATH_Fast_Sincf_Deg(float x) -{ - if(x == 0.0f) - { - return 1.0f; - } - -#if __GNUC__ <= GNUC_FSCA_ERROR_VERSION - - RETURN_FSCA_STRUCT sine_cosine = MATH_fsca_Float_Deg(x); - float sine_value = sine_cosine.sine; - -#else - - _Complex float sine_cosine = MATH_fsca_Float_Deg(x); - float sine_value = __real__ sine_cosine; - -#endif - - return MATH_Fast_Divide(sine_value, x); -} - -// Sinc function (rads) -static inline __attribute__((always_inline)) float MATH_Fast_Sincf_Rad(float x) -{ - if(x == 0.0f) - { - return 1.0f; - } - -#if __GNUC__ <= GNUC_FSCA_ERROR_VERSION - - RETURN_FSCA_STRUCT sine_cosine = MATH_fsca_Float_Rad(x); - float sine_value = sine_cosine.sine; - -#else - - _Complex float sine_cosine = MATH_fsca_Float_Rad(x); - float sine_value = __real__ sine_cosine; - -#endif - - return MATH_Fast_Divide(sine_value, x); -} - -//------------------------------------------------------------------------------ -// Kaiser Window -//------------------------------------------------------------------------------ -// -// These use regular divides because they only need to be run once during loads, -// not during runtime. -// -// Adapted from public domain NVidia Filter.cpp: -// https://github.com/castano/nvidia-texture-tools/blob/master/src/nvimage/Filter.cpp -// (as of 3/23/2020) -// - -// -// Kaiser window utility functions -// - -// Utility function for 0th-order bessel function -static inline __attribute__((always_inline)) float MATH_Bessel0(float x) -{ - const float EPSILON_RATIO = 1e-6f; - float xh, sum, power, ds, k; - // int k; - - xh = 0.5f * x; - sum = 1.0f; - power = 1.0f; - k = 0.0f; // k = 0; - ds = 1.0; - while (ds > (sum * EPSILON_RATIO)) - { - k += 1.0f; // ++k; - power = power * (xh / k); - ds = power * power; - sum = sum + ds; - } - - return sum; -} - -// Utility for kaiser window's expected sincf() format (radians) -static inline __attribute__((always_inline)) float MATH_NV_Sincf_Rad(const float x) -{ - // Does SH4 need this correction term? x86's sinf() definitely does, - // but SH4 might be ok with if(x == 0.0f) return 1.0f; Not sure. - if (MATH_fabs(x) < 0.0001f) // NV_EPSILON is 0.0001f - { - return 1.0f + x*x*(-1.0f/6.0f + (x*x)/120.0f); // 1.0 + x^2 * (-1/6 + x^2/120) - } - else - { - -#if __GNUC__ <= GNUC_FSCA_ERROR_VERSION - - RETURN_FSCA_STRUCT sine_cosine = MATH_fsca_Float_Rad(x); - float sine_value = sine_cosine.sine; - -#else - - _Complex float sine_cosine = MATH_fsca_Float_Rad(x); - float sine_value = __real__ sine_cosine; - -#endif - - return sine_value / x; - } -} - -// Utility for kaiser window's expected sincf() format (fsca units) -static inline __attribute__((always_inline)) float MATH_NV_Sincf(const float x) -{ - // Does SH4 need this correction term? x86's sinf() definitely does, - // but SH4 might be ok with if(x == 0.0f) return 1.0f; Not sure. - if (MATH_fabs(x) < 0.0001f) // NV_EPSILON is 0.0001f - { - return 1.0f + x*x*(-1.0f/6.0f + (x*x)/120.0f); // 1.0 + x^2 * (-1/6 + x^2/120) - } - else - { - -#if __GNUC__ <= GNUC_FSCA_ERROR_VERSION - - RETURN_FSCA_STRUCT sine_cosine = MATH_fsca_Float(x); - float sine_value = sine_cosine.sine; - -#else - - _Complex float sine_cosine = MATH_fsca_Float(x); - float sine_value = __real__ sine_cosine; - -#endif - - return sine_value / x; - } -} - -// -// Kaiser window mipmap generator main functions -// - -// Generates mipmaps. Angle 'x' in radians. -static inline __attribute__((always_inline)) float MATH_Kaiser_Window_Rad(float x, float alpha, float stretch, float m_width) -{ - const float sinc_value = MATH_NV_Sincf_Rad(MATH_pi * x * stretch); - const float t = x / m_width; - - if ((1 - t * t) >= 0) - { - return sinc_value * MATH_Bessel0(alpha * MATH_fsqrt(1 - t * t)) / MATH_Bessel0(alpha); - } - else - { - return 0; - } -} - -// Generates mipmaps. Angle 'x' in fsca units. -static inline __attribute__((always_inline)) float MATH_Kaiser_Window(float x, float alpha, float stretch, float m_width) -{ - const float sinc_value = MATH_NV_Sincf(MATH_pi * x * stretch); - const float t = x / m_width; - - if ((1 - t * t) >= 0) - { - return sinc_value * MATH_Bessel0(alpha * MATH_fsqrt(1 - t * t)) / MATH_Bessel0(alpha); - } - else - { - return 0; - } -} - -//============================================================================== -// Miscellaneous Snippets -//============================================================================== -// -// The following snippets are best implemented manually in user code (they can't -// be put into their own functions without incurring performance penalties). -// -// They also serve as examples of how one might use the functions in this header. -// -/* - Normalize a vector (x, y, z) and get its pre-normalized magnitude (length) -*/ - -// -// Normalize a vector (x, y, z) and get its pre-normalized magnitude (length) -// -// magnitude = sqrt(x^2 + y^2 + z^2) -// (x, y, z) = 1/magnitude * (x, y, z) -// -// x, y, z, and magnitude are assumed already existing floats -// - -/* -- start -- - - // Don't need an 'else' with this (if length is 0, x = y = z = 0) - magnitude = 0; - - if(__builtin_expect(x || y || z, 1)) - { - temp = MATH_Sum_of_Squares(x, y, z, 0); // temp = x^2 + y^2 + z^2 + 0^2 - float normalizer = MATH_fsrra(temp); // 1/sqrt(temp) - x = normalizer * x; - y = normalizer * y; - z = normalizer * z; - magnitude = MATH_Fast_Invert(normalizer); - } - --- end -- */ - - -#endif /* __SH4_MATH_H_ */ - diff --git a/GL/platforms/software.h b/GL/platforms/software.h index 5fee317..fbe12be 100644 --- a/GL/platforms/software.h +++ b/GL/platforms/software.h @@ -7,9 +7,6 @@ #define PREFETCH(addr) do {} while(0) -#define MATH_Fast_Divide(n, d) (n / d) -#define MATH_fmac(a, b, c) (a * b + c) -#define MATH_Fast_Sqrt(x) sqrtf((x)) #define MATH_fsrra(x) (1.0f / sqrtf((x))) #define MATH_Fast_Invert(x) (1.0f / (x)) From 3b4b1b6975bf32e849010f378fe3bfcfacf66a75 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sat, 1 Feb 2025 14:00:49 +1100 Subject: [PATCH 56/72] Fix compile error --- GL/platforms/sh4.h | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/GL/platforms/sh4.h b/GL/platforms/sh4.h index 336cd9e..63e7081 100644 --- a/GL/platforms/sh4.h +++ b/GL/platforms/sh4.h @@ -10,6 +10,19 @@ #include "../types.h" #include "../private.h" +#ifndef NDEBUG +#define PERF_WARNING(msg) printf("[PERF] %s\n", msg) +#else +#define PERF_WARNING(msg) (void) 0 +#endif + +#ifndef GL_FORCE_INLINE +#define GL_NO_INSTRUMENT inline __attribute__((no_instrument_function)) +#define GL_INLINE_DEBUG GL_NO_INSTRUMENT __attribute__((always_inline)) +#define GL_FORCE_INLINE static GL_INLINE_DEBUG +#endif + + // ---- sh4_math.h - SH7091 Math Module ---- // // This file is part of the DreamHAL project, a hardware abstraction library @@ -45,19 +58,6 @@ GL_FORCE_INLINE float MATH_Fast_Invert(float x) } // end of ---- sh4_math.h ---- - -#ifndef NDEBUG -#define PERF_WARNING(msg) printf("[PERF] %s\n", msg) -#else -#define PERF_WARNING(msg) (void) 0 -#endif - -#ifndef GL_FORCE_INLINE -#define GL_NO_INSTRUMENT inline __attribute__((no_instrument_function)) -#define GL_INLINE_DEBUG GL_NO_INSTRUMENT __attribute__((always_inline)) -#define GL_FORCE_INLINE static GL_INLINE_DEBUG -#endif - #define PREFETCH(addr) __builtin_prefetch((addr)) GL_FORCE_INLINE void* memcpy_fast(void *dest, const void *src, size_t len) { From bdecf90d6406e0b1c08de87c19de8f04ba97eeb8 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sat, 1 Feb 2025 15:38:59 +1100 Subject: [PATCH 57/72] Calculate read attribute functions when attribute states changes, instead of at every draw call --- CMakeLists.txt | 1 + GL/attributes.c | 567 ++++++++++++++++++++++++++++++++++++++++++ GL/draw.c | 637 +++--------------------------------------------- GL/private.h | 22 +- 4 files changed, 611 insertions(+), 616 deletions(-) create mode 100644 GL/attributes.c diff --git a/CMakeLists.txt b/CMakeLists.txt index e51c14d..e416cdd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -68,6 +68,7 @@ set( containers/aligned_vector.c containers/named_array.c containers/stack.c + GL/attributes.c GL/draw.c GL/error.c GL/flush.c diff --git a/GL/attributes.c b/GL/attributes.c new file mode 100644 index 0000000..4ed6ca3 --- /dev/null +++ b/GL/attributes.c @@ -0,0 +1,567 @@ +#include +#include +#include +#include +#include +#include + +#include "private.h" +#include "platform.h" + + +AttribPointerList ATTRIB_POINTERS; +GLuint ENABLED_VERTEX_ATTRIBUTES = 0; + +static const float ONE_OVER_TWO_FIVE_FIVE = 1.0f / 255.0f; + +extern inline GLuint _glRecalcFastPath(); + +GL_FORCE_INLINE GLsizei byte_size(GLenum type) { + switch(type) { + case GL_BYTE: return sizeof(GLbyte); + case GL_UNSIGNED_BYTE: return sizeof(GLubyte); + case GL_SHORT: return sizeof(GLshort); + case GL_UNSIGNED_SHORT: return sizeof(GLushort); + case GL_INT: return sizeof(GLint); + case GL_UNSIGNED_INT: return sizeof(GLuint); + case GL_DOUBLE: return sizeof(GLdouble); + case GL_UNSIGNED_INT_2_10_10_10_REV: return sizeof(GLuint); + case GL_FLOAT: + default: return sizeof(GLfloat); + } +} + +static void _readVertexData3f3f(const GLubyte* __restrict__ in, GLubyte* __restrict__ out) { + vec3cpy(out, in); +} + +// 10:10:10:2REV format +static void _readVertexData1i3f(const GLubyte* in, GLubyte* out) { + static const float MULTIPLIER = 1.0f / 1023.0f; + + GLfloat* output = (GLfloat*) out; + + union { + int value; + struct { + signed int x: 10; + signed int y: 10; + signed int z: 10; + signed int w: 2; + } bits; + } input; + + input.value = *((const GLint*) in); + + output[0] = (2.0f * (float) input.bits.x + 1.0f) * MULTIPLIER; + output[1] = (2.0f * (float) input.bits.y + 1.0f) * MULTIPLIER; + output[2] = (2.0f * (float) input.bits.z + 1.0f) * MULTIPLIER; +} + +static void _readVertexData3us3f(const GLubyte* in, GLubyte* out) { + const GLushort* input = (const GLushort*) in; + float* output = (float*) out; + + output[0] = input[0]; + output[1] = input[1]; + output[2] = input[2]; +} + +static void _readVertexData3ui3f(const GLubyte* in, GLubyte* out) { + const GLuint* input = (const GLuint*) in; + float* output = (float*) out; + + output[0] = input[0]; + output[1] = input[1]; + output[2] = input[2]; +} + + +static void _readVertexData3ub3f(const GLubyte* input, GLubyte* out) { + float* output = (float*) out; + + output[0] = input[0] * ONE_OVER_TWO_FIVE_FIVE; + output[1] = input[1] * ONE_OVER_TWO_FIVE_FIVE; + output[2] = input[2] * ONE_OVER_TWO_FIVE_FIVE; +} + +static void _readVertexData2f2f(const GLubyte* in, GLubyte* out) { + vec2cpy(out, in); +} + +static void _readVertexData2f3f(const GLubyte* in, GLubyte* out) { + const float* input = (const float*) in; + float* output = (float*) out; + + vec2cpy(output, input); + output[2] = 0.0f; +} + +static void _readVertexData2ub3f(const GLubyte* input, GLubyte* out) { + float* output = (float*) out; + + output[0] = input[0] * ONE_OVER_TWO_FIVE_FIVE; + output[1] = input[1] * ONE_OVER_TWO_FIVE_FIVE; + output[2] = 0.0f; +} + +static void _readVertexData2us3f(const GLubyte* in, GLubyte* out) { + const GLushort* input = (const GLushort*) in; + float* output = (float*) out; + + output[0] = input[0]; + output[1] = input[1]; + output[2] = 0.0f; +} + +static void _readVertexData2us2f(const GLubyte* in, GLubyte* out) { + const GLushort* input = (const GLushort*) in; + float* output = (float*) out; + + output[0] = (float)input[0] / SHRT_MAX; + output[1] = (float)input[1] / SHRT_MAX; +} + +static void _readVertexData2ui2f(const GLubyte* in, GLubyte* out) { + const GLuint* input = (const GLuint*) in; + float* output = (float*) out; + + output[0] = input[0]; + output[1] = input[1]; +} + +static void _readVertexData2ub2f(const GLubyte* input, GLubyte* out) { + float* output = (float*) out; + + output[0] = input[0] * ONE_OVER_TWO_FIVE_FIVE; + output[1] = input[1] * ONE_OVER_TWO_FIVE_FIVE; +} + +static void _readVertexData2ui3f(const GLubyte* in, GLubyte* out) { + const GLuint* input = (const GLuint*) in; + float* output = (float*) out; + + output[0] = input[0]; + output[1] = input[1]; + output[2] = 0.0f; +} + +static void _readVertexData4ubARGB(const GLubyte* input, GLubyte* output) { + output[R8IDX] = input[0]; + output[G8IDX] = input[1]; + output[B8IDX] = input[2]; + output[A8IDX] = input[3]; +} + +static void _readVertexData4fARGB(const GLubyte* in, GLubyte* output) { + const float* input = (const float*) in; + + output[R8IDX] = (GLubyte) clamp(input[0] * 255.0f, 0, 255); + output[G8IDX] = (GLubyte) clamp(input[1] * 255.0f, 0, 255); + output[B8IDX] = (GLubyte) clamp(input[2] * 255.0f, 0, 255); + output[A8IDX] = (GLubyte) clamp(input[3] * 255.0f, 0, 255); +} + +static void _readVertexData3fARGB(const GLubyte* in, GLubyte* output) { + const float* input = (const float*) in; + + output[R8IDX] = (GLubyte) clamp(input[0] * 255.0f, 0, 255); + output[G8IDX] = (GLubyte) clamp(input[1] * 255.0f, 0, 255); + output[B8IDX] = (GLubyte) clamp(input[2] * 255.0f, 0, 255); + output[A8IDX] = 255; +} + +static void _readVertexData3ubARGB(const GLubyte* __restrict__ input, GLubyte* __restrict__ output) { + output[R8IDX] = input[0]; + output[G8IDX] = input[1]; + output[B8IDX] = input[2]; + output[A8IDX] = 255; +} + +static void _readVertexData4ubRevARGB(const GLubyte* __restrict__ input, GLubyte* __restrict__ output) { + argbcpy(output, input); +} + +static void _readVertexData4fRevARGB(const GLubyte* __restrict__ in, GLubyte* __restrict__ output) { + const float* input = (const float*) in; + + output[0] = (GLubyte) clamp(input[0] * 255.0f, 0, 255); + output[1] = (GLubyte) clamp(input[1] * 255.0f, 0, 255); + output[2] = (GLubyte) clamp(input[2] * 255.0f, 0, 255); + output[3] = (GLubyte) clamp(input[3] * 255.0f, 0, 255); +} + +static void _fillWithNegZVE(const GLubyte* __restrict__ input, GLubyte* __restrict__ out) { + _GL_UNUSED(input); + + typedef struct { + float x, y, z; + } V; + + static const V NegZ = {0.0f, 0.0f, -1.0f}; + + *((V*) out) = NegZ; +} + +static void _fillWhiteARGB(const GLubyte* __restrict__ input, GLubyte* __restrict__ output) { + _GL_UNUSED(input); + *((uint32_t*) output) = ~0; +} + +static void _fillZero2f(const GLubyte* __restrict__ input, GLubyte* __restrict__ out) { + _GL_UNUSED(input); + memset(out, 0, sizeof(float) * 2); +} + +static void _readVertexData3usARGB(const GLubyte* input, GLubyte* output) { + _GL_UNUSED(input); + _GL_UNUSED(output); + gl_assert(0 && "Not Implemented"); +} + +static void _readVertexData3uiARGB(const GLubyte* input, GLubyte* output) { + _GL_UNUSED(input); + _GL_UNUSED(output); + gl_assert(0 && "Not Implemented"); +} + +static void _readVertexData4usARGB(const GLubyte* input, GLubyte* output) { + _GL_UNUSED(input); + _GL_UNUSED(output); + gl_assert(0 && "Not Implemented"); +} + +static void _readVertexData4uiARGB(const GLubyte* input, GLubyte* output) { + _GL_UNUSED(input); + _GL_UNUSED(output); + gl_assert(0 && "Not Implemented"); +} + +static void _readVertexData4usRevARGB(const GLubyte* input, GLubyte* output) { + _GL_UNUSED(input); + _GL_UNUSED(output); + gl_assert(0 && "Not Implemented"); +} + +static void _readVertexData4uiRevARGB(const GLubyte* input, GLubyte* output) { + _GL_UNUSED(input); + _GL_UNUSED(output); + gl_assert(0 && "Not Implemented"); +} + +static ReadAttributeFunc calcReadDiffuseFunc() { + if((ENABLED_VERTEX_ATTRIBUTES & DIFFUSE_ENABLED_FLAG) != DIFFUSE_ENABLED_FLAG) { + /* Just fill the whole thing white if the attribute is disabled */ + return _fillWhiteARGB; + } + + switch(ATTRIB_POINTERS.colour.type) { + default: + case GL_DOUBLE: + case GL_FLOAT: + return (ATTRIB_POINTERS.colour.size == 3) ? _readVertexData3fARGB: + (ATTRIB_POINTERS.colour.size == 4) ? _readVertexData4fARGB: + _readVertexData4fRevARGB; + case GL_BYTE: + case GL_UNSIGNED_BYTE: + return (ATTRIB_POINTERS.colour.size == 3) ? _readVertexData3ubARGB: + (ATTRIB_POINTERS.colour.size == 4) ? _readVertexData4ubARGB: + _readVertexData4ubRevARGB; + case GL_SHORT: + case GL_UNSIGNED_SHORT: + return (ATTRIB_POINTERS.colour.size == 3) ? _readVertexData3usARGB: + (ATTRIB_POINTERS.colour.size == 4) ? _readVertexData4usARGB: + _readVertexData4usRevARGB; + case GL_INT: + case GL_UNSIGNED_INT: + return (ATTRIB_POINTERS.colour.size == 3) ? _readVertexData3uiARGB: + (ATTRIB_POINTERS.colour.size == 4) ? _readVertexData4uiARGB: + _readVertexData4uiRevARGB; + } +} + +static ReadAttributeFunc calcReadPositionFunc() { + switch(ATTRIB_POINTERS.vertex.type) { + default: + case GL_DOUBLE: + case GL_FLOAT: + return (ATTRIB_POINTERS.vertex.size == 3) ? _readVertexData3f3f: + _readVertexData2f3f; + case GL_BYTE: + case GL_UNSIGNED_BYTE: + return (ATTRIB_POINTERS.vertex.size == 3) ? _readVertexData3ub3f: + _readVertexData2ub3f; + case GL_SHORT: + case GL_UNSIGNED_SHORT: + return (ATTRIB_POINTERS.vertex.size == 3) ? _readVertexData3us3f: + _readVertexData2us3f; + case GL_INT: + case GL_UNSIGNED_INT: + return (ATTRIB_POINTERS.vertex.size == 3) ? _readVertexData3ui3f: + _readVertexData2ui3f; + } +} + +static ReadAttributeFunc calcReadUVFunc() { + if((ENABLED_VERTEX_ATTRIBUTES & UV_ENABLED_FLAG) != UV_ENABLED_FLAG) { + return _fillZero2f; + } + + switch(ATTRIB_POINTERS.uv.type) { + default: + case GL_DOUBLE: + case GL_FLOAT: + return _readVertexData2f2f; + case GL_BYTE: + case GL_UNSIGNED_BYTE: + return _readVertexData2ub2f; + case GL_SHORT: + case GL_UNSIGNED_SHORT: + return _readVertexData2us2f; + case GL_INT: + case GL_UNSIGNED_INT: + return _readVertexData2ui2f; + } +} + +static ReadAttributeFunc calcReadSTFunc() { + if((ENABLED_VERTEX_ATTRIBUTES & ST_ENABLED_FLAG) != ST_ENABLED_FLAG) { + return _fillZero2f; + } + + switch(ATTRIB_POINTERS.st.type) { + default: + case GL_DOUBLE: + case GL_FLOAT: + return _readVertexData2f2f; + case GL_BYTE: + case GL_UNSIGNED_BYTE: + return _readVertexData2ub2f; + case GL_SHORT: + case GL_UNSIGNED_SHORT: + return _readVertexData2us2f; + case GL_INT: + case GL_UNSIGNED_INT: + return _readVertexData2ui2f; + } +} + +static ReadAttributeFunc calcReadNormalFunc() { + if((ENABLED_VERTEX_ATTRIBUTES & NORMAL_ENABLED_FLAG) != NORMAL_ENABLED_FLAG) { + return _fillWithNegZVE; + } + + switch(ATTRIB_POINTERS.normal.type) { + default: + case GL_DOUBLE: + case GL_FLOAT: + return _readVertexData3f3f; + break; + case GL_BYTE: + case GL_UNSIGNED_BYTE: + return _readVertexData3ub3f; + break; + case GL_SHORT: + case GL_UNSIGNED_SHORT: + return _readVertexData3us3f; + break; + case GL_INT: + case GL_UNSIGNED_INT: + return _readVertexData3ui3f; + break; + case GL_UNSIGNED_INT_2_10_10_10_REV: + return _readVertexData1i3f; + break; + } +} + +void APIENTRY glEnableClientState(GLenum cap) { + TRACE(); + + switch(cap) { + case GL_VERTEX_ARRAY: + ENABLED_VERTEX_ATTRIBUTES |= VERTEX_ENABLED_FLAG; + break; + case GL_COLOR_ARRAY: + ENABLED_VERTEX_ATTRIBUTES |= DIFFUSE_ENABLED_FLAG; + break; + case GL_NORMAL_ARRAY: + ENABLED_VERTEX_ATTRIBUTES |= NORMAL_ENABLED_FLAG; + break; + case GL_TEXTURE_COORD_ARRAY: + (ACTIVE_CLIENT_TEXTURE) ? + (ENABLED_VERTEX_ATTRIBUTES |= ST_ENABLED_FLAG): + (ENABLED_VERTEX_ATTRIBUTES |= UV_ENABLED_FLAG); + break; + default: + _glKosThrowError(GL_INVALID_ENUM, __func__); + } + + /* It's possible that we called glVertexPointer and friends before + * calling glEnableClientState, so we should recheck to make sure + * everything is in the right format with this new information */ + _glRecalcFastPath(); +} + +void APIENTRY glDisableClientState(GLenum cap) { + TRACE(); + + switch(cap) { + case GL_VERTEX_ARRAY: + ENABLED_VERTEX_ATTRIBUTES &= ~VERTEX_ENABLED_FLAG; + break; + case GL_COLOR_ARRAY: + ENABLED_VERTEX_ATTRIBUTES &= ~DIFFUSE_ENABLED_FLAG; + break; + case GL_NORMAL_ARRAY: + ENABLED_VERTEX_ATTRIBUTES &= ~NORMAL_ENABLED_FLAG; + break; + case GL_TEXTURE_COORD_ARRAY: + (ACTIVE_CLIENT_TEXTURE) ? + (ENABLED_VERTEX_ATTRIBUTES &= ~ST_ENABLED_FLAG): + (ENABLED_VERTEX_ATTRIBUTES &= ~UV_ENABLED_FLAG); + break; + default: + _glKosThrowError(GL_INVALID_ENUM, __func__); + } + + /* State changed, recalculate */ + _glRecalcFastPath(); +} + + +// Used to avoid checking and updating attribute related state unless necessary +GL_FORCE_INLINE GLboolean _glStateUnchanged(AttribPointer* p, GLint size, GLenum type, GLsizei stride) { + return (p->size == size && p->type == type && p->stride == stride); +} + +void APIENTRY glTexCoordPointer(GLint size, GLenum type, GLsizei stride, const GLvoid * pointer) { + TRACE(); + + stride = (stride) ? stride : size * byte_size(type); + AttribPointer* tointer = (ACTIVE_CLIENT_TEXTURE == 0) ? &ATTRIB_POINTERS.uv : &ATTRIB_POINTERS.st; + tointer->ptr = pointer; + + if(_glStateUnchanged(tointer, size, type, stride)) return; + + if(size < 1 || size > 4) { + _glKosThrowError(GL_INVALID_VALUE, __func__); + return; + } + + tointer->stride = stride; + tointer->type = type; + tointer->size = size; + + ATTRIB_POINTERS.uv_func = calcReadUVFunc(); + ATTRIB_POINTERS.st_func = calcReadSTFunc(); + _glRecalcFastPath(); +} + +void APIENTRY glVertexPointer(GLint size, GLenum type, GLsizei stride, const GLvoid * pointer) { + TRACE(); + + stride = (stride) ? stride : (size * byte_size(type)); + ATTRIB_POINTERS.vertex.ptr = pointer; + + if(_glStateUnchanged(&ATTRIB_POINTERS.vertex, size, type, stride)) return; + + if(size < 2 || size > 4) { + _glKosThrowError(GL_INVALID_VALUE, __func__); + return; + } + + ATTRIB_POINTERS.vertex.stride = stride; + ATTRIB_POINTERS.vertex.type = type; + ATTRIB_POINTERS.vertex.size = size; + ATTRIB_POINTERS.vertex_func = calcReadPositionFunc(); + + _glRecalcFastPath(); +} + +void APIENTRY glColorPointer(GLint size, GLenum type, GLsizei stride, const GLvoid * pointer) { + TRACE(); + + stride = (stride) ? stride : ((size == GL_BGRA) ? 4 : size) * byte_size(type); + ATTRIB_POINTERS.colour.ptr = pointer; + + if(_glStateUnchanged(&ATTRIB_POINTERS.colour, size, type, stride)) return; + + if(size != 3 && size != 4 && size != GL_BGRA) { + _glKosThrowError(GL_INVALID_VALUE, __func__); + return; + } + + ATTRIB_POINTERS.colour.type = type; + ATTRIB_POINTERS.colour.size = size; + ATTRIB_POINTERS.colour.stride = stride; + ATTRIB_POINTERS.colour_func = calcReadDiffuseFunc(); + + _glRecalcFastPath(); +} + +void APIENTRY glNormalPointer(GLenum type, GLsizei stride, const GLvoid * pointer) { + TRACE(); + + GLint validTypes[] = { + GL_DOUBLE, + GL_FLOAT, + GL_BYTE, + GL_UNSIGNED_BYTE, + GL_INT, + GL_UNSIGNED_INT, + GL_UNSIGNED_INT_2_10_10_10_REV, + 0 + }; + + stride = (stride) ? stride : ATTRIB_POINTERS.normal.size * byte_size(type); + ATTRIB_POINTERS.normal.ptr = pointer; + + if(_glStateUnchanged(&ATTRIB_POINTERS.normal, 3, type, stride)) return; + + if(_glCheckValidEnum(type, validTypes, __func__) != 0) { + return; + } + + ATTRIB_POINTERS.normal.size = (type == GL_UNSIGNED_INT_2_10_10_10_REV) ? 1 : 3; + ATTRIB_POINTERS.normal.stride = stride; + ATTRIB_POINTERS.normal.type = type; + ATTRIB_POINTERS.normal_func = calcReadNormalFunc(); + + _glRecalcFastPath(); +} + + +void _glInitAttributePointers() { + TRACE(); + + ATTRIB_POINTERS.vertex.ptr = NULL; + ATTRIB_POINTERS.vertex.stride = 0; + ATTRIB_POINTERS.vertex.type = GL_FLOAT; + ATTRIB_POINTERS.vertex.size = 4; + ATTRIB_POINTERS.vertex_func = calcReadPositionFunc(); + + ATTRIB_POINTERS.colour.ptr = NULL; + ATTRIB_POINTERS.colour.stride = 0; + ATTRIB_POINTERS.colour.type = GL_FLOAT; + ATTRIB_POINTERS.colour.size = 4; + ATTRIB_POINTERS.colour_func = calcReadDiffuseFunc(); + + ATTRIB_POINTERS.uv.ptr = NULL; + ATTRIB_POINTERS.uv.stride = 0; + ATTRIB_POINTERS.uv.type = GL_FLOAT; + ATTRIB_POINTERS.uv.size = 4; + ATTRIB_POINTERS.uv_func = calcReadUVFunc(); + + ATTRIB_POINTERS.st.ptr = NULL; + ATTRIB_POINTERS.st.stride = 0; + ATTRIB_POINTERS.st.type = GL_FLOAT; + ATTRIB_POINTERS.st.size = 4; + ATTRIB_POINTERS.st_func = calcReadSTFunc(); + + ATTRIB_POINTERS.normal.ptr = NULL; + ATTRIB_POINTERS.normal.stride = 0; + ATTRIB_POINTERS.normal.type = GL_FLOAT; + ATTRIB_POINTERS.normal.size = 3; + ATTRIB_POINTERS.normal_func = calcReadNormalFunc(); +} diff --git a/GL/draw.c b/GL/draw.c index b822c7f..514d03c 100644 --- a/GL/draw.c +++ b/GL/draw.c @@ -8,15 +8,8 @@ #include "private.h" #include "platform.h" - -AttribPointerList ATTRIB_POINTERS; -GLuint ENABLED_VERTEX_ATTRIBUTES = 0; GLuint FAST_PATH_ENABLED = GL_FALSE; - -static GLubyte ACTIVE_CLIENT_TEXTURE = 0; -static const float ONE_OVER_TWO_FIVE_FIVE = 1.0f / 255.0f; - -extern inline GLuint _glRecalcFastPath(); +GLubyte ACTIVE_CLIENT_TEXTURE; extern GLboolean AUTOSORT_ENABLED; @@ -25,296 +18,6 @@ extern GLboolean AUTOSORT_ENABLED; while(i--) -void _glInitAttributePointers() { - TRACE(); - - ATTRIB_POINTERS.vertex.ptr = NULL; - ATTRIB_POINTERS.vertex.stride = 0; - ATTRIB_POINTERS.vertex.type = GL_FLOAT; - ATTRIB_POINTERS.vertex.size = 4; - - ATTRIB_POINTERS.colour.ptr = NULL; - ATTRIB_POINTERS.colour.stride = 0; - ATTRIB_POINTERS.colour.type = GL_FLOAT; - ATTRIB_POINTERS.colour.size = 4; - - ATTRIB_POINTERS.uv.ptr = NULL; - ATTRIB_POINTERS.uv.stride = 0; - ATTRIB_POINTERS.uv.type = GL_FLOAT; - ATTRIB_POINTERS.uv.size = 4; - - ATTRIB_POINTERS.st.ptr = NULL; - ATTRIB_POINTERS.st.stride = 0; - ATTRIB_POINTERS.st.type = GL_FLOAT; - ATTRIB_POINTERS.st.size = 4; - - ATTRIB_POINTERS.normal.ptr = NULL; - ATTRIB_POINTERS.normal.stride = 0; - ATTRIB_POINTERS.normal.type = GL_FLOAT; - ATTRIB_POINTERS.normal.size = 3; -} - -GL_FORCE_INLINE GLsizei byte_size(GLenum type) { - switch(type) { - case GL_BYTE: return sizeof(GLbyte); - case GL_UNSIGNED_BYTE: return sizeof(GLubyte); - case GL_SHORT: return sizeof(GLshort); - case GL_UNSIGNED_SHORT: return sizeof(GLushort); - case GL_INT: return sizeof(GLint); - case GL_UNSIGNED_INT: return sizeof(GLuint); - case GL_DOUBLE: return sizeof(GLdouble); - case GL_UNSIGNED_INT_2_10_10_10_REV: return sizeof(GLuint); - case GL_FLOAT: - default: return sizeof(GLfloat); - } -} - -typedef void (*FloatParseFunc)(GLfloat* out, const GLubyte* in); -typedef void (*ByteParseFunc)(GLubyte* out, const GLubyte* in); -typedef void (*PolyBuildFunc)(Vertex* first, Vertex* previous, Vertex* vertex, Vertex* next, const GLsizei i); - -static void _readVertexData3f3f(const GLubyte* __restrict__ in, GLubyte* __restrict__ out) { - vec3cpy(out, in); -} - -// 10:10:10:2REV format -static void _readVertexData1i3f(const GLubyte* in, GLubyte* out) { - static const float MULTIPLIER = 1.0f / 1023.0f; - - GLfloat* output = (GLfloat*) out; - - union { - int value; - struct { - signed int x: 10; - signed int y: 10; - signed int z: 10; - signed int w: 2; - } bits; - } input; - - input.value = *((const GLint*) in); - - output[0] = (2.0f * (float) input.bits.x + 1.0f) * MULTIPLIER; - output[1] = (2.0f * (float) input.bits.y + 1.0f) * MULTIPLIER; - output[2] = (2.0f * (float) input.bits.z + 1.0f) * MULTIPLIER; -} - -static void _readVertexData3us3f(const GLubyte* in, GLubyte* out) { - const GLushort* input = (const GLushort*) in; - float* output = (float*) out; - - output[0] = input[0]; - output[1] = input[1]; - output[2] = input[2]; -} - -static void _readVertexData3ui3f(const GLubyte* in, GLubyte* out) { - const GLuint* input = (const GLuint*) in; - float* output = (float*) out; - - output[0] = input[0]; - output[1] = input[1]; - output[2] = input[2]; -} - - -static void _readVertexData3ub3f(const GLubyte* input, GLubyte* out) { - float* output = (float*) out; - - output[0] = input[0] * ONE_OVER_TWO_FIVE_FIVE; - output[1] = input[1] * ONE_OVER_TWO_FIVE_FIVE; - output[2] = input[2] * ONE_OVER_TWO_FIVE_FIVE; -} - -static void _readVertexData2f2f(const GLubyte* in, GLubyte* out) { - vec2cpy(out, in); -} - -static void _readVertexData2f3f(const GLubyte* in, GLubyte* out) { - const float* input = (const float*) in; - float* output = (float*) out; - - vec2cpy(output, input); - output[2] = 0.0f; -} - -static void _readVertexData2ub3f(const GLubyte* input, GLubyte* out) { - float* output = (float*) out; - - output[0] = input[0] * ONE_OVER_TWO_FIVE_FIVE; - output[1] = input[1] * ONE_OVER_TWO_FIVE_FIVE; - output[2] = 0.0f; -} - -static void _readVertexData2us3f(const GLubyte* in, GLubyte* out) { - const GLushort* input = (const GLushort*) in; - float* output = (float*) out; - - output[0] = input[0]; - output[1] = input[1]; - output[2] = 0.0f; -} - -static void _readVertexData2us2f(const GLubyte* in, GLubyte* out) { - const GLushort* input = (const GLushort*) in; - float* output = (float*) out; - - output[0] = (float)input[0] / SHRT_MAX; - output[1] = (float)input[1] / SHRT_MAX; -} - -static void _readVertexData2ui2f(const GLubyte* in, GLubyte* out) { - const GLuint* input = (const GLuint*) in; - float* output = (float*) out; - - output[0] = input[0]; - output[1] = input[1]; -} - -static void _readVertexData2ub2f(const GLubyte* input, GLubyte* out) { - float* output = (float*) out; - - output[0] = input[0] * ONE_OVER_TWO_FIVE_FIVE; - output[1] = input[1] * ONE_OVER_TWO_FIVE_FIVE; -} - -static void _readVertexData2ui3f(const GLubyte* in, GLubyte* out) { - const GLuint* input = (const GLuint*) in; - float* output = (float*) out; - - output[0] = input[0]; - output[1] = input[1]; - output[2] = 0.0f; -} - -static void _readVertexData4ubARGB(const GLubyte* input, GLubyte* output) { - output[R8IDX] = input[0]; - output[G8IDX] = input[1]; - output[B8IDX] = input[2]; - output[A8IDX] = input[3]; -} - -static void _readVertexData4fARGB(const GLubyte* in, GLubyte* output) { - const float* input = (const float*) in; - - output[R8IDX] = (GLubyte) clamp(input[0] * 255.0f, 0, 255); - output[G8IDX] = (GLubyte) clamp(input[1] * 255.0f, 0, 255); - output[B8IDX] = (GLubyte) clamp(input[2] * 255.0f, 0, 255); - output[A8IDX] = (GLubyte) clamp(input[3] * 255.0f, 0, 255); -} - -static void _readVertexData3fARGB(const GLubyte* in, GLubyte* output) { - const float* input = (const float*) in; - - output[R8IDX] = (GLubyte) clamp(input[0] * 255.0f, 0, 255); - output[G8IDX] = (GLubyte) clamp(input[1] * 255.0f, 0, 255); - output[B8IDX] = (GLubyte) clamp(input[2] * 255.0f, 0, 255); - output[A8IDX] = 255; -} - -static void _readVertexData3ubARGB(const GLubyte* __restrict__ input, GLubyte* __restrict__ output) { - output[R8IDX] = input[0]; - output[G8IDX] = input[1]; - output[B8IDX] = input[2]; - output[A8IDX] = 255; -} - -static void _readVertexData4ubRevARGB(const GLubyte* __restrict__ input, GLubyte* __restrict__ output) { - argbcpy(output, input); -} - -static void _readVertexData4fRevARGB(const GLubyte* __restrict__ in, GLubyte* __restrict__ output) { - const float* input = (const float*) in; - - output[0] = (GLubyte) clamp(input[0] * 255.0f, 0, 255); - output[1] = (GLubyte) clamp(input[1] * 255.0f, 0, 255); - output[2] = (GLubyte) clamp(input[2] * 255.0f, 0, 255); - output[3] = (GLubyte) clamp(input[3] * 255.0f, 0, 255); -} - -static void _fillWithNegZVE(const GLubyte* __restrict__ input, GLubyte* __restrict__ out) { - _GL_UNUSED(input); - - typedef struct { - float x, y, z; - } V; - - static const V NegZ = {0.0f, 0.0f, -1.0f}; - - *((V*) out) = NegZ; -} - -static void _fillWhiteARGB(const GLubyte* __restrict__ input, GLubyte* __restrict__ output) { - _GL_UNUSED(input); - *((uint32_t*) output) = ~0; -} - -static void _fillZero2f(const GLubyte* __restrict__ input, GLubyte* __restrict__ out) { - _GL_UNUSED(input); - memset(out, 0, sizeof(float) * 2); -} - -static void _readVertexData3usARGB(const GLubyte* input, GLubyte* output) { - _GL_UNUSED(input); - _GL_UNUSED(output); - gl_assert(0 && "Not Implemented"); -} - -static void _readVertexData3uiARGB(const GLubyte* input, GLubyte* output) { - _GL_UNUSED(input); - _GL_UNUSED(output); - gl_assert(0 && "Not Implemented"); -} - -static void _readVertexData4usARGB(const GLubyte* input, GLubyte* output) { - _GL_UNUSED(input); - _GL_UNUSED(output); - gl_assert(0 && "Not Implemented"); -} - -static void _readVertexData4uiARGB(const GLubyte* input, GLubyte* output) { - _GL_UNUSED(input); - _GL_UNUSED(output); - gl_assert(0 && "Not Implemented"); -} - -static void _readVertexData4usRevARGB(const GLubyte* input, GLubyte* output) { - _GL_UNUSED(input); - _GL_UNUSED(output); - gl_assert(0 && "Not Implemented"); -} - -static void _readVertexData4uiRevARGB(const GLubyte* input, GLubyte* output) { - _GL_UNUSED(input); - _GL_UNUSED(output); - gl_assert(0 && "Not Implemented"); -} - -GLuint* _glGetEnabledAttributes() { - return &ENABLED_VERTEX_ATTRIBUTES; -} - -AttribPointer* _glGetVertexAttribPointer() { - return &ATTRIB_POINTERS.vertex; -} - -AttribPointer* _glGetDiffuseAttribPointer() { - return &ATTRIB_POINTERS.colour; -} - -AttribPointer* _glGetNormalAttribPointer() { - return &ATTRIB_POINTERS.normal; -} - -AttribPointer* _glGetUVAttribPointer() { - return &ATTRIB_POINTERS.uv; -} - -AttribPointer* _glGetSTAttribPointer() { - return &ATTRIB_POINTERS.st; -} - typedef GLuint (*IndexParseFunc)(const GLubyte* in); static inline GLuint _parseUByteIndex(const GLubyte* in) { @@ -329,6 +32,14 @@ static inline GLuint _parseUShortIndex(const GLubyte* in) { return *((GLshort*) in); } +GL_FORCE_INLINE GLsizei index_size(GLenum type) { + switch(type) { + case GL_UNSIGNED_BYTE: return sizeof(GLubyte); + case GL_UNSIGNED_SHORT: return sizeof(GLushort); + case GL_UNSIGNED_INT: return sizeof(GLuint); + default: return sizeof(GLushort); + } +} GL_FORCE_INLINE IndexParseFunc _calcParseIndexFunc(GLenum type) { switch(type) { @@ -574,138 +285,8 @@ static GL_NO_INLINE void genLineLoop(Vertex* output, GLuint count) { draw_line(dst, &first, &last); } -typedef void (*ReadPositionFunc)(const GLubyte*, GLubyte*); -typedef void (*ReadDiffuseFunc)(const GLubyte*, GLubyte*); -typedef void (*ReadUVFunc)(const GLubyte*, GLubyte*); -typedef void (*ReadNormalFunc)(const GLubyte*, GLubyte*); - -ReadPositionFunc calcReadDiffuseFunc() { - if((ENABLED_VERTEX_ATTRIBUTES & DIFFUSE_ENABLED_FLAG) != DIFFUSE_ENABLED_FLAG) { - /* Just fill the whole thing white if the attribute is disabled */ - return _fillWhiteARGB; - } - - switch(ATTRIB_POINTERS.colour.type) { - default: - case GL_DOUBLE: - case GL_FLOAT: - return (ATTRIB_POINTERS.colour.size == 3) ? _readVertexData3fARGB: - (ATTRIB_POINTERS.colour.size == 4) ? _readVertexData4fARGB: - _readVertexData4fRevARGB; - case GL_BYTE: - case GL_UNSIGNED_BYTE: - return (ATTRIB_POINTERS.colour.size == 3) ? _readVertexData3ubARGB: - (ATTRIB_POINTERS.colour.size == 4) ? _readVertexData4ubARGB: - _readVertexData4ubRevARGB; - case GL_SHORT: - case GL_UNSIGNED_SHORT: - return (ATTRIB_POINTERS.colour.size == 3) ? _readVertexData3usARGB: - (ATTRIB_POINTERS.colour.size == 4) ? _readVertexData4usARGB: - _readVertexData4usRevARGB; - case GL_INT: - case GL_UNSIGNED_INT: - return (ATTRIB_POINTERS.colour.size == 3) ? _readVertexData3uiARGB: - (ATTRIB_POINTERS.colour.size == 4) ? _readVertexData4uiARGB: - _readVertexData4uiRevARGB; - } -} - -ReadPositionFunc calcReadPositionFunc() { - switch(ATTRIB_POINTERS.vertex.type) { - default: - case GL_DOUBLE: - case GL_FLOAT: - return (ATTRIB_POINTERS.vertex.size == 3) ? _readVertexData3f3f: - _readVertexData2f3f; - case GL_BYTE: - case GL_UNSIGNED_BYTE: - return (ATTRIB_POINTERS.vertex.size == 3) ? _readVertexData3ub3f: - _readVertexData2ub3f; - case GL_SHORT: - case GL_UNSIGNED_SHORT: - return (ATTRIB_POINTERS.vertex.size == 3) ? _readVertexData3us3f: - _readVertexData2us3f; - case GL_INT: - case GL_UNSIGNED_INT: - return (ATTRIB_POINTERS.vertex.size == 3) ? _readVertexData3ui3f: - _readVertexData2ui3f; - } -} - -ReadUVFunc calcReadUVFunc() { - if((ENABLED_VERTEX_ATTRIBUTES & UV_ENABLED_FLAG) != UV_ENABLED_FLAG) { - return _fillZero2f; - } - - switch(ATTRIB_POINTERS.uv.type) { - default: - case GL_DOUBLE: - case GL_FLOAT: - return _readVertexData2f2f; - case GL_BYTE: - case GL_UNSIGNED_BYTE: - return _readVertexData2ub2f; - case GL_SHORT: - case GL_UNSIGNED_SHORT: - return _readVertexData2us2f; - case GL_INT: - case GL_UNSIGNED_INT: - return _readVertexData2ui2f; - } -} - -ReadUVFunc calcReadSTFunc() { - if((ENABLED_VERTEX_ATTRIBUTES & ST_ENABLED_FLAG) != ST_ENABLED_FLAG) { - return _fillZero2f; - } - - switch(ATTRIB_POINTERS.st.type) { - default: - case GL_DOUBLE: - case GL_FLOAT: - return _readVertexData2f2f; - case GL_BYTE: - case GL_UNSIGNED_BYTE: - return _readVertexData2ub2f; - case GL_SHORT: - case GL_UNSIGNED_SHORT: - return _readVertexData2us2f; - case GL_INT: - case GL_UNSIGNED_INT: - return _readVertexData2ui2f; - } -} - -ReadNormalFunc calcReadNormalFunc() { - if((ENABLED_VERTEX_ATTRIBUTES & NORMAL_ENABLED_FLAG) != NORMAL_ENABLED_FLAG) { - return _fillWithNegZVE; - } - - switch(ATTRIB_POINTERS.normal.type) { - default: - case GL_DOUBLE: - case GL_FLOAT: - return _readVertexData3f3f; - break; - case GL_BYTE: - case GL_UNSIGNED_BYTE: - return _readVertexData3ub3f; - break; - case GL_SHORT: - case GL_UNSIGNED_SHORT: - return _readVertexData3us3f; - break; - case GL_INT: - case GL_UNSIGNED_INT: - return _readVertexData3ui3f; - break; - case GL_UNSIGNED_INT_2_10_10_10_REV: - return _readVertexData1i3f; - break; - } -} - -static void _readPositionData(ReadDiffuseFunc func, const GLuint first, const GLuint count, Vertex* it) { +static void _readPositionData(const GLuint first, const GLuint count, Vertex* it) { + const ReadAttributeFunc func = ATTRIB_POINTERS.vertex_func; const GLsizei vstride = ATTRIB_POINTERS.vertex.stride; const GLubyte* vptr = ((GLubyte*) ATTRIB_POINTERS.vertex.ptr + (first * vstride)); @@ -722,7 +303,8 @@ static void _readPositionData(ReadDiffuseFunc func, const GLuint first, const GL } } -static void _readUVData(ReadUVFunc func, const GLuint first, const GLuint count, Vertex* it) { +static void _readUVData(const GLuint first, const GLuint count, Vertex* it) { + const ReadAttributeFunc func = ATTRIB_POINTERS.uv_func; const GLsizei uvstride = ATTRIB_POINTERS.uv.stride; const GLubyte* uvptr = ((GLubyte*) ATTRIB_POINTERS.uv.ptr + (first * uvstride)); @@ -735,7 +317,8 @@ static void _readUVData(ReadUVFunc func, const GLuint first, const GLuint count, } } -static void _readSTData(ReadUVFunc func, const GLuint first, const GLuint count, VertexExtra* it) { +static void _readSTData(const GLuint first, const GLuint count, VertexExtra* it) { + const ReadAttributeFunc func = ATTRIB_POINTERS.st_func; const GLsizei ststride = ATTRIB_POINTERS.st.stride; const GLubyte* stptr = ((GLubyte*) ATTRIB_POINTERS.st.ptr + (first * ststride)); @@ -747,7 +330,8 @@ static void _readSTData(ReadUVFunc func, const GLuint first, const GLuint count, } } -static void _readNormalData(ReadNormalFunc func, const GLuint first, const GLuint count, VertexExtra* it) { +static void _readNormalData(const GLuint first, const GLuint count, VertexExtra* it) { + const ReadAttributeFunc func = ATTRIB_POINTERS.normal_func; const GLsizei nstride = ATTRIB_POINTERS.normal.stride; const GLubyte* nptr = ((GLubyte*) ATTRIB_POINTERS.normal.ptr + (first * nstride)); @@ -771,11 +355,8 @@ static void _readNormalData(ReadNormalFunc func, const GLuint first, const GLuin } } -GL_FORCE_INLINE GLuint diffusePointerSize() { - return (ATTRIB_POINTERS.colour.size == GL_BGRA) ? 4 : ATTRIB_POINTERS.colour.size; -} - -static void _readDiffuseData(ReadDiffuseFunc func, const GLuint first, const GLuint count, Vertex* it) { +static void _readDiffuseData(const GLuint first, const GLuint count, Vertex* it) { + const ReadAttributeFunc func = ATTRIB_POINTERS.colour_func; const GLuint cstride = ATTRIB_POINTERS.colour.stride; const GLubyte* cptr = ((GLubyte*) ATTRIB_POINTERS.colour.ptr) + (first * cstride); @@ -791,7 +372,7 @@ static void generateElements( SubmissionTarget* target, const GLsizei first, const GLuint count, const GLubyte* indices, const GLenum type) { - const GLsizei istride = byte_size(type); + const GLsizei istride = index_size(type); const IndexParseFunc IndexFunc = _calcParseIndexFunc(type); GLubyte* xyz; @@ -807,19 +388,19 @@ static void generateElements( uint32_t i = first; uint32_t idx = 0; - const ReadPositionFunc pos_func = calcReadPositionFunc(); + const ReadAttributeFunc pos_func = ATTRIB_POINTERS.vertex_func; const GLsizei vstride = ATTRIB_POINTERS.vertex.stride; - const ReadUVFunc uv_func = calcReadUVFunc(); + const ReadAttributeFunc uv_func = ATTRIB_POINTERS.uv_func; const GLuint uvstride = ATTRIB_POINTERS.uv.stride; - const ReadUVFunc st_func = calcReadSTFunc(); + const ReadAttributeFunc st_func = ATTRIB_POINTERS.st_func; const GLuint ststride = ATTRIB_POINTERS.st.stride; - const ReadDiffuseFunc diffuse_func = calcReadDiffuseFunc(); + const ReadAttributeFunc diffuse_func = ATTRIB_POINTERS.colour_func; const GLuint dstride = ATTRIB_POINTERS.colour.stride; - const ReadNormalFunc normal_func = calcReadNormalFunc(); + const ReadAttributeFunc normal_func = ATTRIB_POINTERS.normal_func; const GLuint nstride = ATTRIB_POINTERS.normal.stride; for(; i < first + count; ++i) { @@ -867,7 +448,7 @@ static void generateElementsFastPath( const GLuint dstride = ATTRIB_POINTERS.colour.stride; const GLuint nstride = ATTRIB_POINTERS.normal.stride; - const GLsizei istride = byte_size(type); + const GLsizei istride = index_size(type); const IndexParseFunc IndexFunc = _calcParseIndexFunc(type); /* Copy the pos, uv and color directly in one go */ @@ -965,17 +546,11 @@ static void generateArrays(SubmissionTarget* target, const GLsizei first, const Vertex* start = _glSubmissionTargetStart(target); VertexExtra* ve = aligned_vector_at(target->extras, 0); - const ReadPositionFunc pfunc = calcReadPositionFunc(); - const ReadDiffuseFunc dfunc = calcReadDiffuseFunc(); - const ReadUVFunc uvfunc = calcReadUVFunc(); - const ReadNormalFunc nfunc = calcReadNormalFunc(); - const ReadUVFunc stfunc = calcReadSTFunc(); - - _readPositionData(pfunc, first, count, start); - _readDiffuseData(dfunc, first, count, start); - _readUVData(uvfunc, first, count, start); - _readNormalData(nfunc, first, count, ve); - _readSTData(stfunc, first, count, ve); + _readPositionData(first, count, start); + _readDiffuseData(first, count, start); + _readUVData(first, count, start); + _readNormalData(first, count, ve); + _readSTData(first, count, ve); } static void generate(SubmissionTarget* target, const GLenum mode, const GLsizei first, const GLuint count, @@ -1397,60 +972,6 @@ void APIENTRY glDrawArrays(GLenum mode, GLint first, GLsizei count) { submitVertices(mode, first, count, GL_UNSIGNED_INT, NULL); } -void APIENTRY glEnableClientState(GLenum cap) { - TRACE(); - - switch(cap) { - case GL_VERTEX_ARRAY: - ENABLED_VERTEX_ATTRIBUTES |= VERTEX_ENABLED_FLAG; - break; - case GL_COLOR_ARRAY: - ENABLED_VERTEX_ATTRIBUTES |= DIFFUSE_ENABLED_FLAG; - break; - case GL_NORMAL_ARRAY: - ENABLED_VERTEX_ATTRIBUTES |= NORMAL_ENABLED_FLAG; - break; - case GL_TEXTURE_COORD_ARRAY: - (ACTIVE_CLIENT_TEXTURE) ? - (ENABLED_VERTEX_ATTRIBUTES |= ST_ENABLED_FLAG): - (ENABLED_VERTEX_ATTRIBUTES |= UV_ENABLED_FLAG); - break; - default: - _glKosThrowError(GL_INVALID_ENUM, __func__); - } - - /* It's possible that we called glVertexPointer and friends before - * calling glEnableClientState, so we should recheck to make sure - * everything is in the right format with this new information */ - _glRecalcFastPath(); -} - -void APIENTRY glDisableClientState(GLenum cap) { - TRACE(); - - switch(cap) { - case GL_VERTEX_ARRAY: - ENABLED_VERTEX_ATTRIBUTES &= ~VERTEX_ENABLED_FLAG; - break; - case GL_COLOR_ARRAY: - ENABLED_VERTEX_ATTRIBUTES &= ~DIFFUSE_ENABLED_FLAG; - break; - case GL_NORMAL_ARRAY: - ENABLED_VERTEX_ATTRIBUTES &= ~NORMAL_ENABLED_FLAG; - break; - case GL_TEXTURE_COORD_ARRAY: - (ACTIVE_CLIENT_TEXTURE) ? - (ENABLED_VERTEX_ATTRIBUTES &= ~ST_ENABLED_FLAG): - (ENABLED_VERTEX_ATTRIBUTES &= ~UV_ENABLED_FLAG); - break; - default: - _glKosThrowError(GL_INVALID_ENUM, __func__); - } - - /* State changed, recalculate */ - _glRecalcFastPath(); -} - GLuint _glGetActiveClientTexture() { return ACTIVE_CLIENT_TEXTURE; } @@ -1465,99 +986,3 @@ void APIENTRY glClientActiveTextureARB(GLenum texture) { ACTIVE_CLIENT_TEXTURE = (texture == GL_TEXTURE1_ARB) ? 1 : 0; } - -// Used to avoid checking and updating attribute related state unless necessary -GL_FORCE_INLINE GLboolean _glStateUnchanged(AttribPointer* p, GLint size, GLenum type, GLsizei stride) { - return (p->size == size && p->type == type && p->stride == stride); -} - -void APIENTRY glTexCoordPointer(GLint size, GLenum type, GLsizei stride, const GLvoid * pointer) { - TRACE(); - - stride = (stride) ? stride : size * byte_size(type); - AttribPointer* tointer = (ACTIVE_CLIENT_TEXTURE == 0) ? &ATTRIB_POINTERS.uv : &ATTRIB_POINTERS.st; - tointer->ptr = pointer; - - if(_glStateUnchanged(tointer, size, type, stride)) return; - - if(size < 1 || size > 4) { - _glKosThrowError(GL_INVALID_VALUE, __func__); - return; - } - - tointer->stride = stride; - tointer->type = type; - tointer->size = size; - - _glRecalcFastPath(); -} - -void APIENTRY glVertexPointer(GLint size, GLenum type, GLsizei stride, const GLvoid * pointer) { - TRACE(); - - stride = (stride) ? stride : (size * byte_size(type)); - ATTRIB_POINTERS.vertex.ptr = pointer; - - if(_glStateUnchanged(&ATTRIB_POINTERS.vertex, size, type, stride)) return; - - if(size < 2 || size > 4) { - _glKosThrowError(GL_INVALID_VALUE, __func__); - return; - } - - ATTRIB_POINTERS.vertex.stride = stride; - ATTRIB_POINTERS.vertex.type = type; - ATTRIB_POINTERS.vertex.size = size; - - _glRecalcFastPath(); -} - -void APIENTRY glColorPointer(GLint size, GLenum type, GLsizei stride, const GLvoid * pointer) { - TRACE(); - - stride = (stride) ? stride : ((size == GL_BGRA) ? 4 : size) * byte_size(type); - ATTRIB_POINTERS.colour.ptr = pointer; - - if(_glStateUnchanged(&ATTRIB_POINTERS.colour, size, type, stride)) return; - - if(size != 3 && size != 4 && size != GL_BGRA) { - _glKosThrowError(GL_INVALID_VALUE, __func__); - return; - } - - ATTRIB_POINTERS.colour.type = type; - ATTRIB_POINTERS.colour.size = size; - ATTRIB_POINTERS.colour.stride = stride; - - _glRecalcFastPath(); -} - -void APIENTRY glNormalPointer(GLenum type, GLsizei stride, const GLvoid * pointer) { - TRACE(); - - GLint validTypes[] = { - GL_DOUBLE, - GL_FLOAT, - GL_BYTE, - GL_UNSIGNED_BYTE, - GL_INT, - GL_UNSIGNED_INT, - GL_UNSIGNED_INT_2_10_10_10_REV, - 0 - }; - - stride = (stride) ? stride : ATTRIB_POINTERS.normal.size * byte_size(type); - ATTRIB_POINTERS.normal.ptr = pointer; - - if(_glStateUnchanged(&ATTRIB_POINTERS.normal, 3, type, stride)) return; - - if(_glCheckValidEnum(type, validTypes, __func__) != 0) { - return; - } - - ATTRIB_POINTERS.normal.size = (type == GL_UNSIGNED_INT_2_10_10_10_REV) ? 1 : 3; - ATTRIB_POINTERS.normal.stride = stride; - ATTRIB_POINTERS.normal.type = type; - - _glRecalcFastPath(); -} diff --git a/GL/private.h b/GL/private.h index 8230f01..bf13e0b 100644 --- a/GL/private.h +++ b/GL/private.h @@ -346,6 +346,7 @@ typedef struct { GLsizei stride; // 4 GLint size; // 4 } AttribPointer; +typedef void (*ReadAttributeFunc)(const GLubyte*, GLubyte*); typedef struct { AttribPointer vertex; // 16 @@ -353,25 +354,29 @@ typedef struct { AttribPointer uv; // 48 AttribPointer st; // 64 AttribPointer normal; // 80 - AttribPointer padding; // 96 + + ReadAttributeFunc vertex_func; + ReadAttributeFunc colour_func; + ReadAttributeFunc uv_func; + ReadAttributeFunc st_func; + ReadAttributeFunc normal_func; } AttribPointerList; +extern GLuint ENABLED_VERTEX_ATTRIBUTES; +extern AttribPointerList ATTRIB_POINTERS; + GLboolean _glCheckValidEnum(GLint param, GLint* values, const char* func); GLuint* _glGetEnabledAttributes(); -AttribPointer* _glGetVertexAttribPointer(); -AttribPointer* _glGetDiffuseAttribPointer(); -AttribPointer* _glGetNormalAttribPointer(); -AttribPointer* _glGetUVAttribPointer(); -AttribPointer* _glGetSTAttribPointer(); -GLenum _glGetShadeModel(); +GLenum _glGetShadeModel(); TextureObject* _glGetTexture0(); TextureObject* _glGetTexture1(); TextureObject* _glGetBoundTexture(); extern GLubyte ACTIVE_TEXTURE; extern GLboolean TEXTURES_ENABLED[]; +extern GLubyte ACTIVE_CLIENT_TEXTURE; GLubyte _glGetActiveTexture(); GLint _glGetTextureInternalFormat(); @@ -422,9 +427,6 @@ GLboolean _glIsColorMaterialEnabled(); GLboolean _glIsNormalizeEnabled(); -extern AttribPointerList ATTRIB_POINTERS; - -extern GLuint ENABLED_VERTEX_ATTRIBUTES; extern GLuint FAST_PATH_ENABLED; GL_FORCE_INLINE GLuint _glIsVertexDataFastPathCompatible() { From a35659ce3d0db0b5bdd69e0dda8329849b577d6f Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sat, 1 Feb 2025 16:05:07 +1100 Subject: [PATCH 58/72] Fix enable/disable attribute calls not updating read functions --- GL/attributes.c | 72 +++++++++++++++++++++---------------------------- 1 file changed, 30 insertions(+), 42 deletions(-) diff --git a/GL/attributes.c b/GL/attributes.c index 4ed6ca3..13d5c0c 100644 --- a/GL/attributes.c +++ b/GL/attributes.c @@ -31,6 +31,12 @@ GL_FORCE_INLINE GLsizei byte_size(GLenum type) { } } +// Used to avoid checking and updating attribute related state unless necessary +GL_FORCE_INLINE GLboolean _glStateUnchanged(AttribPointer* p, GLint size, GLenum type, GLsizei stride) { + return (p->size == size && p->type == type && p->stride == stride); +} + + static void _readVertexData3f3f(const GLubyte* __restrict__ in, GLubyte* __restrict__ out) { vec3cpy(out, in); } @@ -381,18 +387,24 @@ void APIENTRY glEnableClientState(GLenum cap) { switch(cap) { case GL_VERTEX_ARRAY: ENABLED_VERTEX_ATTRIBUTES |= VERTEX_ENABLED_FLAG; - break; + ATTRIB_POINTERS.vertex_func = calcReadPositionFunc(); + break; case GL_COLOR_ARRAY: ENABLED_VERTEX_ATTRIBUTES |= DIFFUSE_ENABLED_FLAG; - break; + ATTRIB_POINTERS.colour_func = calcReadDiffuseFunc(); + break; case GL_NORMAL_ARRAY: ENABLED_VERTEX_ATTRIBUTES |= NORMAL_ENABLED_FLAG; - break; + ATTRIB_POINTERS.normal_func = calcReadNormalFunc(); + break; case GL_TEXTURE_COORD_ARRAY: (ACTIVE_CLIENT_TEXTURE) ? (ENABLED_VERTEX_ATTRIBUTES |= ST_ENABLED_FLAG): (ENABLED_VERTEX_ATTRIBUTES |= UV_ENABLED_FLAG); - break; + + ATTRIB_POINTERS.uv_func = calcReadUVFunc(); + ATTRIB_POINTERS.st_func = calcReadSTFunc(); + break; default: _glKosThrowError(GL_INVALID_ENUM, __func__); } @@ -409,18 +421,24 @@ void APIENTRY glDisableClientState(GLenum cap) { switch(cap) { case GL_VERTEX_ARRAY: ENABLED_VERTEX_ATTRIBUTES &= ~VERTEX_ENABLED_FLAG; - break; + ATTRIB_POINTERS.vertex_func = calcReadPositionFunc(); + break; case GL_COLOR_ARRAY: ENABLED_VERTEX_ATTRIBUTES &= ~DIFFUSE_ENABLED_FLAG; - break; + ATTRIB_POINTERS.colour_func = calcReadDiffuseFunc(); + break; case GL_NORMAL_ARRAY: ENABLED_VERTEX_ATTRIBUTES &= ~NORMAL_ENABLED_FLAG; - break; + ATTRIB_POINTERS.normal_func = calcReadNormalFunc(); + break; case GL_TEXTURE_COORD_ARRAY: (ACTIVE_CLIENT_TEXTURE) ? (ENABLED_VERTEX_ATTRIBUTES &= ~ST_ENABLED_FLAG): (ENABLED_VERTEX_ATTRIBUTES &= ~UV_ENABLED_FLAG); - break; + + ATTRIB_POINTERS.uv_func = calcReadUVFunc(); + ATTRIB_POINTERS.st_func = calcReadSTFunc(); + break; default: _glKosThrowError(GL_INVALID_ENUM, __func__); } @@ -430,11 +448,6 @@ void APIENTRY glDisableClientState(GLenum cap) { } -// Used to avoid checking and updating attribute related state unless necessary -GL_FORCE_INLINE GLboolean _glStateUnchanged(AttribPointer* p, GLint size, GLenum type, GLsizei stride) { - return (p->size == size && p->type == type && p->stride == stride); -} - void APIENTRY glTexCoordPointer(GLint size, GLenum type, GLsizei stride, const GLvoid * pointer) { TRACE(); @@ -535,33 +548,8 @@ void APIENTRY glNormalPointer(GLenum type, GLsizei stride, const GLvoid * poin void _glInitAttributePointers() { TRACE(); - ATTRIB_POINTERS.vertex.ptr = NULL; - ATTRIB_POINTERS.vertex.stride = 0; - ATTRIB_POINTERS.vertex.type = GL_FLOAT; - ATTRIB_POINTERS.vertex.size = 4; - ATTRIB_POINTERS.vertex_func = calcReadPositionFunc(); - - ATTRIB_POINTERS.colour.ptr = NULL; - ATTRIB_POINTERS.colour.stride = 0; - ATTRIB_POINTERS.colour.type = GL_FLOAT; - ATTRIB_POINTERS.colour.size = 4; - ATTRIB_POINTERS.colour_func = calcReadDiffuseFunc(); - - ATTRIB_POINTERS.uv.ptr = NULL; - ATTRIB_POINTERS.uv.stride = 0; - ATTRIB_POINTERS.uv.type = GL_FLOAT; - ATTRIB_POINTERS.uv.size = 4; - ATTRIB_POINTERS.uv_func = calcReadUVFunc(); - - ATTRIB_POINTERS.st.ptr = NULL; - ATTRIB_POINTERS.st.stride = 0; - ATTRIB_POINTERS.st.type = GL_FLOAT; - ATTRIB_POINTERS.st.size = 4; - ATTRIB_POINTERS.st_func = calcReadSTFunc(); - - ATTRIB_POINTERS.normal.ptr = NULL; - ATTRIB_POINTERS.normal.stride = 0; - ATTRIB_POINTERS.normal.type = GL_FLOAT; - ATTRIB_POINTERS.normal.size = 3; - ATTRIB_POINTERS.normal_func = calcReadNormalFunc(); + glVertexPointer(4, GL_FLOAT, 0, NULL); + glTexCoordPointer(2, GL_FLOAT, 0, NULL); + glColorPointer(4, GL_FLOAT, 0, NULL); + glNormalPointer(GL_FLOAT, 0, NULL); } From 3550c89501ee0157bb685c42e306b54657d02a80 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sat, 1 Feb 2025 17:04:42 +1100 Subject: [PATCH 59/72] Make non-textured non-fast drawing a little bit faster --- GL/attributes.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/GL/attributes.c b/GL/attributes.c index 13d5c0c..337d427 100644 --- a/GL/attributes.c +++ b/GL/attributes.c @@ -199,24 +199,25 @@ static void _readVertexData4fRevARGB(const GLubyte* __restrict__ in, GLubyte* __ static void _fillWithNegZVE(const GLubyte* __restrict__ input, GLubyte* __restrict__ out) { _GL_UNUSED(input); - - typedef struct { - float x, y, z; - } V; + typedef struct { float x, y, z; } V; static const V NegZ = {0.0f, 0.0f, -1.0f}; *((V*) out) = NegZ; } -static void _fillWhiteARGB(const GLubyte* __restrict__ input, GLubyte* __restrict__ output) { +static void _fillWhiteARGB(const GLubyte* __restrict__ input, GLubyte* __restrict__ output) { _GL_UNUSED(input); *((uint32_t*) output) = ~0; } static void _fillZero2f(const GLubyte* __restrict__ input, GLubyte* __restrict__ out) { _GL_UNUSED(input); - memset(out, 0, sizeof(float) * 2); + //memset(out, 0, sizeof(float) * 2); + // memset does 8 byte writes - faster to manually write as uint32 + uint32_t* dst = (uint32_t*)out; + dst[0] = 0; + dst[1] = 0; } static void _readVertexData3usARGB(const GLubyte* input, GLubyte* output) { From 5318f11f11b58297d0b56bf1f8040a6ca5be0a49 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sat, 1 Feb 2025 18:17:28 +1100 Subject: [PATCH 60/72] Defer recomputing attributes state when possible --- GL/attributes.c | 228 +++++++++++++++++++++++++++---------------- GL/draw.c | 98 +++++++++---------- GL/draw_fastpath.inc | 22 ++--- GL/immediate.c | 64 ++++-------- GL/private.h | 65 ++---------- 5 files changed, 232 insertions(+), 245 deletions(-) diff --git a/GL/attributes.c b/GL/attributes.c index 337d427..607e2f3 100644 --- a/GL/attributes.c +++ b/GL/attributes.c @@ -8,14 +8,9 @@ #include "private.h" #include "platform.h" - -AttribPointerList ATTRIB_POINTERS; -GLuint ENABLED_VERTEX_ATTRIBUTES = 0; - +AttribPointerList ATTRIB_LIST; static const float ONE_OVER_TWO_FIVE_FIVE = 1.0f / 255.0f; -extern inline GLuint _glRecalcFastPath(); - GL_FORCE_INLINE GLsizei byte_size(GLenum type) { switch(type) { case GL_BYTE: return sizeof(GLbyte); @@ -36,6 +31,10 @@ GL_FORCE_INLINE GLboolean _glStateUnchanged(AttribPointer* p, GLint size, GLenum return (p->size == size && p->type == type && p->stride == stride); } +GLuint* _glGetEnabledAttributes() { + return &ATTRIB_LIST.enabled; +} + static void _readVertexData3f3f(const GLubyte* __restrict__ in, GLubyte* __restrict__ out) { vec3cpy(out, in); @@ -257,64 +256,64 @@ static void _readVertexData4uiRevARGB(const GLubyte* input, GLubyte* output) { } static ReadAttributeFunc calcReadDiffuseFunc() { - if((ENABLED_VERTEX_ATTRIBUTES & DIFFUSE_ENABLED_FLAG) != DIFFUSE_ENABLED_FLAG) { + if((ATTRIB_LIST.enabled & DIFFUSE_ENABLED_FLAG) != DIFFUSE_ENABLED_FLAG) { /* Just fill the whole thing white if the attribute is disabled */ return _fillWhiteARGB; } - switch(ATTRIB_POINTERS.colour.type) { + switch(ATTRIB_LIST.colour.type) { default: case GL_DOUBLE: case GL_FLOAT: - return (ATTRIB_POINTERS.colour.size == 3) ? _readVertexData3fARGB: - (ATTRIB_POINTERS.colour.size == 4) ? _readVertexData4fARGB: + return (ATTRIB_LIST.colour.size == 3) ? _readVertexData3fARGB: + (ATTRIB_LIST.colour.size == 4) ? _readVertexData4fARGB: _readVertexData4fRevARGB; case GL_BYTE: case GL_UNSIGNED_BYTE: - return (ATTRIB_POINTERS.colour.size == 3) ? _readVertexData3ubARGB: - (ATTRIB_POINTERS.colour.size == 4) ? _readVertexData4ubARGB: + return (ATTRIB_LIST.colour.size == 3) ? _readVertexData3ubARGB: + (ATTRIB_LIST.colour.size == 4) ? _readVertexData4ubARGB: _readVertexData4ubRevARGB; case GL_SHORT: case GL_UNSIGNED_SHORT: - return (ATTRIB_POINTERS.colour.size == 3) ? _readVertexData3usARGB: - (ATTRIB_POINTERS.colour.size == 4) ? _readVertexData4usARGB: + return (ATTRIB_LIST.colour.size == 3) ? _readVertexData3usARGB: + (ATTRIB_LIST.colour.size == 4) ? _readVertexData4usARGB: _readVertexData4usRevARGB; case GL_INT: case GL_UNSIGNED_INT: - return (ATTRIB_POINTERS.colour.size == 3) ? _readVertexData3uiARGB: - (ATTRIB_POINTERS.colour.size == 4) ? _readVertexData4uiARGB: + return (ATTRIB_LIST.colour.size == 3) ? _readVertexData3uiARGB: + (ATTRIB_LIST.colour.size == 4) ? _readVertexData4uiARGB: _readVertexData4uiRevARGB; } } static ReadAttributeFunc calcReadPositionFunc() { - switch(ATTRIB_POINTERS.vertex.type) { + switch(ATTRIB_LIST.vertex.type) { default: case GL_DOUBLE: case GL_FLOAT: - return (ATTRIB_POINTERS.vertex.size == 3) ? _readVertexData3f3f: + return (ATTRIB_LIST.vertex.size == 3) ? _readVertexData3f3f: _readVertexData2f3f; case GL_BYTE: case GL_UNSIGNED_BYTE: - return (ATTRIB_POINTERS.vertex.size == 3) ? _readVertexData3ub3f: + return (ATTRIB_LIST.vertex.size == 3) ? _readVertexData3ub3f: _readVertexData2ub3f; case GL_SHORT: case GL_UNSIGNED_SHORT: - return (ATTRIB_POINTERS.vertex.size == 3) ? _readVertexData3us3f: + return (ATTRIB_LIST.vertex.size == 3) ? _readVertexData3us3f: _readVertexData2us3f; case GL_INT: case GL_UNSIGNED_INT: - return (ATTRIB_POINTERS.vertex.size == 3) ? _readVertexData3ui3f: + return (ATTRIB_LIST.vertex.size == 3) ? _readVertexData3ui3f: _readVertexData2ui3f; } } static ReadAttributeFunc calcReadUVFunc() { - if((ENABLED_VERTEX_ATTRIBUTES & UV_ENABLED_FLAG) != UV_ENABLED_FLAG) { + if((ATTRIB_LIST.enabled & UV_ENABLED_FLAG) != UV_ENABLED_FLAG) { return _fillZero2f; } - switch(ATTRIB_POINTERS.uv.type) { + switch(ATTRIB_LIST.uv.type) { default: case GL_DOUBLE: case GL_FLOAT: @@ -332,11 +331,11 @@ static ReadAttributeFunc calcReadUVFunc() { } static ReadAttributeFunc calcReadSTFunc() { - if((ENABLED_VERTEX_ATTRIBUTES & ST_ENABLED_FLAG) != ST_ENABLED_FLAG) { + if((ATTRIB_LIST.enabled & ST_ENABLED_FLAG) != ST_ENABLED_FLAG) { return _fillZero2f; } - switch(ATTRIB_POINTERS.st.type) { + switch(ATTRIB_LIST.st.type) { default: case GL_DOUBLE: case GL_FLOAT: @@ -354,11 +353,11 @@ static ReadAttributeFunc calcReadSTFunc() { } static ReadAttributeFunc calcReadNormalFunc() { - if((ENABLED_VERTEX_ATTRIBUTES & NORMAL_ENABLED_FLAG) != NORMAL_ENABLED_FLAG) { + if((ATTRIB_LIST.enabled & NORMAL_ENABLED_FLAG) != NORMAL_ENABLED_FLAG) { return _fillWithNegZVE; } - switch(ATTRIB_POINTERS.normal.type) { + switch(ATTRIB_LIST.normal.type) { default: case GL_DOUBLE: case GL_FLOAT: @@ -387,33 +386,29 @@ void APIENTRY glEnableClientState(GLenum cap) { switch(cap) { case GL_VERTEX_ARRAY: - ENABLED_VERTEX_ATTRIBUTES |= VERTEX_ENABLED_FLAG; - ATTRIB_POINTERS.vertex_func = calcReadPositionFunc(); + ATTRIB_LIST.enabled |= VERTEX_ENABLED_FLAG; + ATTRIB_LIST.dirty |= VERTEX_ENABLED_FLAG; break; case GL_COLOR_ARRAY: - ENABLED_VERTEX_ATTRIBUTES |= DIFFUSE_ENABLED_FLAG; - ATTRIB_POINTERS.colour_func = calcReadDiffuseFunc(); + ATTRIB_LIST.enabled |= DIFFUSE_ENABLED_FLAG; + ATTRIB_LIST.dirty |= DIFFUSE_ENABLED_FLAG; break; case GL_NORMAL_ARRAY: - ENABLED_VERTEX_ATTRIBUTES |= NORMAL_ENABLED_FLAG; - ATTRIB_POINTERS.normal_func = calcReadNormalFunc(); + ATTRIB_LIST.enabled |= NORMAL_ENABLED_FLAG; + ATTRIB_LIST.dirty |= NORMAL_ENABLED_FLAG; break; case GL_TEXTURE_COORD_ARRAY: (ACTIVE_CLIENT_TEXTURE) ? - (ENABLED_VERTEX_ATTRIBUTES |= ST_ENABLED_FLAG): - (ENABLED_VERTEX_ATTRIBUTES |= UV_ENABLED_FLAG); + (ATTRIB_LIST.enabled |= ST_ENABLED_FLAG): + (ATTRIB_LIST.enabled |= UV_ENABLED_FLAG); - ATTRIB_POINTERS.uv_func = calcReadUVFunc(); - ATTRIB_POINTERS.st_func = calcReadSTFunc(); + (ACTIVE_CLIENT_TEXTURE) ? + (ATTRIB_LIST.dirty |= ST_ENABLED_FLAG): + (ATTRIB_LIST.dirty |= UV_ENABLED_FLAG); break; default: _glKosThrowError(GL_INVALID_ENUM, __func__); } - - /* It's possible that we called glVertexPointer and friends before - * calling glEnableClientState, so we should recheck to make sure - * everything is in the right format with this new information */ - _glRecalcFastPath(); } void APIENTRY glDisableClientState(GLenum cap) { @@ -421,31 +416,29 @@ void APIENTRY glDisableClientState(GLenum cap) { switch(cap) { case GL_VERTEX_ARRAY: - ENABLED_VERTEX_ATTRIBUTES &= ~VERTEX_ENABLED_FLAG; - ATTRIB_POINTERS.vertex_func = calcReadPositionFunc(); + ATTRIB_LIST.enabled &= ~VERTEX_ENABLED_FLAG; + ATTRIB_LIST.dirty |= VERTEX_ENABLED_FLAG; break; case GL_COLOR_ARRAY: - ENABLED_VERTEX_ATTRIBUTES &= ~DIFFUSE_ENABLED_FLAG; - ATTRIB_POINTERS.colour_func = calcReadDiffuseFunc(); + ATTRIB_LIST.enabled &= ~DIFFUSE_ENABLED_FLAG; + ATTRIB_LIST.dirty |= DIFFUSE_ENABLED_FLAG; break; case GL_NORMAL_ARRAY: - ENABLED_VERTEX_ATTRIBUTES &= ~NORMAL_ENABLED_FLAG; - ATTRIB_POINTERS.normal_func = calcReadNormalFunc(); + ATTRIB_LIST.enabled &= ~NORMAL_ENABLED_FLAG; + ATTRIB_LIST.dirty |= NORMAL_ENABLED_FLAG; break; case GL_TEXTURE_COORD_ARRAY: (ACTIVE_CLIENT_TEXTURE) ? - (ENABLED_VERTEX_ATTRIBUTES &= ~ST_ENABLED_FLAG): - (ENABLED_VERTEX_ATTRIBUTES &= ~UV_ENABLED_FLAG); + (ATTRIB_LIST.enabled &= ~ST_ENABLED_FLAG): + (ATTRIB_LIST.enabled &= ~UV_ENABLED_FLAG); - ATTRIB_POINTERS.uv_func = calcReadUVFunc(); - ATTRIB_POINTERS.st_func = calcReadSTFunc(); + (ACTIVE_CLIENT_TEXTURE) ? + (ATTRIB_LIST.dirty |= ST_ENABLED_FLAG): + (ATTRIB_LIST.dirty |= UV_ENABLED_FLAG); break; default: _glKosThrowError(GL_INVALID_ENUM, __func__); } - - /* State changed, recalculate */ - _glRecalcFastPath(); } @@ -453,7 +446,7 @@ void APIENTRY glTexCoordPointer(GLint size, GLenum type, GLsizei stride, const G TRACE(); stride = (stride) ? stride : size * byte_size(type); - AttribPointer* tointer = (ACTIVE_CLIENT_TEXTURE == 0) ? &ATTRIB_POINTERS.uv : &ATTRIB_POINTERS.st; + AttribPointer* tointer = (ACTIVE_CLIENT_TEXTURE == 0) ? &ATTRIB_LIST.uv : &ATTRIB_LIST.st; tointer->ptr = pointer; if(_glStateUnchanged(tointer, size, type, stride)) return; @@ -467,51 +460,49 @@ void APIENTRY glTexCoordPointer(GLint size, GLenum type, GLsizei stride, const G tointer->type = type; tointer->size = size; - ATTRIB_POINTERS.uv_func = calcReadUVFunc(); - ATTRIB_POINTERS.st_func = calcReadSTFunc(); - _glRecalcFastPath(); + (ACTIVE_CLIENT_TEXTURE) ? + (ATTRIB_LIST.dirty |= ST_ENABLED_FLAG): + (ATTRIB_LIST.dirty |= UV_ENABLED_FLAG); } void APIENTRY glVertexPointer(GLint size, GLenum type, GLsizei stride, const GLvoid * pointer) { TRACE(); stride = (stride) ? stride : (size * byte_size(type)); - ATTRIB_POINTERS.vertex.ptr = pointer; + ATTRIB_LIST.vertex.ptr = pointer; - if(_glStateUnchanged(&ATTRIB_POINTERS.vertex, size, type, stride)) return; + if(_glStateUnchanged(&ATTRIB_LIST.vertex, size, type, stride)) return; if(size < 2 || size > 4) { _glKosThrowError(GL_INVALID_VALUE, __func__); return; } - ATTRIB_POINTERS.vertex.stride = stride; - ATTRIB_POINTERS.vertex.type = type; - ATTRIB_POINTERS.vertex.size = size; - ATTRIB_POINTERS.vertex_func = calcReadPositionFunc(); + ATTRIB_LIST.vertex.stride = stride; + ATTRIB_LIST.vertex.type = type; + ATTRIB_LIST.vertex.size = size; - _glRecalcFastPath(); + ATTRIB_LIST.dirty |= VERTEX_ENABLED_FLAG; } void APIENTRY glColorPointer(GLint size, GLenum type, GLsizei stride, const GLvoid * pointer) { TRACE(); stride = (stride) ? stride : ((size == GL_BGRA) ? 4 : size) * byte_size(type); - ATTRIB_POINTERS.colour.ptr = pointer; + ATTRIB_LIST.colour.ptr = pointer; - if(_glStateUnchanged(&ATTRIB_POINTERS.colour, size, type, stride)) return; + if(_glStateUnchanged(&ATTRIB_LIST.colour, size, type, stride)) return; if(size != 3 && size != 4 && size != GL_BGRA) { _glKosThrowError(GL_INVALID_VALUE, __func__); return; } - ATTRIB_POINTERS.colour.type = type; - ATTRIB_POINTERS.colour.size = size; - ATTRIB_POINTERS.colour.stride = stride; - ATTRIB_POINTERS.colour_func = calcReadDiffuseFunc(); + ATTRIB_LIST.colour.type = type; + ATTRIB_LIST.colour.size = size; + ATTRIB_LIST.colour.stride = stride; - _glRecalcFastPath(); + ATTRIB_LIST.dirty |= DIFFUSE_ENABLED_FLAG; } void APIENTRY glNormalPointer(GLenum type, GLsizei stride, const GLvoid * pointer) { @@ -528,29 +519,102 @@ void APIENTRY glNormalPointer(GLenum type, GLsizei stride, const GLvoid * poin 0 }; - stride = (stride) ? stride : ATTRIB_POINTERS.normal.size * byte_size(type); - ATTRIB_POINTERS.normal.ptr = pointer; + stride = (stride) ? stride : ATTRIB_LIST.normal.size * byte_size(type); + ATTRIB_LIST.normal.ptr = pointer; - if(_glStateUnchanged(&ATTRIB_POINTERS.normal, 3, type, stride)) return; + if(_glStateUnchanged(&ATTRIB_LIST.normal, 3, type, stride)) return; if(_glCheckValidEnum(type, validTypes, __func__) != 0) { return; } - ATTRIB_POINTERS.normal.size = (type == GL_UNSIGNED_INT_2_10_10_10_REV) ? 1 : 3; - ATTRIB_POINTERS.normal.stride = stride; - ATTRIB_POINTERS.normal.type = type; - ATTRIB_POINTERS.normal_func = calcReadNormalFunc(); + ATTRIB_LIST.normal.size = (type == GL_UNSIGNED_INT_2_10_10_10_REV) ? 1 : 3; + ATTRIB_LIST.normal.stride = stride; + ATTRIB_LIST.normal.type = type; - _glRecalcFastPath(); + ATTRIB_LIST.dirty |= NORMAL_ENABLED_FLAG; } void _glInitAttributePointers() { TRACE(); + ATTRIB_LIST.dirty = ~0; // all attributes dirty - glVertexPointer(4, GL_FLOAT, 0, NULL); + glVertexPointer(3, GL_FLOAT, 0, NULL); glTexCoordPointer(2, GL_FLOAT, 0, NULL); glColorPointer(4, GL_FLOAT, 0, NULL); glNormalPointer(GL_FLOAT, 0, NULL); } + +GL_FORCE_INLINE GLuint _glIsVertexDataFastPathCompatible() { + /* The fast path is enabled when all enabled elements of the vertex + * match the output format. This means: + * + * xyz == 3f + * uv == 2f + * rgba == argb4444 + * st == 2f + * normal == 3f + * + * When this happens we do inline straight copies of the enabled data + * and transforms for positions and normals happen while copying. + */ + + if((ATTRIB_LIST.enabled & VERTEX_ENABLED_FLAG)) { + if(ATTRIB_LIST.vertex.size != 3 || ATTRIB_LIST.vertex.type != GL_FLOAT) { + return GL_FALSE; + } + } + + if((ATTRIB_LIST.enabled & UV_ENABLED_FLAG)) { + if(ATTRIB_LIST.uv.size != 2 || ATTRIB_LIST.uv.type != GL_FLOAT) { + return GL_FALSE; + } + } + + if((ATTRIB_LIST.enabled & DIFFUSE_ENABLED_FLAG)) { + /* FIXME: Shouldn't this be a reversed format? */ + if(ATTRIB_LIST.colour.size != GL_BGRA || ATTRIB_LIST.colour.type != GL_UNSIGNED_BYTE) { + return GL_FALSE; + } + } + + if((ATTRIB_LIST.enabled & ST_ENABLED_FLAG)) { + if(ATTRIB_LIST.st.size != 2 || ATTRIB_LIST.st.type != GL_FLOAT) { + return GL_FALSE; + } + } + + if((ATTRIB_LIST.enabled & NORMAL_ENABLED_FLAG)) { + if(ATTRIB_LIST.normal.size != 3 || ATTRIB_LIST.normal.type != GL_FLOAT) { + return GL_FALSE; + } + } + + return GL_TRUE; +} + +void _glUpdateAttributes() { + if(ATTRIB_LIST.dirty & VERTEX_ENABLED_FLAG) { + ATTRIB_LIST.vertex_func = calcReadPositionFunc(); + } + + if(ATTRIB_LIST.dirty & UV_ENABLED_FLAG) { + ATTRIB_LIST.uv_func = calcReadUVFunc(); + } + + if(ATTRIB_LIST.dirty & DIFFUSE_ENABLED_FLAG) { + ATTRIB_LIST.colour_func = calcReadDiffuseFunc(); + } + + if(ATTRIB_LIST.dirty & ST_ENABLED_FLAG) { + ATTRIB_LIST.st_func = calcReadSTFunc(); + } + + if(ATTRIB_LIST.dirty & NORMAL_ENABLED_FLAG) { + ATTRIB_LIST.normal_func = calcReadNormalFunc(); + } + + ATTRIB_LIST.fast_path = _glIsVertexDataFastPathCompatible(); + ATTRIB_LIST.dirty = 0; +} diff --git a/GL/draw.c b/GL/draw.c index 514d03c..98b5cfd 100644 --- a/GL/draw.c +++ b/GL/draw.c @@ -8,7 +8,6 @@ #include "private.h" #include "platform.h" -GLuint FAST_PATH_ENABLED = GL_FALSE; GLubyte ACTIVE_CLIENT_TEXTURE; extern GLboolean AUTOSORT_ENABLED; @@ -286,9 +285,9 @@ static GL_NO_INLINE void genLineLoop(Vertex* output, GLuint count) { } static void _readPositionData(const GLuint first, const GLuint count, Vertex* it) { - const ReadAttributeFunc func = ATTRIB_POINTERS.vertex_func; - const GLsizei vstride = ATTRIB_POINTERS.vertex.stride; - const GLubyte* vptr = ((GLubyte*) ATTRIB_POINTERS.vertex.ptr + (first * vstride)); + const ReadAttributeFunc func = ATTRIB_LIST.vertex_func; + const GLsizei vstride = ATTRIB_LIST.vertex.stride; + const GLubyte* vptr = ((GLubyte*) ATTRIB_LIST.vertex.ptr + (first * vstride)); float pos[3], w = 1.0f; @@ -304,9 +303,9 @@ static void _readPositionData(const GLuint first, const GLuint count, Vertex* it } static void _readUVData(const GLuint first, const GLuint count, Vertex* it) { - const ReadAttributeFunc func = ATTRIB_POINTERS.uv_func; - const GLsizei uvstride = ATTRIB_POINTERS.uv.stride; - const GLubyte* uvptr = ((GLubyte*) ATTRIB_POINTERS.uv.ptr + (first * uvstride)); + const ReadAttributeFunc func = ATTRIB_LIST.uv_func; + const GLsizei uvstride = ATTRIB_LIST.uv.stride; + const GLubyte* uvptr = ((GLubyte*) ATTRIB_LIST.uv.ptr + (first * uvstride)); ITERATE(count) { PREFETCH(uvptr + uvstride); @@ -318,9 +317,9 @@ static void _readUVData(const GLuint first, const GLuint count, Vertex* it) { } static void _readSTData(const GLuint first, const GLuint count, VertexExtra* it) { - const ReadAttributeFunc func = ATTRIB_POINTERS.st_func; - const GLsizei ststride = ATTRIB_POINTERS.st.stride; - const GLubyte* stptr = ((GLubyte*) ATTRIB_POINTERS.st.ptr + (first * ststride)); + const ReadAttributeFunc func = ATTRIB_LIST.st_func; + const GLsizei ststride = ATTRIB_LIST.st.stride; + const GLubyte* stptr = ((GLubyte*) ATTRIB_LIST.st.ptr + (first * ststride)); ITERATE(count) { PREFETCH(stptr + ststride); @@ -331,9 +330,9 @@ static void _readSTData(const GLuint first, const GLuint count, VertexExtra* it) } static void _readNormalData(const GLuint first, const GLuint count, VertexExtra* it) { - const ReadAttributeFunc func = ATTRIB_POINTERS.normal_func; - const GLsizei nstride = ATTRIB_POINTERS.normal.stride; - const GLubyte* nptr = ((GLubyte*) ATTRIB_POINTERS.normal.ptr + (first * nstride)); + const ReadAttributeFunc func = ATTRIB_LIST.normal_func; + const GLsizei nstride = ATTRIB_LIST.normal.stride; + const GLubyte* nptr = ((GLubyte*) ATTRIB_LIST.normal.ptr + (first * nstride)); ITERATE(count) { func(nptr, (GLubyte*) it->nxyz); @@ -356,9 +355,9 @@ static void _readNormalData(const GLuint first, const GLuint count, VertexExtra* } static void _readDiffuseData(const GLuint first, const GLuint count, Vertex* it) { - const ReadAttributeFunc func = ATTRIB_POINTERS.colour_func; - const GLuint cstride = ATTRIB_POINTERS.colour.stride; - const GLubyte* cptr = ((GLubyte*) ATTRIB_POINTERS.colour.ptr) + (first * cstride); + const ReadAttributeFunc func = ATTRIB_LIST.colour_func; + const GLuint cstride = ATTRIB_LIST.colour.stride; + const GLubyte* cptr = ((GLubyte*) ATTRIB_LIST.colour.ptr) + (first * cstride); ITERATE(count) { PREFETCH(cptr + cstride); @@ -388,29 +387,29 @@ static void generateElements( uint32_t i = first; uint32_t idx = 0; - const ReadAttributeFunc pos_func = ATTRIB_POINTERS.vertex_func; - const GLsizei vstride = ATTRIB_POINTERS.vertex.stride; + const ReadAttributeFunc pos_func = ATTRIB_LIST.vertex_func; + const GLsizei vstride = ATTRIB_LIST.vertex.stride; - const ReadAttributeFunc uv_func = ATTRIB_POINTERS.uv_func; - const GLuint uvstride = ATTRIB_POINTERS.uv.stride; + const ReadAttributeFunc uv_func = ATTRIB_LIST.uv_func; + const GLuint uvstride = ATTRIB_LIST.uv.stride; - const ReadAttributeFunc st_func = ATTRIB_POINTERS.st_func; - const GLuint ststride = ATTRIB_POINTERS.st.stride; + const ReadAttributeFunc st_func = ATTRIB_LIST.st_func; + const GLuint ststride = ATTRIB_LIST.st.stride; - const ReadAttributeFunc diffuse_func = ATTRIB_POINTERS.colour_func; - const GLuint dstride = ATTRIB_POINTERS.colour.stride; + const ReadAttributeFunc diffuse_func = ATTRIB_LIST.colour_func; + const GLuint dstride = ATTRIB_LIST.colour.stride; - const ReadAttributeFunc normal_func = ATTRIB_POINTERS.normal_func; - const GLuint nstride = ATTRIB_POINTERS.normal.stride; + const ReadAttributeFunc normal_func = ATTRIB_LIST.normal_func; + const GLuint nstride = ATTRIB_LIST.normal.stride; for(; i < first + count; ++i) { idx = IndexFunc(indices + (i * istride)); - xyz = (GLubyte*) ATTRIB_POINTERS.vertex.ptr + (idx * vstride); - uv = (GLubyte*) ATTRIB_POINTERS.uv.ptr + (idx * uvstride); - bgra = (GLubyte*) ATTRIB_POINTERS.colour.ptr + (idx * dstride); - st = (GLubyte*) ATTRIB_POINTERS.st.ptr + (idx * ststride); - nxyz = (GLubyte*) ATTRIB_POINTERS.normal.ptr + (idx * nstride); + xyz = (GLubyte*) ATTRIB_LIST.vertex.ptr + (idx * vstride); + uv = (GLubyte*) ATTRIB_LIST.uv.ptr + (idx * uvstride); + bgra = (GLubyte*) ATTRIB_LIST.colour.ptr + (idx * dstride); + st = (GLubyte*) ATTRIB_LIST.st.ptr + (idx * ststride); + nxyz = (GLubyte*) ATTRIB_LIST.normal.ptr + (idx * nstride); pos_func(xyz, (GLubyte*) pos); TransformVertex((const float*) pos, &w, output->xyz, &output->w); @@ -442,21 +441,21 @@ static void generateElementsFastPath( Vertex* start = _glSubmissionTargetStart(target); - const GLuint vstride = ATTRIB_POINTERS.vertex.stride; - const GLuint uvstride = ATTRIB_POINTERS.uv.stride; - const GLuint ststride = ATTRIB_POINTERS.st.stride; - const GLuint dstride = ATTRIB_POINTERS.colour.stride; - const GLuint nstride = ATTRIB_POINTERS.normal.stride; + const GLuint vstride = ATTRIB_LIST.vertex.stride; + const GLuint uvstride = ATTRIB_LIST.uv.stride; + const GLuint ststride = ATTRIB_LIST.st.stride; + const GLuint dstride = ATTRIB_LIST.colour.stride; + const GLuint nstride = ATTRIB_LIST.normal.stride; const GLsizei istride = index_size(type); const IndexParseFunc IndexFunc = _calcParseIndexFunc(type); /* Copy the pos, uv and color directly in one go */ - const GLubyte* pos = (ENABLED_VERTEX_ATTRIBUTES & VERTEX_ENABLED_FLAG) ? ATTRIB_POINTERS.vertex.ptr : NULL; - const GLubyte* uv = (ENABLED_VERTEX_ATTRIBUTES & UV_ENABLED_FLAG) ? ATTRIB_POINTERS.uv.ptr : NULL; - const GLubyte* col = (ENABLED_VERTEX_ATTRIBUTES & DIFFUSE_ENABLED_FLAG) ? ATTRIB_POINTERS.colour.ptr : NULL; - const GLubyte* st = (ENABLED_VERTEX_ATTRIBUTES & ST_ENABLED_FLAG) ? ATTRIB_POINTERS.st.ptr : NULL; - const GLubyte* n = (ENABLED_VERTEX_ATTRIBUTES & NORMAL_ENABLED_FLAG) ? ATTRIB_POINTERS.normal.ptr : NULL; + const GLubyte* pos = (ATTRIB_LIST.enabled & VERTEX_ENABLED_FLAG) ? ATTRIB_LIST.vertex.ptr : NULL; + const GLubyte* uv = (ATTRIB_LIST.enabled & UV_ENABLED_FLAG) ? ATTRIB_LIST.uv.ptr : NULL; + const GLubyte* col = (ATTRIB_LIST.enabled & DIFFUSE_ENABLED_FLAG) ? ATTRIB_LIST.colour.ptr : NULL; + const GLubyte* st = (ATTRIB_LIST.enabled & ST_ENABLED_FLAG) ? ATTRIB_LIST.st.ptr : NULL; + const GLubyte* n = (ATTRIB_LIST.enabled & NORMAL_ENABLED_FLAG) ? ATTRIB_LIST.normal.ptr : NULL; VertexExtra* ve = aligned_vector_at(target->extras, 0); Vertex* it = start; @@ -472,32 +471,32 @@ static void generateElementsFastPath( it->flags = GPU_CMD_VERTEX; - pos = (GLubyte*) ATTRIB_POINTERS.vertex.ptr + (idx * vstride); + pos = (GLubyte*) ATTRIB_LIST.vertex.ptr + (idx * vstride); TransformVertex((const float*) pos, &w, it->xyz, &it->w); if(uv) { - uv = (GLubyte*) ATTRIB_POINTERS.uv.ptr + (idx * uvstride); + uv = (GLubyte*) ATTRIB_LIST.uv.ptr + (idx * uvstride); MEMCPY4(it->uv, uv, sizeof(float) * 2); } else { *((Float2*) it->uv) = F2ZERO; } if(col) { - col = (GLubyte*) ATTRIB_POINTERS.colour.ptr + (idx * dstride); + col = (GLubyte*) ATTRIB_LIST.colour.ptr + (idx * dstride); MEMCPY4(it->bgra, col, sizeof(uint32_t)); } else { *((uint32_t*) it->bgra) = ~0; } if(st) { - st = (GLubyte*) ATTRIB_POINTERS.st.ptr + (idx * ststride); + st = (GLubyte*) ATTRIB_LIST.st.ptr + (idx * ststride); MEMCPY4(ve->st, st, sizeof(float) * 2); } else { *((Float2*) ve->st) = F2ZERO; } if(n) { - n = (GLubyte*) ATTRIB_POINTERS.normal.ptr + (idx * nstride); + n = (GLubyte*) ATTRIB_LIST.normal.ptr + (idx * nstride); MEMCPY4(ve->nxyz, n, sizeof(float) * 3); } else { *((Float3*) ve->nxyz) = F3Z; @@ -558,7 +557,7 @@ static void generate(SubmissionTarget* target, const GLenum mode, const GLsizei /* Read from the client buffers and generate an array of ClipVertices */ TRACE(); - if(FAST_PATH_ENABLED) { + if(ATTRIB_LIST.fast_path) { if(indices) { generateElementsFastPath(target, first, count, indices, type); } else { @@ -834,7 +833,8 @@ GL_FORCE_INLINE void submitVertices(GLenum mode, GLsizei first, GLuint count, GL TRACE(); /* Do nothing if vertices aren't enabled */ - if(!(ENABLED_VERTEX_ATTRIBUTES & VERTEX_ENABLED_FLAG)) return; + if(!(ATTRIB_LIST.enabled & VERTEX_ENABLED_FLAG)) return; + if(ATTRIB_LIST.dirty) _glUpdateAttributes(); /* No vertices? Do nothing */ if(!count) return; @@ -924,7 +924,7 @@ GL_FORCE_INLINE void submitVertices(GLenum mode, GLsizei first, GLuint count, GL // TextureObject* texture1 = _glGetTexture1(); // /* Multitexture implicitly disabled */ - // if(!texture1 || ((ENABLED_VERTEX_ATTRIBUTES & ST_ENABLED_FLAG) != ST_ENABLED_FLAG)) { + // if(!texture1 || ((ATTRIB_LIST.enabled & ST_ENABLED_FLAG) != ST_ENABLED_FLAG)) { // /* Multitexture actively disabled */ // return; // } diff --git a/GL/draw_fastpath.inc b/GL/draw_fastpath.inc index 8ea3514..b26e6a9 100644 --- a/GL/draw_fastpath.inc +++ b/GL/draw_fastpath.inc @@ -6,7 +6,7 @@ MAKE_FUNC(POLYMODE) { static const float w = 1.0f; - if(!(ENABLED_VERTEX_ATTRIBUTES & VERTEX_ENABLED_FLAG)) { + if(!(ATTRIB_LIST.enabled & VERTEX_ENABLED_FLAG)) { /* If we don't have vertices, do nothing */ return; } @@ -29,8 +29,8 @@ MAKE_FUNC(POLYMODE) const int_fast32_t loop = ((min + BATCH_SIZE) > count) ? count - min : BATCH_SIZE; const int offset = (first + min); - stride = ATTRIB_POINTERS.uv.stride; - ptr = (ENABLED_VERTEX_ATTRIBUTES & UV_ENABLED_FLAG) ? ATTRIB_POINTERS.uv.ptr + ((first + min) * stride) : NULL; + stride = ATTRIB_LIST.uv.stride; + ptr = (ATTRIB_LIST.enabled & UV_ENABLED_FLAG) ? ATTRIB_LIST.uv.ptr + ((first + min) * stride) : NULL; it = (Vertex*) start; if(ptr) { @@ -48,8 +48,8 @@ MAKE_FUNC(POLYMODE) } } - stride = ATTRIB_POINTERS.colour.stride; - ptr = (ENABLED_VERTEX_ATTRIBUTES & DIFFUSE_ENABLED_FLAG) ? ATTRIB_POINTERS.colour.ptr + (offset * stride) : NULL; + stride = ATTRIB_LIST.colour.stride; + ptr = (ATTRIB_LIST.enabled & DIFFUSE_ENABLED_FLAG) ? ATTRIB_LIST.colour.ptr + (offset * stride) : NULL; it = (Vertex*) start; if(ptr) { @@ -68,8 +68,8 @@ MAKE_FUNC(POLYMODE) } } - stride = ATTRIB_POINTERS.vertex.stride; - ptr = ATTRIB_POINTERS.vertex.ptr + (offset * stride); + stride = ATTRIB_LIST.vertex.stride; + ptr = ATTRIB_LIST.vertex.ptr + (offset * stride); it = (Vertex*) start; PREFETCH(ptr); @@ -82,8 +82,8 @@ MAKE_FUNC(POLYMODE) start = aligned_vector_at(target->extras, min); - stride = ATTRIB_POINTERS.st.stride; - ptr = (ENABLED_VERTEX_ATTRIBUTES & ST_ENABLED_FLAG) ? ATTRIB_POINTERS.st.ptr + (offset * stride) : NULL; + stride = ATTRIB_LIST.st.stride; + ptr = (ATTRIB_LIST.enabled & ST_ENABLED_FLAG) ? ATTRIB_LIST.st.ptr + (offset * stride) : NULL; ve = (VertexExtra*) start; if(ptr) { @@ -102,8 +102,8 @@ MAKE_FUNC(POLYMODE) } } - stride = ATTRIB_POINTERS.normal.stride; - ptr = (ENABLED_VERTEX_ATTRIBUTES & NORMAL_ENABLED_FLAG) ? ATTRIB_POINTERS.normal.ptr + (offset * stride) : NULL; + stride = ATTRIB_LIST.normal.stride; + ptr = (ATTRIB_LIST.enabled & NORMAL_ENABLED_FLAG) ? ATTRIB_LIST.normal.ptr + (offset * stride) : NULL; ve = (VertexExtra*) start; if(ptr) { diff --git a/GL/immediate.c b/GL/immediate.c index df17635..971d92d 100644 --- a/GL/immediate.c +++ b/GL/immediate.c @@ -12,8 +12,6 @@ #include "private.h" -extern inline GLuint _glRecalcFastPath(); - GLboolean IMMEDIATE_MODE_ACTIVE = GL_FALSE; static GLenum ACTIVE_POLYGON_MODE = GL_TRIANGLES; @@ -49,6 +47,7 @@ typedef struct __attribute__((aligned(32))) { void _glInitImmediateMode(GLuint initial_size) { aligned_vector_init(&VERTICES, sizeof(IMVertex)); aligned_vector_reserve(&VERTICES, initial_size); + IM_ATTRIBS.fast_path = GL_TRUE; IM_ATTRIBS.vertex.ptr = aligned_vector_front(&VERTICES); IM_ATTRIBS.vertex.size = 3; @@ -87,7 +86,7 @@ void APIENTRY glBegin(GLenum mode) { } void APIENTRY glColor4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a) { - IM_ENABLED_VERTEX_ATTRIBUTES |= DIFFUSE_ENABLED_FLAG; + IM_ATTRIBS.enabled |= DIFFUSE_ENABLED_FLAG; COLOR[A8IDX] = (GLubyte)(a * 255.0f); COLOR[R8IDX] = (GLubyte)(r * 255.0f); @@ -96,7 +95,7 @@ void APIENTRY glColor4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a) { } void APIENTRY glColor4ub(GLubyte r, GLubyte g, GLubyte b, GLubyte a) { - IM_ENABLED_VERTEX_ATTRIBUTES |= DIFFUSE_ENABLED_FLAG; + IM_ATTRIBS.enabled |= DIFFUSE_ENABLED_FLAG; COLOR[A8IDX] = a; COLOR[R8IDX] = r; @@ -105,7 +104,7 @@ void APIENTRY glColor4ub(GLubyte r, GLubyte g, GLubyte b, GLubyte a) { } void APIENTRY glColor4ubv(const GLubyte *v) { - IM_ENABLED_VERTEX_ATTRIBUTES |= DIFFUSE_ENABLED_FLAG; + IM_ATTRIBS.enabled |= DIFFUSE_ENABLED_FLAG; COLOR[A8IDX] = v[3]; COLOR[R8IDX] = v[0]; @@ -114,7 +113,7 @@ void APIENTRY glColor4ubv(const GLubyte *v) { } void APIENTRY glColor4fv(const GLfloat* v) { - IM_ENABLED_VERTEX_ATTRIBUTES |= DIFFUSE_ENABLED_FLAG; + IM_ATTRIBS.enabled |= DIFFUSE_ENABLED_FLAG; COLOR[B8IDX] = (GLubyte)(v[2] * 255); COLOR[G8IDX] = (GLubyte)(v[1] * 255); @@ -123,7 +122,7 @@ void APIENTRY glColor4fv(const GLfloat* v) { } void APIENTRY glColor3f(GLfloat r, GLfloat g, GLfloat b) { - IM_ENABLED_VERTEX_ATTRIBUTES |= DIFFUSE_ENABLED_FLAG; + IM_ATTRIBS.enabled |= DIFFUSE_ENABLED_FLAG; COLOR[B8IDX] = (GLubyte)(b * 255.0f); COLOR[G8IDX] = (GLubyte)(g * 255.0f); @@ -132,7 +131,7 @@ void APIENTRY glColor3f(GLfloat r, GLfloat g, GLfloat b) { } void APIENTRY glColor3ub(GLubyte red, GLubyte green, GLubyte blue) { - IM_ENABLED_VERTEX_ATTRIBUTES |= DIFFUSE_ENABLED_FLAG; + IM_ATTRIBS.enabled |= DIFFUSE_ENABLED_FLAG; COLOR[A8IDX] = 255; COLOR[R8IDX] = red; @@ -141,7 +140,7 @@ void APIENTRY glColor3ub(GLubyte red, GLubyte green, GLubyte blue) { } void APIENTRY glColor3ubv(const GLubyte *v) { - IM_ENABLED_VERTEX_ATTRIBUTES |= DIFFUSE_ENABLED_FLAG; + IM_ATTRIBS.enabled |= DIFFUSE_ENABLED_FLAG; COLOR[A8IDX] = 255; COLOR[R8IDX] = v[0]; @@ -150,7 +149,7 @@ void APIENTRY glColor3ubv(const GLubyte *v) { } void APIENTRY glColor3fv(const GLfloat* v) { - IM_ENABLED_VERTEX_ATTRIBUTES |= DIFFUSE_ENABLED_FLAG; + IM_ATTRIBS.enabled |= DIFFUSE_ENABLED_FLAG; COLOR[A8IDX] = 255; COLOR[R8IDX] = (GLubyte)(v[0] * 255); @@ -167,7 +166,7 @@ typedef union punned { } punned_t; void APIENTRY glVertex3f(GLfloat x, GLfloat y, GLfloat z) { - IM_ENABLED_VERTEX_ATTRIBUTES |= VERTEX_ENABLED_FLAG; + IM_ATTRIBS.enabled |= VERTEX_ENABLED_FLAG; IMVertex* vert = aligned_vector_extend(&VERTICES, 1); @@ -208,11 +207,11 @@ void APIENTRY glVertex4fv(const GLfloat* v) { void APIENTRY glMultiTexCoord2fARB(GLenum target, GLfloat s, GLfloat t) { if(target == GL_TEXTURE0) { - IM_ENABLED_VERTEX_ATTRIBUTES |= UV_ENABLED_FLAG; + IM_ATTRIBS.enabled |= UV_ENABLED_FLAG; UV_COORD[0] = s; UV_COORD[1] = t; } else if(target == GL_TEXTURE1) { - IM_ENABLED_VERTEX_ATTRIBUTES |= ST_ENABLED_FLAG; + IM_ATTRIBS.enabled |= ST_ENABLED_FLAG; ST_COORD[0] = s; ST_COORD[1] = t; } else { @@ -222,7 +221,7 @@ void APIENTRY glMultiTexCoord2fARB(GLenum target, GLfloat s, GLfloat t) { } void APIENTRY glTexCoord1f(GLfloat u) { - IM_ENABLED_VERTEX_ATTRIBUTES |= UV_ENABLED_FLAG; + IM_ATTRIBS.enabled |= UV_ENABLED_FLAG; UV_COORD[0] = u; UV_COORD[1] = 0.0f; } @@ -232,7 +231,7 @@ void APIENTRY glTexCoord1fv(const GLfloat* v) { } void APIENTRY glTexCoord2f(GLfloat u, GLfloat v) { - IM_ENABLED_VERTEX_ATTRIBUTES |= UV_ENABLED_FLAG; + IM_ATTRIBS.enabled |= UV_ENABLED_FLAG; UV_COORD[0] = u; UV_COORD[1] = v; } @@ -242,7 +241,7 @@ void APIENTRY glTexCoord2fv(const GLfloat* v) { } void APIENTRY glNormal3f(GLfloat x, GLfloat y, GLfloat z) { - IM_ENABLED_VERTEX_ATTRIBUTES |= NORMAL_ENABLED_FLAG; + IM_ATTRIBS.enabled |= NORMAL_ENABLED_FLAG; NORMAL[0] = x; NORMAL[1] = y; NORMAL[2] = z; @@ -262,38 +261,15 @@ void APIENTRY glEnd() { IM_ATTRIBS.colour.ptr = IM_ATTRIBS.st.ptr + 8; IM_ATTRIBS.normal.ptr = IM_ATTRIBS.colour.ptr + 4; - GLuint* attrs = &ENABLED_VERTEX_ATTRIBUTES; - - /* Redirect attrib pointers */ - AttribPointerList stashed_attrib_pointers = ATTRIB_POINTERS; - ATTRIB_POINTERS = IM_ATTRIBS; - - GLuint prevAttrs = *attrs; - - *attrs = IM_ENABLED_VERTEX_ATTRIBUTES; - - /* Store the fast path enabled setting so we can restore it - * after drawing */ - const GLboolean fp_was_enabled = FAST_PATH_ENABLED; - -#ifndef NDEBUG - // Immediate mode should always activate the fast path - GLuint fastPathEnabled = _glRecalcFastPath(); - gl_assert(fastPathEnabled); -#else - /* If we're not debugging, set to true - we assume we haven't broken it! */ - FAST_PATH_ENABLED = GL_TRUE; -#endif - + /* Redirect attrib state */ + AttribPointerList stashed_state = ATTRIB_LIST; + ATTRIB_LIST = IM_ATTRIBS; + glDrawArrays(ACTIVE_POLYGON_MODE, 0, aligned_vector_header(&VERTICES)->size); - ATTRIB_POINTERS = stashed_attrib_pointers; - - *attrs = prevAttrs; + ATTRIB_LIST = stashed_state; aligned_vector_clear(&VERTICES); - - FAST_PATH_ENABLED = fp_was_enabled; } void APIENTRY glRectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2) { diff --git a/GL/private.h b/GL/private.h index bf13e0b..981bff0 100644 --- a/GL/private.h +++ b/GL/private.h @@ -355,6 +355,10 @@ typedef struct { AttribPointer st; // 64 AttribPointer normal; // 80 + GLuint enabled; // list of currently enabled/used attributes + GLuint dirty; // list of attributes that need state recalculating + GLboolean fast_path; + ReadAttributeFunc vertex_func; ReadAttributeFunc colour_func; ReadAttributeFunc uv_func; @@ -362,12 +366,12 @@ typedef struct { ReadAttributeFunc normal_func; } AttribPointerList; -extern GLuint ENABLED_VERTEX_ATTRIBUTES; -extern AttribPointerList ATTRIB_POINTERS; +extern AttribPointerList ATTRIB_LIST; GLboolean _glCheckValidEnum(GLint param, GLint* values, const char* func); GLuint* _glGetEnabledAttributes(); +GL_NO_INLINE void _glUpdateAttributes(); GLenum _glGetShadeModel(); TextureObject* _glGetTexture0(); @@ -427,63 +431,6 @@ GLboolean _glIsColorMaterialEnabled(); GLboolean _glIsNormalizeEnabled(); -extern GLuint FAST_PATH_ENABLED; - -GL_FORCE_INLINE GLuint _glIsVertexDataFastPathCompatible() { - /* The fast path is enabled when all enabled elements of the vertex - * match the output format. This means: - * - * xyz == 3f - * uv == 2f - * rgba == argb4444 - * st == 2f - * normal == 3f - * - * When this happens we do inline straight copies of the enabled data - * and transforms for positions and normals happen while copying. - */ - - - - if((ENABLED_VERTEX_ATTRIBUTES & VERTEX_ENABLED_FLAG)) { - if(ATTRIB_POINTERS.vertex.size != 3 || ATTRIB_POINTERS.vertex.type != GL_FLOAT) { - return GL_FALSE; - } - } - - if((ENABLED_VERTEX_ATTRIBUTES & UV_ENABLED_FLAG)) { - if(ATTRIB_POINTERS.uv.size != 2 || ATTRIB_POINTERS.uv.type != GL_FLOAT) { - return GL_FALSE; - } - } - - if((ENABLED_VERTEX_ATTRIBUTES & DIFFUSE_ENABLED_FLAG)) { - /* FIXME: Shouldn't this be a reversed format? */ - if(ATTRIB_POINTERS.colour.size != GL_BGRA || ATTRIB_POINTERS.colour.type != GL_UNSIGNED_BYTE) { - return GL_FALSE; - } - } - - if((ENABLED_VERTEX_ATTRIBUTES & ST_ENABLED_FLAG)) { - if(ATTRIB_POINTERS.st.size != 2 || ATTRIB_POINTERS.st.type != GL_FLOAT) { - return GL_FALSE; - } - } - - if((ENABLED_VERTEX_ATTRIBUTES & NORMAL_ENABLED_FLAG)) { - if(ATTRIB_POINTERS.normal.size != 3 || ATTRIB_POINTERS.normal.type != GL_FLOAT) { - return GL_FALSE; - } - } - - return GL_TRUE; -} - -GL_FORCE_INLINE GLuint _glRecalcFastPath() { - FAST_PATH_ENABLED = _glIsVertexDataFastPathCompatible(); - return FAST_PATH_ENABLED; -} - extern GLboolean IMMEDIATE_MODE_ACTIVE; extern GLenum LAST_ERROR; From e2fc2da055950551dd810f07506a994feb12de21 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sat, 1 Feb 2025 19:58:22 +1100 Subject: [PATCH 61/72] Move error handling code into the cold path --- GL/error.c | 27 +++++++++++++++++++++++++-- GL/private.h | 31 +------------------------------ 2 files changed, 26 insertions(+), 32 deletions(-) diff --git a/GL/error.c b/GL/error.c index 4eb180d..4fe965e 100644 --- a/GL/error.c +++ b/GL/error.c @@ -12,8 +12,31 @@ #include "private.h" -GLenum LAST_ERROR = GL_NO_ERROR; -char ERROR_FUNCTION[64] = { '\0' }; +static GLenum LAST_ERROR = GL_NO_ERROR; +static char ERROR_FUNCTION[64] = { '\0' }; + +GL_FORCE_INLINE const char* _glErrorEnumAsString(GLenum error) { + switch(error) { + case GL_INVALID_ENUM: return "GL_INVALID_ENUM"; + case GL_OUT_OF_MEMORY: return "GL_OUT_OF_MEMORY"; + case GL_INVALID_OPERATION: return "GL_INVALID_OPERATION"; + case GL_INVALID_VALUE: return "GL_INVALID_VALUE"; + default: + return "GL_UNKNOWN_ERROR"; + } +} + +void _glKosThrowError(GLenum error, const char *function) { + if(LAST_ERROR == GL_NO_ERROR) { + LAST_ERROR = error; + sprintf(ERROR_FUNCTION, "%s\n", function); + fprintf(stderr, "GL ERROR: %s when calling %s\n", _glErrorEnumAsString(LAST_ERROR), ERROR_FUNCTION); + } +} + +GL_FORCE_INLINE void _glKosResetError() { + LAST_ERROR = GL_NO_ERROR; +} /* Quoth the GL Spec: When an error occurs, the error flag is set to the appropriate error code diff --git a/GL/private.h b/GL/private.h index 8230f01..aca0b87 100644 --- a/GL/private.h +++ b/GL/private.h @@ -484,36 +484,7 @@ GL_FORCE_INLINE GLuint _glRecalcFastPath() { extern GLboolean IMMEDIATE_MODE_ACTIVE; -extern GLenum LAST_ERROR; -extern char ERROR_FUNCTION[64]; - -GL_FORCE_INLINE const char* _glErrorEnumAsString(GLenum error) { - switch(error) { - case GL_INVALID_ENUM: return "GL_INVALID_ENUM"; - case GL_OUT_OF_MEMORY: return "GL_OUT_OF_MEMORY"; - case GL_INVALID_OPERATION: return "GL_INVALID_OPERATION"; - case GL_INVALID_VALUE: return "GL_INVALID_VALUE"; - default: - return "GL_UNKNOWN_ERROR"; - } -} - -GL_FORCE_INLINE void _glKosThrowError(GLenum error, const char *function) { - if(LAST_ERROR == GL_NO_ERROR) { - LAST_ERROR = error; - sprintf(ERROR_FUNCTION, "%s\n", function); - fprintf(stderr, "GL ERROR: %s when calling %s\n", _glErrorEnumAsString(LAST_ERROR), ERROR_FUNCTION); - } -} - -GL_FORCE_INLINE GLubyte _glKosHasError() { - return (LAST_ERROR != GL_NO_ERROR) ? GL_TRUE : GL_FALSE; -} - -GL_FORCE_INLINE void _glKosResetError() { - LAST_ERROR = GL_NO_ERROR; - sprintf(ERROR_FUNCTION, "\n"); -} +GL_NO_INLINE void _glKosThrowError(GLenum error, const char *function); GL_FORCE_INLINE GLboolean _glCheckImmediateModeInactive(const char* func) { /* Returns 1 on error */ From e2c3ff0ed6cb36f43c12b8d7a3507d32d5b73c9f Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sat, 1 Feb 2025 20:12:23 +1100 Subject: [PATCH 62/72] Fix not building for desktop --- GL/platforms/software.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GL/platforms/software.h b/GL/platforms/software.h index fbe12be..e93df6d 100644 --- a/GL/platforms/software.h +++ b/GL/platforms/software.h @@ -25,7 +25,7 @@ } while(0) #define VEC3_LENGTH(x, y, z, d) \ - d = MATH_Fast_Sqrt((x) * (x) + (y) * (y) + (z) * (z)) + d = sqrtf((x) * (x) + (y) * (y) + (z) * (z)) #define VEC3_DOT(x1, y1, z1, x2, y2, z2, d) \ d = (x1 * x2) + (y1 * y2) + (z1 * z2) From 9d717800bd63be3ae64e4c77f4eccacc1e07f982 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sun, 2 Feb 2025 13:51:30 +1100 Subject: [PATCH 63/72] Reorganise attribute parsing functions --- GL/attributes.c | 625 +++++++++++++++++++++++++----------------------- 1 file changed, 329 insertions(+), 296 deletions(-) diff --git a/GL/attributes.c b/GL/attributes.c index 607e2f3..703d562 100644 --- a/GL/attributes.c +++ b/GL/attributes.c @@ -36,12 +36,333 @@ GLuint* _glGetEnabledAttributes() { } -static void _readVertexData3f3f(const GLubyte* __restrict__ in, GLubyte* __restrict__ out) { +static void _readPosition3f3f(const GLubyte* __restrict__ in, GLubyte* __restrict__ out) { vec3cpy(out, in); } +static void _readPosition3ub3f(const GLubyte* input, GLubyte* out) { + float* output = (float*) out; + + output[0] = input[0] * ONE_OVER_TWO_FIVE_FIVE; + output[1] = input[1] * ONE_OVER_TWO_FIVE_FIVE; + output[2] = input[2] * ONE_OVER_TWO_FIVE_FIVE; +} + +static void _readPosition3us3f(const GLubyte* in, GLubyte* out) { + const GLushort* input = (const GLushort*) in; + float* output = (float*) out; + + output[0] = input[0]; + output[1] = input[1]; + output[2] = input[2]; +} + +static void _readPosition3ui3f(const GLubyte* in, GLubyte* out) { + const GLuint* input = (const GLuint*) in; + float* output = (float*) out; + + output[0] = input[0]; + output[1] = input[1]; + output[2] = input[2]; +} + +static void _readPosition2f3f(const GLubyte* in, GLubyte* out) { + const float* input = (const float*) in; + float* output = (float*) out; + + vec2cpy(output, input); + output[2] = 0.0f; +} + +static void _readPosition2ub3f(const GLubyte* input, GLubyte* out) { + float* output = (float*) out; + + output[0] = input[0] * ONE_OVER_TWO_FIVE_FIVE; + output[1] = input[1] * ONE_OVER_TWO_FIVE_FIVE; + output[2] = 0.0f; +} + +static void _readPosition2us3f(const GLubyte* in, GLubyte* out) { + const GLushort* input = (const GLushort*) in; + float* output = (float*) out; + + output[0] = input[0]; + output[1] = input[1]; + output[2] = 0.0f; +} + +static void _readPosition2ui3f(const GLubyte* in, GLubyte* out) { + const GLuint* input = (const GLuint*) in; + float* output = (float*) out; + + output[0] = input[0]; + output[1] = input[1]; + output[2] = 0.0f; +} + +static ReadAttributeFunc calcReadPositionFunc() { + switch(ATTRIB_LIST.vertex.type) { + default: + case GL_DOUBLE: + case GL_FLOAT: + return (ATTRIB_LIST.vertex.size == 3) ? _readPosition3f3f: + _readPosition2f3f; + case GL_BYTE: + case GL_UNSIGNED_BYTE: + return (ATTRIB_LIST.vertex.size == 3) ? _readPosition3ub3f: + _readPosition2ub3f; + case GL_SHORT: + case GL_UNSIGNED_SHORT: + return (ATTRIB_LIST.vertex.size == 3) ? _readPosition3us3f: + _readPosition2us3f; + case GL_INT: + case GL_UNSIGNED_INT: + return (ATTRIB_LIST.vertex.size == 3) ? _readPosition3ui3f: + _readPosition2ui3f; + } +} + + +static void _fillWhiteARGB(const GLubyte* __restrict__ input, GLubyte* __restrict__ output) { + _GL_UNUSED(input); + *((uint32_t*) output) = ~0; +} + +static void _readColour4ubARGB(const GLubyte* input, GLubyte* output) { + output[R8IDX] = input[0]; + output[G8IDX] = input[1]; + output[B8IDX] = input[2]; + output[A8IDX] = input[3]; +} + +static void _readColour4fARGB(const GLubyte* in, GLubyte* output) { + const float* input = (const float*) in; + + output[R8IDX] = (GLubyte) clamp(input[0] * 255.0f, 0, 255); + output[G8IDX] = (GLubyte) clamp(input[1] * 255.0f, 0, 255); + output[B8IDX] = (GLubyte) clamp(input[2] * 255.0f, 0, 255); + output[A8IDX] = (GLubyte) clamp(input[3] * 255.0f, 0, 255); +} + +static void _readColour3fARGB(const GLubyte* in, GLubyte* output) { + const float* input = (const float*) in; + + output[R8IDX] = (GLubyte) clamp(input[0] * 255.0f, 0, 255); + output[G8IDX] = (GLubyte) clamp(input[1] * 255.0f, 0, 255); + output[B8IDX] = (GLubyte) clamp(input[2] * 255.0f, 0, 255); + output[A8IDX] = 255; +} + +static void _readColour3ubARGB(const GLubyte* __restrict__ input, GLubyte* __restrict__ output) { + output[R8IDX] = input[0]; + output[G8IDX] = input[1]; + output[B8IDX] = input[2]; + output[A8IDX] = 255; +} + +static void _readColour4ubRevARGB(const GLubyte* __restrict__ input, GLubyte* __restrict__ output) { + argbcpy(output, input); +} + +static void _readColour4fRevARGB(const GLubyte* __restrict__ in, GLubyte* __restrict__ output) { + const float* input = (const float*) in; + + output[0] = (GLubyte) clamp(input[0] * 255.0f, 0, 255); + output[1] = (GLubyte) clamp(input[1] * 255.0f, 0, 255); + output[2] = (GLubyte) clamp(input[2] * 255.0f, 0, 255); + output[3] = (GLubyte) clamp(input[3] * 255.0f, 0, 255); +} + +static void _readColour3usARGB(const GLubyte* input, GLubyte* output) { + _GL_UNUSED(input); + _GL_UNUSED(output); + gl_assert(0 && "Not Implemented"); +} + +static void _readColour3uiARGB(const GLubyte* input, GLubyte* output) { + _GL_UNUSED(input); + _GL_UNUSED(output); + gl_assert(0 && "Not Implemented"); +} + +static void _readColour4usARGB(const GLubyte* input, GLubyte* output) { + _GL_UNUSED(input); + _GL_UNUSED(output); + gl_assert(0 && "Not Implemented"); +} + +static void _readColour4uiARGB(const GLubyte* input, GLubyte* output) { + _GL_UNUSED(input); + _GL_UNUSED(output); + gl_assert(0 && "Not Implemented"); +} + +static void _readColour4usRevARGB(const GLubyte* input, GLubyte* output) { + _GL_UNUSED(input); + _GL_UNUSED(output); + gl_assert(0 && "Not Implemented"); +} + +static void _readColour4uiRevARGB(const GLubyte* input, GLubyte* output) { + _GL_UNUSED(input); + _GL_UNUSED(output); + gl_assert(0 && "Not Implemented"); +} + +static ReadAttributeFunc calcReadDiffuseFunc() { + if((ATTRIB_LIST.enabled & DIFFUSE_ENABLED_FLAG) != DIFFUSE_ENABLED_FLAG) { + /* Just fill the whole thing white if the attribute is disabled */ + return _fillWhiteARGB; + } + + switch(ATTRIB_LIST.colour.type) { + default: + case GL_DOUBLE: + case GL_FLOAT: + return (ATTRIB_LIST.colour.size == 3) ? _readColour3fARGB: + (ATTRIB_LIST.colour.size == 4) ? _readColour4fARGB: + _readColour4fRevARGB; + case GL_BYTE: + case GL_UNSIGNED_BYTE: + return (ATTRIB_LIST.colour.size == 3) ? _readColour3ubARGB: + (ATTRIB_LIST.colour.size == 4) ? _readColour4ubARGB: + _readColour4ubRevARGB; + case GL_SHORT: + case GL_UNSIGNED_SHORT: + return (ATTRIB_LIST.colour.size == 3) ? _readColour3usARGB: + (ATTRIB_LIST.colour.size == 4) ? _readColour4usARGB: + _readColour4usRevARGB; + case GL_INT: + case GL_UNSIGNED_INT: + return (ATTRIB_LIST.colour.size == 3) ? _readColour3uiARGB: + (ATTRIB_LIST.colour.size == 4) ? _readColour4uiARGB: + _readColour4uiRevARGB; + } +} + + +static void _fillZero2f(const GLubyte* __restrict__ input, GLubyte* __restrict__ out) { + _GL_UNUSED(input); + //memset(out, 0, sizeof(float) * 2); + // memset does 8 byte writes - faster to manually write as uint32 + uint32_t* dst = (uint32_t*)out; + dst[0] = 0; + dst[1] = 0; +} + +static void _readTexcoord2f2f(const GLubyte* in, GLubyte* out) { + vec2cpy(out, in); +} + +static void _readTexcoord2ub2f(const GLubyte* input, GLubyte* out) { + float* output = (float*) out; + + output[0] = input[0] * ONE_OVER_TWO_FIVE_FIVE; + output[1] = input[1] * ONE_OVER_TWO_FIVE_FIVE; +} + +static void _readTexcoord2us2f(const GLubyte* in, GLubyte* out) { + const GLushort* input = (const GLushort*) in; + float* output = (float*) out; + + output[0] = (float)input[0] / SHRT_MAX; + output[1] = (float)input[1] / SHRT_MAX; +} + +static void _readTexcoord2ui2f(const GLubyte* in, GLubyte* out) { + const GLuint* input = (const GLuint*) in; + float* output = (float*) out; + + output[0] = input[0]; + output[1] = input[1]; +} + +static ReadAttributeFunc calcReadUVFunc() { + if((ATTRIB_LIST.enabled & UV_ENABLED_FLAG) != UV_ENABLED_FLAG) { + return _fillZero2f; + } + + switch(ATTRIB_LIST.uv.type) { + default: + case GL_DOUBLE: + case GL_FLOAT: + return _readTexcoord2f2f; + case GL_BYTE: + case GL_UNSIGNED_BYTE: + return _readTexcoord2ub2f; + case GL_SHORT: + case GL_UNSIGNED_SHORT: + return _readTexcoord2us2f; + case GL_INT: + case GL_UNSIGNED_INT: + return _readTexcoord2ui2f; + } +} + +static ReadAttributeFunc calcReadSTFunc() { + if((ATTRIB_LIST.enabled & ST_ENABLED_FLAG) != ST_ENABLED_FLAG) { + return _fillZero2f; + } + + switch(ATTRIB_LIST.st.type) { + default: + case GL_DOUBLE: + case GL_FLOAT: + return _readTexcoord2f2f; + case GL_BYTE: + case GL_UNSIGNED_BYTE: + return _readTexcoord2ub2f; + case GL_SHORT: + case GL_UNSIGNED_SHORT: + return _readTexcoord2us2f; + case GL_INT: + case GL_UNSIGNED_INT: + return _readTexcoord2ui2f; + } +} + + +static void _fillWithNegZVE(const GLubyte* __restrict__ input, GLubyte* __restrict__ out) { + _GL_UNUSED(input); + typedef struct { float x, y, z; } V; + + static const V NegZ = {0.0f, 0.0f, -1.0f}; + + *((V*) out) = NegZ; +} + +static void _readNormal3f3f(const GLubyte* __restrict__ in, GLubyte* __restrict__ out) { + vec3cpy(out, in); +} + +static void _readNormal3ub3f(const GLubyte* input, GLubyte* out) { + float* output = (float*) out; + + output[0] = input[0] * ONE_OVER_TWO_FIVE_FIVE; + output[1] = input[1] * ONE_OVER_TWO_FIVE_FIVE; + output[2] = input[2] * ONE_OVER_TWO_FIVE_FIVE; +} + +static void _readNormal3us3f(const GLubyte* in, GLubyte* out) { + const GLushort* input = (const GLushort*) in; + float* output = (float*) out; + + output[0] = input[0]; + output[1] = input[1]; + output[2] = input[2]; +} + +static void _readNormal3ui3f(const GLubyte* in, GLubyte* out) { + const GLuint* input = (const GLuint*) in; + float* output = (float*) out; + + output[0] = input[0]; + output[1] = input[1]; + output[2] = input[2]; +} + // 10:10:10:2REV format -static void _readVertexData1i3f(const GLubyte* in, GLubyte* out) { +static void _readNormal1i3f(const GLubyte* in, GLubyte* out) { static const float MULTIPLIER = 1.0f / 1023.0f; GLfloat* output = (GLfloat*) out; @@ -63,295 +384,6 @@ static void _readVertexData1i3f(const GLubyte* in, GLubyte* out) { output[2] = (2.0f * (float) input.bits.z + 1.0f) * MULTIPLIER; } -static void _readVertexData3us3f(const GLubyte* in, GLubyte* out) { - const GLushort* input = (const GLushort*) in; - float* output = (float*) out; - - output[0] = input[0]; - output[1] = input[1]; - output[2] = input[2]; -} - -static void _readVertexData3ui3f(const GLubyte* in, GLubyte* out) { - const GLuint* input = (const GLuint*) in; - float* output = (float*) out; - - output[0] = input[0]; - output[1] = input[1]; - output[2] = input[2]; -} - - -static void _readVertexData3ub3f(const GLubyte* input, GLubyte* out) { - float* output = (float*) out; - - output[0] = input[0] * ONE_OVER_TWO_FIVE_FIVE; - output[1] = input[1] * ONE_OVER_TWO_FIVE_FIVE; - output[2] = input[2] * ONE_OVER_TWO_FIVE_FIVE; -} - -static void _readVertexData2f2f(const GLubyte* in, GLubyte* out) { - vec2cpy(out, in); -} - -static void _readVertexData2f3f(const GLubyte* in, GLubyte* out) { - const float* input = (const float*) in; - float* output = (float*) out; - - vec2cpy(output, input); - output[2] = 0.0f; -} - -static void _readVertexData2ub3f(const GLubyte* input, GLubyte* out) { - float* output = (float*) out; - - output[0] = input[0] * ONE_OVER_TWO_FIVE_FIVE; - output[1] = input[1] * ONE_OVER_TWO_FIVE_FIVE; - output[2] = 0.0f; -} - -static void _readVertexData2us3f(const GLubyte* in, GLubyte* out) { - const GLushort* input = (const GLushort*) in; - float* output = (float*) out; - - output[0] = input[0]; - output[1] = input[1]; - output[2] = 0.0f; -} - -static void _readVertexData2us2f(const GLubyte* in, GLubyte* out) { - const GLushort* input = (const GLushort*) in; - float* output = (float*) out; - - output[0] = (float)input[0] / SHRT_MAX; - output[1] = (float)input[1] / SHRT_MAX; -} - -static void _readVertexData2ui2f(const GLubyte* in, GLubyte* out) { - const GLuint* input = (const GLuint*) in; - float* output = (float*) out; - - output[0] = input[0]; - output[1] = input[1]; -} - -static void _readVertexData2ub2f(const GLubyte* input, GLubyte* out) { - float* output = (float*) out; - - output[0] = input[0] * ONE_OVER_TWO_FIVE_FIVE; - output[1] = input[1] * ONE_OVER_TWO_FIVE_FIVE; -} - -static void _readVertexData2ui3f(const GLubyte* in, GLubyte* out) { - const GLuint* input = (const GLuint*) in; - float* output = (float*) out; - - output[0] = input[0]; - output[1] = input[1]; - output[2] = 0.0f; -} - -static void _readVertexData4ubARGB(const GLubyte* input, GLubyte* output) { - output[R8IDX] = input[0]; - output[G8IDX] = input[1]; - output[B8IDX] = input[2]; - output[A8IDX] = input[3]; -} - -static void _readVertexData4fARGB(const GLubyte* in, GLubyte* output) { - const float* input = (const float*) in; - - output[R8IDX] = (GLubyte) clamp(input[0] * 255.0f, 0, 255); - output[G8IDX] = (GLubyte) clamp(input[1] * 255.0f, 0, 255); - output[B8IDX] = (GLubyte) clamp(input[2] * 255.0f, 0, 255); - output[A8IDX] = (GLubyte) clamp(input[3] * 255.0f, 0, 255); -} - -static void _readVertexData3fARGB(const GLubyte* in, GLubyte* output) { - const float* input = (const float*) in; - - output[R8IDX] = (GLubyte) clamp(input[0] * 255.0f, 0, 255); - output[G8IDX] = (GLubyte) clamp(input[1] * 255.0f, 0, 255); - output[B8IDX] = (GLubyte) clamp(input[2] * 255.0f, 0, 255); - output[A8IDX] = 255; -} - -static void _readVertexData3ubARGB(const GLubyte* __restrict__ input, GLubyte* __restrict__ output) { - output[R8IDX] = input[0]; - output[G8IDX] = input[1]; - output[B8IDX] = input[2]; - output[A8IDX] = 255; -} - -static void _readVertexData4ubRevARGB(const GLubyte* __restrict__ input, GLubyte* __restrict__ output) { - argbcpy(output, input); -} - -static void _readVertexData4fRevARGB(const GLubyte* __restrict__ in, GLubyte* __restrict__ output) { - const float* input = (const float*) in; - - output[0] = (GLubyte) clamp(input[0] * 255.0f, 0, 255); - output[1] = (GLubyte) clamp(input[1] * 255.0f, 0, 255); - output[2] = (GLubyte) clamp(input[2] * 255.0f, 0, 255); - output[3] = (GLubyte) clamp(input[3] * 255.0f, 0, 255); -} - -static void _fillWithNegZVE(const GLubyte* __restrict__ input, GLubyte* __restrict__ out) { - _GL_UNUSED(input); - typedef struct { float x, y, z; } V; - - static const V NegZ = {0.0f, 0.0f, -1.0f}; - - *((V*) out) = NegZ; -} - -static void _fillWhiteARGB(const GLubyte* __restrict__ input, GLubyte* __restrict__ output) { - _GL_UNUSED(input); - *((uint32_t*) output) = ~0; -} - -static void _fillZero2f(const GLubyte* __restrict__ input, GLubyte* __restrict__ out) { - _GL_UNUSED(input); - //memset(out, 0, sizeof(float) * 2); - // memset does 8 byte writes - faster to manually write as uint32 - uint32_t* dst = (uint32_t*)out; - dst[0] = 0; - dst[1] = 0; -} - -static void _readVertexData3usARGB(const GLubyte* input, GLubyte* output) { - _GL_UNUSED(input); - _GL_UNUSED(output); - gl_assert(0 && "Not Implemented"); -} - -static void _readVertexData3uiARGB(const GLubyte* input, GLubyte* output) { - _GL_UNUSED(input); - _GL_UNUSED(output); - gl_assert(0 && "Not Implemented"); -} - -static void _readVertexData4usARGB(const GLubyte* input, GLubyte* output) { - _GL_UNUSED(input); - _GL_UNUSED(output); - gl_assert(0 && "Not Implemented"); -} - -static void _readVertexData4uiARGB(const GLubyte* input, GLubyte* output) { - _GL_UNUSED(input); - _GL_UNUSED(output); - gl_assert(0 && "Not Implemented"); -} - -static void _readVertexData4usRevARGB(const GLubyte* input, GLubyte* output) { - _GL_UNUSED(input); - _GL_UNUSED(output); - gl_assert(0 && "Not Implemented"); -} - -static void _readVertexData4uiRevARGB(const GLubyte* input, GLubyte* output) { - _GL_UNUSED(input); - _GL_UNUSED(output); - gl_assert(0 && "Not Implemented"); -} - -static ReadAttributeFunc calcReadDiffuseFunc() { - if((ATTRIB_LIST.enabled & DIFFUSE_ENABLED_FLAG) != DIFFUSE_ENABLED_FLAG) { - /* Just fill the whole thing white if the attribute is disabled */ - return _fillWhiteARGB; - } - - switch(ATTRIB_LIST.colour.type) { - default: - case GL_DOUBLE: - case GL_FLOAT: - return (ATTRIB_LIST.colour.size == 3) ? _readVertexData3fARGB: - (ATTRIB_LIST.colour.size == 4) ? _readVertexData4fARGB: - _readVertexData4fRevARGB; - case GL_BYTE: - case GL_UNSIGNED_BYTE: - return (ATTRIB_LIST.colour.size == 3) ? _readVertexData3ubARGB: - (ATTRIB_LIST.colour.size == 4) ? _readVertexData4ubARGB: - _readVertexData4ubRevARGB; - case GL_SHORT: - case GL_UNSIGNED_SHORT: - return (ATTRIB_LIST.colour.size == 3) ? _readVertexData3usARGB: - (ATTRIB_LIST.colour.size == 4) ? _readVertexData4usARGB: - _readVertexData4usRevARGB; - case GL_INT: - case GL_UNSIGNED_INT: - return (ATTRIB_LIST.colour.size == 3) ? _readVertexData3uiARGB: - (ATTRIB_LIST.colour.size == 4) ? _readVertexData4uiARGB: - _readVertexData4uiRevARGB; - } -} - -static ReadAttributeFunc calcReadPositionFunc() { - switch(ATTRIB_LIST.vertex.type) { - default: - case GL_DOUBLE: - case GL_FLOAT: - return (ATTRIB_LIST.vertex.size == 3) ? _readVertexData3f3f: - _readVertexData2f3f; - case GL_BYTE: - case GL_UNSIGNED_BYTE: - return (ATTRIB_LIST.vertex.size == 3) ? _readVertexData3ub3f: - _readVertexData2ub3f; - case GL_SHORT: - case GL_UNSIGNED_SHORT: - return (ATTRIB_LIST.vertex.size == 3) ? _readVertexData3us3f: - _readVertexData2us3f; - case GL_INT: - case GL_UNSIGNED_INT: - return (ATTRIB_LIST.vertex.size == 3) ? _readVertexData3ui3f: - _readVertexData2ui3f; - } -} - -static ReadAttributeFunc calcReadUVFunc() { - if((ATTRIB_LIST.enabled & UV_ENABLED_FLAG) != UV_ENABLED_FLAG) { - return _fillZero2f; - } - - switch(ATTRIB_LIST.uv.type) { - default: - case GL_DOUBLE: - case GL_FLOAT: - return _readVertexData2f2f; - case GL_BYTE: - case GL_UNSIGNED_BYTE: - return _readVertexData2ub2f; - case GL_SHORT: - case GL_UNSIGNED_SHORT: - return _readVertexData2us2f; - case GL_INT: - case GL_UNSIGNED_INT: - return _readVertexData2ui2f; - } -} - -static ReadAttributeFunc calcReadSTFunc() { - if((ATTRIB_LIST.enabled & ST_ENABLED_FLAG) != ST_ENABLED_FLAG) { - return _fillZero2f; - } - - switch(ATTRIB_LIST.st.type) { - default: - case GL_DOUBLE: - case GL_FLOAT: - return _readVertexData2f2f; - case GL_BYTE: - case GL_UNSIGNED_BYTE: - return _readVertexData2ub2f; - case GL_SHORT: - case GL_UNSIGNED_SHORT: - return _readVertexData2us2f; - case GL_INT: - case GL_UNSIGNED_INT: - return _readVertexData2ui2f; - } -} - static ReadAttributeFunc calcReadNormalFunc() { if((ATTRIB_LIST.enabled & NORMAL_ENABLED_FLAG) != NORMAL_ENABLED_FLAG) { return _fillWithNegZVE; @@ -361,26 +393,27 @@ static ReadAttributeFunc calcReadNormalFunc() { default: case GL_DOUBLE: case GL_FLOAT: - return _readVertexData3f3f; + return _readNormal3f3f; break; case GL_BYTE: case GL_UNSIGNED_BYTE: - return _readVertexData3ub3f; + return _readNormal3ub3f; break; case GL_SHORT: case GL_UNSIGNED_SHORT: - return _readVertexData3us3f; + return _readNormal3us3f; break; case GL_INT: case GL_UNSIGNED_INT: - return _readVertexData3ui3f; + return _readNormal3ui3f; break; case GL_UNSIGNED_INT_2_10_10_10_REV: - return _readVertexData1i3f; + return _readNormal1i3f; break; } } + void APIENTRY glEnableClientState(GLenum cap) { TRACE(); From 3b2e5499347aa9e92d8431d01229b33443e33734 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sun, 2 Feb 2025 14:36:40 +1100 Subject: [PATCH 64/72] Optimise vertex transform in non-fast path to avoid storing xyz to memory and then loading it again --- GL/attributes.c | 78 ++++++++++++++++++++++++++--------------- GL/draw.c | 12 ++----- GL/draw_fastpath.inc | 3 +- GL/platforms/sh4.h | 13 ++++--- GL/platforms/software.c | 10 +++--- GL/platforms/software.h | 2 +- 6 files changed, 66 insertions(+), 52 deletions(-) diff --git a/GL/attributes.c b/GL/attributes.c index 703d562..f12f1ed 100644 --- a/GL/attributes.c +++ b/GL/attributes.c @@ -37,67 +37,89 @@ GLuint* _glGetEnabledAttributes() { static void _readPosition3f3f(const GLubyte* __restrict__ in, GLubyte* __restrict__ out) { - vec3cpy(out, in); + const float* input = (const float*) in; + Vertex* it = (Vertex*) out; + + float x = input[0]; + float y = input[1]; + float z = input[2]; + float w = 1.0f; + TransformVertex(x, y, z, w, it->xyz, &it->w); } static void _readPosition3ub3f(const GLubyte* input, GLubyte* out) { - float* output = (float*) out; + Vertex* it = (Vertex*)out; - output[0] = input[0] * ONE_OVER_TWO_FIVE_FIVE; - output[1] = input[1] * ONE_OVER_TWO_FIVE_FIVE; - output[2] = input[2] * ONE_OVER_TWO_FIVE_FIVE; + float x = input[0] * ONE_OVER_TWO_FIVE_FIVE; + float y = input[1] * ONE_OVER_TWO_FIVE_FIVE; + float z = input[2] * ONE_OVER_TWO_FIVE_FIVE; + float w = 1.0f; + TransformVertex(x, y, z, w, it->xyz, &it->w); } static void _readPosition3us3f(const GLubyte* in, GLubyte* out) { const GLushort* input = (const GLushort*) in; - float* output = (float*) out; + Vertex* it = (Vertex*) out; - output[0] = input[0]; - output[1] = input[1]; - output[2] = input[2]; + float x = input[0]; + float y = input[1]; + float z = input[2]; + float w = 1.0f; + TransformVertex(x, y, z, w, it->xyz, &it->w); } static void _readPosition3ui3f(const GLubyte* in, GLubyte* out) { const GLuint* input = (const GLuint*) in; - float* output = (float*) out; + Vertex* it = (Vertex*) out; - output[0] = input[0]; - output[1] = input[1]; - output[2] = input[2]; + float x = input[0]; + float y = input[1]; + float z = input[2]; + float w = 1.0f; + TransformVertex(x, y, z, w, it->xyz, &it->w); } static void _readPosition2f3f(const GLubyte* in, GLubyte* out) { const float* input = (const float*) in; - float* output = (float*) out; + Vertex* it = (Vertex*) out; - vec2cpy(output, input); - output[2] = 0.0f; + float x = input[0]; + float y = input[1]; + float z = 0.0f; + float w = 1.0f; + TransformVertex(x, y, z, w, it->xyz, &it->w); } static void _readPosition2ub3f(const GLubyte* input, GLubyte* out) { - float* output = (float*) out; + Vertex* it = (Vertex*) out; - output[0] = input[0] * ONE_OVER_TWO_FIVE_FIVE; - output[1] = input[1] * ONE_OVER_TWO_FIVE_FIVE; - output[2] = 0.0f; + float x = input[0] * ONE_OVER_TWO_FIVE_FIVE; + float y = input[1] * ONE_OVER_TWO_FIVE_FIVE; + float z = 0.0f; + float w = 1.0f; + TransformVertex(x, y, z, w, it->xyz, &it->w); } static void _readPosition2us3f(const GLubyte* in, GLubyte* out) { const GLushort* input = (const GLushort*) in; - float* output = (float*) out; + Vertex* it = (Vertex*) out; - output[0] = input[0]; - output[1] = input[1]; - output[2] = 0.0f; + float x = input[0]; + float y = input[1]; + float z = 0.0f; + float w = 1.0f; + TransformVertex(x, y, z, w, it->xyz, &it->w); } static void _readPosition2ui3f(const GLubyte* in, GLubyte* out) { const GLuint* input = (const GLuint*) in; - float* output = (float*) out; + Vertex* it = (Vertex*)out; - output[0] = input[0]; - output[1] = input[1]; - output[2] = 0.0f; + float x = input[0]; + float y = input[1]; + float z = 0.0f; + float w = 1.0f; + TransformVertex(x, y, z, w, it->xyz, &it->w); } static ReadAttributeFunc calcReadPositionFunc() { diff --git a/GL/draw.c b/GL/draw.c index 98b5cfd..b6e5086 100644 --- a/GL/draw.c +++ b/GL/draw.c @@ -289,13 +289,10 @@ static void _readPositionData(const GLuint first, const GLuint count, Vertex* it const GLsizei vstride = ATTRIB_LIST.vertex.stride; const GLubyte* vptr = ((GLubyte*) ATTRIB_LIST.vertex.ptr + (first * vstride)); - float pos[3], w = 1.0f; - ITERATE(count) { PREFETCH(vptr + vstride); - func(vptr, (GLubyte*) pos); + func(vptr, (GLubyte*) it); it->flags = GPU_CMD_VERTEX; - TransformVertex(pos, &w, it->xyz, &it->w); vptr += vstride; ++it; @@ -411,8 +408,7 @@ static void generateElements( st = (GLubyte*) ATTRIB_LIST.st.ptr + (idx * ststride); nxyz = (GLubyte*) ATTRIB_LIST.normal.ptr + (idx * nstride); - pos_func(xyz, (GLubyte*) pos); - TransformVertex((const float*) pos, &w, output->xyz, &output->w); + pos_func(xyz, (GLubyte*) output); uv_func(uv, (GLubyte*) output->uv); diffuse_func(bgra, output->bgra); st_func(st, (GLubyte*) ve->st); @@ -460,8 +456,6 @@ static void generateElementsFastPath( VertexExtra* ve = aligned_vector_at(target->extras, 0); Vertex* it = start; - const float w = 1.0f; - if(!pos) { return; } @@ -472,7 +466,7 @@ static void generateElementsFastPath( it->flags = GPU_CMD_VERTEX; pos = (GLubyte*) ATTRIB_LIST.vertex.ptr + (idx * vstride); - TransformVertex((const float*) pos, &w, it->xyz, &it->w); + TransformVertex(((float*) pos)[0], ((float*) pos)[1], ((float*) pos)[2], 1.0f, it->xyz, &it->w); if(uv) { uv = (GLubyte*) ATTRIB_LIST.uv.ptr + (idx * uvstride); diff --git a/GL/draw_fastpath.inc b/GL/draw_fastpath.inc index b26e6a9..fe3b527 100644 --- a/GL/draw_fastpath.inc +++ b/GL/draw_fastpath.inc @@ -5,7 +5,6 @@ MAKE_FUNC(POLYMODE) { - static const float w = 1.0f; if(!(ATTRIB_LIST.enabled & VERTEX_ENABLED_FLAG)) { /* If we don't have vertices, do nothing */ return; @@ -75,7 +74,7 @@ MAKE_FUNC(POLYMODE) PREFETCH(ptr); for(int_fast32_t i = 0; i < loop; ++i, ++it) { PREFETCH(ptr + stride); - TransformVertex((const float*) ptr, &w, it->xyz, &it->w); + TransformVertex(((float*) ptr)[0], ((float*) ptr)[1], ((float*) ptr)[2], 1.0f, it->xyz, &it->w); PROCESS_VERTEX_FLAGS(it, min + i); ptr += stride; } diff --git a/GL/platforms/sh4.h b/GL/platforms/sh4.h index 5cbcc08..6b9bad0 100644 --- a/GL/platforms/sh4.h +++ b/GL/platforms/sh4.h @@ -106,15 +106,14 @@ inline void TransformVec4(float* x) { } -GL_FORCE_INLINE void TransformVertex(const float* xyz, const float* w, float* oxyz, float* ow) { - register float __x __asm__("fr12") = (xyz[0]); - register float __y __asm__("fr13") = (xyz[1]); - register float __z __asm__("fr14") = (xyz[2]); - register float __w __asm__("fr15") = (*w); +GL_FORCE_INLINE void TransformVertex(float x, float y, float z, float w, float* oxyz, float* ow) { + register float __x __asm__("fr4") = x; + register float __y __asm__("fr5") = y; + register float __z __asm__("fr6") = z; + register float __w __asm__("fr7") = w; __asm__ __volatile__( - "fldi1 fr15\n" - "ftrv xmtrx,fv12\n" + "ftrv xmtrx,fv4\n" : "=f" (__x), "=f" (__y), "=f" (__z), "=f" (__w) : "0" (__x), "1" (__y), "2" (__z), "3" (__w) ); diff --git a/GL/platforms/software.c b/GL/platforms/software.c index bf9ba47..9a2b4e5 100644 --- a/GL/platforms/software.c +++ b/GL/platforms/software.c @@ -636,12 +636,12 @@ void TransformVertices(Vertex* vertices, const int count) { } } -void TransformVertex(const float* xyz, const float* w, float* oxyz, float* ow) { +void TransformVertex(float x, float y, float z, float w, float* oxyz, float* ow) { float ret[4]; - ret[0] = xyz[0]; - ret[1] = xyz[1]; - ret[2] = xyz[2]; - ret[3] = *w; + ret[0] = x; + ret[1] = y; + ret[2] = z; + ret[3] = w; TransformVec4(ret); diff --git a/GL/platforms/software.h b/GL/platforms/software.h index 5fee317..cc89f97 100644 --- a/GL/platforms/software.h +++ b/GL/platforms/software.h @@ -53,7 +53,7 @@ static inline void TransformNormalNoMod(const float* xIn, float* xOut) { } void TransformVertices(Vertex* vertices, const int count); -void TransformVertex(const float* xyz, const float* w, float* oxyz, float* ow); +void TransformVertex(float x, float y, float z, float w, float* oxyz, float* ow); void InitGPU(_Bool autosort, _Bool fsaa); From a566bba082d96ad5bd64615b77450c8b4e7e79eb Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sun, 2 Feb 2025 15:58:19 +1100 Subject: [PATCH 65/72] Call TransformVertex directly instead of using TransformVertices --- GL/draw.c | 8 ++++++-- GL/platforms/sh4.h | 22 ---------------------- GL/platforms/software.c | 31 +++++++------------------------ GL/platforms/software.h | 1 - 4 files changed, 13 insertions(+), 49 deletions(-) diff --git a/GL/draw.c b/GL/draw.c index b6e5086..a8dade5 100644 --- a/GL/draw.c +++ b/GL/draw.c @@ -615,9 +615,13 @@ static void transform(SubmissionTarget* target) { TRACE(); /* Perform modelview transform, storing W */ - Vertex* vertex = _glSubmissionTargetStart(target); + Vertex* it = _glSubmissionTargetStart(target); + int count = target->count; - TransformVertices(vertex, target->count); + for(int i = 0; i < count; ++i, ++it) { + TransformVertex(it->xyz[0], it->xyz[1], it->xyz[2], it->w, + it->xyz, &it->w); + } } static void mat_transform_normal3(const float* xyz, const float* xyzOut, const uint32_t count, const uint32_t inStride, const uint32_t outStride) { diff --git a/GL/platforms/sh4.h b/GL/platforms/sh4.h index 6b9bad0..1139283 100644 --- a/GL/platforms/sh4.h +++ b/GL/platforms/sh4.h @@ -124,28 +124,6 @@ GL_FORCE_INLINE void TransformVertex(float x, float y, float z, float w, float* *ow = __w; } -static inline void TransformVertices(Vertex* vertices, const int count) { - Vertex* it = vertices; - for(int i = 0; i < count; ++i, ++it) { - register float __x __asm__("fr12") = (it->xyz[0]); - register float __y __asm__("fr13") = (it->xyz[1]); - register float __z __asm__("fr14") = (it->xyz[2]); - register float __w __asm__("fr15") = (it->w); - - __asm__ __volatile__( - "fldi1 fr15\n" - "ftrv xmtrx,fv12\n" - : "=f" (__x), "=f" (__y), "=f" (__z), "=f" (__w) - : "0" (__x), "1" (__y), "2" (__z), "3" (__w) - ); - - it->xyz[0] = __x; - it->xyz[1] = __y; - it->xyz[2] = __z; - it->w = __w; - } -} - void InitGPU(_Bool autosort, _Bool fsaa); static inline size_t GPUMemoryAvailable() { diff --git a/GL/platforms/software.c b/GL/platforms/software.c index 9a2b4e5..57940b6 100644 --- a/GL/platforms/software.c +++ b/GL/platforms/software.c @@ -619,34 +619,17 @@ void TransformVec4(float* v) { FASTCPY(v, ret, sizeof(float) * 4); } -void TransformVertices(Vertex* vertices, const int count) { - float ret[4]; - for(int i = 0; i < count; ++i, ++vertices) { - ret[0] = vertices->xyz[0]; - ret[1] = vertices->xyz[1]; - ret[2] = vertices->xyz[2]; - ret[3] = 1.0f; - - TransformVec4(ret); - - vertices->xyz[0] = ret[0]; - vertices->xyz[1] = ret[1]; - vertices->xyz[2] = ret[2]; - vertices->w = ret[3]; - } -} - void TransformVertex(float x, float y, float z, float w, float* oxyz, float* ow) { - float ret[4]; - ret[0] = x; - ret[1] = y; - ret[2] = z; - ret[3] = w; + float vec[4], ret[4]; + vec[0] = x; + vec[1] = y; + vec[2] = z; + vec[3] = w; - TransformVec4(ret); + TransformVec4NoMod(vec, ret); oxyz[0] = ret[0]; oxyz[1] = ret[1]; oxyz[2] = ret[2]; - *ow = ret[3]; + *ow = ret[3]; } diff --git a/GL/platforms/software.h b/GL/platforms/software.h index cc89f97..744a9bc 100644 --- a/GL/platforms/software.h +++ b/GL/platforms/software.h @@ -52,7 +52,6 @@ static inline void TransformNormalNoMod(const float* xIn, float* xOut) { (void) xOut; } -void TransformVertices(Vertex* vertices, const int count); void TransformVertex(float x, float y, float z, float w, float* oxyz, float* ow); void InitGPU(_Bool autosort, _Bool fsaa); From 5b5e6d3ee66b4ac1fbcefb874478635761ceb2b5 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Mon, 3 Feb 2025 06:53:16 +1100 Subject: [PATCH 66/72] Fix alloc_count_continuous calculation --- GL/alloc/alloc.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/GL/alloc/alloc.c b/GL/alloc/alloc.c index fe9aed1..defc220 100644 --- a/GL/alloc/alloc.c +++ b/GL/alloc/alloc.c @@ -515,29 +515,27 @@ size_t alloc_count_free(void* pool) { size_t alloc_count_continuous(void* pool) { (void) pool; - size_t largest_block = 0; + size_t contiguous_free = 0; + size_t most_contiguous = 0; - size_t free_bits = 0; for(size_t i = 0; i < pool_header.block_count; ++i) { uint8_t t = pool_header.block_usage[i]; for(int i = 7; i >= 0; --i) { bool bitset = (t & (1 << i)); if(!bitset) { - ++free_bits; + ++contiguous_free; } else { - free_bits = 0; - size_t free_size = free_bits * 256; - if(free_size > largest_block) { - largest_block = free_size; + if(contiguous_free > most_contiguous) { + most_contiguous = contiguous_free; } + contiguous_free = 0; } } } - if(free_bits && (free_bits * 256) > largest_block) { - largest_block = (free_bits * 256); + if(contiguous_free > most_contiguous) { + most_contiguous = contiguous_free; } -printf("LARGEST: %d\n", largest_block); - return largest_block; + return most_contiguous * 256; } From 4255767f9f7cd592f74169a44d9fdc90e263e08b Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Wed, 5 Feb 2025 20:34:04 +1100 Subject: [PATCH 67/72] Refactor dtex parser --- samples/depth_funcs_alpha_testing/gl_png.c | 315 +++++++++++---------- samples/depth_funcs_alpha_testing/gl_png.h | 2 +- 2 files changed, 159 insertions(+), 158 deletions(-) diff --git a/samples/depth_funcs_alpha_testing/gl_png.c b/samples/depth_funcs_alpha_testing/gl_png.c index 5415638..01e8ad5 100644 --- a/samples/depth_funcs_alpha_testing/gl_png.c +++ b/samples/depth_funcs_alpha_testing/gl_png.c @@ -14,178 +14,179 @@ GLfloat global_diffuse[] = {1.0, 1.0, 1.0, 1.0}; GLfloat global_ambient[] = {1.0, 1.0, 1.0, 1.0}; +static int decode_dtex(Image* image, FILE* file) { + struct { + char id[4]; // 'DTEX' + GLushort width; + GLushort height; + GLuint type; + GLuint size; + } header; + + fread(&header, sizeof(header), 1, file); + + image->twiddled = (header.type & (1 << 26)) < 1; + image->compressed = (header.type & (1 << 30)) > 0; + image->mipmapped = (header.type & (1 << 31)) > 0; + GLuint format = (header.type >> 27) & 0b111; + + image->data = (char *) malloc (header.size); + image->sizeX = header.width; + image->sizeY = header.height; + image->dataSize = header.size; + + fread(image->data, image->dataSize, 1, file); + fclose(file); + + if(image->compressed) { + printf("Compressed - "); + if(image->twiddled) { + printf("Twiddled - "); + switch(format) { + case 0: { + if(image->mipmapped) { + image->internalFormat = GL_COMPRESSED_ARGB_1555_VQ_MIPMAP_TWID_KOS; + } else { + image->internalFormat = GL_COMPRESSED_ARGB_1555_VQ_TWID_KOS; + } + } break; + case 1: { + if(image->mipmapped) { + image->internalFormat = GL_COMPRESSED_RGB_565_VQ_MIPMAP_TWID_KOS; + } else { + image->internalFormat = GL_COMPRESSED_RGB_565_VQ_TWID_KOS; + } + } break; + case 2: { + if(image->mipmapped) { + image->internalFormat = GL_COMPRESSED_ARGB_4444_VQ_MIPMAP_TWID_KOS; + } else { + image->internalFormat = GL_COMPRESSED_ARGB_4444_VQ_TWID_KOS; + } + } + break; + default: + fprintf(stderr, "Invalid texture format"); + return 0; + } + } else { + switch(format) { + case 0: { + if(image->mipmapped) { + image->internalFormat = GL_COMPRESSED_ARGB_1555_VQ_MIPMAP_KOS; + } else { + image->internalFormat = GL_COMPRESSED_ARGB_1555_VQ_KOS; + } + } break; + case 1: { + if(image->mipmapped) { + image->internalFormat = GL_COMPRESSED_RGB_565_VQ_MIPMAP_KOS; + } else { + image->internalFormat = GL_COMPRESSED_RGB_565_VQ_KOS; + } + } break; + case 2: { + if(image->mipmapped) { + image->internalFormat = GL_COMPRESSED_ARGB_4444_VQ_MIPMAP_KOS; + } else { + image->internalFormat = GL_COMPRESSED_ARGB_4444_VQ_KOS; + } + } + break; + default: + fprintf(stderr, "Invalid texture format"); + return 0; + } + } + } else { + printf("Uncompressed - "); + //printf("Color:%u -", format); + switch(format) { + case 0: + image->internalFormat = GL_UNSIGNED_SHORT_1_5_5_5_REV_TWID_KOS; + //image->internalFormat = GL_UNSIGNED_SHORT_1_5_5_5_REV; + break; + case 1: + image->internalFormat = GL_UNSIGNED_SHORT_5_6_5_REV; + break; + case 2: + image->internalFormat = GL_UNSIGNED_SHORT_4_4_4_4_REV; + break; + } + } + printf("\n"); +} int dtex_to_gl_texture(texture *tex, char* filename) { // Load Texture - Image *image; + Image image = { 0 }; - // allocate space for texture - image = (Image *) malloc(sizeof(Image)); - if (image == NULL) { - printf("No memory for .DTEX file\n"); - return(0); - } + FILE* file = NULL; - FILE* file = NULL; + // make sure the file is there. + if ((file = fopen(filename, "rb")) == NULL) + { + printf("File not found"); + return 0; + } - // make sure the file is there. - if ((file = fopen(filename, "rb")) == NULL) - { - printf("File not found"); - return 0; - } + decode_dtex(&image, file); - struct { - char id[4]; // 'DTEX' - GLushort width; - GLushort height; - GLuint type; - GLuint size; - } header; + // Create Texture + GLuint texture_id; + glGenTextures(1, &texture_id); + glBindTexture(GL_TEXTURE_2D, texture_id); // 2d texture (x and y size) - fread(&header, sizeof(header), 1, file); + GLint newFormat = GL_RGB; + GLint colorType = GL_RGB; - GLboolean twiddled = (header.type & (1 << 26)) < 1; - GLboolean compressed = (header.type & (1 << 30)) > 0; - GLboolean mipmapped = (header.type & (1 << 31)) > 0; - GLuint format = (header.type >> 27) & 0b111; + if (image.internalFormat == GL_UNSIGNED_SHORT_1_5_5_5_REV_TWID_KOS || + image.internalFormat == GL_UNSIGNED_SHORT_4_4_4_4_REV){ + newFormat = GL_BGRA; + colorType = GL_RGBA; + printf("Reversing RGBA\n"); + } - image->data = (char *) malloc (header.size); - image->sizeX = header.width; - image->sizeY = header.height; - image->dataSize = header.size; - - GLuint expected = 2 * header.width * header.height; - GLuint ratio = (GLuint) (((GLfloat) expected) / ((GLfloat) header.size)); - - fread(image->data, image->dataSize, 1, file); - fclose(file); - - if(compressed) { - printf("Compressed - "); - if(twiddled) { - printf("Twiddled - "); - switch(format) { - case 0: { - if(mipmapped) { - image->internalFormat = GL_COMPRESSED_ARGB_1555_VQ_MIPMAP_TWID_KOS; - } else { - image->internalFormat = GL_COMPRESSED_ARGB_1555_VQ_TWID_KOS; - } - } break; - case 1: { - if(mipmapped) { - image->internalFormat = GL_COMPRESSED_RGB_565_VQ_MIPMAP_TWID_KOS; - } else { - image->internalFormat = GL_COMPRESSED_RGB_565_VQ_TWID_KOS; - } - } break; - case 2: { - if(mipmapped) { - image->internalFormat = GL_COMPRESSED_ARGB_4444_VQ_MIPMAP_TWID_KOS; - } else { - image->internalFormat = GL_COMPRESSED_ARGB_4444_VQ_TWID_KOS; - } - } - break; - default: - fprintf(stderr, "Invalid texture format"); - return 0; - } - } else { - switch(format) { - case 0: { - if(mipmapped) { - image->internalFormat = GL_COMPRESSED_ARGB_1555_VQ_MIPMAP_KOS; - } else { - image->internalFormat = GL_COMPRESSED_ARGB_1555_VQ_KOS; - } - } break; - case 1: { - if(mipmapped) { - image->internalFormat = GL_COMPRESSED_RGB_565_VQ_MIPMAP_KOS; - } else { - image->internalFormat = GL_COMPRESSED_RGB_565_VQ_KOS; - } - } break; - case 2: { - if(mipmapped) { - image->internalFormat = GL_COMPRESSED_ARGB_4444_VQ_MIPMAP_KOS; - } else { - image->internalFormat = GL_COMPRESSED_ARGB_4444_VQ_KOS; - } - } - break; - default: - fprintf(stderr, "Invalid texture format"); - return 0; - } - } - } else { - printf("Uncompressed - "); - //printf("Color:%u -", format); - switch(format) { - - case 0: - image->internalFormat = GL_UNSIGNED_SHORT_1_5_5_5_REV_TWID_KOS; - //image->internalFormat = GL_UNSIGNED_SHORT_1_5_5_5_REV; - break; - case 1: - image->internalFormat = GL_UNSIGNED_SHORT_5_6_5_REV; - break; - case 2: - image->internalFormat = GL_UNSIGNED_SHORT_4_4_4_4_REV; - break; - } - } - printf("\n"); - - // Create Texture - GLuint texture_id; - glGenTextures(1, &texture_id); - glBindTexture(GL_TEXTURE_2D, texture_id); // 2d texture (x and y size) - - GLint newFormat = format; - GLint colorType = GL_RGB; - - if (image->internalFormat == GL_UNSIGNED_SHORT_1_5_5_5_REV_TWID_KOS || - image->internalFormat == GL_UNSIGNED_SHORT_4_4_4_4_REV){ - newFormat = GL_BGRA; - colorType = GL_RGBA; - printf("Reversing RGBA\n"); - } - - if (image->internalFormat == GL_UNSIGNED_SHORT_5_6_5_REV){ - newFormat = GL_RGB; - colorType = GL_RGB; - printf("Reversing RGB\n"); - } + if (image.internalFormat == GL_UNSIGNED_SHORT_5_6_5_REV){ + newFormat = GL_RGB; + colorType = GL_RGB; + printf("Reversing RGB\n"); + } + if (image.compressed) { + glCompressedTexImage2D(GL_TEXTURE_2D, 0, + image.internalFormat, image.sizeX, image.sizeY, + 0, image.dataSize, image.data); + } else { glTexImage2D(GL_TEXTURE_2D, 0, - colorType, image->sizeX, image->sizeY, 0, - newFormat, image->internalFormat, image->data); + colorType, image.sizeX, image.sizeY, 0, + newFormat, image.internalFormat, image.data); + } - tex->id = texture_id; - tex->w = image->sizeX; - tex->h = image->sizeY; - tex->u = 0.f; - tex->v = 0.f; - tex->a = tex->light = 1; - tex->color[0] = tex->color[1] = tex->color[2] = 1.0f; - tex->uSize = tex->vSize = 1.0f; - tex->xScale = tex->yScale = 1.0f; - tex->format = image->internalFormat; - tex->min_filter = tex->mag_filter = GL_NEAREST; - tex->blend_source = GL_SRC_ALPHA; - tex->blend_dest = GL_ONE_MINUS_SRC_ALPHA; - strcpy(tex->path, filename); + tex->id = texture_id; + tex->w = image.sizeX; + tex->h = image.sizeY; + tex->u = 0.f; + tex->v = 0.f; + tex->a = tex->light = 1; + tex->color[0] = tex->color[1] = tex->color[2] = 1.0f; + tex->uSize = tex->vSize = 1.0f; + tex->xScale = tex->yScale = 1.0f; + tex->format = image.internalFormat; + tex->min_filter = tex->mag_filter = GL_NEAREST; + tex->blend_source = GL_SRC_ALPHA; + tex->blend_dest = GL_ONE_MINUS_SRC_ALPHA; + strcpy(tex->path, filename); + + GLuint expected = 2 * image.sizeX * image.sizeY; + GLuint ratio = (GLuint) (((GLfloat) expected) / ((GLfloat) image.dataSize)); - printf("Texture size: %lu x %lu\n", image->sizeX, image->sizeY); - printf("Texture ratio: %d\n", ratio); - printf("Texture size: %lu x %lu\n", image->sizeX, image->sizeY); - printf("Texture %s loaded\n", tex->path); + printf("Texture size: %lu x %lu\n", image.sizeX, image.sizeY); + printf("Texture ratio: %d\n", ratio); + printf("Texture size: %lu x %lu\n", image.sizeX, image.sizeY); + printf("Texture %s loaded\n", tex->path); - return(1); + return(1); } void draw_textured_quad(texture *tex) { diff --git a/samples/depth_funcs_alpha_testing/gl_png.h b/samples/depth_funcs_alpha_testing/gl_png.h index 29b312f..0639e36 100644 --- a/samples/depth_funcs_alpha_testing/gl_png.h +++ b/samples/depth_funcs_alpha_testing/gl_png.h @@ -30,7 +30,7 @@ typedef struct Image { unsigned long sizeY; char *data; GLenum internalFormat; - GLboolean mipmapped; + unsigned int mipmapped, compressed, twiddled; unsigned int dataSize; } Image; From 72baba7a5ec563cc6d30496f5c15925302b77046 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Wed, 5 Feb 2025 21:36:28 +1100 Subject: [PATCH 68/72] Refactor dtex parser again --- samples/depth_funcs_alpha_testing/gl_png.c | 138 +++++++++++---------- 1 file changed, 71 insertions(+), 67 deletions(-) diff --git a/samples/depth_funcs_alpha_testing/gl_png.c b/samples/depth_funcs_alpha_testing/gl_png.c index 01e8ad5..2d16032 100644 --- a/samples/depth_funcs_alpha_testing/gl_png.c +++ b/samples/depth_funcs_alpha_testing/gl_png.c @@ -38,83 +38,87 @@ static int decode_dtex(Image* image, FILE* file) { fread(image->data, image->dataSize, 1, file); fclose(file); - if(image->compressed) { - printf("Compressed - "); - if(image->twiddled) { - printf("Twiddled - "); - switch(format) { - case 0: { - if(image->mipmapped) { - image->internalFormat = GL_COMPRESSED_ARGB_1555_VQ_MIPMAP_TWID_KOS; - } else { - image->internalFormat = GL_COMPRESSED_ARGB_1555_VQ_TWID_KOS; - } - } break; - case 1: { - if(image->mipmapped) { - image->internalFormat = GL_COMPRESSED_RGB_565_VQ_MIPMAP_TWID_KOS; - } else { - image->internalFormat = GL_COMPRESSED_RGB_565_VQ_TWID_KOS; - } - } break; - case 2: { - if(image->mipmapped) { - image->internalFormat = GL_COMPRESSED_ARGB_4444_VQ_MIPMAP_TWID_KOS; - } else { - image->internalFormat = GL_COMPRESSED_ARGB_4444_VQ_TWID_KOS; - } - } - break; - default: - fprintf(stderr, "Invalid texture format"); - return 0; - } - } else { - switch(format) { - case 0: { - if(image->mipmapped) { - image->internalFormat = GL_COMPRESSED_ARGB_1555_VQ_MIPMAP_KOS; - } else { - image->internalFormat = GL_COMPRESSED_ARGB_1555_VQ_KOS; - } - } break; - case 1: { - if(image->mipmapped) { - image->internalFormat = GL_COMPRESSED_RGB_565_VQ_MIPMAP_KOS; - } else { - image->internalFormat = GL_COMPRESSED_RGB_565_VQ_KOS; - } - } break; - case 2: { - if(image->mipmapped) { - image->internalFormat = GL_COMPRESSED_ARGB_4444_VQ_MIPMAP_KOS; - } else { - image->internalFormat = GL_COMPRESSED_ARGB_4444_VQ_KOS; - } - } - break; - default: - fprintf(stderr, "Invalid texture format"); - return 0; - } - } - } else { - printf("Uncompressed - "); - //printf("Color:%u -", format); + if(image->compressed && image->twiddled) { switch(format) { case 0: + puts("Compressed & Twiddled - ARGB 1555"); + if(image->mipmapped) { + image->internalFormat = GL_COMPRESSED_ARGB_1555_VQ_MIPMAP_TWID_KOS; + } else { + image->internalFormat = GL_COMPRESSED_ARGB_1555_VQ_TWID_KOS; + } + return 1; + + case 1: + puts("Compressed & Twiddled - RGB 565"); + if(image->mipmapped) { + image->internalFormat = GL_COMPRESSED_RGB_565_VQ_MIPMAP_TWID_KOS; + } else { + image->internalFormat = GL_COMPRESSED_RGB_565_VQ_TWID_KOS; + } + return 1; + + case 2: + puts("Compressed & Twiddled - ARGB 4444"); + if(image->mipmapped) { + image->internalFormat = GL_COMPRESSED_ARGB_4444_VQ_MIPMAP_TWID_KOS; + } else { + image->internalFormat = GL_COMPRESSED_ARGB_4444_VQ_TWID_KOS; + } + return 1; + + } + } else if (image->compressed) { + switch(format) { + case 0: + puts("Compressed - ARGB 1555"); + if(image->mipmapped) { + image->internalFormat = GL_COMPRESSED_ARGB_1555_VQ_MIPMAP_KOS; + } else { + image->internalFormat = GL_COMPRESSED_ARGB_1555_VQ_KOS; + } + return 1; + + case 1: + puts("Compressed - RGB 565"); + if(image->mipmapped) { + image->internalFormat = GL_COMPRESSED_RGB_565_VQ_MIPMAP_KOS; + } else { + image->internalFormat = GL_COMPRESSED_RGB_565_VQ_KOS; + } + return 1; + + case 2: + puts("Compressed - ARGB 4444"); + if(image->mipmapped) { + image->internalFormat = GL_COMPRESSED_ARGB_4444_VQ_MIPMAP_KOS; + } else { + image->internalFormat = GL_COMPRESSED_ARGB_4444_VQ_KOS; + } + return 1; + } + } else { + switch (format) { + case 0: + puts("Uncompressed - ARGB 1555"); image->internalFormat = GL_UNSIGNED_SHORT_1_5_5_5_REV_TWID_KOS; //image->internalFormat = GL_UNSIGNED_SHORT_1_5_5_5_REV; - break; + return 1; + case 1: + puts("Uncompressed - RGB 565"); image->internalFormat = GL_UNSIGNED_SHORT_5_6_5_REV; - break; + return 1; + case 2: + puts("Uncompressed - ARGB 4444"); image->internalFormat = GL_UNSIGNED_SHORT_4_4_4_4_REV; - break; + return 1; } } - printf("\n"); + + fprintf(stderr, "Invalid texture format %u\n", header.type); + return 0; } int dtex_to_gl_texture(texture *tex, char* filename) { From 455ad29e4c05c1f81a4d60efaa08d43b5df776ba Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Wed, 5 Feb 2025 21:42:50 +1100 Subject: [PATCH 69/72] At least the provided .dtex files load now --- samples/depth_funcs_alpha_testing/gl_png.c | 33 ++++++++-------------- samples/depth_funcs_alpha_testing/gl_png.h | 2 +- 2 files changed, 12 insertions(+), 23 deletions(-) diff --git a/samples/depth_funcs_alpha_testing/gl_png.c b/samples/depth_funcs_alpha_testing/gl_png.c index 2d16032..29becd4 100644 --- a/samples/depth_funcs_alpha_testing/gl_png.c +++ b/samples/depth_funcs_alpha_testing/gl_png.c @@ -101,18 +101,23 @@ static int decode_dtex(Image* image, FILE* file) { switch (format) { case 0: puts("Uncompressed - ARGB 1555"); - image->internalFormat = GL_UNSIGNED_SHORT_1_5_5_5_REV_TWID_KOS; - //image->internalFormat = GL_UNSIGNED_SHORT_1_5_5_5_REV; + image->internalFormat = GL_ARGB1555_TWID_KOS; + image->transferFormat = GL_BGRA; + image->transferType = GL_UNSIGNED_SHORT_1_5_5_5_REV_TWID_KOS; return 1; case 1: puts("Uncompressed - RGB 565"); - image->internalFormat = GL_UNSIGNED_SHORT_5_6_5_REV; + image->internalFormat = GL_RGB565_TWID_KOS; + image->transferFormat = GL_RGB; + image->transferType = GL_UNSIGNED_SHORT_5_6_5_TWID_KOS; return 1; case 2: puts("Uncompressed - ARGB 4444"); - image->internalFormat = GL_UNSIGNED_SHORT_4_4_4_4_REV; + image->internalFormat = GL_ARGB4444_TWID_KOS; + image->transferFormat = GL_BGRA; + image->transferType = GL_UNSIGNED_SHORT_4_4_4_4_REV_TWID_KOS; return 1; } } @@ -141,30 +146,14 @@ int dtex_to_gl_texture(texture *tex, char* filename) { glGenTextures(1, &texture_id); glBindTexture(GL_TEXTURE_2D, texture_id); // 2d texture (x and y size) - GLint newFormat = GL_RGB; - GLint colorType = GL_RGB; - - if (image.internalFormat == GL_UNSIGNED_SHORT_1_5_5_5_REV_TWID_KOS || - image.internalFormat == GL_UNSIGNED_SHORT_4_4_4_4_REV){ - newFormat = GL_BGRA; - colorType = GL_RGBA; - printf("Reversing RGBA\n"); - } - - if (image.internalFormat == GL_UNSIGNED_SHORT_5_6_5_REV){ - newFormat = GL_RGB; - colorType = GL_RGB; - printf("Reversing RGB\n"); - } - if (image.compressed) { glCompressedTexImage2D(GL_TEXTURE_2D, 0, image.internalFormat, image.sizeX, image.sizeY, 0, image.dataSize, image.data); } else { glTexImage2D(GL_TEXTURE_2D, 0, - colorType, image.sizeX, image.sizeY, 0, - newFormat, image.internalFormat, image.data); + image.internalFormat, image.sizeX, image.sizeY, 0, + image.transferFormat, image.transferType, image.data); } tex->id = texture_id; diff --git a/samples/depth_funcs_alpha_testing/gl_png.h b/samples/depth_funcs_alpha_testing/gl_png.h index 0639e36..4b16eec 100644 --- a/samples/depth_funcs_alpha_testing/gl_png.h +++ b/samples/depth_funcs_alpha_testing/gl_png.h @@ -29,7 +29,7 @@ typedef struct Image { unsigned long sizeX; unsigned long sizeY; char *data; - GLenum internalFormat; + GLenum internalFormat, transferFormat, transferType; unsigned int mipmapped, compressed, twiddled; unsigned int dataSize; } Image; From 62cb72091d8da93a3ab2e1ccff5517250741f82e Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Wed, 5 Feb 2025 21:47:35 +1100 Subject: [PATCH 70/72] Fix wrong glEnable call --- samples/depth_funcs_alpha_testing/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/depth_funcs_alpha_testing/main.c b/samples/depth_funcs_alpha_testing/main.c index 517d6a0..257b093 100644 --- a/samples/depth_funcs_alpha_testing/main.c +++ b/samples/depth_funcs_alpha_testing/main.c @@ -88,7 +88,7 @@ void DrawGLScene() glLoadIdentity(); glTranslated(-1 , -1, -5); glDepthFunc(GL_LESS); - glEnable(GL_DEPTH_FUNC); + glEnable(GL_DEPTH_TEST); for (int i = 0; i < 5; i++) { glTranslated(0.5, 0, -0.2); From 41e30028df8ffa68b36a9426dfb3229171afc475 Mon Sep 17 00:00:00 2001 From: GPF Date: Wed, 5 Feb 2025 10:42:05 -0700 Subject: [PATCH 71/72] fixed gluPerspective to use GLdouble instead of GLfloat for m4-single compilation. --- GL/glu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GL/glu.c b/GL/glu.c index 2ed4444..9b2f48d 100644 --- a/GL/glu.c +++ b/GL/glu.c @@ -4,9 +4,9 @@ /* Set the Perspective */ void APIENTRY gluPerspective(GLdouble angle, GLdouble aspect, GLdouble znear, GLdouble zfar) { - GLfloat fW, fH; + GLdouble fW, fH; - fH = tanf(angle * (M_PI / 360.0f)) * znear; + fH = tan(angle * (M_PI / 360.0)) * znear; fW = fH * aspect; glFrustum(-fW, fW, -fH, fH, znear, zfar); From b7ac22ec34d1f5a9a2bc387e64f0a7953fb992a5 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sat, 8 Feb 2025 12:23:43 +1100 Subject: [PATCH 72/72] Fix lighting using some values calculated for last vertex, instead of the current vertex --- GL/draw.c | 41 +++++------------------------------------ GL/lighting.c | 39 ++++++++++++++++++--------------------- GL/private.h | 8 +------- 3 files changed, 24 insertions(+), 64 deletions(-) diff --git a/GL/draw.c b/GL/draw.c index 6e0df5c..f39e00e 100644 --- a/GL/draw.c +++ b/GL/draw.c @@ -90,17 +90,6 @@ GL_FORCE_INLINE IndexParseFunc _calcParseIndexFunc(GLenum type) { x = __x; y = __y; z = __z; \ } - -GL_FORCE_INLINE void transformToEyeSpace(GLfloat* point) { - _glMatrixLoadModelView(); - mat_trans_single3_nodiv(point[0], point[1], point[2]); -} - -GL_FORCE_INLINE void transformNormalToEyeSpace(GLfloat* normal) { - _glMatrixLoadNormal(); - mat_trans_normal3(normal[0], normal[1], normal[2]); -} - GL_FORCE_INLINE PolyHeader *_glSubmissionTargetHeader(SubmissionTarget* target) { gl_assert(target->header_offset < aligned_vector_size(&target->output->vector)); return aligned_vector_at(&target->output->vector, target->header_offset); @@ -622,42 +611,22 @@ static void transform(SubmissionTarget* target) { } } -static void mat_transform_normal3(const float* xyz, const float* xyzOut, const uint32_t count, const uint32_t inStride, const uint32_t outStride) { - const uint8_t* dataIn = (const uint8_t*) xyz; - uint8_t* dataOut = (uint8_t*) xyzOut; - +static void mat_transform_normal3(VertexExtra* extra, const uint32_t count) { ITERATE(count) { - const float* in = (const float*) dataIn; - float* out = (float*) dataOut; - - TransformNormalNoMod(in, out); - - dataIn += inStride; - dataOut += outStride; + TransformNormalNoMod(extra->nxyz, extra->nxyz); + extra++; } } static void light(SubmissionTarget* target) { - - static AlignedVector* eye_space_data = NULL; - - if(!eye_space_data) { - eye_space_data = (AlignedVector*) malloc(sizeof(AlignedVector)); - aligned_vector_init(eye_space_data, sizeof(EyeSpaceData)); - } - - aligned_vector_resize(eye_space_data, target->count); - /* Perform lighting calculations and manipulate the colour */ Vertex* vertex = _glSubmissionTargetStart(target); VertexExtra* extra = aligned_vector_at(target->extras, 0); - EyeSpaceData* eye_space = (EyeSpaceData*) eye_space_data->data; _glMatrixLoadNormal(); - mat_transform_normal3(extra->nxyz, eye_space->n, target->count, sizeof(VertexExtra), sizeof(EyeSpaceData)); + mat_transform_normal3(extra, target->count); - EyeSpaceData* ES = aligned_vector_at(eye_space_data, 0); - _glPerformLighting(vertex, ES, target->count); + _glPerformLighting(vertex, extra, target->count); } GL_FORCE_INLINE int _calc_pvr_face_culling() { diff --git a/GL/lighting.c b/GL/lighting.c index fc61a1c..806ed61 100644 --- a/GL/lighting.c +++ b/GL/lighting.c @@ -499,14 +499,14 @@ GL_FORCE_INLINE void _glLightVertexPoint( #undef _PROCESS_COMPONENT } -void _glPerformLighting(Vertex* vertices, EyeSpaceData* es, const uint32_t count) { +void _glPerformLighting(Vertex* vertices, VertexExtra* extra, const uint32_t count) { GLubyte i; GLuint j; Material* material = _glActiveMaterial(); Vertex* vertex = vertices; - EyeSpaceData* data = es; + VertexExtra* data = extra; /* Calculate the colour material function once */ void (*updateColourMaterial)(const GLubyte*) = NULL; @@ -529,32 +529,29 @@ void _glPerformLighting(Vertex* vertices, EyeSpaceData* es, const uint32_t count } } - /* Calculate the ambient lighting and set up colour material */ + if(!_glEnabledLightCount()) { + return; + } + for(j = 0; j < count; ++j, ++vertex, ++data) { + /* Calculate the ambient lighting and set up colour material */ if(updateColourMaterial) { updateColourMaterial(vertex->bgra); } /* Copy the base colour across */ - vec4cpy(data->finalColour, material->baseColour); - } + float finalColour[4]; + vec4cpy(finalColour, material->baseColour); - if(!_glEnabledLightCount()) { - return; - } - - vertex = vertices; - data = es; - for(j = 0; j < count; ++j, ++vertex, ++data) { /* Direction to vertex in eye space */ float Vx = -vertex->xyz[0]; float Vy = -vertex->xyz[1]; float Vz = -vertex->xyz[2]; VEC3_NORMALIZE(Vx, Vy, Vz); - const float Nx = data->n[0]; - const float Ny = data->n[1]; - const float Nz = data->n[2]; + const float Nx = data->nxyz[0]; + const float Ny = data->nxyz[1]; + const float Nz = data->nxyz[2]; for(i = 0; i < MAX_GLDC_LIGHTS; ++i) { LightSource* light = _glLightAt(i); @@ -588,7 +585,7 @@ void _glPerformLighting(Vertex* vertices, EyeSpaceData* es, const uint32_t count if(NdotH < 0.0f) NdotH = 0.0f; _glLightVertexDirectional( - data->finalColour, + finalColour, i, LdotN, NdotH ); } else { @@ -627,17 +624,17 @@ void _glPerformLighting(Vertex* vertices, EyeSpaceData* es, const uint32_t count if(NdotH < 0.0f) NdotH = 0.0f; _glLightVertexPoint( - data->finalColour, + finalColour, i, LdotN, NdotH, att ); } } } - vertex->bgra[R8IDX] = clamp(data->finalColour[0] * 255.0f, 0, 255); - vertex->bgra[G8IDX] = clamp(data->finalColour[1] * 255.0f, 0, 255); - vertex->bgra[B8IDX] = clamp(data->finalColour[2] * 255.0f, 0, 255); - vertex->bgra[A8IDX] = clamp(data->finalColour[3] * 255.0f, 0, 255); + vertex->bgra[R8IDX] = clamp(finalColour[0] * 255.0f, 0, 255); + vertex->bgra[G8IDX] = clamp(finalColour[1] * 255.0f, 0, 255); + vertex->bgra[B8IDX] = clamp(finalColour[2] * 255.0f, 0, 255); + vertex->bgra[A8IDX] = clamp(finalColour[3] * 255.0f, 0, 255); } } diff --git a/GL/private.h b/GL/private.h index 422690d..cc42dae 100644 --- a/GL/private.h +++ b/GL/private.h @@ -445,13 +445,7 @@ GL_FORCE_INLINE GLboolean _glCheckImmediateModeInactive(const char* func) { return GL_FALSE; } -typedef struct { - float n[3]; // 12 bytes - float finalColour[4]; //28 bytes - uint32_t padding; // 32 bytes -} EyeSpaceData; - -extern void _glPerformLighting(Vertex* vertices, EyeSpaceData *es, const uint32_t count); +extern void _glPerformLighting(Vertex* vertices, VertexExtra* extra, const uint32_t count); unsigned char _glIsClippingEnabled(); void _glEnableClipping(unsigned char v);