diff options
-rw-r--r-- | src/sna/sna_accel.c | 260 |
1 files changed, 156 insertions, 104 deletions
diff --git a/src/sna/sna_accel.c b/src/sna/sna_accel.c index d5605be1..9b6b2c7f 100644 --- a/src/sna/sna_accel.c +++ b/src/sna/sna_accel.c @@ -1766,6 +1766,33 @@ sna_copy_init_blt(struct sna_copy_op *copy, return sna->render.copy(sna, alu, src, src_bo, dst, dst_bo, copy); } +static const BoxRec * +find_clip_box_for_y(const BoxRec *begin, const BoxRec *end, int16_t y) +{ + const BoxRec *mid; + + if (end == begin) + return end; + + if (end - begin == 1) { + if (begin->y2 > y) + return begin; + else + return end; + } + + mid = begin + (end - begin) / 2; + if (mid->y2 > y) + /* If no box is found in [begin, mid], the function + * will return @mid, which is then known to be the + * correct answer. + */ + return find_clip_box_for_y(begin, mid, y); + else + return find_clip_box_for_y(mid, end, y); +} + + static Bool sna_fill_spans_blt(DrawablePtr drawable, struct kgem_bo *bo, struct sna_damage **damage, @@ -1777,6 +1804,7 @@ sna_fill_spans_blt(DrawablePtr drawable, PixmapPtr pixmap = get_drawable_pixmap(drawable); int16_t dx, dy; struct sna_fill_op fill; + BoxRec box[512], *b = box, *const last_box = box + ARRAY_SIZE(box); static void * const jump[] = { &&no_damage_translate, &&damage_translate, @@ -1805,17 +1833,25 @@ no_damage_translate: dx += drawable->x; dy += drawable->y; no_damage: - do { - BoxRec box; - - box.x1 = pt->x + dx; - box.x2 = box.x1 + *width++; - box.y1 = pt->y + dy; - box.y2 = box.y1 + 1; - pt++; + { + unsigned offset = dx|dy; + do { + *(DDXPointRec *)b = *pt++; + if (offset) { + b->x1 += dx; + b->y1 += dy; + } + b->x2 = b->x1 + (int)*width++; + b->y2 = b->y1 + 1; - fill.box(sna, &fill, &box); - } while (--n); + if (++b == last_box) { + fill.boxes(sna, &fill, box, last_box - box); + b = box; + } + } while (--n); + if (b != box) + fill.boxes(sna, &fill, box, b - box); + } goto done; damage_translate: @@ -1823,18 +1859,22 @@ damage_translate: dy += drawable->y; damage: do { - BoxRec box; - - box.x1 = pt->x + dx; - box.x2 = box.x1 + *width++; - box.y1 = pt->y + dy; - box.y2 = box.y1 + 1; - pt++; + *(DDXPointRec *)b = *pt++; + b->x1 += dx; + b->y1 += dy; + b->x2 = b->x1 + (int)*width++; + b->y2 = b->y1 + 1; - fill.box(sna, &fill, &box); - assert_pixmap_contains_box(pixmap, &box); - sna_damage_add_box(damage, &box); + if (++b == last_box) { + fill.boxes(sna, &fill, box, last_box - box); + sna_damage_add_boxes(damage, box, last_box - box, 0, 0); + b = box; + } } while (--n); + if (b != box) { + fill.boxes(sna, &fill, box, b - box); + sna_damage_add_boxes(damage, box, b - box, 0, 0); + } goto done; { @@ -1860,29 +1900,29 @@ no_damage_clipped: if (clip.data == NULL) { do { - BoxRec box; - - box.x1 = pt->x; - box.y1 = pt->y; - box.x2 = box.x1 + (int)*width++; - box.y2 = box.y1 + 1; - pt++; + *(DDXPointRec *)b = *pt++; + b->x2 = b->x1 + (int)*width++; + b->y2 = b->y1 + 1; - if (box_intersect(&box, &clip.extents)) { - box.x1 += dx; - box.x2 += dx; - box.y1 += dy; - box.y2 += dy; - fill.box(sna, &fill, &box); + if (box_intersect(b, &clip.extents)) { + b->x1 += dx; + b->x2 += dx; + b->y1 += dy; + b->y2 += dy; + if (++b == last_box) { + fill.boxes(sna, &fill, box, last_box - box); + b = box; + } } } while (--n); } else { + const BoxRec * const clip_start = RegionBoxptr(&clip); + const BoxRec * const clip_end = clip_start + clip.data->numRects; do { - int nc = clip.data->numRects; - const BoxRec *b = RegionBoxptr(&clip); int16_t X1 = pt->x; int16_t y = pt->y; int16_t X2 = X1 + (int)*width; + const BoxRec *c; pt++; width++; @@ -1899,31 +1939,41 @@ no_damage_clipped: if (X1 >= X2) continue; - y += dy; - do { - if (b->y1 <= y && y < b->y2) { - int x1 = b->x1; - int x2 = b->x2; - - if (x1 < X1) - x1 = X1; - x1 += dx; - if (x1 < 0) - x1 = 0; - if (x2 > X2) - x2 = X2; - x2 += dx; - if (x2 > pixmap->drawable.width) - x2 = pixmap->drawable.width; - - if (x2 > x1) - fill.blt(sna, &fill, x1, y, x2-x1, 1); + c = find_clip_box_for_y(clip_start, + clip_end, + y); + while (c != clip_end) { + if (y + 1 <= c->y1) + break; + + if (X2 <= c->x1) + continue; + if (X1 >= c->x2) + break; + + b->x1 = c->x1; + b->x2 = c->x2; + c++; + + if (b->x1 < X1) + b->x1 = X1; + if (b->x2 > X2) + b->x2 = X2; + + b->x1 += dx; + b->x2 += dx; + b->y1 = y + dy; + b->y2 = b->y1 + 1; + if (++b == last_box) { + fill.boxes(sna, &fill, box, last_box - box); + b = box; } - b++; - } while (--nc); + } } while (--n); RegionUninit(&clip); } + if (b != box) + fill.boxes(sna, &fill, box, b - box); goto done; } @@ -1950,31 +2000,30 @@ damage_clipped: if (clip.data == NULL) { do { - BoxRec box; - - box.x1 = pt->x; - box.y1 = pt->y; - box.x2 = box.x1 + (int)*width++; - box.y2 = box.y1 + 1; - pt++; + *(DDXPointRec *)b = *pt++; + b->x2 = b->x1 + (int)*width++; + b->y2 = b->y1 + 1; - if (box_intersect(&box, &clip.extents)) { - box.x1 += dx; - box.x2 += dx; - box.y1 += dy; - box.y2 += dy; - fill.box(sna, &fill, &box); - assert_pixmap_contains_box(pixmap, &box); - sna_damage_add_box(damage, &box); + if (box_intersect(b, &clip.extents)) { + b->x1 += dx; + b->x2 += dx; + b->y1 += dy; + b->y2 += dy; + if (++b == last_box) { + fill.boxes(sna, &fill, box, last_box - box); + sna_damage_add_boxes(damage, box, b - box, 0, 0); + b = box; + } } } while (--n); } else { + const BoxRec * const clip_start = RegionBoxptr(&clip); + const BoxRec * const clip_end = clip_start + clip.data->numRects; do { - int nc = clip.data->numRects; - const BoxRec *b = RegionBoxptr(&clip); int16_t X1 = pt->x; int16_t y = pt->y; int16_t X2 = X1 + (int)*width; + const BoxRec *c; pt++; width++; @@ -1991,41 +2040,44 @@ damage_clipped: if (X1 >= X2) continue; - y += dy; - do { - if (b->y1 <= y && y < b->y2) { - int x1 = b->x1; - int x2 = b->x2; - - if (x1 < X1) - x1 = X1; - x1 += dx; - if (x1 < 0) - x1 = 0; - if (x2 > X2) - x2 = X2; - x2 += dx; - if (x2 > pixmap->drawable.width) - x2 = pixmap->drawable.width; - - if (x2 > x1) { - BoxRec box; - - box.x1 = x1; - box.y1 = y; - box.x2 = x2; - box.y2 = box.y1 + 1; - - fill.box(sna, &fill, &box); - assert_pixmap_contains_box(pixmap, &box); - sna_damage_add_box(damage, &box); - } + c = find_clip_box_for_y(clip_start, + clip_end, + y); + while (c != clip_end) { + if (y + 1 <= c->y1) + break; + + if (X2 <= c->x1) + continue; + if (X1 >= c->x2) + break; + + b->x1 = c->x1; + b->x2 = c->x2; + c++; + + if (b->x1 < X1) + b->x1 = X1; + if (b->x2 > X2) + b->x2 = X2; + + b->x1 += dx; + b->x2 += dx; + b->y1 = y + dy; + b->y2 = b->y1 + 1; + if (++b == last_box) { + fill.boxes(sna, &fill, box, last_box - box); + sna_damage_add_boxes(damage, box, last_box - box, 0, 0); + b = box; } - b++; - } while (--nc); + } } while (--n); RegionUninit(&clip); } + if (b != box) { + fill.boxes(sna, &fill, box, b - box); + sna_damage_add_boxes(damage, box, b - box, 0, 0); + } goto done; } |