diff options
Diffstat (limited to 'src/sna/sna_blt.c')
-rw-r--r-- | src/sna/sna_blt.c | 356 |
1 files changed, 322 insertions, 34 deletions
diff --git a/src/sna/sna_blt.c b/src/sna/sna_blt.c index 5879e973..07771a90 100644 --- a/src/sna/sna_blt.c +++ b/src/sna/sna_blt.c @@ -307,6 +307,104 @@ static Bool sna_blt_copy_init(struct sna *sna, return TRUE; } +static Bool sna_blt_alpha_fixup_init(struct sna *sna, + struct sna_blt_state *blt, + struct kgem_bo *src, + struct kgem_bo *dst, + int bpp, uint32_t alpha) +{ + struct kgem *kgem = &sna->kgem; + + blt->bo[0] = src; + blt->bo[1] = dst; + + blt->cmd = XY_FULL_MONO_PATTERN_BLT; + blt->pitch[0] = src->pitch; + if (kgem->gen >= 40 && src->tiling) { + blt->cmd |= BLT_SRC_TILED; + blt->pitch[0] >>= 2; + } + assert(blt->pitch[0] < MAXSHORT); + + blt->pitch[1] = dst->pitch; + if (kgem->gen >= 40 && dst->tiling) { + blt->cmd |= BLT_DST_TILED; + blt->pitch[1] >>= 2; + } + assert(blt->pitch[1] < MAXSHORT); + + blt->overwrites = 1; + blt->br13 = (0xfc << 16) | blt->pitch[1]; + switch (bpp) { + default: assert(0); + case 32: blt->cmd |= BLT_WRITE_ALPHA | BLT_WRITE_RGB; + blt->br13 |= 1 << 25; /* RGB8888 */ + case 16: blt->br13 |= 1 << 24; /* RGB565 */ + case 8: break; + } + blt->pixel = alpha; + + kgem_set_mode(kgem, KGEM_BLT); + if (!kgem_check_bo_fenced(kgem, src, dst, NULL)) { + _kgem_submit(kgem); + _kgem_set_mode(kgem, KGEM_BLT); + } + + sna->blt_state.fill_bo = 0; + return TRUE; +} + +static void sna_blt_alpha_fixup_one(struct sna *sna, + const struct sna_blt_state *blt, + int src_x, int src_y, + int width, int height, + int dst_x, int dst_y) +{ + struct kgem *kgem = &sna->kgem; + uint32_t *b; + + DBG(("%s: (%d, %d) -> (%d, %d) x (%d, %d)\n", + __FUNCTION__, src_x, src_y, dst_x, dst_y, width, height)); + + assert(src_x >= 0); + assert(src_y >= 0); + assert((src_y + height) * blt->bo[0]->pitch <= blt->bo[0]->size); + assert(dst_x >= 0); + assert(dst_y >= 0); + assert((dst_y + height) * blt->bo[1]->pitch <= blt->bo[1]->size); + assert(width > 0); + assert(height > 0); + + if (!kgem_check_batch(kgem, 12) || !kgem_check_reloc(kgem, 2)) { + _kgem_submit(kgem); + _kgem_set_mode(kgem, KGEM_BLT); + } + + b = kgem->batch + kgem->nbatch; + b[0] = blt->cmd; + b[1] = blt->br13; + b[2] = (dst_y << 16) | dst_x; + b[3] = ((dst_y + height) << 16) | (dst_x + width); + b[4] = kgem_add_reloc(kgem, kgem->nbatch + 4, + blt->bo[1], + I915_GEM_DOMAIN_RENDER << 16 | + I915_GEM_DOMAIN_RENDER | + KGEM_RELOC_FENCED, + 0); + b[5] = blt->pitch[0]; + b[6] = (src_y << 16) | src_x; + b[7] = kgem_add_reloc(kgem, kgem->nbatch + 7, + blt->bo[0], + I915_GEM_DOMAIN_RENDER << 16 | + KGEM_RELOC_FENCED, + 0); + b[8] = blt->pixel; + b[9] = blt->pixel; + b[10] = 0; + b[11] = 0; + kgem->nbatch += 12; +} + static void sna_blt_copy_one(struct sna *sna, const struct sna_blt_state *blt, int src_x, int src_y, @@ -930,9 +1028,90 @@ static void blt_composite_copy_boxes(struct sna *sna, } while(--nbox); } +fastcall static void +blt_composite_copy_with_alpha(struct sna *sna, + const struct sna_composite_op *op, + const struct sna_composite_rectangles *r) +{ + int x1, x2, y1, y2; + int src_x, src_y; + + DBG(("%s: src=(%d, %d), dst=(%d, %d), size=(%d, %d)\n", + __FUNCTION__, + r->src.x, r->src.y, + r->dst.x, r->dst.y, + r->width, r->height)); + + /* XXX higher layer should have clipped? */ + + x1 = r->dst.x + op->dst.x; + y1 = r->dst.y + op->dst.y; + x2 = x1 + r->width; + y2 = y1 + r->height; + + src_x = r->src.x - x1; + src_y = r->src.y - y1; + + /* clip against dst */ + if (x1 < 0) + x1 = 0; + if (y1 < 0) + y1 = 0; + + if (x2 > op->dst.width) + x2 = op->dst.width; + + if (y2 > op->dst.height) + y2 = op->dst.height; + + DBG(("%s: box=(%d, %d), (%d, %d)\n", __FUNCTION__, x1, y1, x2, y2)); + + if (x2 <= x1 || y2 <= y1) + return; + + sna_blt_alpha_fixup_one(sna, &op->u.blt, + x1 + src_x, y1 + src_y, + x2 - x1, y2 - y1, + x1, y1); +} + +fastcall static void +blt_composite_copy_box_with_alpha(struct sna *sna, + const struct sna_composite_op *op, + const BoxRec *box) +{ + DBG(("%s: box (%d, %d), (%d, %d)\n", + __FUNCTION__, box->x1, box->y1, box->x2, box->y2)); + sna_blt_alpha_fixup_one(sna, &op->u.blt, + box->x1 + op->u.blt.sx, + box->y1 + op->u.blt.sy, + box->x2 - box->x1, + box->y2 - box->y1, + box->x1 + op->dst.x, + box->y1 + op->dst.y); +} + +static void +blt_composite_copy_boxes_with_alpha(struct sna *sna, + const struct sna_composite_op *op, + const BoxRec *box, int nbox) +{ + DBG(("%s: nbox=%d\n", __FUNCTION__, nbox)); + do { + DBG(("%s: box (%d, %d), (%d, %d)\n", + __FUNCTION__, box->x1, box->y1, box->x2, box->y2)); + sna_blt_alpha_fixup_one(sna, &op->u.blt, + box->x1 + op->u.blt.sx, box->y1 + op->u.blt.sy, + box->x2 - box->x1, box->y2 - box->y1, + box->x1 + op->dst.x, box->y1 + op->dst.y); + box++; + } while(--nbox); +} + static Bool prepare_blt_copy(struct sna *sna, - struct sna_composite_op *op) + struct sna_composite_op *op, + uint32_t alpha_fixup) { PixmapPtr src = op->u.blt.src_pixmap; struct sna_pixmap *priv = sna_pixmap(src); @@ -947,19 +1126,32 @@ prepare_blt_copy(struct sna *sna, DBG(("%s\n", __FUNCTION__)); - op->blt = blt_composite_copy; - op->box = blt_composite_copy_box; - op->boxes = blt_composite_copy_boxes; if (sna->kgem.gen >= 60) op->done = gen6_blt_copy_done; else op->done = blt_done; - return sna_blt_copy_init(sna, &op->u.blt, - priv->gpu_bo, - op->dst.bo, - src->drawable.bitsPerPixel, - GXcopy); + if (alpha_fixup) { + op->blt = blt_composite_copy_with_alpha; + op->box = blt_composite_copy_box_with_alpha; + op->boxes = blt_composite_copy_boxes_with_alpha; + + return sna_blt_alpha_fixup_init(sna, &op->u.blt, + priv->gpu_bo, + op->dst.bo, + src->drawable.bitsPerPixel, + alpha_fixup); + } else { + op->blt = blt_composite_copy; + op->box = blt_composite_copy_box; + op->boxes = blt_composite_copy_boxes; + + return sna_blt_copy_init(sna, &op->u.blt, + priv->gpu_bo, + op->dst.bo, + src->drawable.bitsPerPixel, + GXcopy); + } } static void blt_vmap_done(struct sna *sna, const struct sna_composite_op *op) @@ -1082,9 +1274,80 @@ static void blt_put_composite_boxes(struct sna *sna, } } +fastcall static void +blt_put_composite_with_alpha(struct sna *sna, + const struct sna_composite_op *op, + const struct sna_composite_rectangles *r) +{ + PixmapPtr dst = op->dst.pixmap; + PixmapPtr src = op->u.blt.src_pixmap; + struct sna_pixmap *dst_priv = sna_pixmap(dst); + int pitch = src->devKind; + char *data = src->devPrivate.ptr; + + int16_t dst_x = r->dst.x + op->dst.x; + int16_t dst_y = r->dst.y + op->dst.y; + int16_t src_x = r->src.x + op->u.blt.sx; + int16_t src_y = r->src.y + op->u.blt.sy; + BoxRec box; + + box.x1 = dst_x; + box.y1 = dst_y; + box.x2 = dst_x + r->width; + box.y2 = dst_y + r->height; + + sna_write_boxes__xor(sna, dst, + dst_priv->gpu_bo, 0, 0, + data, pitch, src_x, src_y, + &box, 1, + 0xffffffff, op->u.blt.pixel); +} + +fastcall static void +blt_put_composite_box_with_alpha(struct sna *sna, + const struct sna_composite_op *op, + const BoxRec *box) +{ + PixmapPtr src = op->u.blt.src_pixmap; + + DBG(("%s: src=(%d, %d), dst=(%d, %d)\n", __FUNCTION__, + op->u.blt.sx, op->u.blt.sy, + op->dst.x, op->dst.y)); + + sna_write_boxes__xor(sna, op->dst.pixmap, + op->dst.bo, op->dst.x, op->dst.y, + src->devPrivate.ptr, + src->devKind, + op->u.blt.sx, op->u.blt.sy, + box, 1, + 0xffffffff, op->u.blt.pixel); +} + +static void +blt_put_composite_boxes_with_alpha(struct sna *sna, + const struct sna_composite_op *op, + const BoxRec *box, int n) +{ + PixmapPtr src = op->u.blt.src_pixmap; + + DBG(("%s: src=(%d, %d), dst=(%d, %d), [(%d, %d), (%d, %d) x %d]\n", __FUNCTION__, + op->u.blt.sx, op->u.blt.sy, + op->dst.x, op->dst.y, + box->x1, box->y1, box->x2, box->y2, n)); + + sna_write_boxes__xor(sna, op->dst.pixmap, + op->dst.bo, op->dst.x, op->dst.y, + src->devPrivate.ptr, + src->devKind, + op->u.blt.sx, op->u.blt.sy, + box, n, + 0xffffffff, op->u.blt.pixel); +} + static Bool prepare_blt_put(struct sna *sna, - struct sna_composite_op *op) + struct sna_composite_op *op, + uint32_t alpha_fixup) { PixmapPtr src = op->u.blt.src_pixmap; struct sna_pixmap *priv = sna_pixmap(src); @@ -1105,26 +1368,43 @@ prepare_blt_put(struct sna *sna, free_bo = src_bo; } if (src_bo) { - op->blt = blt_composite_copy; - op->box = blt_composite_copy_box; - op->boxes = blt_composite_copy_boxes; - op->u.blt.src_pixmap = (void *)free_bo; op->done = blt_vmap_done; src_bo->pitch = src->devKind; - if (!sna_blt_copy_init(sna, &op->u.blt, - src_bo, op->dst.bo, - op->dst.pixmap->drawable.bitsPerPixel, - GXcopy)) - return FALSE; + if (alpha_fixup) { + op->blt = blt_composite_copy_with_alpha; + op->box = blt_composite_copy_box_with_alpha; + op->boxes = blt_composite_copy_boxes_with_alpha; + + return sna_blt_alpha_fixup_init(sna, &op->u.blt, + src_bo, op->dst.bo, + op->dst.pixmap->drawable.bitsPerPixel, + alpha_fixup); + } else { + op->blt = blt_composite_copy; + op->box = blt_composite_copy_box; + op->boxes = blt_composite_copy_boxes; + + return sna_blt_copy_init(sna, &op->u.blt, + src_bo, op->dst.bo, + op->dst.pixmap->drawable.bitsPerPixel, + GXcopy); + } } else { if (!sna_pixmap_move_to_cpu(src, MOVE_READ)) return FALSE; - op->blt = blt_put_composite; - op->box = blt_put_composite_box; - op->boxes = blt_put_composite_boxes; + if (alpha_fixup) { + op->u.blt.pixel = alpha_fixup; + op->blt = blt_put_composite_with_alpha; + op->box = blt_put_composite_box_with_alpha; + op->boxes = blt_put_composite_boxes_with_alpha; + } else { + op->blt = blt_put_composite; + op->box = blt_put_composite_box; + op->boxes = blt_put_composite_boxes; + } op->done = nop_done; } @@ -1209,6 +1489,13 @@ reduce_damage(struct sna_composite_op *op, op->damage = NULL; } +#define alphaless(format) PICT_FORMAT(PICT_FORMAT_BPP(format), \ + PICT_FORMAT_TYPE(format), \ + 0, \ + PICT_FORMAT_R(format), \ + PICT_FORMAT_G(format), \ + PICT_FORMAT_B(format)) + Bool sna_blt_composite(struct sna *sna, uint32_t op, @@ -1223,6 +1510,7 @@ sna_blt_composite(struct sna *sna, PictFormat src_format = src->format; struct sna_pixmap *priv; int16_t tx, ty; + uint32_t alpha_fixup; Bool ret; #if DEBUG_NO_BLT || NO_BLT_COMPOSITE @@ -1309,13 +1597,13 @@ sna_blt_composite(struct sna *sna, return FALSE; } + alpha_fixup = 0; if (!(dst->format == src_format || - dst->format == PICT_FORMAT(PICT_FORMAT_BPP(src_format), - PICT_FORMAT_TYPE(src_format), - 0, - PICT_FORMAT_R(src_format), - PICT_FORMAT_G(src_format), - PICT_FORMAT_B(src_format)))) { + dst->format == alphaless(src_format) || + (alphaless(dst->format) == alphaless(src_format) && + sna_get_pixel_from_rgba(&alpha_fixup, + 0, 0, 0, 0xffff, + dst->format)))) { DBG(("%s: incompatible src/dst formats src=%08x, dst=%08x\n", __FUNCTION__, (unsigned)src_format, dst->format)); return FALSE; @@ -1349,18 +1637,18 @@ sna_blt_composite(struct sna *sna, tmp->u.blt.sx = x - dst_x; tmp->u.blt.sy = y - dst_y; - DBG(("%s: blt dst offset (%d, %d), source offset (%d, %d)\n", + DBG(("%s: blt dst offset (%d, %d), source offset (%d, %d), with alpha fixup? %x\n", __FUNCTION__, - tmp->dst.x, tmp->dst.y, tmp->u.blt.sx, tmp->u.blt.sy)); + tmp->dst.x, tmp->dst.y, tmp->u.blt.sx, tmp->u.blt.sy, alpha_fixup)); if (has_gpu_area(blt->src_pixmap, x, y, width, height)) - ret = prepare_blt_copy(sna, tmp); + ret = prepare_blt_copy(sna, tmp, alpha_fixup); else if (has_cpu_area(blt->src_pixmap, x, y, width, height)) - ret = prepare_blt_put(sna, tmp); + ret = prepare_blt_put(sna, tmp, alpha_fixup); else if (sna_pixmap_move_to_gpu(blt->src_pixmap, MOVE_READ)) - ret = prepare_blt_copy(sna, tmp); + ret = prepare_blt_copy(sna, tmp, alpha_fixup); else - ret = prepare_blt_put(sna, tmp); + ret = prepare_blt_put(sna, tmp, alpha_fixup); return ret; } |