intel: When making a new teximage miptree, make a full one.
authorEric Anholt <eric@anholt.net>
Mon, 10 Jan 2011 20:05:14 +0000 (12:05 -0800)
committerEric Anholt <eric@anholt.net>
Tue, 11 Jan 2011 01:21:11 +0000 (17:21 -0800)
If we hit this path, we're level 1+ and the base level got allocated
as a single level instead of a full tree (so we don't match
intelObj->mt).  This tries to recover from that so that we end up with
2 allocations and 1 validation blit (old -> new) instead of
allocations equal to number of levels and levels - 1 blits.

src/mesa/drivers/dri/intel/intel_tex_image.c

index 450c3ce..cd8c4c2 100644 (file)
@@ -56,11 +56,11 @@ logbase2(int n)
  * 0)..(1x1).  Consider pruning this tree at a validation if the
  * saving is worth it.
  */
-static void
-guess_and_alloc_mipmap_tree(struct intel_context *intel,
-                            struct intel_texture_object *intelObj,
-                            struct intel_texture_image *intelImage,
-                           GLboolean expect_accelerated_upload)
+static struct intel_mipmap_tree *
+intel_miptree_create_for_teximage(struct intel_context *intel,
+                                 struct intel_texture_object *intelObj,
+                                 struct intel_texture_image *intelImage,
+                                 GLboolean expect_accelerated_upload)
 {
    GLuint firstLevel;
    GLuint lastLevel;
@@ -73,70 +73,71 @@ guess_and_alloc_mipmap_tree(struct intel_context *intel,
    DBG("%s\n", __FUNCTION__);
 
    if (intelImage->base.Border)
-      return;
+      return NULL;
 
    if (intelImage->level > intelObj->base.BaseLevel &&
        (intelImage->base.Width == 1 ||
         (intelObj->base.Target != GL_TEXTURE_1D &&
          intelImage->base.Height == 1) ||
         (intelObj->base.Target == GL_TEXTURE_3D &&
-         intelImage->base.Depth == 1)))
-      return;
-
-   /* If this image disrespects BaseLevel, allocate from level zero.
-    * Usually BaseLevel == 0, so it's unlikely to happen.
-    */
-   if (intelImage->level < intelObj->base.BaseLevel)
-      firstLevel = 0;
-   else
-      firstLevel = intelObj->base.BaseLevel;
-
-
-   /* Figure out image dimensions at start level. 
-    */
-   for (i = intelImage->level; i > firstLevel; i--) {
-      width <<= 1;
-      if (height != 1)
-         height <<= 1;
-      if (depth != 1)
-         depth <<= 1;
-   }
+         intelImage->base.Depth == 1))) {
+      /* For this combination, we're at some lower mipmap level and
+       * some important dimension is 1.  We can't extrapolate up to a
+       * likely base level width/height/depth for a full mipmap stack
+       * from this info, so just allocate this one level.
+       */
+      firstLevel = intelImage->level;
+      lastLevel = intelImage->level;
+   } else {
+      /* If this image disrespects BaseLevel, allocate from level zero.
+       * Usually BaseLevel == 0, so it's unlikely to happen.
+       */
+      if (intelImage->level < intelObj->base.BaseLevel)
+        firstLevel = 0;
+      else
+        firstLevel = intelObj->base.BaseLevel;
+
+      /* Figure out image dimensions at start level. */
+      for (i = intelImage->level; i > firstLevel; i--) {
+        width <<= 1;
+        if (height != 1)
+           height <<= 1;
+        if (depth != 1)
+           depth <<= 1;
+      }
 
-   /* Guess a reasonable value for lastLevel.  This is probably going
-    * to be wrong fairly often and might mean that we have to look at
-    * resizable buffers, or require that buffers implement lazy
-    * pagetable arrangements.
-    */
-   if ((intelObj->base.MinFilter == GL_NEAREST ||
-        intelObj->base.MinFilter == GL_LINEAR) &&
-       intelImage->level == firstLevel &&
-       (intel->gen < 4 || firstLevel == 0)) {
-      lastLevel = firstLevel;
-   }
-   else {
-      lastLevel = firstLevel + logbase2(MAX2(MAX2(width, height), depth));
+      /* Guess a reasonable value for lastLevel.  This is probably going
+       * to be wrong fairly often and might mean that we have to look at
+       * resizable buffers, or require that buffers implement lazy
+       * pagetable arrangements.
+       */
+      if ((intelObj->base.MinFilter == GL_NEAREST ||
+          intelObj->base.MinFilter == GL_LINEAR) &&
+         intelImage->level == firstLevel &&
+         (intel->gen < 4 || firstLevel == 0)) {
+        lastLevel = firstLevel;
+      } else {
+        lastLevel = firstLevel + logbase2(MAX2(MAX2(width, height), depth));
+      }
    }
 
-   assert(!intelObj->mt);
    if (_mesa_is_format_compressed(intelImage->base.TexFormat))
       comp_byte = intel_compressed_num_bytes(intelImage->base.TexFormat);
 
    texelBytes = _mesa_get_format_bytes(intelImage->base.TexFormat);
 
-   intelObj->mt = intel_miptree_create(intel,
-                                       intelObj->base.Target,
-                                       intelImage->base._BaseFormat,
-                                       intelImage->base.InternalFormat,
-                                       firstLevel,
-                                       lastLevel,
-                                       width,
-                                       height,
-                                       depth,
-                                       texelBytes,
-                                       comp_byte,
-                                      expect_accelerated_upload);
-
-   DBG("%s - success\n", __FUNCTION__);
+   return intel_miptree_create(intel,
+                              intelObj->base.Target,
+                              intelImage->base._BaseFormat,
+                              intelImage->base.InternalFormat,
+                              firstLevel,
+                              lastLevel,
+                              width,
+                              height,
+                              depth,
+                              texelBytes,
+                              comp_byte,
+                              expect_accelerated_upload);
 }
 
 
@@ -344,41 +345,29 @@ intelTexImage(struct gl_context * ctx,
       texImage->Data = NULL;
    }
 
-   if (!intelObj->mt) {
-      guess_and_alloc_mipmap_tree(intel, intelObj, intelImage, pixels == NULL);
-      if (!intelObj->mt) {
-        DBG("guess_and_alloc_mipmap_tree: failed\n");
-      }
-   }
-
    assert(!intelImage->mt);
 
    if (intelObj->mt &&
        intel_miptree_match_image(intelObj->mt, &intelImage->base)) {
-
+      /* Use an existing miptree when possible */
       intel_miptree_reference(&intelImage->mt, intelObj->mt);
       assert(intelImage->mt);
    } else if (intelImage->base.Border == 0) {
-      int comp_byte = 0;
-      GLuint texelBytes = _mesa_get_format_bytes(intelImage->base.TexFormat);
-      GLenum baseFormat = _mesa_get_format_base_format(intelImage->base.TexFormat);
-      if (_mesa_is_format_compressed(intelImage->base.TexFormat)) {
-        comp_byte =
-           intel_compressed_num_bytes(intelImage->base.TexFormat);
-      }
-
       /* Didn't fit in the object miptree, but it's suitable for inclusion in
        * a miptree, so create one just for our level and store it in the image.
        * It'll get moved into the object miptree at validate time.
        */
-      intelImage->mt = intel_miptree_create(intel, target,
-                                           baseFormat,
-                                           internalFormat,
-                                           level, level,
-                                           width, height, depth,
-                                           texelBytes,
-                                           comp_byte, pixels == NULL);
-
+      intelImage->mt = intel_miptree_create_for_teximage(intel, intelObj,
+                                                        intelImage,
+                                                        pixels == NULL);
+
+      /* Even if the object currently has a mipmap tree associated
+       * with it, this one is a more likely candidate to represent the
+       * whole object since our level didn't fit what was there
+       * before, and any lower levels would fit into our miptree.
+       */
+      if (intelImage->mt)
+        intel_miptree_reference(&intelObj->mt, intelImage->mt);
    }
 
    /* PBO fastpaths: