From: Marek Olšák Date: Sun, 25 Jul 2010 08:07:12 +0000 (+0200) Subject: r300g: make sure a texture is large enough for the CBZB clear X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=451a0ddb190e5185372fed9ec57d24a822442ecc;p=mesa.git r300g: make sure a texture is large enough for the CBZB clear The number of macrotiles in the Y direction must be even, otherwise memory corruption may happen (e.g. broken fonts). Basically, if we get a buffer in resource_from_handle, we can determine from the buffer size whether it's safe to use the CBZB clear or not. --- diff --git a/src/gallium/drivers/r300/r300_texture_desc.c b/src/gallium/drivers/r300/r300_texture_desc.c index 02591aa01f1..343089bf2c5 100644 --- a/src/gallium/drivers/r300/r300_texture_desc.c +++ b/src/gallium/drivers/r300/r300_texture_desc.c @@ -154,7 +154,7 @@ static unsigned r300_texture_get_stride(struct r300_screen *screen, static unsigned r300_texture_get_nblocksy(struct r300_texture_desc *desc, unsigned level, - boolean align_for_cbzb) + boolean *out_aligned_for_cbzb) { unsigned height, tile_height; @@ -175,12 +175,28 @@ static unsigned r300_texture_get_nblocksy(struct r300_texture_desc *desc, height = util_next_power_of_two(height); } - /* Allocate an even number of macrotiles for the CBZB clear. - * Do so for 3 or more macrotiles in the Y direction. */ - if (align_for_cbzb && - level == 0 && desc->b.b.last_level == 0 && - desc->macrotile[0] && height >= tile_height * 3) { - height = align(height, tile_height * 2); + /* See if the CBZB clear can be used on the buffer, + * taking the texture size into account. */ + if (out_aligned_for_cbzb) { + if (desc->macrotile[level]) { + /* When clearing, the layer (width*height) is horizontally split + * into two, and the upper and lower halves are cleared by the CB + * and ZB units, respectively. Therefore, the number of macrotiles + * in the Y direction must be even. */ + + /* Align the height so that there is an even number of macrotiles. + * Do so for 3 or more macrotiles in the Y direction. */ + if (level == 0 && desc->b.b.last_level == 0 && + (desc->b.b.target == PIPE_TEXTURE_1D || + desc->b.b.target == PIPE_TEXTURE_2D) && + height >= tile_height * 3) { + height = align(height, tile_height * 2); + } + + *out_aligned_for_cbzb = height % (tile_height * 2) == 0; + } else { + *out_aligned_for_cbzb = FALSE; + } } } @@ -219,11 +235,15 @@ static unsigned stride_to_width(enum pipe_format format, } static void r300_setup_miptree(struct r300_screen *screen, - struct r300_texture_desc *desc) + struct r300_texture_desc *desc, + boolean align_for_cbzb) { struct pipe_resource *base = &desc->b.b; unsigned stride, size, layer_size, nblocksy, i; boolean rv350_mode = screen->caps.is_rv350; + boolean aligned_for_cbzb; + + desc->size_in_bytes = 0; SCREEN_DBG(screen, DBG_TEXALLOC, "r300: Making miptree for texture, format %s\n", @@ -238,7 +258,15 @@ static void r300_setup_miptree(struct r300_screen *screen, R300_BUFFER_TILED : R300_BUFFER_LINEAR; stride = r300_texture_get_stride(screen, desc, i); - nblocksy = r300_texture_get_nblocksy(desc, i, desc->stride_in_bytes_override == 0); + + /* Compute the number of blocks in Y, see if the CBZB clear can be + * used on the texture. */ + aligned_for_cbzb = FALSE; + if (align_for_cbzb && desc->cbzb_allowed[i]) + nblocksy = r300_texture_get_nblocksy(desc, i, &aligned_for_cbzb); + else + nblocksy = r300_texture_get_nblocksy(desc, i, NULL); + layer_size = stride * nblocksy; if (base->nr_samples) { @@ -255,6 +283,7 @@ static void r300_setup_miptree(struct r300_screen *screen, desc->layer_size_in_bytes[i] = layer_size; desc->stride_in_bytes[i] = stride; desc->stride_in_pixels[i] = stride_to_width(desc->b.b.format, stride); + desc->cbzb_allowed[i] = desc->cbzb_allowed[i] && aligned_for_cbzb; SCREEN_DBG(screen, DBG_TEXALLOC, "r300: Texture miptree: Level %d " "(%dx%dx%d px, pitch %d bytes) %d bytes total, macrotiled %s\n", @@ -296,44 +325,6 @@ static void r300_setup_cbzb_flags(struct r300_screen *rscreen, for (i = 0; i <= desc->b.b.last_level; i++) desc->cbzb_allowed[i] = first_level_valid && desc->macrotile[i]; - return; -#if 0 - /* When clearing, the layer (width*height) is horizontally split - * into two, and the upper and lower halves are cleared by the CB - * and ZB units, respectively. Therefore, the number of macrotiles - * in the Y direction must be even. */ - - if (desc->b.b.last_level > 0 || - desc->b.b.target == PIPE_TEXTURE_3D || - desc->b.b.target == PIPE_TEXTURE_CUBE) { - /* For mipmapped, 3D, or cube textures, just check if there are - * enough macrotiles per layer. */ - for (i = 0; i <= desc->b.b.last_level; i++) { - desc->cbzb_allowed[i] = FALSE; - - if (first_level_valid && desc->macrotile[i]) { - unsigned height, tile_height, num_macrotiles; - - /* Compute the number of macrotiles in the Y direction. */ - tile_height = r300_get_pixel_alignment(desc->b.b.format, - desc->b.b.nr_samples, - desc->microtile, - R300_BUFFER_TILED, - DIM_HEIGHT); - height = r300_texture_get_height(desc, i); - num_macrotiles = height / tile_height; - - desc->cbzb_allowed[i] = num_macrotiles % 2 == 0; - } - } - } else { - /* For 1D and 2D non-mipmapped textures */ - unsigned layer_size; - - layer_size = desc->stride_in_bytes[0] * - r300_texture_get_nblocksy(desc, 0, TRUE); - } -#endif } static void r300_setup_tiling(struct r300_screen *screen, @@ -409,8 +400,6 @@ boolean r300_texture_desc_init(struct r300_screen *rscreen, desc->stride_in_bytes_override = stride_in_bytes_override; - r300_setup_flags(desc); - if (microtile == R300_BUFFER_SELECT_LAYOUT || macrotile == R300_BUFFER_SELECT_LAYOUT) { r300_setup_tiling(rscreen, desc); @@ -420,10 +409,19 @@ boolean r300_texture_desc_init(struct r300_screen *rscreen, assert(desc->b.b.last_level == 0); } - r300_setup_miptree(rscreen, desc); - r300_texture_3d_fix_mipmapping(rscreen, desc); + r300_setup_flags(desc); r300_setup_cbzb_flags(rscreen, desc); + /* Setup the miptree description. */ + r300_setup_miptree(rscreen, desc, TRUE); + /* If the required buffer size is larger the given max size, + * try again without the alignment for the CBZB clear. */ + if (max_buffer_size && desc->size_in_bytes > max_buffer_size) { + r300_setup_miptree(rscreen, desc, FALSE); + } + + r300_texture_3d_fix_mipmapping(rscreen, desc); + if (max_buffer_size) { /* Make sure the buffer we got is large enough. */ if (desc->size_in_bytes > max_buffer_size) { @@ -437,7 +435,6 @@ boolean r300_texture_desc_init(struct r300_screen *rscreen, desc->buffer_size_in_bytes = max_buffer_size; } else { desc->buffer_size_in_bytes = desc->size_in_bytes; - } if (SCREEN_DBG_ON(rscreen, DBG_TEX))