From e3a6f57ad6c0e7bda5d45eb146194ed39f45abdd Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Mon, 28 Sep 2009 09:28:50 -0600 Subject: st/mesa: fix/simplify st_texture_object::lastLevel calculation Don't compute the st_texture_object::lastLevel field based on the texture filters. Use the _MaxLevel value that core Mesa computes for us. When called from the GenerateMipmap path, we'll use the lastLevel field as-is. --- src/mesa/state_tracker/st_cb_texture.c | 62 +++++----------------------------- 1 file changed, 9 insertions(+), 53 deletions(-) (limited to 'src/mesa/state_tracker') diff --git a/src/mesa/state_tracker/st_cb_texture.c b/src/mesa/state_tracker/st_cb_texture.c index cfa33d48e1..085da3eab4 100644 --- a/src/mesa/state_tracker/st_cb_texture.c +++ b/src/mesa/state_tracker/st_cb_texture.c @@ -1708,53 +1708,6 @@ st_CopyTexSubImage3D(GLcontext * ctx, GLenum target, GLint level, } -/** - * Compute which mipmap levels that really need to be sent to the hardware. - * This depends on the base image size, GL_TEXTURE_MIN_LOD, - * GL_TEXTURE_MAX_LOD, GL_TEXTURE_BASE_LEVEL, and GL_TEXTURE_MAX_LEVEL. - */ -static void -calculate_first_last_level(struct st_texture_object *stObj) -{ - struct gl_texture_object *tObj = &stObj->base; - - /* These must be signed values. MinLod and MaxLod can be negative numbers, - * and having firstLevel and lastLevel as signed prevents the need for - * extra sign checks. - */ - GLint firstLevel; - GLint lastLevel; - - /* Yes, this looks overly complicated, but it's all needed. - */ - switch (tObj->Target) { - case GL_TEXTURE_1D: - case GL_TEXTURE_2D: - case GL_TEXTURE_3D: - case GL_TEXTURE_CUBE_MAP: - if (tObj->MinFilter == GL_NEAREST || tObj->MinFilter == GL_LINEAR) { - /* GL_NEAREST and GL_LINEAR only care about GL_TEXTURE_BASE_LEVEL. - */ - firstLevel = lastLevel = tObj->BaseLevel; - } - else { - firstLevel = 0; - lastLevel = MIN2(tObj->MaxLevel, - (int) tObj->Image[0][tObj->BaseLevel]->WidthLog2); - } - break; - case GL_TEXTURE_RECTANGLE_NV: - case GL_TEXTURE_4D_SGIS: - firstLevel = lastLevel = 0; - break; - default: - return; - } - - stObj->lastLevel = lastLevel; -} - - static void copy_image_data_to_texture(struct st_context *st, struct st_texture_object *stObj, @@ -1818,13 +1771,16 @@ st_finalize_texture(GLcontext *ctx, *needFlush = GL_FALSE; - /* We know/require this is true by now: - */ - assert(stObj->base._Complete); + if (stObj->base._Complete) { + /* The texture is complete and we know exactly how many mipmap levels + * are present/needed. This is conditional because we may be called + * from the st_generate_mipmap() function when the texture object is + * incomplete. In that case, we'll have set stObj->lastLevel before + * we get here. + */ + stObj->lastLevel = stObj->base._MaxLevel - stObj->base.BaseLevel; + } - /* What levels must the texture include at a minimum? - */ - calculate_first_last_level(stObj); firstImage = st_texture_image(stObj->base.Image[0][stObj->base.BaseLevel]); /* If both firstImage and stObj point to a texture which can contain -- cgit v1.2.3 From c7fddaf6122da489f4430f6bc2211bcb4740f416 Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Fri, 25 Sep 2009 17:24:27 -0600 Subject: st/mesa: fix st_generate_mipmap() issues The main issue is we didn't always have a gallium texture object with enough space to store the to-be-generated mipmap levels. When that's the case, allocate a new gallium texture and use st_texure_finalize() to copy images from the old texture to the new one. We also had the baseLevel parameter to st_render_mipmap() wrong. --- src/mesa/state_tracker/st_gen_mipmap.c | 82 +++++++++++++++++++++++++++++++++- 1 file changed, 80 insertions(+), 2 deletions(-) (limited to 'src/mesa/state_tracker') diff --git a/src/mesa/state_tracker/st_gen_mipmap.c b/src/mesa/state_tracker/st_gen_mipmap.c index 58f6933652..f75b2348b8 100644 --- a/src/mesa/state_tracker/st_gen_mipmap.c +++ b/src/mesa/state_tracker/st_gen_mipmap.c @@ -27,6 +27,7 @@ #include "main/imports.h" +#include "main/macros.h" #include "main/mipmap.h" #include "main/teximage.h" #include "main/texformat.h" @@ -161,6 +162,43 @@ fallback_generate_mipmap(GLcontext *ctx, GLenum target, } +/** + * Compute the expected number of mipmap levels in the texture given + * the width/height/depth of the base image and the GL_TEXTURE_BASE_LEVEL/ + * GL_TEXTURE_MAX_LEVEL settings. This will tell us how many mipmap + * level should be generated. + */ +static GLuint +compute_num_levels(GLcontext *ctx, + struct gl_texture_object *texObj, + GLenum target) +{ + if (target == GL_TEXTURE_RECTANGLE_ARB) { + return 1; + } + else { + const GLuint maxLevels = texObj->MaxLevel - texObj->BaseLevel + 1; + const struct gl_texture_image *baseImage = + _mesa_get_tex_image(ctx, texObj, target, texObj->BaseLevel); + GLuint size, numLevels; + + size = MAX2(baseImage->Width2, baseImage->Height2); + size = MAX2(size, baseImage->Depth2); + + numLevels = 0; + + while (size > 0) { + numLevels++; + size >>= 1; + } + + numLevels = MIN2(numLevels, maxLevels); + + return numLevels; + } +} + + void st_generate_mipmap(GLcontext *ctx, GLenum target, struct gl_texture_object *texObj) @@ -174,9 +212,49 @@ st_generate_mipmap(GLcontext *ctx, GLenum target, if (!pt) return; - lastLevel = pt->last_level; + /* find expected last mipmap level */ + lastLevel = compute_num_levels(ctx, texObj, target) - 1; + + if (pt->last_level < lastLevel) { + /* The current gallium texture doesn't have space for all the + * mipmap levels we need to generate. So allocate a new texture. + */ + struct st_texture_object *stObj = st_texture_object(texObj); + struct pipe_texture *oldTex = stObj->pt; + GLboolean needFlush; + + /* create new texture with space for more levels */ + stObj->pt = st_texture_create(st, + oldTex->target, + oldTex->format, + lastLevel, + oldTex->width[0], + oldTex->height[0], + oldTex->depth[0], + oldTex->tex_usage); + + /* The texture isn't in a "complete" state yet so set the expected + * lastLevel here, since it won't get done in st_finalize_texture(). + */ + stObj->lastLevel = lastLevel; + + /* This will copy the old texture's base image into the new texture + * which we just allocated. + */ + st_finalize_texture(ctx, st->pipe, texObj, &needFlush); + + /* release the old tex (will likely be freed too) */ + pipe_texture_reference(&oldTex, NULL); + + pt = stObj->pt; + } + + assert(lastLevel <= pt->last_level); - if (!st_render_mipmap(st, target, pt, baseLevel, lastLevel)) { + /* Recall that the Mesa BaseLevel image is stored in the gallium + * texture's level[0] position. So pass baseLevel=0 here. + */ + if (!st_render_mipmap(st, target, pt, 0, lastLevel)) { fallback_generate_mipmap(ctx, target, texObj); } -- cgit v1.2.3