From 4c61bf84b11e26e6f22648668c95ea760a379163 Mon Sep 17 00:00:00 2001 From: marha Date: Fri, 11 Jun 2010 12:14:52 +0000 Subject: xserver git update 11/6/2010 --- xorg-server/exa/exa.c | 27 +- xorg-server/exa/exa_accel.c | 80 +- xorg-server/exa/exa_classic.c | 534 +++---- xorg-server/exa/exa_migration_classic.c | 1490 +++++++++--------- xorg-server/exa/exa_mixed.c | 583 ++++--- xorg-server/exa/exa_priv.h | 10 +- xorg-server/exa/exa_render.c | 2512 +++++++++++++++---------------- xorg-server/exa/exa_unaccel.c | 56 +- 8 files changed, 2649 insertions(+), 2643 deletions(-) (limited to 'xorg-server/exa') diff --git a/xorg-server/exa/exa.c b/xorg-server/exa/exa.c index a7bb5a29f..823c9a23f 100644 --- a/xorg-server/exa/exa.c +++ b/xorg-server/exa/exa.c @@ -37,12 +37,9 @@ #include "exa_priv.h" #include "exa.h" -static int exaScreenPrivateKeyIndex; -DevPrivateKey exaScreenPrivateKey = &exaScreenPrivateKeyIndex; -static int exaPixmapPrivateKeyIndex; -DevPrivateKey exaPixmapPrivateKey = &exaPixmapPrivateKeyIndex; -static int exaGCPrivateKeyIndex; -DevPrivateKey exaGCPrivateKey = &exaGCPrivateKeyIndex; +DevPrivateKeyRec exaScreenPrivateKeyRec; +DevPrivateKeyRec exaPixmapPrivateKeyRec; +DevPrivateKeyRec exaGCPrivateKeyRec; #ifdef MITSHM static ShmFuncs exaShmFuncs = { NULL, NULL }; @@ -161,10 +158,10 @@ exaPixmapDirty (PixmapPtr pPix, int x1, int y1, int x2, int y2) if (box.x1 >= box.x2 || box.y1 >= box.y2) return; - REGION_INIT(pScreen, ®ion, &box, 1); + RegionInit(®ion, &box, 1); DamageRegionAppend(&pPix->drawable, ®ion); DamageRegionProcessPending(&pPix->drawable); - REGION_UNINIT(pScreen, ®ion); + RegionUninit(®ion); } static int @@ -658,7 +655,7 @@ exaBitmapToRegion(PixmapPtr pPix) exaPrepareAccess(&pPix->drawable, EXA_PREPARE_SRC); swap(pExaScr, pScreen, BitmapToRegion); - ret = pScreen->BitmapToRegion(pPix); + ret = (*pScreen->BitmapToRegion)(pPix); swap(pExaScr, pScreen, BitmapToRegion); exaFinishAccess(&pPix->drawable, EXA_PREPARE_SRC); @@ -889,7 +886,13 @@ exaDriverInit (ScreenPtr pScreen, ps = GetPictureScreenIfSet(pScreen); - pExaScr = calloc(sizeof (ExaScreenPrivRec), 1); + if (!dixRegisterPrivateKey(&exaScreenPrivateKeyRec, PRIVATE_SCREEN, 0)) { + LogMessage(X_WARNING, "EXA(%d): Failed to register screen private\n", + pScreen->myNum); + return FALSE; + } + + pExaScr = calloc (sizeof (ExaScreenPrivRec), 1); if (!pExaScr) { LogMessage(X_WARNING, "EXA(%d): Failed to allocate screen private\n", pScreen->myNum); @@ -904,7 +907,7 @@ exaDriverInit (ScreenPtr pScreen, exaDDXDriverInit(pScreen); - if (!dixRequestPrivate(exaGCPrivateKey, sizeof(ExaGCPrivRec))) { + if (!dixRegisterPrivateKey(&exaGCPrivateKeyRec, PRIVATE_GC, sizeof(ExaGCPrivRec))) { LogMessage(X_WARNING, "EXA(%d): Failed to allocate GC private\n", pScreen->myNum); @@ -953,7 +956,7 @@ exaDriverInit (ScreenPtr pScreen, */ if (pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS) { - if (!dixRequestPrivate(exaPixmapPrivateKey, sizeof(ExaPixmapPrivRec))) { + if (!dixRegisterPrivateKey(&exaPixmapPrivateKeyRec, PRIVATE_PIXMAP, sizeof(ExaPixmapPrivRec))) { LogMessage(X_WARNING, "EXA(%d): Failed to allocate pixmap private\n", pScreen->myNum); diff --git a/xorg-server/exa/exa_accel.c b/xorg-server/exa/exa_accel.c index e30ddce74..cb364303d 100644 --- a/xorg-server/exa/exa_accel.c +++ b/xorg-server/exa/exa_accel.c @@ -81,7 +81,7 @@ exaFillSpans(DrawablePtr pDrawable, GCPtr pGC, int n, return; } - pextent = REGION_EXTENTS(pGC->pScreen, pClip); + pextent = RegionExtents(pClip); extentX1 = pextent->x1; extentY1 = pextent->y1; extentX2 = pextent->x2; @@ -106,7 +106,7 @@ exaFillSpans(DrawablePtr pDrawable, GCPtr pGC, int n, if (fullX1 >= fullX2) continue; - nbox = REGION_NUM_RECTS (pClip); + nbox = RegionNumRects (pClip); if (nbox == 1) { (*pExaScr->info->Solid) (pPixmap, @@ -115,7 +115,7 @@ exaFillSpans(DrawablePtr pDrawable, GCPtr pGC, int n, } else { - pbox = REGION_RECTS(pClip); + pbox = RegionRects(pClip); while(nbox--) { if (pbox->y1 <= fullY1 && fullY1 < pbox->y2) @@ -192,8 +192,8 @@ exaDoPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, y += pDrawable->y; pClip = fbGetCompositeClip(pGC); - for (nbox = REGION_NUM_RECTS(pClip), - pbox = REGION_RECTS(pClip); + for (nbox = RegionNumRects(pClip), + pbox = RegionRects(pClip); nbox--; pbox++) { @@ -407,7 +407,7 @@ exaHWCopyNtoN (DrawablePtr pSrcDrawable, rects[i].height = pbox[i].y2 - pbox[i].y1; } - /* This must match the miRegionCopy() logic for reversing rect order */ + /* This must match the RegionCopy() logic for reversing rect order */ if (nbox == 1 || (dx > 0 && dy > 0) || (pDstDrawable != pSrcDrawable && (pDstDrawable->type != DRAWABLE_WINDOW || @@ -416,15 +416,15 @@ exaHWCopyNtoN (DrawablePtr pSrcDrawable, else ordering = CT_UNSORTED; - srcregion = RECTS_TO_REGION(pScreen, nbox, rects, ordering); + srcregion = RegionFromRects(nbox, rects, ordering); free(rects); if (!pGC || !exaGCReadsDestination(pDstDrawable, pGC->planemask, pGC->fillStyle, pGC->alu, pGC->clientClipType)) { - dstregion = REGION_CREATE(pScreen, NullBox, 0); - REGION_COPY(pScreen, dstregion, srcregion); - REGION_TRANSLATE(pScreen, dstregion, dst_off_x - dx - src_off_x, + dstregion = RegionCreate(NullBox, 0); + RegionCopy(dstregion, srcregion); + RegionTranslate(dstregion, dst_off_x - dx - src_off_x, dst_off_y - dy - src_off_y); } } @@ -551,12 +551,12 @@ fallback: out: if (dstregion) { - REGION_UNINIT(pScreen, dstregion); - REGION_DESTROY(pScreen, dstregion); + RegionUninit(dstregion); + RegionDestroy(dstregion); } if (srcregion) { - REGION_UNINIT(pScreen, srcregion); - REGION_DESTROY(pScreen, srcregion); + RegionUninit(srcregion); + RegionDestroy(srcregion); } return ret; @@ -788,13 +788,13 @@ exaPolyFillRect(DrawablePtr pDrawable, int xoff, yoff; int xorg, yorg; int n; - RegionPtr pReg = RECTS_TO_REGION(pScreen, nrect, prect, CT_UNSORTED); + RegionPtr pReg = RegionFromRects(nrect, prect, CT_UNSORTED); /* Compute intersection of rects and clip region */ - REGION_TRANSLATE(pScreen, pReg, pDrawable->x, pDrawable->y); - REGION_INTERSECT(pScreen, pReg, pClip, pReg); + RegionTranslate(pReg, pDrawable->x, pDrawable->y); + RegionIntersect(pReg, pClip, pReg); - if (!REGION_NUM_RECTS(pReg)) { + if (!RegionNumRects(pReg)) { goto out; } @@ -856,7 +856,7 @@ fallback: xorg = pDrawable->x; yorg = pDrawable->y; - pextent = REGION_EXTENTS(pGC->pScreen, pClip); + pextent = RegionExtents(pClip); extentX1 = pextent->x1; extentY1 = pextent->y1; extentX2 = pextent->x2; @@ -883,7 +883,7 @@ fallback: if ((fullX1 >= fullX2) || (fullY1 >= fullY2)) continue; - n = REGION_NUM_RECTS (pClip); + n = RegionNumRects (pClip); if (n == 1) { (*pExaScr->info->Solid) (pPixmap, @@ -892,7 +892,7 @@ fallback: } else { - pbox = REGION_RECTS(pClip); + pbox = RegionRects(pClip); /* * clip the rectangle to each box in the clip region * this is logically equivalent to calling Intersect(), @@ -927,8 +927,8 @@ fallback: exaMarkSync(pDrawable->pScreen); out: - REGION_UNINIT(pScreen, pReg); - REGION_DESTROY(pScreen, pReg); + RegionUninit(pReg); + RegionDestroy(pReg); } const GCOps exaOps = { @@ -964,14 +964,14 @@ exaCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc) dx = ptOldOrg.x - pWin->drawable.x; dy = ptOldOrg.y - pWin->drawable.y; - REGION_TRANSLATE(pWin->drawable.pScreen, prgnSrc, -dx, -dy); + RegionTranslate(prgnSrc, -dx, -dy); - REGION_INIT (pWin->drawable.pScreen, &rgnDst, NullBox, 0); + RegionInit(&rgnDst, NullBox, 0); - REGION_INTERSECT(pWin->drawable.pScreen, &rgnDst, &pWin->borderClip, prgnSrc); + RegionIntersect(&rgnDst, &pWin->borderClip, prgnSrc); #ifdef COMPOSITE if (pPixmap->screen_x || pPixmap->screen_y) - REGION_TRANSLATE (pWin->drawable.pScreen, &rgnDst, + RegionTranslate(&rgnDst, -pPixmap->screen_x, -pPixmap->screen_y); #endif @@ -987,11 +987,11 @@ exaCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc) pExaScr->fallback_flags &= ~EXA_ACCEL_COPYWINDOW; fallback: - REGION_UNINIT(pWin->drawable.pScreen, &rgnDst); + RegionUninit(&rgnDst); if (pExaScr->fallback_flags & EXA_FALLBACK_COPYWINDOW) { pExaScr->fallback_flags &= ~EXA_FALLBACK_COPYWINDOW; - REGION_TRANSLATE(pWin->drawable.pScreen, prgnSrc, dx, dy); + RegionTranslate(prgnSrc, dx, dy); ExaCheckCopyWindow(pWin, ptOldOrg, prgnSrc); } } @@ -1007,7 +1007,7 @@ exaFillRegionSolid (DrawablePtr pDrawable, RegionPtr pRegion, Pixel pixel, Bool ret = FALSE; exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff); - REGION_TRANSLATE(pScreen, pRegion, xoff, yoff); + RegionTranslate(pRegion, xoff, yoff); if (pExaScr->fallback_counter || pExaPixmap->accel_blocked) goto out; @@ -1030,8 +1030,8 @@ exaFillRegionSolid (DrawablePtr pDrawable, RegionPtr pRegion, Pixel pixel, int nbox; BoxPtr pBox; - nbox = REGION_NUM_RECTS (pRegion); - pBox = REGION_RECTS (pRegion); + nbox = RegionNumRects (pRegion); + pBox = RegionRects (pRegion); while (nbox--) { @@ -1060,18 +1060,18 @@ exaFillRegionSolid (DrawablePtr pDrawable, RegionPtr pRegion, Pixel pixel, *(CARD8*)pExaPixmap->sys_ptr = pixel; } - REGION_UNION(pScreen, &pExaPixmap->validSys, &pExaPixmap->validSys, + RegionUnion(&pExaPixmap->validSys, &pExaPixmap->validSys, pRegion); - REGION_UNION(pScreen, &pExaPixmap->validFB, &pExaPixmap->validFB, + RegionUnion(&pExaPixmap->validFB, &pExaPixmap->validFB, pRegion); - REGION_SUBTRACT(pScreen, pending_damage, pending_damage, pRegion); + RegionSubtract(pending_damage, pending_damage, pRegion); } ret = TRUE; } out: - REGION_TRANSLATE(pScreen, pRegion, -xoff, -yoff); + RegionTranslate(pRegion, -xoff, -yoff); return ret; } @@ -1090,8 +1090,8 @@ exaFillRegionTiled (DrawablePtr pDrawable, RegionPtr pRegion, PixmapPtr pTile, ExaPixmapPrivPtr pTileExaPixmap = ExaGetPixmapPriv(pTile); int xoff, yoff; int tileWidth, tileHeight; - int nbox = REGION_NUM_RECTS (pRegion); - BoxPtr pBox = REGION_RECTS (pRegion); + int nbox = RegionNumRects (pRegion); + BoxPtr pBox = RegionRects (pRegion); Bool ret = FALSE; int i; @@ -1137,7 +1137,7 @@ exaFillRegionTiled (DrawablePtr pDrawable, RegionPtr pRegion, PixmapPtr pTile, if ((*pExaScr->info->PrepareCopy) (pTile, pPixmap, 1, 1, alu, planemask)) { if (xoff || yoff) - REGION_TRANSLATE(pScreen, pRegion, xoff, yoff); + RegionTranslate(pRegion, xoff, yoff); for (i = 0; i < nbox; i++) { @@ -1245,7 +1245,7 @@ exaFillRegionTiled (DrawablePtr pDrawable, RegionPtr pRegion, PixmapPtr pTile, exaMarkSync(pDrawable->pScreen); if (xoff || yoff) - REGION_TRANSLATE(pScreen, pRegion, -xoff, -yoff); + RegionTranslate(pRegion, -xoff, -yoff); } return ret; diff --git a/xorg-server/exa/exa_classic.c b/xorg-server/exa/exa_classic.c index e1ead6c0d..8b92d6880 100644 --- a/xorg-server/exa/exa_classic.c +++ b/xorg-server/exa/exa_classic.c @@ -1,267 +1,267 @@ -/* - * Copyright © 2009 Maarten Maathuis - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - */ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include - -#include "exa_priv.h" -#include "exa.h" - -/* This file holds the classic exa specific implementation. */ - -static _X_INLINE void* -ExaGetPixmapAddress(PixmapPtr p) -{ - ExaPixmapPriv(p); - - if (pExaPixmap->use_gpu_copy && pExaPixmap->fb_ptr) - return pExaPixmap->fb_ptr; - else - return pExaPixmap->sys_ptr; -} - -/** - * exaCreatePixmap() creates a new pixmap. - * - * If width and height are 0, this won't be a full-fledged pixmap and it will - * get ModifyPixmapHeader() called on it later. So, we mark it as pinned, because - * ModifyPixmapHeader() would break migration. These types of pixmaps are used - * for scratch pixmaps, or to represent the visible screen. - */ -PixmapPtr -exaCreatePixmap_classic(ScreenPtr pScreen, int w, int h, int depth, - unsigned usage_hint) -{ - PixmapPtr pPixmap; - ExaPixmapPrivPtr pExaPixmap; - BoxRec box; - int bpp; - ExaScreenPriv(pScreen); - - if (w > 32767 || h > 32767) - return NullPixmap; - - swap(pExaScr, pScreen, CreatePixmap); - pPixmap = pScreen->CreatePixmap (pScreen, w, h, depth, usage_hint); - swap(pExaScr, pScreen, CreatePixmap); - - if (!pPixmap) - return NULL; - - pExaPixmap = ExaGetPixmapPriv(pPixmap); - pExaPixmap->driverPriv = NULL; - - bpp = pPixmap->drawable.bitsPerPixel; - - pExaPixmap->driverPriv = NULL; - /* Scratch pixmaps may have w/h equal to zero, and may not be - * migrated. - */ - if (!w || !h) - pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED; - else - pExaPixmap->score = EXA_PIXMAP_SCORE_INIT; - - pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr; - pExaPixmap->sys_pitch = pPixmap->devKind; - - pPixmap->devPrivate.ptr = NULL; - pExaPixmap->use_gpu_copy = FALSE; - - pExaPixmap->fb_ptr = NULL; - exaSetFbPitch(pExaScr, pExaPixmap, w, h, bpp); - pExaPixmap->fb_size = pExaPixmap->fb_pitch * h; - - if (pExaPixmap->fb_pitch > 131071) { - swap(pExaScr, pScreen, DestroyPixmap); - pScreen->DestroyPixmap (pPixmap); - swap(pExaScr, pScreen, DestroyPixmap); - return NULL; - } - - /* Set up damage tracking */ - pExaPixmap->pDamage = DamageCreate (NULL, NULL, - DamageReportNone, TRUE, - pScreen, pPixmap); - - if (pExaPixmap->pDamage == NULL) { - swap(pExaScr, pScreen, DestroyPixmap); - pScreen->DestroyPixmap (pPixmap); - swap(pExaScr, pScreen, DestroyPixmap); - return NULL; - } - - DamageRegister (&pPixmap->drawable, pExaPixmap->pDamage); - /* This ensures that pending damage reflects the current operation. */ - /* This is used by exa to optimize migration. */ - DamageSetReportAfterOp (pExaPixmap->pDamage, TRUE); - - pExaPixmap->area = NULL; - - /* We set the initial pixmap as completely valid for a simple reason. - * Imagine a 1000x1000 pixmap, it has 1 million pixels, 250000 of which - * could form single pixel rects as part of a region. Setting the complete region - * as valid is a natural defragmentation of the region. - */ - box.x1 = 0; - box.y1 = 0; - box.x2 = w; - box.y2 = h; - REGION_INIT(pScreen, &pExaPixmap->validSys, &box, 0); - REGION_INIT(pScreen, &pExaPixmap->validFB, &box, 0); - - exaSetAccelBlock(pExaScr, pExaPixmap, - w, h, bpp); - - /* During a fallback we must prepare access. */ - if (pExaScr->fallback_counter) - exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_AUX_DEST); - - return pPixmap; -} - -Bool -exaModifyPixmapHeader_classic(PixmapPtr pPixmap, int width, int height, int depth, - int bitsPerPixel, int devKind, pointer pPixData) -{ - ScreenPtr pScreen; - ExaScreenPrivPtr pExaScr; - ExaPixmapPrivPtr pExaPixmap; - Bool ret; - - if (!pPixmap) - return FALSE; - - pScreen = pPixmap->drawable.pScreen; - pExaScr = ExaGetScreenPriv(pScreen); - pExaPixmap = ExaGetPixmapPriv(pPixmap); - - if (pExaPixmap) { - if (pPixData) - pExaPixmap->sys_ptr = pPixData; - - if (devKind > 0) - pExaPixmap->sys_pitch = devKind; - - /* Classic EXA: - * - Framebuffer. - * - Scratch pixmap with gpu memory. - */ - if (pExaScr->info->memoryBase && pPixData) { - if ((CARD8 *)pPixData >= pExaScr->info->memoryBase && - ((CARD8 *)pPixData - pExaScr->info->memoryBase) < - pExaScr->info->memorySize) { - pExaPixmap->fb_ptr = pPixData; - pExaPixmap->fb_pitch = devKind; - pExaPixmap->use_gpu_copy = TRUE; - } - } - - if (width > 0 && height > 0 && bitsPerPixel > 0) { - exaSetFbPitch(pExaScr, pExaPixmap, - width, height, bitsPerPixel); - - exaSetAccelBlock(pExaScr, pExaPixmap, - width, height, bitsPerPixel); - } - - /* Pixmaps subject to ModifyPixmapHeader will be pinned to system or - * gpu memory, so there's no need to track damage. - */ - if (pExaPixmap->pDamage) { - DamageUnregister(&pPixmap->drawable, pExaPixmap->pDamage); - DamageDestroy(pExaPixmap->pDamage); - pExaPixmap->pDamage = NULL; - } - } - - swap(pExaScr, pScreen, ModifyPixmapHeader); - ret = pScreen->ModifyPixmapHeader(pPixmap, width, height, depth, - bitsPerPixel, devKind, pPixData); - swap(pExaScr, pScreen, ModifyPixmapHeader); - - /* Always NULL this, we don't want lingering pointers. */ - pPixmap->devPrivate.ptr = NULL; - - return ret; -} - -Bool -exaDestroyPixmap_classic (PixmapPtr pPixmap) -{ - ScreenPtr pScreen = pPixmap->drawable.pScreen; - ExaScreenPriv(pScreen); - Bool ret; - - if (pPixmap->refcnt == 1) - { - ExaPixmapPriv (pPixmap); - - /* During a fallback we must finish access, but we don't know the index. */ - if (pExaScr->fallback_counter) - exaFinishAccess(&pPixmap->drawable, -1); - - if (pExaPixmap->area) - { - DBG_PIXMAP(("-- 0x%p (0x%x) (%dx%d)\n", - (void*)pPixmap->drawable.id, - ExaGetPixmapPriv(pPixmap)->area->offset, - pPixmap->drawable.width, - pPixmap->drawable.height)); - /* Free the offscreen area */ - exaOffscreenFree (pPixmap->drawable.pScreen, pExaPixmap->area); - pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr; - pPixmap->devKind = pExaPixmap->sys_pitch; - } - REGION_UNINIT(pPixmap->drawable.pScreen, &pExaPixmap->validSys); - REGION_UNINIT(pPixmap->drawable.pScreen, &pExaPixmap->validFB); - } - - swap(pExaScr, pScreen, DestroyPixmap); - ret = pScreen->DestroyPixmap (pPixmap); - swap(pExaScr, pScreen, DestroyPixmap); - - return ret; -} - -Bool -exaPixmapHasGpuCopy_classic(PixmapPtr pPixmap) -{ - ScreenPtr pScreen = pPixmap->drawable.pScreen; - ExaScreenPriv(pScreen); - ExaPixmapPriv(pPixmap); - Bool ret; - - if (pExaScr->info->PixmapIsOffscreen) { - pPixmap->devPrivate.ptr = ExaGetPixmapAddress(pPixmap); - ret = pExaScr->info->PixmapIsOffscreen(pPixmap); - pPixmap->devPrivate.ptr = NULL; - } else - ret = (pExaPixmap->use_gpu_copy && pExaPixmap->fb_ptr); - - return ret; -} +/* + * Copyright © 2009 Maarten Maathuis + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include + +#include "exa_priv.h" +#include "exa.h" + +/* This file holds the classic exa specific implementation. */ + +static _X_INLINE void* +ExaGetPixmapAddress(PixmapPtr p) +{ + ExaPixmapPriv(p); + + if (pExaPixmap->use_gpu_copy && pExaPixmap->fb_ptr) + return pExaPixmap->fb_ptr; + else + return pExaPixmap->sys_ptr; +} + +/** + * exaCreatePixmap() creates a new pixmap. + * + * If width and height are 0, this won't be a full-fledged pixmap and it will + * get ModifyPixmapHeader() called on it later. So, we mark it as pinned, because + * ModifyPixmapHeader() would break migration. These types of pixmaps are used + * for scratch pixmaps, or to represent the visible screen. + */ +PixmapPtr +exaCreatePixmap_classic(ScreenPtr pScreen, int w, int h, int depth, + unsigned usage_hint) +{ + PixmapPtr pPixmap; + ExaPixmapPrivPtr pExaPixmap; + BoxRec box; + int bpp; + ExaScreenPriv(pScreen); + + if (w > 32767 || h > 32767) + return NullPixmap; + + swap(pExaScr, pScreen, CreatePixmap); + pPixmap = pScreen->CreatePixmap (pScreen, w, h, depth, usage_hint); + swap(pExaScr, pScreen, CreatePixmap); + + if (!pPixmap) + return NULL; + + pExaPixmap = ExaGetPixmapPriv(pPixmap); + pExaPixmap->driverPriv = NULL; + + bpp = pPixmap->drawable.bitsPerPixel; + + pExaPixmap->driverPriv = NULL; + /* Scratch pixmaps may have w/h equal to zero, and may not be + * migrated. + */ + if (!w || !h) + pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED; + else + pExaPixmap->score = EXA_PIXMAP_SCORE_INIT; + + pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr; + pExaPixmap->sys_pitch = pPixmap->devKind; + + pPixmap->devPrivate.ptr = NULL; + pExaPixmap->use_gpu_copy = FALSE; + + pExaPixmap->fb_ptr = NULL; + exaSetFbPitch(pExaScr, pExaPixmap, w, h, bpp); + pExaPixmap->fb_size = pExaPixmap->fb_pitch * h; + + if (pExaPixmap->fb_pitch > 131071) { + swap(pExaScr, pScreen, DestroyPixmap); + pScreen->DestroyPixmap (pPixmap); + swap(pExaScr, pScreen, DestroyPixmap); + return NULL; + } + + /* Set up damage tracking */ + pExaPixmap->pDamage = DamageCreate (NULL, NULL, + DamageReportNone, TRUE, + pScreen, pPixmap); + + if (pExaPixmap->pDamage == NULL) { + swap(pExaScr, pScreen, DestroyPixmap); + pScreen->DestroyPixmap (pPixmap); + swap(pExaScr, pScreen, DestroyPixmap); + return NULL; + } + + DamageRegister (&pPixmap->drawable, pExaPixmap->pDamage); + /* This ensures that pending damage reflects the current operation. */ + /* This is used by exa to optimize migration. */ + DamageSetReportAfterOp (pExaPixmap->pDamage, TRUE); + + pExaPixmap->area = NULL; + + /* We set the initial pixmap as completely valid for a simple reason. + * Imagine a 1000x1000 pixmap, it has 1 million pixels, 250000 of which + * could form single pixel rects as part of a region. Setting the complete region + * as valid is a natural defragmentation of the region. + */ + box.x1 = 0; + box.y1 = 0; + box.x2 = w; + box.y2 = h; + RegionInit(&pExaPixmap->validSys, &box, 0); + RegionInit(&pExaPixmap->validFB, &box, 0); + + exaSetAccelBlock(pExaScr, pExaPixmap, + w, h, bpp); + + /* During a fallback we must prepare access. */ + if (pExaScr->fallback_counter) + exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_AUX_DEST); + + return pPixmap; +} + +Bool +exaModifyPixmapHeader_classic(PixmapPtr pPixmap, int width, int height, int depth, + int bitsPerPixel, int devKind, pointer pPixData) +{ + ScreenPtr pScreen; + ExaScreenPrivPtr pExaScr; + ExaPixmapPrivPtr pExaPixmap; + Bool ret; + + if (!pPixmap) + return FALSE; + + pScreen = pPixmap->drawable.pScreen; + pExaScr = ExaGetScreenPriv(pScreen); + pExaPixmap = ExaGetPixmapPriv(pPixmap); + + if (pExaPixmap) { + if (pPixData) + pExaPixmap->sys_ptr = pPixData; + + if (devKind > 0) + pExaPixmap->sys_pitch = devKind; + + /* Classic EXA: + * - Framebuffer. + * - Scratch pixmap with gpu memory. + */ + if (pExaScr->info->memoryBase && pPixData) { + if ((CARD8 *)pPixData >= pExaScr->info->memoryBase && + ((CARD8 *)pPixData - pExaScr->info->memoryBase) < + pExaScr->info->memorySize) { + pExaPixmap->fb_ptr = pPixData; + pExaPixmap->fb_pitch = devKind; + pExaPixmap->use_gpu_copy = TRUE; + } + } + + if (width > 0 && height > 0 && bitsPerPixel > 0) { + exaSetFbPitch(pExaScr, pExaPixmap, + width, height, bitsPerPixel); + + exaSetAccelBlock(pExaScr, pExaPixmap, + width, height, bitsPerPixel); + } + + /* Pixmaps subject to ModifyPixmapHeader will be pinned to system or + * gpu memory, so there's no need to track damage. + */ + if (pExaPixmap->pDamage) { + DamageUnregister(&pPixmap->drawable, pExaPixmap->pDamage); + DamageDestroy(pExaPixmap->pDamage); + pExaPixmap->pDamage = NULL; + } + } + + swap(pExaScr, pScreen, ModifyPixmapHeader); + ret = pScreen->ModifyPixmapHeader(pPixmap, width, height, depth, + bitsPerPixel, devKind, pPixData); + swap(pExaScr, pScreen, ModifyPixmapHeader); + + /* Always NULL this, we don't want lingering pointers. */ + pPixmap->devPrivate.ptr = NULL; + + return ret; +} + +Bool +exaDestroyPixmap_classic (PixmapPtr pPixmap) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + ExaScreenPriv(pScreen); + Bool ret; + + if (pPixmap->refcnt == 1) + { + ExaPixmapPriv (pPixmap); + + /* During a fallback we must finish access, but we don't know the index. */ + if (pExaScr->fallback_counter) + exaFinishAccess(&pPixmap->drawable, -1); + + if (pExaPixmap->area) + { + DBG_PIXMAP(("-- 0x%p (0x%x) (%dx%d)\n", + (void*)pPixmap->drawable.id, + ExaGetPixmapPriv(pPixmap)->area->offset, + pPixmap->drawable.width, + pPixmap->drawable.height)); + /* Free the offscreen area */ + exaOffscreenFree (pPixmap->drawable.pScreen, pExaPixmap->area); + pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr; + pPixmap->devKind = pExaPixmap->sys_pitch; + } + RegionUninit(&pExaPixmap->validSys); + RegionUninit(&pExaPixmap->validFB); + } + + swap(pExaScr, pScreen, DestroyPixmap); + ret = pScreen->DestroyPixmap (pPixmap); + swap(pExaScr, pScreen, DestroyPixmap); + + return ret; +} + +Bool +exaPixmapHasGpuCopy_classic(PixmapPtr pPixmap) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + ExaScreenPriv(pScreen); + ExaPixmapPriv(pPixmap); + Bool ret; + + if (pExaScr->info->PixmapIsOffscreen) { + pPixmap->devPrivate.ptr = ExaGetPixmapAddress(pPixmap); + ret = pExaScr->info->PixmapIsOffscreen(pPixmap); + pPixmap->devPrivate.ptr = NULL; + } else + ret = (pExaPixmap->use_gpu_copy && pExaPixmap->fb_ptr); + + return ret; +} diff --git a/xorg-server/exa/exa_migration_classic.c b/xorg-server/exa/exa_migration_classic.c index 871679ffc..5ec2ac0b8 100644 --- a/xorg-server/exa/exa_migration_classic.c +++ b/xorg-server/exa/exa_migration_classic.c @@ -1,745 +1,745 @@ -/* - * Copyright © 2006 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * Authors: - * Eric Anholt - * Michel Dänzer - * - */ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include - -#include "exa_priv.h" -#include "exa.h" - -#if DEBUG_MIGRATE -#define DBG_MIGRATE(a) ErrorF a -#else -#define DBG_MIGRATE(a) -#endif - -/** - * The fallback path for UTS/DFS failing is to just memcpy. exaCopyDirtyToSys - * and exaCopyDirtyToFb both needed to do this loop. - */ -static void -exaMemcpyBox (PixmapPtr pPixmap, BoxPtr pbox, CARD8 *src, int src_pitch, - CARD8 *dst, int dst_pitch) - { - int i, cpp = pPixmap->drawable.bitsPerPixel / 8; - int bytes = (pbox->x2 - pbox->x1) * cpp; - - src += pbox->y1 * src_pitch + pbox->x1 * cpp; - dst += pbox->y1 * dst_pitch + pbox->x1 * cpp; - - for (i = pbox->y2 - pbox->y1; i; i--) { - memcpy (dst, src, bytes); - src += src_pitch; - dst += dst_pitch; - } -} - -/** - * Returns TRUE if the pixmap is dirty (has been modified in its current - * location compared to the other), or lacks a private for tracking - * dirtiness. - */ -static Bool -exaPixmapIsDirty (PixmapPtr pPix) -{ - ExaPixmapPriv (pPix); - - if (pExaPixmap == NULL) - EXA_FatalErrorDebugWithRet(("EXA bug: exaPixmapIsDirty was called on a non-exa pixmap.\n"), TRUE); - - if (!pExaPixmap->pDamage) - return FALSE; - - return REGION_NOTEMPTY (pScreen, DamageRegion(pExaPixmap->pDamage)) || - !REGION_EQUAL(pScreen, &pExaPixmap->validSys, &pExaPixmap->validFB); -} - -/** - * Returns TRUE if the pixmap is either pinned in FB, or has a sufficient score - * to be considered "should be in framebuffer". That's just anything that has - * had more acceleration than fallbacks, or has no score yet. - * - * Only valid if using a migration scheme that tracks score. - */ -static Bool -exaPixmapShouldBeInFB (PixmapPtr pPix) -{ - ExaPixmapPriv (pPix); - - if (exaPixmapIsPinned (pPix)) - return TRUE; - - return pExaPixmap->score >= 0; -} - -/** - * If the pixmap is currently dirty, this copies at least the dirty area from - * FB to system or vice versa. Both areas must be allocated. - */ -static void -exaCopyDirty(ExaMigrationPtr migrate, RegionPtr pValidDst, RegionPtr pValidSrc, - Bool (*transfer) (PixmapPtr pPix, int x, int y, int w, int h, - char *sys, int sys_pitch), int fallback_index, - void (*sync) (ScreenPtr pScreen)) -{ - PixmapPtr pPixmap = migrate->pPix; - ExaPixmapPriv (pPixmap); - RegionPtr damage = DamageRegion (pExaPixmap->pDamage); - RegionRec CopyReg; - Bool save_use_gpu_copy; - int save_pitch; - BoxPtr pBox; - int nbox; - Bool access_prepared = FALSE; - Bool need_sync = FALSE; - - /* Damaged bits are valid in current copy but invalid in other one */ - if (pExaPixmap->use_gpu_copy) { - REGION_UNION(pScreen, &pExaPixmap->validFB, &pExaPixmap->validFB, - damage); - REGION_SUBTRACT(pScreen, &pExaPixmap->validSys, &pExaPixmap->validSys, - damage); - } else { - REGION_UNION(pScreen, &pExaPixmap->validSys, &pExaPixmap->validSys, - damage); - REGION_SUBTRACT(pScreen, &pExaPixmap->validFB, &pExaPixmap->validFB, - damage); - } - - REGION_EMPTY(pScreen, damage); - - /* Copy bits valid in source but not in destination */ - REGION_NULL(pScreen, &CopyReg); - REGION_SUBTRACT(pScreen, &CopyReg, pValidSrc, pValidDst); - - if (migrate->as_dst) { - ExaScreenPriv (pPixmap->drawable.pScreen); - - /* XXX: The pending damage region will be marked as damaged after the - * operation, so it should serve as an upper bound for the region that - * needs to be synchronized for the operation. Unfortunately, this - * causes corruption in some cases, e.g. when starting compiz. See - * https://bugs.freedesktop.org/show_bug.cgi?id=12916 . - */ - if (pExaScr->optimize_migration) { - RegionPtr pending_damage = DamagePendingRegion(pExaPixmap->pDamage); - -#if DEBUG_MIGRATE - if (REGION_NIL(pending_damage)) { - static Bool firsttime = TRUE; - - if (firsttime) { - ErrorF("%s: Pending damage region empty!\n", __func__); - firsttime = FALSE; - } - } -#endif - - /* Try to prevent destination valid region from growing too many - * rects by filling it up to the extents of the union of the - * destination valid region and the pending damage region. - */ - if (REGION_NUM_RECTS(pValidDst) > 10) { - BoxRec box; - BoxPtr pValidExt, pDamageExt; - RegionRec closure; - - pValidExt = REGION_EXTENTS(pScreen, pValidDst); - pDamageExt = REGION_EXTENTS(pScreen, pending_damage); - - box.x1 = min(pValidExt->x1, pDamageExt->x1); - box.y1 = min(pValidExt->y1, pDamageExt->y1); - box.x2 = max(pValidExt->x2, pDamageExt->x2); - box.y2 = max(pValidExt->y2, pDamageExt->y2); - - REGION_INIT(pScreen, &closure, &box, 0); - REGION_INTERSECT(pScreen, &CopyReg, &CopyReg, &closure); - } else - REGION_INTERSECT(pScreen, &CopyReg, &CopyReg, pending_damage); - } - - /* The caller may provide a region to be subtracted from the calculated - * dirty region. This is to avoid migration of bits that don't - * contribute to the result of the operation. - */ - if (migrate->pReg) - REGION_SUBTRACT(pScreen, &CopyReg, &CopyReg, migrate->pReg); - } else { - /* The caller may restrict the region to be migrated for source pixmaps - * to what's relevant for the operation. - */ - if (migrate->pReg) - REGION_INTERSECT(pScreen, &CopyReg, &CopyReg, migrate->pReg); - } - - pBox = REGION_RECTS(&CopyReg); - nbox = REGION_NUM_RECTS(&CopyReg); - - save_use_gpu_copy = pExaPixmap->use_gpu_copy; - save_pitch = pPixmap->devKind; - pExaPixmap->use_gpu_copy = TRUE; - pPixmap->devKind = pExaPixmap->fb_pitch; - - while (nbox--) { - pBox->x1 = max(pBox->x1, 0); - pBox->y1 = max(pBox->y1, 0); - pBox->x2 = min(pBox->x2, pPixmap->drawable.width); - pBox->y2 = min(pBox->y2, pPixmap->drawable.height); - - if (pBox->x1 >= pBox->x2 || pBox->y1 >= pBox->y2) - continue; - - if (!transfer || !transfer (pPixmap, - pBox->x1, pBox->y1, - pBox->x2 - pBox->x1, - pBox->y2 - pBox->y1, - (char *) (pExaPixmap->sys_ptr - + pBox->y1 * pExaPixmap->sys_pitch - + pBox->x1 * pPixmap->drawable.bitsPerPixel / 8), - pExaPixmap->sys_pitch)) - { - if (!access_prepared) { - ExaDoPrepareAccess(pPixmap, fallback_index); - access_prepared = TRUE; - } - if (fallback_index == EXA_PREPARE_DEST) { - exaMemcpyBox (pPixmap, pBox, - pExaPixmap->sys_ptr, pExaPixmap->sys_pitch, - pPixmap->devPrivate.ptr, pPixmap->devKind); - } else { - exaMemcpyBox (pPixmap, pBox, - pPixmap->devPrivate.ptr, pPixmap->devKind, - pExaPixmap->sys_ptr, pExaPixmap->sys_pitch); - } - } else - need_sync = TRUE; - - pBox++; - } - - pExaPixmap->use_gpu_copy = save_use_gpu_copy; - pPixmap->devKind = save_pitch; - - /* Try to prevent source valid region from growing too many rects by - * removing parts of it which are also in the destination valid region. - * Removing anything beyond that would lead to data loss. - */ - if (REGION_NUM_RECTS(pValidSrc) > 20) - REGION_SUBTRACT(pScreen, pValidSrc, pValidSrc, pValidDst); - - /* The copied bits are now valid in destination */ - REGION_UNION(pScreen, pValidDst, pValidDst, &CopyReg); - - REGION_UNINIT(pScreen, &CopyReg); - - if (access_prepared) - exaFinishAccess(&pPixmap->drawable, fallback_index); - else if (need_sync && sync) - sync (pPixmap->drawable.pScreen); -} - -/** - * If the pixmap is currently dirty, this copies at least the dirty area from - * the framebuffer memory copy to the system memory copy. Both areas must be - * allocated. - */ -void -exaCopyDirtyToSys (ExaMigrationPtr migrate) -{ - PixmapPtr pPixmap = migrate->pPix; - ExaScreenPriv (pPixmap->drawable.pScreen); - ExaPixmapPriv (pPixmap); - - exaCopyDirty(migrate, &pExaPixmap->validSys, &pExaPixmap->validFB, - pExaScr->info->DownloadFromScreen, EXA_PREPARE_SRC, - exaWaitSync); -} - -/** - * If the pixmap is currently dirty, this copies at least the dirty area from - * the system memory copy to the framebuffer memory copy. Both areas must be - * allocated. - */ -void -exaCopyDirtyToFb (ExaMigrationPtr migrate) -{ - PixmapPtr pPixmap = migrate->pPix; - ExaScreenPriv (pPixmap->drawable.pScreen); - ExaPixmapPriv (pPixmap); - - exaCopyDirty(migrate, &pExaPixmap->validFB, &pExaPixmap->validSys, - pExaScr->info->UploadToScreen, EXA_PREPARE_DEST, NULL); -} - -/** - * Allocates a framebuffer copy of the pixmap if necessary, and then copies - * any necessary pixmap data into the framebuffer copy and points the pixmap at - * it. - * - * Note that when first allocated, a pixmap will have FALSE dirty flag. - * This is intentional because pixmap data starts out undefined. So if we move - * it in due to the first operation against it being accelerated, it will have - * undefined framebuffer contents that we didn't have to upload. If we do - * moveouts (and moveins) after the first movein, then we will only have to copy - * back and forth if the pixmap was written to after the last synchronization of - * the two copies. Then, at exaPixmapSave (when the framebuffer copy goes away) - * we mark the pixmap dirty, so that the next exaMoveInPixmap will actually move - * all the data, since it's almost surely all valid now. - */ -static void -exaDoMoveInPixmap (ExaMigrationPtr migrate) -{ - PixmapPtr pPixmap = migrate->pPix; - ScreenPtr pScreen = pPixmap->drawable.pScreen; - ExaScreenPriv (pScreen); - ExaPixmapPriv (pPixmap); - - /* If we're VT-switched away, no touching card memory allowed. */ - if (pExaScr->swappedOut) - return; - - /* If we're not allowed to move, then fail. */ - if (exaPixmapIsPinned(pPixmap)) - return; - - /* Don't migrate in pixmaps which are less than 8bpp. This avoids a lot of - * fragility in EXA, and <8bpp is probably not used enough any more to care - * (at least, not in acceleratd paths). - */ - if (pPixmap->drawable.bitsPerPixel < 8) - return; - - if (pExaPixmap->accel_blocked) - return; - - if (pExaPixmap->area == NULL) { - pExaPixmap->area = - exaOffscreenAlloc (pScreen, pExaPixmap->fb_size, - pExaScr->info->pixmapOffsetAlign, FALSE, - exaPixmapSave, (pointer) pPixmap); - if (pExaPixmap->area == NULL) - return; - - pExaPixmap->fb_ptr = (CARD8 *) pExaScr->info->memoryBase + - pExaPixmap->area->offset; - } - - exaCopyDirtyToFb (migrate); - - if (exaPixmapHasGpuCopy(pPixmap)) - return; - - DBG_MIGRATE (("-> %p (0x%x) (%dx%d) (%c)\n", pPixmap, - (ExaGetPixmapPriv(pPixmap)->area ? - ExaGetPixmapPriv(pPixmap)->area->offset : 0), - pPixmap->drawable.width, - pPixmap->drawable.height, - exaPixmapIsDirty(pPixmap) ? 'd' : 'c')); - - pExaPixmap->use_gpu_copy = TRUE; - - pPixmap->devKind = pExaPixmap->fb_pitch; - pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; -} - -void -exaMoveInPixmap_classic (PixmapPtr pPixmap) -{ - static ExaMigrationRec migrate = { .as_dst = FALSE, .as_src = TRUE, - .pReg = NULL }; - - migrate.pPix = pPixmap; - exaDoMoveInPixmap (&migrate); -} - -/** - * Switches the current active location of the pixmap to system memory, copying - * updated data out if necessary. - */ -static void -exaDoMoveOutPixmap (ExaMigrationPtr migrate) -{ - PixmapPtr pPixmap = migrate->pPix; - ExaPixmapPriv (pPixmap); - - if (!pExaPixmap->area || exaPixmapIsPinned(pPixmap)) - return; - - exaCopyDirtyToSys (migrate); - - if (exaPixmapHasGpuCopy(pPixmap)) { - - DBG_MIGRATE (("<- %p (%p) (%dx%d) (%c)\n", pPixmap, - (void*)(ExaGetPixmapPriv(pPixmap)->area ? - ExaGetPixmapPriv(pPixmap)->area->offset : 0), - pPixmap->drawable.width, - pPixmap->drawable.height, - exaPixmapIsDirty(pPixmap) ? 'd' : 'c')); - - pExaPixmap->use_gpu_copy = FALSE; - - pPixmap->devKind = pExaPixmap->sys_pitch; - pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; - } -} - -void -exaMoveOutPixmap_classic (PixmapPtr pPixmap) -{ - static ExaMigrationRec migrate = { .as_dst = FALSE, .as_src = TRUE, - .pReg = NULL }; - - migrate.pPix = pPixmap; - exaDoMoveOutPixmap (&migrate); -} - - -/** - * Copies out important pixmap data and removes references to framebuffer area. - * Called when the memory manager decides it's time to kick the pixmap out of - * framebuffer entirely. - */ -void -exaPixmapSave (ScreenPtr pScreen, ExaOffscreenArea *area) -{ - PixmapPtr pPixmap = area->privData; - ExaPixmapPriv(pPixmap); - - exaMoveOutPixmap(pPixmap); - - pExaPixmap->fb_ptr = NULL; - pExaPixmap->area = NULL; - - /* Mark all FB bits as invalid, so all valid system bits get copied to FB - * next time */ - REGION_EMPTY(pPixmap->drawable.pScreen, &pExaPixmap->validFB); -} - -/** - * For the "greedy" migration scheme, pushes the pixmap toward being located in - * framebuffer memory. - */ -static void -exaMigrateTowardFb (ExaMigrationPtr migrate) -{ - PixmapPtr pPixmap = migrate->pPix; - ExaPixmapPriv (pPixmap); - - if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED) { - DBG_MIGRATE(("UseScreen: not migrating pinned pixmap %p\n", - (pointer)pPixmap)); - return; - } - - DBG_MIGRATE(("UseScreen %p score %d\n", - (pointer)pPixmap, pExaPixmap->score)); - - if (pExaPixmap->score == EXA_PIXMAP_SCORE_INIT) { - exaDoMoveInPixmap(migrate); - pExaPixmap->score = 0; - } - - if (pExaPixmap->score < EXA_PIXMAP_SCORE_MAX) - pExaPixmap->score++; - - if (pExaPixmap->score >= EXA_PIXMAP_SCORE_MOVE_IN && - !exaPixmapHasGpuCopy(pPixmap)) - { - exaDoMoveInPixmap(migrate); - } - - if (exaPixmapHasGpuCopy(pPixmap)) { - exaCopyDirtyToFb (migrate); - ExaOffscreenMarkUsed (pPixmap); - } else - exaCopyDirtyToSys (migrate); -} - -/** - * For the "greedy" migration scheme, pushes the pixmap toward being located in - * system memory. - */ -static void -exaMigrateTowardSys (ExaMigrationPtr migrate) -{ - PixmapPtr pPixmap = migrate->pPix; - ExaPixmapPriv (pPixmap); - - DBG_MIGRATE(("UseMem: %p score %d\n", (pointer)pPixmap, pExaPixmap->score)); - - if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED) - return; - - if (pExaPixmap->score == EXA_PIXMAP_SCORE_INIT) - pExaPixmap->score = 0; - - if (pExaPixmap->score > EXA_PIXMAP_SCORE_MIN) - pExaPixmap->score--; - - if (pExaPixmap->score <= EXA_PIXMAP_SCORE_MOVE_OUT && pExaPixmap->area) - exaDoMoveOutPixmap(migrate); - - if (exaPixmapHasGpuCopy(pPixmap)) { - exaCopyDirtyToFb (migrate); - ExaOffscreenMarkUsed (pPixmap); - } else - exaCopyDirtyToSys (migrate); -} - -/** - * If the pixmap has both a framebuffer and system memory copy, this function - * asserts that both of them are the same. - */ -static Bool -exaAssertNotDirty (PixmapPtr pPixmap) -{ - ExaPixmapPriv (pPixmap); - CARD8 *dst, *src; - RegionRec ValidReg; - int dst_pitch, src_pitch, cpp, y, nbox, save_pitch; - BoxPtr pBox; - Bool ret = TRUE, save_use_gpu_copy; - - if (exaPixmapIsPinned(pPixmap) || pExaPixmap->area == NULL) - return ret; - - REGION_NULL(pScreen, &ValidReg); - REGION_INTERSECT(pScreen, &ValidReg, &pExaPixmap->validFB, - &pExaPixmap->validSys); - nbox = REGION_NUM_RECTS(&ValidReg); - - if (!nbox) - goto out; - - pBox = REGION_RECTS(&ValidReg); - - dst_pitch = pExaPixmap->sys_pitch; - src_pitch = pExaPixmap->fb_pitch; - cpp = pPixmap->drawable.bitsPerPixel / 8; - - save_use_gpu_copy = pExaPixmap->use_gpu_copy; - save_pitch = pPixmap->devKind; - pExaPixmap->use_gpu_copy = TRUE; - pPixmap->devKind = pExaPixmap->fb_pitch; - - if (!ExaDoPrepareAccess(pPixmap, EXA_PREPARE_SRC)) - goto skip; - - while (nbox--) { - int rowbytes; - - pBox->x1 = max(pBox->x1, 0); - pBox->y1 = max(pBox->y1, 0); - pBox->x2 = min(pBox->x2, pPixmap->drawable.width); - pBox->y2 = min(pBox->y2, pPixmap->drawable.height); - - if (pBox->x1 >= pBox->x2 || pBox->y1 >= pBox->y2) - continue; - - rowbytes = (pBox->x2 - pBox->x1) * cpp; - src = (CARD8 *) pPixmap->devPrivate.ptr + pBox->y1 * src_pitch + pBox->x1 * cpp; - dst = pExaPixmap->sys_ptr + pBox->y1 * dst_pitch + pBox->x1 * cpp; - - for (y = pBox->y1; y < pBox->y2; - y++, src += src_pitch, dst += dst_pitch) { - if (memcmp(dst, src, rowbytes) != 0) { - ret = FALSE; - exaPixmapDirty(pPixmap, pBox->x1, pBox->y1, pBox->x2, - pBox->y2); - break; - } - } - } - -skip: - exaFinishAccess(&pPixmap->drawable, EXA_PREPARE_SRC); - - pExaPixmap->use_gpu_copy = save_use_gpu_copy; - pPixmap->devKind = save_pitch; - -out: - REGION_UNINIT(pScreen, &ValidReg); - return ret; -} - -/** - * Performs migration of the pixmaps according to the operation information - * provided in pixmaps and can_accel and the migration scheme chosen in the - * config file. - */ -void -exaDoMigration_classic (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel) -{ - ScreenPtr pScreen = pixmaps[0].pPix->drawable.pScreen; - ExaScreenPriv(pScreen); - int i, j; - - /* If this debugging flag is set, check each pixmap for whether it is marked - * as clean, and if so, actually check if that's the case. This should help - * catch issues with failing to mark a drawable as dirty. While it will - * catch them late (after the operation happened), it at least explains what - * went wrong, and instrumenting the code to find what operation happened - * to the pixmap last shouldn't be hard. - */ - if (pExaScr->checkDirtyCorrectness) { - for (i = 0; i < npixmaps; i++) { - if (!exaPixmapIsDirty (pixmaps[i].pPix) && - !exaAssertNotDirty (pixmaps[i].pPix)) - ErrorF("%s: Pixmap %d dirty but not marked as such!\n", __func__, i); - } - } - /* If anything is pinned in system memory, we won't be able to - * accelerate. - */ - for (i = 0; i < npixmaps; i++) { - if (exaPixmapIsPinned (pixmaps[i].pPix) && - !exaPixmapHasGpuCopy (pixmaps[i].pPix)) - { - EXA_FALLBACK(("Pixmap %p (%dx%d) pinned in sys\n", pixmaps[i].pPix, - pixmaps[i].pPix->drawable.width, - pixmaps[i].pPix->drawable.height)); - can_accel = FALSE; - break; - } - } - - if (pExaScr->migration == ExaMigrationSmart) { - /* If we've got something as a destination that we shouldn't cause to - * become newly dirtied, take the unaccelerated route. - */ - for (i = 0; i < npixmaps; i++) { - if (pixmaps[i].as_dst && !exaPixmapShouldBeInFB (pixmaps[i].pPix) && - !exaPixmapIsDirty (pixmaps[i].pPix)) - { - for (i = 0; i < npixmaps; i++) { - if (!exaPixmapIsDirty (pixmaps[i].pPix)) - exaDoMoveOutPixmap (pixmaps + i); - } - return; - } - } - - /* If we aren't going to accelerate, then we migrate everybody toward - * system memory, and kick out if it's free. - */ - if (!can_accel) { - for (i = 0; i < npixmaps; i++) { - exaMigrateTowardSys (pixmaps + i); - if (!exaPixmapIsDirty (pixmaps[i].pPix)) - exaDoMoveOutPixmap (pixmaps + i); - } - return; - } - - /* Finally, the acceleration path. Move them all in. */ - for (i = 0; i < npixmaps; i++) { - exaMigrateTowardFb(pixmaps + i); - exaDoMoveInPixmap(pixmaps + i); - } - } else if (pExaScr->migration == ExaMigrationGreedy) { - /* If we can't accelerate, either because the driver can't or because one of - * the pixmaps is pinned in system memory, then we migrate everybody toward - * system memory. - * - * We also migrate toward system if all pixmaps involved are currently in - * system memory -- this can mitigate thrashing when there are significantly - * more pixmaps active than would fit in memory. - * - * If not, then we migrate toward FB so that hopefully acceleration can - * happen. - */ - if (!can_accel) { - for (i = 0; i < npixmaps; i++) - exaMigrateTowardSys (pixmaps + i); - return; - } - - for (i = 0; i < npixmaps; i++) { - if (exaPixmapHasGpuCopy(pixmaps[i].pPix)) { - /* Found one in FB, so move all to FB. */ - for (j = 0; j < npixmaps; j++) - exaMigrateTowardFb(pixmaps + i); - return; - } - } - - /* Nobody's in FB, so move all away from FB. */ - for (i = 0; i < npixmaps; i++) - exaMigrateTowardSys(pixmaps + i); - } else if (pExaScr->migration == ExaMigrationAlways) { - /* Always move the pixmaps out if we can't accelerate. If we can - * accelerate, try to move them all in. If that fails, then move them - * back out. - */ - if (!can_accel) { - for (i = 0; i < npixmaps; i++) - exaDoMoveOutPixmap(pixmaps + i); - return; - } - - /* Now, try to move them all into FB */ - for (i = 0; i < npixmaps; i++) { - exaDoMoveInPixmap(pixmaps + i); - } - - /* If we couldn't fit everything in, abort */ - for (i = 0; i < npixmaps; i++) { - if (!exaPixmapHasGpuCopy(pixmaps[i].pPix)) { - return; - } - } - - /* Yay, everything has a gpu copy, mark memory as used */ - for (i = 0; i < npixmaps; i++) { - ExaOffscreenMarkUsed (pixmaps[i].pPix); - } - } -} - -void -exaPrepareAccessReg_classic(PixmapPtr pPixmap, int index, RegionPtr pReg) -{ - ExaMigrationRec pixmaps[1]; - - if (index == EXA_PREPARE_DEST || index == EXA_PREPARE_AUX_DEST) { - pixmaps[0].as_dst = TRUE; - pixmaps[0].as_src = FALSE; - } else { - pixmaps[0].as_dst = FALSE; - pixmaps[0].as_src = TRUE; - } - pixmaps[0].pPix = pPixmap; - pixmaps[0].pReg = pReg; - - exaDoMigration(pixmaps, 1, FALSE); - - (void)ExaDoPrepareAccess(pPixmap, index); -} +/* + * Copyright © 2006 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Authors: + * Eric Anholt + * Michel Dänzer + * + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include + +#include "exa_priv.h" +#include "exa.h" + +#if DEBUG_MIGRATE +#define DBG_MIGRATE(a) ErrorF a +#else +#define DBG_MIGRATE(a) +#endif + +/** + * The fallback path for UTS/DFS failing is to just memcpy. exaCopyDirtyToSys + * and exaCopyDirtyToFb both needed to do this loop. + */ +static void +exaMemcpyBox (PixmapPtr pPixmap, BoxPtr pbox, CARD8 *src, int src_pitch, + CARD8 *dst, int dst_pitch) + { + int i, cpp = pPixmap->drawable.bitsPerPixel / 8; + int bytes = (pbox->x2 - pbox->x1) * cpp; + + src += pbox->y1 * src_pitch + pbox->x1 * cpp; + dst += pbox->y1 * dst_pitch + pbox->x1 * cpp; + + for (i = pbox->y2 - pbox->y1; i; i--) { + memcpy (dst, src, bytes); + src += src_pitch; + dst += dst_pitch; + } +} + +/** + * Returns TRUE if the pixmap is dirty (has been modified in its current + * location compared to the other), or lacks a private for tracking + * dirtiness. + */ +static Bool +exaPixmapIsDirty (PixmapPtr pPix) +{ + ExaPixmapPriv (pPix); + + if (pExaPixmap == NULL) + EXA_FatalErrorDebugWithRet(("EXA bug: exaPixmapIsDirty was called on a non-exa pixmap.\n"), TRUE); + + if (!pExaPixmap->pDamage) + return FALSE; + + return RegionNotEmpty(DamageRegion(pExaPixmap->pDamage)) || + !RegionEqual(&pExaPixmap->validSys, &pExaPixmap->validFB); +} + +/** + * Returns TRUE if the pixmap is either pinned in FB, or has a sufficient score + * to be considered "should be in framebuffer". That's just anything that has + * had more acceleration than fallbacks, or has no score yet. + * + * Only valid if using a migration scheme that tracks score. + */ +static Bool +exaPixmapShouldBeInFB (PixmapPtr pPix) +{ + ExaPixmapPriv (pPix); + + if (exaPixmapIsPinned (pPix)) + return TRUE; + + return pExaPixmap->score >= 0; +} + +/** + * If the pixmap is currently dirty, this copies at least the dirty area from + * FB to system or vice versa. Both areas must be allocated. + */ +static void +exaCopyDirty(ExaMigrationPtr migrate, RegionPtr pValidDst, RegionPtr pValidSrc, + Bool (*transfer) (PixmapPtr pPix, int x, int y, int w, int h, + char *sys, int sys_pitch), int fallback_index, + void (*sync) (ScreenPtr pScreen)) +{ + PixmapPtr pPixmap = migrate->pPix; + ExaPixmapPriv (pPixmap); + RegionPtr damage = DamageRegion (pExaPixmap->pDamage); + RegionRec CopyReg; + Bool save_use_gpu_copy; + int save_pitch; + BoxPtr pBox; + int nbox; + Bool access_prepared = FALSE; + Bool need_sync = FALSE; + + /* Damaged bits are valid in current copy but invalid in other one */ + if (pExaPixmap->use_gpu_copy) { + RegionUnion(&pExaPixmap->validFB, &pExaPixmap->validFB, + damage); + RegionSubtract(&pExaPixmap->validSys, &pExaPixmap->validSys, + damage); + } else { + RegionUnion(&pExaPixmap->validSys, &pExaPixmap->validSys, + damage); + RegionSubtract(&pExaPixmap->validFB, &pExaPixmap->validFB, + damage); + } + + RegionEmpty(damage); + + /* Copy bits valid in source but not in destination */ + RegionNull(&CopyReg); + RegionSubtract(&CopyReg, pValidSrc, pValidDst); + + if (migrate->as_dst) { + ExaScreenPriv (pPixmap->drawable.pScreen); + + /* XXX: The pending damage region will be marked as damaged after the + * operation, so it should serve as an upper bound for the region that + * needs to be synchronized for the operation. Unfortunately, this + * causes corruption in some cases, e.g. when starting compiz. See + * https://bugs.freedesktop.org/show_bug.cgi?id=12916 . + */ + if (pExaScr->optimize_migration) { + RegionPtr pending_damage = DamagePendingRegion(pExaPixmap->pDamage); + +#if DEBUG_MIGRATE + if (RegionNil(pending_damage)) { + static Bool firsttime = TRUE; + + if (firsttime) { + ErrorF("%s: Pending damage region empty!\n", __func__); + firsttime = FALSE; + } + } +#endif + + /* Try to prevent destination valid region from growing too many + * rects by filling it up to the extents of the union of the + * destination valid region and the pending damage region. + */ + if (RegionNumRects(pValidDst) > 10) { + BoxRec box; + BoxPtr pValidExt, pDamageExt; + RegionRec closure; + + pValidExt = RegionExtents(pValidDst); + pDamageExt = RegionExtents(pending_damage); + + box.x1 = min(pValidExt->x1, pDamageExt->x1); + box.y1 = min(pValidExt->y1, pDamageExt->y1); + box.x2 = max(pValidExt->x2, pDamageExt->x2); + box.y2 = max(pValidExt->y2, pDamageExt->y2); + + RegionInit(&closure, &box, 0); + RegionIntersect(&CopyReg, &CopyReg, &closure); + } else + RegionIntersect(&CopyReg, &CopyReg, pending_damage); + } + + /* The caller may provide a region to be subtracted from the calculated + * dirty region. This is to avoid migration of bits that don't + * contribute to the result of the operation. + */ + if (migrate->pReg) + RegionSubtract(&CopyReg, &CopyReg, migrate->pReg); + } else { + /* The caller may restrict the region to be migrated for source pixmaps + * to what's relevant for the operation. + */ + if (migrate->pReg) + RegionIntersect(&CopyReg, &CopyReg, migrate->pReg); + } + + pBox = RegionRects(&CopyReg); + nbox = RegionNumRects(&CopyReg); + + save_use_gpu_copy = pExaPixmap->use_gpu_copy; + save_pitch = pPixmap->devKind; + pExaPixmap->use_gpu_copy = TRUE; + pPixmap->devKind = pExaPixmap->fb_pitch; + + while (nbox--) { + pBox->x1 = max(pBox->x1, 0); + pBox->y1 = max(pBox->y1, 0); + pBox->x2 = min(pBox->x2, pPixmap->drawable.width); + pBox->y2 = min(pBox->y2, pPixmap->drawable.height); + + if (pBox->x1 >= pBox->x2 || pBox->y1 >= pBox->y2) + continue; + + if (!transfer || !transfer (pPixmap, + pBox->x1, pBox->y1, + pBox->x2 - pBox->x1, + pBox->y2 - pBox->y1, + (char *) (pExaPixmap->sys_ptr + + pBox->y1 * pExaPixmap->sys_pitch + + pBox->x1 * pPixmap->drawable.bitsPerPixel / 8), + pExaPixmap->sys_pitch)) + { + if (!access_prepared) { + ExaDoPrepareAccess(pPixmap, fallback_index); + access_prepared = TRUE; + } + if (fallback_index == EXA_PREPARE_DEST) { + exaMemcpyBox (pPixmap, pBox, + pExaPixmap->sys_ptr, pExaPixmap->sys_pitch, + pPixmap->devPrivate.ptr, pPixmap->devKind); + } else { + exaMemcpyBox (pPixmap, pBox, + pPixmap->devPrivate.ptr, pPixmap->devKind, + pExaPixmap->sys_ptr, pExaPixmap->sys_pitch); + } + } else + need_sync = TRUE; + + pBox++; + } + + pExaPixmap->use_gpu_copy = save_use_gpu_copy; + pPixmap->devKind = save_pitch; + + /* Try to prevent source valid region from growing too many rects by + * removing parts of it which are also in the destination valid region. + * Removing anything beyond that would lead to data loss. + */ + if (RegionNumRects(pValidSrc) > 20) + RegionSubtract(pValidSrc, pValidSrc, pValidDst); + + /* The copied bits are now valid in destination */ + RegionUnion(pValidDst, pValidDst, &CopyReg); + + RegionUninit(&CopyReg); + + if (access_prepared) + exaFinishAccess(&pPixmap->drawable, fallback_index); + else if (need_sync && sync) + sync (pPixmap->drawable.pScreen); +} + +/** + * If the pixmap is currently dirty, this copies at least the dirty area from + * the framebuffer memory copy to the system memory copy. Both areas must be + * allocated. + */ +void +exaCopyDirtyToSys (ExaMigrationPtr migrate) +{ + PixmapPtr pPixmap = migrate->pPix; + ExaScreenPriv (pPixmap->drawable.pScreen); + ExaPixmapPriv (pPixmap); + + exaCopyDirty(migrate, &pExaPixmap->validSys, &pExaPixmap->validFB, + pExaScr->info->DownloadFromScreen, EXA_PREPARE_SRC, + exaWaitSync); +} + +/** + * If the pixmap is currently dirty, this copies at least the dirty area from + * the system memory copy to the framebuffer memory copy. Both areas must be + * allocated. + */ +void +exaCopyDirtyToFb (ExaMigrationPtr migrate) +{ + PixmapPtr pPixmap = migrate->pPix; + ExaScreenPriv (pPixmap->drawable.pScreen); + ExaPixmapPriv (pPixmap); + + exaCopyDirty(migrate, &pExaPixmap->validFB, &pExaPixmap->validSys, + pExaScr->info->UploadToScreen, EXA_PREPARE_DEST, NULL); +} + +/** + * Allocates a framebuffer copy of the pixmap if necessary, and then copies + * any necessary pixmap data into the framebuffer copy and points the pixmap at + * it. + * + * Note that when first allocated, a pixmap will have FALSE dirty flag. + * This is intentional because pixmap data starts out undefined. So if we move + * it in due to the first operation against it being accelerated, it will have + * undefined framebuffer contents that we didn't have to upload. If we do + * moveouts (and moveins) after the first movein, then we will only have to copy + * back and forth if the pixmap was written to after the last synchronization of + * the two copies. Then, at exaPixmapSave (when the framebuffer copy goes away) + * we mark the pixmap dirty, so that the next exaMoveInPixmap will actually move + * all the data, since it's almost surely all valid now. + */ +static void +exaDoMoveInPixmap (ExaMigrationPtr migrate) +{ + PixmapPtr pPixmap = migrate->pPix; + ScreenPtr pScreen = pPixmap->drawable.pScreen; + ExaScreenPriv (pScreen); + ExaPixmapPriv (pPixmap); + + /* If we're VT-switched away, no touching card memory allowed. */ + if (pExaScr->swappedOut) + return; + + /* If we're not allowed to move, then fail. */ + if (exaPixmapIsPinned(pPixmap)) + return; + + /* Don't migrate in pixmaps which are less than 8bpp. This avoids a lot of + * fragility in EXA, and <8bpp is probably not used enough any more to care + * (at least, not in acceleratd paths). + */ + if (pPixmap->drawable.bitsPerPixel < 8) + return; + + if (pExaPixmap->accel_blocked) + return; + + if (pExaPixmap->area == NULL) { + pExaPixmap->area = + exaOffscreenAlloc (pScreen, pExaPixmap->fb_size, + pExaScr->info->pixmapOffsetAlign, FALSE, + exaPixmapSave, (pointer) pPixmap); + if (pExaPixmap->area == NULL) + return; + + pExaPixmap->fb_ptr = (CARD8 *) pExaScr->info->memoryBase + + pExaPixmap->area->offset; + } + + exaCopyDirtyToFb (migrate); + + if (exaPixmapHasGpuCopy(pPixmap)) + return; + + DBG_MIGRATE (("-> %p (0x%x) (%dx%d) (%c)\n", pPixmap, + (ExaGetPixmapPriv(pPixmap)->area ? + ExaGetPixmapPriv(pPixmap)->area->offset : 0), + pPixmap->drawable.width, + pPixmap->drawable.height, + exaPixmapIsDirty(pPixmap) ? 'd' : 'c')); + + pExaPixmap->use_gpu_copy = TRUE; + + pPixmap->devKind = pExaPixmap->fb_pitch; + pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; +} + +void +exaMoveInPixmap_classic (PixmapPtr pPixmap) +{ + static ExaMigrationRec migrate = { .as_dst = FALSE, .as_src = TRUE, + .pReg = NULL }; + + migrate.pPix = pPixmap; + exaDoMoveInPixmap (&migrate); +} + +/** + * Switches the current active location of the pixmap to system memory, copying + * updated data out if necessary. + */ +static void +exaDoMoveOutPixmap (ExaMigrationPtr migrate) +{ + PixmapPtr pPixmap = migrate->pPix; + ExaPixmapPriv (pPixmap); + + if (!pExaPixmap->area || exaPixmapIsPinned(pPixmap)) + return; + + exaCopyDirtyToSys (migrate); + + if (exaPixmapHasGpuCopy(pPixmap)) { + + DBG_MIGRATE (("<- %p (%p) (%dx%d) (%c)\n", pPixmap, + (void*)(ExaGetPixmapPriv(pPixmap)->area ? + ExaGetPixmapPriv(pPixmap)->area->offset : 0), + pPixmap->drawable.width, + pPixmap->drawable.height, + exaPixmapIsDirty(pPixmap) ? 'd' : 'c')); + + pExaPixmap->use_gpu_copy = FALSE; + + pPixmap->devKind = pExaPixmap->sys_pitch; + pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; + } +} + +void +exaMoveOutPixmap_classic (PixmapPtr pPixmap) +{ + static ExaMigrationRec migrate = { .as_dst = FALSE, .as_src = TRUE, + .pReg = NULL }; + + migrate.pPix = pPixmap; + exaDoMoveOutPixmap (&migrate); +} + + +/** + * Copies out important pixmap data and removes references to framebuffer area. + * Called when the memory manager decides it's time to kick the pixmap out of + * framebuffer entirely. + */ +void +exaPixmapSave (ScreenPtr pScreen, ExaOffscreenArea *area) +{ + PixmapPtr pPixmap = area->privData; + ExaPixmapPriv(pPixmap); + + exaMoveOutPixmap(pPixmap); + + pExaPixmap->fb_ptr = NULL; + pExaPixmap->area = NULL; + + /* Mark all FB bits as invalid, so all valid system bits get copied to FB + * next time */ + RegionEmpty(&pExaPixmap->validFB); +} + +/** + * For the "greedy" migration scheme, pushes the pixmap toward being located in + * framebuffer memory. + */ +static void +exaMigrateTowardFb (ExaMigrationPtr migrate) +{ + PixmapPtr pPixmap = migrate->pPix; + ExaPixmapPriv (pPixmap); + + if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED) { + DBG_MIGRATE(("UseScreen: not migrating pinned pixmap %p\n", + (pointer)pPixmap)); + return; + } + + DBG_MIGRATE(("UseScreen %p score %d\n", + (pointer)pPixmap, pExaPixmap->score)); + + if (pExaPixmap->score == EXA_PIXMAP_SCORE_INIT) { + exaDoMoveInPixmap(migrate); + pExaPixmap->score = 0; + } + + if (pExaPixmap->score < EXA_PIXMAP_SCORE_MAX) + pExaPixmap->score++; + + if (pExaPixmap->score >= EXA_PIXMAP_SCORE_MOVE_IN && + !exaPixmapHasGpuCopy(pPixmap)) + { + exaDoMoveInPixmap(migrate); + } + + if (exaPixmapHasGpuCopy(pPixmap)) { + exaCopyDirtyToFb (migrate); + ExaOffscreenMarkUsed (pPixmap); + } else + exaCopyDirtyToSys (migrate); +} + +/** + * For the "greedy" migration scheme, pushes the pixmap toward being located in + * system memory. + */ +static void +exaMigrateTowardSys (ExaMigrationPtr migrate) +{ + PixmapPtr pPixmap = migrate->pPix; + ExaPixmapPriv (pPixmap); + + DBG_MIGRATE(("UseMem: %p score %d\n", (pointer)pPixmap, pExaPixmap->score)); + + if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED) + return; + + if (pExaPixmap->score == EXA_PIXMAP_SCORE_INIT) + pExaPixmap->score = 0; + + if (pExaPixmap->score > EXA_PIXMAP_SCORE_MIN) + pExaPixmap->score--; + + if (pExaPixmap->score <= EXA_PIXMAP_SCORE_MOVE_OUT && pExaPixmap->area) + exaDoMoveOutPixmap(migrate); + + if (exaPixmapHasGpuCopy(pPixmap)) { + exaCopyDirtyToFb (migrate); + ExaOffscreenMarkUsed (pPixmap); + } else + exaCopyDirtyToSys (migrate); +} + +/** + * If the pixmap has both a framebuffer and system memory copy, this function + * asserts that both of them are the same. + */ +static Bool +exaAssertNotDirty (PixmapPtr pPixmap) +{ + ExaPixmapPriv (pPixmap); + CARD8 *dst, *src; + RegionRec ValidReg; + int dst_pitch, src_pitch, cpp, y, nbox, save_pitch; + BoxPtr pBox; + Bool ret = TRUE, save_use_gpu_copy; + + if (exaPixmapIsPinned(pPixmap) || pExaPixmap->area == NULL) + return ret; + + RegionNull(&ValidReg); + RegionIntersect(&ValidReg, &pExaPixmap->validFB, + &pExaPixmap->validSys); + nbox = RegionNumRects(&ValidReg); + + if (!nbox) + goto out; + + pBox = RegionRects(&ValidReg); + + dst_pitch = pExaPixmap->sys_pitch; + src_pitch = pExaPixmap->fb_pitch; + cpp = pPixmap->drawable.bitsPerPixel / 8; + + save_use_gpu_copy = pExaPixmap->use_gpu_copy; + save_pitch = pPixmap->devKind; + pExaPixmap->use_gpu_copy = TRUE; + pPixmap->devKind = pExaPixmap->fb_pitch; + + if (!ExaDoPrepareAccess(pPixmap, EXA_PREPARE_SRC)) + goto skip; + + while (nbox--) { + int rowbytes; + + pBox->x1 = max(pBox->x1, 0); + pBox->y1 = max(pBox->y1, 0); + pBox->x2 = min(pBox->x2, pPixmap->drawable.width); + pBox->y2 = min(pBox->y2, pPixmap->drawable.height); + + if (pBox->x1 >= pBox->x2 || pBox->y1 >= pBox->y2) + continue; + + rowbytes = (pBox->x2 - pBox->x1) * cpp; + src = (CARD8 *) pPixmap->devPrivate.ptr + pBox->y1 * src_pitch + pBox->x1 * cpp; + dst = pExaPixmap->sys_ptr + pBox->y1 * dst_pitch + pBox->x1 * cpp; + + for (y = pBox->y1; y < pBox->y2; + y++, src += src_pitch, dst += dst_pitch) { + if (memcmp(dst, src, rowbytes) != 0) { + ret = FALSE; + exaPixmapDirty(pPixmap, pBox->x1, pBox->y1, pBox->x2, + pBox->y2); + break; + } + } + } + +skip: + exaFinishAccess(&pPixmap->drawable, EXA_PREPARE_SRC); + + pExaPixmap->use_gpu_copy = save_use_gpu_copy; + pPixmap->devKind = save_pitch; + +out: + RegionUninit(&ValidReg); + return ret; +} + +/** + * Performs migration of the pixmaps according to the operation information + * provided in pixmaps and can_accel and the migration scheme chosen in the + * config file. + */ +void +exaDoMigration_classic (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel) +{ + ScreenPtr pScreen = pixmaps[0].pPix->drawable.pScreen; + ExaScreenPriv(pScreen); + int i, j; + + /* If this debugging flag is set, check each pixmap for whether it is marked + * as clean, and if so, actually check if that's the case. This should help + * catch issues with failing to mark a drawable as dirty. While it will + * catch them late (after the operation happened), it at least explains what + * went wrong, and instrumenting the code to find what operation happened + * to the pixmap last shouldn't be hard. + */ + if (pExaScr->checkDirtyCorrectness) { + for (i = 0; i < npixmaps; i++) { + if (!exaPixmapIsDirty (pixmaps[i].pPix) && + !exaAssertNotDirty (pixmaps[i].pPix)) + ErrorF("%s: Pixmap %d dirty but not marked as such!\n", __func__, i); + } + } + /* If anything is pinned in system memory, we won't be able to + * accelerate. + */ + for (i = 0; i < npixmaps; i++) { + if (exaPixmapIsPinned (pixmaps[i].pPix) && + !exaPixmapHasGpuCopy (pixmaps[i].pPix)) + { + EXA_FALLBACK(("Pixmap %p (%dx%d) pinned in sys\n", pixmaps[i].pPix, + pixmaps[i].pPix->drawable.width, + pixmaps[i].pPix->drawable.height)); + can_accel = FALSE; + break; + } + } + + if (pExaScr->migration == ExaMigrationSmart) { + /* If we've got something as a destination that we shouldn't cause to + * become newly dirtied, take the unaccelerated route. + */ + for (i = 0; i < npixmaps; i++) { + if (pixmaps[i].as_dst && !exaPixmapShouldBeInFB (pixmaps[i].pPix) && + !exaPixmapIsDirty (pixmaps[i].pPix)) + { + for (i = 0; i < npixmaps; i++) { + if (!exaPixmapIsDirty (pixmaps[i].pPix)) + exaDoMoveOutPixmap (pixmaps + i); + } + return; + } + } + + /* If we aren't going to accelerate, then we migrate everybody toward + * system memory, and kick out if it's free. + */ + if (!can_accel) { + for (i = 0; i < npixmaps; i++) { + exaMigrateTowardSys (pixmaps + i); + if (!exaPixmapIsDirty (pixmaps[i].pPix)) + exaDoMoveOutPixmap (pixmaps + i); + } + return; + } + + /* Finally, the acceleration path. Move them all in. */ + for (i = 0; i < npixmaps; i++) { + exaMigrateTowardFb(pixmaps + i); + exaDoMoveInPixmap(pixmaps + i); + } + } else if (pExaScr->migration == ExaMigrationGreedy) { + /* If we can't accelerate, either because the driver can't or because one of + * the pixmaps is pinned in system memory, then we migrate everybody toward + * system memory. + * + * We also migrate toward system if all pixmaps involved are currently in + * system memory -- this can mitigate thrashing when there are significantly + * more pixmaps active than would fit in memory. + * + * If not, then we migrate toward FB so that hopefully acceleration can + * happen. + */ + if (!can_accel) { + for (i = 0; i < npixmaps; i++) + exaMigrateTowardSys (pixmaps + i); + return; + } + + for (i = 0; i < npixmaps; i++) { + if (exaPixmapHasGpuCopy(pixmaps[i].pPix)) { + /* Found one in FB, so move all to FB. */ + for (j = 0; j < npixmaps; j++) + exaMigrateTowardFb(pixmaps + i); + return; + } + } + + /* Nobody's in FB, so move all away from FB. */ + for (i = 0; i < npixmaps; i++) + exaMigrateTowardSys(pixmaps + i); + } else if (pExaScr->migration == ExaMigrationAlways) { + /* Always move the pixmaps out if we can't accelerate. If we can + * accelerate, try to move them all in. If that fails, then move them + * back out. + */ + if (!can_accel) { + for (i = 0; i < npixmaps; i++) + exaDoMoveOutPixmap(pixmaps + i); + return; + } + + /* Now, try to move them all into FB */ + for (i = 0; i < npixmaps; i++) { + exaDoMoveInPixmap(pixmaps + i); + } + + /* If we couldn't fit everything in, abort */ + for (i = 0; i < npixmaps; i++) { + if (!exaPixmapHasGpuCopy(pixmaps[i].pPix)) { + return; + } + } + + /* Yay, everything has a gpu copy, mark memory as used */ + for (i = 0; i < npixmaps; i++) { + ExaOffscreenMarkUsed (pixmaps[i].pPix); + } + } +} + +void +exaPrepareAccessReg_classic(PixmapPtr pPixmap, int index, RegionPtr pReg) +{ + ExaMigrationRec pixmaps[1]; + + if (index == EXA_PREPARE_DEST || index == EXA_PREPARE_AUX_DEST) { + pixmaps[0].as_dst = TRUE; + pixmaps[0].as_src = FALSE; + } else { + pixmaps[0].as_dst = FALSE; + pixmaps[0].as_src = TRUE; + } + pixmaps[0].pPix = pPixmap; + pixmaps[0].pReg = pReg; + + exaDoMigration(pixmaps, 1, FALSE); + + (void)ExaDoPrepareAccess(pPixmap, index); +} diff --git a/xorg-server/exa/exa_mixed.c b/xorg-server/exa/exa_mixed.c index 49e04f22a..4425cede4 100644 --- a/xorg-server/exa/exa_mixed.c +++ b/xorg-server/exa/exa_mixed.c @@ -1,292 +1,291 @@ -/* - * Copyright © 2009 Maarten Maathuis - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - */ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include - -#include "exa_priv.h" -#include "exa.h" - -/* This file holds the driver allocated pixmaps + better initial placement code. - */ - -static _X_INLINE void* -ExaGetPixmapAddress(PixmapPtr p) -{ - ExaPixmapPriv(p); - - return pExaPixmap->sys_ptr; -} - -/** - * exaCreatePixmap() creates a new pixmap. - */ -PixmapPtr -exaCreatePixmap_mixed(ScreenPtr pScreen, int w, int h, int depth, - unsigned usage_hint) -{ - PixmapPtr pPixmap; - ExaPixmapPrivPtr pExaPixmap; - int bpp; - size_t paddedWidth; - ExaScreenPriv(pScreen); - - if (w > 32767 || h > 32767) - return NullPixmap; - - swap(pExaScr, pScreen, CreatePixmap); - pPixmap = pScreen->CreatePixmap(pScreen, 0, 0, depth, usage_hint); - swap(pExaScr, pScreen, CreatePixmap); - - if (!pPixmap) - return NULL; - - pExaPixmap = ExaGetPixmapPriv(pPixmap); - pExaPixmap->driverPriv = NULL; - - bpp = pPixmap->drawable.bitsPerPixel; - - paddedWidth = ((w * bpp + FB_MASK) >> FB_SHIFT) * sizeof(FbBits); - if (paddedWidth / 4 > 32767 || h > 32767) - return NullPixmap; - - /* We will allocate the system pixmap later if needed. */ - pPixmap->devPrivate.ptr = NULL; - pExaPixmap->sys_ptr = NULL; - pExaPixmap->sys_pitch = paddedWidth; - - pExaPixmap->area = NULL; - pExaPixmap->fb_ptr = NULL; - pExaPixmap->pDamage = NULL; - - exaSetFbPitch(pExaScr, pExaPixmap, w, h, bpp); - exaSetAccelBlock(pExaScr, pExaPixmap, - w, h, bpp); - - (*pScreen->ModifyPixmapHeader)(pPixmap, w, h, 0, 0, - paddedWidth, NULL); - - /* A scratch pixmap will become a driver pixmap right away. */ - if (!w || !h) { - exaCreateDriverPixmap_mixed(pPixmap); - pExaPixmap->use_gpu_copy = exaPixmapHasGpuCopy(pPixmap); - } else { - pExaPixmap->use_gpu_copy = FALSE; - - if (w == 1 && h == 1) { - pExaPixmap->sys_ptr = malloc((pPixmap->drawable.bitsPerPixel + 7) / 8); - - /* Set up damage tracking */ - pExaPixmap->pDamage = DamageCreate(exaDamageReport_mixed, NULL, - DamageReportNonEmpty, TRUE, - pPixmap->drawable.pScreen, - pPixmap); - - DamageRegister(&pPixmap->drawable, pExaPixmap->pDamage); - /* This ensures that pending damage reflects the current operation. */ - /* This is used by exa to optimize migration. */ - DamageSetReportAfterOp(pExaPixmap->pDamage, TRUE); - } - } - - /* During a fallback we must prepare access. */ - if (pExaScr->fallback_counter) - exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_AUX_DEST); - - return pPixmap; -} - -Bool -exaModifyPixmapHeader_mixed(PixmapPtr pPixmap, int width, int height, int depth, - int bitsPerPixel, int devKind, pointer pPixData) -{ - ScreenPtr pScreen; - ExaScreenPrivPtr pExaScr; - ExaPixmapPrivPtr pExaPixmap; - Bool ret, has_gpu_copy; - - if (!pPixmap) - return FALSE; - - pScreen = pPixmap->drawable.pScreen; - pExaScr = ExaGetScreenPriv(pScreen); - pExaPixmap = ExaGetPixmapPriv(pPixmap); - - if (pPixData) { - if (pExaPixmap->driverPriv) { - if (pExaPixmap->pDamage) { - DamageUnregister(&pPixmap->drawable, pExaPixmap->pDamage); - DamageDestroy(pExaPixmap->pDamage); - pExaPixmap->pDamage = NULL; - } - - pExaScr->info->DestroyPixmap(pScreen, pExaPixmap->driverPriv); - pExaPixmap->driverPriv = NULL; - } - - pExaPixmap->use_gpu_copy = FALSE; - pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED; - } - - has_gpu_copy = exaPixmapHasGpuCopy(pPixmap); - - if (width <= 0) - width = pPixmap->drawable.width; - - if (height <= 0) - height = pPixmap->drawable.height; - - if (bitsPerPixel <= 0) { - if (depth <= 0) - bitsPerPixel = pPixmap->drawable.bitsPerPixel; - else - bitsPerPixel = BitsPerPixel(depth); - } - - if (depth <= 0) - depth = pPixmap->drawable.depth; - - if (width != pPixmap->drawable.width || - height != pPixmap->drawable.height || - depth != pPixmap->drawable.depth || - bitsPerPixel != pPixmap->drawable.bitsPerPixel) { - if (pExaPixmap->driverPriv) { - exaSetFbPitch(pExaScr, pExaPixmap, - width, height, bitsPerPixel); - - exaSetAccelBlock(pExaScr, pExaPixmap, - width, height, bitsPerPixel); - REGION_EMPTY(pScreen, &pExaPixmap->validFB); - } - - /* Need to re-create system copy if there's also a GPU copy */ - if (has_gpu_copy && pExaPixmap->sys_ptr) { - free(pExaPixmap->sys_ptr); - pExaPixmap->sys_ptr = NULL; - pExaPixmap->sys_pitch = devKind > 0 ? devKind : - PixmapBytePad(width, depth); - DamageUnregister(&pPixmap->drawable, pExaPixmap->pDamage); - DamageDestroy(pExaPixmap->pDamage); - pExaPixmap->pDamage = NULL; - REGION_EMPTY(pScreen, &pExaPixmap->validSys); - - if (pExaScr->deferred_mixed_pixmap == pPixmap) - pExaScr->deferred_mixed_pixmap = NULL; - } - } - - if (has_gpu_copy) { - pPixmap->devPrivate.ptr = pExaPixmap->fb_ptr; - pPixmap->devKind = pExaPixmap->fb_pitch; - } else { - pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr; - pPixmap->devKind = pExaPixmap->sys_pitch; - } - - /* Only pass driver pixmaps to the driver. */ - if (pExaScr->info->ModifyPixmapHeader && pExaPixmap->driverPriv) { - ret = pExaScr->info->ModifyPixmapHeader(pPixmap, width, height, depth, - bitsPerPixel, devKind, pPixData); - if (ret == TRUE) - goto out; - } - - swap(pExaScr, pScreen, ModifyPixmapHeader); - ret = pScreen->ModifyPixmapHeader(pPixmap, width, height, depth, - bitsPerPixel, devKind, pPixData); - swap(pExaScr, pScreen, ModifyPixmapHeader); - -out: - if (has_gpu_copy) { - pExaPixmap->fb_ptr = pPixmap->devPrivate.ptr; - pExaPixmap->fb_pitch = pPixmap->devKind; - } else { - pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr; - pExaPixmap->sys_pitch = pPixmap->devKind; - } - /* Always NULL this, we don't want lingering pointers. */ - pPixmap->devPrivate.ptr = NULL; - - return ret; -} - -Bool -exaDestroyPixmap_mixed(PixmapPtr pPixmap) -{ - ScreenPtr pScreen = pPixmap->drawable.pScreen; - ExaScreenPriv(pScreen); - Bool ret; - - if (pPixmap->refcnt == 1) - { - ExaPixmapPriv (pPixmap); - - /* During a fallback we must finish access, but we don't know the index. */ - if (pExaScr->fallback_counter) - exaFinishAccess(&pPixmap->drawable, -1); - - if (pExaScr->deferred_mixed_pixmap == pPixmap) - pExaScr->deferred_mixed_pixmap = NULL; - - if (pExaPixmap->driverPriv) - pExaScr->info->DestroyPixmap(pScreen, pExaPixmap->driverPriv); - pExaPixmap->driverPriv = NULL; - - if (pExaPixmap->pDamage) { - if (pExaPixmap->sys_ptr) - free(pExaPixmap->sys_ptr); - pExaPixmap->sys_ptr = NULL; - pExaPixmap->pDamage = NULL; - } - } - - swap(pExaScr, pScreen, DestroyPixmap); - ret = pScreen->DestroyPixmap (pPixmap); - swap(pExaScr, pScreen, DestroyPixmap); - - return ret; -} - -Bool -exaPixmapHasGpuCopy_mixed(PixmapPtr pPixmap) -{ - ScreenPtr pScreen = pPixmap->drawable.pScreen; - ExaScreenPriv(pScreen); - ExaPixmapPriv(pPixmap); - pointer saved_ptr; - Bool ret; - - if (!pExaPixmap->driverPriv) - return FALSE; - - saved_ptr = pPixmap->devPrivate.ptr; - pPixmap->devPrivate.ptr = ExaGetPixmapAddress(pPixmap); - ret = pExaScr->info->PixmapIsOffscreen(pPixmap); - pPixmap->devPrivate.ptr = saved_ptr; - - return ret; -} +/* + * Copyright © 2009 Maarten Maathuis + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include + +#include "exa_priv.h" +#include "exa.h" + +/* This file holds the driver allocated pixmaps + better initial placement code. + */ + +static _X_INLINE void* +ExaGetPixmapAddress(PixmapPtr p) +{ + ExaPixmapPriv(p); + + return pExaPixmap->sys_ptr; +} + +/** + * exaCreatePixmap() creates a new pixmap. + */ +PixmapPtr +exaCreatePixmap_mixed(ScreenPtr pScreen, int w, int h, int depth, + unsigned usage_hint) +{ + PixmapPtr pPixmap; + ExaPixmapPrivPtr pExaPixmap; + int bpp; + size_t paddedWidth; + ExaScreenPriv(pScreen); + + if (w > 32767 || h > 32767) + return NullPixmap; + + swap(pExaScr, pScreen, CreatePixmap); + pPixmap = pScreen->CreatePixmap(pScreen, 0, 0, depth, usage_hint); + swap(pExaScr, pScreen, CreatePixmap); + + if (!pPixmap) + return NULL; + + pExaPixmap = ExaGetPixmapPriv(pPixmap); + pExaPixmap->driverPriv = NULL; + + bpp = pPixmap->drawable.bitsPerPixel; + + paddedWidth = ((w * bpp + FB_MASK) >> FB_SHIFT) * sizeof(FbBits); + if (paddedWidth / 4 > 32767 || h > 32767) + return NullPixmap; + + /* We will allocate the system pixmap later if needed. */ + pPixmap->devPrivate.ptr = NULL; + pExaPixmap->sys_ptr = NULL; + pExaPixmap->sys_pitch = paddedWidth; + + pExaPixmap->area = NULL; + pExaPixmap->fb_ptr = NULL; + pExaPixmap->pDamage = NULL; + + exaSetFbPitch(pExaScr, pExaPixmap, w, h, bpp); + exaSetAccelBlock(pExaScr, pExaPixmap, + w, h, bpp); + + (*pScreen->ModifyPixmapHeader)(pPixmap, w, h, 0, 0, + paddedWidth, NULL); + + /* A scratch pixmap will become a driver pixmap right away. */ + if (!w || !h) { + exaCreateDriverPixmap_mixed(pPixmap); + pExaPixmap->use_gpu_copy = exaPixmapHasGpuCopy(pPixmap); + } else { + pExaPixmap->use_gpu_copy = FALSE; + + if (w == 1 && h == 1) { + pExaPixmap->sys_ptr = malloc((pPixmap->drawable.bitsPerPixel + 7) / 8); + + /* Set up damage tracking */ + pExaPixmap->pDamage = DamageCreate(exaDamageReport_mixed, NULL, + DamageReportNonEmpty, TRUE, + pPixmap->drawable.pScreen, + pPixmap); + + DamageRegister(&pPixmap->drawable, pExaPixmap->pDamage); + /* This ensures that pending damage reflects the current operation. */ + /* This is used by exa to optimize migration. */ + DamageSetReportAfterOp(pExaPixmap->pDamage, TRUE); + } + } + + /* During a fallback we must prepare access. */ + if (pExaScr->fallback_counter) + exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_AUX_DEST); + + return pPixmap; +} + +Bool +exaModifyPixmapHeader_mixed(PixmapPtr pPixmap, int width, int height, int depth, + int bitsPerPixel, int devKind, pointer pPixData) +{ + ScreenPtr pScreen; + ExaScreenPrivPtr pExaScr; + ExaPixmapPrivPtr pExaPixmap; + Bool ret, has_gpu_copy; + + if (!pPixmap) + return FALSE; + + pScreen = pPixmap->drawable.pScreen; + pExaScr = ExaGetScreenPriv(pScreen); + pExaPixmap = ExaGetPixmapPriv(pPixmap); + + if (pPixData) { + if (pExaPixmap->driverPriv) { + if (pExaPixmap->pDamage) { + DamageUnregister(&pPixmap->drawable, pExaPixmap->pDamage); + DamageDestroy(pExaPixmap->pDamage); + pExaPixmap->pDamage = NULL; + } + + pExaScr->info->DestroyPixmap(pScreen, pExaPixmap->driverPriv); + pExaPixmap->driverPriv = NULL; + } + + pExaPixmap->use_gpu_copy = FALSE; + pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED; + } + + has_gpu_copy = exaPixmapHasGpuCopy(pPixmap); + + if (width <= 0) + width = pPixmap->drawable.width; + + if (height <= 0) + height = pPixmap->drawable.height; + + if (bitsPerPixel <= 0) { + if (depth <= 0) + bitsPerPixel = pPixmap->drawable.bitsPerPixel; + else + bitsPerPixel = BitsPerPixel(depth); + } + + if (depth <= 0) + depth = pPixmap->drawable.depth; + + if (width != pPixmap->drawable.width || + height != pPixmap->drawable.height || + depth != pPixmap->drawable.depth || + bitsPerPixel != pPixmap->drawable.bitsPerPixel) { + if (pExaPixmap->driverPriv) { + exaSetFbPitch(pExaScr, pExaPixmap, + width, height, bitsPerPixel); + + exaSetAccelBlock(pExaScr, pExaPixmap, + width, height, bitsPerPixel); + RegionEmpty(&pExaPixmap->validFB); + } + + /* Need to re-create system copy if there's also a GPU copy */ + if (has_gpu_copy && pExaPixmap->sys_ptr) { + free(pExaPixmap->sys_ptr); + pExaPixmap->sys_ptr = NULL; + pExaPixmap->sys_pitch = devKind > 0 ? devKind : + PixmapBytePad(width, depth); + DamageUnregister(&pPixmap->drawable, pExaPixmap->pDamage); + DamageDestroy(pExaPixmap->pDamage); + pExaPixmap->pDamage = NULL; + RegionEmpty(&pExaPixmap->validSys); + + if (pExaScr->deferred_mixed_pixmap == pPixmap) + pExaScr->deferred_mixed_pixmap = NULL; + } + } + + if (has_gpu_copy) { + pPixmap->devPrivate.ptr = pExaPixmap->fb_ptr; + pPixmap->devKind = pExaPixmap->fb_pitch; + } else { + pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr; + pPixmap->devKind = pExaPixmap->sys_pitch; + } + + /* Only pass driver pixmaps to the driver. */ + if (pExaScr->info->ModifyPixmapHeader && pExaPixmap->driverPriv) { + ret = pExaScr->info->ModifyPixmapHeader(pPixmap, width, height, depth, + bitsPerPixel, devKind, pPixData); + if (ret == TRUE) + goto out; + } + + swap(pExaScr, pScreen, ModifyPixmapHeader); + ret = pScreen->ModifyPixmapHeader(pPixmap, width, height, depth, + bitsPerPixel, devKind, pPixData); + swap(pExaScr, pScreen, ModifyPixmapHeader); + +out: + if (has_gpu_copy) { + pExaPixmap->fb_ptr = pPixmap->devPrivate.ptr; + pExaPixmap->fb_pitch = pPixmap->devKind; + } else { + pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr; + pExaPixmap->sys_pitch = pPixmap->devKind; + } + /* Always NULL this, we don't want lingering pointers. */ + pPixmap->devPrivate.ptr = NULL; + + return ret; +} + +Bool +exaDestroyPixmap_mixed(PixmapPtr pPixmap) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + ExaScreenPriv(pScreen); + Bool ret; + + if (pPixmap->refcnt == 1) + { + ExaPixmapPriv (pPixmap); + + /* During a fallback we must finish access, but we don't know the index. */ + if (pExaScr->fallback_counter) + exaFinishAccess(&pPixmap->drawable, -1); + + if (pExaScr->deferred_mixed_pixmap == pPixmap) + pExaScr->deferred_mixed_pixmap = NULL; + + if (pExaPixmap->driverPriv) + pExaScr->info->DestroyPixmap(pScreen, pExaPixmap->driverPriv); + pExaPixmap->driverPriv = NULL; + + if (pExaPixmap->pDamage) { + free(pExaPixmap->sys_ptr); + pExaPixmap->sys_ptr = NULL; + pExaPixmap->pDamage = NULL; + } + } + + swap(pExaScr, pScreen, DestroyPixmap); + ret = pScreen->DestroyPixmap (pPixmap); + swap(pExaScr, pScreen, DestroyPixmap); + + return ret; +} + +Bool +exaPixmapHasGpuCopy_mixed(PixmapPtr pPixmap) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + ExaScreenPriv(pScreen); + ExaPixmapPriv(pPixmap); + pointer saved_ptr; + Bool ret; + + if (!pExaPixmap->driverPriv) + return FALSE; + + saved_ptr = pPixmap->devPrivate.ptr; + pPixmap->devPrivate.ptr = ExaGetPixmapAddress(pPixmap); + ret = pExaScr->info->PixmapIsOffscreen(pPixmap); + pPixmap->devPrivate.ptr = saved_ptr; + + return ret; +} diff --git a/xorg-server/exa/exa_priv.h b/xorg-server/exa/exa_priv.h index 575d836b8..baf49590a 100644 --- a/xorg-server/exa/exa_priv.h +++ b/xorg-server/exa/exa_priv.h @@ -221,9 +221,13 @@ typedef struct { (PixmapWidthPaddingInfo[d].padRoundUp+1))) #endif -extern DevPrivateKey exaScreenPrivateKey; -extern DevPrivateKey exaPixmapPrivateKey; -extern DevPrivateKey exaGCPrivateKey; +extern DevPrivateKeyRec exaScreenPrivateKeyRec; +#define exaScreenPrivateKey (&exaScreenPrivateKeyRec) +extern DevPrivateKeyRec exaPixmapPrivateKeyRec; +#define exaPixmapPrivateKey (&exaPixmapPrivateKeyRec) +extern DevPrivateKeyRec exaGCPrivateKeyRec; +#define exaGCPrivateKey (&exaGCPrivateKeyRec) + #define ExaGetScreenPriv(s) ((ExaScreenPrivPtr)dixLookupPrivate(&(s)->devPrivates, exaScreenPrivateKey)) #define ExaScreenPriv(s) ExaScreenPrivPtr pExaScr = ExaGetScreenPriv(s) diff --git a/xorg-server/exa/exa_render.c b/xorg-server/exa/exa_render.c index b7f383f38..026f5d16d 100644 --- a/xorg-server/exa/exa_render.c +++ b/xorg-server/exa/exa_render.c @@ -1,1256 +1,1256 @@ -/* - * Copyright © 2001 Keith Packard - * - * Partly based on code that is Copyright © The XFree86 Project 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 Keith Packard not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. Keith Packard makes no - * representations about the suitability of this software for any purpose. It - * is provided "as is" without express or implied warranty. - * - * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL KEITH PACKARD 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. - */ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include - -#include "exa_priv.h" - -#include "mipict.h" - -#if DEBUG_TRACE_FALL -static void exaCompositeFallbackPictDesc(PicturePtr pict, char *string, int n) -{ - char format[20]; - char size[20]; - char loc; - int temp; - - if (!pict) { - snprintf(string, n, "None"); - return; - } - - switch (pict->format) - { - case PICT_a8r8g8b8: - snprintf(format, 20, "ARGB8888"); - break; - case PICT_x8r8g8b8: - snprintf(format, 20, "XRGB8888"); - break; - case PICT_b8g8r8a8: - snprintf(format, 20, "BGRA8888"); - break; - case PICT_b8g8r8x8: - snprintf(format, 20, "BGRX8888"); - break; - case PICT_r5g6b5: - snprintf(format, 20, "RGB565 "); - break; - case PICT_x1r5g5b5: - snprintf(format, 20, "RGB555 "); - break; - case PICT_a8: - snprintf(format, 20, "A8 "); - break; - case PICT_a1: - snprintf(format, 20, "A1 "); - break; - default: - snprintf(format, 20, "0x%x", (int)pict->format); - break; - } - - if (pict->pDrawable) { - loc = exaGetOffscreenPixmap(pict->pDrawable, &temp, &temp) ? 's' : 'm'; - - snprintf(size, 20, "%dx%d%s", pict->pDrawable->width, - pict->pDrawable->height, pict->repeat ? - " R" : ""); - } else { - loc = '-'; - - snprintf(size, 20, "%s", pict->repeat ? " R" : ""); - } - - snprintf(string, n, "%p:%c fmt %s (%s)", pict->pDrawable, loc, format, size); -} - -static void -exaPrintCompositeFallback(CARD8 op, - PicturePtr pSrc, - PicturePtr pMask, - PicturePtr pDst) -{ - char sop[20]; - char srcdesc[40], maskdesc[40], dstdesc[40]; - - switch(op) - { - case PictOpSrc: - sprintf(sop, "Src"); - break; - case PictOpOver: - sprintf(sop, "Over"); - break; - default: - sprintf(sop, "0x%x", (int)op); - break; - } - - exaCompositeFallbackPictDesc(pSrc, srcdesc, 40); - exaCompositeFallbackPictDesc(pMask, maskdesc, 40); - exaCompositeFallbackPictDesc(pDst, dstdesc, 40); - - ErrorF("Composite fallback: op %s, \n" - " src %s, \n" - " mask %s, \n" - " dst %s, \n", - sop, srcdesc, maskdesc, dstdesc); -} -#endif /* DEBUG_TRACE_FALL */ - -Bool -exaOpReadsDestination (CARD8 op) -{ - /* FALSE (does not read destination) is the list of ops in the protocol - * document with "0" in the "Fb" column and no "Ab" in the "Fa" column. - * That's just Clear and Src. ReduceCompositeOp() will already have - * converted con/disjoint clear/src to Clear or Src. - */ - switch (op) { - case PictOpClear: - case PictOpSrc: - return FALSE; - default: - return TRUE; - } -} - - -static Bool -exaGetPixelFromRGBA(CARD32 *pixel, - CARD16 red, - CARD16 green, - CARD16 blue, - CARD16 alpha, - PictFormatPtr pFormat) -{ - int rbits, bbits, gbits, abits; - int rshift, bshift, gshift, ashift; - - *pixel = 0; - - if (!PICT_FORMAT_COLOR(pFormat->format) && - PICT_FORMAT_TYPE(pFormat->format) != PICT_TYPE_A) - return FALSE; - - rbits = PICT_FORMAT_R(pFormat->format); - gbits = PICT_FORMAT_G(pFormat->format); - bbits = PICT_FORMAT_B(pFormat->format); - abits = PICT_FORMAT_A(pFormat->format); - - rshift = pFormat->direct.red; - gshift = pFormat->direct.green; - bshift = pFormat->direct.blue; - ashift = pFormat->direct.alpha; - - *pixel |= ( blue >> (16 - bbits)) << bshift; - *pixel |= ( red >> (16 - rbits)) << rshift; - *pixel |= (green >> (16 - gbits)) << gshift; - *pixel |= (alpha >> (16 - abits)) << ashift; - - return TRUE; -} - -static Bool -exaGetRGBAFromPixel(CARD32 pixel, - CARD16 *red, - CARD16 *green, - CARD16 *blue, - CARD16 *alpha, - PictFormatPtr pFormat, - PictFormatShort format) -{ - int rbits, bbits, gbits, abits; - int rshift, bshift, gshift, ashift; - - if (!PICT_FORMAT_COLOR(format) && PICT_FORMAT_TYPE(format) != PICT_TYPE_A) - return FALSE; - - rbits = PICT_FORMAT_R(format); - gbits = PICT_FORMAT_G(format); - bbits = PICT_FORMAT_B(format); - abits = PICT_FORMAT_A(format); - - if (pFormat) { - rshift = pFormat->direct.red; - gshift = pFormat->direct.green; - bshift = pFormat->direct.blue; - ashift = pFormat->direct.alpha; - } else if (format == PICT_a8r8g8b8) { - rshift = 16; - gshift = 8; - bshift = 0; - ashift = 24; - } else - FatalError("EXA bug: exaGetRGBAFromPixel() doesn't match " - "createSourcePicture()\n"); - - if (rbits) { - *red = ((pixel >> rshift ) & ((1 << rbits) - 1)) << (16 - rbits); - while (rbits < 16) { - *red |= *red >> rbits; - rbits <<= 1; - } - - *green = ((pixel >> gshift ) & ((1 << gbits) - 1)) << (16 - gbits); - while (gbits < 16) { - *green |= *green >> gbits; - gbits <<= 1; - } - - *blue = ((pixel >> bshift ) & ((1 << bbits) - 1)) << (16 - bbits); - while (bbits < 16) { - *blue |= *blue >> bbits; - bbits <<= 1; - } - } else { - *red = 0x0000; - *green = 0x0000; - *blue = 0x0000; - } - - if (abits) { - *alpha = ((pixel >> ashift ) & ((1 << abits) - 1)) << (16 - abits); - while (abits < 16) { - *alpha |= *alpha >> abits; - abits <<= 1; - } - } else - *alpha = 0xffff; - - return TRUE; -} - -static int -exaTryDriverSolidFill(PicturePtr pSrc, - PicturePtr pDst, - INT16 xSrc, - INT16 ySrc, - INT16 xDst, - INT16 yDst, - CARD16 width, - CARD16 height) -{ - ExaScreenPriv (pDst->pDrawable->pScreen); - RegionRec region; - BoxPtr pbox; - int nbox; - int dst_off_x, dst_off_y; - PixmapPtr pSrcPix, pDstPix; - ExaPixmapPrivPtr pDstExaPix; - CARD32 pixel; - CARD16 red, green, blue, alpha; - - pDstPix = exaGetDrawablePixmap (pDst->pDrawable); - pDstExaPix = ExaGetPixmapPriv(pDstPix); - - /* Check whether the accelerator can use the destination pixmap. - */ - if (pDstExaPix->accel_blocked) - { - return -1; - } - - xDst += pDst->pDrawable->x; - yDst += pDst->pDrawable->y; - if (pSrc->pDrawable) { - xSrc += pSrc->pDrawable->x; - ySrc += pSrc->pDrawable->y; - } - - if (!miComputeCompositeRegion (®ion, pSrc, NULL, pDst, - xSrc, ySrc, 0, 0, xDst, yDst, - width, height)) - return 1; - - exaGetDrawableDeltas (pDst->pDrawable, pDstPix, &dst_off_x, &dst_off_y); - - REGION_TRANSLATE(pScreen, ®ion, dst_off_x, dst_off_y); - - if (pSrc->pDrawable) { - pSrcPix = exaGetDrawablePixmap (pSrc->pDrawable); - pixel = exaGetPixmapFirstPixel (pSrcPix); - } else - pixel = pSrc->pSourcePict->solidFill.color; - - if (!exaGetRGBAFromPixel(pixel, &red, &green, &blue, &alpha, - pSrc->pFormat, pSrc->format) || - !exaGetPixelFromRGBA(&pixel, red, green, blue, alpha, - pDst->pFormat)) - { - REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); - return -1; - } - - if (pExaScr->do_migration) { - ExaMigrationRec pixmaps[1]; - - pixmaps[0].as_dst = TRUE; - pixmaps[0].as_src = FALSE; - pixmaps[0].pPix = pDstPix; - pixmaps[0].pReg = ®ion; - exaDoMigration(pixmaps, 1, TRUE); - } - - if (!exaPixmapHasGpuCopy(pDstPix)) { - REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); - return 0; - } - - if (!(*pExaScr->info->PrepareSolid) (pDstPix, GXcopy, 0xffffffff, pixel)) - { - REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); - return -1; - } - - nbox = REGION_NUM_RECTS(®ion); - pbox = REGION_RECTS(®ion); - - while (nbox--) - { - (*pExaScr->info->Solid) (pDstPix, pbox->x1, pbox->y1, pbox->x2, pbox->y2); - pbox++; - } - - (*pExaScr->info->DoneSolid) (pDstPix); - exaMarkSync(pDst->pDrawable->pScreen); - - REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); - return 1; -} - -static int -exaTryDriverCompositeRects(CARD8 op, - PicturePtr pSrc, - PicturePtr pMask, - PicturePtr pDst, - int nrect, - ExaCompositeRectPtr rects) -{ - ExaScreenPriv (pDst->pDrawable->pScreen); - int src_off_x = 0, src_off_y = 0, mask_off_x = 0, mask_off_y = 0; - int dst_off_x, dst_off_y; - PixmapPtr pSrcPix = NULL, pMaskPix = NULL, pDstPix; - ExaPixmapPrivPtr pSrcExaPix = NULL, pMaskExaPix = NULL, pDstExaPix; - - if (!pExaScr->info->PrepareComposite) - return -1; - - if (pSrc->pDrawable) { - pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable); - pSrcExaPix = ExaGetPixmapPriv(pSrcPix); - } - - if (pMask && pMask->pDrawable) { - pMaskPix = exaGetDrawablePixmap(pMask->pDrawable); - pMaskExaPix = ExaGetPixmapPriv(pMaskPix); - } - - pDstPix = exaGetDrawablePixmap(pDst->pDrawable); - pDstExaPix = ExaGetPixmapPriv(pDstPix); - - /* Check whether the accelerator can use these pixmaps. - * FIXME: If it cannot, use temporary pixmaps so that the drawing - * happens within limits. - */ - if (pDstExaPix->accel_blocked || - (pSrcExaPix && pSrcExaPix->accel_blocked) || - (pMaskExaPix && pMaskExaPix->accel_blocked)) - { - return -1; - } - - if (pExaScr->info->CheckComposite && - !(*pExaScr->info->CheckComposite) (op, pSrc, pMask, pDst)) - { - return -1; - } - - if (pExaScr->do_migration) { - ExaMigrationRec pixmaps[3]; - int i = 0; - - pixmaps[i].as_dst = TRUE; - pixmaps[i].as_src = exaOpReadsDestination(op); - pixmaps[i].pPix = pDstPix; - pixmaps[i].pReg = NULL; - i++; - - if (pSrcPix) { - pixmaps[i].as_dst = FALSE; - pixmaps[i].as_src = TRUE; - pixmaps[i].pPix = pSrcPix; - pixmaps[i].pReg = NULL; - i++; - } - - if (pMaskPix) { - pixmaps[i].as_dst = FALSE; - pixmaps[i].as_src = TRUE; - pixmaps[i].pPix = pMaskPix; - pixmaps[i].pReg = NULL; - i++; - } - - exaDoMigration(pixmaps, i, TRUE); - } - - pDstPix = exaGetOffscreenPixmap (pDst->pDrawable, &dst_off_x, &dst_off_y); - if (!pDstPix) - return 0; - - if (pSrcPix) { - pSrcPix = exaGetOffscreenPixmap (pSrc->pDrawable, &src_off_x, &src_off_y); - if (!pSrcPix) - return 0; - } - - if (pMaskPix) { - pMaskPix = exaGetOffscreenPixmap (pMask->pDrawable, &mask_off_x, &mask_off_y); - if (!pMaskPix) - return 0; - } - - if (!(*pExaScr->info->PrepareComposite) (op, pSrc, pMask, pDst, pSrcPix, - pMaskPix, pDstPix)) - return -1; - - while (nrect--) - { - INT16 xDst = rects->xDst + pDst->pDrawable->x; - INT16 yDst = rects->yDst + pDst->pDrawable->y; - INT16 xMask = rects->xMask; - INT16 yMask = rects->yMask; - INT16 xSrc = rects->xSrc; - INT16 ySrc = rects->ySrc; - RegionRec region; - BoxPtr pbox; - int nbox; - - if (pMaskPix) { - xMask += pMask->pDrawable->x; - yMask += pMask->pDrawable->y; - } - - if (pSrcPix) { - xSrc += pSrc->pDrawable->x; - ySrc += pSrc->pDrawable->y; - } - - if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst, - xSrc, ySrc, xMask, yMask, 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); - - xMask = xMask + mask_off_x - xDst - dst_off_x; - yMask = yMask + mask_off_y - yDst - dst_off_y; - xSrc = xSrc + src_off_x - xDst - dst_off_x; - ySrc = ySrc + src_off_y - yDst - dst_off_y; - - while (nbox--) - { - (*pExaScr->info->Composite) (pDstPix, - pbox->x1 + xSrc, - pbox->y1 + ySrc, - pbox->x1 + xMask, - pbox->y1 + yMask, - pbox->x1, - pbox->y1, - pbox->x2 - pbox->x1, - pbox->y2 - pbox->y1); - pbox++; - } - - next_rect: - REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); - - rects++; - } - - (*pExaScr->info->DoneComposite) (pDstPix); - exaMarkSync(pDst->pDrawable->pScreen); - - return 1; -} - -/** - * Copy a number of rectangles from source to destination in a single - * operation. This is specialized for glyph rendering: we don't have the - * special-case fallbacks found in exaComposite() - if the driver can support - * it, we use the driver functionality, otherwise we fall back straight to - * software. - */ -void -exaCompositeRects(CARD8 op, - PicturePtr pSrc, - PicturePtr pMask, - PicturePtr pDst, - int nrect, - ExaCompositeRectPtr rects) -{ - ExaScreenPriv (pDst->pDrawable->pScreen); - int n; - ExaCompositeRectPtr r; - int ret; - - /* If we get a mask, that means we're rendering to the exaGlyphs - * destination directly, so the damage layer takes care of this. - */ - if (!pMask) { - RegionRec region; - int x1 = MAXSHORT; - int y1 = MAXSHORT; - int x2 = MINSHORT; - int y2 = MINSHORT; - BoxRec box; - - /* We have to manage the damage ourselves, since CompositeRects isn't - * something in the screen that can be managed by the damage extension, - * and EXA depends on damage to track what needs to be migrated between - * the gpu and the cpu. - */ - - /* Compute the overall extents of the composited region - we're making - * the assumption here that we are compositing a bunch of glyphs that - * cluster closely together and damaging each glyph individually would - * be a loss compared to damaging the bounding box. - */ - n = nrect; - r = rects; - while (n--) { - int rect_x2 = r->xDst + r->width; - int rect_y2 = r->yDst + r->height; - - if (r->xDst < x1) x1 = r->xDst; - if (r->yDst < y1) y1 = r->yDst; - if (rect_x2 > x2) x2 = rect_x2; - if (rect_y2 > y2) y2 = rect_y2; - - r++; - } - - if (x2 <= x1 || y2 <= y1) - return; - - box.x1 = x1; - box.x2 = x2 < MAXSHORT ? x2 : MAXSHORT; - box.y1 = y1; - box.y2 = y2 < MAXSHORT ? y2 : MAXSHORT; - - /* The pixmap migration code relies on pendingDamage indicating - * the bounds of the current rendering, so we need to force - * the actual damage into that region before we do anything, and - * (see use of DamagePendingRegion in exaCopyDirty) - */ - - REGION_INIT(pScreen, ®ion, &box, 1); - - DamageRegionAppend(pDst->pDrawable, ®ion); - - REGION_UNINIT(pScreen, ®ion); - } - - /************************************************************/ - - ValidatePicture (pSrc); - if (pMask) - ValidatePicture (pMask); - ValidatePicture (pDst); - - ret = exaTryDriverCompositeRects(op, pSrc, pMask, pDst, nrect, rects); - - if (ret != 1) { - if (ret == -1 && op == PictOpOver && pMask && pMask->componentAlpha && - (!pExaScr->info->CheckComposite || - ((*pExaScr->info->CheckComposite)(PictOpOutReverse, pSrc, pMask, - pDst) && - (*pExaScr->info->CheckComposite)(PictOpAdd, pSrc, pMask, pDst)))) { - ret = exaTryDriverCompositeRects(PictOpOutReverse, pSrc, pMask, - pDst, nrect, rects); - if (ret == 1) { - op = PictOpAdd; - ret = exaTryDriverCompositeRects(op, pSrc, pMask, pDst, nrect, - rects); - } - } - - if (ret != 1) { - n = nrect; - r = rects; - while (n--) { - ExaCheckComposite (op, pSrc, pMask, pDst, - r->xSrc, r->ySrc, - r->xMask, r->yMask, - r->xDst, r->yDst, - r->width, r->height); - r++; - } - } - } - - /************************************************************/ - - if (!pMask) { - /* Now we have to flush the damage out from pendingDamage => damage - * Calling DamageRegionProcessPending has that effect. - */ - - DamageRegionProcessPending(pDst->pDrawable); - } -} - -static int -exaTryDriverComposite(CARD8 op, - PicturePtr pSrc, - PicturePtr pMask, - PicturePtr pDst, - INT16 xSrc, - INT16 ySrc, - INT16 xMask, - INT16 yMask, - INT16 xDst, - INT16 yDst, - CARD16 width, - CARD16 height) -{ - ExaScreenPriv (pDst->pDrawable->pScreen); - RegionRec region; - BoxPtr pbox; - int nbox; - int src_off_x, src_off_y, mask_off_x, mask_off_y, dst_off_x, dst_off_y; - PixmapPtr pSrcPix = NULL, pMaskPix = NULL, pDstPix; - ExaPixmapPrivPtr pSrcExaPix = NULL, pMaskExaPix = NULL, pDstExaPix; - - if (pSrc->pDrawable) { - pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable); - pSrcExaPix = ExaGetPixmapPriv(pSrcPix); - } - - pDstPix = exaGetDrawablePixmap(pDst->pDrawable); - pDstExaPix = ExaGetPixmapPriv(pDstPix); - - if (pMask && pMask->pDrawable) { - pMaskPix = exaGetDrawablePixmap(pMask->pDrawable); - pMaskExaPix = ExaGetPixmapPriv(pMaskPix); - } - - /* Check whether the accelerator can use these pixmaps. - * FIXME: If it cannot, use temporary pixmaps so that the drawing - * happens within limits. - */ - if (pDstExaPix->accel_blocked || - (pSrcExaPix && pSrcExaPix->accel_blocked) || - (pMaskExaPix && (pMaskExaPix->accel_blocked))) - { - return -1; - } - - xDst += pDst->pDrawable->x; - yDst += pDst->pDrawable->y; - - if (pMaskPix) { - xMask += pMask->pDrawable->x; - yMask += pMask->pDrawable->y; - } - - if (pSrcPix) { - xSrc += pSrc->pDrawable->x; - ySrc += pSrc->pDrawable->y; - } - - if (pExaScr->info->CheckComposite && - !(*pExaScr->info->CheckComposite) (op, pSrc, pMask, pDst)) - { - return -1; - } - - if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst, - xSrc, ySrc, xMask, yMask, xDst, yDst, - width, height)) - return 1; - - exaGetDrawableDeltas (pDst->pDrawable, pDstPix, &dst_off_x, &dst_off_y); - - REGION_TRANSLATE(pScreen, ®ion, dst_off_x, dst_off_y); - - if (pExaScr->do_migration) { - ExaMigrationRec pixmaps[3]; - int i = 0; - - pixmaps[i].as_dst = TRUE; - pixmaps[i].as_src = exaOpReadsDestination(op); - pixmaps[i].pPix = pDstPix; - pixmaps[i].pReg = pixmaps[0].as_src ? NULL : ®ion; - i++; - - if (pSrcPix) { - pixmaps[i].as_dst = FALSE; - pixmaps[i].as_src = TRUE; - pixmaps[i].pPix = pSrcPix; - pixmaps[i].pReg = NULL; - i++; - } - - if (pMaskPix) { - pixmaps[i].as_dst = FALSE; - pixmaps[i].as_src = TRUE; - pixmaps[i].pPix = pMaskPix; - pixmaps[i].pReg = NULL; - i++; - } - - exaDoMigration(pixmaps, i, TRUE); - } - - if (pSrcPix) { - pSrcPix = exaGetOffscreenPixmap (pSrc->pDrawable, &src_off_x, &src_off_y); - if (!pSrcPix) { - REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); - return 0; - } - } - - if (pMaskPix) { - pMaskPix = exaGetOffscreenPixmap (pMask->pDrawable, &mask_off_x, - &mask_off_y); - if (!pMaskPix) { - REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); - return 0; - } - } - - if (!exaPixmapHasGpuCopy(pDstPix)) { - REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); - return 0; - } - - if (!(*pExaScr->info->PrepareComposite) (op, pSrc, pMask, pDst, pSrcPix, - pMaskPix, pDstPix)) - { - REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); - return -1; - } - - nbox = REGION_NUM_RECTS(®ion); - pbox = REGION_RECTS(®ion); - - xMask = xMask + mask_off_x - xDst - dst_off_x; - yMask = yMask + mask_off_y - yDst - dst_off_y; - - xSrc = xSrc + src_off_x - xDst - dst_off_x; - ySrc = ySrc + src_off_y - yDst - dst_off_y; - - while (nbox--) - { - (*pExaScr->info->Composite) (pDstPix, - pbox->x1 + xSrc, - pbox->y1 + ySrc, - pbox->x1 + xMask, - pbox->y1 + yMask, - pbox->x1, - pbox->y1, - pbox->x2 - pbox->x1, - pbox->y2 - pbox->y1); - pbox++; - } - (*pExaScr->info->DoneComposite) (pDstPix); - exaMarkSync(pDst->pDrawable->pScreen); - - REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); - return 1; -} - -/** - * exaTryMagicTwoPassCompositeHelper implements PictOpOver using two passes of - * simpler operations PictOpOutReverse and PictOpAdd. Mainly used for component - * alpha and limited 1-tmu cards. - * - * From http://anholt.livejournal.com/32058.html: - * - * The trouble is that component-alpha rendering requires two different sources - * for blending: one for the source value to the blender, which is the - * per-channel multiplication of source and mask, and one for the source alpha - * for multiplying with the destination channels, which is the multiplication - * of the source channels by the mask alpha. So the equation for Over is: - * - * dst.A = src.A * mask.A + (1 - (src.A * mask.A)) * dst.A - * dst.R = src.R * mask.R + (1 - (src.A * mask.R)) * dst.R - * dst.G = src.G * mask.G + (1 - (src.A * mask.G)) * dst.G - * dst.B = src.B * mask.B + (1 - (src.A * mask.B)) * dst.B - * - * But we can do some simpler operations, right? How about PictOpOutReverse, - * which has a source factor of 0 and dest factor of (1 - source alpha). We - * can get the source alpha value (srca.X = src.A * mask.X) out of the texture - * blenders pretty easily. So we can do a component-alpha OutReverse, which - * gets us: - * - * dst.A = 0 + (1 - (src.A * mask.A)) * dst.A - * dst.R = 0 + (1 - (src.A * mask.R)) * dst.R - * dst.G = 0 + (1 - (src.A * mask.G)) * dst.G - * dst.B = 0 + (1 - (src.A * mask.B)) * dst.B - * - * OK. And if an op doesn't use the source alpha value for the destination - * factor, then we can do the channel multiplication in the texture blenders - * to get the source value, and ignore the source alpha that we wouldn't use. - * We've supported this in the Radeon driver for a long time. An example would - * be PictOpAdd, which does: - * - * dst.A = src.A * mask.A + dst.A - * dst.R = src.R * mask.R + dst.R - * dst.G = src.G * mask.G + dst.G - * dst.B = src.B * mask.B + dst.B - * - * Hey, this looks good! If we do a PictOpOutReverse and then a PictOpAdd right - * after it, we get: - * - * dst.A = src.A * mask.A + ((1 - (src.A * mask.A)) * dst.A) - * dst.R = src.R * mask.R + ((1 - (src.A * mask.R)) * dst.R) - * dst.G = src.G * mask.G + ((1 - (src.A * mask.G)) * dst.G) - * dst.B = src.B * mask.B + ((1 - (src.A * mask.B)) * dst.B) - */ - -static int -exaTryMagicTwoPassCompositeHelper(CARD8 op, - PicturePtr pSrc, - PicturePtr pMask, - PicturePtr pDst, - INT16 xSrc, - INT16 ySrc, - INT16 xMask, - INT16 yMask, - INT16 xDst, - INT16 yDst, - CARD16 width, - CARD16 height) -{ - ExaScreenPriv (pDst->pDrawable->pScreen); - - assert(op == PictOpOver); - - if (pExaScr->info->CheckComposite && - (!(*pExaScr->info->CheckComposite)(PictOpOutReverse, pSrc, pMask, - pDst) || - !(*pExaScr->info->CheckComposite)(PictOpAdd, pSrc, pMask, pDst))) - { - return -1; - } - - /* Now, we think we should be able to accelerate this operation. First, - * composite the destination to be the destination times the source alpha - * factors. - */ - exaComposite(PictOpOutReverse, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, - xDst, yDst, width, height); - - /* Then, add in the source value times the destination alpha factors (1.0). - */ - exaComposite(PictOpAdd, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, - xDst, yDst, width, height); - - return 1; -} - -void -exaComposite(CARD8 op, - PicturePtr pSrc, - PicturePtr pMask, - PicturePtr pDst, - INT16 xSrc, - INT16 ySrc, - INT16 xMask, - INT16 yMask, - INT16 xDst, - INT16 yDst, - CARD16 width, - CARD16 height) -{ - ExaScreenPriv (pDst->pDrawable->pScreen); - int ret = -1; - Bool saveSrcRepeat = pSrc->repeat; - Bool saveMaskRepeat = pMask ? pMask->repeat : 0; - RegionRec region; - - if (pExaScr->swappedOut) - goto fallback; - - /* Remove repeat in source if useless */ - if (pSrc->pDrawable && pSrc->repeat && !pSrc->transform && xSrc >= 0 && - (xSrc + width) <= pSrc->pDrawable->width && ySrc >= 0 && - (ySrc + height) <= pSrc->pDrawable->height) - pSrc->repeat = 0; - - if (!pMask && !pSrc->alphaMap && !pDst->alphaMap && - (op == PictOpSrc || (op == PictOpOver && !PICT_FORMAT_A(pSrc->format)))) - { - if (pSrc->pDrawable ? - (pSrc->pDrawable->width == 1 && pSrc->pDrawable->height == 1 && - pSrc->repeat) : - (pSrc->pSourcePict->type == SourcePictTypeSolidFill)) - { - ret = exaTryDriverSolidFill(pSrc, pDst, xSrc, ySrc, xDst, yDst, - width, height); - if (ret == 1) - goto done; - } else if (pSrc->pDrawable && !pSrc->transform && - ((op == PictOpSrc && - (pSrc->format == pDst->format || - (PICT_FORMAT_COLOR(pDst->format) && - PICT_FORMAT_COLOR(pSrc->format) && - pDst->format == PICT_FORMAT(PICT_FORMAT_BPP(pSrc->format), - PICT_FORMAT_TYPE(pSrc->format), - 0, - PICT_FORMAT_R(pSrc->format), - PICT_FORMAT_G(pSrc->format), - PICT_FORMAT_B(pSrc->format))))) || - (op == PictOpOver && pSrc->format == pDst->format && - !PICT_FORMAT_A(pSrc->format)))) - { - if (!pSrc->repeat && xSrc >= 0 && ySrc >= 0 && - (xSrc + width <= pSrc->pDrawable->width) && - (ySrc + height <= pSrc->pDrawable->height)) - { - Bool ret; - xDst += pDst->pDrawable->x; - yDst += pDst->pDrawable->y; - xSrc += pSrc->pDrawable->x; - ySrc += pSrc->pDrawable->y; - - if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst, - xSrc, ySrc, xMask, yMask, xDst, - yDst, width, height)) - goto done; - - ret = exaHWCopyNtoN(pSrc->pDrawable, pDst->pDrawable, NULL, - REGION_RECTS(®ion), REGION_NUM_RECTS(®ion), - xSrc - xDst, ySrc - yDst, FALSE, FALSE); - REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); - - /* Reset values to their original values. */ - xDst -= pDst->pDrawable->x; - yDst -= pDst->pDrawable->y; - xSrc -= pSrc->pDrawable->x; - ySrc -= pSrc->pDrawable->y; - - if (!ret) - goto fallback; - - goto done; - } - - 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 (pExaScr->info->PrepareComposite && !pSrc->alphaMap && - !pDst->alphaMap) - { - ret = exaTryDriverComposite(op, pSrc, pMask, pDst, xSrc, - ySrc, xMask, yMask, xDst, yDst, - width, height); - if (ret == 1) - goto done; - } - - /* Now see if we can use exaFillRegionTiled() */ - xDst += pDst->pDrawable->x; - yDst += pDst->pDrawable->y; - xSrc += pSrc->pDrawable->x; - ySrc += pSrc->pDrawable->y; - - if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst, xSrc, - ySrc, xMask, yMask, xDst, yDst, - width, height)) - goto done; - - /* pattern origin is the point in the destination drawable - * corresponding to (0,0) in the source */ - patOrg.x = xDst - xSrc; - patOrg.y = yDst - ySrc; - - ret = exaFillRegionTiled(pDst->pDrawable, ®ion, - (PixmapPtr)pSrc->pDrawable, - &patOrg, FB_ALLONES, GXcopy, CT_NONE); - - REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); - - if (ret) - goto done; - - /* Let's be correct and restore the variables to their original state. */ - xDst -= pDst->pDrawable->x; - yDst -= pDst->pDrawable->y; - xSrc -= pSrc->pDrawable->x; - ySrc -= pSrc->pDrawable->y; - } - } - } - - /* Remove repeat in mask if useless */ - if (pMask && pMask->pDrawable && pMask->repeat && !pMask->transform && - xMask >= 0 && (xMask + width) <= pMask->pDrawable->width && - yMask >= 0 && (yMask + height) <= pMask->pDrawable->height) - pMask->repeat = 0; - - if (pExaScr->info->PrepareComposite && - !pSrc->alphaMap && (!pMask || !pMask->alphaMap) && !pDst->alphaMap) - { - Bool isSrcSolid; - - ret = exaTryDriverComposite(op, pSrc, pMask, pDst, xSrc, ySrc, xMask, - yMask, xDst, yDst, width, height); - if (ret == 1) - goto done; - - /* 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) : - (pSrc->pSourcePict->type == SourcePictTypeSolidFill); - - /* 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 passes with - * an OutReverse and then an Add. - */ - if (ret == -1 && op == PictOpOver && pMask && - (pMask->componentAlpha || isSrcSolid)) { - ret = exaTryMagicTwoPassCompositeHelper(op, pSrc, pMask, pDst, - xSrc, ySrc, - xMask, yMask, xDst, yDst, - width, height); - if (ret == 1) - goto done; - } - } - -fallback: -#if DEBUG_TRACE_FALL - exaPrintCompositeFallback (op, pSrc, pMask, pDst); -#endif - - ExaCheckComposite (op, pSrc, pMask, pDst, xSrc, ySrc, - xMask, yMask, xDst, yDst, width, height); - -done: - pSrc->repeat = saveSrcRepeat; - if (pMask) - pMask->repeat = saveMaskRepeat; -} - -/** - * Same as miCreateAlphaPicture, except it uses ExaCheckPolyFillRect instead - * of PolyFillRect to initialize the pixmap after creating it, to prevent - * the pixmap from being migrated. - * - * See the comments about exaTrapezoids and exaTriangles. - */ -static PicturePtr -exaCreateAlphaPicture (ScreenPtr pScreen, - PicturePtr pDst, - PictFormatPtr pPictFormat, - CARD16 width, - CARD16 height) -{ - PixmapPtr pPixmap; - PicturePtr pPicture; - GCPtr pGC; - int error; - xRectangle rect; - - if (width > 32767 || height > 32767) - return 0; - - if (!pPictFormat) - { - if (pDst->polyEdge == PolyEdgeSharp) - pPictFormat = PictureMatchFormat (pScreen, 1, PICT_a1); - else - pPictFormat = PictureMatchFormat (pScreen, 8, PICT_a8); - if (!pPictFormat) - return 0; - } - - pPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, - pPictFormat->depth, 0); - if (!pPixmap) - return 0; - pGC = GetScratchGC (pPixmap->drawable.depth, pScreen); - if (!pGC) - { - (*pScreen->DestroyPixmap) (pPixmap); - return 0; - } - ValidateGC (&pPixmap->drawable, pGC); - rect.x = 0; - rect.y = 0; - rect.width = width; - rect.height = height; - ExaCheckPolyFillRect (&pPixmap->drawable, pGC, 1, &rect); - exaPixmapDirty (pPixmap, 0, 0, width, height); - FreeScratchGC (pGC); - pPicture = CreatePicture (0, &pPixmap->drawable, pPictFormat, - 0, 0, serverClient, &error); - (*pScreen->DestroyPixmap) (pPixmap); - return pPicture; -} - -/** - * exaTrapezoids is essentially a copy of miTrapezoids that uses - * exaCreateAlphaPicture instead of miCreateAlphaPicture. - * - * The problem with miCreateAlphaPicture is that it calls PolyFillRect - * to initialize the contents after creating the pixmap, which - * causes the pixmap to be moved in for acceleration. The subsequent - * call to RasterizeTrapezoid won't be accelerated however, which - * forces the pixmap to be moved out again. - * - * exaCreateAlphaPicture avoids this roundtrip by using ExaCheckPolyFillRect - * to initialize the contents. - */ -void -exaTrapezoids (CARD8 op, PicturePtr pSrc, PicturePtr pDst, - PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, - int ntrap, xTrapezoid *traps) -{ - ScreenPtr pScreen = pDst->pDrawable->pScreen; - PictureScreenPtr ps = GetPictureScreen(pScreen); - BoxRec bounds; - - if (maskFormat) { - PicturePtr pPicture; - INT16 xDst, yDst; - INT16 xRel, yRel; - - miTrapezoidBounds (ntrap, traps, &bounds); - - if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) - return; - - xDst = traps[0].left.p1.x >> 16; - yDst = traps[0].left.p1.y >> 16; - - pPicture = exaCreateAlphaPicture (pScreen, pDst, maskFormat, - bounds.x2 - bounds.x1, - bounds.y2 - bounds.y1); - if (!pPicture) - return; - - exaPrepareAccess(pPicture->pDrawable, EXA_PREPARE_DEST); - for (; ntrap; ntrap--, traps++) - (*ps->RasterizeTrapezoid) (pPicture, traps, - -bounds.x1, -bounds.y1); - exaFinishAccess(pPicture->pDrawable, EXA_PREPARE_DEST); - - xRel = bounds.x1 + xSrc - xDst; - yRel = bounds.y1 + ySrc - yDst; - CompositePicture (op, pSrc, pPicture, pDst, - xRel, yRel, 0, 0, bounds.x1, bounds.y1, - bounds.x2 - bounds.x1, - bounds.y2 - bounds.y1); - FreePicture (pPicture, 0); - } else { - if (pDst->polyEdge == PolyEdgeSharp) - maskFormat = PictureMatchFormat (pScreen, 1, PICT_a1); - else - maskFormat = PictureMatchFormat (pScreen, 8, PICT_a8); - for (; ntrap; ntrap--, traps++) - exaTrapezoids (op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, traps); - } -} - -/** - * exaTriangles is essentially a copy of miTriangles that uses - * exaCreateAlphaPicture instead of miCreateAlphaPicture. - * - * The problem with miCreateAlphaPicture is that it calls PolyFillRect - * to initialize the contents after creating the pixmap, which - * causes the pixmap to be moved in for acceleration. The subsequent - * call to AddTriangles won't be accelerated however, which forces the pixmap - * to be moved out again. - * - * exaCreateAlphaPicture avoids this roundtrip by using ExaCheckPolyFillRect - * to initialize the contents. - */ -void -exaTriangles (CARD8 op, PicturePtr pSrc, PicturePtr pDst, - PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, - int ntri, xTriangle *tris) -{ - ScreenPtr pScreen = pDst->pDrawable->pScreen; - PictureScreenPtr ps = GetPictureScreen(pScreen); - BoxRec bounds; - - if (maskFormat) { - PicturePtr pPicture; - INT16 xDst, yDst; - INT16 xRel, yRel; - - miTriangleBounds (ntri, tris, &bounds); - - if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) - return; - - xDst = tris[0].p1.x >> 16; - yDst = tris[0].p1.y >> 16; - - pPicture = exaCreateAlphaPicture (pScreen, pDst, maskFormat, - bounds.x2 - bounds.x1, - bounds.y2 - bounds.y1); - if (!pPicture) - return; - - exaPrepareAccess(pPicture->pDrawable, EXA_PREPARE_DEST); - (*ps->AddTriangles) (pPicture, -bounds.x1, -bounds.y1, ntri, tris); - exaFinishAccess(pPicture->pDrawable, EXA_PREPARE_DEST); - - xRel = bounds.x1 + xSrc - xDst; - yRel = bounds.y1 + ySrc - yDst; - CompositePicture (op, pSrc, pPicture, pDst, - xRel, yRel, 0, 0, bounds.x1, bounds.y1, - bounds.x2 - bounds.x1, bounds.y2 - bounds.y1); - FreePicture (pPicture, 0); - } else { - if (pDst->polyEdge == PolyEdgeSharp) - maskFormat = PictureMatchFormat (pScreen, 1, PICT_a1); - else - maskFormat = PictureMatchFormat (pScreen, 8, PICT_a8); - - for (; ntri; ntri--, tris++) - exaTriangles (op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, tris); - } -} +/* + * Copyright © 2001 Keith Packard + * + * Partly based on code that is Copyright © The XFree86 Project 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 Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD 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. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include + +#include "exa_priv.h" + +#include "mipict.h" + +#if DEBUG_TRACE_FALL +static void exaCompositeFallbackPictDesc(PicturePtr pict, char *string, int n) +{ + char format[20]; + char size[20]; + char loc; + int temp; + + if (!pict) { + snprintf(string, n, "None"); + return; + } + + switch (pict->format) + { + case PICT_a8r8g8b8: + snprintf(format, 20, "ARGB8888"); + break; + case PICT_x8r8g8b8: + snprintf(format, 20, "XRGB8888"); + break; + case PICT_b8g8r8a8: + snprintf(format, 20, "BGRA8888"); + break; + case PICT_b8g8r8x8: + snprintf(format, 20, "BGRX8888"); + break; + case PICT_r5g6b5: + snprintf(format, 20, "RGB565 "); + break; + case PICT_x1r5g5b5: + snprintf(format, 20, "RGB555 "); + break; + case PICT_a8: + snprintf(format, 20, "A8 "); + break; + case PICT_a1: + snprintf(format, 20, "A1 "); + break; + default: + snprintf(format, 20, "0x%x", (int)pict->format); + break; + } + + if (pict->pDrawable) { + loc = exaGetOffscreenPixmap(pict->pDrawable, &temp, &temp) ? 's' : 'm'; + + snprintf(size, 20, "%dx%d%s", pict->pDrawable->width, + pict->pDrawable->height, pict->repeat ? + " R" : ""); + } else { + loc = '-'; + + snprintf(size, 20, "%s", pict->repeat ? " R" : ""); + } + + snprintf(string, n, "%p:%c fmt %s (%s)", pict->pDrawable, loc, format, size); +} + +static void +exaPrintCompositeFallback(CARD8 op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst) +{ + char sop[20]; + char srcdesc[40], maskdesc[40], dstdesc[40]; + + switch(op) + { + case PictOpSrc: + sprintf(sop, "Src"); + break; + case PictOpOver: + sprintf(sop, "Over"); + break; + default: + sprintf(sop, "0x%x", (int)op); + break; + } + + exaCompositeFallbackPictDesc(pSrc, srcdesc, 40); + exaCompositeFallbackPictDesc(pMask, maskdesc, 40); + exaCompositeFallbackPictDesc(pDst, dstdesc, 40); + + ErrorF("Composite fallback: op %s, \n" + " src %s, \n" + " mask %s, \n" + " dst %s, \n", + sop, srcdesc, maskdesc, dstdesc); +} +#endif /* DEBUG_TRACE_FALL */ + +Bool +exaOpReadsDestination (CARD8 op) +{ + /* FALSE (does not read destination) is the list of ops in the protocol + * document with "0" in the "Fb" column and no "Ab" in the "Fa" column. + * That's just Clear and Src. ReduceCompositeOp() will already have + * converted con/disjoint clear/src to Clear or Src. + */ + switch (op) { + case PictOpClear: + case PictOpSrc: + return FALSE; + default: + return TRUE; + } +} + + +static Bool +exaGetPixelFromRGBA(CARD32 *pixel, + CARD16 red, + CARD16 green, + CARD16 blue, + CARD16 alpha, + PictFormatPtr pFormat) +{ + int rbits, bbits, gbits, abits; + int rshift, bshift, gshift, ashift; + + *pixel = 0; + + if (!PICT_FORMAT_COLOR(pFormat->format) && + PICT_FORMAT_TYPE(pFormat->format) != PICT_TYPE_A) + return FALSE; + + rbits = PICT_FORMAT_R(pFormat->format); + gbits = PICT_FORMAT_G(pFormat->format); + bbits = PICT_FORMAT_B(pFormat->format); + abits = PICT_FORMAT_A(pFormat->format); + + rshift = pFormat->direct.red; + gshift = pFormat->direct.green; + bshift = pFormat->direct.blue; + ashift = pFormat->direct.alpha; + + *pixel |= ( blue >> (16 - bbits)) << bshift; + *pixel |= ( red >> (16 - rbits)) << rshift; + *pixel |= (green >> (16 - gbits)) << gshift; + *pixel |= (alpha >> (16 - abits)) << ashift; + + return TRUE; +} + +static Bool +exaGetRGBAFromPixel(CARD32 pixel, + CARD16 *red, + CARD16 *green, + CARD16 *blue, + CARD16 *alpha, + PictFormatPtr pFormat, + PictFormatShort format) +{ + int rbits, bbits, gbits, abits; + int rshift, bshift, gshift, ashift; + + if (!PICT_FORMAT_COLOR(format) && PICT_FORMAT_TYPE(format) != PICT_TYPE_A) + return FALSE; + + rbits = PICT_FORMAT_R(format); + gbits = PICT_FORMAT_G(format); + bbits = PICT_FORMAT_B(format); + abits = PICT_FORMAT_A(format); + + if (pFormat) { + rshift = pFormat->direct.red; + gshift = pFormat->direct.green; + bshift = pFormat->direct.blue; + ashift = pFormat->direct.alpha; + } else if (format == PICT_a8r8g8b8) { + rshift = 16; + gshift = 8; + bshift = 0; + ashift = 24; + } else + FatalError("EXA bug: exaGetRGBAFromPixel() doesn't match " + "createSourcePicture()\n"); + + if (rbits) { + *red = ((pixel >> rshift ) & ((1 << rbits) - 1)) << (16 - rbits); + while (rbits < 16) { + *red |= *red >> rbits; + rbits <<= 1; + } + + *green = ((pixel >> gshift ) & ((1 << gbits) - 1)) << (16 - gbits); + while (gbits < 16) { + *green |= *green >> gbits; + gbits <<= 1; + } + + *blue = ((pixel >> bshift ) & ((1 << bbits) - 1)) << (16 - bbits); + while (bbits < 16) { + *blue |= *blue >> bbits; + bbits <<= 1; + } + } else { + *red = 0x0000; + *green = 0x0000; + *blue = 0x0000; + } + + if (abits) { + *alpha = ((pixel >> ashift ) & ((1 << abits) - 1)) << (16 - abits); + while (abits < 16) { + *alpha |= *alpha >> abits; + abits <<= 1; + } + } else + *alpha = 0xffff; + + return TRUE; +} + +static int +exaTryDriverSolidFill(PicturePtr pSrc, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + ExaScreenPriv (pDst->pDrawable->pScreen); + RegionRec region; + BoxPtr pbox; + int nbox; + int dst_off_x, dst_off_y; + PixmapPtr pSrcPix, pDstPix; + ExaPixmapPrivPtr pDstExaPix; + CARD32 pixel; + CARD16 red, green, blue, alpha; + + pDstPix = exaGetDrawablePixmap (pDst->pDrawable); + pDstExaPix = ExaGetPixmapPriv(pDstPix); + + /* Check whether the accelerator can use the destination pixmap. + */ + if (pDstExaPix->accel_blocked) + { + return -1; + } + + xDst += pDst->pDrawable->x; + yDst += pDst->pDrawable->y; + if (pSrc->pDrawable) { + xSrc += pSrc->pDrawable->x; + ySrc += pSrc->pDrawable->y; + } + + if (!miComputeCompositeRegion (®ion, pSrc, NULL, pDst, + xSrc, ySrc, 0, 0, xDst, yDst, + width, height)) + return 1; + + exaGetDrawableDeltas (pDst->pDrawable, pDstPix, &dst_off_x, &dst_off_y); + + RegionTranslate(®ion, dst_off_x, dst_off_y); + + if (pSrc->pDrawable) { + pSrcPix = exaGetDrawablePixmap (pSrc->pDrawable); + pixel = exaGetPixmapFirstPixel (pSrcPix); + } else + pixel = pSrc->pSourcePict->solidFill.color; + + if (!exaGetRGBAFromPixel(pixel, &red, &green, &blue, &alpha, + pSrc->pFormat, pSrc->format) || + !exaGetPixelFromRGBA(&pixel, red, green, blue, alpha, + pDst->pFormat)) + { + RegionUninit(®ion); + return -1; + } + + if (pExaScr->do_migration) { + ExaMigrationRec pixmaps[1]; + + pixmaps[0].as_dst = TRUE; + pixmaps[0].as_src = FALSE; + pixmaps[0].pPix = pDstPix; + pixmaps[0].pReg = ®ion; + exaDoMigration(pixmaps, 1, TRUE); + } + + if (!exaPixmapHasGpuCopy(pDstPix)) { + RegionUninit(®ion); + return 0; + } + + if (!(*pExaScr->info->PrepareSolid) (pDstPix, GXcopy, 0xffffffff, pixel)) + { + RegionUninit(®ion); + return -1; + } + + nbox = RegionNumRects(®ion); + pbox = RegionRects(®ion); + + while (nbox--) + { + (*pExaScr->info->Solid) (pDstPix, pbox->x1, pbox->y1, pbox->x2, pbox->y2); + pbox++; + } + + (*pExaScr->info->DoneSolid) (pDstPix); + exaMarkSync(pDst->pDrawable->pScreen); + + RegionUninit(®ion); + return 1; +} + +static int +exaTryDriverCompositeRects(CARD8 op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + int nrect, + ExaCompositeRectPtr rects) +{ + ExaScreenPriv (pDst->pDrawable->pScreen); + int src_off_x = 0, src_off_y = 0, mask_off_x = 0, mask_off_y = 0; + int dst_off_x, dst_off_y; + PixmapPtr pSrcPix = NULL, pMaskPix = NULL, pDstPix; + ExaPixmapPrivPtr pSrcExaPix = NULL, pMaskExaPix = NULL, pDstExaPix; + + if (!pExaScr->info->PrepareComposite) + return -1; + + if (pSrc->pDrawable) { + pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable); + pSrcExaPix = ExaGetPixmapPriv(pSrcPix); + } + + if (pMask && pMask->pDrawable) { + pMaskPix = exaGetDrawablePixmap(pMask->pDrawable); + pMaskExaPix = ExaGetPixmapPriv(pMaskPix); + } + + pDstPix = exaGetDrawablePixmap(pDst->pDrawable); + pDstExaPix = ExaGetPixmapPriv(pDstPix); + + /* Check whether the accelerator can use these pixmaps. + * FIXME: If it cannot, use temporary pixmaps so that the drawing + * happens within limits. + */ + if (pDstExaPix->accel_blocked || + (pSrcExaPix && pSrcExaPix->accel_blocked) || + (pMaskExaPix && pMaskExaPix->accel_blocked)) + { + return -1; + } + + if (pExaScr->info->CheckComposite && + !(*pExaScr->info->CheckComposite) (op, pSrc, pMask, pDst)) + { + return -1; + } + + if (pExaScr->do_migration) { + ExaMigrationRec pixmaps[3]; + int i = 0; + + pixmaps[i].as_dst = TRUE; + pixmaps[i].as_src = exaOpReadsDestination(op); + pixmaps[i].pPix = pDstPix; + pixmaps[i].pReg = NULL; + i++; + + if (pSrcPix) { + pixmaps[i].as_dst = FALSE; + pixmaps[i].as_src = TRUE; + pixmaps[i].pPix = pSrcPix; + pixmaps[i].pReg = NULL; + i++; + } + + if (pMaskPix) { + pixmaps[i].as_dst = FALSE; + pixmaps[i].as_src = TRUE; + pixmaps[i].pPix = pMaskPix; + pixmaps[i].pReg = NULL; + i++; + } + + exaDoMigration(pixmaps, i, TRUE); + } + + pDstPix = exaGetOffscreenPixmap (pDst->pDrawable, &dst_off_x, &dst_off_y); + if (!pDstPix) + return 0; + + if (pSrcPix) { + pSrcPix = exaGetOffscreenPixmap (pSrc->pDrawable, &src_off_x, &src_off_y); + if (!pSrcPix) + return 0; + } + + if (pMaskPix) { + pMaskPix = exaGetOffscreenPixmap (pMask->pDrawable, &mask_off_x, &mask_off_y); + if (!pMaskPix) + return 0; + } + + if (!(*pExaScr->info->PrepareComposite) (op, pSrc, pMask, pDst, pSrcPix, + pMaskPix, pDstPix)) + return -1; + + while (nrect--) + { + INT16 xDst = rects->xDst + pDst->pDrawable->x; + INT16 yDst = rects->yDst + pDst->pDrawable->y; + INT16 xMask = rects->xMask; + INT16 yMask = rects->yMask; + INT16 xSrc = rects->xSrc; + INT16 ySrc = rects->ySrc; + RegionRec region; + BoxPtr pbox; + int nbox; + + if (pMaskPix) { + xMask += pMask->pDrawable->x; + yMask += pMask->pDrawable->y; + } + + if (pSrcPix) { + xSrc += pSrc->pDrawable->x; + ySrc += pSrc->pDrawable->y; + } + + if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst, + xSrc, ySrc, xMask, yMask, xDst, yDst, + rects->width, rects->height)) + goto next_rect; + + RegionTranslate(®ion, dst_off_x, dst_off_y); + + nbox = RegionNumRects(®ion); + pbox = RegionRects(®ion); + + xMask = xMask + mask_off_x - xDst - dst_off_x; + yMask = yMask + mask_off_y - yDst - dst_off_y; + xSrc = xSrc + src_off_x - xDst - dst_off_x; + ySrc = ySrc + src_off_y - yDst - dst_off_y; + + while (nbox--) + { + (*pExaScr->info->Composite) (pDstPix, + pbox->x1 + xSrc, + pbox->y1 + ySrc, + pbox->x1 + xMask, + pbox->y1 + yMask, + pbox->x1, + pbox->y1, + pbox->x2 - pbox->x1, + pbox->y2 - pbox->y1); + pbox++; + } + + next_rect: + RegionUninit(®ion); + + rects++; + } + + (*pExaScr->info->DoneComposite) (pDstPix); + exaMarkSync(pDst->pDrawable->pScreen); + + return 1; +} + +/** + * Copy a number of rectangles from source to destination in a single + * operation. This is specialized for glyph rendering: we don't have the + * special-case fallbacks found in exaComposite() - if the driver can support + * it, we use the driver functionality, otherwise we fall back straight to + * software. + */ +void +exaCompositeRects(CARD8 op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + int nrect, + ExaCompositeRectPtr rects) +{ + ExaScreenPriv (pDst->pDrawable->pScreen); + int n; + ExaCompositeRectPtr r; + int ret; + + /* If we get a mask, that means we're rendering to the exaGlyphs + * destination directly, so the damage layer takes care of this. + */ + if (!pMask) { + RegionRec region; + int x1 = MAXSHORT; + int y1 = MAXSHORT; + int x2 = MINSHORT; + int y2 = MINSHORT; + BoxRec box; + + /* We have to manage the damage ourselves, since CompositeRects isn't + * something in the screen that can be managed by the damage extension, + * and EXA depends on damage to track what needs to be migrated between + * the gpu and the cpu. + */ + + /* Compute the overall extents of the composited region - we're making + * the assumption here that we are compositing a bunch of glyphs that + * cluster closely together and damaging each glyph individually would + * be a loss compared to damaging the bounding box. + */ + n = nrect; + r = rects; + while (n--) { + int rect_x2 = r->xDst + r->width; + int rect_y2 = r->yDst + r->height; + + if (r->xDst < x1) x1 = r->xDst; + if (r->yDst < y1) y1 = r->yDst; + if (rect_x2 > x2) x2 = rect_x2; + if (rect_y2 > y2) y2 = rect_y2; + + r++; + } + + if (x2 <= x1 || y2 <= y1) + return; + + box.x1 = x1; + box.x2 = x2 < MAXSHORT ? x2 : MAXSHORT; + box.y1 = y1; + box.y2 = y2 < MAXSHORT ? y2 : MAXSHORT; + + /* The pixmap migration code relies on pendingDamage indicating + * the bounds of the current rendering, so we need to force + * the actual damage into that region before we do anything, and + * (see use of DamagePendingRegion in exaCopyDirty) + */ + + RegionInit(®ion, &box, 1); + + DamageRegionAppend(pDst->pDrawable, ®ion); + + RegionUninit(®ion); + } + + /************************************************************/ + + ValidatePicture (pSrc); + if (pMask) + ValidatePicture (pMask); + ValidatePicture (pDst); + + ret = exaTryDriverCompositeRects(op, pSrc, pMask, pDst, nrect, rects); + + if (ret != 1) { + if (ret == -1 && op == PictOpOver && pMask && pMask->componentAlpha && + (!pExaScr->info->CheckComposite || + ((*pExaScr->info->CheckComposite)(PictOpOutReverse, pSrc, pMask, + pDst) && + (*pExaScr->info->CheckComposite)(PictOpAdd, pSrc, pMask, pDst)))) { + ret = exaTryDriverCompositeRects(PictOpOutReverse, pSrc, pMask, + pDst, nrect, rects); + if (ret == 1) { + op = PictOpAdd; + ret = exaTryDriverCompositeRects(op, pSrc, pMask, pDst, nrect, + rects); + } + } + + if (ret != 1) { + n = nrect; + r = rects; + while (n--) { + ExaCheckComposite (op, pSrc, pMask, pDst, + r->xSrc, r->ySrc, + r->xMask, r->yMask, + r->xDst, r->yDst, + r->width, r->height); + r++; + } + } + } + + /************************************************************/ + + if (!pMask) { + /* Now we have to flush the damage out from pendingDamage => damage + * Calling DamageRegionProcessPending has that effect. + */ + + DamageRegionProcessPending(pDst->pDrawable); + } +} + +static int +exaTryDriverComposite(CARD8 op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + ExaScreenPriv (pDst->pDrawable->pScreen); + RegionRec region; + BoxPtr pbox; + int nbox; + int src_off_x, src_off_y, mask_off_x, mask_off_y, dst_off_x, dst_off_y; + PixmapPtr pSrcPix = NULL, pMaskPix = NULL, pDstPix; + ExaPixmapPrivPtr pSrcExaPix = NULL, pMaskExaPix = NULL, pDstExaPix; + + if (pSrc->pDrawable) { + pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable); + pSrcExaPix = ExaGetPixmapPriv(pSrcPix); + } + + pDstPix = exaGetDrawablePixmap(pDst->pDrawable); + pDstExaPix = ExaGetPixmapPriv(pDstPix); + + if (pMask && pMask->pDrawable) { + pMaskPix = exaGetDrawablePixmap(pMask->pDrawable); + pMaskExaPix = ExaGetPixmapPriv(pMaskPix); + } + + /* Check whether the accelerator can use these pixmaps. + * FIXME: If it cannot, use temporary pixmaps so that the drawing + * happens within limits. + */ + if (pDstExaPix->accel_blocked || + (pSrcExaPix && pSrcExaPix->accel_blocked) || + (pMaskExaPix && (pMaskExaPix->accel_blocked))) + { + return -1; + } + + xDst += pDst->pDrawable->x; + yDst += pDst->pDrawable->y; + + if (pMaskPix) { + xMask += pMask->pDrawable->x; + yMask += pMask->pDrawable->y; + } + + if (pSrcPix) { + xSrc += pSrc->pDrawable->x; + ySrc += pSrc->pDrawable->y; + } + + if (pExaScr->info->CheckComposite && + !(*pExaScr->info->CheckComposite) (op, pSrc, pMask, pDst)) + { + return -1; + } + + if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst, + xSrc, ySrc, xMask, yMask, xDst, yDst, + width, height)) + return 1; + + exaGetDrawableDeltas (pDst->pDrawable, pDstPix, &dst_off_x, &dst_off_y); + + RegionTranslate(®ion, dst_off_x, dst_off_y); + + if (pExaScr->do_migration) { + ExaMigrationRec pixmaps[3]; + int i = 0; + + pixmaps[i].as_dst = TRUE; + pixmaps[i].as_src = exaOpReadsDestination(op); + pixmaps[i].pPix = pDstPix; + pixmaps[i].pReg = pixmaps[0].as_src ? NULL : ®ion; + i++; + + if (pSrcPix) { + pixmaps[i].as_dst = FALSE; + pixmaps[i].as_src = TRUE; + pixmaps[i].pPix = pSrcPix; + pixmaps[i].pReg = NULL; + i++; + } + + if (pMaskPix) { + pixmaps[i].as_dst = FALSE; + pixmaps[i].as_src = TRUE; + pixmaps[i].pPix = pMaskPix; + pixmaps[i].pReg = NULL; + i++; + } + + exaDoMigration(pixmaps, i, TRUE); + } + + if (pSrcPix) { + pSrcPix = exaGetOffscreenPixmap (pSrc->pDrawable, &src_off_x, &src_off_y); + if (!pSrcPix) { + RegionUninit(®ion); + return 0; + } + } + + if (pMaskPix) { + pMaskPix = exaGetOffscreenPixmap (pMask->pDrawable, &mask_off_x, + &mask_off_y); + if (!pMaskPix) { + RegionUninit(®ion); + return 0; + } + } + + if (!exaPixmapHasGpuCopy(pDstPix)) { + RegionUninit(®ion); + return 0; + } + + if (!(*pExaScr->info->PrepareComposite) (op, pSrc, pMask, pDst, pSrcPix, + pMaskPix, pDstPix)) + { + RegionUninit(®ion); + return -1; + } + + nbox = RegionNumRects(®ion); + pbox = RegionRects(®ion); + + xMask = xMask + mask_off_x - xDst - dst_off_x; + yMask = yMask + mask_off_y - yDst - dst_off_y; + + xSrc = xSrc + src_off_x - xDst - dst_off_x; + ySrc = ySrc + src_off_y - yDst - dst_off_y; + + while (nbox--) + { + (*pExaScr->info->Composite) (pDstPix, + pbox->x1 + xSrc, + pbox->y1 + ySrc, + pbox->x1 + xMask, + pbox->y1 + yMask, + pbox->x1, + pbox->y1, + pbox->x2 - pbox->x1, + pbox->y2 - pbox->y1); + pbox++; + } + (*pExaScr->info->DoneComposite) (pDstPix); + exaMarkSync(pDst->pDrawable->pScreen); + + RegionUninit(®ion); + return 1; +} + +/** + * exaTryMagicTwoPassCompositeHelper implements PictOpOver using two passes of + * simpler operations PictOpOutReverse and PictOpAdd. Mainly used for component + * alpha and limited 1-tmu cards. + * + * From http://anholt.livejournal.com/32058.html: + * + * The trouble is that component-alpha rendering requires two different sources + * for blending: one for the source value to the blender, which is the + * per-channel multiplication of source and mask, and one for the source alpha + * for multiplying with the destination channels, which is the multiplication + * of the source channels by the mask alpha. So the equation for Over is: + * + * dst.A = src.A * mask.A + (1 - (src.A * mask.A)) * dst.A + * dst.R = src.R * mask.R + (1 - (src.A * mask.R)) * dst.R + * dst.G = src.G * mask.G + (1 - (src.A * mask.G)) * dst.G + * dst.B = src.B * mask.B + (1 - (src.A * mask.B)) * dst.B + * + * But we can do some simpler operations, right? How about PictOpOutReverse, + * which has a source factor of 0 and dest factor of (1 - source alpha). We + * can get the source alpha value (srca.X = src.A * mask.X) out of the texture + * blenders pretty easily. So we can do a component-alpha OutReverse, which + * gets us: + * + * dst.A = 0 + (1 - (src.A * mask.A)) * dst.A + * dst.R = 0 + (1 - (src.A * mask.R)) * dst.R + * dst.G = 0 + (1 - (src.A * mask.G)) * dst.G + * dst.B = 0 + (1 - (src.A * mask.B)) * dst.B + * + * OK. And if an op doesn't use the source alpha value for the destination + * factor, then we can do the channel multiplication in the texture blenders + * to get the source value, and ignore the source alpha that we wouldn't use. + * We've supported this in the Radeon driver for a long time. An example would + * be PictOpAdd, which does: + * + * dst.A = src.A * mask.A + dst.A + * dst.R = src.R * mask.R + dst.R + * dst.G = src.G * mask.G + dst.G + * dst.B = src.B * mask.B + dst.B + * + * Hey, this looks good! If we do a PictOpOutReverse and then a PictOpAdd right + * after it, we get: + * + * dst.A = src.A * mask.A + ((1 - (src.A * mask.A)) * dst.A) + * dst.R = src.R * mask.R + ((1 - (src.A * mask.R)) * dst.R) + * dst.G = src.G * mask.G + ((1 - (src.A * mask.G)) * dst.G) + * dst.B = src.B * mask.B + ((1 - (src.A * mask.B)) * dst.B) + */ + +static int +exaTryMagicTwoPassCompositeHelper(CARD8 op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + ExaScreenPriv (pDst->pDrawable->pScreen); + + assert(op == PictOpOver); + + if (pExaScr->info->CheckComposite && + (!(*pExaScr->info->CheckComposite)(PictOpOutReverse, pSrc, pMask, + pDst) || + !(*pExaScr->info->CheckComposite)(PictOpAdd, pSrc, pMask, pDst))) + { + return -1; + } + + /* Now, we think we should be able to accelerate this operation. First, + * composite the destination to be the destination times the source alpha + * factors. + */ + exaComposite(PictOpOutReverse, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, + xDst, yDst, width, height); + + /* Then, add in the source value times the destination alpha factors (1.0). + */ + exaComposite(PictOpAdd, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, + xDst, yDst, width, height); + + return 1; +} + +void +exaComposite(CARD8 op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + ExaScreenPriv (pDst->pDrawable->pScreen); + int ret = -1; + Bool saveSrcRepeat = pSrc->repeat; + Bool saveMaskRepeat = pMask ? pMask->repeat : 0; + RegionRec region; + + if (pExaScr->swappedOut) + goto fallback; + + /* Remove repeat in source if useless */ + if (pSrc->pDrawable && pSrc->repeat && !pSrc->transform && xSrc >= 0 && + (xSrc + width) <= pSrc->pDrawable->width && ySrc >= 0 && + (ySrc + height) <= pSrc->pDrawable->height) + pSrc->repeat = 0; + + if (!pMask && !pSrc->alphaMap && !pDst->alphaMap && + (op == PictOpSrc || (op == PictOpOver && !PICT_FORMAT_A(pSrc->format)))) + { + if (pSrc->pDrawable ? + (pSrc->pDrawable->width == 1 && pSrc->pDrawable->height == 1 && + pSrc->repeat) : + (pSrc->pSourcePict->type == SourcePictTypeSolidFill)) + { + ret = exaTryDriverSolidFill(pSrc, pDst, xSrc, ySrc, xDst, yDst, + width, height); + if (ret == 1) + goto done; + } else if (pSrc->pDrawable && !pSrc->transform && + ((op == PictOpSrc && + (pSrc->format == pDst->format || + (PICT_FORMAT_COLOR(pDst->format) && + PICT_FORMAT_COLOR(pSrc->format) && + pDst->format == PICT_FORMAT(PICT_FORMAT_BPP(pSrc->format), + PICT_FORMAT_TYPE(pSrc->format), + 0, + PICT_FORMAT_R(pSrc->format), + PICT_FORMAT_G(pSrc->format), + PICT_FORMAT_B(pSrc->format))))) || + (op == PictOpOver && pSrc->format == pDst->format && + !PICT_FORMAT_A(pSrc->format)))) + { + if (!pSrc->repeat && xSrc >= 0 && ySrc >= 0 && + (xSrc + width <= pSrc->pDrawable->width) && + (ySrc + height <= pSrc->pDrawable->height)) + { + Bool ret; + xDst += pDst->pDrawable->x; + yDst += pDst->pDrawable->y; + xSrc += pSrc->pDrawable->x; + ySrc += pSrc->pDrawable->y; + + if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst, + xSrc, ySrc, xMask, yMask, xDst, + yDst, width, height)) + goto done; + + ret = exaHWCopyNtoN(pSrc->pDrawable, pDst->pDrawable, NULL, + RegionRects(®ion), RegionNumRects(®ion), + xSrc - xDst, ySrc - yDst, FALSE, FALSE); + RegionUninit(®ion); + + /* Reset values to their original values. */ + xDst -= pDst->pDrawable->x; + yDst -= pDst->pDrawable->y; + xSrc -= pSrc->pDrawable->x; + ySrc -= pSrc->pDrawable->y; + + if (!ret) + goto fallback; + + goto done; + } + + 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 (pExaScr->info->PrepareComposite && !pSrc->alphaMap && + !pDst->alphaMap) + { + ret = exaTryDriverComposite(op, pSrc, pMask, pDst, xSrc, + ySrc, xMask, yMask, xDst, yDst, + width, height); + if (ret == 1) + goto done; + } + + /* Now see if we can use exaFillRegionTiled() */ + xDst += pDst->pDrawable->x; + yDst += pDst->pDrawable->y; + xSrc += pSrc->pDrawable->x; + ySrc += pSrc->pDrawable->y; + + if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst, xSrc, + ySrc, xMask, yMask, xDst, yDst, + width, height)) + goto done; + + /* pattern origin is the point in the destination drawable + * corresponding to (0,0) in the source */ + patOrg.x = xDst - xSrc; + patOrg.y = yDst - ySrc; + + ret = exaFillRegionTiled(pDst->pDrawable, ®ion, + (PixmapPtr)pSrc->pDrawable, + &patOrg, FB_ALLONES, GXcopy, CT_NONE); + + RegionUninit(®ion); + + if (ret) + goto done; + + /* Let's be correct and restore the variables to their original state. */ + xDst -= pDst->pDrawable->x; + yDst -= pDst->pDrawable->y; + xSrc -= pSrc->pDrawable->x; + ySrc -= pSrc->pDrawable->y; + } + } + } + + /* Remove repeat in mask if useless */ + if (pMask && pMask->pDrawable && pMask->repeat && !pMask->transform && + xMask >= 0 && (xMask + width) <= pMask->pDrawable->width && + yMask >= 0 && (yMask + height) <= pMask->pDrawable->height) + pMask->repeat = 0; + + if (pExaScr->info->PrepareComposite && + !pSrc->alphaMap && (!pMask || !pMask->alphaMap) && !pDst->alphaMap) + { + Bool isSrcSolid; + + ret = exaTryDriverComposite(op, pSrc, pMask, pDst, xSrc, ySrc, xMask, + yMask, xDst, yDst, width, height); + if (ret == 1) + goto done; + + /* 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) : + (pSrc->pSourcePict->type == SourcePictTypeSolidFill); + + /* 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 passes with + * an OutReverse and then an Add. + */ + if (ret == -1 && op == PictOpOver && pMask && + (pMask->componentAlpha || isSrcSolid)) { + ret = exaTryMagicTwoPassCompositeHelper(op, pSrc, pMask, pDst, + xSrc, ySrc, + xMask, yMask, xDst, yDst, + width, height); + if (ret == 1) + goto done; + } + } + +fallback: +#if DEBUG_TRACE_FALL + exaPrintCompositeFallback (op, pSrc, pMask, pDst); +#endif + + ExaCheckComposite (op, pSrc, pMask, pDst, xSrc, ySrc, + xMask, yMask, xDst, yDst, width, height); + +done: + pSrc->repeat = saveSrcRepeat; + if (pMask) + pMask->repeat = saveMaskRepeat; +} + +/** + * Same as miCreateAlphaPicture, except it uses ExaCheckPolyFillRect instead + * of PolyFillRect to initialize the pixmap after creating it, to prevent + * the pixmap from being migrated. + * + * See the comments about exaTrapezoids and exaTriangles. + */ +static PicturePtr +exaCreateAlphaPicture (ScreenPtr pScreen, + PicturePtr pDst, + PictFormatPtr pPictFormat, + CARD16 width, + CARD16 height) +{ + PixmapPtr pPixmap; + PicturePtr pPicture; + GCPtr pGC; + int error; + xRectangle rect; + + if (width > 32767 || height > 32767) + return 0; + + if (!pPictFormat) + { + if (pDst->polyEdge == PolyEdgeSharp) + pPictFormat = PictureMatchFormat (pScreen, 1, PICT_a1); + else + pPictFormat = PictureMatchFormat (pScreen, 8, PICT_a8); + if (!pPictFormat) + return 0; + } + + pPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, + pPictFormat->depth, 0); + if (!pPixmap) + return 0; + pGC = GetScratchGC (pPixmap->drawable.depth, pScreen); + if (!pGC) + { + (*pScreen->DestroyPixmap) (pPixmap); + return 0; + } + ValidateGC (&pPixmap->drawable, pGC); + rect.x = 0; + rect.y = 0; + rect.width = width; + rect.height = height; + ExaCheckPolyFillRect (&pPixmap->drawable, pGC, 1, &rect); + exaPixmapDirty (pPixmap, 0, 0, width, height); + FreeScratchGC (pGC); + pPicture = CreatePicture (0, &pPixmap->drawable, pPictFormat, + 0, 0, serverClient, &error); + (*pScreen->DestroyPixmap) (pPixmap); + return pPicture; +} + +/** + * exaTrapezoids is essentially a copy of miTrapezoids that uses + * exaCreateAlphaPicture instead of miCreateAlphaPicture. + * + * The problem with miCreateAlphaPicture is that it calls PolyFillRect + * to initialize the contents after creating the pixmap, which + * causes the pixmap to be moved in for acceleration. The subsequent + * call to RasterizeTrapezoid won't be accelerated however, which + * forces the pixmap to be moved out again. + * + * exaCreateAlphaPicture avoids this roundtrip by using ExaCheckPolyFillRect + * to initialize the contents. + */ +void +exaTrapezoids (CARD8 op, PicturePtr pSrc, PicturePtr pDst, + PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, + int ntrap, xTrapezoid *traps) +{ + ScreenPtr pScreen = pDst->pDrawable->pScreen; + PictureScreenPtr ps = GetPictureScreen(pScreen); + BoxRec bounds; + + if (maskFormat) { + PicturePtr pPicture; + INT16 xDst, yDst; + INT16 xRel, yRel; + + miTrapezoidBounds (ntrap, traps, &bounds); + + if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) + return; + + xDst = traps[0].left.p1.x >> 16; + yDst = traps[0].left.p1.y >> 16; + + pPicture = exaCreateAlphaPicture (pScreen, pDst, maskFormat, + bounds.x2 - bounds.x1, + bounds.y2 - bounds.y1); + if (!pPicture) + return; + + exaPrepareAccess(pPicture->pDrawable, EXA_PREPARE_DEST); + for (; ntrap; ntrap--, traps++) + (*ps->RasterizeTrapezoid) (pPicture, traps, + -bounds.x1, -bounds.y1); + exaFinishAccess(pPicture->pDrawable, EXA_PREPARE_DEST); + + xRel = bounds.x1 + xSrc - xDst; + yRel = bounds.y1 + ySrc - yDst; + CompositePicture (op, pSrc, pPicture, pDst, + xRel, yRel, 0, 0, bounds.x1, bounds.y1, + bounds.x2 - bounds.x1, + bounds.y2 - bounds.y1); + FreePicture (pPicture, 0); + } else { + if (pDst->polyEdge == PolyEdgeSharp) + maskFormat = PictureMatchFormat (pScreen, 1, PICT_a1); + else + maskFormat = PictureMatchFormat (pScreen, 8, PICT_a8); + for (; ntrap; ntrap--, traps++) + exaTrapezoids (op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, traps); + } +} + +/** + * exaTriangles is essentially a copy of miTriangles that uses + * exaCreateAlphaPicture instead of miCreateAlphaPicture. + * + * The problem with miCreateAlphaPicture is that it calls PolyFillRect + * to initialize the contents after creating the pixmap, which + * causes the pixmap to be moved in for acceleration. The subsequent + * call to AddTriangles won't be accelerated however, which forces the pixmap + * to be moved out again. + * + * exaCreateAlphaPicture avoids this roundtrip by using ExaCheckPolyFillRect + * to initialize the contents. + */ +void +exaTriangles (CARD8 op, PicturePtr pSrc, PicturePtr pDst, + PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, + int ntri, xTriangle *tris) +{ + ScreenPtr pScreen = pDst->pDrawable->pScreen; + PictureScreenPtr ps = GetPictureScreen(pScreen); + BoxRec bounds; + + if (maskFormat) { + PicturePtr pPicture; + INT16 xDst, yDst; + INT16 xRel, yRel; + + miTriangleBounds (ntri, tris, &bounds); + + if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) + return; + + xDst = tris[0].p1.x >> 16; + yDst = tris[0].p1.y >> 16; + + pPicture = exaCreateAlphaPicture (pScreen, pDst, maskFormat, + bounds.x2 - bounds.x1, + bounds.y2 - bounds.y1); + if (!pPicture) + return; + + exaPrepareAccess(pPicture->pDrawable, EXA_PREPARE_DEST); + (*ps->AddTriangles) (pPicture, -bounds.x1, -bounds.y1, ntri, tris); + exaFinishAccess(pPicture->pDrawable, EXA_PREPARE_DEST); + + xRel = bounds.x1 + xSrc - xDst; + yRel = bounds.y1 + ySrc - yDst; + CompositePicture (op, pSrc, pPicture, pDst, + xRel, yRel, 0, 0, bounds.x1, bounds.y1, + bounds.x2 - bounds.x1, bounds.y2 - bounds.y1); + FreePicture (pPicture, 0); + } else { + if (pDst->polyEdge == PolyEdgeSharp) + maskFormat = PictureMatchFormat (pScreen, 1, PICT_a1); + else + maskFormat = PictureMatchFormat (pScreen, 8, PICT_a8); + + for (; ntri; ntri--, tris++) + exaTriangles (op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, tris); + } +} diff --git a/xorg-server/exa/exa_unaccel.c b/xorg-server/exa/exa_unaccel.c index 46be2eff9..5e4a8c573 100644 --- a/xorg-server/exa/exa_unaccel.c +++ b/xorg-server/exa/exa_unaccel.c @@ -131,10 +131,10 @@ ExaCheckCopyNtoN (DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, PixmapPtr pPixmap = exaGetDrawablePixmap(pSrc); exaGetDrawableDeltas(pSrc, pPixmap, &xoff, &yoff); - REGION_INIT(pScreen, ®, pbox, nbox); - REGION_TRANSLATE(pScreen, ®, xoff + dx, yoff + dy); + RegionInit(®, pbox, nbox); + RegionTranslate(®, xoff + dx, yoff + dy); pExaScr->prepare_access_reg(pPixmap, EXA_PREPARE_SRC, ®); - REGION_UNINIT(pScreen, ®); + RegionUninit(®); } else exaPrepareAccess (pSrc, EXA_PREPARE_SRC); @@ -144,10 +144,10 @@ ExaCheckCopyNtoN (DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, PixmapPtr pPixmap = exaGetDrawablePixmap(pDst); exaGetDrawableDeltas(pSrc, pPixmap, &xoff, &yoff); - REGION_INIT(pScreen, ®, pbox, nbox); - REGION_TRANSLATE(pScreen, ®, xoff, yoff); + RegionInit(®, pbox, nbox); + RegionTranslate(®, xoff, yoff); pExaScr->prepare_access_reg(pPixmap, EXA_PREPARE_DEST, ®); - REGION_UNINIT(pScreen, ®); + RegionUninit(®); } else exaPrepareAccess (pDst, EXA_PREPARE_DEST); @@ -188,9 +188,9 @@ ExaFallbackPrepareReg(DrawablePtr pDrawable, box.x2 = box.x1 + width; box.y2 = box.y1 + height; - REGION_INIT(pScreen, ®, &box, 1); + RegionInit(®, &box, 1); pExaScr->prepare_access_reg(pPixmap, index, ®); - REGION_UNINIT(pScreen, ®); + RegionUninit(®); } else exaPrepareAccess(pDrawable, index); } @@ -382,9 +382,9 @@ ExaCheckCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc) int xoff, yoff; exaGetDrawableDeltas(&pWin->drawable, pPixmap, &xoff, &yoff); - REGION_TRANSLATE(pScreen, prgnSrc, xoff, yoff); + RegionTranslate(prgnSrc, xoff, yoff); pExaScr->prepare_access_reg(pPixmap, EXA_PREPARE_SRC, prgnSrc); - REGION_TRANSLATE(pScreen, prgnSrc, -xoff, -yoff); + RegionTranslate(prgnSrc, -xoff, -yoff); } else exaPrepareAccess(pDrawable, EXA_PREPARE_SRC); @@ -458,9 +458,9 @@ ExaSrcValidate(DrawablePtr pDrawable, dst = (pExaScr->srcPix == pPix) ? &pExaScr->srcReg : &pExaScr->maskReg; - REGION_INIT(pScreen, ®, &box, 1); - REGION_UNION(pScreen, dst, dst, ®); - REGION_UNINIT(pScreen, ®); + RegionInit(®, &box, 1); + RegionUnion(dst, dst, ®); + RegionUninit(®); if (pExaScr->SavedSourceValidate) { swap(pExaScr, pScreen, SourceValidate); @@ -495,30 +495,30 @@ ExaPrepareCompositeReg(ScreenPtr pScreen, Bool ret; - REGION_NULL(pScreen, ®ion); + RegionNull(®ion); if (pSrc->pDrawable) { pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable); - REGION_NULL(pScreen, &pExaScr->srcReg); + RegionNull(&pExaScr->srcReg); srcReg = &pExaScr->srcReg; pExaScr->srcPix = pSrcPix; if (pSrc != pDst) - REGION_TRANSLATE(pScreen, pSrc->pCompositeClip, + RegionTranslate(pSrc->pCompositeClip, -pSrc->pDrawable->x, -pSrc->pDrawable->y); } if (pMask && pMask->pDrawable) { pMaskPix = exaGetDrawablePixmap(pMask->pDrawable); - REGION_NULL(pScreen, &pExaScr->maskReg); + RegionNull(&pExaScr->maskReg); maskReg = &pExaScr->maskReg; if (pMask != pDst && pMask != pSrc) - REGION_TRANSLATE(pScreen, pMask->pCompositeClip, + RegionTranslate(pMask->pCompositeClip, -pMask->pDrawable->x, -pMask->pDrawable->y); } - REGION_TRANSLATE(pScreen, pDst->pCompositeClip, + RegionTranslate(pDst->pCompositeClip, -pDst->pDrawable->x, -pDst->pDrawable->y); @@ -531,23 +531,23 @@ ExaPrepareCompositeReg(ScreenPtr pScreen, width, height); swap(pExaScr, pScreen, SourceValidate); - REGION_TRANSLATE(pScreen, pDst->pCompositeClip, + RegionTranslate(pDst->pCompositeClip, pDst->pDrawable->x, pDst->pDrawable->y); if (pSrc->pDrawable && pSrc != pDst) - REGION_TRANSLATE(pScreen, pSrc->pCompositeClip, + RegionTranslate(pSrc->pCompositeClip, pSrc->pDrawable->x, pSrc->pDrawable->y); if (pMask && pMask->pDrawable && pMask != pDst && pMask != pSrc) - REGION_TRANSLATE(pScreen, pMask->pCompositeClip, + RegionTranslate(pMask->pCompositeClip, pMask->pDrawable->x, pMask->pDrawable->y); if (!ret) { if (srcReg) - REGION_UNINIT(pScreen, srcReg); + RegionUninit(srcReg); if (maskReg) - REGION_UNINIT(pScreen, maskReg); + RegionUninit(maskReg); return FALSE; } @@ -577,9 +577,9 @@ ExaPrepareCompositeReg(ScreenPtr pScreen, maskReg); if (srcReg) - REGION_UNINIT(pScreen, srcReg); + RegionUninit(srcReg); if (maskReg) - REGION_UNINIT(pScreen, maskReg); + RegionUninit(maskReg); pDstPix = exaGetDrawablePixmap(pDst->pDrawable); if (!exaOpReadsDestination(op)) { @@ -587,7 +587,7 @@ ExaPrepareCompositeReg(ScreenPtr pScreen, int yoff; exaGetDrawableDeltas (pDst->pDrawable, pDstPix, &xoff, &yoff); - REGION_TRANSLATE(pScreen, ®ion, pDst->pDrawable->x + xoff, + RegionTranslate(®ion, pDst->pDrawable->x + xoff, pDst->pDrawable->y + yoff); dstReg = ®ion; } @@ -598,7 +598,7 @@ ExaPrepareCompositeReg(ScreenPtr pScreen, dstReg); pExaScr->prepare_access_reg(pDstPix, EXA_PREPARE_DEST, dstReg); - REGION_UNINIT(pScreen, ®ion); + RegionUninit(®ion); return TRUE; } -- cgit v1.2.3