diff --git a/GL/framebuffer.c b/GL/framebuffer.c index 8e86493..cd77798 100644 --- a/GL/framebuffer.c +++ b/GL/framebuffer.c @@ -222,6 +222,9 @@ void APIENTRY glGenerateMipmapEXT(GLenum target) { GLuint prevWidth = tex->width; GLuint prevHeight = tex->height; + /* Make sure there is room for the mipmap data on the texture object */ + _glAllocateSpaceForMipmaps(tex); + for(; i < _glGetMipmapLevelCount(tex); ++i) { GLubyte* prevData = _glGetMipmapLocation(tex, i - 1); GLubyte* thisData = _glGetMipmapLocation(tex, i); diff --git a/GL/private.h b/GL/private.h index 45286f8..d708fef 100644 --- a/GL/private.h +++ b/GL/private.h @@ -200,6 +200,7 @@ pvr_poly_cxt_t* _glGetPVRContext(); GLubyte _glInitTextures(); void _glUpdatePVRTextureContext(pvr_poly_cxt_t* context, GLshort textureUnit); +void _glAllocateSpaceForMipmaps(TextureObject* active); typedef struct { const void* ptr; diff --git a/GL/texture.c b/GL/texture.c index 1ea25c8..62bc950 100644 --- a/GL/texture.c +++ b/GL/texture.c @@ -781,6 +781,31 @@ GLboolean _glIsMipmapComplete(const TextureObject* obj) { #define MIN(a, b) ( (a)<(b)? (a):(b) ) +void _glAllocateSpaceForMipmaps(TextureObject* active) { + if(active->data && active->mipmap > 1) { + /* Already done */ + return; + } + + /* We've allocated level 0 before, but now we're allocating + * a level beyond that, we need to reallocate the data, copy level 0 + * then free the original + */ + + GLubyte* src = active->data; + GLubyte* dest = active->data = pvr_mem_malloc(_glGetMipmapDataSize(active)); + + /* If there was existing data, then copy it across before freeing */ + if(src) { + GLuint i = 0; + for(; i < active->width * active->height * active->dataStride; ++i) { + *dest++ = *src++; + } + + pvr_mem_free(src); + } +} + void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *data) { @@ -888,7 +913,12 @@ void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat, active->mipmapCount = _glGetMipmapLevelCount(active); active->dataStride = destStride; - GLuint size = _glGetMipmapDataSize(active); + GLuint size = bytes; + + /* If we're uploading a mipmap level, we need to allocate the full amount of space */ + if(level > 0) { + size = _glGetMipmapDataSize(active); + } assert(size); active->data = pvr_mem_malloc(size); @@ -898,6 +928,12 @@ void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat, active->isPaletted = isPaletted; } + /* We're supplying a mipmap level, but previously we only had + * data for the first level (level 0, e.g. 1 << 0 == 1) */ + if(level > 0 && active->mipmap == 1) { + _glAllocateSpaceForMipmaps(active); + } + /* Mark this level as set in the mipmap bitmask */ active->mipmap |= (1 << level);