diff --git a/src/sna/sna.h b/src/sna/sna.h index 38ae404f..cabf04c7 100644 --- a/src/sna/sna.h +++ b/src/sna/sna.h @@ -192,6 +192,7 @@ static inline struct sna_pixmap *sna_pixmap_from_drawable(DrawablePtr drawable) struct sna_gc { long changes; long serial; + void *priv; }; static inline struct sna_gc *sna_gc(GCPtr gc) diff --git a/src/sna/sna_accel.c b/src/sna/sna_accel.c index 3f53e01e..c258812e 100644 --- a/src/sna/sna_accel.c +++ b/src/sna/sna_accel.c @@ -75,7 +75,7 @@ #define ACCEL_POLY_SEGMENT 1 #define ACCEL_POLY_RECTANGLE 1 #define ACCEL_POLY_ARC 1 -//#define ACCEL_FILL_POLYGON 1 +#define ACCEL_POLY_FILL_POLYGON 1 #define ACCEL_POLY_FILL_RECT 1 //#define ACCEL_POLY_FILL_ARC 1 #define ACCEL_POLY_TEXT8 1 @@ -3597,6 +3597,251 @@ find_clip_box_for_y(const BoxRec *begin, const BoxRec *end, int16_t y) return find_clip_box_for_y(mid, end, y); } +static void +sna_fill_spans__cpu(DrawablePtr drawable, + GCPtr gc, int n, + DDXPointPtr pt, int *width, int sorted) +{ + BoxRec extents; + + DBG(("%s x %d\n", __FUNCTION__, n)); + + extents = gc->pCompositeClip->extents; + while (n--) { + BoxRec b; + + DBG(("%s: (%d, %d) + %d\n", + __FUNCTION__, pt->x, pt->y, *width)); + + *(DDXPointRec *)&b = *pt++; + b.x2 = b.x1 + *width++; + b.y2 = b.y1 + 1; + + if (!box_intersect(&b, &extents)) + continue; + + if (region_is_singular(gc->pCompositeClip)) { + fbFill(drawable, gc, b.x1, b.y1, b.x2 - b.x1, 1); + } else { + const BoxRec * const clip_start = RegionBoxptr(gc->pCompositeClip); + const BoxRec * const clip_end = clip_start + gc->pCompositeClip->data->numRects; + const BoxRec *c; + + c = find_clip_box_for_y(clip_start, + clip_end, + b.y1); + while (c != clip_end) { + int16_t x1, x2; + + if (b.y2 <= c->y1) + break; + + if (b.x1 >= c->x2) + break; + if (b.x2 <= c->x1) { + c++; + continue; + } + + x1 = c->x1; + x2 = c->x2; + c++; + + if (x1 < b.x1) + x1 = b.x1; + if (x2 > b.x2) + x2 = b.x2; + if (x2 > x1) + fbFill(drawable, gc, + x1, b.y1, x2 - x1, 1); + } + } + } +} + +struct sna_fill_spans { + struct sna *sna; + PixmapPtr pixmap; + RegionRec region; + unsigned flags; + struct sna_damage **damage; + int16_t dx, dy; + void *op; +}; + +static void +sna_fill_spans__fill(DrawablePtr drawable, + GCPtr gc, int n, + DDXPointPtr pt, int *width, int sorted) +{ + struct sna_fill_spans *data = sna_gc(gc)->priv; + struct sna_fill_op *op = data->op; + BoxRec box[512]; + + DBG(("%s: alu=%d, fg=%08lx, count=%d\n", + __FUNCTION__, gc->alu, gc->fgPixel, n)); + + assert(n); + do { + BoxRec *b = box; + int nbox = n; + if (nbox > ARRAY_SIZE(box)) + nbox = ARRAY_SIZE(box); + n -= nbox; + do { + *(DDXPointRec *)b = *pt++; + b->x2 = b->x1 + (int)*width++; + b->y2 = b->y1 + 1; + DBG(("%s: (%d, %d), (%d, %d)\n", + __FUNCTION__, b->x1, b->y1, b->x2, b->y2)); + if (b->x2 > b->x1) + b++; + } while (--nbox); + if (b != box) + op->boxes(data->sna, op, box, b - box); + } while (n); +} + +static void +sna_fill_spans__fill_offset(DrawablePtr drawable, + GCPtr gc, int n, + DDXPointPtr pt, int *width, int sorted) +{ + struct sna_fill_spans *data = sna_gc(gc)->priv; + struct sna_fill_op *op = data->op; + BoxRec box[512]; + + DBG(("%s: alu=%d, fg=%08lx\n", __FUNCTION__, gc->alu, gc->fgPixel)); + + do { + BoxRec *b = box; + int nbox = n; + if (nbox > ARRAY_SIZE(box)) + nbox = ARRAY_SIZE(box); + n -= nbox; + do { + *(DDXPointRec *)b = *pt++; + b->x1 += data->dx; + b->y1 += data->dy; + b->x2 = b->x1 + (int)*width++; + b->y2 = b->y1 + 1; + if (b->x2 > b->x1) + b++; + } while (--nbox); + if (b != box) + op->boxes(data->sna, op, box, b - box); + } while (n); +} + +static void +sna_fill_spans__fill_clip_extents(DrawablePtr drawable, + GCPtr gc, int n, + DDXPointPtr pt, int *width, int sorted) +{ + struct sna_fill_spans *data = sna_gc(gc)->priv; + struct sna_fill_op *op = data->op; + const BoxRec *extents = &data->region.extents; + BoxRec box[512], *b = box, *const last_box = box + ARRAY_SIZE(box); + + DBG(("%s: alu=%d, fg=%08lx, count=%d, extents=(%d, %d), (%d, %d)\n", + __FUNCTION__, gc->alu, gc->fgPixel, n, + extents->x1, extents->y1, + extents->x2, extents->y2)); + + assert(n); + do { + *(DDXPointRec *)b = *pt++; + b->x2 = b->x1 + (int)*width++; + b->y2 = b->y1 + 1; + if (box_intersect(b, extents)) { + b->x1 += data->dx; + b->x2 += data->dx; + b->y1 += data->dy; + b->y2 += data->dy; + if (++b == last_box) { + op->boxes(data->sna, op, box, last_box - box); + b = box; + } + } + } while (--n); + if (b != box) + op->boxes(data->sna, op, box, b - box); +} + +static void +sna_fill_spans__fill_clip_boxes(DrawablePtr drawable, + GCPtr gc, int n, + DDXPointPtr pt, int *width, int sorted) +{ + struct sna_fill_spans *data = sna_gc(gc)->priv; + struct sna_fill_op *op = data->op; + BoxRec box[512], *b = box, *const last_box = box + ARRAY_SIZE(box); + const BoxRec * const clip_start = RegionBoxptr(&data->region); + const BoxRec * const clip_end = clip_start + data->region.data->numRects; + + DBG(("%s: alu=%d, fg=%08lx, count=%d, extents=(%d, %d), (%d, %d)\n", + __FUNCTION__, gc->alu, gc->fgPixel, n, + data->region.extents.x1, data->region.extents.y1, + data->region.extents.x2, data->region.extents.y2)); + + assert(n); + do { + int16_t X1 = pt->x; + int16_t y = pt->y; + int16_t X2 = X1 + (int)*width; + const BoxRec *c; + + pt++; + width++; + + if (y < data->region.extents.y1 || data->region.extents.y2 <= y) + continue; + + if (X1 < data->region.extents.x1) + X1 = data->region.extents.x1; + + if (X2 > data->region.extents.x2) + X2 = data->region.extents.x2; + + if (X1 >= X2) + continue; + + c = find_clip_box_for_y(clip_start, clip_end, y); + while (c != clip_end) { + if (y + 1 <= c->y1) + break; + + if (X1 >= c->x2) + break; + if (X2 <= c->x1) { + c++; + continue; + } + + b->x1 = c->x1; + b->x2 = c->x2; + c++; + + if (b->x1 < X1) + b->x1 = X1; + if (b->x2 > X2) + b->x2 = X2; + if (b->x2 <= b->x1) + continue; + + b->x1 += data->dx; + b->x2 += data->dx; + b->y1 = y + data->dy; + b->y2 = b->y1 + 1; + if (++b == last_box) { + op->boxes(data->sna, op, box, last_box - box); + b = box; + } + } + } while (--n); + if (b != box) + op->boxes(data->sna, op, box, b - box); +} static Bool sna_fill_spans_blt(DrawablePtr drawable, @@ -4061,7 +4306,7 @@ fallback: goto out; if (!sna_drawable_move_region_to_cpu(drawable, ®ion, drawable_gc_flags(drawable, - gc, true))) + gc, n > 1))) goto out; fbFillSpans(drawable, gc, n, pt, width, sorted); @@ -7505,6 +7750,146 @@ get_pixel(PixmapPtr pixmap) } } +static bool +gc_is_solid(GCPtr gc, uint32_t *color) +{ + if (gc->fillStyle == FillSolid || + (gc->fillStyle == FillTiled && gc->tileIsPixel) || + (gc->fillStyle == FillOpaqueStippled && gc->bgPixel == gc->fgPixel)) { + *color = gc->fillStyle == FillTiled ? gc->tile.pixel : gc->fgPixel; + return true; + } + + return false; +} + +static void +sna_poly_fill_polygon(DrawablePtr draw, GCPtr gc, + int shape, int mode, + int n, DDXPointPtr pt) +{ + struct sna_fill_spans data; + struct sna_pixmap *priv; + + DBG(("%s(n=%d, PlaneMask: %lx (solid %d), solid fill: %d [style=%d, tileIsPixel=%d], alu=%d)\n", __FUNCTION__, + n, gc->planemask, !!PM_IS_SOLID(draw, gc->planemask), + (gc->fillStyle == FillSolid || + (gc->fillStyle == FillTiled && gc->tileIsPixel)), + gc->fillStyle, gc->tileIsPixel, + gc->alu)); + + data.flags = sna_poly_point_extents(draw, gc, mode, n, pt, + &data.region.extents); + if (data.flags == 0) { + DBG(("%s, nothing to do\n", __FUNCTION__)); + return; + } + + DBG(("%s: extents(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__, + data.region.extents.x1, data.region.extents.y1, + data.region.extents.x2, data.region.extents.y2, + data.flags)); + + data.region.data = NULL; + + if (FORCE_FALLBACK) + goto fallback; + + if (!ACCEL_POLY_FILL_POLYGON) + goto fallback; + + data.pixmap = get_drawable_pixmap(draw); + data.sna = to_sna_from_pixmap(data.pixmap); + priv = sna_pixmap(data.pixmap); + if (priv == NULL) { + DBG(("%s: fallback -- unattached\n", __FUNCTION__)); + goto fallback; + } + + if (wedged(data.sna)) { + DBG(("%s: fallback -- wedged\n", __FUNCTION__)); + goto fallback; + } + + if (!PM_IS_SOLID(draw, gc->planemask)) + goto fallback; + + if (sna_drawable_use_gpu_bo(draw, + &data.region.extents, + &data.damage)) { + uint32_t color; + + get_drawable_deltas(draw, data.pixmap, &data.dx, &data.dy); + + if (gc_is_solid(gc, &color)) { + struct sna_fill_op fill; + + if (!sna_fill_init_blt(&fill, + data.sna, data.pixmap, + priv->gpu_bo, gc->alu, color)) + goto fallback; + + data.op = &fill; + sna_gc(gc)->priv = &data; + + if ((data.flags & 2) == 0) { + if (data.dx | data.dy) + gc->ops->FillSpans = sna_fill_spans__fill_offset; + else + gc->ops->FillSpans = sna_fill_spans__fill; + } else { + region_maybe_clip(&data.region, + gc->pCompositeClip); + if (!RegionNotEmpty(&data.region)) + return; + + if (region_is_singular(&data.region)) + gc->ops->FillSpans = sna_fill_spans__fill_clip_extents; + else + gc->ops->FillSpans = sna_fill_spans__fill_clip_boxes; + } + assert(gc->miTranslate); + miFillPolygon(draw, gc, shape, mode, n, pt); + gc->ops->FillSpans = sna_fill_spans; + + fill.done(data.sna, &fill); + if (data.damage) + sna_damage_add(data.damage, &data.region); + RegionUninit(&data.region); + return; + } + + /* XXX */ + miFillPolygon(draw, gc, shape, mode, n, pt); + return; + } + +fallback: + DBG(("%s: fallback (%d, %d), (%d, %d)\n", __FUNCTION__, + data.region.extents.x1, data.region.extents.y1, + data.region.extents.x2, data.region.extents.y2)); + region_maybe_clip(&data.region, gc->pCompositeClip); + if (!RegionNotEmpty(&data.region)) { + DBG(("%s: nothing to do, all clipped\n", __FUNCTION__)); + return; + } + + if (!sna_gc_move_to_cpu(gc, draw)) + goto out; + + if (!sna_drawable_move_region_to_cpu(draw, &data.region, + drawable_gc_flags(draw, gc, + true))) + goto out; + + DBG(("%s: fallback -- miFillPolygon -> sna_fill_spans__cpu\n", __FUNCTION__)); + gc->ops->FillSpans = sna_fill_spans__cpu; + miFillPolygon(draw, gc, shape, mode, n, pt); + gc->ops->FillSpans = sna_fill_spans; +out: + RegionUninit(&data.region); +} + static Bool sna_poly_fill_rect_tiled_blt(DrawablePtr drawable, struct kgem_bo *bo, @@ -10015,7 +10400,7 @@ out: RegionUninit(®ion); } -static const GCOps sna_gc_ops = { +static GCOps sna_gc_ops = { sna_fill_spans, sna_set_spans, sna_put_image, @@ -10026,7 +10411,7 @@ static const GCOps sna_gc_ops = { sna_poly_segment, sna_poly_rectangle, sna_poly_arc, - miFillPolygon, + sna_poly_fill_polygon, sna_poly_fill_rect, miPolyFillArc, sna_poly_text8, @@ -10051,7 +10436,7 @@ sna_validate_gc(GCPtr gc, unsigned long changes, DrawablePtr drawable) sna_gc(gc)->changes |= changes; } -static const GCFuncs sna_gc_funcs = { +static GCFuncs sna_gc_funcs = { sna_validate_gc, miChangeGC, miCopyGC, @@ -10066,8 +10451,8 @@ static int sna_create_gc(GCPtr gc) if (!fbCreateGC(gc)) return FALSE; - gc->funcs = (GCFuncs *)&sna_gc_funcs; - gc->ops = (GCOps *)&sna_gc_ops; + gc->funcs = &sna_gc_funcs; + gc->ops = &sna_gc_ops; return TRUE; } diff --git a/src/sna/sna_blt.c b/src/sna/sna_blt.c index 86cc3111..535628c0 100644 --- a/src/sna/sna_blt.c +++ b/src/sna/sna_blt.c @@ -117,17 +117,17 @@ static bool sna_blt_fill_init(struct sna *sna, uint32_t pixel) { struct kgem *kgem = &sna->kgem; - int pitch; + assert(bo->tiling != I915_TILING_Y); blt->bo[0] = bo; - pitch = bo->pitch; + blt->br13 = bo->pitch; blt->cmd = XY_SCANLINE_BLT; - if (kgem->gen >= 40 && blt->bo[0]->tiling) { - blt->cmd |= 1 << 11; - pitch >>= 2; + if (kgem->gen >= 40 && bo->tiling) { + blt->cmd |= BLT_DST_TILED; + blt->br13 >>= 2; } - assert(pitch < MAXSHORT); + assert(blt->br13 < MAXSHORT); if (alu == GXclear) pixel = 0; @@ -138,7 +138,7 @@ static bool sna_blt_fill_init(struct sna *sna, alu = GXset; } - blt->br13 = 1<<31 | (fill_ROP[alu] << 16) | pitch; + blt->br13 |= 1<<31 | (fill_ROP[alu] << 16); switch (bpp) { default: assert(0); case 32: blt->br13 |= 1 << 25; /* RGB8888 */