mesa: rework texture completeness testing
authorBrian Paul <brianp@vmware.com>
Sat, 17 Mar 2012 22:30:03 +0000 (16:30 -0600)
committerBrian Paul <brianp@vmware.com>
Tue, 20 Mar 2012 14:23:32 +0000 (08:23 -0600)
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 <jfonseca@vmware.com>
Reviewed-by: Eric Anholt <eric@anholt.net>
src/mesa/drivers/dri/intel/intel_tex_validate.c
src/mesa/main/mtypes.h
src/mesa/main/texobj.c
src/mesa/main/texobj.h
src/mesa/main/texparam.c
src/mesa/main/texstate.c
src/mesa/state_tracker/st_cb_texture.c
src/mesa/swrast/s_context.c
src/mesa/swrast/s_texfilter.c
src/mesa/swrast/s_texfilter.h

index a63068b9cffd4c108124821b2793935622fa6d2d..0f4a1a831933e20f8d17314349705d3a860390ab 100644 (file)
@@ -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?
     */
index f76096a4929fa5ebf30fbaad339ab1a978b90d78..c6e5b9467c040daae296923a6f7b9d99f9f7a018 100644 (file)
@@ -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 */
index c07e1ceba1b52f56f0037f3449ca714742a5a936..da27d9236e9abefe26cf0abd3c5dc818d47adf09 100644 (file)
@@ -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;
    }
index 03dfbe3045d3f29694e207469092e8b3f6f0d5fd..850091e9636a0ec16a321fecbe2f246dac3afa7f 100644 (file)
@@ -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 );
index 205f51f4231a29553d6f946786268bbc7becfeb6..9abc503e3149915230dfdc3e91e78c3edc96290a 100644 (file)
@@ -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;
          }
index 187ec9c366f453983ffe9dd8b2e16f09512df584..ee778ffd0475fcadb976d3a0ff9c1a6e427415b6 100644 (file)
@@ -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;
index ea59ccf255c0cfd50d7d5cb114077764ce7a34be..f9c190a68ad07a7b063f5484291bbaee94e67259 100644 (file)
@@ -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
index beb9158794ecc3d6c8200ee074fd4aaf9c23c4fa..432db71c8b0b355c3b8a03fd6e23e3d1c4d29df7 100644 (file)
@@ -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));
    }
 }
 
index d142d3d076273342cc60b5e88be255ac5cd470b2..412316f369fdf0a392f0ce9e6c38f9bff697e4b9 100644 (file)
@@ -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 {
index 69f2d80003a0187479c7a96b08d2c68868b46941..58b57365c7200082f9af2949047ea414f7be441d 100644 (file)
@@ -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