diff options
-rw-r--r-- | src/mesa/main/mipmap.c | 251 |
1 files changed, 225 insertions, 26 deletions
diff --git a/src/mesa/main/mipmap.c b/src/mesa/main/mipmap.c index e9fcb545a1e..2bdb1111813 100644 --- a/src/mesa/main/mipmap.c +++ b/src/mesa/main/mipmap.c @@ -1885,38 +1885,208 @@ next_mipmap_level_size(GLenum target, GLint border, } } +static void +generate_mipmap_uncompressed(struct gl_context *ctx, GLenum target, + struct gl_texture_object *texObj, + const struct gl_texture_image *srcImage, + GLuint maxLevel) +{ + GLint level; + gl_format convertFormat; + const GLubyte *srcData = NULL; + GLubyte *dstData = NULL; + GLenum datatype; + GLuint comps; + /* Find convertFormat - the format that do_row() will process */ + if (_mesa_is_format_compressed(srcImage->TexFormat)) { + /* setup for compressed textures - need to allocate temporary + * image buffers to hold uncompressed images. + */ + GLuint row; + GLint components, size; + GLchan *dst; + assert(texObj->Target == GL_TEXTURE_2D || + texObj->Target == GL_TEXTURE_CUBE_MAP_ARB); -/** - * Automatic mipmap generation. - * This is the fallback/default function for ctx->Driver.GenerateMipmap(). - * Generate a complete set of mipmaps from texObj's BaseLevel image. - * Stop at texObj's MaxLevel or when we get to the 1x1 texture. - * For cube maps, target will be one of - * GL_TEXTURE_CUBE_MAP_POSITIVE/NEGATIVE_X/Y/Z; never GL_TEXTURE_CUBE_MAP. - */ -void -_mesa_generate_mipmap(struct gl_context *ctx, GLenum target, - struct gl_texture_object *texObj) + if (srcImage->_BaseFormat == GL_RGB) { + convertFormat = MESA_FORMAT_RGB888; + components = 3; + } else if (srcImage->_BaseFormat == GL_RED) { + convertFormat = MESA_FORMAT_R8; + components = 1; + } else if (srcImage->_BaseFormat == GL_RG) { + convertFormat = MESA_FORMAT_RG88; + components = 2; + } else if (srcImage->_BaseFormat == GL_RGBA) { + convertFormat = MESA_FORMAT_RGBA8888; + components = 4; + } else if (srcImage->_BaseFormat == GL_LUMINANCE) { + convertFormat = MESA_FORMAT_L8; + components = 1; + } else if (srcImage->_BaseFormat == GL_LUMINANCE_ALPHA) { + convertFormat = MESA_FORMAT_AL88; + components = 2; + } else { + _mesa_problem(ctx, "bad srcImage->_BaseFormat in _mesa_generate_mipmaps"); + return; + } + + /* allocate storage for uncompressed GL_RGB or GL_RGBA images */ + size = _mesa_bytes_per_pixel(srcImage->_BaseFormat, CHAN_TYPE) + * srcImage->Width * srcImage->Height * srcImage->Depth + 20; + /* 20 extra bytes, just be safe when calling last FetchTexel */ + srcData = (GLubyte *) malloc(size); + if (!srcData) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "generate mipmaps"); + return; + } + dstData = (GLubyte *) malloc(size / 2); /* 1/4 would probably be OK */ + if (!dstData) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "generate mipmaps"); + free((void *) srcData); + return; + } + + /* decompress base image here */ + dst = (GLchan *) srcData; + for (row = 0; row < srcImage->Height; row++) { + GLuint col; + for (col = 0; col < srcImage->Width; col++) { + srcImage->FetchTexelc(srcImage, col, row, 0, dst); + dst += components; + } + } + } + else { + /* uncompressed */ + convertFormat = srcImage->TexFormat; + } + + _mesa_format_to_type_and_comps(convertFormat, &datatype, &comps); + + for (level = texObj->BaseLevel; level < maxLevel; level++) { + /* generate image[level+1] from image[level] */ + const struct gl_texture_image *srcImage; + struct gl_texture_image *dstImage; + GLint srcWidth, srcHeight, srcDepth; + GLint dstWidth, dstHeight, dstDepth; + GLint border; + GLboolean nextLevel; + + /* get src image parameters */ + srcImage = _mesa_select_tex_image(ctx, texObj, target, level); + ASSERT(srcImage); + srcWidth = srcImage->Width; + srcHeight = srcImage->Height; + srcDepth = srcImage->Depth; + border = srcImage->Border; + + nextLevel = next_mipmap_level_size(target, border, + srcWidth, srcHeight, srcDepth, + &dstWidth, &dstHeight, &dstDepth); + if (!nextLevel) { + /* all done */ + if (_mesa_is_format_compressed(srcImage->TexFormat)) { + free((void *) srcData); + free(dstData); + } + return; + } + + /* get dest gl_texture_image */ + dstImage = _mesa_get_tex_image(ctx, texObj, target, level + 1); + if (!dstImage) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps"); + return; + } + + /* Free old image data */ + if (dstImage->Data) + ctx->Driver.FreeTexImageData(ctx, dstImage); + + /* initialize new image */ + _mesa_init_teximage_fields(ctx, target, dstImage, dstWidth, dstHeight, + dstDepth, border, srcImage->InternalFormat, + srcImage->TexFormat); + dstImage->DriverData = NULL; + dstImage->FetchTexelc = srcImage->FetchTexelc; + dstImage->FetchTexelf = srcImage->FetchTexelf; + + /* Alloc new teximage data buffer */ + { + GLuint size = _mesa_format_image_size(dstImage->TexFormat, + dstWidth, dstHeight, dstDepth); + dstImage->Data = _mesa_alloc_texmemory(size); + if (!dstImage->Data) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps"); + return; + } + } + + /* Setup src and dest data pointers */ + if (_mesa_is_format_compressed(dstImage->TexFormat)) { + /* srcData and dstData are already set */ + ASSERT(srcData); + ASSERT(dstData); + } + else { + srcData = (const GLubyte *) srcImage->Data; + dstData = (GLubyte *) dstImage->Data; + } + + ASSERT(dstImage->TexFormat); + ASSERT(dstImage->FetchTexelc); + ASSERT(dstImage->FetchTexelf); + + _mesa_generate_mipmap_level(target, datatype, comps, border, + srcWidth, srcHeight, srcDepth, + srcData, srcImage->RowStride, + dstWidth, dstHeight, dstDepth, + dstData, dstImage->RowStride); + + + if (_mesa_is_format_compressed(dstImage->TexFormat)) { + GLubyte *temp; + /* compress image from dstData into dstImage->Data */ + const GLenum srcFormat = _mesa_get_format_base_format(convertFormat); + GLint dstRowStride + = _mesa_format_row_stride(dstImage->TexFormat, dstWidth); + + _mesa_texstore(ctx, 2, dstImage->_BaseFormat, + dstImage->TexFormat, + dstImage->Data, + 0, 0, 0, /* dstX/Y/Zoffset */ + dstRowStride, 0, /* strides */ + dstWidth, dstHeight, 1, /* size */ + srcFormat, CHAN_TYPE, + dstData, /* src data, actually */ + &ctx->DefaultPacking); + + /* swap src and dest pointers */ + temp = (GLubyte *) srcData; + srcData = dstData; + dstData = temp; + } + + } /* loop over mipmap levels */ +} + +static void +generate_mipmap_compressed(struct gl_context *ctx, GLenum target, + struct gl_texture_object *texObj, + const struct gl_texture_image *srcImage, + GLuint maxLevel) { - const struct gl_texture_image *srcImage; + GLint level; gl_format convertFormat; const GLubyte *srcData = NULL; GLubyte *dstData = NULL; - GLint level, maxLevels; GLenum datatype; GLuint comps; - ASSERT(texObj); - srcImage = _mesa_select_tex_image(ctx, texObj, target, texObj->BaseLevel); - ASSERT(srcImage); - - maxLevels = _mesa_max_texture_levels(ctx, texObj->Target); - ASSERT(maxLevels > 0); /* bad target */ - /* Find convertFormat - the format that do_row() will process */ - if (_mesa_is_format_compressed(srcImage->TexFormat)) { /* setup for compressed textures - need to allocate temporary * image buffers to hold uncompressed images. @@ -1984,8 +2154,7 @@ _mesa_generate_mipmap(struct gl_context *ctx, GLenum target, _mesa_format_to_type_and_comps(convertFormat, &datatype, &comps); - for (level = texObj->BaseLevel; level < texObj->MaxLevel - && level < maxLevels - 1; level++) { + for (level = texObj->BaseLevel; level < maxLevel; level++) { /* generate image[level+1] from image[level] */ const struct gl_texture_image *srcImage; struct gl_texture_image *dstImage; @@ -2060,12 +2229,11 @@ _mesa_generate_mipmap(struct gl_context *ctx, GLenum target, ASSERT(dstImage->FetchTexelf); _mesa_generate_mipmap_level(target, datatype, comps, border, - srcWidth, srcHeight, srcDepth, + srcWidth, srcHeight, srcDepth, srcData, srcImage->RowStride, - dstWidth, dstHeight, dstDepth, + dstWidth, dstHeight, dstDepth, dstData, dstImage->RowStride); - if (_mesa_is_format_compressed(dstImage->TexFormat)) { GLubyte *temp; /* compress image from dstData into dstImage->Data */ @@ -2092,6 +2260,37 @@ _mesa_generate_mipmap(struct gl_context *ctx, GLenum target, } /* loop over mipmap levels */ } +/** + * Automatic mipmap generation. + * This is the fallback/default function for ctx->Driver.GenerateMipmap(). + * Generate a complete set of mipmaps from texObj's BaseLevel image. + * Stop at texObj's MaxLevel or when we get to the 1x1 texture. + * For cube maps, target will be one of + * GL_TEXTURE_CUBE_MAP_POSITIVE/NEGATIVE_X/Y/Z; never GL_TEXTURE_CUBE_MAP. + */ +void +_mesa_generate_mipmap(struct gl_context *ctx, GLenum target, + struct gl_texture_object *texObj) +{ + const struct gl_texture_image *srcImage; + GLint maxLevel; + + ASSERT(texObj); + srcImage = _mesa_select_tex_image(ctx, texObj, target, texObj->BaseLevel); + ASSERT(srcImage); + + maxLevel = _mesa_max_texture_levels(ctx, texObj->Target) - 1; + ASSERT(maxLevel >= 0); /* bad target */ + + maxLevel = MIN2(maxLevel, texObj->MaxLevel); + + if (_mesa_is_format_compressed(srcImage->TexFormat)) { + generate_mipmap_compressed(ctx, target, texObj, srcImage, maxLevel); + } else { + generate_mipmap_uncompressed(ctx, target, texObj, srcImage, maxLevel); + } +} + /** * Helper function for drivers which need to rescale texture images to |