intel: When making a new teximage miptree, make a full one.

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.
This commit is contained in:
Eric Anholt 2011-01-10 12:05:14 -08:00
parent bd4a2e9209
commit 48024fb44c
1 changed files with 66 additions and 77 deletions

View 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;
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;
/* 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;
}
/* 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: