mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2025-12-24 11:00:11 +01:00
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.
This commit is contained in:
parent
49330fc5ac
commit
451a0ddb19
1 changed files with 49 additions and 52 deletions
|
|
@ -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))
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue