llvmpipe: Ensure the 16x16 special rasterization path does not touch outside the...
authorJosé Fonseca <jfonseca@vmware.com>
Wed, 5 Oct 2011 10:31:15 +0000 (11:31 +0100)
committerJosé Fonseca <jfonseca@vmware.com>
Wed, 5 Oct 2011 17:07:05 +0000 (18:07 +0100)
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
src/gallium/drivers/llvmpipe/lp_rast_priv.h
src/gallium/drivers/llvmpipe/lp_rast_tri.c
src/gallium/drivers/llvmpipe/lp_setup_tri.c

index 131785852c881f3a6c7a394dc079ae9287d7485b..c4560bfe6c02dab56743f228bfc18579e3b30b2d 100644 (file)
@@ -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);
 
index cd686bc82c13fc3a769359db0e62799c05133d3a..d0bda354732731889a62484a357dabd285286e86 100644 (file)
@@ -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);
 
index 042c315635e2749c2c9274b44a873188f3b6dd59..3adfbaacd3505bad4fd654a3a169fb566c7e5cfe 100644 (file)
@@ -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 */
index bfb6bf277bd93f85fc432cafa292c516f8124809..1737d1dbacf301260a3ba104383c3423d44c7d52 100644 (file)
@@ -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,