From 588c082ec8fd2f3806a6a684162afaeabd9e1efa Mon Sep 17 00:00:00 2001 From: Luke Benstead Date: Mon, 11 Mar 2019 19:07:59 +0000 Subject: [PATCH 1/3] Allow specifying palette, autosort, memory options via glKosInitEx --- GL/flush.c | 27 +++++++++++++++++++++++---- GL/private.h | 1 + GL/texture.c | 25 +++++++++++++++++++++---- include/gl.h | 3 --- include/glkos.h | 28 +++++++++++++++++++++++++++- samples/paletted_pcx/main.c | 7 ++++++- 6 files changed, 78 insertions(+), 13 deletions(-) diff --git a/GL/flush.c b/GL/flush.c index 0b9dd8b..e5e5274 100644 --- a/GL/flush.c +++ b/GL/flush.c @@ -2,6 +2,7 @@ #include +#include "../include/glkos.h" #include "../containers/aligned_vector.h" #include "private.h" #include "profiler.h" @@ -38,14 +39,14 @@ static void pvr_list_submit(void *src, int n) { d[0] = d[8] = 0; } -static void _glInitPVR() { +static void _glInitPVR(GLboolean autosort) { pvr_init_params_t params = { /* Enable opaque and translucent polygons with size 32 and 32 */ {PVR_BINSIZE_32, PVR_BINSIZE_0, PVR_BINSIZE_32, PVR_BINSIZE_0, PVR_BINSIZE_32}, PVR_VERTEX_BUF_SIZE, /* Vertex buffer size */ 0, /* No DMA */ 0, /* No FSAA */ - 1 /* Disable translucent auto-sorting to match traditional GL */ + (autosort) ? 0 : 1 /* Disable translucent auto-sorting to match traditional GL */ }; pvr_init(¶ms); @@ -75,10 +76,16 @@ void APIENTRY glFinish() { } -void APIENTRY glKosInit() { +void APIENTRY glKosInitConfig(GLdcConfig* config) { + config->autosort_enabled = GL_FALSE; + config->initial_vbuf_capacity = 256; + config->internal_palette_format = GL_RGBA4; +} + +void APIENTRY glKosInitEx(GLdcConfig* config) { TRACE(); - _glInitPVR(); + _glInitPVR(config->autosort_enabled); _glInitMatrices(); _glInitAttributePointers(); @@ -87,6 +94,8 @@ void APIENTRY glKosInit() { _glInitImmediateMode(); _glInitFramebuffers(); + _glSetInternalPaletteFormat(GL_RGBA4); + _glInitTextures(); OP_LIST.list_type = PVR_LIST_OP_POLY; @@ -96,6 +105,16 @@ void APIENTRY glKosInit() { aligned_vector_init(&OP_LIST.vector, sizeof(ClipVertex)); aligned_vector_init(&PT_LIST.vector, sizeof(ClipVertex)); aligned_vector_init(&TR_LIST.vector, sizeof(ClipVertex)); + + aligned_vector_reserve(&OP_LIST.vector, config->initial_vbuf_capacity); + aligned_vector_reserve(&PT_LIST.vector, config->initial_vbuf_capacity); + aligned_vector_reserve(&TR_LIST.vector, config->initial_vbuf_capacity); +} + +void APIENTRY glKosInit() { + GLdcConfig config; + glKosInitConfig(&config); + glKosInitEx(&config); } #define QACRTA ((((unsigned int)0x10000000)>>26)<<2)&0x1c diff --git a/GL/private.h b/GL/private.h index 7465bc5..29392a1 100644 --- a/GL/private.h +++ b/GL/private.h @@ -147,6 +147,7 @@ TextureObject* _glGetBoundTexture(); GLubyte _glGetActiveTexture(); GLuint _glGetActiveClientTexture(); TexturePalette* _glGetSharedPalette(GLshort bank); +void _glSetInternalPaletteFormat(GLenum val); GLboolean _glIsSharedTexturePaletteEnabled(); void _glApplyColorTable(TexturePalette *palette); diff --git a/GL/texture.c b/GL/texture.c index 91ebf2f..53f2c66 100644 --- a/GL/texture.c +++ b/GL/texture.c @@ -24,9 +24,13 @@ static GLuint _determinePVRFormat(GLint internalFormat, GLenum type); #define PACK_ARGB8888(a,r,g,b) ( ((a & 0xFF) << 24) | ((r & 0xFF) << 16) | ((g & 0xFF) << 8) | (b & 0xFF) ) + +#define _PACK4(v) ((v * 0xF) / 0xFF) +#define PACK_ARGB4444(a,r,g,b) (_PACK4(a) << 12) | (_PACK4(r) << 8) | (_PACK4(g) << 4) | (_PACK4(b)) + static GLboolean BANKS_USED[4]; // Each time a 256 colour bank is used, this is set to true static GLboolean SUBBANKS_USED[4][16]; // 4 counts of the used 16 colour banks within the 256 ones - +static GLenum INTERNAL_PALETTE_FORMAT = GL_RGBA4; static TexturePalette* _initTexturePalette() { TexturePalette* palette = (TexturePalette*) malloc(sizeof(TexturePalette)); @@ -100,6 +104,17 @@ TexturePalette* _glGetSharedPalette(GLshort bank) { return SHARED_PALETTES[bank]; } +void _glSetInternalPaletteFormat(GLenum val) { + INTERNAL_PALETTE_FORMAT = val; + + if(INTERNAL_PALETTE_FORMAT == GL_RGBA4) { + pvr_set_pal_format(PVR_PAL_ARGB4444); + } else { + assert(INTERNAL_PALETTE_FORMAT == GL_RGBA8); + pvr_set_pal_format(PVR_PAL_ARGB8888); + } +} + void _glApplyColorTable(TexturePalette* src) { /* * FIXME: @@ -110,13 +125,15 @@ void _glApplyColorTable(TexturePalette* src) { return; } - pvr_set_pal_format(PVR_PAL_ARGB8888); - GLushort i; GLushort offset = src->size * src->bank; for(i = 0; i < src->width; ++i) { GLubyte* entry = &src->data[i * 4]; - pvr_set_pal_entry(offset + i, PACK_ARGB8888(entry[3], entry[0], entry[1], entry[2])); + if(INTERNAL_PALETTE_FORMAT == GL_RGBA8) { + pvr_set_pal_entry(offset + i, PACK_ARGB8888(entry[3], entry[0], entry[1], entry[2])); + } else { + pvr_set_pal_entry(offset + i, PACK_ARGB4444(entry[3], entry[0], entry[1], entry[2])); + } } } diff --git a/include/gl.h b/include/gl.h index 6a3bb5e..ec78f20 100644 --- a/include/gl.h +++ b/include/gl.h @@ -390,9 +390,6 @@ __BEGIN_DECLS #define GLAPI extern #define APIENTRY -/* Initialize the GL pipeline. GL will initialize the PVR. */ -GLAPI void APIENTRY glKosInit(); - GLAPI void APIENTRY glFlush(); GLAPI void APIENTRY glFinish(); diff --git a/include/glkos.h b/include/glkos.h index b809f73..ba2b323 100644 --- a/include/glkos.h +++ b/include/glkos.h @@ -35,8 +35,34 @@ __BEGIN_DECLS #define GL_UNSIGNED_BYTE_TWID_KOS 0xEEFB -GLAPI void APIENTRY glKosSwapBuffers(); +/* Initialize the GL pipeline. GL will initialize the PVR. */ +GLAPI void APIENTRY glKosInit(); +typedef struct { + /* If GL_TRUE, enables pvr autosorting, this *will* break glDepthFunc/glDepthTest */ + GLboolean autosort_enabled; + + /* The internal format for paletted textures, must be GL_RGBA4 (default) or GL_RGBA8 */ + GLenum internal_palette_format; + + /* Initial capacity of each of the OP, TR and PT lists in vertices */ + GLuint initial_vbuf_capacity; +} GLdcConfig; + + +GLAPI void APIENTRY glKosInitConfig(GLdcConfig* config); + +/* Usage: + * + * GLdcConfig config; + * glKosInitConfig(&config); + * + * config.autosort_enabled = GL_TRUE; + * + * glKosInitEx(&config); + */ +GLAPI void APIENTRY glKosInitEx(GLdcConfig* config); +GLAPI void APIENTRY glKosSwapBuffers(); /* * CUSTOM EXTENSION multiple_shared_palette_KOS diff --git a/samples/paletted_pcx/main.c b/samples/paletted_pcx/main.c index 8cb52fc..b82a54a 100644 --- a/samples/paletted_pcx/main.c +++ b/samples/paletted_pcx/main.c @@ -329,7 +329,12 @@ void DrawGLScene() int main(int argc, char **argv) { - glKosInit(); + GLdcConfig config; + glKosInitConfig(&config); + + config.internal_palette_format = GL_RGBA8; + + glKosInitEx(&config); InitGL(640, 480); ReSizeGLScene(640, 480); From 2485ea3428bf93ea06883b723500db9437893f14 Mon Sep 17 00:00:00 2001 From: Luke Benstead Date: Mon, 11 Mar 2019 19:08:32 +0000 Subject: [PATCH 2/3] Prove rectangular twiddling is broken --- samples/paletted_pcx/romdisk/NeHe.pcx | Bin 29379 -> 55420 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/samples/paletted_pcx/romdisk/NeHe.pcx b/samples/paletted_pcx/romdisk/NeHe.pcx index 267225f6c84220ee9067de31a8a4ce28db08ffa3..c234a720e91474aa0992972f20f6a65097ca9ede 100644 GIT binary patch literal 55420 zcmeFa3sjW%o$w!FlBOAu1Sw8zl-9{q$Oep}Eg4t(KSctVB`_H(9(78Xn8~439*G&I?f2J1|e?Pba z-Y&$QjsFMt>3EkN=L*Na>JG=d^y4qh@NqltRoBb>`QLFaJKl09O3LZ9=Y40>B*k{y z@wQu1&hq=|v=oo+9*ftjT$py1{}bo3;@v4}zU5N9^4rDPxxTa%cl>j4F7u+b{Bm)D z6iaqmN}@adH*t2naMd)Qys&xOOI=Oo9VyPuHiwek>WLnyOZ-yR~smUPh|u0ng2FKzDZ2 z0jSd?HM<7o*rg#kHZ<5Jwe_22Xgi1GjA_N2#reQ@hX%K`*Kg+Yn{(aVMGQyfN^wE9 z&tF=%Lv|iKEQhSa7oM^YAKba4ZgrOU&McQKDSb%alf%zHW$6cat2EaqU{@&&8@hfH z!DZf>s>W97mi-brw;p?J+OZK2cX6jc=D|apsP^Szsg<4WgQ0Nf{A1fUq`4$6-q-XP zAK2FZNW0X2ySTQ#y=&X%12WcGoWjZD-HB<-i=`Y&`}K4?<>29`?7`=T2JL5_I=Hh= zN+rt|UY?y>DxZC5$0NM=%!MIqP@WM0dq_&Na^V=|k`%Wxg7QJ0BHM25?w9>~_RLhn zuQJowQ;N4Mt3GyMXz)-|Zi={G1bm54scV-*z`(ILFL(3J-0hErVCGPG=+NPvr3+mb z`B;2PZu{WSb|5)Wo))i=r1)|Xq^A1XQhBKKURfgdN~yK_Qt7=}rL|vts5C3=%Pp?m zA$5Rqi8riLxp&FErBYX1ZZ&Nv&h?@k{y7SPgL;fFkU+Vz{O zIPl9Lp|(o~Ij`#5Fa{Rujp<9@Db`+>*5jG}mE=js$iF~^msc06QIeD98@Lf?97 z%6aR*{J0`n&-?%(D9py84 zVjGG89!`4)cF+T(@ZRCTe-nFP**Sq>)x*Z#p`vYviK8<2aDH=Q5Md< z3KXX;UwJJjUJZ(;p7@-@#cK?99l28!yZ-5_4h)9tyABOLW{q`9@jElbyFTsndfH45 zi}AA&JVyh&es~p!eI?GFRoi}Ouv6_qQ~9_$n^8A7%lsmMDVtSs@^_NL#%p Y*T*ARwu$N@|Y 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 From 957ebfa662cdf3dcc15cbcd2e1aa7d5a53885167 Mon Sep 17 00:00:00 2001 From: Luke Benstead Date: Mon, 11 Mar 2019 19:14:30 +0000 Subject: [PATCH 3/3] Fix texture twiddling --- GL/texture.c | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/GL/texture.c b/GL/texture.c index 53f2c66..a3c852f 100644 --- a/GL/texture.c +++ b/GL/texture.c @@ -774,19 +774,12 @@ GLboolean _glIsMipmapComplete(const TextureObject* obj) { return GL_TRUE; } +#define TWIDTAB(x) ( (x&1)|((x&2)<<1)|((x&4)<<2)|((x&8)<<3)|((x&16)<<4)| \ + ((x&32)<<5)|((x&64)<<6)|((x&128)<<7)|((x&256)<<8)|((x&512)<<9) ) -static inline GLuint morton_1by1(GLuint x) { - x &= 0x0000ffff; // x = ---- ---- ---- ---- fedc ba98 7654 3210 - x = (x ^ (x << 8)) & 0x00ff00ff; // x = ---- ---- fedc ba98 ---- ---- 7654 3210 - x = (x ^ (x << 4)) & 0x0f0f0f0f; // x = ---- fedc ---- ba98 ---- 7654 ---- 3210 - x = (x ^ (x << 2)) & 0x33333333; // x = --fe --dc --ba --98 --76 --54 --32 --10 - x = (x ^ (x << 1)) & 0x55555555; // x = -f-e -d-c -b-a -9-8 -7-6 -5-4 -3-2 -1-0 - return x; -} +#define TWIDOUT(x, y) ( TWIDTAB((y)) | (TWIDTAB((x)) << 1) ) +#define MIN(a, b) ( (a)<(b)? (a):(b) ) -static inline GLuint morton_index(GLuint x, GLuint y) { - return (morton_1by1(y) << 1) | morton_1by1(x); -} void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, @@ -947,16 +940,17 @@ void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat, if(needsTwiddling) { assert(type == GL_UNSIGNED_BYTE); // Anything else needs this loop adjusting - GLuint x, y; - for(y = 0; y < height; ++y) { - for(x = 0; x < width; ++x) { - GLuint src = (y * width) + x; - GLuint dest = morton_index(x, y); + GLuint x, y, min, min2, mask; - targetData[dest] = ((GLubyte*) data)[src]; + min = MIN(w, h); + min2 = min * min; + mask = min - 1; + + for(y = 0; y < h; y++) { + for(x = 0; x < w; x++) { + targetData[TWIDOUT(x & mask, y & mask) + (x / min + y / min) * min2] = ((GLubyte*) data)[y * w + x]; } } - } else { /* No conversion? Just copy the data, and the pvr_format is correct */ sq_cpy(targetData, data, bytes);