diff options
Diffstat (limited to 'uxa')
-rw-r--r-- | uxa/uxa-accel.c | 473 | ||||
-rw-r--r-- | uxa/uxa-glyphs.c | 1527 | ||||
-rw-r--r-- | uxa/uxa-priv.h | 117 | ||||
-rw-r--r-- | uxa/uxa-render.c | 1214 | ||||
-rw-r--r-- | uxa/uxa.c | 73 | ||||
-rw-r--r-- | uxa/uxa.h | 45 |
6 files changed, 2262 insertions, 1187 deletions
diff --git a/uxa/uxa-accel.c b/uxa/uxa-accel.c index bede1f41..245738a6 100644 --- a/uxa/uxa-accel.c +++ b/uxa/uxa-accel.c @@ -34,33 +34,185 @@ #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 4: return PICT_a4; + case 8: return PICT_a8; + case 15: return PICT_x1r5g5b5; + case 16: return PICT_r5g6b5; + default: + case 24: return PICT_x8r8g8b8; +#if 0 + case 30: return PICT_x2r10g10b10; +#endif + 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) + 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->swappedOut || pGC->fillStyle != FillSolid || - !(pPixmap = uxa_get_offscreen_pixmap(pDrawable, &off_x, &off_y)) || - !(*uxa_screen->info->prepare_solid) (pPixmap, + 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->y1 > 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 +238,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 +255,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 +266,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 @@ -204,92 +361,12 @@ uxa_do_put_image(DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, return TRUE; } -#ifdef MITSHM - -#include "xorgVersion.h" - -static Bool -uxa_do_shm_put_image(DrawablePtr pDrawable, GCPtr pGC, int depth, - unsigned int format, int w, int h, int sx, int sy, int sw, - int sh, int dx, int dy, char *data) -{ - int src_stride = PixmapBytePad(w, depth); - - if (uxa_do_put_image - (pDrawable, pGC, depth, dx, dy, sw, sh, format, - data + sy * src_stride + sx * BitsPerPixel(depth) / 8, src_stride)) - return TRUE; - - if (format == ZPixmap) { - PixmapPtr pPixmap; - - pPixmap = - GetScratchPixmapHeader(pDrawable->pScreen, w, h, depth, - BitsPerPixel(depth), PixmapBytePad(w, - depth), - (pointer) data); - if (!pPixmap) - return FALSE; - - if (!uxa_prepare_access(pDrawable, UXA_ACCESS_RW)) { - FreeScratchPixmapHeader(pPixmap); - return FALSE; - } - - fbCopyArea((DrawablePtr) pPixmap, pDrawable, pGC, sx, sy, sw, - sh, dx, dy); - uxa_finish_access(pDrawable); - - FreeScratchPixmapHeader(pPixmap); - - return TRUE; - } - - return FALSE; -} - -#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,5,99,0,0) - -/* The actual ShmPutImage isn't wrapped by the damage layer, so we need to - * inform any interested parties of the damage incurred to the drawable. - * - * We also need to set the pending damage to ensure correct migration in all - * cases. - */ -void -uxa_shm_put_image(DrawablePtr pDrawable, GCPtr pGC, int depth, - unsigned int format, int w, int h, int sx, int sy, int sw, - int sh, int dx, int dy, char *data) -{ - if (!uxa_do_shm_put_image - (pDrawable, pGC, depth, format, w, h, sx, sy, sw, sh, dx, dy, - data)) { - if (!uxa_prepare_access(pDrawable, UXA_ACCESS_RW)) - return; - fbShmPutImage(pDrawable, pGC, depth, format, w, h, sx, sy, sw, - sh, dx, dy, data); - uxa_finish_access(pDrawable); - } -} -#else -#define uxa_shm_put_image NULL -#endif - -ShmFuncs uxa_shm_funcs = { NULL, uxa_shm_put_image }; - -#endif - static void uxa_put_image(DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, int w, int h, int leftPad, int format, char *bits) { -#ifdef MITSHM - if (!uxa_do_shm_put_image - (pDrawable, pGC, depth, format, w, h, 0, 0, w, h, x, y, bits)) -#else if (!uxa_do_put_image(pDrawable, pGC, depth, x, y, w, h, format, bits, PixmapBytePad(w, pDrawable->depth))) -#endif uxa_check_put_image(pDrawable, pGC, depth, x, y, w, h, leftPad, format, bits); } @@ -435,6 +512,14 @@ uxa_copy_n_to_n(DrawablePtr pSrcDrawable, 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); @@ -450,8 +535,45 @@ uxa_copy_n_to_n(DrawablePtr pSrcDrawable, goto fallback; } - if (!uxa_pixmap_is_offscreen(pDstPixmap)) - goto fallback; + if (!uxa_pixmap_is_offscreen(pDstPixmap)) { + int stride, bpp; + char *dst; + + if (!uxa_pixmap_is_offscreen(pSrcPixmap)) + goto fallback; + + if (!uxa_screen->info->get_image) + goto fallback; + + /* Don't bother with under 8bpp, XYPixmaps. */ + bpp = pSrcPixmap->drawable.bitsPerPixel; + if (bpp != pDstDrawable->bitsPerPixel || bpp < 8) + goto fallback; + + /* Only accelerate copies: no rop or planemask. */ + if (pGC && (!UXA_PM_IS_SOLID(pSrcDrawable, pGC->planemask) || pGC->alu != GXcopy)) + goto fallback; + + dst = pDstPixmap->devPrivate.ptr; + stride = pDstPixmap->devKind; + bpp /= 8; + while (nbox--) { + if (!uxa_screen->info->get_image(pSrcPixmap, + pbox->x1 + dx + src_off_x, + pbox->y1 + dy + src_off_y, + pbox->x2 - pbox->x1, + pbox->y2 - pbox->y1, + (char *) dst + + (pbox->y1 + dst_off_y) * stride + + (pbox->x1 + dst_off_x) * bpp, + stride)) + goto fallback; + + pbox++; + } + + return; + } if (uxa_pixmap_is_offscreen(pSrcPixmap)) { if (!(*uxa_screen->info->prepare_copy) (pSrcPixmap, pDstPixmap, @@ -558,7 +680,7 @@ uxa_poly_point(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, return; } - prect = xalloc(sizeof(xRectangle) * npt); + prect = malloc(sizeof(xRectangle) * npt); if (!prect) return; for (i = 0; i < npt; i++) { @@ -572,7 +694,7 @@ uxa_poly_point(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, prect[i].height = 1; } pGC->ops->PolyFillRect(pDrawable, pGC, npt, prect); - xfree(prect); + free(prect); } /** @@ -595,7 +717,7 @@ uxa_poly_lines(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, return; } - prect = xalloc(sizeof(xRectangle) * (npt - 1)); + prect = malloc(sizeof(xRectangle) * (npt - 1)); if (!prect) return; x1 = ppt[0].x; @@ -611,7 +733,7 @@ uxa_poly_lines(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, } if (x1 != x2 && y1 != y2) { - xfree(prect); + free(prect); uxa_check_poly_lines(pDrawable, pGC, mode, npt, ppt); return; } @@ -635,7 +757,7 @@ uxa_poly_lines(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, y1 = y2; } pGC->ops->PolyFillRect(pDrawable, pGC, npt - 1, prect); - xfree(prect); + free(prect); } /** @@ -664,7 +786,7 @@ uxa_poly_segment(DrawablePtr pDrawable, GCPtr pGC, int nseg, xSegment * pSeg) } } - prect = xalloc(sizeof(xRectangle) * nseg); + prect = malloc(sizeof(xRectangle) * nseg); if (!prect) return; for (i = 0; i < nseg; i++) { @@ -692,7 +814,7 @@ uxa_poly_segment(DrawablePtr pDrawable, GCPtr pGC, int nseg, xSegment * pSeg) } } pGC->ops->PolyFillRect(pDrawable, pGC, nseg, prect); - xfree(prect); + free(prect); } static Bool uxa_fill_region_solid(DrawablePtr pDrawable, RegionPtr pRegion, @@ -704,7 +826,7 @@ uxa_poly_fill_rect(DrawablePtr pDrawable, { uxa_screen_t *uxa_screen = uxa_get_screen(pDrawable->pScreen); RegionPtr pClip = fbGetCompositeClip(pGC); - PixmapPtr pPixmap = uxa_get_drawable_pixmap(pDrawable); + PixmapPtr pPixmap; register BoxPtr pbox; BoxPtr pextent; int extentX1, extentX2, extentY1, extentY2; @@ -722,11 +844,13 @@ uxa_poly_fill_rect(DrawablePtr pDrawable, if (!REGION_NUM_RECTS(pReg)) goto out; - uxa_get_drawable_deltas(pDrawable, pPixmap, &xoff, &yoff); - if (uxa_screen->swappedOut) goto fallback; + pPixmap = uxa_get_offscreen_pixmap (pDrawable, &xoff, &yoff); + if (!pPixmap) + goto fallback; + /* For ROPs where overlaps don't matter, convert rectangles to region * and call uxa_fill_region_{solid,tiled}. */ @@ -752,8 +876,12 @@ uxa_poly_fill_rect(DrawablePtr pDrawable, goto fallback; } - if (!uxa_pixmap_is_offscreen(pPixmap) || - !(*uxa_screen->info->prepare_solid) (pPixmap, + if (uxa_screen->info->check_solid && + !uxa_screen->info->check_solid(pDrawable, pGC->alu, pGC->planemask)) { + goto fallback; + } + + if (!(*uxa_screen->info->prepare_solid) (pPixmap, pGC->alu, pGC->planemask, pGC->fgPixel)) { @@ -896,35 +1024,121 @@ uxa_fill_region_solid(DrawablePtr pDrawable, RegionPtr pRegion, Pixel pixel, CARD32 planemask, CARD32 alu) { - uxa_screen_t *uxa_screen = uxa_get_screen(pDrawable->pScreen); - PixmapPtr pPixmap = uxa_get_drawable_pixmap(pDrawable); + ScreenPtr screen = pDrawable->pScreen; + uxa_screen_t *uxa_screen = uxa_get_screen(screen); + PixmapPtr pixmap; int xoff, yoff; + int nbox; + BoxPtr pBox, extents; Bool ret = FALSE; - uxa_get_drawable_deltas(pDrawable, pPixmap, &xoff, &yoff); - REGION_TRANSLATE(pScreen, pRegion, xoff, yoff); + pixmap = uxa_get_offscreen_pixmap(pDrawable, &xoff, &yoff); + if (!pixmap) + return FALSE; - if (uxa_pixmap_is_offscreen(pPixmap) && - (*uxa_screen->info->prepare_solid) (pPixmap, alu, planemask, pixel)) - { - int nbox; - BoxPtr pBox; + REGION_TRANSLATE(screen, pRegion, xoff, yoff); - nbox = REGION_NUM_RECTS(pRegion); - pBox = REGION_RECTS(pRegion); + nbox = REGION_NUM_RECTS(pRegion); + pBox = REGION_RECTS(pRegion); + extents = REGION_EXTENTS(screen, pRegion); + + /* Using GEM, the relocation costs outweigh the advantages of the blitter */ + if (nbox == 1 || (alu != GXcopy && alu != GXclear) || planemask != FB_ALLONES) { +try_solid: + if (uxa_screen->info->check_solid && + !uxa_screen->info->check_solid(&pixmap->drawable, alu, planemask)) + goto err; + + if (!uxa_screen->info->prepare_solid(pixmap, alu, planemask, pixel)) + goto err; while (nbox--) { - (*uxa_screen->info->solid) (pPixmap, pBox->x1, pBox->y1, - pBox->x2, pBox->y2); + uxa_screen->info->solid(pixmap, + pBox->x1, pBox->y1, + pBox->x2, pBox->y2); pBox++; } - (*uxa_screen->info->done_solid) (pPixmap); - ret = TRUE; + uxa_screen->info->done_solid(pixmap); + } else { + PicturePtr dst, src; + PixmapPtr src_pixmap = NULL; + xRenderColor color; + int error; + + dst = CreatePicture(0, &pixmap->drawable, + PictureMatchFormat(screen, + pixmap->drawable.depth, + format_for_depth(pixmap->drawable.depth)), + 0, 0, serverClient, &error); + if (!dst) + goto err; + + ValidatePicture(dst); + + uxa_get_rgba_from_pixel(pixel, + &color.red, + &color.green, + &color.blue, + &color.alpha, + format_for_depth(pixmap->drawable.depth)); + src = CreateSolidPicture(0, &color, &error); + if (!src) { + FreePicture(dst, 0); + goto err; + } + + if (!uxa_screen->info->check_composite(PictOpSrc, src, NULL, dst, + extents->x2 - extents->x1, + extents->y2 - extents->y1)) { + FreePicture(src, 0); + FreePicture(dst, 0); + goto try_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 err; + } + } + + if (!uxa_screen->info->prepare_composite(PictOpSrc, src, NULL, dst, src_pixmap, NULL, pixmap)) { + FreePicture(src, 0); + FreePicture(dst, 0); + goto err; + } + + while (nbox--) { + uxa_screen->info->composite(pixmap, + 0, 0, 0, 0, + pBox->x1, + pBox->y1, + pBox->x2 - pBox->x1, + pBox->y2 - pBox->y1); + pBox++; + } + + uxa_screen->info->done_composite(pixmap); + FreePicture(src, 0); + FreePicture(dst, 0); } - REGION_TRANSLATE(pScreen, pRegion, -xoff, -yoff); + ret = TRUE; +err: + REGION_TRANSLATE(screen, pRegion, -xoff, -yoff); return ret; } @@ -956,15 +1170,16 @@ uxa_fill_region_tiled(DrawablePtr pDrawable, uxa_get_pixmap_first_pixel(pTile), planemask, alu); - 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->check_copy && + !uxa_screen->info->check_copy(pTile, pPixmap, alu, planemask)) + return FALSE; + + REGION_TRANSLATE(pScreen, pRegion, xoff, yoff); + 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 5c233216..823cf82f 100644 --- a/uxa/uxa-glyphs.c +++ b/uxa/uxa-glyphs.c @@ -1,11 +1,29 @@ /* - * Copyright © 2008 Red Hat, Inc. + * Copyright © 2010 Intel Corporation + * Partly based on code Copyright © 2008 Red Hat, Inc. * Partly based on code Copyright © 2000 SuSE, Inc. * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Intel not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Intel makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL INTEL + * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting * documentation, and that the name of Red Hat not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. Red Hat makes no representations about the @@ -16,7 +34,7 @@ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL Red Hat * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Permission to use, copy, modify, distribute, and sell this software and its @@ -33,11 +51,11 @@ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * Author: Owen Taylor <otaylor@fishsoup.net> - * Based on code by: Keith Packard + * Author: Chris Wilson <chris@chris-wilson.co.uk> + * Based on code by: Keith Packard <keithp@keithp.com> and Owen Taylor <otaylor@fishsoup.net> */ #ifdef HAVE_DIX_CONFIG_H @@ -51,99 +69,63 @@ #include "mipict.h" -#if DEBUG_GLYPH_CACHE -#define DBG_GLYPH_CACHE(a) ErrorF a -#else -#define DBG_GLYPH_CACHE(a) -#endif - /* Width of the pixmaps we use for the caches; this should be less than * max texture size of the driver; this may need to actually come from * the driver. */ -#define CACHE_PICTURE_WIDTH 1024 - -/* Maximum number of glyphs we buffer on the stack before flushing - * rendering to the mask or destination surface. - */ -#define GLYPH_BUFFER_SIZE 256 - -typedef struct { - PicturePtr source; - uxa_composite_rect_t rects[GLYPH_BUFFER_SIZE]; - int count; -} uxa_glyph_buffer_t; - -typedef enum { - UXA_GLYPH_SUCCESS, /* Glyph added to render buffer */ - UXA_GLYPH_FAIL, /* out of memory, etc */ - UXA_GLYPH_NEED_FLUSH, /* would evict a glyph already in the buffer */ -} uxa_glyph_cache_result_t; +#define CACHE_PICTURE_SIZE 1024 +#define GLYPH_MIN_SIZE 8 +#define GLYPH_MAX_SIZE 64 +#define GLYPH_CACHE_SIZE (CACHE_PICTURE_SIZE * CACHE_PICTURE_SIZE / (GLYPH_MIN_SIZE * GLYPH_MIN_SIZE)) + +struct uxa_glyph { + uxa_glyph_cache_t *cache; + uint16_t x, y; + uint16_t size, pos; +}; + +#if HAS_DEVPRIVATEKEYREC +static DevPrivateKeyRec uxa_glyph_key; +#else +static int uxa_glyph_key; +#endif -void uxa_glyphs_init(ScreenPtr pScreen) +static inline struct uxa_glyph *uxa_glyph_get_private(GlyphPtr glyph) { - uxa_screen_t *uxa_screen = uxa_get_screen(pScreen); - int i = 0; - - memset(uxa_screen->glyphCaches, 0, sizeof(uxa_screen->glyphCaches)); +#if HAS_DEVPRIVATEKEYREC + return dixGetPrivate(&glyph->devPrivates, &uxa_glyph_key); +#else + return dixLookupPrivate(&glyph->devPrivates, &uxa_glyph_key); +#endif +} - uxa_screen->glyphCaches[i].format = PICT_a8; - uxa_screen->glyphCaches[i].glyphWidth = - uxa_screen->glyphCaches[i].glyphHeight = 16; - i++; - uxa_screen->glyphCaches[i].format = PICT_a8; - uxa_screen->glyphCaches[i].glyphWidth = - uxa_screen->glyphCaches[i].glyphHeight = 32; - i++; - uxa_screen->glyphCaches[i].format = PICT_a8r8g8b8; - uxa_screen->glyphCaches[i].glyphWidth = - uxa_screen->glyphCaches[i].glyphHeight = 16; - i++; - uxa_screen->glyphCaches[i].format = PICT_a8r8g8b8; - uxa_screen->glyphCaches[i].glyphWidth = - uxa_screen->glyphCaches[i].glyphHeight = 32; - i++; - - assert(i == UXA_NUM_GLYPH_CACHES); - - for (i = 0; i < UXA_NUM_GLYPH_CACHES; i++) { - uxa_screen->glyphCaches[i].columns = - CACHE_PICTURE_WIDTH / uxa_screen->glyphCaches[i].glyphWidth; - uxa_screen->glyphCaches[i].size = 256; - uxa_screen->glyphCaches[i].hashSize = 557; - } +static inline void uxa_glyph_set_private(GlyphPtr glyph, struct uxa_glyph *priv) +{ + dixSetPrivate(&glyph->devPrivates, &uxa_glyph_key, priv); } -static void uxa_unrealize_glyph_caches(ScreenPtr pScreen, unsigned int format) +#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0) + +static void uxa_unrealize_glyph_caches(ScreenPtr pScreen) { uxa_screen_t *uxa_screen = uxa_get_screen(pScreen); int i; - for (i = 0; i < UXA_NUM_GLYPH_CACHES; i++) { + for (i = 0; i < UXA_NUM_GLYPH_CACHE_FORMATS; i++) { uxa_glyph_cache_t *cache = &uxa_screen->glyphCaches[i]; - if (cache->format != format) - continue; - - if (cache->picture) { - FreePicture((pointer) cache->picture, (XID) 0); - cache->picture = NULL; - } - - if (cache->hashEntries) { - xfree(cache->hashEntries); - cache->hashEntries = NULL; - } + if (cache->picture) + FreePicture(cache->picture, 0); - if (cache->glyphs) { - xfree(cache->glyphs); - cache->glyphs = NULL; - } - cache->glyphCount = 0; + if (cache->glyphs) + free(cache->glyphs); } } -#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0) +void uxa_glyphs_fini(ScreenPtr pScreen) +{ + uxa_unrealize_glyph_caches(pScreen); +} /* All caches for a single format share a single pixmap for glyph storage, * allowing mixing glyphs of different sizes without paying a penalty @@ -154,460 +136,176 @@ static void uxa_unrealize_glyph_caches(ScreenPtr pScreen, unsigned int format) * This function allocates the storage pixmap, and then fills in the * rest of the allocated structures for all caches with the given format. */ -static Bool uxa_realize_glyph_caches(ScreenPtr pScreen, unsigned int format) +static Bool uxa_realize_glyph_caches(ScreenPtr pScreen) { uxa_screen_t *uxa_screen = uxa_get_screen(pScreen); - int depth = PIXMAN_FORMAT_DEPTH(format); - PictFormatPtr pPictFormat; - PixmapPtr pPixmap; - PicturePtr pPicture; - CARD32 component_alpha; - int height; + unsigned int formats[] = { + PIXMAN_a8, + PIXMAN_a8r8g8b8, + }; int i; - int error; - pPictFormat = PictureMatchFormat(pScreen, depth, format); - if (!pPictFormat) - return FALSE; - - /* Compute the total vertical size needed for the format */ + memset(uxa_screen->glyphCaches, 0, sizeof(uxa_screen->glyphCaches)); - height = 0; - for (i = 0; i < UXA_NUM_GLYPH_CACHES; i++) { + for (i = 0; i < sizeof(formats)/sizeof(formats[0]); i++) { uxa_glyph_cache_t *cache = &uxa_screen->glyphCaches[i]; - int rows; - - if (cache->format != format) - continue; - - cache->yOffset = height; - - rows = (cache->size + cache->columns - 1) / cache->columns; - height += rows * cache->glyphHeight; - } - - /* Now allocate the pixmap and picture */ - - pPixmap = (*pScreen->CreatePixmap) (pScreen, - CACHE_PICTURE_WIDTH, - height, depth, - INTEL_CREATE_PIXMAP_TILING_X); - if (!pPixmap) - return FALSE; - - component_alpha = NeedsComponent(pPictFormat->format); - pPicture = CreatePicture(0, &pPixmap->drawable, pPictFormat, - CPComponentAlpha, &component_alpha, - serverClient, &error); - - (*pScreen->DestroyPixmap) (pPixmap); /* picture holds a refcount */ + PixmapPtr pixmap; + PicturePtr picture; + CARD32 component_alpha; + int depth = PIXMAN_FORMAT_DEPTH(formats[i]); + int error; + PictFormatPtr pPictFormat = PictureMatchFormat(pScreen, depth, formats[i]); + if (!pPictFormat) + goto bail; - if (!pPicture) - return FALSE; + /* Now allocate the pixmap and picture */ + pixmap = pScreen->CreatePixmap(pScreen, + CACHE_PICTURE_SIZE, CACHE_PICTURE_SIZE, depth, + INTEL_CREATE_PIXMAP_TILING_X); + if (!pixmap) + goto bail; + assert (uxa_pixmap_is_offscreen(pixmap)); - /* And store the picture in all the caches for the format */ + component_alpha = NeedsComponent(pPictFormat->format); + picture = CreatePicture(0, &pixmap->drawable, pPictFormat, + CPComponentAlpha, &component_alpha, + serverClient, &error); - for (i = 0; i < UXA_NUM_GLYPH_CACHES; i++) { - uxa_glyph_cache_t *cache = &uxa_screen->glyphCaches[i]; - int j; + pScreen->DestroyPixmap(pixmap); - if (cache->format != format) - continue; + if (!picture) + goto bail; - cache->picture = pPicture; - cache->picture->refcnt++; - cache->hashEntries = xalloc(sizeof(int) * cache->hashSize); - cache->glyphs = - xalloc(sizeof(uxa_cached_glyph_t) * cache->size); - cache->glyphCount = 0; + ValidatePicture(picture); - if (!cache->hashEntries || !cache->glyphs) + cache->picture = picture; + cache->glyphs = calloc(sizeof(GlyphPtr), GLYPH_CACHE_SIZE); + if (!cache->glyphs) goto bail; - for (j = 0; j < cache->hashSize; j++) - cache->hashEntries[j] = -1; - - cache->evictionPosition = rand() % cache->size; + cache->evict = rand() % GLYPH_CACHE_SIZE; } + assert(i == UXA_NUM_GLYPH_CACHE_FORMATS); - /* Each cache references the picture individually */ - FreePicture((pointer) pPicture, (XID) 0); return TRUE; bail: - uxa_unrealize_glyph_caches(pScreen, format); + uxa_unrealize_glyph_caches(pScreen); return FALSE; } -void uxa_glyphs_fini(ScreenPtr pScreen) -{ - uxa_screen_t *uxa_screen = uxa_get_screen(pScreen); - int i; - - for (i = 0; i < UXA_NUM_GLYPH_CACHES; i++) { - uxa_glyph_cache_t *cache = &uxa_screen->glyphCaches[i]; - if (cache->picture) - uxa_unrealize_glyph_caches(pScreen, cache->format); - } -} - -static int -uxa_glyph_cache_hash_lookup(uxa_glyph_cache_t * cache, GlyphPtr pGlyph) +Bool uxa_glyphs_init(ScreenPtr pScreen) { - int slot; - - slot = (*(CARD32 *) pGlyph->sha1) % cache->hashSize; - - while (TRUE) { /* hash table can never be full */ - int entryPos = cache->hashEntries[slot]; - if (entryPos == -1) - return -1; - - if (memcmp - (pGlyph->sha1, cache->glyphs[entryPos].sha1, - sizeof(pGlyph->sha1)) == 0) { - return entryPos; - } - - slot--; - if (slot < 0) - slot = cache->hashSize - 1; - } -} - -static void -uxa_glyph_cache_hash_insert(uxa_glyph_cache_t * cache, GlyphPtr pGlyph, int pos) -{ - int slot; - - memcpy(cache->glyphs[pos].sha1, pGlyph->sha1, sizeof(pGlyph->sha1)); - - slot = (*(CARD32 *) pGlyph->sha1) % cache->hashSize; - - while (TRUE) { /* hash table can never be full */ - if (cache->hashEntries[slot] == -1) { - cache->hashEntries[slot] = pos; - return; - } - - slot--; - if (slot < 0) - slot = cache->hashSize - 1; - } -} - -static void uxa_glyph_cache_hash_remove(uxa_glyph_cache_t * cache, int pos) -{ - int slot; - int emptiedSlot = -1; - - slot = (*(CARD32 *) cache->glyphs[pos].sha1) % cache->hashSize; - - while (TRUE) { /* hash table can never be full */ - int entryPos = cache->hashEntries[slot]; + /* We are trying to initialise per screen resources prior to the + * complete initialisation of the screen. So ensure the components + * that we depend upon are initialsed prior to our use. + */ + if (!CreateScratchPixmapsForScreen(pScreen->myNum)) + return FALSE; - if (entryPos == -1) - return; +#if HAS_DIXREGISTERPRIVATEKEY + if (!dixRegisterPrivateKey(&uxa_glyph_key, PRIVATE_GLYPH, 0)) + return FALSE; +#else + if (!dixRequestPrivate(&uxa_glyph_key, 0)) + return FALSE; +#endif - if (entryPos == pos) { - cache->hashEntries[slot] = -1; - emptiedSlot = slot; - } else if (emptiedSlot != -1) { - /* See if we can move this entry into the emptied slot, - * we can't do that if if entry would have hashed - * between the current position and the emptied slot. - * (taking wrapping into account). Bad positions - * are: - * - * | XXXXXXXXXX | - * i j - * - * |XXX XXXX| - * j i - * - * i - slot, j - emptiedSlot - * - * (Knuth 6.4R) - */ - - int entrySlot = - (*(CARD32 *) cache->glyphs[entryPos].sha1) % - cache->hashSize; - - if (!((entrySlot >= slot && entrySlot < emptiedSlot) || - (emptiedSlot < slot - && (entrySlot < emptiedSlot - || entrySlot >= slot)))) { - cache->hashEntries[emptiedSlot] = entryPos; - cache->hashEntries[slot] = -1; - emptiedSlot = slot; - } - } + if (!uxa_realize_glyph_caches(pScreen)) + return FALSE; - slot--; - if (slot < 0) - slot = cache->hashSize - 1; - } + return TRUE; } -#define CACHE_X(pos) (((pos) % cache->columns) * cache->glyphWidth) -#define CACHE_Y(pos) (cache->yOffset + ((pos) / cache->columns) * cache->glyphHeight) - /* The most efficient thing to way to upload the glyph to the screen * is to use CopyArea; uxa pixmaps are always offscreen. */ -static Bool -uxa_glyph_cache_upload_glyph(ScreenPtr pScreen, +static void +uxa_glyph_cache_upload_glyph(ScreenPtr screen, uxa_glyph_cache_t * cache, - int pos, GlyphPtr pGlyph) + GlyphPtr glyph, + int x, int y) { - PicturePtr pGlyphPicture = GlyphPicture(pGlyph)[pScreen->myNum]; + PicturePtr pGlyphPicture = GlyphPicture(glyph)[screen->myNum]; PixmapPtr pGlyphPixmap = (PixmapPtr) pGlyphPicture->pDrawable; PixmapPtr pCachePixmap = (PixmapPtr) cache->picture->pDrawable; PixmapPtr scratch; - GCPtr pGC; + GCPtr gc; - /* UploadToScreen only works if bpp match */ - if (pGlyphPixmap->drawable.bitsPerPixel != - pCachePixmap->drawable.bitsPerPixel) - return FALSE; + gc = GetScratchGC(pCachePixmap->drawable.depth, screen); + if (!gc) + return; - pGC = GetScratchGC(pCachePixmap->drawable.depth, pScreen); - ValidateGC(&pCachePixmap->drawable, pGC); + ValidateGC(&pCachePixmap->drawable, gc); + scratch = pGlyphPixmap; /* Create a temporary bo to stream the updates to the cache */ - scratch = (*pScreen->CreatePixmap)(pScreen, - pGlyph->info.width, - pGlyph->info.height, - pGlyphPixmap->drawable.depth, - UXA_CREATE_PIXMAP_FOR_MAP); - if (scratch) { - (void)uxa_copy_area(&pGlyphPixmap->drawable, - &scratch->drawable, - pGC, - 0, 0, - pGlyph->info.width, pGlyph->info.height, - 0, 0); - } else { - scratch = pGlyphPixmap; - } - - (void)uxa_copy_area(&scratch->drawable, - &pCachePixmap->drawable, - pGC, - 0, 0, pGlyph->info.width, pGlyph->info.height, - CACHE_X(pos), CACHE_Y(pos)); - - if (scratch != pGlyphPixmap) - (*pScreen->DestroyPixmap)(scratch); - - FreeScratchGC(pGC); - - return TRUE; -} - -static uxa_glyph_cache_result_t -uxa_glyph_cache_buffer_glyph(ScreenPtr pScreen, - uxa_glyph_cache_t * cache, - uxa_glyph_buffer_t * buffer, - GlyphPtr pGlyph, int xGlyph, int yGlyph) -{ - uxa_composite_rect_t *rect; - int pos; - - if (buffer->source && buffer->source != cache->picture) - return UXA_GLYPH_NEED_FLUSH; - - if (!cache->picture) { - if (!uxa_realize_glyph_caches(pScreen, cache->format)) - return UXA_GLYPH_FAIL; - } - - DBG_GLYPH_CACHE(("(%d,%d,%s): buffering glyph %lx\n", - cache->glyphWidth, cache->glyphHeight, - cache->format == PICT_a8 ? "A" : "ARGB", - (long)*(CARD32 *) pGlyph->sha1)); - - pos = uxa_glyph_cache_hash_lookup(cache, pGlyph); - if (pos != -1) { - DBG_GLYPH_CACHE((" found existing glyph at %d\n", pos)); - } else { - if (cache->glyphCount < cache->size) { - /* Space remaining; we fill from the start */ - pos = cache->glyphCount; - cache->glyphCount++; - DBG_GLYPH_CACHE((" storing glyph in free space at %d\n", pos)); - - uxa_glyph_cache_hash_insert(cache, pGlyph, pos); - - } else { - /* Need to evict an entry. We have to see if any glyphs - * already in the output buffer were at this position in - * the cache - */ - - pos = cache->evictionPosition; - DBG_GLYPH_CACHE((" evicting glyph at %d\n", pos)); - if (buffer->count) { - int x, y; - int i; - - x = CACHE_X(pos); - y = CACHE_Y(pos); - - for (i = 0; i < buffer->count; i++) { - if (buffer->rects[i].xSrc == x - && buffer->rects[i].ySrc == y) { - DBG_GLYPH_CACHE((" must flush buffer\n")); - return UXA_GLYPH_NEED_FLUSH; - } + if (pGlyphPixmap->drawable.depth != pCachePixmap->drawable.depth || + !uxa_pixmap_is_offscreen(scratch)) { + scratch = screen->CreatePixmap(screen, + glyph->info.width, + glyph->info.height, + pCachePixmap->drawable.depth, + UXA_CREATE_PIXMAP_FOR_MAP); + if (scratch) { + if (pGlyphPixmap->drawable.depth != pCachePixmap->drawable.depth) { + PicturePtr picture; + int error; + + picture = CreatePicture(0, &scratch->drawable, + PictureMatchFormat(screen, + pCachePixmap->drawable.depth, + cache->picture->format), + 0, NULL, + serverClient, &error); + if (picture) { + ValidatePicture(picture); + uxa_composite(PictOpSrc, pGlyphPicture, NULL, picture, + 0, 0, + 0, 0, + 0, 0, + glyph->info.width, glyph->info.height); + FreePicture(picture, 0); } + } else { + uxa_copy_area(&pGlyphPixmap->drawable, + &scratch->drawable, + gc, + 0, 0, + glyph->info.width, glyph->info.height, + 0, 0); } - - /* OK, we're all set, swap in the new glyph */ - uxa_glyph_cache_hash_remove(cache, pos); - uxa_glyph_cache_hash_insert(cache, pGlyph, pos); - - /* And pick a new eviction position */ - cache->evictionPosition = rand() % cache->size; - } - - /* Now actually upload the glyph into the cache picture; if - * we can't do it with UploadToScreen (because the glyph is - * offscreen, etc), we fall back to CompositePicture. - */ - if (!uxa_glyph_cache_upload_glyph(pScreen, cache, pos, pGlyph)) { - CompositePicture(PictOpSrc, - GlyphPicture(pGlyph)[pScreen->myNum], - None, - cache->picture, - 0, 0, - 0, 0, - CACHE_X(pos), - CACHE_Y(pos), - pGlyph->info.width, - pGlyph->info.height); - } - - } - - buffer->source = cache->picture; - - rect = &buffer->rects[buffer->count]; - rect->xSrc = CACHE_X(pos); - rect->ySrc = CACHE_Y(pos); - rect->xDst = xGlyph - pGlyph->info.x; - rect->yDst = yGlyph - pGlyph->info.y; - rect->width = pGlyph->info.width; - rect->height = pGlyph->info.height; - - buffer->count++; - - return UXA_GLYPH_SUCCESS; -} - -#undef CACHE_X -#undef CACHE_Y - -static uxa_glyph_cache_result_t -uxa_buffer_glyph(ScreenPtr pScreen, - uxa_glyph_buffer_t * buffer, - GlyphPtr pGlyph, int xGlyph, int yGlyph) -{ - uxa_screen_t *uxa_screen = uxa_get_screen(pScreen); - unsigned int format = (GlyphPicture(pGlyph)[pScreen->myNum])->format; - int width = pGlyph->info.width; - int height = pGlyph->info.height; - uxa_composite_rect_t *rect; - PicturePtr source; - int i; - - if (buffer->count == GLYPH_BUFFER_SIZE) - return UXA_GLYPH_NEED_FLUSH; - - if (PICT_FORMAT_BPP(format) == 1) - format = PICT_a8; - - for (i = 0; i < UXA_NUM_GLYPH_CACHES; i++) { - uxa_glyph_cache_t *cache = &uxa_screen->glyphCaches[i]; - - if (format == cache->format && - width <= cache->glyphWidth && - height <= cache->glyphHeight) { - uxa_glyph_cache_result_t result = - uxa_glyph_cache_buffer_glyph(pScreen, - &uxa_screen-> - glyphCaches[i], - buffer, - pGlyph, xGlyph, - yGlyph); - switch (result) { - case UXA_GLYPH_FAIL: - break; - case UXA_GLYPH_SUCCESS: - case UXA_GLYPH_NEED_FLUSH: - return result; - } + } else { + scratch = pGlyphPixmap; } } - /* Couldn't find the glyph in the cache, use the glyph picture directly */ - - source = GlyphPicture(pGlyph)[pScreen->myNum]; - if (buffer->source && buffer->source != source) - return UXA_GLYPH_NEED_FLUSH; + uxa_copy_area(&scratch->drawable, &pCachePixmap->drawable, gc, + 0, 0, + glyph->info.width, glyph->info.height, + x, y); - buffer->source = source; - - rect = &buffer->rects[buffer->count]; - rect->xSrc = 0; - rect->ySrc = 0; - rect->xDst = xGlyph - pGlyph->info.x; - rect->yDst = yGlyph - pGlyph->info.y; - rect->width = pGlyph->info.width; - rect->height = pGlyph->info.height; - - buffer->count++; + if (scratch != pGlyphPixmap) + screen->DestroyPixmap(scratch); - return UXA_GLYPH_SUCCESS; + FreeScratchGC(gc); } -static void uxa_glyphs_to_mask(PicturePtr pMask, uxa_glyph_buffer_t * buffer) +void +uxa_glyph_unrealize(ScreenPtr pScreen, + GlyphPtr pGlyph) { - uxa_composite_rects(PictOpAdd, buffer->source, pMask, - buffer->count, buffer->rects); - - buffer->count = 0; - buffer->source = NULL; -} + struct uxa_glyph *priv; -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) -{ - int i; + priv = uxa_glyph_get_private(pGlyph); + if (priv == NULL) + return; - for (i = 0; i < buffer->count; i++) { - 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); - } + priv->cache->glyphs[priv->pos] = NULL; - buffer->count = 0; - buffer->source = NULL; + uxa_glyph_set_private(pGlyph, NULL); + free(priv); } /* Cut and paste from render/glyph.c - probably should export it instead */ @@ -616,47 +314,43 @@ uxa_glyph_extents(int nlist, GlyphListPtr list, GlyphPtr * glyphs, BoxPtr extents) { int x1, x2, y1, y2; - int n; - GlyphPtr glyph; - int x, y; + int x, y, n; - x = 0; - y = 0; - extents->x1 = MAXSHORT; - extents->x2 = MINSHORT; - extents->y1 = MAXSHORT; - extents->y2 = MINSHORT; + x1 = y1 = MAXSHORT; + x2 = y2 = MINSHORT; + x = y = 0; while (nlist--) { x += list->xOff; y += list->yOff; n = list->len; list++; while (n--) { - glyph = *glyphs++; - x1 = x - glyph->info.x; - if (x1 < MINSHORT) - x1 = MINSHORT; - y1 = y - glyph->info.y; - if (y1 < MINSHORT) - y1 = MINSHORT; - x2 = x1 + glyph->info.width; - if (x2 > MAXSHORT) - x2 = MAXSHORT; - y2 = y1 + glyph->info.height; - if (y2 > MAXSHORT) - y2 = MAXSHORT; - if (x1 < extents->x1) - extents->x1 = x1; - if (x2 > extents->x2) - extents->x2 = x2; - if (y1 < extents->y1) - extents->y1 = y1; - if (y2 > extents->y2) - extents->y2 = y2; + GlyphPtr glyph = *glyphs++; + int v; + + v = x - glyph->info.x; + if (v < x1) + x1 = v; + v += glyph->info.width; + if (v > x2) + x2 = v; + + v = y - glyph->info.y; + if (v < y1) + y1 = v; + v += glyph->info.height; + if (v > y2) + y2 = v; + x += glyph->info.xOff; y += glyph->info.yOff; } } + + extents->x1 = x1 < MINSHORT ? MINSHORT : x1; + extents->x2 = x2 > MAXSHORT ? MAXSHORT : x2; + extents->y1 = y1 < MINSHORT ? MINSHORT : y1; + extents->y2 = y2 > MAXSHORT ? MAXSHORT : y2; } /** @@ -668,7 +362,6 @@ uxa_glyphs_intersect(int nlist, GlyphListPtr list, GlyphPtr * glyphs) { int x1, x2, y1, y2; int n; - GlyphPtr glyph; int x, y; BoxRec extents; Bool first = TRUE; @@ -685,7 +378,7 @@ uxa_glyphs_intersect(int nlist, GlyphListPtr list, GlyphPtr * glyphs) n = list->len; list++; while (n--) { - glyph = *glyphs++; + GlyphPtr glyph = *glyphs++; if (glyph->info.width == 0 || glyph->info.height == 0) { x += glyph->info.xOff; @@ -735,121 +428,98 @@ uxa_glyphs_intersect(int nlist, GlyphListPtr list, GlyphPtr * glyphs) return FALSE; } -void -uxa_glyphs(CARD8 op, - PicturePtr pSrc, - PicturePtr pDst, - PictFormatPtr maskFormat, - INT16 xSrc, - INT16 ySrc, int nlist, GlyphListPtr list, GlyphPtr * glyphs) +static void +uxa_check_glyphs(CARD8 op, + PicturePtr src, + PicturePtr dst, + PictFormatPtr maskFormat, + INT16 xSrc, + INT16 ySrc, int nlist, GlyphListPtr list, GlyphPtr * glyphs) { - PicturePtr pPicture; - PixmapPtr pMaskPixmap = 0; - PicturePtr pMask; - ScreenPtr pScreen = pDst->pDrawable->pScreen; + int screen = dst->pDrawable->pScreen->myNum; + pixman_image_t *image; + PixmapPtr scratch; + PicturePtr mask; int width = 0, height = 0; - int x, y; + int x, y, n; int xDst = list->xOff, yDst = list->yOff; - int n; - GlyphPtr glyph; - int error; BoxRec extents = { 0, 0, 0, 0 }; - CARD32 component_alpha; - uxa_glyph_buffer_t buffer; - - /* 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. - */ - if (!maskFormat) { - Bool sameFormat = TRUE; - int i; - - maskFormat = list[0].format; - - 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 (maskFormat) { - GCPtr pGC; - xRectangle rect; + pixman_format_code_t format; + CARD32 component_alpha; + int error; 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; - if (maskFormat->depth == 1) { - PictFormatPtr a8Format = - PictureMatchFormat(pScreen, 8, PICT_a8); + format = maskFormat->format | + (BitsPerPixel(maskFormat->depth) << 24); + image = + pixman_image_create_bits(format, width, height, NULL, 0); + if (!image) + return; - if (a8Format) - maskFormat = a8Format; - } + scratch = GetScratchPixmapHeader(dst->pDrawable->pScreen, width, height, + PIXMAN_FORMAT_DEPTH(format), + PIXMAN_FORMAT_BPP(format), + pixman_image_get_stride(image), + pixman_image_get_data(image)); - pMaskPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, - maskFormat->depth, - CREATE_PIXMAP_USAGE_SCRATCH); - if (!pMaskPixmap) + if (!scratch) { + pixman_image_unref(image); return; + } + component_alpha = NeedsComponent(maskFormat->format); - pMask = CreatePicture(0, &pMaskPixmap->drawable, - maskFormat, CPComponentAlpha, - &component_alpha, serverClient, &error); - if (!pMask) { - (*pScreen->DestroyPixmap) (pMaskPixmap); + mask = CreatePicture(0, &scratch->drawable, + maskFormat, CPComponentAlpha, + &component_alpha, serverClient, &error); + if (!mask) { + FreeScratchPixmapHeader(scratch); + pixman_image_unref(image); 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); + ValidatePicture(mask); + x = -extents.x1; y = -extents.y1; } else { - pMask = pDst; + mask = dst; x = 0; y = 0; } - buffer.count = 0; - buffer.source = NULL; + while (nlist--) { x += list->xOff; y += list->yOff; n = list->len; while (n--) { - glyph = *glyphs++; - pPicture = GlyphPicture(glyph)[pScreen->myNum]; - - if (glyph->info.width > 0 && glyph->info.height > 0 && - uxa_buffer_glyph(pScreen, &buffer, glyph, x, - y) == UXA_GLYPH_NEED_FLUSH) { - if (maskFormat) - uxa_glyphs_to_mask(pMask, &buffer); - else - uxa_glyphs_to_dst(op, pSrc, pDst, - &buffer, xSrc, ySrc, - xDst, yDst); - - uxa_buffer_glyph(pScreen, &buffer, glyph, x, y); + GlyphPtr glyph = *glyphs++; + PicturePtr g = GlyphPicture(glyph)[screen]; + if (g) { + if (maskFormat) { + CompositePicture(PictOpAdd, g, NULL, mask, + 0, 0, + 0, 0, + x - glyph->info.x, + y - glyph->info.y, + glyph->info.width, + glyph->info.height); + } else { + CompositePicture(op, src, g, dst, + xSrc + (x - glyph->info.x) - xDst, + ySrc + (y - glyph->info.y) - yDst, + 0, 0, + x - glyph->info.x, + y - glyph->info.y, + glyph->info.width, + glyph->info.height); + } } x += glyph->info.xOff; @@ -858,24 +528,659 @@ uxa_glyphs(CARD8 op, list++; } - if (buffer.count) { - if (maskFormat) - uxa_glyphs_to_mask(pMask, &buffer); - else - uxa_glyphs_to_dst(op, pSrc, pDst, &buffer, - xSrc, ySrc, xDst, yDst); - } - if (maskFormat) { x = extents.x1; y = extents.y1; - CompositePicture(op, - pSrc, - pMask, - pDst, + CompositePicture(op, src, mask, dst, 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(mask, 0); + FreeScratchPixmapHeader(scratch); + pixman_image_unref(image); + } +} + +static inline unsigned int +uxa_glyph_size_to_count(int size) +{ + size /= GLYPH_MIN_SIZE; + return size * size; +} + +static inline unsigned int +uxa_glyph_count_to_mask(int count) +{ + return ~(count - 1); +} + +static inline unsigned int +uxa_glyph_size_to_mask(int size) +{ + return uxa_glyph_count_to_mask(uxa_glyph_size_to_count(size)); +} + +static PicturePtr +uxa_glyph_cache(ScreenPtr screen, GlyphPtr glyph, int *out_x, int *out_y) +{ + uxa_screen_t *uxa_screen = uxa_get_screen(screen); + PicturePtr glyph_picture = GlyphPicture(glyph)[screen->myNum]; + uxa_glyph_cache_t *cache = &uxa_screen->glyphCaches[PICT_FORMAT_RGB(glyph_picture->format) != 0]; + struct uxa_glyph *priv = NULL; + int size, mask, pos, s; + + if (glyph->info.width > GLYPH_MAX_SIZE || glyph->info.height > GLYPH_MAX_SIZE) + return NULL; + + for (size = GLYPH_MIN_SIZE; size <= GLYPH_MAX_SIZE; size *= 2) + if (glyph->info.width <= size && glyph->info.height <= size) + break; + + s = uxa_glyph_size_to_count(size); + mask = uxa_glyph_count_to_mask(s); + pos = (cache->count + s - 1) & mask; + if (pos < GLYPH_CACHE_SIZE) { + cache->count = pos + s; + } else { + for (s = size; s <= GLYPH_MAX_SIZE; s *= 2) { + int i = cache->evict & uxa_glyph_size_to_mask(s); + GlyphPtr evicted = cache->glyphs[i]; + if (evicted == NULL) + continue; + + priv = uxa_glyph_get_private(evicted); + if (priv->size >= s) { + cache->glyphs[i] = NULL; + uxa_glyph_set_private(evicted, NULL); + pos = cache->evict & uxa_glyph_size_to_mask(size); + } else + priv = NULL; + break; + } + if (priv == NULL) { + int count = uxa_glyph_size_to_count(size); + mask = uxa_glyph_count_to_mask(count); + pos = cache->evict & mask; + for (s = 0; s < count; s++) { + GlyphPtr evicted = cache->glyphs[pos + s]; + if (evicted != NULL) { + if (priv != NULL) + free(priv); + + priv = uxa_glyph_get_private(evicted); + uxa_glyph_set_private(evicted, NULL); + cache->glyphs[pos + s] = NULL; + } + } + } + + /* And pick a new eviction position */ + cache->evict = rand() % GLYPH_CACHE_SIZE; + } + + if (priv == NULL) { + priv = malloc(sizeof(struct uxa_glyph)); + if (priv == NULL) + return NULL; + } + + uxa_glyph_set_private(glyph, priv); + cache->glyphs[pos] = glyph; + + priv->cache = cache; + priv->size = size; + priv->pos = pos; + s = pos / ((GLYPH_MAX_SIZE / GLYPH_MIN_SIZE) * (GLYPH_MAX_SIZE / GLYPH_MIN_SIZE)); + priv->x = s % (CACHE_PICTURE_SIZE / GLYPH_MAX_SIZE) * GLYPH_MAX_SIZE; + priv->y = (s / (CACHE_PICTURE_SIZE / GLYPH_MAX_SIZE)) * GLYPH_MAX_SIZE; + for (s = GLYPH_MIN_SIZE; s < GLYPH_MAX_SIZE; s *= 2) { + if (pos & 1) + priv->x += s; + if (pos & 2) + priv->y += s; + pos >>= 2; + } + + uxa_glyph_cache_upload_glyph(screen, cache, glyph, priv->x, priv->y); + + *out_x = priv->x; + *out_y = priv->y; + return cache->picture; +} + +static int +uxa_glyphs_to_dst(CARD8 op, + PicturePtr pSrc, + PicturePtr pDst, + INT16 src_x, INT16 src_y, + INT16 xDst, INT16 yDst, + int nlist, GlyphListPtr list, GlyphPtr * glyphs, + BoxPtr extents) +{ + ScreenPtr screen = pDst->pDrawable->pScreen; + uxa_screen_t *uxa_screen = uxa_get_screen(screen); + PixmapPtr src_pixmap, dst_pixmap; + PicturePtr localSrc, glyph_atlas; + int x, y, n; + BoxRec box; + + if (uxa_screen->info->check_composite_texture && + uxa_screen->info->check_composite_texture(screen, pSrc)) { + if (pSrc->pDrawable) { + int src_off_x, src_off_y; + + src_pixmap = uxa_get_offscreen_pixmap(pSrc->pDrawable, &src_off_x, &src_off_y); + if (src_pixmap == NULL) + return -1; + + src_x += pSrc->pDrawable->x + src_off_x; + src_y += pSrc->pDrawable->y + src_off_y; + } else { + src_pixmap = NULL; + } + localSrc = pSrc; + } else { + int width, height; + + if (extents == NULL) { + uxa_glyph_extents(nlist, list, glyphs, &box); + extents = &box; + } + + width = extents->x2 - extents->x1; + height = extents->y2 - extents->y1; + if (width == 0 || height == 0) + return 0; + + if (pSrc->pDrawable) { + int src_off_x, src_off_y; + + src_off_x = extents->x1 - xDst; + src_off_y = extents->y1 - yDst; + localSrc = uxa_acquire_drawable(screen, pSrc, + src_x + src_off_x, src_y + src_off_y, + width, height, + &src_x, &src_y); + if (uxa_screen->info->check_composite_texture && + !uxa_screen->info->check_composite_texture(screen, localSrc)) { + if (localSrc != pSrc) + FreePicture(localSrc, 0); + return -1; + } + + src_pixmap = uxa_get_offscreen_pixmap(localSrc->pDrawable, &src_off_x, &src_off_y); + if (src_pixmap == NULL) { + if (localSrc != pSrc) + FreePicture(localSrc, 0); + return -1; + } + + src_x += localSrc->pDrawable->x + src_off_x; + src_y += localSrc->pDrawable->y + src_off_y; + } else { + localSrc = uxa_acquire_pattern(screen, pSrc, + PICT_a8r8g8b8, x, y, width, height); + if (!localSrc) + return 1; + + src_pixmap = uxa_get_drawable_pixmap(localSrc->pDrawable); + if (src_pixmap == NULL) { + FreePicture(localSrc, 0); + return -1; + } + + src_x = src_y = 0; + } + } + + dst_pixmap = uxa_get_offscreen_pixmap(pDst->pDrawable, &x, &y); + x += xDst + pDst->pDrawable->x - list->xOff; + y += yDst + pDst->pDrawable->y - list->yOff; + + glyph_atlas = NULL; + while (nlist--) { + x += list->xOff; + y += list->yOff; + n = list->len; + while (n--) { + GlyphPtr glyph = *glyphs++; + PicturePtr this_atlas; + int mask_x, mask_y, nrect; + struct uxa_glyph *priv; + BoxPtr rects; + + if (glyph->info.width == 0 || glyph->info.height == 0) + goto next_glyph; + + priv = uxa_glyph_get_private(glyph); + if (priv != NULL) { + mask_x = priv->x; + mask_y = priv->y; + this_atlas = priv->cache->picture; + } else { + if (glyph_atlas) { + uxa_screen->info->done_composite(dst_pixmap); + glyph_atlas = NULL; + } + this_atlas = uxa_glyph_cache(screen, glyph, &mask_x, &mask_y); + if (this_atlas == NULL) { + /* no cache for this glyph */ + this_atlas = GlyphPicture(glyph)[screen->myNum]; + mask_x = mask_y = 0; + } + } + + if (this_atlas != glyph_atlas) { + PixmapPtr mask_pixmap; + + if (glyph_atlas) + uxa_screen->info->done_composite(dst_pixmap); + + mask_pixmap = + uxa_get_drawable_pixmap(this_atlas->pDrawable); + assert (uxa_pixmap_is_offscreen(mask_pixmap)); + + if (!uxa_screen->info->prepare_composite(op, + localSrc, this_atlas, pDst, + src_pixmap, mask_pixmap, dst_pixmap)) + return -1; + + glyph_atlas = this_atlas; + } + + rects = REGION_RECTS(pDst->pCompositeClip); + nrect = REGION_NUM_RECTS(pDst->pCompositeClip); + while (nrect--) { + int x1 = x - glyph->info.x, dx = 0; + int y1 = y - glyph->info.y, dy = 0; + int x2 = x1 + glyph->info.width; + int y2 = y1 + glyph->info.height; + + if (rects->y1 >= y2) + break; + + if (x1 < rects->x1) + dx = rects->x1 - x1, x1 = rects->x1; + if (x2 > rects->x2) + x2 = rects->x2; + if (y1 < rects->y1) + dy = rects->y1 - y1, y1 = rects->y1; + if (y2 > rects->y2) + y2 = rects->y2; + + if (x1 < x2 && y1 < y2) { + uxa_screen->info->composite(dst_pixmap, + x1 + src_x, y1 + src_y, + dx + mask_x, dy + mask_y, + x1, y1, + x2 - x1, y2 - y1); + } + rects++; + } + +next_glyph: + x += glyph->info.xOff; + y += glyph->info.yOff; + } + list++; + } + if (glyph_atlas) + uxa_screen->info->done_composite(dst_pixmap); + + if (localSrc != pSrc) + FreePicture(localSrc, 0); + + return 0; +} + +static void +uxa_clear_pixmap(ScreenPtr screen, + uxa_screen_t *uxa_screen, + PixmapPtr pixmap) +{ + if (uxa_screen->info->check_solid && + !uxa_screen->info->check_solid(&pixmap->drawable, GXcopy, FB_ALLONES)) + goto fallback; + + if (!uxa_screen->info->prepare_solid(pixmap, GXcopy, FB_ALLONES, 0)) + goto fallback; + + uxa_screen->info->solid(pixmap, + 0, 0, + pixmap->drawable.width, + pixmap->drawable.height); + + uxa_screen->info->done_solid(pixmap); + return; + +fallback: + { + GCPtr gc; + + gc = GetScratchGC(pixmap->drawable.depth, screen); + if (gc) { + xRectangle rect; + + ValidateGC(&pixmap->drawable, gc); + + rect.x = 0; + rect.y = 0; + rect.width = pixmap->drawable.width; + rect.height = pixmap->drawable.height; + gc->ops->PolyFillRect(&pixmap->drawable, gc, 1, &rect); + + FreeScratchGC(gc); + } + } +} + +static int +uxa_glyphs_via_mask(CARD8 op, + PicturePtr pSrc, + PicturePtr pDst, + PictFormatPtr maskFormat, + INT16 xSrc, INT16 ySrc, + INT16 xDst, INT16 yDst, + int nlist, GlyphListPtr list, GlyphPtr * glyphs, + BoxPtr extents) +{ + ScreenPtr screen = pDst->pDrawable->pScreen; + uxa_screen_t *uxa_screen = uxa_get_screen(screen); + CARD32 component_alpha; + PixmapPtr pixmap; + PicturePtr glyph_atlas, mask; + int x, y, width, height; + int dst_off_x, dst_off_y; + int n, error; + BoxRec box; + + if (!extents) { + uxa_glyph_extents(nlist, list, glyphs, &box); + + if (box.x2 <= box.x1 || box.y2 <= box.y1) + return 0; + + extents = &box; + dst_off_x = box.x1; + dst_off_y = box.y1; + } else { + dst_off_x = dst_off_y = 0; + } + + width = extents->x2 - extents->x1; + height = extents->y2 - extents->y1; + x = -extents->x1; + y = -extents->y1; + + if (maskFormat->depth == 1) { + PictFormatPtr a8Format = + PictureMatchFormat(screen, 8, PICT_a8); + + if (!a8Format) + return -1; + + maskFormat = a8Format; + } + + pixmap = screen->CreatePixmap(screen, width, height, + maskFormat->depth, + CREATE_PIXMAP_USAGE_SCRATCH); + if (!pixmap) + return 1; + + uxa_clear_pixmap(screen, uxa_screen, pixmap); + + component_alpha = NeedsComponent(maskFormat->format); + mask = CreatePicture(0, &pixmap->drawable, + maskFormat, CPComponentAlpha, + &component_alpha, serverClient, &error); + screen->DestroyPixmap(pixmap); + + if (!mask) + return 1; + + ValidatePicture(mask); + + glyph_atlas = NULL; + while (nlist--) { + x += list->xOff; + y += list->yOff; + n = list->len; + while (n--) { + GlyphPtr glyph = *glyphs++; + PicturePtr this_atlas; + int src_x, src_y; + struct uxa_glyph *priv; + + if (glyph->info.width == 0 || glyph->info.height == 0) + goto next_glyph; + + priv = uxa_glyph_get_private(glyph); + if (priv != NULL) { + src_x = priv->x; + src_y = priv->y; + this_atlas = priv->cache->picture; + } else { + if (glyph_atlas) { + uxa_screen->info->done_composite(pixmap); + glyph_atlas = NULL; + } + this_atlas = uxa_glyph_cache(screen, glyph, &src_x, &src_y); + if (this_atlas == NULL) { + /* no cache for this glyph */ + this_atlas = GlyphPicture(glyph)[screen->myNum]; + src_x = src_y = 0; + } + } + + if (this_atlas != glyph_atlas) { + PixmapPtr src_pixmap; + + if (glyph_atlas) + uxa_screen->info->done_composite(pixmap); + + src_pixmap = + uxa_get_drawable_pixmap(this_atlas->pDrawable); + assert (uxa_pixmap_is_offscreen(src_pixmap)); + + if (!uxa_screen->info->prepare_composite(PictOpAdd, + this_atlas, NULL, mask, + src_pixmap, NULL, pixmap)) + return -1; + + glyph_atlas = this_atlas; + } + + uxa_screen->info->composite(pixmap, + src_x, src_y, + 0, 0, + x - glyph->info.x, + y - glyph->info.y, + glyph->info.width, + glyph->info.height); + +next_glyph: + x += glyph->info.xOff; + y += glyph->info.yOff; + } + list++; + } + if (glyph_atlas) + uxa_screen->info->done_composite(pixmap); + + uxa_composite(op, + pSrc, mask, pDst, + dst_off_x + xSrc - xDst, + dst_off_y + ySrc - yDst, + 0, 0, + dst_off_x, dst_off_y, + width, height); + + FreePicture(mask, 0); + return 0; +} + +void +uxa_glyphs(CARD8 op, + PicturePtr pSrc, + PicturePtr pDst, + PictFormatPtr maskFormat, + INT16 xSrc, INT16 ySrc, + int nlist, GlyphListPtr list, GlyphPtr * glyphs) +{ + ScreenPtr screen = pDst->pDrawable->pScreen; + uxa_screen_t *uxa_screen = uxa_get_screen(screen); + int xDst = list->xOff, yDst = list->yOff; + BoxRec extents = { 0, 0, 0, 0 }; + Bool have_extents = FALSE; + int width, height, ret; + 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; + } + + /* basic sanity check */ + if (uxa_screen->info->check_composite && + !uxa_screen->info->check_composite(op, pSrc, NULL, pDst, 0, 0)) { + goto fallback; + } + + ValidatePicture(pSrc); + ValidatePicture(pDst); + + if (!maskFormat) { + /* 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; + + for (i = 0; i < nlist; i++) { + if (maskFormat->format != list[i].format->format) { + sameFormat = FALSE; + break; + } + } + + if (!sameFormat || + uxa_glyphs_intersect(nlist, list, glyphs)) + maskFormat = NULL; + } + } + + 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 x, y, 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; + 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) { + ret = uxa_glyphs_via_mask(op, + pSrc, localDst, maskFormat, + xSrc, ySrc, + xDst, yDst, + nlist, list, glyphs, + have_extents ? &extents : NULL); + } else { + ret = uxa_glyphs_to_dst(op, + pSrc, localDst, + xSrc, ySrc, + xDst, yDst, + nlist, list, glyphs, + have_extents ? &extents : NULL); + } + if (ret) { + if (localDst != pDst) + FreePicture(localDst, 0); + + goto fallback; + } + + 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 c1f3688c..4b988f4e 100644 --- a/uxa/uxa-priv.h +++ b/uxa/uxa-priv.h @@ -41,14 +41,6 @@ #include <X11/X.h> #define NEED_EVENTS #include <X11/Xproto.h> -#ifdef MITSHM -#ifdef HAVE_XEXTPROTO_71 -#include <X11/extensions/shm.h> -#else -#define _XSHM_SERVER_ -#include <X11/extensions/shmstr.h> -#endif -#endif #include "scrnintstr.h" #include "pixmapstr.h" #include "windowstr.h" @@ -103,37 +95,13 @@ char uxa_drawable_location(DrawablePtr pDrawable); #endif typedef struct { - unsigned char sha1[20]; -} uxa_cached_glyph_t; - -typedef struct { - /* The identity of the cache, statically configured at initialization */ - unsigned int format; - int glyphWidth; - int glyphHeight; - - /* Size of cache; eventually this should be dynamically determined */ - int size; - - /* Hash table mapping from glyph sha1 to position in the glyph; we use - * open addressing with a hash table size determined based on size and large - * enough so that we always have a good amount of free space, so we can - * use linear probing. (Linear probing is preferrable to double hashing - * here because it allows us to easily remove entries.) - */ - int *hashEntries; - int hashSize; - - uxa_cached_glyph_t *glyphs; - int glyphCount; /* Current number of glyphs */ - PicturePtr picture; /* Where the glyphs of the cache are stored */ - int yOffset; /* y location within the picture where the cache starts */ - int columns; /* Number of columns the glyphs are layed out in */ - int evictionPosition; /* Next random position to evict a glyph */ + GlyphPtr *glyphs; + uint16_t count; + uint16_t evict; } uxa_glyph_cache_t; -#define UXA_NUM_GLYPH_CACHES 4 +#define UXA_NUM_GLYPH_CACHE_FORMATS 2 typedef struct { uint32_t color; @@ -156,10 +124,12 @@ typedef struct { BitmapToRegionProcPtr SavedBitmapToRegion; #ifdef RENDER CompositeProcPtr SavedComposite; + CompositeRectsProcPtr SavedCompositeRects; TrianglesProcPtr SavedTriangles; GlyphsProcPtr SavedGlyphs; TrapezoidsProcPtr SavedTrapezoids; AddTrapsProcPtr SavedAddTraps; + UnrealizeGlyphProcPtr SavedUnrealizeGlyph; #endif EnableDisableFBAccessProcPtr SavedEnableDisableFBAccess; @@ -168,7 +138,7 @@ typedef struct { unsigned disableFbCount; unsigned offScreenCounter; - uxa_glyph_cache_t glyphCaches[UXA_NUM_GLYPH_CACHES]; + uxa_glyph_cache_t glyphCaches[UXA_NUM_GLYPH_CACHE_FORMATS]; PicturePtr solid_clear, solid_black, solid_white; uxa_solid_cache_t solid_cache[UXA_NUM_SOLID_CACHE]; @@ -187,11 +157,19 @@ typedef struct { (PixmapWidthPaddingInfo[d].padRoundUp+1))) #endif +#if HAS_DEVPRIVATEKEYREC +extern DevPrivateKeyRec uxa_screen_index; +#else extern int uxa_screen_index; +#endif + static inline uxa_screen_t *uxa_get_screen(ScreenPtr screen) { - return (uxa_screen_t *) dixLookupPrivate(&screen->devPrivates, - &uxa_screen_index); +#if HAS_DEVPRIVATEKEYREC + return dixGetPrivate(&screen->devPrivates, &uxa_screen_index); +#else + return dixLookupPrivate(&screen->devPrivates, &uxa_screen_index); +#endif } /** Align an offset to an arbitrary alignment */ @@ -307,11 +285,6 @@ Bool uxa_fill_region_tiled(DrawablePtr pDrawable, RegionPtr pRegion, PixmapPtr pTile, DDXPointPtr pPatOrg, CARD32 planemask, CARD32 alu); -void -uxa_shm_put_image(DrawablePtr pDrawable, GCPtr pGC, int depth, - unsigned int format, int w, int h, int sx, int sy, int sw, - int sh, int dx, int dy, char *data); - void uxa_paint_window(WindowPtr pWin, RegionPtr pRegion, int what); void @@ -320,24 +293,6 @@ uxa_get_image(DrawablePtr pDrawable, int x, int y, int w, int h, extern const GCOps uxa_ops; -#ifdef MITSHM -/* XXX these come from shmint.h, which isn't exported by the server */ - -#ifdef HAVE_XEXTPROTO_71 -#include "shmint.h" -#else - -void ShmRegisterFuncs(ScreenPtr pScreen, ShmFuncsPtr funcs); - -void ShmSetPixmapFormat(ScreenPtr pScreen, int format); - -void fbShmPutImage(XSHM_PUT_IMAGE_ARGS); -#endif - -extern ShmFuncs uxa_shm_funcs; - -#endif - #ifdef RENDER /* XXX these are in fbpict.h, which is not installed */ @@ -417,6 +372,13 @@ uxa_composite_rects(CARD8 op, PicturePtr pDst, int nrect, uxa_composite_rect_t * rects); void +uxa_solid_rects (CARD8 op, + PicturePtr dst, + xRenderColor *color, + int num_rects, + xRectangle *rects); + +void uxa_trapezoids(CARD8 op, PicturePtr pSrc, PicturePtr pDst, PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, int ntrap, xTrapezoid * traps); @@ -426,8 +388,33 @@ 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); +Bool uxa_glyphs_init(ScreenPtr pScreen); void uxa_glyphs_fini(ScreenPtr pScreen); @@ -439,4 +426,8 @@ uxa_glyphs(CARD8 op, INT16 xSrc, INT16 ySrc, int nlist, GlyphListPtr list, GlyphPtr * glyphs); +void +uxa_glyph_unrealize(ScreenPtr pScreen, + GlyphPtr pGlyph); + #endif /* UXAPRIV_H */ diff --git a/uxa/uxa-render.c b/uxa/uxa-render.c index 30934d0d..056b60a4 100644 --- a/uxa/uxa-render.c +++ b/uxa/uxa-render.c @@ -85,29 +85,88 @@ static void uxa_composite_fallback_pict_desc(PicturePtr pict, char *string, pict->alphaMap ? " with alpha map" :""); } +static const char * +op_to_string(CARD8 op) +{ + switch (op) { +#define C(x) case PictOp##x: return #x + C(Clear); + C(Src); + C(Dst); + C(Over); + C(OverReverse); + C(In); + C(InReverse); + C(Out); + C(OutReverse); + C(Atop); + C(AtopReverse); + C(Xor); + C(Add); + C(Saturate); + + /* + * Operators only available in version 0.2 + */ + C(DisjointClear); + C(DisjointSrc); + C(DisjointDst); + C(DisjointOver); + C(DisjointOverReverse); + C(DisjointIn); + C(DisjointInReverse); + C(DisjointOut); + C(DisjointOutReverse); + C(DisjointAtop); + C(DisjointAtopReverse); + C(DisjointXor); + + C(ConjointClear); + C(ConjointSrc); + C(ConjointDst); + C(ConjointOver); + C(ConjointOverReverse); + C(ConjointIn); + C(ConjointInReverse); + C(ConjointOut); + C(ConjointOutReverse); + C(ConjointAtop); + C(ConjointAtopReverse); + C(ConjointXor); + + /* + * Operators only available in version 0.11 + */ + C(Multiply); + C(Screen); + C(Overlay); + C(Darken); + C(Lighten); + C(ColorDodge); + C(ColorBurn); + C(HardLight); + C(SoftLight); + C(Difference); + C(Exclusion); + C(HSLHue); + C(HSLSaturation); + C(HSLColor); + C(HSLLuminosity); + default: return "garbage"; +#undef C + } +} + static void uxa_print_composite_fallback(const char *func, CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst) { uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen); - char sop[20]; char srcdesc[40], maskdesc[40], dstdesc[40]; if (! uxa_screen->fallback_debug) return; - switch (op) { - case PictOpSrc: - sprintf(sop, "Src"); - break; - case PictOpOver: - sprintf(sop, "Over"); - break; - default: - sprintf(sop, "0x%x", (int)op); - break; - } - uxa_composite_fallback_pict_desc(pSrc, srcdesc, 40); uxa_composite_fallback_pict_desc(pMask, maskdesc, 40); uxa_composite_fallback_pict_desc(pDst, dstdesc, 40); @@ -118,7 +177,7 @@ uxa_print_composite_fallback(const char *func, CARD8 op, " mask %s, \n" " dst %s, \n" " screen %s\n", - func, sop, srcdesc, maskdesc, dstdesc, + func, op_to_string (op), srcdesc, maskdesc, dstdesc, uxa_screen->swappedOut ? "swapped out" : "normal"); } @@ -182,7 +241,7 @@ uxa_get_pixel_from_rgba(CARD32 * pixel, return TRUE; } -static Bool +Bool uxa_get_rgba_from_pixel(CARD32 pixel, CARD16 * red, CARD16 * green, @@ -290,7 +349,12 @@ uxa_try_driver_solid_fill(PicturePtr pSrc, PixmapPtr pSrcPix = NULL, pDstPix; CARD32 pixel; - pDstPix = uxa_get_drawable_pixmap(pDst->pDrawable); + if (uxa_screen->info->check_solid && !uxa_screen->info->check_solid(pDst->pDrawable, GXcopy, FB_ALLONES)) + return -1; + + pDstPix = uxa_get_offscreen_pixmap(pDst->pDrawable, &dst_off_x, &dst_off_y); + if (!pDstPix) + return -1; xDst += pDst->pDrawable->x; yDst += pDst->pDrawable->y; @@ -306,16 +370,6 @@ uxa_try_driver_solid_fill(PicturePtr pSrc, width, height)) return 1; - uxa_get_drawable_deltas(pDst->pDrawable, pDstPix, &dst_off_x, - &dst_off_y); - - REGION_TRANSLATE(pScreen, ®ion, dst_off_x, dst_off_y); - - if (!uxa_pixmap_is_offscreen(pDstPix)) { - REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); - return 0; - } - if (pSrcPix) { if (! uxa_get_color_for_pixmap (pSrcPix, pSrc->format, pDst->format, &pixel)) { REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); @@ -334,11 +388,13 @@ uxa_try_driver_solid_fill(PicturePtr pSrc, } if (!(*uxa_screen->info->prepare_solid) - (pDstPix, GXcopy, 0xffffffff, pixel)) { + (pDstPix, GXcopy, FB_ALLONES, pixel)) { REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); return -1; } + REGION_TRANSLATE(pScreen, ®ion, dst_off_x, dst_off_y); + nbox = REGION_NUM_RECTS(®ion); pbox = REGION_RECTS(®ion); @@ -391,74 +447,84 @@ uxa_picture_for_pixman_format(ScreenPtr pScreen, } static PicturePtr -uxa_picture_from_pixman_image(ScreenPtr pScreen, +uxa_picture_from_pixman_image(ScreenPtr screen, pixman_image_t * image, pixman_format_code_t format) { - PicturePtr pPicture; - PixmapPtr pPixmap; + uxa_screen_t *uxa_screen = uxa_get_screen(screen); + PicturePtr picture; + PixmapPtr pixmap; int width, height; width = pixman_image_get_width(image); height = pixman_image_get_height(image); - pPicture = uxa_picture_for_pixman_format(pScreen, format, - width, height); - if (!pPicture) + picture = uxa_picture_for_pixman_format(screen, format, + width, height); + if (!picture) return 0; - pPixmap = GetScratchPixmapHeader(pScreen, width, height, - PIXMAN_FORMAT_DEPTH(format), - PIXMAN_FORMAT_BPP(format), - pixman_image_get_stride(image), - pixman_image_get_data(image)); - if (!pPixmap) { - FreePicture(pPicture, 0); + if (uxa_screen->info->put_image && + ((picture->pDrawable->depth << 24) | picture->format) == format && + uxa_screen->info->put_image((PixmapPtr)picture->pDrawable, + 0, 0, + width, height, + (char *)pixman_image_get_data(image), + pixman_image_get_stride(image))) + return picture; + + pixmap = GetScratchPixmapHeader(screen, width, height, + PIXMAN_FORMAT_DEPTH(format), + PIXMAN_FORMAT_BPP(format), + pixman_image_get_stride(image), + pixman_image_get_data(image)); + if (!pixmap) { + FreePicture(picture, 0); return 0; } - if (((pPicture->pDrawable->depth << 24) | pPicture->format) == format) { - GCPtr pGC; + if (((picture->pDrawable->depth << 24) | picture->format) == format) { + GCPtr gc; - pGC = GetScratchGC(PIXMAN_FORMAT_DEPTH(format), pScreen); - if (!pGC) { - FreeScratchPixmapHeader(pPixmap); - FreePicture(pPicture, 0); - return 0; - } - ValidateGC(pPicture->pDrawable, pGC); + gc = GetScratchGC(PIXMAN_FORMAT_DEPTH(format), screen); + if (!gc) { + FreeScratchPixmapHeader(pixmap); + FreePicture(picture, 0); + return 0; + } + ValidateGC(picture->pDrawable, gc); - (*pGC->ops->CopyArea) (&pPixmap->drawable, pPicture->pDrawable, - pGC, 0, 0, width, height, 0, 0); + (*gc->ops->CopyArea) (&pixmap->drawable, picture->pDrawable, + gc, 0, 0, width, height, 0, 0); - FreeScratchGC(pGC); + FreeScratchGC(gc); } else { - PicturePtr pSrc; - int error; - - pSrc = CreatePicture(0, &pPixmap->drawable, - PictureMatchFormat(pScreen, - PIXMAN_FORMAT_DEPTH(format), - format), - 0, 0, serverClient, &error); - if (!pSrc) { - FreeScratchPixmapHeader(pPixmap); - FreePicture(pPicture, 0); - return 0; - } - ValidatePicture(pSrc); + PicturePtr src; + int error; + + src = CreatePicture(0, &pixmap->drawable, + PictureMatchFormat(screen, + PIXMAN_FORMAT_DEPTH(format), + format), + 0, 0, serverClient, &error); + if (!src) { + FreeScratchPixmapHeader(pixmap); + FreePicture(picture, 0); + return 0; + } + ValidatePicture(src); - if (uxa_prepare_access(pPicture->pDrawable, UXA_ACCESS_RW)) { - fbComposite(PictOpSrc, pSrc, NULL, pPicture, - 0, 0, 0, 0, 0, 0, width, height); - uxa_finish_access(pPicture->pDrawable); - } + if (uxa_prepare_access(picture->pDrawable, UXA_ACCESS_RW)) { + fbComposite(PictOpSrc, src, NULL, picture, + 0, 0, 0, 0, 0, 0, width, height); + uxa_finish_access(picture->pDrawable); + } - FreePicture(pSrc, 0); + FreePicture(src, 0); } - FreeScratchPixmapHeader(pPixmap); + FreeScratchPixmapHeader(pixmap); - return pPicture; + return picture; } static PicturePtr @@ -490,6 +556,21 @@ uxa_create_solid(ScreenPtr screen, uint32_t color) } static PicturePtr +uxa_solid_clear(ScreenPtr screen) +{ + uxa_screen_t *uxa_screen = uxa_get_screen(screen); + PicturePtr picture; + + if (!uxa_screen->solid_clear) { + uxa_screen->solid_clear = uxa_create_solid(screen, 0); + if (!uxa_screen->solid_clear) + return 0; + } + picture = uxa_screen->solid_clear; + return picture; +} + +PicturePtr uxa_acquire_solid(ScreenPtr screen, SourcePict *source) { uxa_screen_t *uxa_screen = uxa_get_screen(screen); @@ -498,12 +579,10 @@ uxa_acquire_solid(ScreenPtr screen, SourcePict *source) int i; if ((solid->color >> 24) == 0) { - if (!uxa_screen->solid_clear) { - uxa_screen->solid_clear = uxa_create_solid(screen, 0); - if (!uxa_screen->solid_clear) - return 0; - } - picture = uxa_screen->solid_clear; + picture = uxa_solid_clear(screen); + if (!picture) + return 0; + goto DONE; } else if (solid->color == 0xff000000) { if (!uxa_screen->solid_black) { @@ -548,7 +627,7 @@ DONE: return picture; } -static PicturePtr +PicturePtr uxa_acquire_pattern(ScreenPtr pScreen, PicturePtr pSrc, pixman_format_code_t format, @@ -577,158 +656,398 @@ uxa_acquire_pattern(ScreenPtr pScreen, } } -static PicturePtr -uxa_acquire_source(ScreenPtr pScreen, - PicturePtr pPict, - INT16 x, INT16 y, - CARD16 width, CARD16 height, INT16 * out_x, INT16 * out_y) +static Bool +transform_is_integer_translation(PictTransformPtr t, int *tx, int *ty) { - if (pPict->pDrawable) { - *out_x = x + pPict->pDrawable->x; - *out_y = y + pPict->pDrawable->y; - return pPict; + if (t == NULL) { + *tx = *ty = 0; + return TRUE; } - *out_x = 0; - *out_y = 0; - return uxa_acquire_pattern(pScreen, pPict, - PICT_a8r8g8b8, x, y, width, height); + if (t->matrix[0][0] != IntToxFixed(1) || + t->matrix[0][1] != 0 || + t->matrix[1][0] != 0 || + t->matrix[1][1] != IntToxFixed(1) || + t->matrix[2][0] != 0 || + t->matrix[2][1] != 0 || + t->matrix[2][2] != IntToxFixed(1)) + return FALSE; + + if (xFixedFrac(t->matrix[0][2]) != 0 || + xFixedFrac(t->matrix[1][2]) != 0) + return FALSE; + + *tx = xFixedToInt(t->matrix[0][2]); + *ty = xFixedToInt(t->matrix[1][2]); + return TRUE; } static PicturePtr -uxa_acquire_mask(ScreenPtr pScreen, - PicturePtr pPict, - INT16 x, INT16 y, - INT16 width, INT16 height, INT16 * out_x, INT16 * out_y) +uxa_render_picture(ScreenPtr screen, + PicturePtr src, + pixman_format_code_t format, + INT16 x, INT16 y, + CARD16 width, CARD16 height) { - if (pPict->pDrawable) { - *out_x = x + pPict->pDrawable->x; - *out_y = y + pPict->pDrawable->y; - return pPict; + PicturePtr picture; + int ret = 0; + + /* XXX we need a mechanism for the card to choose the fallback format */ + + /* force alpha channel in case source does not entirely cover the extents */ + if (PIXMAN_FORMAT_A(format) == 0) + format = PIXMAN_a8r8g8b8; /* available on all hardware */ + + picture = uxa_picture_for_pixman_format(screen, format, width, height); + if (!picture) + return 0; + + if (uxa_prepare_access(picture->pDrawable, UXA_ACCESS_RW)) { + if (uxa_prepare_access(src->pDrawable, UXA_ACCESS_RO)) { + ret = 1; + fbComposite(PictOpSrc, src, NULL, picture, + x, y, 0, 0, 0, 0, width, height); + uxa_finish_access(src->pDrawable); + } + uxa_finish_access(picture->pDrawable); } - *out_x = 0; - *out_y = 0; - return uxa_acquire_pattern(pScreen, pPict, - PICT_a8, x, y, width, height); + if (!ret) { + FreePicture(picture, 0); + return 0; + } + + return picture; } static int -uxa_try_driver_composite_rects(CARD8 op, - PicturePtr pSrc, - PicturePtr pDst, - int nrect, uxa_composite_rect_t * rects) +drawable_contains (DrawablePtr drawable, int x, int y, int w, int h) { - 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 (x < 0 || y < 0) + return FALSE; - if (!uxa_screen->info->prepare_composite || uxa_screen->swappedOut) - return -1; + if (x + w > drawable->width) + return FALSE; - if (uxa_screen->info->check_composite && - !(*uxa_screen->info->check_composite) (op, pSrc, NULL, pDst)) { - return -1; + if (y + h > drawable->height) + return FALSE; + + return TRUE; +} + +PicturePtr +uxa_acquire_drawable(ScreenPtr pScreen, + PicturePtr pSrc, + INT16 x, INT16 y, + CARD16 width, CARD16 height, + INT16 * out_x, INT16 * out_y) +{ + PixmapPtr pPixmap; + PicturePtr pDst; + int depth, error; + int tx, ty; + GCPtr pGC; + + depth = pSrc->pDrawable->depth; + if (!transform_is_integer_translation(pSrc->transform, &tx, &ty) || + !drawable_contains(pSrc->pDrawable, x + tx, y + ty, width, height) || + depth == 1 || + pSrc->filter == PictFilterConvolution) { + /* XXX extract the sample extents and do the transformation on the GPU */ + pDst = uxa_render_picture(pScreen, pSrc, + pSrc->format | (BitsPerPixel(pSrc->pDrawable->depth) << 24), + x, y, width, height); + + goto done; + } else { + if (width == pSrc->pDrawable->width && height == pSrc->pDrawable->height) { + *out_x = x + pSrc->pDrawable->x; + *out_y = y + pSrc->pDrawable->y; + return pSrc; + } } - pDstPix = - uxa_get_offscreen_pixmap(pDst->pDrawable, &dst_off_x, &dst_off_y); - if (!pDstPix) + pPixmap = pScreen->CreatePixmap(pScreen, + width, height, depth, + CREATE_PIXMAP_USAGE_SCRATCH); + if (!pPixmap) return 0; - pSrcPix = - uxa_get_offscreen_pixmap(pSrc->pDrawable, &src_off_x, &src_off_y); - if (!pSrcPix) + /* Skip the copy if the result remains in memory and not a bo */ + if (!uxa_pixmap_is_offscreen(pPixmap)) { + pScreen->DestroyPixmap(pPixmap); return 0; + } - if (!(*uxa_screen->info->prepare_composite) - (op, pSrc, NULL, pDst, pSrcPix, NULL, pDstPix)) - return -1; + pGC = GetScratchGC(depth, pScreen); + if (!pGC) { + pScreen->DestroyPixmap(pPixmap); + return 0; + } + + ValidateGC(&pPixmap->drawable, pGC); + pGC->ops->CopyArea(pSrc->pDrawable, &pPixmap->drawable, pGC, + x + tx, y + ty, width, height, 0, 0); + FreeScratchGC(pGC); + + pDst = CreatePicture(0, &pPixmap->drawable, + PictureMatchFormat(pScreen, depth, pSrc->format), + 0, 0, serverClient, &error); + pScreen->DestroyPixmap(pPixmap); + ValidatePicture(pDst); + +done: + pDst->componentAlpha = pSrc->componentAlpha; + *out_x = 0; + *out_y = 0; + return pDst; +} - 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++; +static PicturePtr +uxa_acquire_picture(ScreenPtr screen, + PicturePtr src, + pixman_format_code_t format, + INT16 x, INT16 y, + CARD16 width, CARD16 height, + INT16 * out_x, INT16 * out_y) +{ + uxa_screen_t *uxa_screen = uxa_get_screen(screen); + + 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; + } -next_rect: - REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); + if (src->pDrawable) { + PicturePtr dst; - rects++; + dst = uxa_acquire_drawable(screen, src, + x, y, width, height, + out_x, out_y); + if (!dst) + return 0; + + 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; } - (*uxa_screen->info->done_composite) (pDstPix); - return 1; + *out_x = 0; + *out_y = 0; + return uxa_acquire_pattern(screen, src, + format, x, y, width, height); +} + +static PicturePtr +uxa_acquire_source(ScreenPtr screen, + PicturePtr pict, + INT16 x, INT16 y, + CARD16 width, CARD16 height, + INT16 * out_x, INT16 * out_y) +{ + return uxa_acquire_picture (screen, pict, + PICT_a8r8g8b8, + x, y, + width, height, + out_x, out_y); +} + +static PicturePtr +uxa_acquire_mask(ScreenPtr screen, + PicturePtr pict, + INT16 x, INT16 y, + INT16 width, INT16 height, + INT16 * out_x, INT16 * out_y) +{ + return uxa_acquire_picture (screen, pict, + PICT_a8, + x, y, + width, height, + out_x, out_y); +} + +static Bool +_pixman_region_init_rectangles(pixman_region16_t *region, + int num_rects, + xRectangle *rects, + int tx, int ty) +{ + pixman_box16_t stack_boxes[64], *boxes = stack_boxes; + pixman_bool_t ret; + int i; + + if (num_rects > sizeof(stack_boxes) / sizeof(stack_boxes[0])) { + boxes = malloc(sizeof(pixman_box16_t) * num_rects); + if (boxes == NULL) + return FALSE; + } + + for (i = 0; i < num_rects; i++) { + boxes[i].x1 = rects[i].x + tx; + boxes[i].y1 = rects[i].y + ty; + boxes[i].x2 = rects[i].x + tx + rects[i].width; + boxes[i].y2 = rects[i].y + ty + rects[i].height; + } + + ret = pixman_region_init_rects(region, boxes, num_rects); + + if (boxes != stack_boxes) + free(boxes); + + return ret; } -/** - * 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) +uxa_solid_rects (CARD8 op, + PicturePtr dst, + xRenderColor *color, + int num_rects, + xRectangle *rects) { - int n; - uxa_composite_rect_t *r; + ScreenPtr screen = dst->pDrawable->pScreen; + uxa_screen_t *uxa_screen = uxa_get_screen(screen); + PixmapPtr dst_pixmap, src_pixmap = NULL; + pixman_region16_t region; + pixman_box16_t *boxes, *extents; + PicturePtr src; + int dst_x, dst_y; + int num_boxes; + + if (!pixman_region_not_empty(dst->pCompositeClip)) + return; - /************************************************************/ + if (dst->alphaMap) + goto fallback; - ValidatePicture(pSrc); - ValidatePicture(pDst); + dst_pixmap = uxa_get_offscreen_pixmap(dst->pDrawable, &dst_x, &dst_y); + if (!dst_pixmap) + goto fallback; + + if (!_pixman_region_init_rectangles(®ion, + num_rects, rects, + dst->pDrawable->x, dst->pDrawable->y)) + goto fallback; + + if (!pixman_region_intersect(®ion, ®ion, dst->pCompositeClip)) { + pixman_region_fini(®ion); + return; + } + + /* XXX xserver-1.8: CompositeRects is not tracked by Damage, so we must + * manually append the damaged regions ourselves. + */ + DamageRegionAppend(dst->pDrawable, ®ion); + + 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; + if (color->alpha >= 0xff00 && op == PictOpOver) { + color->alpha = 0xffff; + op = PictOpSrc; + } + + /* Using GEM, the relocation costs outweigh the advantages of the blitter */ + 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 (!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; + + 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 { + int error; + + src = CreateSolidPicture(0, color, &error); + if (!src) + goto err_region; + + 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_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++; + 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) + goto err_src; } + + if (!uxa_screen->info->prepare_composite(op, src, NULL, dst, src_pixmap, NULL, dst_pixmap)) + goto err_src; + + while (num_boxes--) { + uxa_screen->info->composite(dst_pixmap, + 0, 0, 0, 0, + boxes->x1, + boxes->y1, + boxes->x2 - boxes->x1, + boxes->y2 - boxes->y1); + boxes++; + } + + uxa_screen->info->done_composite(dst_pixmap); + FreePicture(src, 0); } - /************************************************************/ + pixman_region_fini(®ion); + return; +err_src: + FreePicture(src, 0); +err_region: + pixman_region_fini(®ion); +fallback: + uxa_screen->SavedCompositeRects(op, dst, color, num_rects, rects); } static int @@ -736,130 +1055,217 @@ uxa_try_driver_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); + 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; - xDst += pDst->pDrawable->x; - yDst += pDst->pDrawable->y; + if (uxa_screen->info->check_composite && + !(*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); - localSrc = uxa_acquire_source(pDst->pDrawable->pScreen, - pSrc, xSrc, ySrc, width, height, + 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(localDst->pDrawable, &dst_off_x, &dst_off_y); + if (!pDstPix) { + if (localDst != pDst) + FreePicture(localDst, 0); + return -1; + } + + xDst += localDst->pDrawable->x; + yDst += localDst->pDrawable->y; + + 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, xMask, yMask, width, height, + 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 (uxa_screen->info->check_composite && - !(*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, 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; } - pDstPix = - uxa_get_offscreen_pixmap(pDst->pDrawable, &dst_off_x, &dst_off_y); + if (localSrc->pDrawable) { + pSrcPix = uxa_get_offscreen_pixmap(localSrc->pDrawable, + &src_off_x, &src_off_y); + if (!pSrcPix) { + REGION_UNINIT(screen, ®ion); - pSrcPix = uxa_get_offscreen_pixmap(localSrc->pDrawable, - &src_off_x, &src_off_y); + if (localSrc != pSrc) + FreePicture(localSrc, 0); + if (localMask && localMask != pMask) + FreePicture(localMask, 0); + if (localDst != pDst) + FreePicture(localDst, 0); - if (localMask) - pMaskPix = uxa_get_offscreen_pixmap(localMask->pDrawable, - &mask_off_x, &mask_off_y); + return 0; + } + } else { + pSrcPix = NULL; + } - if (!pDstPix || !pSrcPix || (localMask && !pMaskPix)) { - REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); + if (localMask) { + if (localMask->pDrawable) { + pMaskPix = uxa_get_offscreen_pixmap(localMask->pDrawable, + &mask_off_x, &mask_off_y); + if (!pMaskPix) { + REGION_UNINIT(screen, ®ion); - if (localSrc != pSrc) - FreePicture(localSrc, 0); - if (localMask && localMask != pMask) - FreePicture(localMask, 0); + if (localSrc != pSrc) + FreePicture(localSrc, 0); + if (localMask && localMask != pMask) + FreePicture(localMask, 0); + if (localDst != pDst) + FreePicture(localDst, 0); - return 0; + return 0; + } + } else { + pMaskPix = NULL; + } } - 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; } @@ -917,36 +1323,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; } @@ -958,99 +1428,113 @@ compatible_formats (CARD8 op, PicturePtr dst, PicturePtr src) if (src->format == dst->format) return 1; - if (src->format == PICT_a8r8g8b8 && dst->format == PICT_x8r8g8b8) + /* Is the destination an alpha-less version of source? */ + if (dst->format == PICT_FORMAT(PICT_FORMAT_BPP(src->format), + PICT_FORMAT_TYPE(src->format), + 0, + PICT_FORMAT_R(src->format), + PICT_FORMAT_G(src->format), + PICT_FORMAT_B(src->format))) return 1; - if (src->format == PICT_a8b8g8r8 && dst->format == PICT_x8b8g8r8) - return 1; - - /* xrgb is promoted to argb during image upload... */ + /* XXX xrgb is promoted to argb during image upload... */ +#if 0 if (dst->format == PICT_a8r8g8b8 && src->format == PICT_x8r8g8b8) return 1; +#endif } else if (op == PictOpOver) { - if (src->alphaMap || dst->alphaMap) - return 0; - - if (src->format != dst->format) + if (PICT_FORMAT_A(src->format)) return 0; - if (src->format == PICT_x8r8g8b8 || src->format == PICT_x8b8g8r8) - return 1; + return src->format == dst->format; } return 0; } -static int -drawable_contains (DrawablePtr drawable, int x1, int y1, int x2, int y2) -{ - if (x1 < 0 || y1 < 0) - return FALSE; - - if (x2 > drawable->width) - return FALSE; - - if (y2 > drawable->height) - return FALSE; - - return TRUE; -} - void 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; Bool saveSrcRepeat = pSrc->repeat; Bool saveMaskRepeat = pMask ? pMask->repeat : 0; RegionRec region; + int tx, ty; if (uxa_screen->swappedOut) goto fallback; + 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->transform && + if (pSrc->pDrawable && pSrc->repeat && pSrc->filter != PictFilterConvolution && + transform_is_integer_translation(pSrc->transform, &tx, &ty) && (pSrc->pDrawable->width > 1 || pSrc->pDrawable->height > 1) && - xSrc >= 0 && (xSrc + width) <= pSrc->pDrawable->width && - ySrc >= 0 && (ySrc + height) <= pSrc->pDrawable->height) + drawable_contains(pSrc->pDrawable, xSrc + tx, ySrc + ty, width, height)) pSrc->repeat = 0; if (!pMask) { + if (op == PictOpClear) { + PicturePtr clear = uxa_solid_clear(pDst->pDrawable->pScreen); + if (clear && + uxa_try_driver_solid_fill(clear, pDst, + xSrc, ySrc, + xDst, yDst, + width, height) == 1) + goto done; + } + if (pSrc->pDrawable == NULL) { if (pSrc->pSourcePict) { SourcePict *source = pSrc->pSourcePict; if (source->type == SourcePictTypeSolidFill) { - ret = uxa_try_driver_solid_fill(pSrc, pDst, - xSrc, ySrc, - xDst, yDst, - width, height); - if (ret == 1) - goto done; + if (op == PictOpSrc || + (op == PictOpOver && + (source->solidFill.color & 0xff000000) == 0xff000000)) { + ret = uxa_try_driver_solid_fill(pSrc, pDst, + xSrc, ySrc, + xDst, yDst, + width, height); + if (ret == 1) + goto done; + } } } - } else if (compatible_formats (op, pDst, pSrc)) { - if (pSrc->pDrawable->width == 1 && - pSrc->pDrawable->height == 1 && - pSrc->repeat) { - ret = uxa_try_driver_solid_fill(pSrc, pDst, - xSrc, ySrc, - xDst, yDst, - width, height); - if (ret == 1) - goto done; - } else if (!pSrc->repeat && !pSrc->transform && - drawable_contains(pSrc->pDrawable, xSrc, ySrc, xSrc + width, ySrc + height)) { + } else if (pSrc->pDrawable->width == 1 && + pSrc->pDrawable->height == 1 && + pSrc->repeat && + (op == PictOpSrc || (op == PictOpOver && !PICT_FORMAT_A(pSrc->format)))) { + ret = uxa_try_driver_solid_fill(pSrc, pDst, + xSrc, ySrc, + xDst, yDst, + width, height); + if (ret == 1) + goto done; + } else if (compatible_formats (op, pDst, pSrc) && + pSrc->filter != PictFilterConvolution && + transform_is_integer_translation(pSrc->transform, &tx, &ty)) { + if (!pSrc->repeat && + drawable_contains(pSrc->pDrawable, + xSrc + tx, ySrc + ty, + width, height)) { xDst += pDst->pDrawable->x; yDst += pDst->pDrawable->y; - xSrc += pSrc->pDrawable->x; - ySrc += pSrc->pDrawable->y; + xSrc += pSrc->pDrawable->x + tx; + ySrc += pSrc->pDrawable->y + ty; if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst, xSrc, ySrc, @@ -1066,16 +1550,14 @@ uxa_composite(CARD8 op, REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); goto done; - } else if (pSrc->pDrawable->type == DRAWABLE_PIXMAP && - !pSrc->transform && - pSrc->repeatType == RepeatNormal) { + } else if (pSrc->repeat && pSrc->repeatType == RepeatNormal && + pSrc->pDrawable->type == DRAWABLE_PIXMAP) { DDXPointRec patOrg; /* Let's see if the driver can do the repeat * in one go */ - if (uxa_screen->info->prepare_composite - && !pSrc->alphaMap && !pDst->alphaMap) { + if (uxa_screen->info->prepare_composite) { ret = uxa_try_driver_composite(op, pSrc, pMask, pDst, xSrc, ySrc, @@ -1091,8 +1573,8 @@ uxa_composite(CARD8 op, */ xDst += pDst->pDrawable->x; yDst += pDst->pDrawable->y; - xSrc += pSrc->pDrawable->x; - ySrc += pSrc->pDrawable->y; + xSrc += pSrc->pDrawable->x + tx; + ySrc += pSrc->pDrawable->y + ty; if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst, xSrc, ySrc, @@ -1121,15 +1603,14 @@ uxa_composite(CARD8 op, } /* Remove repeat in mask if useless */ - if (pMask && pMask->repeat && !pMask->transform && pMask->pDrawable && + if (pMask && pMask->pDrawable && pMask->repeat && + pMask->filter != PictFilterConvolution && + transform_is_integer_translation(pMask->transform, &tx, &ty) && (pMask->pDrawable->width > 1 || pMask->pDrawable->height > 1) && - xMask >= 0 && (xMask + width) <= pMask->pDrawable->width && - yMask >= 0 && (yMask + height) <= pMask->pDrawable->height) + drawable_contains(pMask->pDrawable, xMask + tx, yMask + ty, width, height)) pMask->repeat = 0; - if (uxa_screen->info->prepare_composite && - !pSrc->alphaMap && (!pMask || !pMask->alphaMap) && !pDst->alphaMap) - { + if (uxa_screen->info->prepare_composite) { Bool isSrcSolid; ret = @@ -1142,9 +1623,15 @@ 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 && - pSrc->pDrawable->width == 1 && - pSrc->pDrawable->height == 1 && pSrc->repeat; + + isSrcSolid = + pSrc->pDrawable ? + pSrc->pDrawable->width == 1 && + pSrc->pDrawable->height == 1 && + pSrc->repeat : + pSrc->pSourcePict ? + pSrc->pSourcePict->type == SourcePictTypeSolidFill : + 0; /* If we couldn't do the Composite in a single pass, and it * was a component-alpha Over, see if we can do it in two @@ -1156,13 +1643,13 @@ uxa_composite(CARD8 op, uxa_try_magic_two_pass_composite_helper(op, pSrc, pMask, pDst, xSrc, ySrc, - xMask, - yMask, xDst, - yDst, width, - height); + xMask, yMask, + xDst, yDst, + width, height); if (ret == 1) goto done; } + } fallback: @@ -1232,15 +1719,15 @@ uxa_create_alpha_picture(ScreenPtr pScreen, * uxa_check_poly_fill_rect to initialize the contents. */ void -uxa_trapezoids(CARD8 op, PicturePtr pSrc, PicturePtr pDst, +uxa_trapezoids(CARD8 op, PicturePtr src, PicturePtr dst, PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, int ntrap, xTrapezoid * traps) { - ScreenPtr pScreen = pDst->pDrawable->pScreen; - PictureScreenPtr ps = GetPictureScreen(pScreen); + ScreenPtr screen = dst->pDrawable->pScreen; BoxRec bounds; - Bool direct = op == PictOpAdd && miIsSolidAlpha(pSrc); + Bool direct; + direct = op == PictOpAdd && miIsSolidAlpha(src); if (maskFormat || direct) { miTrapezoidBounds(ntrap, traps, &bounds); @@ -1252,7 +1739,7 @@ uxa_trapezoids(CARD8 op, PicturePtr pSrc, PicturePtr pDst, * Check for solid alpha add */ if (direct) { - DrawablePtr pDraw = pDst->pDrawable; + DrawablePtr pDraw = dst->pDrawable; PixmapPtr pixmap = uxa_get_drawable_pixmap(pDraw); int xoff, yoff; @@ -1262,12 +1749,15 @@ uxa_trapezoids(CARD8 op, PicturePtr pSrc, PicturePtr pDst, yoff += pDraw->y; if (uxa_prepare_access(pDraw, UXA_ACCESS_RW)) { + PictureScreenPtr ps = GetPictureScreen(screen); + for (; ntrap; ntrap--, traps++) - (*ps->RasterizeTrapezoid) (pDst, traps, 0, 0); + (*ps->RasterizeTrapezoid) (dst, traps, 0, 0); uxa_finish_access(pDraw); } } else if (maskFormat) { - PicturePtr pPicture; + PixmapPtr scratch = NULL; + PicturePtr mask; INT16 xDst, yDst; INT16 xRel, yRel; int width, height; @@ -1291,28 +1781,48 @@ uxa_trapezoids(CARD8 op, PicturePtr pSrc, PicturePtr pDst, pixman_rasterize_trapezoid(image, (pixman_trapezoid_t *) traps, -bounds.x1, -bounds.y1); - - pPicture = - uxa_picture_from_pixman_image(pScreen, image, format); - pixman_image_unref(image); - if (!pPicture) + if (uxa_drawable_is_offscreen(dst->pDrawable)) { + mask = uxa_picture_from_pixman_image(screen, image, format); + } else { + int error; + + scratch = GetScratchPixmapHeader(screen, width, height, + PIXMAN_FORMAT_DEPTH(format), + PIXMAN_FORMAT_BPP(format), + pixman_image_get_stride(image), + pixman_image_get_data(image)); + mask = CreatePicture(0, &scratch->drawable, + PictureMatchFormat(screen, + PIXMAN_FORMAT_DEPTH(format), + format), + 0, 0, serverClient, &error); + } + if (!mask) { + if (scratch) + FreeScratchPixmapHeader(scratch); + pixman_image_unref(image); return; + } xRel = bounds.x1 + xSrc - xDst; yRel = bounds.y1 + ySrc - yDst; - CompositePicture(op, pSrc, pPicture, pDst, + CompositePicture(op, src, mask, dst, xRel, yRel, 0, 0, bounds.x1, bounds.y1, width, height); - FreePicture(pPicture, 0); + FreePicture(mask, 0); + + if (scratch) + FreeScratchPixmapHeader(scratch); + pixman_image_unref(image); } else { - if (pDst->polyEdge == PolyEdgeSharp) - maskFormat = PictureMatchFormat(pScreen, 1, PICT_a1); + if (dst->polyEdge == PolyEdgeSharp) + maskFormat = PictureMatchFormat(screen, 1, PICT_a1); else - maskFormat = PictureMatchFormat(pScreen, 8, PICT_a8); + maskFormat = PictureMatchFormat(screen, 8, PICT_a8); for (; ntrap; ntrap--, traps++) - uxa_trapezoids(op, pSrc, pDst, maskFormat, xSrc, ySrc, + uxa_trapezoids(op, src, dst, maskFormat, xSrc, ySrc, 1, traps); } } @@ -39,7 +39,11 @@ #include "dixfontstr.h" #include "uxa.h" +#if HAS_DEVPRIVATEKEYREC +DevPrivateKeyRec uxa_screen_index; +#else int uxa_screen_index; +#endif /** * uxa_get_drawable_pixmap() returns a backing pixmap for a given drawable. @@ -388,14 +392,17 @@ static Bool uxa_close_screen(int i, ScreenPtr pScreen) #ifdef RENDER if (ps) { ps->Composite = uxa_screen->SavedComposite; + ps->CompositeRects = uxa_screen->SavedCompositeRects; ps->Glyphs = uxa_screen->SavedGlyphs; ps->Trapezoids = uxa_screen->SavedTrapezoids; ps->AddTraps = uxa_screen->SavedAddTraps; ps->Triangles = uxa_screen->SavedTriangles; + + ps->UnrealizeGlyph = uxa_screen->SavedUnrealizeGlyph; } #endif - xfree(uxa_screen); + free(uxa_screen); return (*pScreen->CloseScreen) (i, pScreen); } @@ -406,13 +413,13 @@ static Bool uxa_close_screen(int i, ScreenPtr pScreen) * without breaking ABI between UXA and the drivers. The driver's * responsibility is to check beforehand that the UXA module has a matching * major number and sufficient minor. Drivers are responsible for freeing the - * driver structure using xfree(). + * driver structure using free(). * * @return a newly allocated, zero-filled driver structure */ uxa_driver_t *uxa_driver_alloc(void) { - return xcalloc(1, sizeof(uxa_driver_t)); + return calloc(1, sizeof(uxa_driver_t)); } /** @@ -429,9 +436,6 @@ Bool uxa_driver_init(ScreenPtr screen, uxa_driver_t * uxa_driver) { uxa_screen_t *uxa_screen; ScrnInfoPtr scrn = xf86Screens[screen->myNum]; -#ifdef RENDER - PictureScreenPtr ps; -#endif if (!uxa_driver) return FALSE; @@ -460,11 +464,11 @@ Bool uxa_driver_init(ScreenPtr screen, uxa_driver_t * uxa_driver) "non-NULL\n", screen->myNum); return FALSE; } -#ifdef RENDER - ps = GetPictureScreenIfSet(screen); +#if HAS_DIXREGISTERPRIVATEKEY + if (!dixRegisterPrivateKey(&uxa_screen_index, PRIVATE_SCREEN, 0)) + return FALSE; #endif - - uxa_screen = xcalloc(sizeof(uxa_screen_t), 1); + uxa_screen = calloc(sizeof(uxa_screen_t), 1); if (!uxa_screen) { LogMessage(X_WARNING, @@ -513,33 +517,32 @@ Bool uxa_driver_init(ScreenPtr screen, uxa_driver_t * uxa_driver) scrn->EnableDisableFBAccess = uxa_xorg_enable_disable_fb_access; #ifdef RENDER - if (ps) { - uxa_screen->SavedComposite = ps->Composite; - ps->Composite = uxa_composite; + { + PictureScreenPtr ps = GetPictureScreenIfSet(screen); + if (ps) { + uxa_screen->SavedComposite = ps->Composite; + ps->Composite = uxa_composite; - uxa_screen->SavedGlyphs = ps->Glyphs; - ps->Glyphs = uxa_glyphs; + uxa_screen->SavedCompositeRects = ps->CompositeRects; + ps->CompositeRects = uxa_solid_rects; - uxa_screen->SavedTriangles = ps->Triangles; - ps->Triangles = uxa_triangles; + uxa_screen->SavedGlyphs = ps->Glyphs; + ps->Glyphs = uxa_glyphs; - uxa_screen->SavedTrapezoids = ps->Trapezoids; - ps->Trapezoids = uxa_trapezoids; + uxa_screen->SavedUnrealizeGlyph = ps->UnrealizeGlyph; + ps->UnrealizeGlyph = uxa_glyph_unrealize; - uxa_screen->SavedAddTraps = ps->AddTraps; - ps->AddTraps = uxa_check_add_traps; - } -#endif + uxa_screen->SavedTriangles = ps->Triangles; + ps->Triangles = uxa_triangles; -#ifdef MITSHM - /* Re-register with the MI funcs, which don't allow shared pixmaps. - * Shared pixmaps are almost always a performance loss for us, but this - * still allows for SHM PutImage. - */ - ShmRegisterFuncs(screen, &uxa_shm_funcs); -#endif + uxa_screen->SavedTrapezoids = ps->Trapezoids; + ps->Trapezoids = uxa_trapezoids; - uxa_glyphs_init(screen); + uxa_screen->SavedAddTraps = ps->AddTraps; + ps->AddTraps = uxa_check_add_traps; + } + } +#endif LogMessage(X_INFO, "UXA(%d): Driver registered support for the following" @@ -561,6 +564,14 @@ Bool uxa_driver_init(ScreenPtr screen, uxa_driver_t * uxa_driver) return TRUE; } +Bool uxa_resources_init(ScreenPtr screen) +{ + if (!uxa_glyphs_init(screen)) + return FALSE; + + return TRUE; +} + /** * uxa_driver_fini tears down UXA on a given screen. * @@ -74,6 +74,17 @@ typedef struct _UxaDriver { * @{ */ /** + * check_solid() checks whether the driver can do a solid fill to this drawable. + * @param pDrawable Destination drawable + * @param alu raster operation + * @param planemask write mask for the fill + * + * The check_solid() call is recommended if prepare_solid() is + * implemented, but is not required. + */ + Bool(*check_solid) (DrawablePtr pDrawable, int alu, Pixel planemask); + + /** * prepare_solid() sets up the driver for doing a solid fill. * @param pPixmap Destination pixmap * @param alu raster operation @@ -138,6 +149,10 @@ typedef struct _UxaDriver { * @{ */ /** + * check_copy() checks whether the driver can blit between the two Pictures + */ + Bool(*check_copy) (PixmapPtr pSrc, PixmapPtr pDst, int alu, Pixel planemask); + /** * prepare_copy() sets up the driver for doing a copy within video * memory. - * @@ -232,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 @@ -249,7 +266,32 @@ 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 + * operation can be used without midification. + * + * @param pScreen Screen + * @param pPicture Picture + * + * The check_composite_texture() call is recommended if prepare_composite() is + * implemented, but is not required. + */ + Bool(*check_composite_texture) (ScreenPtr pScreen, + PicturePtr pPicture); /** * prepare_composite() sets up the driver for doing a composite @@ -516,6 +558,7 @@ typedef struct _UxaDriver { uxa_driver_t *uxa_driver_alloc(void); Bool uxa_driver_init(ScreenPtr screen, uxa_driver_t * uxa_driver); +Bool uxa_resources_init(ScreenPtr screen); void uxa_driver_fini(ScreenPtr pScreen); |