summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMarek Olšák <maraeo@gmail.com>2010-07-25 10:07:12 +0200
committerMarek Olšák <maraeo@gmail.com>2010-07-25 10:33:09 +0200
commit451a0ddb190e5185372fed9ec57d24a822442ecc (patch)
tree31d3195810798fb0e1640973fbef9dfbc7e0fffd /src
parent49330fc5ac13e25cb201e62995329cffaf5046f0 (diff)
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.
Diffstat (limited to 'src')
-rw-r--r--src/gallium/drivers/r300/r300_texture_desc.c101
1 files changed, 49 insertions, 52 deletions
diff --git a/src/gallium/drivers/r300/r300_texture_desc.c b/src/gallium/drivers/r300/r300_texture_desc.c
index 02591aa01f..343089bf2c 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))