From c620087432b2055aa9301f19f8b6444080698c90 Mon Sep 17 00:00:00 2001 From: José Fonseca <jfonseca@vmware.com> Date: Wed, 5 Oct 2011 11:31:15 +0100 Subject: llvmpipe: Ensure the 16x16 special rasterization path does not touch outside the tile. llvmpipe has a few special rasterization paths for triangles contained in 16x16 blocks, but it allows the 16x16 block to be aligned only to a 4x4 grid. Some 16x16 blocks could actually intersect the tile if the triangle is 16 pixels in one dimension but 4 in the other, causing a buffer overflow. The fix consists of budging the 16x16 blocks back inside the tile. --- src/gallium/drivers/llvmpipe/lp_rast.c | 2 ++ src/gallium/drivers/llvmpipe/lp_rast_priv.h | 6 ++++++ src/gallium/drivers/llvmpipe/lp_rast_tri.c | 4 ++-- src/gallium/drivers/llvmpipe/lp_setup_tri.c | 24 +++++++++++++++++++++--- 4 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/gallium/drivers/llvmpipe/lp_rast.c b/src/gallium/drivers/llvmpipe/lp_rast.c index 131785852c8..c4560bfe6c0 100644 --- a/src/gallium/drivers/llvmpipe/lp_rast.c +++ b/src/gallium/drivers/llvmpipe/lp_rast.c @@ -436,6 +436,8 @@ lp_rast_shade_quads_mask(struct lp_rasterizer_task *task, assert(state); /* Sanity checks */ + assert(x < scene->tiles_x * TILE_SIZE); + assert(y < scene->tiles_y * TILE_SIZE); assert(x % TILE_VECTOR_WIDTH == 0); assert(y % TILE_VECTOR_HEIGHT == 0); diff --git a/src/gallium/drivers/llvmpipe/lp_rast_priv.h b/src/gallium/drivers/llvmpipe/lp_rast_priv.h index cd686bc82c1..d0bda354732 100644 --- a/src/gallium/drivers/llvmpipe/lp_rast_priv.h +++ b/src/gallium/drivers/llvmpipe/lp_rast_priv.h @@ -151,6 +151,8 @@ lp_rast_get_depth_block_pointer(struct lp_rasterizer_task *task, const struct lp_scene *scene = task->scene; void *depth; + assert(x < scene->tiles_x * TILE_SIZE); + assert(y < scene->tiles_y * TILE_SIZE); assert((x % TILE_VECTOR_WIDTH) == 0); assert((y % TILE_VECTOR_HEIGHT) == 0); @@ -181,6 +183,8 @@ lp_rast_get_color_tile_pointer(struct lp_rasterizer_task *task, { const struct lp_scene *scene = task->scene; + assert(task->x < scene->tiles_x * TILE_SIZE); + assert(task->y < scene->tiles_y * TILE_SIZE); assert(task->x % TILE_SIZE == 0); assert(task->y % TILE_SIZE == 0); assert(buf < scene->fb.nr_cbufs); @@ -219,6 +223,8 @@ lp_rast_get_color_block_pointer(struct lp_rasterizer_task *task, unsigned px, py, pixel_offset; uint8_t *color; + assert(x < task->scene->tiles_x * TILE_SIZE); + assert(y < task->scene->tiles_y * TILE_SIZE); assert((x % TILE_VECTOR_WIDTH) == 0); assert((y % TILE_VECTOR_HEIGHT) == 0); diff --git a/src/gallium/drivers/llvmpipe/lp_rast_tri.c b/src/gallium/drivers/llvmpipe/lp_rast_tri.c index 042c315635e..3adfbaacd35 100644 --- a/src/gallium/drivers/llvmpipe/lp_rast_tri.c +++ b/src/gallium/drivers/llvmpipe/lp_rast_tri.c @@ -364,8 +364,8 @@ lp_rast_triangle_3_4(struct lp_rasterizer_task *task, { const struct lp_rast_triangle *tri = arg.triangle.tri; const struct lp_rast_plane *plane = GET_PLANES(tri); - int x = (arg.triangle.plane_mask & 0xff) + task->x; - int y = (arg.triangle.plane_mask >> 8) + task->y; + unsigned x = (arg.triangle.plane_mask & 0xff) + task->x; + unsigned y = (arg.triangle.plane_mask >> 8) + task->y; __m128i p0 = _mm_load_si128((__m128i *)&plane[0]); /* c, dcdx, dcdy, eo */ __m128i p1 = _mm_load_si128((__m128i *)&plane[1]); /* c, dcdx, dcdy, eo */ diff --git a/src/gallium/drivers/llvmpipe/lp_setup_tri.c b/src/gallium/drivers/llvmpipe/lp_setup_tri.c index bfb6bf277bd..1737d1dbacf 100644 --- a/src/gallium/drivers/llvmpipe/lp_setup_tri.c +++ b/src/gallium/drivers/llvmpipe/lp_setup_tri.c @@ -593,18 +593,32 @@ lp_setup_bin_triangle( struct lp_setup_context *setup, { int ix0 = bbox->x0 / TILE_SIZE; int iy0 = bbox->y0 / TILE_SIZE; - int px = bbox->x0 & 63 & ~3; - int py = bbox->y0 & 63 & ~3; - int mask = px | (py << 8); + unsigned px = bbox->x0 & 63 & ~3; + unsigned py = bbox->y0 & 63 & ~3; + unsigned mask; assert(iy0 == bbox->y1 / TILE_SIZE && ix0 == bbox->x1 / TILE_SIZE); + if (4 <= sz && sz < 16) { + /* + * 16x16 block is only 4x4 aligned, and can exceed the tile dimensions + * if the triangle is 16 pixels in one dimension but 4 in the other. + * So budge the 16x16 back inside the tile. + */ + px = MIN2(px, TILE_SIZE - 16); + py = MIN2(py, TILE_SIZE - 16); + } + + mask = px | (py << 8); + if (nr_planes == 3) { if (sz < 4) { /* Triangle is contained in a single 4x4 stamp: */ + assert(px + 4 <= TILE_SIZE); + assert(py + 4 <= TILE_SIZE); return lp_scene_bin_cmd_with_state( scene, ix0, iy0, setup->fs.stored, LP_RAST_OP_TRIANGLE_3_4, @@ -615,6 +629,8 @@ lp_setup_bin_triangle( struct lp_setup_context *setup, { /* Triangle is contained in a single 16x16 block: */ + assert(px + 16 <= TILE_SIZE); + assert(py + 16 <= TILE_SIZE); return lp_scene_bin_cmd_with_state( scene, ix0, iy0, setup->fs.stored, LP_RAST_OP_TRIANGLE_3_16, @@ -623,6 +639,8 @@ lp_setup_bin_triangle( struct lp_setup_context *setup, } else if (nr_planes == 4 && sz < 16) { + assert(px + 16 <= TILE_SIZE); + assert(py + 16 <= TILE_SIZE); return lp_scene_bin_cmd_with_state(scene, ix0, iy0, setup->fs.stored, LP_RAST_OP_TRIANGLE_4_16, -- cgit v1.2.3