diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2009-09-04 17:10:25 +0100 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2009-09-14 16:26:57 +0100 |
commit | c2abfa8e54acab61250dba1e435760e3b1499c8c (patch) | |
tree | 8662346d018c5a3f7466d5a9ca9f103a28d4d836 /uxa/uxa-render.c | |
parent | efbcf29dd1a1ca058b7a2a93f0685102c06c9369 (diff) |
Avoid fallbacks for compositing gradient patterns
Currently when asked to composite using a gradient source or mask, we
fallback to using fbComposite(). This has the side-effect of causing a
readback on the destination surface, stalling the GPU pipeline. Instead,
like uxa_trapezoids(), we can use pixman to fill a scratch pixmap and then
copy that to an offscreen pixmap for use with uxa_composite().
Speedups on i915:
firefox-talos-svg: 710378.14 -> 549262.96: 1.29x speedup
No slowdowns.
Thanks to Søeren Sandmann Pedersen for spotting the missing
ValidatePicture().
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Diffstat (limited to 'uxa/uxa-render.c')
-rw-r--r-- | uxa/uxa-render.c | 274 |
1 files changed, 207 insertions, 67 deletions
diff --git a/uxa/uxa-render.c b/uxa/uxa-render.c index 13128ed7..e071fc40 100644 --- a/uxa/uxa-render.c +++ b/uxa/uxa-render.c @@ -29,6 +29,7 @@ #include <stdlib.h> #include "uxa-priv.h" +#include <xorgVersion.h> #ifdef RENDER #include "mipict.h" @@ -314,6 +315,137 @@ uxa_try_driver_solid_fill(PicturePtr pSrc, return 1; } +static PicturePtr +uxa_picture_from_pixman_image (ScreenPtr pScreen, + pixman_image_t *image, + pixman_format_code_t format) +{ + PicturePtr pPicture; + PixmapPtr pPixmap; + GCPtr pGC; + int width, height, depth; + int error; + + width = pixman_image_get_width (image); + height = pixman_image_get_height (image); + depth = pixman_image_get_depth (image); + + pPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, depth, + UXA_CREATE_PIXMAP_FOR_MAP); + if (!pPixmap) + return 0; + + pPicture = CreatePicture (0, &pPixmap->drawable, + PictureMatchFormat (pScreen, depth, format), + 0, 0, serverClient, &error); + (*pScreen->DestroyPixmap) (pPixmap); + ValidatePicture (pPicture); + + pPixmap = GetScratchPixmapHeader(pScreen, width, height, depth, + BitsPerPixel (depth), + pixman_image_get_stride (image), + pixman_image_get_data (image)); + if (!pPixmap) + { + FreePicture (pPicture, 0); + return 0; + } + + pGC = GetScratchGC (depth, pScreen); + if (!pGC) + { + FreeScratchPixmapHeader (pPixmap); + FreePicture (pPicture, 0); + return 0; + } + ValidateGC (pPicture->pDrawable, pGC); + + (*pGC->ops->CopyArea) (&pPixmap->drawable, pPicture->pDrawable, + pGC, 0, 0, width, height, 0, 0); + + FreeScratchGC (pGC); + FreeScratchPixmapHeader (pPixmap); + + return pPicture; +} + +#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC (1,6,99,1,0) +#define IMAGE_FROM_PICT(P) image_from_pict(P, 0) +#else +#define IMAGE_FROM_PICT(P) image_from_pict(P, 0, 0) +#endif + +static PicturePtr +uxa_acquire_pattern (ScreenPtr pScreen, + PicturePtr pPict, + pixman_format_code_t format, + INT16 x, INT16 y, + CARD16 width, CARD16 height) +{ + pixman_image_t *source, *image; + + source = IMAGE_FROM_PICT (pPict); + if (!source) + return 0; + + image = pixman_image_create_bits (format, width, height, NULL, 0); + if (!image) { + pixman_image_unref (source); + return 0; + } + + pixman_image_composite (PIXMAN_OP_SRC, + source, NULL, image, + x, y, + 0, 0, + 0, 0, + width, height); + pixman_image_unref (source); + + pPict = uxa_picture_from_pixman_image (pScreen, image, format); + pixman_image_unref (image); + + return pPict; +} + +static PicturePtr +uxa_acquire_source (ScreenPtr pScreen, + PicturePtr pPict, + INT16 x, INT16 y, + CARD16 width, CARD16 height, + INT16 *out_x, INT16 *out_y) +{ + if (pPict->pDrawable) { + *out_x = x + pPict->pDrawable->x; + *out_y = y + pPict->pDrawable->y; + return pPict; + } + + *out_x = 0; + *out_y = 0; + return uxa_acquire_pattern (pScreen, pPict, + PICT_a8r8g8b8, x, y, width, height); +} + +static PicturePtr +uxa_acquire_mask (ScreenPtr pScreen, + PicturePtr pPict, + INT16 x, INT16 y, + INT16 width, INT16 height, + INT16 *out_x, INT16 *out_y) +{ + if (pPict->pDrawable) { + *out_x = x + pPict->pDrawable->x; + *out_y = y + pPict->pDrawable->y; + return pPict; + } + + *out_x = 0; + *out_y = 0; + return uxa_acquire_pattern (pScreen, pPict, + PICT_a8, x, y, width, height); +} + static int uxa_try_driver_composite_rects(CARD8 op, PicturePtr pSrc, @@ -333,7 +465,7 @@ uxa_try_driver_composite_rects(CARD8 op, { return -1; } - + pDstPix = uxa_get_offscreen_pixmap(pDst->pDrawable, &dst_off_x, &dst_off_y); if (!pDstPix) return 0; @@ -453,48 +585,84 @@ uxa_try_driver_composite(CARD8 op, int nbox; 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; xDst += pDst->pDrawable->x; yDst += pDst->pDrawable->y; + localSrc = uxa_acquire_source (pDst->pDrawable->pScreen, + pSrc, xSrc, ySrc, width, height, + &xSrc, &ySrc); + if (! localSrc) + return 0; + if (pMask) { - xMask += pMask->pDrawable->x; - yMask += pMask->pDrawable->y; - } + localMask = uxa_acquire_mask (pDst->pDrawable->pScreen, + pMask, xMask, yMask, width, height, + &xMask, &yMask); + if (! localMask) { + if (localSrc != pSrc) + FreePicture (localSrc, 0); - xSrc += pSrc->pDrawable->x; - ySrc += pSrc->pDrawable->y; + return 0; + } + } if (uxa_screen->info->check_composite && - !(*uxa_screen->info->check_composite) (op, pSrc, pMask, pDst)) + !(*uxa_screen->info->check_composite) (op, localSrc, localMask, pDst)) { + if (localSrc != pSrc) + FreePicture (localSrc, 0); + if (localMask && localMask != pMask) + FreePicture (localMask, 0); + return -1; } - if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst, + if (!miComputeCompositeRegion (®ion, localSrc, localMask, pDst, xSrc, ySrc, xMask, yMask, xDst, yDst, width, height)) + { + if (localSrc != pSrc) + FreePicture (localSrc, 0); + if (localMask && localMask != pMask) + FreePicture (localMask, 0); + return 1; + } pDstPix = uxa_get_offscreen_pixmap (pDst->pDrawable, &dst_off_x, &dst_off_y); - pSrcPix = uxa_get_offscreen_pixmap (pSrc->pDrawable, &src_off_x, &src_off_y); + pSrcPix = uxa_get_offscreen_pixmap (localSrc->pDrawable, + &src_off_x, &src_off_y); - if (pMask) - pMaskPix = uxa_get_offscreen_pixmap (pMask->pDrawable, &mask_off_x, - &mask_off_y); + if (localMask) + pMaskPix = uxa_get_offscreen_pixmap (localMask->pDrawable, + &mask_off_x, &mask_off_y); - if (!pDstPix || !pSrcPix || (pMask && !pMaskPix)) { + if (!pDstPix || !pSrcPix || (localMask && !pMaskPix)) { REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); + + if (localSrc != pSrc) + FreePicture (localSrc, 0); + if (localMask && localMask != pMask) + FreePicture (localMask, 0); + return 0; } REGION_TRANSLATE(pScreen, ®ion, dst_off_x, dst_off_y); - if (!(*uxa_screen->info->prepare_composite) (op, pSrc, pMask, pDst, pSrcPix, - pMaskPix, pDstPix)) + if (!(*uxa_screen->info->prepare_composite) (op, localSrc, localMask, pDst, + pSrcPix, pMaskPix, pDstPix)) { REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); + + if (localSrc != pSrc) + FreePicture (localSrc, 0); + if (localMask && localMask != pMask) + FreePicture (localMask, 0); + return -1; } @@ -523,6 +691,12 @@ uxa_try_driver_composite(CARD8 op, (*uxa_screen->info->done_composite) (pDstPix); REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); + + if (localSrc != pSrc) + FreePicture (localSrc, 0); + if (localMask && localMask != pMask) + FreePicture (localMask, 0); + return 1; } @@ -636,14 +810,11 @@ uxa_composite(CARD8 op, Bool saveMaskRepeat = pMask ? pMask->repeat : 0; RegionRec region; - /* We currently don't support acceleration of gradients, or other pictures - * with a NULL pDrawable. - */ - if (uxa_screen->swappedOut || - pSrc->pDrawable == NULL || (pMask != NULL && pMask->pDrawable == NULL)) - { + if (uxa_screen->swappedOut) goto fallback; - } + + if (pSrc->pDrawable == NULL || (pMask && pMask->pDrawable == NULL)) + goto composite; /* Remove repeat in source if useless */ if (pSrc->repeat && !pSrc->transform && xSrc >= 0 && @@ -738,10 +909,11 @@ uxa_composite(CARD8 op, } } +composite: /* Remove repeat in mask if useless */ - if (pMask && pMask->repeat && !pMask->transform && xMask >= 0 && - (xMask + width) <= pMask->pDrawable->width && yMask >= 0 && - (yMask + height) <= pMask->pDrawable->height) + if (pMask && pMask->repeat && !pMask->transform && pMask->pDrawable && + xMask >= 0 && (xMask + width) <= pMask->pDrawable->width && + yMask >= 0 && (yMask + height) <= pMask->pDrawable->height) pMask->repeat = 0; if (uxa_screen->info->prepare_composite && @@ -757,7 +929,8 @@ uxa_composite(CARD8 op, /* For generic masks and solid src pictures, mach64 can do Over in two * passes, similar to the component-alpha case. */ - isSrcSolid = pSrc->pDrawable->width == 1 && + isSrcSolid = pSrc->pDrawable && + pSrc->pDrawable->width == 1 && pSrc->pDrawable->height == 1 && pSrc->repeat; @@ -888,62 +1061,29 @@ uxa_trapezoids (CARD8 op, PicturePtr pSrc, PicturePtr pDst, PicturePtr pPicture; INT16 xDst, yDst; INT16 xRel, yRel; - int width, height, stride; - PixmapPtr pPixmap; - GCPtr pGC; + int width, height; pixman_image_t *image; + pixman_format_code_t format; xDst = traps[0].left.p1.x >> 16; yDst = traps[0].left.p1.y >> 16; width = bounds.x2 - bounds.x1; height = bounds.y2 - bounds.y1; - stride = (width * BitsPerPixel (maskFormat->depth) + 7) / 8; - pPicture = uxa_create_alpha_picture (pScreen, pDst, maskFormat, - width, height); - if (!pPicture) + format = maskFormat->format | (BitsPerPixel (maskFormat->depth) << 24); + image = pixman_image_create_bits (format, width, height, NULL, 0); + if (!image) return; - image = pixman_image_create_bits (pPicture->format, - width, height, - NULL, stride); - if (!image) { - FreePicture (pPicture, 0); - return; - } - for (; ntrap; ntrap--, traps++) pixman_rasterize_trapezoid (image, (pixman_trapezoid_t *) traps, -bounds.x1, -bounds.y1); - pPixmap = GetScratchPixmapHeader(pScreen, width, height, - maskFormat->depth, - BitsPerPixel (maskFormat->depth), - PixmapBytePad (width, maskFormat->depth), - pixman_image_get_data (image)); - if (!pPixmap) { - FreePicture (pPicture, 0); - pixman_image_unref (image); - return; - } - - pGC = GetScratchGC (pPicture->pDrawable->depth, pScreen); - if (!pGC) - { - FreeScratchPixmapHeader (pPixmap); - pixman_image_unref (image); - FreePicture (pPicture, 0); - return; - } - ValidateGC (pPicture->pDrawable, pGC); - - (*pGC->ops->CopyArea) (&pPixmap->drawable, pPicture->pDrawable, - pGC, 0, 0, width, height, 0, 0); - - FreeScratchGC (pGC); - FreeScratchPixmapHeader (pPixmap); + pPicture = uxa_picture_from_pixman_image (pScreen, image, format); pixman_image_unref (image); + if (!pPicture) + return; xRel = bounds.x1 + xSrc - xDst; yRel = bounds.y1 + ySrc - yDst; |