diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2010-05-21 09:55:55 +0100 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2010-05-24 18:31:16 +0100 |
commit | 80a9e64f50aeda6004e3aba1fbfdda50bb1f1c82 (patch) | |
tree | a9e39dec68ff4fd3b4d61a5c26cd7fc18b88a3b0 /uxa | |
parent | 91f560034fc2695680d1208a78fc56d814b0da79 (diff) |
uxa: Use temporary dest when target is too large for compositor
If the destination cannot fit into the 3D pipeline when we need to
composite, we fallback to doing the operation on the CPU. This is very
slow, and quite easy to trigger on i915 by plugging in an external
display.
An alternative is to extract the extents of the operation from the
destination using the blitter which can usually handle much larger
operations. This gives us a temporary target that can fit into the 3D
pipeline and thus be accelerated, before copying back into the larger
real destination.
For x11perf this boosts glyph rendering on PineView, from 38kglyphs/s to
480kglyphs/s. Just a little shy of the native performance of 601kglyphs/s
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Diffstat (limited to 'uxa')
-rw-r--r-- | uxa/uxa-accel.c | 28 | ||||
-rw-r--r-- | uxa/uxa-glyphs.c | 185 | ||||
-rw-r--r-- | uxa/uxa-render.c | 233 | ||||
-rw-r--r-- | uxa/uxa.h | 20 |
4 files changed, 364 insertions, 102 deletions
diff --git a/uxa/uxa-accel.c b/uxa/uxa-accel.c index 0528d796..77963f39 100644 --- a/uxa/uxa-accel.c +++ b/uxa/uxa-accel.c @@ -103,7 +103,7 @@ uxa_fill_spans(DrawablePtr pDrawable, GCPtr pGC, int n, goto solid; } - if (!uxa_screen->info->check_composite(PictOpSrc, src, NULL, dst)) { + if (!uxa_screen->info->check_composite(PictOpSrc, src, NULL, dst, 0, 0)) { FreePicture(src, 0); FreePicture(dst, 0); goto solid; @@ -586,17 +586,17 @@ uxa_copy_n_to_n(DrawablePtr pSrcDrawable, int dst_off_x, dst_off_y; PixmapPtr pSrcPixmap, pDstPixmap; - if (uxa_screen->info->check_copy && - !uxa_screen->info->check_copy(pSrcDrawable, pDstDrawable, - pGC ? pGC->alu : GXcopy, - pGC ? pGC->planemask : FB_ALLONES)) - goto fallback; - pSrcPixmap = uxa_get_drawable_pixmap(pSrcDrawable); pDstPixmap = uxa_get_drawable_pixmap(pDstDrawable); if (!pSrcPixmap || !pDstPixmap) goto fallback; + if (uxa_screen->info->check_copy && + !uxa_screen->info->check_copy(pSrcPixmap, pDstPixmap, + pGC ? pGC->alu : GXcopy, + pGC ? pGC->planemask : FB_ALLONES)) + goto fallback; + uxa_get_drawable_deltas(pSrcDrawable, pSrcPixmap, &src_off_x, &src_off_y); uxa_get_drawable_deltas(pDstDrawable, pDstPixmap, &dst_off_x, @@ -1121,20 +1121,16 @@ uxa_fill_region_tiled(DrawablePtr pDrawable, uxa_get_pixmap_first_pixel(pTile), planemask, alu); + pPixmap = uxa_get_offscreen_pixmap(pDrawable, &xoff, &yoff); + if (!pPixmap || !uxa_pixmap_is_offscreen(pTile)) + goto out; + if (uxa_screen->info->check_copy && - !uxa_screen->info->check_copy(&pTile->drawable, pDrawable, alu, planemask)) + !uxa_screen->info->check_copy(pTile, pPixmap, alu, planemask)) return FALSE; - - pPixmap = uxa_get_drawable_pixmap(pDrawable); - uxa_get_drawable_deltas(pDrawable, pPixmap, &xoff, &yoff); REGION_TRANSLATE(pScreen, pRegion, xoff, yoff); - pPixmap = uxa_get_offscreen_pixmap(pDrawable, &xoff, &yoff); - - if (!pPixmap || !uxa_pixmap_is_offscreen(pTile)) - goto out; - if ((*uxa_screen->info->prepare_copy) (pTile, pPixmap, 1, 1, alu, planemask)) { while (nbox--) { diff --git a/uxa/uxa-glyphs.c b/uxa/uxa-glyphs.c index 921297a5..93a738ed 100644 --- a/uxa/uxa-glyphs.c +++ b/uxa/uxa-glyphs.c @@ -656,7 +656,7 @@ uxa_glyphs_try_driver_composite(CARD8 op, int nrect; if (uxa_screen->info->check_composite && - !(*uxa_screen->info->check_composite) (op, pSrc, buffer->source, pDst)) { + !(*uxa_screen->info->check_composite) (op, pSrc, buffer->source, pDst, 0, 0)) { return -1; } @@ -787,7 +787,7 @@ uxa_glyphs_try_driver_add_to_mask(PicturePtr pDst, int nrect; if (uxa_screen->info->check_composite && - !(*uxa_screen->info->check_composite) (PictOpAdd, buffer->source, NULL, pDst)) { + !(*uxa_screen->info->check_composite) (PictOpAdd, buffer->source, NULL, pDst, 0, 0)) { return -1; } @@ -1109,13 +1109,12 @@ uxa_glyphs(CARD8 op, PicturePtr pSrc, PicturePtr pDst, PictFormatPtr maskFormat, - INT16 xSrc, - INT16 ySrc, int nlist, GlyphListPtr list, GlyphPtr * glyphs) + INT16 xSrc, INT16 ySrc, + int nlist, GlyphListPtr list, GlyphPtr * glyphs) { - ScreenPtr pScreen = pDst->pDrawable->pScreen; - uxa_screen_t *uxa_screen = uxa_get_screen(pScreen); - PixmapPtr pMaskPixmap = 0; - PicturePtr pMask; + ScreenPtr screen = pDst->pDrawable->pScreen; + uxa_screen_t *uxa_screen = uxa_get_screen(screen); + PicturePtr pMask = NULL; int width = 0, height = 0; int x, y; int xDst = list->xOff, yDst = list->yOff; @@ -1123,13 +1122,16 @@ uxa_glyphs(CARD8 op, GlyphPtr glyph; int error; BoxRec extents = { 0, 0, 0, 0 }; + Bool have_extents = FALSE; CARD32 component_alpha; uxa_glyph_buffer_t buffer; + PicturePtr localDst = pDst; if (!uxa_screen->info->prepare_composite || uxa_screen->swappedOut || !uxa_drawable_is_offscreen(pDst->pDrawable) || pDst->alphaMap || pSrc->alphaMap) { +fallback: uxa_check_glyphs(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs); return; } @@ -1161,55 +1163,129 @@ uxa_glyphs(CARD8 op, } } - if (maskFormat) { - GCPtr pGC; - xRectangle rect; + x = y = 0; + if (!maskFormat && + uxa_screen->info->check_composite_target && + !uxa_screen->info->check_composite_target(uxa_get_drawable_pixmap(pDst->pDrawable))) { + int depth = pDst->pDrawable->depth; + PixmapPtr pixmap; + int error; + GCPtr gc; + + pixmap = uxa_get_drawable_pixmap(pDst->pDrawable); + if (uxa_screen->info->check_copy && + !uxa_screen->info->check_copy(pixmap, pixmap, GXcopy, FB_ALLONES)) + goto fallback; uxa_glyph_extents(nlist, list, glyphs, &extents); + /* clip against dst bounds */ + if (extents.x1 < 0) + extents.x1 = 0; + if (extents.y1 < 0) + extents.y1 = 0; + if (extents.x2 > pDst->pDrawable->width) + extents.x2 = pDst->pDrawable->width; + if (extents.y2 > pDst->pDrawable->height) + extents.y2 = pDst->pDrawable->height; + if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1) return; - width = extents.x2 - extents.x1; + width = extents.x2 - extents.x1; height = extents.y2 - extents.y1; + x = -extents.x1; + y = -extents.y1; + have_extents = TRUE; + + xDst += x; + yDst += y; + + pixmap = screen->CreatePixmap(screen, + width, height, depth, + CREATE_PIXMAP_USAGE_SCRATCH); + if (!pixmap) + return; + + gc = GetScratchGC(depth, screen); + if (!gc) { + screen->DestroyPixmap(pixmap); + return; + } + + ValidateGC(&pixmap->drawable, gc); + gc->ops->CopyArea(pDst->pDrawable, &pixmap->drawable, gc, + extents.x1, extents.y1, + width, height, + 0, 0); + FreeScratchGC(gc); + + localDst = CreatePicture(0, &pixmap->drawable, + PictureMatchFormat(screen, depth, pDst->format), + 0, 0, serverClient, &error); + screen->DestroyPixmap(pixmap); + + if (!localDst) + return; + + ValidatePicture(localDst); + } + + if (maskFormat) { + PixmapPtr pixmap; + GCPtr gc; + xRectangle rect; + + if (!have_extents) { + uxa_glyph_extents(nlist, list, glyphs, &extents); + + if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1) + return; + width = extents.x2 - extents.x1; + height = extents.y2 - extents.y1; + x = -extents.x1; + y = -extents.y1; + have_extents = TRUE; + } if (maskFormat->depth == 1) { PictFormatPtr a8Format = - PictureMatchFormat(pScreen, 8, PICT_a8); + PictureMatchFormat(screen, 8, PICT_a8); if (a8Format) maskFormat = a8Format; } - pMaskPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, - maskFormat->depth, - CREATE_PIXMAP_USAGE_SCRATCH); - if (!pMaskPixmap) + pixmap = screen->CreatePixmap(screen, width, height, + maskFormat->depth, + CREATE_PIXMAP_USAGE_SCRATCH); + if (!pixmap) { + if (localDst != pDst) + FreePicture(localDst, 0); return; + } + + gc = GetScratchGC(pixmap->drawable.depth, screen); + ValidateGC(&pixmap->drawable, gc); + rect.x = 0; + rect.y = 0; + rect.width = width; + rect.height = height; + gc->ops->PolyFillRect(&pixmap->drawable, gc, 1, &rect); + FreeScratchGC(gc); + component_alpha = NeedsComponent(maskFormat->format); - pMask = CreatePicture(0, &pMaskPixmap->drawable, + pMask = CreatePicture(0, &pixmap->drawable, maskFormat, CPComponentAlpha, &component_alpha, serverClient, &error); + screen->DestroyPixmap(pixmap); + if (!pMask) { - (*pScreen->DestroyPixmap) (pMaskPixmap); + if (localDst != pDst) + FreePicture(localDst, 0); return; } - pGC = GetScratchGC(pMaskPixmap->drawable.depth, pScreen); - ValidateGC(&pMaskPixmap->drawable, pGC); - rect.x = 0; - rect.y = 0; - rect.width = width; - rect.height = height; - (*pGC->ops->PolyFillRect) (&pMaskPixmap->drawable, pGC, 1, - &rect); - FreeScratchGC(pGC); - x = -extents.x1; - y = -extents.y1; ValidatePicture(pMask); - } else { - pMask = pDst; - x = 0; - y = 0; } buffer.count = 0; @@ -1222,19 +1298,19 @@ uxa_glyphs(CARD8 op, glyph = *glyphs++; if (glyph->info.width > 0 && glyph->info.height > 0 && - uxa_buffer_glyph(pScreen, &buffer, glyph, x, + uxa_buffer_glyph(screen, &buffer, glyph, x, y) == UXA_GLYPH_NEED_FLUSH) { if (maskFormat) uxa_glyphs_to_mask(pMask, &buffer); else - uxa_glyphs_to_dst(op, pSrc, pDst, + uxa_glyphs_to_dst(op, pSrc, localDst, &buffer, xSrc, ySrc, xDst, yDst); buffer.count = 0; buffer.source = NULL; - uxa_buffer_glyph(pScreen, &buffer, glyph, x, y); + uxa_buffer_glyph(screen, &buffer, glyph, x, y); } x += glyph->info.xOff; @@ -1247,20 +1323,41 @@ uxa_glyphs(CARD8 op, if (maskFormat) uxa_glyphs_to_mask(pMask, &buffer); else - uxa_glyphs_to_dst(op, pSrc, pDst, &buffer, + uxa_glyphs_to_dst(op, pSrc, localDst, &buffer, xSrc, ySrc, xDst, yDst); } if (maskFormat) { - x = extents.x1; - y = extents.y1; + if (localDst == pDst) { + x = extents.x1; + y = extents.y1; + } else + x = y = 0; CompositePicture(op, pSrc, pMask, - pDst, + localDst, xSrc + x - xDst, - ySrc + y - yDst, 0, 0, x, y, width, height); - FreePicture((pointer) pMask, (XID) 0); - (*pScreen->DestroyPixmap) (pMaskPixmap); + ySrc + y - yDst, + 0, 0, + x, y, + width, height); + FreePicture(pMask, 0); + } + + if (localDst != pDst) { + GCPtr gc; + + gc = GetScratchGC(pDst->pDrawable->depth, screen); + if (gc) { + ValidateGC(pDst->pDrawable, gc); + gc->ops->CopyArea(localDst->pDrawable, pDst->pDrawable, gc, + 0, 0, + width, height, + extents.x1, extents.y1); + FreeScratchGC(gc); + } + + FreePicture(localDst, 0); } } diff --git a/uxa/uxa-render.c b/uxa/uxa-render.c index c866b854..ec59871b 100644 --- a/uxa/uxa-render.c +++ b/uxa/uxa-render.c @@ -788,7 +788,9 @@ uxa_acquire_drawable(ScreenPtr pScreen, } } - pPixmap = pScreen->CreatePixmap(pScreen, width, height, depth, 0); + pPixmap = pScreen->CreatePixmap(pScreen, + width, height, depth, + CREATE_PIXMAP_USAGE_SCRATCH); if (!pPixmap) return 0; @@ -935,7 +937,7 @@ uxa_solid_rects (CARD8 op, uxa_screen_t *uxa_screen = uxa_get_screen(screen); PixmapPtr dst_pixmap, src_pixmap = NULL; pixman_region16_t region; - pixman_box16_t *boxes; + pixman_box16_t *boxes, *extents; PicturePtr src; int dst_x, dst_y; int num_boxes; @@ -960,6 +962,7 @@ uxa_solid_rects (CARD8 op, pixman_region_translate(®ion, dst_x, dst_y); boxes = pixman_region_rectangles(®ion, &num_boxes); + extents = pixman_region_extents (®ion); if (op == PictOpClear) color->red = color->green = color->blue = color->alpha = 0; @@ -970,6 +973,7 @@ uxa_solid_rects (CARD8 op, if (num_boxes == 1 && (op == PictOpSrc || op == PictOpClear)) { CARD32 pixel; +try_solid: if (uxa_screen->info->check_solid && !uxa_screen->info->check_solid(&dst_pixmap->drawable, GXcopy, FB_ALLONES)) goto err_region; @@ -985,9 +989,12 @@ uxa_solid_rects (CARD8 op, if (!uxa_screen->info->prepare_solid(dst_pixmap, GXcopy, FB_ALLONES, pixel)) goto err_region; - uxa_screen->info->solid(dst_pixmap, - boxes->x1, boxes->y1, - boxes->x2, boxes->y2); + while (num_boxes--) { + uxa_screen->info->solid(dst_pixmap, + boxes->x1, boxes->y1, + boxes->x2, boxes->y2); + boxes++; + } uxa_screen->info->done_solid(dst_pixmap); } else { @@ -997,8 +1004,16 @@ uxa_solid_rects (CARD8 op, if (!src) goto err_region; - if (!uxa_screen->info->check_composite(op, src, NULL, dst)) + if (!uxa_screen->info->check_composite(op, src, NULL, dst, + extents->x2 - extents->x1, + extents->y2 - extents->y1)) { + if (op == PictOpSrc || op == PictOpClear) { + FreePicture(src, 0); + goto try_solid; + } + goto err_src; + } if (!uxa_screen->info->check_composite_texture || !uxa_screen->info->check_composite_texture(screen, src)) { @@ -1053,53 +1068,109 @@ uxa_try_driver_composite(CARD8 op, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height) { - uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen); + ScreenPtr screen = pDst->pDrawable->pScreen; + uxa_screen_t *uxa_screen = uxa_get_screen(screen); RegionRec region; BoxPtr pbox; int nbox; + int xDst_copy, yDst_copy; int src_off_x, src_off_y, mask_off_x, mask_off_y, dst_off_x, dst_off_y; PixmapPtr pSrcPix, pMaskPix = NULL, pDstPix; PicturePtr localSrc, localMask = NULL; + PicturePtr localDst = pDst; if (uxa_screen->info->check_composite && - !(*uxa_screen->info->check_composite) (op, pSrc, pMask, pDst)) + !(*uxa_screen->info->check_composite) (op, pSrc, pMask, pDst, width, height)) return -1; + if (uxa_screen->info->check_composite_target && + !uxa_screen->info->check_composite_target(uxa_get_drawable_pixmap(pDst->pDrawable))) { + int depth = pDst->pDrawable->depth; + PixmapPtr pixmap; + int error; + GCPtr gc; + + pixmap = uxa_get_drawable_pixmap(pDst->pDrawable); + if (uxa_screen->info->check_copy && + !uxa_screen->info->check_copy(pixmap, pixmap, GXcopy, FB_ALLONES)) + return -1; + + pixmap = screen->CreatePixmap(screen, + width, height, depth, + CREATE_PIXMAP_USAGE_SCRATCH); + if (!pixmap) + return 0; + + gc = GetScratchGC(depth, screen); + if (!gc) { + screen->DestroyPixmap(pixmap); + return 0; + } + + ValidateGC(&pixmap->drawable, gc); + gc->ops->CopyArea(pDst->pDrawable, &pixmap->drawable, gc, + xDst, yDst, width, height, 0, 0); + FreeScratchGC(gc); + + xDst_copy = xDst; xDst = 0; + yDst_copy = yDst; yDst = 0; + + localDst = CreatePicture(0, &pixmap->drawable, + PictureMatchFormat(screen, depth, pDst->format), + 0, 0, serverClient, &error); + screen->DestroyPixmap(pixmap); + + if (!localDst) + return 0; + + ValidatePicture(localDst); + } + pDstPix = - uxa_get_offscreen_pixmap(pDst->pDrawable, &dst_off_x, &dst_off_y); - if (!pDstPix) + uxa_get_offscreen_pixmap(localDst->pDrawable, &dst_off_x, &dst_off_y); + if (!pDstPix) { + if (localDst != pDst) + FreePicture(localDst, 0); return -1; + } - xDst += pDst->pDrawable->x; - yDst += pDst->pDrawable->y; + xDst += localDst->pDrawable->x; + yDst += localDst->pDrawable->y; - localSrc = uxa_acquire_source(pDst->pDrawable->pScreen, pSrc, + localSrc = uxa_acquire_source(screen, pSrc, xSrc, ySrc, width, height, &xSrc, &ySrc); - if (!localSrc) + if (!localSrc) { + if (localDst != pDst) + FreePicture(localDst, 0); return 0; + } if (pMask) { - localMask = uxa_acquire_mask(pDst->pDrawable->pScreen, pMask, + localMask = uxa_acquire_mask(screen, pMask, xMask, yMask, width, height, &xMask, &yMask); if (!localMask) { if (localSrc != pSrc) FreePicture(localSrc, 0); + if (localDst != pDst) + FreePicture(localDst, 0); return 0; } } - if (!miComputeCompositeRegion(®ion, localSrc, localMask, pDst, + if (!miComputeCompositeRegion(®ion, localSrc, localMask, localDst, xSrc, ySrc, xMask, yMask, xDst, yDst, width, height)) { if (localSrc != pSrc) FreePicture(localSrc, 0); if (localMask && localMask != pMask) FreePicture(localMask, 0); + if (localDst != pDst) + FreePicture(localDst, 0); return 1; } @@ -1108,12 +1179,14 @@ uxa_try_driver_composite(CARD8 op, pSrcPix = uxa_get_offscreen_pixmap(localSrc->pDrawable, &src_off_x, &src_off_y); if (!pSrcPix) { - REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); + REGION_UNINIT(screen, ®ion); if (localSrc != pSrc) FreePicture(localSrc, 0); if (localMask && localMask != pMask) FreePicture(localMask, 0); + if (localDst != pDst) + FreePicture(localDst, 0); return 0; } @@ -1126,12 +1199,14 @@ uxa_try_driver_composite(CARD8 op, pMaskPix = uxa_get_offscreen_pixmap(localMask->pDrawable, &mask_off_x, &mask_off_y); if (!pMaskPix) { - REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); + REGION_UNINIT(screen, ®ion); if (localSrc != pSrc) FreePicture(localSrc, 0); if (localMask && localMask != pMask) FreePicture(localMask, 0); + if (localDst != pDst) + FreePicture(localDst, 0); return 0; } @@ -1141,13 +1216,15 @@ uxa_try_driver_composite(CARD8 op, } if (!(*uxa_screen->info->prepare_composite) - (op, localSrc, localMask, pDst, pSrcPix, pMaskPix, pDstPix)) { - REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); + (op, localSrc, localMask, localDst, pSrcPix, pMaskPix, pDstPix)) { + REGION_UNINIT(screen, ®ion); if (localSrc != pSrc) FreePicture(localSrc, 0); if (localMask && localMask != pMask) FreePicture(localMask, 0); + if (localDst != pDst) + FreePicture(localDst, 0); return -1; } @@ -1176,13 +1253,27 @@ uxa_try_driver_composite(CARD8 op, } (*uxa_screen->info->done_composite) (pDstPix); - REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); + REGION_UNINIT(screen, ®ion); if (localSrc != pSrc) FreePicture(localSrc, 0); if (localMask && localMask != pMask) FreePicture(localMask, 0); + if (localDst != pDst) { + GCPtr gc; + + gc = GetScratchGC(pDst->pDrawable->depth, screen); + if (gc) { + ValidateGC(pDst->pDrawable, gc); + gc->ops->CopyArea(localDst->pDrawable, pDst->pDrawable, gc, + 0, 0, width, height, xDst_copy, yDst_copy); + FreeScratchGC(gc); + } + + FreePicture(localDst, 0); + } + return 1; } @@ -1240,36 +1331,100 @@ uxa_try_magic_two_pass_composite_helper(CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst, - INT16 xSrc, - INT16 ySrc, - INT16 xMask, - INT16 yMask, - INT16 xDst, - INT16 yDst, CARD16 width, CARD16 height) + INT16 xSrc, INT16 ySrc, + INT16 xMask, INT16 yMask, + INT16 xDst, INT16 yDst, + CARD16 width, CARD16 height) { - uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen); + ScreenPtr screen = pDst->pDrawable->pScreen; + uxa_screen_t *uxa_screen = uxa_get_screen(screen); + PicturePtr localDst = pDst; + int xDst_copy, yDst_copy; assert(op == PictOpOver); if (uxa_screen->info->check_composite && (!(*uxa_screen->info->check_composite) (PictOpOutReverse, pSrc, - pMask, pDst) + pMask, pDst, width, height) || !(*uxa_screen->info->check_composite) (PictOpAdd, pSrc, pMask, - pDst))) { + pDst, width, height))) { return -1; } + if (uxa_screen->info->check_composite_target && + !uxa_screen->info->check_composite_target(uxa_get_drawable_pixmap(pDst->pDrawable))) { + int depth = pDst->pDrawable->depth; + PixmapPtr pixmap; + int error; + GCPtr gc; + + pixmap = uxa_get_drawable_pixmap(pDst->pDrawable); + if (uxa_screen->info->check_copy && + !uxa_screen->info->check_copy(pixmap, pixmap, GXcopy, FB_ALLONES)) + return -1; + + pixmap = screen->CreatePixmap(screen, + width, height, depth, + CREATE_PIXMAP_USAGE_SCRATCH); + if (!pixmap) + return 0; + + gc = GetScratchGC(depth, screen); + if (!gc) { + screen->DestroyPixmap(pixmap); + return 0; + } + + ValidateGC(&pixmap->drawable, gc); + gc->ops->CopyArea(pDst->pDrawable, &pixmap->drawable, gc, + xDst, yDst, width, height, 0, 0); + FreeScratchGC(gc); + + xDst_copy = xDst; xDst = 0; + yDst_copy = yDst; yDst = 0; + + localDst = CreatePicture(0, &pixmap->drawable, + PictureMatchFormat(screen, depth, pDst->format), + 0, 0, serverClient, &error); + screen->DestroyPixmap(pixmap); + + if (!localDst) + return 0; + + ValidatePicture(localDst); + } + /* Now, we think we should be able to accelerate this operation. First, * composite the destination to be the destination times the source alpha * factors. */ - uxa_composite(PictOpOutReverse, pSrc, pMask, pDst, xSrc, ySrc, xMask, - yMask, xDst, yDst, width, height); + uxa_composite(PictOpOutReverse, pSrc, pMask, localDst, + xSrc, ySrc, + xMask, yMask, + xDst, yDst, + width, height); /* Then, add in the source value times the destination alpha factors (1.0). */ - uxa_composite(PictOpAdd, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, - xDst, yDst, width, height); + uxa_composite(PictOpAdd, pSrc, pMask, localDst, + xSrc, ySrc, + xMask, yMask, + xDst, yDst, + width, height); + + if (localDst != pDst) { + GCPtr gc; + + gc = GetScratchGC(pDst->pDrawable->depth, screen); + if (gc) { + ValidateGC(pDst->pDrawable, gc); + gc->ops->CopyArea(localDst->pDrawable, pDst->pDrawable, gc, + 0, 0, width, height, xDst_copy, yDst_copy); + FreeScratchGC(gc); + } + + FreePicture(localDst, 0); + } return 1; } @@ -1325,10 +1480,10 @@ uxa_composite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst, - INT16 xSrc, - INT16 ySrc, - INT16 xMask, - INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height) + INT16 xSrc, INT16 ySrc, + INT16 xMask, INT16 yMask, + INT16 xDst, INT16 yDst, + CARD16 width, CARD16 height) { uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen); int ret = -1; @@ -1343,9 +1498,11 @@ uxa_composite(CARD8 op, if (!uxa_drawable_is_offscreen(pDst->pDrawable)) goto fallback; + if (pDst->alphaMap || pSrc->alphaMap || (pMask && pMask->alphaMap)) goto fallback; + /* Remove repeat in source if useless */ if (pSrc->pDrawable && pSrc->repeat && pSrc->filter != PictFilterConvolution && transform_is_integer_translation(pSrc->transform, &tx, &ty) && @@ -151,9 +151,7 @@ typedef struct _UxaDriver { /** * check_copy() checks whether the driver can blit between the two Pictures */ - Bool(*check_copy) (DrawablePtr pSrcDrawable, - DrawablePtr pDstDrawable, - int alu, Pixel planemask); + Bool(*check_copy) (PixmapPtr pSrc, PixmapPtr pDst, int alu, Pixel planemask); /** * prepare_copy() sets up the driver for doing a copy within video * memory. @@ -249,6 +247,8 @@ typedef struct _UxaDriver { * @param pSrcPicture source Picture * @param pMaskPicture mask picture * @param pDstPicture destination Picture + * @param width The width of the composite operation + * @param height The height of the composite operation * * The check_composite() call checks if the driver could handle * acceleration of op with the given source, mask, and destination @@ -266,7 +266,19 @@ typedef struct _UxaDriver { Bool(*check_composite) (int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture, - PicturePtr pDstPicture); + PicturePtr pDstPicture, + int width, int height); + + /** + * check_composite_target() checks to see if the destination of the composite + * operation can be used without midification. + * + * @param pixmap Destination Pixmap + * + * The check_composite_target() call is recommended if prepare_composite() is + * implemented, but is not required. + */ + Bool(*check_composite_target) (PixmapPtr pixmap); /** * check_composite_texture() checks to see if a source to the composite |