From f4a93e0665881dd58a95abb6525676bd1cc2e6af Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Sat, 17 Mar 2012 16:30:03 -0600 Subject: [PATCH] mesa: rework texture completeness testing MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Instead of gl_texture_object::_Complete there are now two fields: _BaseComplete and _MipmapComplete. The former indicates whether the base texture level is valid. The later indicates whether the whole mipmap is valid. With sampler objects, a single texture can appear to be both complete and incomplete at the same time. See the GL_ARB_sampler_objects spec for more details. To implement this we now check if the texture is complete with respect to a sampler state. Another benefit of this is we no longer need to invalidate a texture's completeness state when we change the minification/magnification filters with glTexParameter(). Reviewed-by: José Fonseca Reviewed-by: Eric Anholt --- src/mesa/drivers/dri/intel/intel_tex_validate.c | 2 +- src/mesa/main/mtypes.h | 3 +- src/mesa/main/texobj.c | 69 ++++++++++++++++--------- src/mesa/main/texobj.h | 13 +++++ src/mesa/main/texparam.c | 7 ++- src/mesa/main/texstate.c | 7 ++- src/mesa/state_tracker/st_cb_texture.c | 2 +- src/mesa/swrast/s_context.c | 5 +- src/mesa/swrast/s_texfilter.c | 6 ++- src/mesa/swrast/s_texfilter.h | 3 +- 10 files changed, 79 insertions(+), 38 deletions(-) diff --git a/src/mesa/drivers/dri/intel/intel_tex_validate.c b/src/mesa/drivers/dri/intel/intel_tex_validate.c index a63068b..0f4a1a8 100644 --- a/src/mesa/drivers/dri/intel/intel_tex_validate.c +++ b/src/mesa/drivers/dri/intel/intel_tex_validate.c @@ -45,7 +45,7 @@ intel_finalize_mipmap_tree(struct intel_context *intel, GLuint unit) /* We know/require this is true by now: */ - assert(intelObj->base._Complete); + assert(intelObj->base._BaseComplete); /* What levels must the tree include at a minimum? */ diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h index f76096a..c6e5b94 100644 --- a/src/mesa/main/mtypes.h +++ b/src/mesa/main/mtypes.h @@ -1316,7 +1316,8 @@ struct gl_texture_object GLenum Swizzle[4]; /**< GL_EXT_texture_swizzle */ GLuint _Swizzle; /**< same as Swizzle, but SWIZZLE_* format */ GLboolean GenerateMipmap; /**< GL_SGIS_generate_mipmap */ - GLboolean _Complete; /**< Is texture object complete? */ + GLboolean _BaseComplete; /**< Is the base texture level valid? */ + GLboolean _MipmapComplete; /**< Is the whole mipmap valid? */ GLboolean _RenderToTexture; /**< Any rendering to this texture? */ GLboolean Purgeable; /**< Is the buffer purgeable under memory pressure? */ GLboolean Immutable; /**< GL_ARB_texture_storage */ diff --git a/src/mesa/main/texobj.c b/src/mesa/main/texobj.c index c07e1ce..da27d92 100644 --- a/src/mesa/main/texobj.c +++ b/src/mesa/main/texobj.c @@ -262,7 +262,8 @@ _mesa_copy_texture_object( struct gl_texture_object *dest, dest->_MaxLevel = src->_MaxLevel; dest->_MaxLambda = src->_MaxLambda; dest->GenerateMipmap = src->GenerateMipmap; - dest->_Complete = src->_Complete; + dest->_BaseComplete = src->_BaseComplete; + dest->_MipmapComplete = src->_MipmapComplete; COPY_4V(dest->Swizzle, src->Swizzle); dest->_Swizzle = src->_Swizzle; @@ -386,14 +387,26 @@ _mesa_reference_texobj_(struct gl_texture_object **ptr, } +enum base_mipmap { BASE, MIPMAP }; + /** - * Mark a texture object as incomplete. + * Mark a texture object as incomplete. There are actually three kinds of + * (in)completeness: + * 1. "base incomplete": the base level of the texture is invalid so no + * texturing is possible. + * 2. "mipmap incomplete": a non-base level of the texture is invalid so + * mipmap filtering isn't possible, but non-mipmap filtering is. + * 3. "texture incompleteness": some combination of texture state and + * sampler state renders the texture incomplete. + * * \param t texture object + * \param bm either BASE or MIPMAP to indicate what's incomplete * \param fmt... string describing why it's incomplete (for debugging). */ static void -incomplete(struct gl_texture_object *t, const char *fmt, ...) +incomplete(struct gl_texture_object *t, enum base_mipmap bm, + const char *fmt, ...) { #if 0 va_list args; @@ -405,7 +418,9 @@ incomplete(struct gl_texture_object *t, const char *fmt, ...) printf("Texture Obj %d incomplete because: %s\n", t->Name, s); #endif - t->_Complete = GL_FALSE; + if (bm == BASE) + t->_BaseComplete = GL_FALSE; + t->_MipmapComplete = GL_FALSE; } @@ -429,18 +444,20 @@ _mesa_test_texobj_completeness( const struct gl_context *ctx, const struct gl_texture_image *baseImage; GLint maxLog2 = 0, maxLevels = 0; - t->_Complete = GL_TRUE; /* be optimistic */ + /* We'll set these to FALSE if tests fail below */ + t->_BaseComplete = GL_TRUE; + t->_MipmapComplete = GL_TRUE; /* Detect cases where the application set the base level to an invalid * value. */ if ((baseLevel < 0) || (baseLevel >= MAX_TEXTURE_LEVELS)) { - incomplete(t, "base level = %d is invalid", baseLevel); + incomplete(t, BASE, "base level = %d is invalid", baseLevel); return; } if (t->MaxLevel < baseLevel) { - incomplete(t, "MAX_LEVEL (%d) < BASE_LEVEL (%d)", + incomplete(t, BASE, "MAX_LEVEL (%d) < BASE_LEVEL (%d)", t->MaxLevel, baseLevel); return; } @@ -449,7 +466,7 @@ _mesa_test_texobj_completeness( const struct gl_context *ctx, /* Always need the base level image */ if (!baseImage) { - incomplete(t, "Image[baseLevel=%d] == NULL", baseLevel); + incomplete(t, BASE, "Image[baseLevel=%d] == NULL", baseLevel); return; } @@ -457,7 +474,7 @@ _mesa_test_texobj_completeness( const struct gl_context *ctx, if (baseImage->Width == 0 || baseImage->Height == 0 || baseImage->Depth == 0) { - incomplete(t, "texture width or height or depth = 0"); + incomplete(t, BASE, "texture width or height or depth = 0"); return; } @@ -525,26 +542,26 @@ _mesa_test_texobj_completeness( const struct gl_context *ctx, if (t->Image[face][baseLevel] == NULL || t->Image[face][baseLevel]->Width2 != w || t->Image[face][baseLevel]->Height2 != h) { - incomplete(t, "Cube face missing or mismatched size"); + incomplete(t, BASE, "Cube face missing or mismatched size"); return; } } } /* - * Do mipmap consistency checking + * Do mipmap consistency checking. + * Note: we don't care about the current texture sampler state here. + * To determine texture completeness we'll either look at _BaseComplete + * or _MipmapComplete depending on the current minification filter mode. */ - if (t->Sampler.MinFilter != GL_NEAREST && t->Sampler.MinFilter != GL_LINEAR) { - /* - * Mipmapping: determine if we have a complete set of mipmaps - */ + { GLint i; const GLint minLevel = baseLevel; const GLint maxLevel = t->_MaxLevel; GLuint width, height, depth, face, numFaces = 1; if (minLevel > maxLevel) { - incomplete(t, "minLevel > maxLevel"); + incomplete(t, BASE, "minLevel > maxLevel"); return; } @@ -572,27 +589,27 @@ _mesa_test_texobj_completeness( const struct gl_context *ctx, const struct gl_texture_image *img = t->Image[face][i]; if (!img) { - incomplete(t, "TexImage[%d] is missing", i); + incomplete(t, MIPMAP, "TexImage[%d] is missing", i); return; } if (img->TexFormat != baseImage->TexFormat) { - incomplete(t, "Format[i] != Format[baseLevel]"); + incomplete(t, MIPMAP, "Format[i] != Format[baseLevel]"); return; } if (img->Border != baseImage->Border) { - incomplete(t, "Border[i] != Border[baseLevel]"); + incomplete(t, MIPMAP, "Border[i] != Border[baseLevel]"); return; } if (img->Width2 != width) { - incomplete(t, "TexImage[%d] bad width %u", i, img->Width2); + incomplete(t, MIPMAP, "TexImage[%d] bad width %u", i, img->Width2); return; } if (img->Height2 != height) { - incomplete(t, "TexImage[%d] bad height %u", i, img->Height2); + incomplete(t, MIPMAP, "TexImage[%d] bad height %u", i, img->Height2); return; } if (img->Depth2 != depth) { - incomplete(t, "TexImage[%d] bad depth %u", i, img->Depth2); + incomplete(t, MIPMAP, "TexImage[%d] bad depth %u", i, img->Depth2); return; } @@ -601,7 +618,7 @@ _mesa_test_texobj_completeness( const struct gl_context *ctx, /* check that cube faces are the same size */ if (img->Width2 != t->Image[0][i]->Width2 || img->Height2 != t->Image[0][i]->Height2) { - incomplete(t, "CubeMap Image[n][i] bad size"); + incomplete(t, MIPMAP, "CubeMap Image[n][i] bad size"); return; } } @@ -666,7 +683,8 @@ void _mesa_dirty_texobj(struct gl_context *ctx, struct gl_texture_object *texObj, GLboolean invalidate_state) { - texObj->_Complete = GL_FALSE; + texObj->_BaseComplete = GL_FALSE; + texObj->_MipmapComplete = GL_FALSE; if (invalidate_state) ctx->NewState |= _NEW_TEXTURE; } @@ -789,7 +807,8 @@ _mesa_get_fallback_texture(struct gl_context *ctx, gl_texture_index tex) } _mesa_test_texobj_completeness(ctx, texObj); - assert(texObj->_Complete); + assert(texObj->_BaseComplete); + assert(texObj->_MipmapComplete); ctx->Shared->FallbackTex[tex] = texObj; } diff --git a/src/mesa/main/texobj.h b/src/mesa/main/texobj.h index 03dfbe3..850091e 100644 --- a/src/mesa/main/texobj.h +++ b/src/mesa/main/texobj.h @@ -35,6 +35,7 @@ #include "compiler.h" #include "glheader.h" #include "mtypes.h" +#include "samplerobj.h" /** @@ -77,6 +78,18 @@ _mesa_reference_texobj(struct gl_texture_object **ptr, } +/** Is the texture "complete" with respect to the given sampler state? */ +static inline GLboolean +_mesa_is_texture_complete(const struct gl_texture_object *texObj, + const struct gl_sampler_object *sampler) +{ + if (_mesa_is_mipmap_filter(sampler)) + return texObj->_MipmapComplete; + else + return texObj->_BaseComplete; +} + + extern void _mesa_test_texobj_completeness( const struct gl_context *ctx, struct gl_texture_object *obj ); diff --git a/src/mesa/main/texparam.c b/src/mesa/main/texparam.c index 205f51f..9abc503 100644 --- a/src/mesa/main/texparam.c +++ b/src/mesa/main/texparam.c @@ -212,8 +212,7 @@ flush(struct gl_context *ctx) /** * This is called just prior to changing any texture object state which - * can effect texture completeness (texture base level, max level, - * minification filter). + * can effect texture completeness (texture base level, max level). * Any pending rendering will be flushed out, we'll set the _NEW_TEXTURE * state flag and then mark the texture object as 'incomplete' so that any * per-texture derived state gets recomputed. @@ -242,7 +241,7 @@ set_tex_parameteri(struct gl_context *ctx, switch (params[0]) { case GL_NEAREST: case GL_LINEAR: - incomplete(ctx, texObj); + flush(ctx); texObj->Sampler.MinFilter = params[0]; return GL_TRUE; case GL_NEAREST_MIPMAP_NEAREST: @@ -251,7 +250,7 @@ set_tex_parameteri(struct gl_context *ctx, case GL_LINEAR_MIPMAP_LINEAR: if (texObj->Target != GL_TEXTURE_RECTANGLE_NV && texObj->Target != GL_TEXTURE_EXTERNAL_OES) { - incomplete(ctx, texObj); + flush(ctx); texObj->Sampler.MinFilter = params[0]; return GL_TRUE; } diff --git a/src/mesa/main/texstate.c b/src/mesa/main/texstate.c index 187ec9c..ee778ff 100644 --- a/src/mesa/main/texstate.c +++ b/src/mesa/main/texstate.c @@ -569,10 +569,13 @@ update_texture_state( struct gl_context *ctx ) for (texIndex = 0; texIndex < NUM_TEXTURE_TARGETS; texIndex++) { if (enabledTargets & (1 << texIndex)) { struct gl_texture_object *texObj = texUnit->CurrentTex[texIndex]; - if (!texObj->_Complete) { + struct gl_sampler_object *sampler = texUnit->Sampler ? + texUnit->Sampler : &texObj->Sampler; + + if (!_mesa_is_texture_complete(texObj, sampler)) { _mesa_test_texobj_completeness(ctx, texObj); } - if (texObj->_Complete) { + if (_mesa_is_texture_complete(texObj, sampler)) { texUnit->_ReallyEnabled = 1 << texIndex; _mesa_reference_texobj(&texUnit->_Current, texObj); break; diff --git a/src/mesa/state_tracker/st_cb_texture.c b/src/mesa/state_tracker/st_cb_texture.c index ea59ccf..f9c190a 100644 --- a/src/mesa/state_tracker/st_cb_texture.c +++ b/src/mesa/state_tracker/st_cb_texture.c @@ -1243,7 +1243,7 @@ st_finalize_texture(struct gl_context *ctx, enum pipe_format firstImageFormat; GLuint ptWidth, ptHeight, ptDepth, ptLayers; - if (stObj->base._Complete) { + if (_mesa_is_texture_complete(tObj, &tObj->Sampler)) { /* 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 diff --git a/src/mesa/swrast/s_context.c b/src/mesa/swrast/s_context.c index beb9158..432db71 100644 --- a/src/mesa/swrast/s_context.c +++ b/src/mesa/swrast/s_context.c @@ -30,6 +30,7 @@ #include "main/bufferobj.h" #include "main/colormac.h" #include "main/mtypes.h" +#include "main/samplerobj.h" #include "main/teximage.h" #include "program/prog_parameter.h" #include "program/prog_statevars.h" @@ -482,7 +483,9 @@ _swrast_update_texture_samplers(struct gl_context *ctx) if (tObj) { _mesa_update_fetch_functions(tObj); } - swrast->TextureSample[u] = _swrast_choose_texture_sample_func(ctx, tObj); + swrast->TextureSample[u] = + _swrast_choose_texture_sample_func(ctx, tObj, + _mesa_get_samplerobj(ctx, u)); } } diff --git a/src/mesa/swrast/s_texfilter.c b/src/mesa/swrast/s_texfilter.c index d142d3d..412316f 100644 --- a/src/mesa/swrast/s_texfilter.c +++ b/src/mesa/swrast/s_texfilter.c @@ -27,6 +27,7 @@ #include "main/context.h" #include "main/colormac.h" #include "main/imports.h" +#include "main/texobj.h" #include "s_context.h" #include "s_texfilter.h" @@ -3612,9 +3613,10 @@ null_sample_func( struct gl_context *ctx, */ texture_sample_func _swrast_choose_texture_sample_func( struct gl_context *ctx, - const struct gl_texture_object *t ) + const struct gl_texture_object *t, + const struct gl_sampler_object *sampler) { - if (!t || !t->_Complete) { + if (!t || !_mesa_is_texture_complete(t, sampler)) { return &null_sample_func; } else { diff --git a/src/mesa/swrast/s_texfilter.h b/src/mesa/swrast/s_texfilter.h index 69f2d80..58b5736 100644 --- a/src/mesa/swrast/s_texfilter.h +++ b/src/mesa/swrast/s_texfilter.h @@ -35,7 +35,8 @@ struct gl_texture_object; extern texture_sample_func _swrast_choose_texture_sample_func( struct gl_context *ctx, - const struct gl_texture_object *tObj ); + const struct gl_texture_object *tObj, + const struct gl_sampler_object *sampler); #endif -- 2.7.4