diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2010-05-21 11:01:30 +0100 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2010-05-24 18:31:45 +0100 |
commit | 9d8ac271404ff219c3d40ae8f829e8b76ac7c359 (patch) | |
tree | 34d5d5ba34da6dfb40255a3627e0b4387242c1a8 /uxa | |
parent | 509df27c7401e96d3062890da73f6af6629adef4 (diff) | |
parent | ea07535240dafc4c6ef55b4b7a2eeaa595febe86 (diff) |
Merge branch 'glyphs'
Tweak glyphs to improve x11perf on i915 by about 33%.
PineView, aa10text: 460 -> 617 kglyphs/s.
PineView, rgb10text: 434 -> 610 kglyphs/s.
Speedups
========
xcb poppler 18.636 -> 13.958: 1.34x speedup
xlib firefox-talos-gfx 71.905 -> 56.232: 1.28x speedup
xcb firefox-talos-gfx 72.882 -> 57.969: 1.26x speedup
xlib gnome-terminal-vim 38.126 -> 34.472: 1.11x speedup
xcb gnome-terminal-vim 35.164 -> 32.573: 1.08x speedup
xlib poppler 19.634 -> 18.246: 1.08x speedup
Note the lack of significant improvement for firefox-planet-gnome.
Diffstat (limited to 'uxa')
-rw-r--r-- | uxa/uxa-accel.c | 207 | ||||
-rw-r--r-- | uxa/uxa-glyphs.c | 529 | ||||
-rw-r--r-- | uxa/uxa-priv.h | 25 | ||||
-rw-r--r-- | uxa/uxa-render.c | 400 | ||||
-rw-r--r-- | uxa/uxa.h | 20 |
5 files changed, 882 insertions, 299 deletions
diff --git a/uxa/uxa-accel.c b/uxa/uxa-accel.c index cfc2d381..77963f39 100644 --- a/uxa/uxa-accel.c +++ b/uxa/uxa-accel.c @@ -34,33 +34,181 @@ #include <X11/fonts/fontstruct.h> #include "dixfontstr.h" #include "uxa.h" +#include "mipict.h" + +static CARD32 +format_for_depth(int depth) +{ + switch (depth) { + case 1: return PICT_a1; + case 8: return PICT_a8; + case 15: return PICT_x1r5g5b5; + case 16: return PICT_r5g6b5; + default: + case 24: return PICT_x8r8g8b8; + case 32: return PICT_a8r8g8b8; + } +} static void uxa_fill_spans(DrawablePtr pDrawable, GCPtr pGC, int n, DDXPointPtr ppt, int *pwidth, int fSorted) { - ScreenPtr pScreen = pDrawable->pScreen; - uxa_screen_t *uxa_screen = uxa_get_screen(pScreen); + ScreenPtr screen = pDrawable->pScreen; + uxa_screen_t *uxa_screen = uxa_get_screen(screen); RegionPtr pClip = fbGetCompositeClip(pGC); - PixmapPtr pPixmap = uxa_get_drawable_pixmap(pDrawable); + PixmapPtr dst_pixmap, src_pixmap = NULL; BoxPtr pextent, pbox; int nbox; int extentX1, extentX2, extentY1, extentY2; int fullX1, fullX2, fullY1; int partX1, partX2; int off_x, off_y; + xRenderColor color; + PictFormatPtr format; + PicturePtr dst, src; + int error; - if (uxa_screen->swappedOut || pGC->fillStyle != FillSolid || - !(pPixmap = uxa_get_offscreen_pixmap(pDrawable, &off_x, &off_y)) || - !(*uxa_screen->info->prepare_solid) (pPixmap, + if (uxa_screen->swappedOut) + goto fallback; + + if (pGC->fillStyle != FillSolid) + goto fallback; + + dst_pixmap = uxa_get_offscreen_pixmap(pDrawable, &off_x, &off_y); + if (!dst_pixmap) + goto fallback; + + if (pGC->alu != GXcopy || pGC->planemask != FB_ALLONES) + goto solid; + + format = PictureMatchFormat(screen, + dst_pixmap->drawable.depth, + format_for_depth(dst_pixmap->drawable.depth)); + dst = CreatePicture(0, &dst_pixmap->drawable, format, 0, 0, serverClient, &error); + if (!dst) + goto solid; + + ValidatePicture(dst); + + uxa_get_rgba_from_pixel(pGC->fgPixel, + &color.red, + &color.green, + &color.blue, + &color.alpha, + format_for_depth(dst_pixmap->drawable.depth)); + src = CreateSolidPicture(0, &color, &error); + if (!src) { + FreePicture(dst, 0); + goto solid; + } + + if (!uxa_screen->info->check_composite(PictOpSrc, src, NULL, dst, 0, 0)) { + FreePicture(src, 0); + FreePicture(dst, 0); + goto solid; + } + + if (!uxa_screen->info->check_composite_texture || + !uxa_screen->info->check_composite_texture(screen, src)) { + PicturePtr solid; + int src_off_x, src_off_y; + + solid = uxa_acquire_solid(screen, src->pSourcePict); + FreePicture(src, 0); + + src = solid; + src_pixmap = uxa_get_offscreen_pixmap(src->pDrawable, + &src_off_x, &src_off_y); + if (!src_pixmap) { + FreePicture(src, 0); + FreePicture(dst, 0); + goto solid; + } + } + + if (!uxa_screen->info->prepare_composite(PictOpSrc, src, NULL, dst, src_pixmap, NULL, dst_pixmap)) { + FreePicture(src, 0); + FreePicture(dst, 0); + goto solid; + } + + pextent = REGION_EXTENTS(pGC->screen, pClip); + extentX1 = pextent->x1; + extentY1 = pextent->y1; + extentX2 = pextent->x2; + extentY2 = pextent->y2; + while (n--) { + fullX1 = ppt->x; + fullY1 = ppt->y; + fullX2 = fullX1 + (int)*pwidth; + ppt++; + pwidth++; + + if (fullY1 < extentY1 || extentY2 <= fullY1) + continue; + + if (fullX1 < extentX1) + fullX1 = extentX1; + + if (fullX2 > extentX2) + fullX2 = extentX2; + + if (fullX1 >= fullX2) + continue; + + nbox = REGION_NUM_RECTS(pClip); + if (nbox == 1) { + uxa_screen->info->composite(dst_pixmap, + 0, 0, 0, 0, + fullX1 + off_x, + fullY1 + off_y, + fullX2 - fullX1, 1); + } else { + pbox = REGION_RECTS(pClip); + while (nbox--) { + if (pbox->y2 >= fullY1) + break; + + if (pbox->y1 <= fullY1) { + partX1 = pbox->x1; + if (partX1 < fullX1) + partX1 = fullX1; + + partX2 = pbox->x2; + if (partX2 > fullX2) + partX2 = fullX2; + + if (partX2 > partX1) { + uxa_screen->info->composite(dst_pixmap, + 0, 0, 0, 0, + partX1 + off_x, + fullY1 + off_y, + partX2 - partX1, 1); + } + } + pbox++; + } + } + } + + uxa_screen->info->done_composite(dst_pixmap); + FreePicture(src, 0); + FreePicture(dst, 0); + return; + +solid: + if (uxa_screen->info->check_solid && + !uxa_screen->info->check_solid(pDrawable, pGC->alu, pGC->planemask)) + goto fallback; + + if (!(*uxa_screen->info->prepare_solid) (dst_pixmap, pGC->alu, pGC->planemask, - pGC->fgPixel)) { - uxa_check_fill_spans(pDrawable, pGC, n, ppt, pwidth, fSorted); - return; - } + pGC->fgPixel)) + goto fallback; - pextent = REGION_EXTENTS(pGC->pScreen, pClip); + pextent = REGION_EXTENTS(pGC->screen, pClip); extentX1 = pextent->x1; extentY1 = pextent->y1; extentX2 = pextent->x2; @@ -86,7 +234,7 @@ uxa_fill_spans(DrawablePtr pDrawable, GCPtr pGC, int n, nbox = REGION_NUM_RECTS(pClip); if (nbox == 1) { - (*uxa_screen->info->solid) (pPixmap, + (*uxa_screen->info->solid) (dst_pixmap, fullX1 + off_x, fullY1 + off_y, fullX2 + off_x, @@ -103,7 +251,7 @@ uxa_fill_spans(DrawablePtr pDrawable, GCPtr pGC, int n, partX2 = fullX2; if (partX2 > partX1) { (*uxa_screen->info-> - solid) (pPixmap, + solid) (dst_pixmap, partX1 + off_x, fullY1 + off_y, partX2 + off_x, @@ -114,7 +262,12 @@ uxa_fill_spans(DrawablePtr pDrawable, GCPtr pGC, int n, } } } - (*uxa_screen->info->done_solid) (pPixmap); + (*uxa_screen->info->done_solid) (dst_pixmap); + + return; + +fallback: + uxa_check_fill_spans(pDrawable, pGC, n, ppt, pwidth, fSorted); } static Bool @@ -433,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, @@ -968,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 f8bb7f54..93a738ed 100644 --- a/uxa/uxa-glyphs.c +++ b/uxa/uxa-glyphs.c @@ -205,6 +205,8 @@ static Bool uxa_realize_glyph_caches(ScreenPtr pScreen, unsigned int format) if (!pPicture) return FALSE; + ValidatePicture(pPicture); + /* And store the picture in all the caches for the format */ for (i = 0; i < UXA_NUM_GLYPH_CACHES; i++) { @@ -573,41 +575,294 @@ uxa_buffer_glyph(ScreenPtr pScreen, return UXA_GLYPH_SUCCESS; } -static void uxa_glyphs_to_mask(PicturePtr pMask, uxa_glyph_buffer_t * buffer) +static PicturePtr +uxa_glyphs_acquire_source(ScreenPtr screen, + PicturePtr src, + INT16 x, INT16 y, + const uxa_glyph_buffer_t * buffer, + INT16 * out_x, INT16 * out_y) +{ + uxa_screen_t *uxa_screen = uxa_get_screen(screen); + int x1, y1, x2, y2; + int width, height; + int i; + + if (uxa_screen->info->check_composite_texture && + uxa_screen->info->check_composite_texture(screen, src)) { + if (src->pDrawable) { + *out_x = x + src->pDrawable->x; + *out_y = y + src->pDrawable->y; + } else { + *out_x = x; + *out_y = y; + } + return src; + } + + for (i = 0; i < buffer->count; i++) { + const uxa_composite_rect_t *r = &buffer->rects[i]; + + if (r->xDst < x1) + x1 = r->xDst; + if (r->xDst + r->width > x2) + x2 = r->xDst + r->width; + + if (r->yDst < y1) + y1 = r->yDst; + if (r->yDst + r->height > y2) + y2 = r->yDst + r->height; + } + + width = x2 - x1; + height = y2 - y1; + + if (src->pDrawable) { + PicturePtr dst; + + dst = uxa_acquire_drawable(screen, src, + x, y, + width, height, + out_x, out_y); + if (uxa_screen->info->check_composite_texture && + !uxa_screen->info->check_composite_texture(screen, dst)) { + if (dst != src) + FreePicture(dst, 0); + return 0; + } + + return dst; + } + + *out_x = 0; + *out_y = 0; + return uxa_acquire_pattern(screen, src, + PICT_a8r8g8b8, x, y, width, height); +} + +static int +uxa_glyphs_try_driver_composite(CARD8 op, + PicturePtr pSrc, + PicturePtr pDst, + const uxa_glyph_buffer_t * buffer, + INT16 xSrc, INT16 ySrc, + INT16 xDst, INT16 yDst) { - uxa_composite_rects(PictOpAdd, buffer->source, pMask, - buffer->count, buffer->rects); + ScreenPtr screen = pDst->pDrawable->pScreen; + uxa_screen_t *uxa_screen = uxa_get_screen(screen); + PicturePtr localSrc; + int src_off_x = 0, src_off_y = 0, mask_off_x, mask_off_y, dst_off_x, dst_off_y; + PixmapPtr pSrcPix = NULL, pMaskPix, pDstPix; + const uxa_composite_rect_t *rects; + int nrect; + + if (uxa_screen->info->check_composite && + !(*uxa_screen->info->check_composite) (op, pSrc, buffer->source, pDst, 0, 0)) { + return -1; + } + + pDstPix = + uxa_get_offscreen_pixmap(pDst->pDrawable, &dst_off_x, &dst_off_y); + + pMaskPix = + uxa_get_offscreen_pixmap(buffer->source->pDrawable, &mask_off_x, &mask_off_y); + if(!pMaskPix) + return -1; + + localSrc = uxa_glyphs_acquire_source(screen, pSrc, + xSrc, ySrc, + buffer, + &xSrc, &ySrc); + if (!localSrc) + return 0; + + if (localSrc->pDrawable) { + pSrcPix = + uxa_get_offscreen_pixmap(localSrc->pDrawable, &src_off_x, &src_off_y); + if (!pSrcPix) { + if (localSrc != pSrc) + FreePicture(localSrc, 0); + return 0; + } + + xSrc += localSrc->pDrawable->x; + ySrc += localSrc->pDrawable->y; + } + + if (!(*uxa_screen->info->prepare_composite) + (op, localSrc, buffer->source, pDst, pSrcPix, pMaskPix, pDstPix)) { + if (localSrc != pSrc) + FreePicture(localSrc, 0); + return -1; + } + + nrect = buffer->count; + rects = buffer->rects; + do { + INT16 _xDst = rects->xDst + pDst->pDrawable->x; + INT16 _yDst = rects->yDst + pDst->pDrawable->y; + INT16 _xMask = rects->xSrc + buffer->source->pDrawable->x; + INT16 _yMask = rects->ySrc + buffer->source->pDrawable->y; + INT16 _xSrc = xSrc, _ySrc = ySrc; + + RegionRec region; + BoxPtr pbox; + int nbox; + + if (!miComputeCompositeRegion(®ion, + localSrc, buffer->source, pDst, + _xSrc, _ySrc, + _xMask, _yMask, + _xDst, _yDst, + rects->width, rects->height)) + goto next_rect; + + _xSrc += src_off_x - _xDst; + _ySrc += src_off_y - _yDst; + _xMask += mask_off_x - _xDst; + _yMask += mask_off_y - _yDst; + + nbox = REGION_NUM_RECTS(®ion); + pbox = REGION_RECTS(®ion); + while (nbox--) { + (*uxa_screen->info->composite) (pDstPix, + pbox->x1 + _xSrc, + pbox->y1 + _ySrc, + pbox->x1 + _xMask, + pbox->y1 + _yMask, + pbox->x1 + dst_off_x, + pbox->y1 + dst_off_y, + pbox->x2 - pbox->x1, + pbox->y2 - pbox->y1); + pbox++; + } + +next_rect: + REGION_UNINIT(screen, ®ion); - buffer->count = 0; - buffer->source = NULL; + rects++; + } while (--nrect); + (*uxa_screen->info->done_composite) (pDstPix); + + if (localSrc != pSrc) + FreePicture(localSrc, 0); + + return 1; } static void uxa_glyphs_to_dst(CARD8 op, PicturePtr pSrc, PicturePtr pDst, - uxa_glyph_buffer_t * buffer, - INT16 xSrc, INT16 ySrc, INT16 xDst, INT16 yDst) + const uxa_glyph_buffer_t * buffer, + INT16 xSrc, INT16 ySrc, + INT16 xDst, INT16 yDst) { - int i; + if (uxa_glyphs_try_driver_composite(op, pSrc, pDst, buffer, + xSrc, ySrc, + xDst, yDst) != 1) { + int i; - for (i = 0; i < buffer->count; i++) { - uxa_composite_rect_t *rect = &buffer->rects[i]; + for (i = 0; i < buffer->count; i++) { + const uxa_composite_rect_t *rect = &buffer->rects[i]; - CompositePicture(op, - pSrc, - buffer->source, - pDst, - xSrc + rect->xDst - xDst, - ySrc + rect->yDst - yDst, - rect->xSrc, - rect->ySrc, - rect->xDst, - rect->yDst, rect->width, rect->height); - } - - buffer->count = 0; - buffer->source = NULL; + CompositePicture(op, + pSrc, buffer->source, pDst, + xSrc + rect->xDst - xDst, + ySrc + rect->yDst - yDst, + rect->xSrc, rect->ySrc, + rect->xDst, rect->yDst, + rect->width, rect->height); + } + } +} + +static int +uxa_glyphs_try_driver_add_to_mask(PicturePtr pDst, + const uxa_glyph_buffer_t *buffer) +{ + uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen); + int src_off_x, src_off_y, dst_off_x, dst_off_y; + PixmapPtr pSrcPix, pDstPix; + const uxa_composite_rect_t *rects; + int nrect; + + if (uxa_screen->info->check_composite && + !(*uxa_screen->info->check_composite) (PictOpAdd, buffer->source, NULL, pDst, 0, 0)) { + return -1; + } + + pDstPix = + uxa_get_offscreen_pixmap(pDst->pDrawable, &dst_off_x, &dst_off_y); + + pSrcPix = + uxa_get_offscreen_pixmap(buffer->source->pDrawable, &src_off_x, &src_off_y); + if(!pSrcPix) + return -1; + + if (!(*uxa_screen->info->prepare_composite) + (PictOpAdd, buffer->source, NULL, pDst, pSrcPix, NULL, pDstPix)) + return -1; + + rects = buffer->rects; + nrect = buffer->count; + do { + INT16 xDst = rects->xDst + pDst->pDrawable->x; + INT16 yDst = rects->yDst + pDst->pDrawable->y; + INT16 xSrc = rects->xSrc + buffer->source->pDrawable->x; + INT16 ySrc = rects->ySrc + buffer->source->pDrawable->y; + + RegionRec region; + BoxPtr pbox; + int nbox; + + if (!miComputeCompositeRegion(®ion, buffer->source, NULL, pDst, + xSrc, ySrc, 0, 0, xDst, yDst, + rects->width, rects->height)) + goto next_rect; + + xSrc += src_off_x - xDst; + ySrc += src_off_y - yDst; + + nbox = REGION_NUM_RECTS(®ion); + pbox = REGION_RECTS(®ion); + + while (nbox--) { + (*uxa_screen->info->composite) (pDstPix, + pbox->x1 + xSrc, + pbox->y1 + ySrc, + 0, 0, + pbox->x1 + dst_off_x, + pbox->y1 + dst_off_y, + pbox->x2 - pbox->x1, + pbox->y2 - pbox->y1); + pbox++; + } + +next_rect: + REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); + + rects++; + } while (--nrect); + (*uxa_screen->info->done_composite) (pDstPix); + + return 1; +} + +static void uxa_glyphs_to_mask(PicturePtr pDst, const uxa_glyph_buffer_t *buffer) +{ + if (uxa_glyphs_try_driver_add_to_mask(pDst, buffer) != 1) { + int i; + + for (i = 0; i < buffer->count; i++) { + const uxa_composite_rect_t *r = &buffer->rects[i]; + + uxa_check_composite(PictOpAdd, buffer->source, NULL, pDst, + r->xSrc, r->ySrc, + 0, 0, + r->xDst, r->yDst, + r->width, r->height); + } + } } /* Cut and paste from render/glyph.c - probably should export it instead */ @@ -854,12 +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) { - PixmapPtr pMaskPixmap = 0; - PicturePtr pMask; - ScreenPtr pScreen = pDst->pDrawable->pScreen; + 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; @@ -867,86 +1122,172 @@ 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_drawable_is_offscreen(pDst->pDrawable)) { + 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; } - /* If we don't have a mask format but all the glyphs have the same format - * and don't intersect, use the glyph format as mask format for the full - * benefits of the glyph cache. - */ + ValidatePicture(pSrc); + ValidatePicture(pDst); + if (!maskFormat) { - Bool sameFormat = TRUE; - int i; + /* If we don't have a mask format but all the glyphs have the same format, + * require ComponentAlpha and don't intersect, use the glyph format as mask + * format for the full benefits of the glyph cache. + */ + if (NeedsComponent(list[0].format->format)) { + Bool sameFormat = TRUE; + int i; - maskFormat = list[0].format; + maskFormat = list[0].format; - for (i = 0; i < nlist; i++) { - if (maskFormat->format != list[i].format->format) { - sameFormat = FALSE; - break; + for (i = 0; i < nlist; i++) { + if (maskFormat->format != list[i].format->format) { + sameFormat = FALSE; + break; + } } - } - if (!sameFormat || (maskFormat->depth != 1 && - uxa_glyphs_intersect(nlist, list, - glyphs))) { - maskFormat = NULL; + if (!sameFormat || + uxa_glyphs_intersect(nlist, list, glyphs)) + maskFormat = NULL; } } - 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; - } else { - pMask = pDst; - x = 0; - y = 0; + + ValidatePicture(pMask); } + buffer.count = 0; buffer.source = NULL; while (nlist--) { @@ -957,16 +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); - uxa_buffer_glyph(pScreen, &buffer, glyph, x, y); + buffer.count = 0; + buffer.source = NULL; + + uxa_buffer_glyph(screen, &buffer, glyph, x, y); } x += glyph->info.xOff; @@ -979,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-priv.h b/uxa/uxa-priv.h index a4763b41..bace6798 100644 --- a/uxa/uxa-priv.h +++ b/uxa/uxa-priv.h @@ -434,6 +434,31 @@ uxa_triangles(CARD8 op, PicturePtr pSrc, PicturePtr pDst, PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, int ntri, xTriangle * tris); +PicturePtr +uxa_acquire_solid(ScreenPtr screen, SourcePict *source); + +PicturePtr +uxa_acquire_drawable(ScreenPtr pScreen, + PicturePtr pSrc, + INT16 x, INT16 y, + CARD16 width, CARD16 height, + INT16 * out_x, INT16 * out_y); + +PicturePtr +uxa_acquire_pattern(ScreenPtr pScreen, + PicturePtr pSrc, + pixman_format_code_t format, + INT16 x, INT16 y, + CARD16 width, CARD16 height); + +Bool +uxa_get_rgba_from_pixel(CARD32 pixel, + CARD16 * red, + CARD16 * green, + CARD16 * blue, + CARD16 * alpha, + CARD32 format); + /* uxa_glyph.c */ void uxa_glyphs_init(ScreenPtr pScreen); diff --git a/uxa/uxa-render.c b/uxa/uxa-render.c index 726079a5..ec59871b 100644 --- a/uxa/uxa-render.c +++ b/uxa/uxa-render.c @@ -251,7 +251,7 @@ uxa_get_pixel_from_rgba(CARD32 * pixel, return TRUE; } -static Bool +Bool uxa_get_rgba_from_pixel(CARD32 pixel, CARD16 * red, CARD16 * green, @@ -391,8 +391,6 @@ uxa_try_driver_solid_fill(PicturePtr pSrc, width, height)) return 1; - REGION_TRANSLATE(pScreen, ®ion, dst_off_x, dst_off_y); - if (pSrcPix) { if (! uxa_get_color_for_pixmap (pSrcPix, pSrc->format, pDst->format, &pixel)) { REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); @@ -432,6 +430,8 @@ uxa_try_driver_solid_fill(PicturePtr pSrc, return -1; } + REGION_TRANSLATE(pScreen, ®ion, dst_off_x, dst_off_y); + nbox = REGION_NUM_RECTS(®ion); pbox = REGION_RECTS(®ion); @@ -607,7 +607,7 @@ uxa_solid_clear(ScreenPtr screen) return picture; } -static PicturePtr +PicturePtr uxa_acquire_solid(ScreenPtr screen, SourcePict *source) { uxa_screen_t *uxa_screen = uxa_get_screen(screen); @@ -664,7 +664,7 @@ DONE: return picture; } -static PicturePtr +PicturePtr uxa_acquire_pattern(ScreenPtr pScreen, PicturePtr pSrc, pixman_format_code_t format, @@ -757,7 +757,7 @@ uxa_render_picture(ScreenPtr screen, return picture; } -static PicturePtr +PicturePtr uxa_acquire_drawable(ScreenPtr pScreen, PicturePtr pSrc, INT16 x, INT16 y, @@ -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,28 +973,28 @@ 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; - if (op == PictOpClear) { - pixel = 0; - } else { - if (!uxa_get_pixel_from_rgba(&pixel, - color->red, - color->green, - color->blue, - color->alpha, - dst->format)) - goto err_region; - } + if (!uxa_get_pixel_from_rgba(&pixel, + color->red, + color->green, + color->blue, + color->alpha, + dst->format)) + goto err_region; 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 { @@ -1001,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)) { @@ -1048,124 +1059,6 @@ fallback: } static int -uxa_try_driver_composite_rects(CARD8 op, - PicturePtr pSrc, - PicturePtr pDst, - int nrect, uxa_composite_rect_t * rects) -{ - uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen); - int src_off_x, src_off_y, dst_off_x, dst_off_y; - PixmapPtr pSrcPix, pDstPix; - - if (!uxa_screen->info->prepare_composite || uxa_screen->swappedOut) - return -1; - - if (uxa_screen->info->check_composite && - !(*uxa_screen->info->check_composite) (op, pSrc, NULL, pDst)) { - return -1; - } - - pDstPix = - uxa_get_offscreen_pixmap(pDst->pDrawable, &dst_off_x, &dst_off_y); - if (!pDstPix) - return 0; - - pSrcPix = - uxa_get_offscreen_pixmap(pSrc->pDrawable, &src_off_x, &src_off_y); - if (!pSrcPix) - return 0; - - if (!(*uxa_screen->info->prepare_composite) - (op, pSrc, NULL, pDst, pSrcPix, NULL, pDstPix)) - return -1; - - while (nrect--) { - INT16 xDst = rects->xDst + pDst->pDrawable->x; - INT16 yDst = rects->yDst + pDst->pDrawable->y; - INT16 xSrc = rects->xSrc + pSrc->pDrawable->x; - INT16 ySrc = rects->ySrc + pSrc->pDrawable->y; - - RegionRec region; - BoxPtr pbox; - int nbox; - - if (!miComputeCompositeRegion(®ion, pSrc, NULL, pDst, - xSrc, ySrc, 0, 0, xDst, yDst, - rects->width, rects->height)) - goto next_rect; - - REGION_TRANSLATE(pScreen, ®ion, dst_off_x, dst_off_y); - - nbox = REGION_NUM_RECTS(®ion); - pbox = REGION_RECTS(®ion); - - xSrc = xSrc + src_off_x - xDst - dst_off_x; - ySrc = ySrc + src_off_y - yDst - dst_off_y; - - while (nbox--) { - (*uxa_screen->info->composite) (pDstPix, - pbox->x1 + xSrc, - pbox->y1 + ySrc, - 0, 0, - pbox->x1, - pbox->y1, - pbox->x2 - pbox->x1, - pbox->y2 - pbox->y1); - pbox++; - } - -next_rect: - REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); - - rects++; - } - (*uxa_screen->info->done_composite) (pDstPix); - - return 1; -} - -/** - * Copy a number of rectangles from source to destination in a single - * operation. This is specialized for building a glyph mask: we don'y - * have a mask argument because we don't need it for that, and we - * don't have he special-case fallbacks found in uxa_composite() - if the - * driver can support it, we use the driver functionality, otherwise we - * fallback straight to software. - */ -void -uxa_composite_rects(CARD8 op, - PicturePtr pSrc, - PicturePtr pDst, int nrect, uxa_composite_rect_t * rects) -{ - int n; - uxa_composite_rect_t *r; - - /************************************************************/ - - ValidatePicture(pSrc); - ValidatePicture(pDst); - - if (uxa_try_driver_composite_rects(op, pSrc, pDst, nrect, rects) != 1) { - uxa_print_composite_fallback("uxa_composite_rects", - op, pSrc, NULL, pDst); - - n = nrect; - r = rects; - while (n--) { - uxa_check_composite(op, pSrc, NULL, pDst, - r->xSrc, r->ySrc, - 0, 0, - r->xDst, r->yDst, - r->width, r->height); - r++; - } - } - - /************************************************************/ - -} - -static int uxa_try_driver_composite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, @@ -1175,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; } @@ -1230,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; } @@ -1248,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; } @@ -1262,52 +1215,65 @@ uxa_try_driver_composite(CARD8 op, } } - REGION_TRANSLATE(pScreen, ®ion, dst_off_x, dst_off_y); - 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; } - nbox = REGION_NUM_RECTS(®ion); - pbox = REGION_RECTS(®ion); - if (pMask) { - xMask = xMask + mask_off_x - xDst - dst_off_x; - yMask = yMask + mask_off_y - yDst - dst_off_y; + xMask = xMask + mask_off_x - xDst; + yMask = yMask + mask_off_y - yDst; } - xSrc = xSrc + src_off_x - xDst - dst_off_x; - ySrc = ySrc + src_off_y - yDst - dst_off_y; + xSrc = xSrc + src_off_x - xDst; + ySrc = ySrc + src_off_y - yDst; + nbox = REGION_NUM_RECTS(®ion); + pbox = REGION_RECTS(®ion); while (nbox--) { (*uxa_screen->info->composite) (pDstPix, pbox->x1 + xSrc, pbox->y1 + ySrc, pbox->x1 + xMask, pbox->y1 + yMask, - pbox->x1, - pbox->y1, + pbox->x1 + dst_off_x, + pbox->y1 + dst_off_y, pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); pbox++; } (*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; } @@ -1365,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; } @@ -1450,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; @@ -1468,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 |