From ba55ccd312e8a025f568ffcdc622660f146e2147 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Fri, 10 Jun 2011 12:00:23 -0700 Subject: [PATCH] mesa: Split _mesa_generate_mipmap along compressed/uncompressed lines. The path taken is wildly different based on this (do we generate from a temporary image, or from level-1's data), and we appear to have stride bugs in the compressed case that are tough to disentangle. This just duplicates the code for the moment, the followon commit will do the actual changes. Only real code change here is handling maxLevel in one common place. --- src/mesa/main/mipmap.c | 255 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 227 insertions(+), 28 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,20 @@ next_mipmap_level_size(GLenum target, GLint border, } } - - - -/** - * 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) +static void +generate_mipmap_uncompressed(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 +1966,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,9 +2041,9 @@ _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); @@ -2092,6 +2073,224 @@ _mesa_generate_mipmap(struct gl_context *ctx, GLenum target, } /* 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) +{ + 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); + + 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 */ +} + +/** + * 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