From 7ce6517f3ac41bf770ab39aba4509d4f535ef663 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 5 Jan 2011 17:02:08 -0800 Subject: [PATCH] intel: Always allocate miptrees from level 0, not tObj->BaseLevel. BaseLevel/MaxLevel are mostly used for two things: clamping texture access for FBO rendering, and limiting the used mipmap levels when incrementally loading textures. By restricting our mipmap trees to just the current BaseLevel/MaxLevel, we caused reallocation thrashing in the common case, for a theoretical win if someone really did want just levels 2..4 or whatever of their texture object. Bug #30366 --- src/mesa/drivers/dri/i965/brw_tex_layout.c | 4 +- src/mesa/drivers/dri/i965/brw_wm_sampler_state.c | 11 +- src/mesa/drivers/dri/i965/brw_wm_surface_state.c | 10 +- src/mesa/drivers/dri/intel/intel_mipmap_tree.c | 17 ++- src/mesa/drivers/dri/intel/intel_mipmap_tree.h | 6 +- src/mesa/drivers/dri/intel/intel_tex.h | 6 ++ src/mesa/drivers/dri/intel/intel_tex_image.c | 125 +++++++---------------- src/mesa/drivers/dri/intel/intel_tex_layout.c | 6 +- src/mesa/drivers/dri/intel/intel_tex_validate.c | 27 ++--- 9 files changed, 71 insertions(+), 141 deletions(-) diff --git a/src/mesa/drivers/dri/i965/brw_tex_layout.c b/src/mesa/drivers/dri/i965/brw_tex_layout.c index 9ac0713..66adc49 100644 --- a/src/mesa/drivers/dri/i965/brw_tex_layout.c +++ b/src/mesa/drivers/dri/i965/brw_tex_layout.c @@ -67,7 +67,7 @@ GLboolean brw_miptree_layout(struct intel_context *intel, i945_miptree_layout_2d(intel, mt, tiling, 6); - for (level = mt->first_level; level <= mt->last_level; level++) { + for (level = 0; level < mt->levels; level++) { for (q = 0; q < 6; q++) { intel_miptree_set_image_offset(mt, level, q, 0, q * qpitch); } @@ -101,7 +101,7 @@ GLboolean brw_miptree_layout(struct intel_context *intel, pack_x_pitch = width; pack_x_nr = 1; - for (level = mt->first_level ; level <= mt->last_level ; level++) { + for (level = 0; level < mt->levels; level++) { GLuint nr_images = mt->target == GL_TEXTURE_3D ? depth : 6; GLint x = 0; GLint y = 0; diff --git a/src/mesa/drivers/dri/i965/brw_wm_sampler_state.c b/src/mesa/drivers/dri/i965/brw_wm_sampler_state.c index 30672b4..f830e25 100644 --- a/src/mesa/drivers/dri/i965/brw_wm_sampler_state.c +++ b/src/mesa/drivers/dri/i965/brw_wm_sampler_state.c @@ -115,6 +115,7 @@ struct wm_sampler_key { struct wm_sampler_entry { GLenum tex_target; GLenum wrap_r, wrap_s, wrap_t; + uint32_t base_level; float maxlod, minlod; float lod_bias; float max_aniso; @@ -243,14 +244,7 @@ static void brw_update_sampler_state(struct brw_context *brw, sampler->ss0.lod_preclamp = 1; /* OpenGL mode */ sampler->ss0.default_color_mode = 0; /* OpenGL/DX10 mode */ - /* Set BaseMipLevel, MaxLOD, MinLOD: - * - * XXX: I don't think that using firstLevel, lastLevel works, - * because we always setup the surface state as if firstLevel == - * level zero. Probably have to subtract firstLevel from each of - * these: - */ - sampler->ss0.base_level = U_FIXED(0, 1); + sampler->ss0.base_level = U_FIXED(key->base_level, 1); sampler->ss1.max_lod = U_FIXED(CLAMP(key->maxlod, 0, 13), 6); sampler->ss1.min_lod = U_FIXED(CLAMP(key->minlod, 0, 13), 6); @@ -292,6 +286,7 @@ brw_wm_sampler_populate_key(struct brw_context *brw, entry->wrap_s = texObj->WrapS; entry->wrap_t = texObj->WrapT; + entry->base_level = texObj->BaseLevel; entry->maxlod = texObj->MaxLod; entry->minlod = texObj->MinLod; entry->lod_bias = texUnit->LodBias + texObj->LodBias; diff --git a/src/mesa/drivers/dri/i965/brw_wm_surface_state.c b/src/mesa/drivers/dri/i965/brw_wm_surface_state.c index 3b59b0b..1769991 100644 --- a/src/mesa/drivers/dri/i965/brw_wm_surface_state.c +++ b/src/mesa/drivers/dri/i965/brw_wm_surface_state.c @@ -181,15 +181,15 @@ brw_update_texture_surface( struct gl_context *ctx, GLuint unit ) /* surf.ss0.data_return_format = BRW_SURFACERETURNFORMAT_S1; */ surf.ss1.base_addr = intelObj->mt->region->buffer->offset; /* reloc */ + /* mip_count is #levels - 1 */ surf.ss2.mip_count = intelObj->_MaxLevel - tObj->BaseLevel; - surf.ss2.width = firstImage->Width - 1; - surf.ss2.height = firstImage->Height - 1; + surf.ss2.width = intelObj->mt->width0 - 1; + surf.ss2.height = intelObj->mt->height0 - 1; brw_set_surface_tiling(&surf, intelObj->mt->region->tiling); surf.ss3.pitch = (intelObj->mt->region->pitch * intelObj->mt->cpp) - 1; - surf.ss3.depth = firstImage->Depth - 1; + surf.ss3.depth = intelObj->mt->depth0 - 1; + surf.ss4.min_lod = tObj->BaseLevel; - surf.ss4.min_lod = 0; - if (tObj->Target == GL_TEXTURE_CUBE_MAP) { surf.ss0.cube_pos_x = 1; surf.ss0.cube_pos_y = 1; diff --git a/src/mesa/drivers/dri/intel/intel_mipmap_tree.c b/src/mesa/drivers/dri/intel/intel_mipmap_tree.c index a340927..2ced6ac 100644 --- a/src/mesa/drivers/dri/intel/intel_mipmap_tree.c +++ b/src/mesa/drivers/dri/intel/intel_mipmap_tree.c @@ -56,8 +56,7 @@ static struct intel_mipmap_tree * intel_miptree_create_internal(struct intel_context *intel, GLenum target, GLenum internal_format, - GLuint first_level, - GLuint last_level, + GLuint levels, GLuint width0, GLuint height0, GLuint depth0, GLuint cpp, GLuint compress_byte, @@ -66,15 +65,14 @@ intel_miptree_create_internal(struct intel_context *intel, GLboolean ok; struct intel_mipmap_tree *mt = calloc(sizeof(*mt), 1); - DBG("%s target %s format %s level %d..%d <-- %p\n", __FUNCTION__, + DBG("%s target %s format %s levels %d <-- %p\n", __FUNCTION__, _mesa_lookup_enum_by_nr(target), _mesa_lookup_enum_by_nr(internal_format), - first_level, last_level, mt); + levels, mt); mt->target = target_to_target(target); mt->internal_format = internal_format; - mt->first_level = first_level; - mt->last_level = last_level; + mt->levels = levels; mt->width0 = width0; mt->height0 = height0; mt->depth0 = depth0; @@ -106,8 +104,7 @@ intel_miptree_create(struct intel_context *intel, GLenum target, GLenum base_format, GLenum internal_format, - GLuint first_level, - GLuint last_level, + GLuint levels, GLuint width0, GLuint height0, GLuint depth0, GLuint cpp, GLuint compress_byte, @@ -126,7 +123,7 @@ intel_miptree_create(struct intel_context *intel, } mt = intel_miptree_create_internal(intel, target, internal_format, - first_level, last_level, width0, + levels, width0, height0, depth0, cpp, compress_byte, tiling); /* @@ -164,7 +161,7 @@ intel_miptree_create_for_region(struct intel_context *intel, struct intel_mipmap_tree *mt; mt = intel_miptree_create_internal(intel, target, internal_format, - 0, 0, + 1, region->width, region->height, 1, region->cpp, compress_byte, I915_TILING_NONE); diff --git a/src/mesa/drivers/dri/intel/intel_mipmap_tree.h b/src/mesa/drivers/dri/intel/intel_mipmap_tree.h index 760a8bc..4bb90bf 100644 --- a/src/mesa/drivers/dri/intel/intel_mipmap_tree.h +++ b/src/mesa/drivers/dri/intel/intel_mipmap_tree.h @@ -93,8 +93,7 @@ struct intel_mipmap_tree GLenum target; GLenum internal_format; - GLuint first_level; - GLuint last_level; + GLuint levels; GLuint width0, height0, depth0; /**< Level zero image dimensions */ GLuint cpp; @@ -124,8 +123,7 @@ struct intel_mipmap_tree *intel_miptree_create(struct intel_context *intel, GLenum target, GLenum base_format, GLenum internal_format, - GLuint first_level, - GLuint last_level, + GLuint levels, GLuint width0, GLuint height0, GLuint depth0, diff --git a/src/mesa/drivers/dri/intel/intel_tex.h b/src/mesa/drivers/dri/intel/intel_tex.h index 6552ed0..7c76bd4 100644 --- a/src/mesa/drivers/dri/intel/intel_tex.h +++ b/src/mesa/drivers/dri/intel/intel_tex.h @@ -65,4 +65,10 @@ void intel_tex_unmap_images(struct intel_context *intel, int intel_compressed_num_bytes(GLuint mesaFormat); +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); + #endif diff --git a/src/mesa/drivers/dri/intel/intel_tex_image.c b/src/mesa/drivers/dri/intel/intel_tex_image.c index 918740a..e0d4ca7 100644 --- a/src/mesa/drivers/dri/intel/intel_tex_image.c +++ b/src/mesa/drivers/dri/intel/intel_tex_image.c @@ -44,24 +44,12 @@ logbase2(int n) return log2; } - -/* Otherwise, store it in memory if (Border != 0) or (any dimension == - * 1). - * - * Otherwise, if max_level >= level >= min_level, create tree with - * space for textures from min_level down to max_level. - * - * Otherwise, create tree with space for textures from (level - * 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) +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; GLuint width = intelImage->base.Width; GLuint height = intelImage->base.Height; @@ -72,28 +60,11 @@ guess_and_alloc_mipmap_tree(struct intel_context *intel, DBG("%s\n", __FUNCTION__); if (intelImage->base.Border) - return; - - 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; - + return NULL; /* Figure out image dimensions at start level. */ - for (i = intelImage->level; i > firstLevel; i--) { + for (i = intelImage->level; i > 0; i--) { width <<= 1; if (height != 1) height <<= 1; @@ -108,34 +79,29 @@ guess_and_alloc_mipmap_tree(struct intel_context *intel, */ if ((intelObj->base.MinFilter == GL_NEAREST || intelObj->base.MinFilter == GL_LINEAR) && - intelImage->level == firstLevel && - (intel->gen < 4 || firstLevel == 0)) { - lastLevel = firstLevel; + intelImage->level == 0) { + lastLevel = 0; } else { - lastLevel = firstLevel + logbase2(MAX2(MAX2(width, height), depth)); + lastLevel = 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, + lastLevel + 1, + width, + height, + depth, + texelBytes, + comp_byte, + expect_accelerated_upload); } @@ -343,41 +309,23 @@ 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)) { - + if (intelObj->mt && intel_miptree_match_image(intelObj->mt, + &intelImage->base)) { 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); + } else { + intel_miptree_release(intel, &intelImage->mt); + intelImage->mt = intel_miptree_create_for_teximage(intel, intelObj, + intelImage, + pixels == NULL); + if (!intelImage->mt) { + DBG("guess_and_alloc_mipmap_tree: failed\n"); } - /* 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. + /* Speculatively set up the object with this miptree so that the + * later levels can just load into the miptree we just made. */ - intelImage->mt = intel_miptree_create(intel, target, - baseFormat, - internalFormat, - level, level, - width, height, depth, - texelBytes, - comp_byte, pixels == NULL); - + if (!intelObj->mt && intelImage->mt) + intel_miptree_reference(&intelObj->mt, intelImage->mt); } /* PBO fastpaths: @@ -396,10 +344,7 @@ intelTexImage(struct gl_context * ctx, * performance (in particular when intel_region_cow() is * required). */ - if (intelObj->mt == intelImage->mt && - intelObj->mt->first_level == level && - intelObj->mt->last_level == level) { - + if (intelImage->mt->levels == 1) { if (try_pbo_zcopy(intel, intelImage, unpack, internalFormat, width, height, format, type, pixels)) { diff --git a/src/mesa/drivers/dri/intel/intel_tex_layout.c b/src/mesa/drivers/dri/intel/intel_tex_layout.c index d39733b..540ef36 100644 --- a/src/mesa/drivers/dri/intel/intel_tex_layout.c +++ b/src/mesa/drivers/dri/intel/intel_tex_layout.c @@ -86,7 +86,7 @@ void i945_miptree_layout_2d(struct intel_context *intel, * constraints of mipmap placement push the right edge of the * 2nd mipmap out past the width of its parent. */ - if (mt->first_level != mt->last_level) { + if (mt->levels > 1) { GLuint mip1_width; if (mt->compressed) { @@ -104,7 +104,7 @@ void i945_miptree_layout_2d(struct intel_context *intel, mt->total_height = 0; - for ( level = mt->first_level ; level <= mt->last_level ; level++ ) { + for (level = 0; level < mt->levels; level++) { GLuint img_height; intel_miptree_set_level_info(mt, level, nr_images, x, y, width, @@ -123,7 +123,7 @@ void i945_miptree_layout_2d(struct intel_context *intel, /* Layout_below: step right after second mipmap. */ - if (level == mt->first_level + 1) { + if (level == 1) { x += ALIGN(width, align_w); } else { diff --git a/src/mesa/drivers/dri/intel/intel_tex_validate.c b/src/mesa/drivers/dri/intel/intel_tex_validate.c index 4d257cc..f1c6239 100644 --- a/src/mesa/drivers/dri/intel/intel_tex_validate.c +++ b/src/mesa/drivers/dri/intel/intel_tex_validate.c @@ -104,8 +104,7 @@ intel_finalize_mipmap_tree(struct intel_context *intel, GLuint unit) */ if (firstImage->mt && firstImage->mt != intelObj->mt && - firstImage->mt->first_level <= tObj->BaseLevel && - firstImage->mt->last_level >= intelObj->_MaxLevel) { + firstImage->mt->levels >= intelObj->_MaxLevel) { if (intelObj->mt) intel_miptree_release(intel, &intelObj->mt); @@ -132,11 +131,10 @@ intel_finalize_mipmap_tree(struct intel_context *intel, GLuint unit) if (intelObj->mt && (intelObj->mt->target != intelObj->base.Target || intelObj->mt->internal_format != firstImage->base.InternalFormat || - intelObj->mt->first_level != tObj->BaseLevel || - intelObj->mt->last_level != intelObj->_MaxLevel || - intelObj->mt->width0 != firstImage->base.Width || - intelObj->mt->height0 != firstImage->base.Height || - intelObj->mt->depth0 != firstImage->base.Depth || + intelObj->mt->levels <= intelObj->_MaxLevel || + intelObj->mt->width0 != firstImage->mt->width0 || + intelObj->mt->height0 != firstImage->mt->height0 || + intelObj->mt->depth0 != firstImage->mt->depth0 || intelObj->mt->cpp != cpp || intelObj->mt->compressed != _mesa_is_format_compressed(firstImage->base.TexFormat))) { intel_miptree_release(intel, &intelObj->mt); @@ -146,18 +144,9 @@ intel_finalize_mipmap_tree(struct intel_context *intel, GLuint unit) /* May need to create a new tree: */ if (!intelObj->mt) { - intelObj->mt = intel_miptree_create(intel, - intelObj->base.Target, - firstImage->base._BaseFormat, - firstImage->base.InternalFormat, - tObj->BaseLevel, - intelObj->_MaxLevel, - firstImage->base.Width, - firstImage->base.Height, - firstImage->base.Depth, - cpp, - comp_byte, - GL_TRUE); + intelObj->mt = intel_miptree_create_for_teximage(intel, intelObj, + firstImage, + GL_TRUE); } /* Pull in any images not in the object's tree: -- 2.7.4