From e5c971e7639095d38da3518a5dc404b708d45cfb Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 18 May 2010 22:16:17 +0100 Subject: uxa: Spans! OMG! Use composite rather than solid blits in order to bring performance on a par with the CPU when using GEM and relocations. Signed-off-by: Chris Wilson --- uxa/uxa-accel.c | 181 ++++++++++++++++++++++++++++++++++++++++++++++++++----- uxa/uxa-priv.h | 11 ++++ uxa/uxa-render.c | 22 +++---- 3 files changed, 187 insertions(+), 27 deletions(-) (limited to 'uxa') diff --git a/uxa/uxa-accel.c b/uxa/uxa-accel.c index cfc2d381..0528d796 100644 --- a/uxa/uxa-accel.c +++ b/uxa/uxa-accel.c @@ -34,33 +34,181 @@ #include #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)) { + 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 diff --git a/uxa/uxa-priv.h b/uxa/uxa-priv.h index a4763b41..8ff2c9c6 100644 --- a/uxa/uxa-priv.h +++ b/uxa/uxa-priv.h @@ -434,6 +434,17 @@ 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); + +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..68e36515 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, @@ -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); @@ -974,17 +974,13 @@ uxa_solid_rects (CARD8 op, !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; -- cgit v1.2.3 From c2abf8d659b8b161a4f9df100b614ee3c8f8e458 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 19 May 2010 16:18:40 +0100 Subject: uxa: translate the region in line for composites When compositing, we need to convert the box into a rect and so the advantages of using REGION_TRANSLATE are lost. Signed-off-by: Chris Wilson --- uxa/uxa-render.c | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) (limited to 'uxa') diff --git a/uxa/uxa-render.c b/uxa/uxa-render.c index 68e36515..139d42e8 100644 --- a/uxa/uxa-render.c +++ b/uxa/uxa-render.c @@ -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); @@ -1090,21 +1090,19 @@ uxa_try_driver_composite_rects(CARD8 op, rects->width, rects->height)) goto next_rect; - REGION_TRANSLATE(pScreen, ®ion, dst_off_x, dst_off_y); + xSrc = xSrc + src_off_x - xDst; + ySrc = ySrc + src_off_y - yDst; 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->x1 + dst_off_x, + pbox->y1 + dst_off_y, pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); pbox++; @@ -1258,8 +1256,6 @@ 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); @@ -1272,25 +1268,24 @@ uxa_try_driver_composite(CARD8 op, 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++; -- cgit v1.2.3 From 91f560034fc2695680d1208a78fc56d814b0da79 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 20 May 2010 10:26:59 +0100 Subject: uxa: Composite glyphs directly onto dst when possible. Without using a mask and compositing directly onto the destination, takes us from 580 kglyphs/s to 850 kglyphs/s on i945 [x11perf -aa10text]. However, the extra intersection check almost entirely cancels out the speed up and we discover that the glyphs in x11perf are always overlapping. Nothing is ever easy. Signed-off-by: Chris Wilson --- uxa/uxa-glyphs.c | 348 ++++++++++++++++++++++++++++++++++++++++++++++++------- uxa/uxa-priv.h | 14 +++ uxa/uxa-render.c | 120 +------------------ 3 files changed, 324 insertions(+), 158 deletions(-) (limited to 'uxa') diff --git a/uxa/uxa-glyphs.c b/uxa/uxa-glyphs.c index f8bb7f54..921297a5 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)) { + return -1; + } - buffer->count = 0; - buffer->source = NULL; + 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); + + 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); + 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)) { + 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]; - buffer->count = 0; - buffer->source = NULL; + 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 */ @@ -857,9 +1112,10 @@ uxa_glyphs(CARD8 op, 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 pScreen = pDst->pDrawable->pScreen; int width = 0, height = 0; int x, y; int xDst = list->xOff, yDst = list->yOff; @@ -870,32 +1126,38 @@ uxa_glyphs(CARD8 op, CARD32 component_alpha; uxa_glyph_buffer_t buffer; - 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) { 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; } } @@ -942,11 +1204,14 @@ uxa_glyphs(CARD8 op, FreeScratchGC(pGC); x = -extents.x1; y = -extents.y1; + + ValidatePicture(pMask); } else { pMask = pDst; x = 0; y = 0; } + buffer.count = 0; buffer.source = NULL; while (nlist--) { @@ -966,6 +1231,9 @@ uxa_glyphs(CARD8 op, &buffer, xSrc, ySrc, xDst, yDst); + buffer.count = 0; + buffer.source = NULL; + uxa_buffer_glyph(pScreen, &buffer, glyph, x, y); } diff --git a/uxa/uxa-priv.h b/uxa/uxa-priv.h index 8ff2c9c6..bace6798 100644 --- a/uxa/uxa-priv.h +++ b/uxa/uxa-priv.h @@ -437,6 +437,20 @@ uxa_triangles(CARD8 op, PicturePtr pSrc, PicturePtr pDst, 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, diff --git a/uxa/uxa-render.c b/uxa/uxa-render.c index 139d42e8..c866b854 100644 --- a/uxa/uxa-render.c +++ b/uxa/uxa-render.c @@ -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, @@ -1043,122 +1043,6 @@ fallback: uxa_screen->SavedCompositeRects(op, dst, color, num_rects, rects); } -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; - - 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, - 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++; - } - (*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, -- cgit v1.2.3 From 80a9e64f50aeda6004e3aba1fbfdda50bb1f1c82 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 21 May 2010 09:55:55 +0100 Subject: 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 --- uxa/uxa-accel.c | 28 +++---- uxa/uxa-glyphs.c | 185 ++++++++++++++++++++++++++++++++----------- uxa/uxa-render.c | 233 ++++++++++++++++++++++++++++++++++++++++++++++--------- uxa/uxa.h | 20 ++++- 4 files changed, 364 insertions(+), 102 deletions(-) (limited to 'uxa') 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) && diff --git a/uxa/uxa.h b/uxa/uxa.h index bf7ec0b5..23f9465b 100644 --- a/uxa/uxa.h +++ b/uxa/uxa.h @@ -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 -- cgit v1.2.3