From 9aee9fe970053e8382dea114747eb6724fe18b55 Mon Sep 17 00:00:00 2001 From: Hayden K <819028+mrneo240@users.noreply.github.com> Date: Fri, 5 Apr 2019 22:15:57 -0400 Subject: [PATCH 1/2] feat: add correct mipmapping * fixes memory layout and handling * allows paletted mipmapped textures --- GL/draw.c | 19 ++++++-- GL/state.c | 75 +++++++++++++++++++++++++++++-- GL/texture.c | 117 +++++++++++++++++++++++++++++++++++++----------- include/glkos.h | 2 + 4 files changed, 179 insertions(+), 34 deletions(-) diff --git a/GL/draw.c b/GL/draw.c index 753ee11..11dec52 100644 --- a/GL/draw.c +++ b/GL/draw.c @@ -1031,7 +1031,8 @@ static void submitVertices(GLenum mode, GLsizei first, GLuint count, GLenum type } /* No vertices? Do nothing */ - if(!count) { + //changed check + if(count < 3) { return; } @@ -1085,9 +1086,15 @@ static void submitVertices(GLenum mode, GLsizei first, GLuint count, GLenum type target->output = _glActivePolyList(); target->count = (mode == GL_TRIANGLE_FAN) ? ((count - 2) * 3) : count; + if(target->count < 3 || count < 3){ + printf("%s: %d = %u verts\n",__func__,count,target->count); + } target->header_offset = target->output->vector.size; target->start_offset = target->header_offset + 1; + if(target-count == 0){ + return; + } assert(target->count); /* Make sure we have enough room for all the "extra" data */ @@ -1207,8 +1214,8 @@ static void submitVertices(GLenum mode, GLsizei first, GLuint count, GLenum type glDepthFunc(GL_EQUAL); glEnable(GL_BLEND); - - /* This is modulation, we need to switch depending on the texture env mode! */ + + /* This is modulation, we need to switch depending on the texture env mode! */ glBlendFunc(GL_DST_COLOR, GL_ZERO); /* Send the buffer again to the transparent list */ @@ -1229,6 +1236,9 @@ void APIENTRY glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvo if(_glCheckImmediateModeInactive(__func__)) { return; } + if(count < 3){ + return; + } submitVertices(mode, 0, count, type, indices); } @@ -1239,6 +1249,9 @@ void APIENTRY glDrawArrays(GLenum mode, GLint first, GLsizei count) { if(_glCheckImmediateModeInactive(__func__)) { return; } + if(count < 3){ + return; + } submitVertices(mode, first, count, GL_UNSIGNED_INT, NULL); } diff --git a/GL/state.c b/GL/state.c index 253b528..1993e15 100644 --- a/GL/state.c +++ b/GL/state.c @@ -18,6 +18,61 @@ pvr_poly_cxt_t* _glGetPVRContext() { return &GL_CONTEXT; } +static GLubyte mipmap_bias = 4; + +GLAPI void APIENTRY glKOS_INTERNAL_SetMipmapBias(GLubyte level) { + switch(level){ + case 1: + mipmap_bias = PVR_MIPBIAS_0_25; + break; + case 2: + mipmap_bias = PVR_MIPBIAS_0_50; + break; + case 3: + mipmap_bias = PVR_MIPBIAS_0_75; + break; + case 4: + mipmap_bias = PVR_MIPBIAS_1_00; + break; + case 5: + mipmap_bias = PVR_MIPBIAS_1_25; + break; + case 6: + mipmap_bias = PVR_MIPBIAS_1_50; + break; + case 7: + mipmap_bias = PVR_MIPBIAS_1_75; + break; + case 8: + mipmap_bias = PVR_MIPBIAS_2_00; + break; + case 9: + mipmap_bias = PVR_MIPBIAS_2_25; + break; + case 10: + mipmap_bias = PVR_MIPBIAS_2_50; + break; + case 11: + mipmap_bias = PVR_MIPBIAS_2_75; + break; + case 12: + mipmap_bias = PVR_MIPBIAS_3_00; + break; + case 13: + mipmap_bias = PVR_MIPBIAS_3_25; + break; + case 14: + mipmap_bias = PVR_MIPBIAS_3_50; + break; + case 15: + mipmap_bias = PVR_MIPBIAS_3_75; + break; + default: + mipmap_bias = PVR_MIPBIAS_1_00; + break; + } +} + /* We can't just use the GL_CONTEXT for this state as the two * GL states are combined, so we store them separately and then @@ -180,6 +235,10 @@ void _glUpdatePVRTextureContext(pvr_poly_cxt_t* context, GLshort textureUnit) { break; } + if(tx1->height != tx1->width){ + enableMipmaps = GL_FALSE; + } + /* FIXME: If you disable mipmaps on a compressed mipmapped texture * you get corruption and I don't know why, so we force mipmapping for now */ if(tx1->isCompressed && _glIsMipmapComplete(tx1)) { @@ -216,16 +275,24 @@ void _glUpdatePVRTextureContext(pvr_poly_cxt_t* context, GLshort textureUnit) { context->txr.enable = PVR_TEXTURE_ENABLE; context->txr.filter = filter; context->txr.mipmap = (enableMipmaps) ? PVR_MIPMAP_ENABLE : PVR_MIPMAP_DISABLE; - context->txr.mipmap_bias = PVR_MIPBIAS_NORMAL; + context->txr.mipmap_bias = mipmap_bias; context->txr.width = tx1->width; context->txr.height = tx1->height; - context->txr.base = tx1->data; + if(enableMipmaps){ + context->txr.base = tx1->data; + } else { + context->txr.base = _glGetMipmapLocation((TextureObject*)tx1,0); + } + context->txr.format = tx1->color; if(tx1->isPaletted) { if(_glIsSharedTexturePaletteEnabled()) { - TexturePalette* palette = _glGetSharedPalette(tx1->shared_bank); - context->txr.format |= PVR_TXRFMT_8BPP_PAL((palette) ? 0 : palette->bank); + //TexturePalette* palette = _glGetSharedPalette(tx1->shared_bank); + context->txr.format |= PVR_TXRFMT_8BPP_PAL(tx1->shared_bank); + if(tx1->shared_bank != 0){ + //printf("%s chose bank %d!\n",__func__,tx1->shared_bank); + } } else { context->txr.format |= PVR_TXRFMT_8BPP_PAL((tx1->palette) ? tx1->palette->bank : 0); } diff --git a/GL/texture.c b/GL/texture.c index 1ea25c8..186ef23 100644 --- a/GL/texture.c +++ b/GL/texture.c @@ -163,21 +163,75 @@ static GLint _determineStride(GLenum format, GLenum type) { GLubyte* _glGetMipmapLocation(TextureObject* obj, GLuint level) { GLuint offset = 0; + if(obj->width == obj->height){ - GLuint i = 0; - GLuint width = obj->width; - GLuint height = obj->height; + if(obj->isPaletted){ + GLuint size = obj->height; - for(; i < level; ++i) { - offset += (width * height * obj->dataStride); + switch(size >> level){ + case 256: + offset = 0x05558; + break; + case 128: + offset = 0x01558; + break; + case 64: + offset = 0x00558; + break; + case 32: + offset = 0x00158; + break; + case 16: + offset = 0x00058; + break; + case 8: + offset = 0x00018; + break; + case 4: + offset = 0x00008; + break; + case 2: + offset = 0x00004; + break; + case 1: + case 0: + offset = 0x00000; + break; + } + } else { + GLuint size = obj->height; - if(width > 1) { - width /= 2; - } - - if(height > 1) { - height /= 2; - } + switch(size >> level){ + case 256: + offset = 0x0AAB0; + break; + case 128: + offset = 0x02AB0; + break; + case 64: + offset = 0x00AB0; + break; + case 32: + offset = 0x002B0; + break; + case 16: + offset = 0x000B0; + break; + case 8: + offset = 0x00030; + break; + case 4: + offset = 0x00010; + break; + case 2: + offset = 0x00008; + break; + case 1: + offset = 0x00006; + break; + } + + } } return ((GLubyte*) obj->data) + offset; @@ -194,7 +248,7 @@ static GLuint _glGetMipmapDataSize(TextureObject* obj) { GLuint width = obj->width; GLuint height = obj->height; - for(; i < _glGetMipmapLevelCount(obj); ++i) { + for(; i < _glGetMipmapLevelCount(obj)+1; ++i) { size += (width * height * obj->dataStride); if(width > 1) { @@ -491,6 +545,8 @@ void APIENTRY glCompressedTexImage2DARB(GLenum target, static GLint _cleanInternalFormat(GLint internalFormat) { switch (internalFormat) { + case GL_COLOR_INDEX4_EXT: + return GL_COLOR_INDEX4_EXT; case GL_COLOR_INDEX8_EXT: return GL_COLOR_INDEX8_EXT; case GL_ALPHA: @@ -613,6 +669,8 @@ static GLuint _determinePVRFormat(GLint internalFormat, GLenum type) { return PVR_TXRFMT_ARGB1555 | PVR_TXRFMT_TWIDDLED | PVR_TXRFMT_VQ_ENABLE; case GL_COLOR_INDEX8_EXT: return PVR_TXRFMT_PAL8BPP | PVR_TXRFMT_TWIDDLED; + case GL_COLOR_INDEX4_EXT: + return PVR_TXRFMT_PAL4BPP | PVR_TXRFMT_TWIDDLED; default: return 0; } @@ -763,15 +821,15 @@ GLboolean _glIsMipmapComplete(const TextureObject* obj) { if(!obj->mipmap || !obj->mipmapCount) { return GL_FALSE; } - + GLsizei i = 0; - for(; i < obj->mipmapCount; ++i) { - if((obj->mipmap & (1 << i)) == 0) { - return GL_FALSE; + for(; i < obj->mipmapCount-3; ++i) { + if((obj->mipmap & (1 << i)) == 1) { + return GL_TRUE; } } - return GL_TRUE; + return GL_FALSE; } #define TWIDTAB(x) ( (x&1)|((x&2)<<1)|((x&4)<<2)|((x&8)<<3)|((x&16)<<4)| \ @@ -812,16 +870,19 @@ void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat, } GLint w = width; - if(w < 8 || (w & -w) != w) { + GLint h = height; + if(level == 0){ + if((w < 8 || (w & -w) != w)) { /* Width is not a power of two. Must be!*/ _glKosThrowError(GL_INVALID_VALUE, "glTexImage2D"); } - GLint h = height; - if(h < 8 || (h & -h) != h) { + + if((h < 8 || (h & -h) != h)) { /* height is not a power of two. Must be!*/ _glKosThrowError(GL_INVALID_VALUE, "glTexImage2D"); } + } if(level < 0) { _glKosThrowError(GL_INVALID_VALUE, "glTexImage2D"); @@ -837,11 +898,6 @@ void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat, GLboolean isPaletted = (internalFormat == GL_COLOR_INDEX8_EXT) ? GL_TRUE : GL_FALSE; - if(isPaletted && level > 0) { - /* Paletted textures can't have mipmaps */ - _glKosThrowError(GL_INVALID_OPERATION, __func__); - } - if(_glKosHasError()) { _glKosPrintError(); return; @@ -854,7 +910,7 @@ void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat, assert(active); - if(active->data) { + if(active->data && (level == 0) ) { /* pre-existing texture - check if changed */ if(active->width != width || active->height != height || @@ -948,11 +1004,18 @@ void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat, min = MIN(w, h); mask = min - 1; + if(height == 1 || width == 1){ + targetData[0] = ((GLubyte*)data)[0]; + targetData[1] = ((GLubyte*)data)[0]; + targetData[2] = ((GLubyte*)data)[0]; + targetData[3] = ((GLubyte*)data)[0]; + } else { for(y = 0; y < h; y += 2) { for(x = 0; x < w; x++) { vtex[TWIDOUT((y & mask) / 2, x & mask) + (x / min + y / min)*min * min / 2] = pixels[y * w + x] | (pixels[(y + 1) * w + x] << 8); } } + } } else { /* No conversion? Just copy the data, and the pvr_format is correct */ sq_cpy(targetData, data, bytes); diff --git a/include/glkos.h b/include/glkos.h index 34435bd..f99607c 100644 --- a/include/glkos.h +++ b/include/glkos.h @@ -67,6 +67,8 @@ GLAPI void APIENTRY glKosInitConfig(GLdcConfig* config); GLAPI void APIENTRY glKosInitEx(GLdcConfig* config); GLAPI void APIENTRY glKosSwapBuffers(); +GLAPI void APIENTRY glKOS_INTERNAL_SetMipmapBias(GLubyte level); + /* * CUSTOM EXTENSION multiple_shared_palette_KOS * From d3cb7d1b216202816d9b8bf6cbf86ec60f189c6e Mon Sep 17 00:00:00 2001 From: Hayden K <819028+mrneo240@users.noreply.github.com> Date: Sun, 7 Apr 2019 19:34:08 -0400 Subject: [PATCH 2/2] fix: minor memory cleanup --- containers/named_array.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/containers/named_array.c b/containers/named_array.c index c028e96..bbfd66f 100644 --- a/containers/named_array.c +++ b/containers/named_array.c @@ -12,6 +12,8 @@ #include "named_array.h" +#define assert__(x) for ( ; !(x) ; assert(x) ) + void named_array_init(NamedArray* array, unsigned int element_size, unsigned int max_elements) { array->element_size = element_size; array->max_element_count = max_elements; @@ -28,6 +30,7 @@ void named_array_init(NamedArray* array, unsigned int element_size, unsigned int array->used_markers = (unsigned char*) malloc(array->marker_count); #endif memset(array->used_markers, 0, sizeof(unsigned char) * array->marker_count); + memset(array->elements, 0, element_size * max_elements); } char named_array_used(NamedArray* array, unsigned int id) { @@ -56,6 +59,17 @@ void* named_array_alloc(NamedArray* array, unsigned int* new_id) { return NULL; } +#define BYTE_TO_BINARY_PATTERN "%c%c%c%c%c%c%c%c" +#define BYTE_TO_BINARY(byte) \ + (byte & 0x80 ? '1' : '0'), \ + (byte & 0x40 ? '1' : '0'), \ + (byte & 0x20 ? '1' : '0'), \ + (byte & 0x10 ? '1' : '0'), \ + (byte & 0x08 ? '1' : '0'), \ + (byte & 0x04 ? '1' : '0'), \ + (byte & 0x02 ? '1' : '0'), \ + (byte & 0x01 ? '1' : '0') + void* named_array_reserve(NamedArray* array, unsigned int id) { if(!named_array_used(array, id)) { unsigned int j = (id % 8); @@ -63,6 +77,11 @@ void* named_array_reserve(NamedArray* array, unsigned int id) { assert(!named_array_used(array, id)); array->used_markers[i] |= (unsigned char) 1 << j; + + assert__(named_array_used(array, id)) { + printf("%s: id %d is not used in [%d,%d] = "BYTE_TO_BINARY_PATTERN"\n",__func__,id,i,j, BYTE_TO_BINARY(array->used_markers[i])); + } + assert(named_array_used(array, id)); unsigned char* ptr = &array->elements[id * array->element_size];