diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/gallium/drivers/llvmpipe/lp_setup_tri.c | 77 |
1 files changed, 50 insertions, 27 deletions
diff --git a/src/gallium/drivers/llvmpipe/lp_setup_tri.c b/src/gallium/drivers/llvmpipe/lp_setup_tri.c index 72c0a9cb0b0..d4ef8f4c9cd 100644 --- a/src/gallium/drivers/llvmpipe/lp_setup_tri.c +++ b/src/gallium/drivers/llvmpipe/lp_setup_tri.c @@ -439,6 +439,32 @@ do_triangle_ccw(struct lp_setup_context *setup, return lp_setup_bin_triangle( setup, tri, &bbox, nr_planes ); } +/* + * __fls: find last set bit in word + * @word: The word to search + * + * Undefined if no zero exists, so code should check against ~0UL first. + */ +#if defined(PIPE_ARCH_X86) +static inline unsigned fls(unsigned word) +{ + asm("bsr %1,%0" + : "=r" (word) + : "rm" (word)); + return word; +} +#else +static inline unsigned fls(unsigned n) +{ + n |= (n >> 1); + n |= (n >> 2); + n |= (n >> 4); + n |= (n >> 8); + n |= (n >> 16); + return n - (n >> 1); +} +#endif + boolean lp_setup_bin_triangle( struct lp_setup_context *setup, @@ -447,52 +473,44 @@ lp_setup_bin_triangle( struct lp_setup_context *setup, int nr_planes ) { struct lp_scene *scene = setup->scene; - int ix0, ix1, iy0, iy1; int i; - /* - * All fields of 'tri' are now set. The remaining code here is - * concerned with binning. + /* What is the largest power-of-two boundary this triangle crosses: */ + int dx = 1 << fls((bbox->x0 ^ bbox->x1) | + (bbox->y0 ^ bbox->y1)); - /* Convert to tile coordinates, and inclusive ranges: + /* The largest dimension of the rasterized area of the triangle + * (aligned to a 4x4 grid), rounded up to the next power of two: */ + int sz = 1 << fls((bbox->x1 - (bbox->x0 & ~3)) | + (bbox->y1 - (bbox->y0 & ~3))); + if (nr_planes == 3) { - int ix0 = bbox->x0 / 16; - int iy0 = bbox->y0 / 16; - int ix1 = bbox->x1 / 16; - int iy1 = bbox->y1 / 16; - - if (iy0 == iy1 && ix0 == ix1) + if (sz < 16 && dx < 64) { + int mask = (bbox->x0 & 63 & ~3) | ((bbox->y0 & 63 & ~3) << 8); /* Triangle is contained in a single 16x16 block: */ - int mask = (ix0 & 3) | ((iy0 & 3) << 4); - - return lp_scene_bin_command( scene, ix0/4, iy0/4, + return lp_scene_bin_command( scene, + bbox->x0/64, bbox->y0/64, LP_RAST_OP_TRIANGLE_3_16, lp_rast_arg_triangle(tri, mask) ); } } - ix0 = bbox->x0 / TILE_SIZE; - iy0 = bbox->y0 / TILE_SIZE; - ix1 = bbox->x1 / TILE_SIZE; - iy1 = bbox->y1 / TILE_SIZE; - - /* - * Clamp to framebuffer size - */ - assert(ix0 == MAX2(ix0, 0)); - assert(iy0 == MAX2(iy0, 0)); - assert(ix1 == MIN2(ix1, scene->tiles_x - 1)); - assert(iy1 == MIN2(iy1, scene->tiles_y - 1)); /* Determine which tile(s) intersect the triangle's bounding box */ - if (iy0 == iy1 && ix0 == ix1) + if (dx < TILE_SIZE) { + int ix0 = bbox->x0 / TILE_SIZE; + int iy0 = bbox->y0 / TILE_SIZE; + + assert(iy0 == bbox->y1 / TILE_SIZE && + ix0 == bbox->x1 / TILE_SIZE); + /* Triangle is contained in a single tile: */ return lp_scene_bin_command( scene, ix0, iy0, @@ -507,6 +525,11 @@ lp_setup_bin_triangle( struct lp_setup_context *setup, int xstep[7]; int ystep[7]; int x, y; + + int ix0 = bbox->x0 / TILE_SIZE; + int iy0 = bbox->y0 / TILE_SIZE; + int ix1 = bbox->x1 / TILE_SIZE; + int iy1 = bbox->y1 / TILE_SIZE; for (i = 0; i < nr_planes; i++) { c[i] = (tri->plane[i].c + |