aboutsummaryrefslogtreecommitdiff
path: root/xorg-server/exa
diff options
context:
space:
mode:
authormarha <marha@users.sourceforge.net>2010-06-11 12:14:52 +0000
committermarha <marha@users.sourceforge.net>2010-06-11 12:14:52 +0000
commit4c61bf84b11e26e6f22648668c95ea760a379163 (patch)
tree0ac762ab2815eae283dded7447ad7cb5a54b926a /xorg-server/exa
parente1dabd2ce8be0d70c6c15353b58de256129dfd1f (diff)
downloadvcxsrv-4c61bf84b11e26e6f22648668c95ea760a379163.tar.gz
vcxsrv-4c61bf84b11e26e6f22648668c95ea760a379163.tar.bz2
vcxsrv-4c61bf84b11e26e6f22648668c95ea760a379163.zip
xserver git update 11/6/2010
Diffstat (limited to 'xorg-server/exa')
-rw-r--r--xorg-server/exa/exa.c27
-rw-r--r--xorg-server/exa/exa_accel.c80
-rw-r--r--xorg-server/exa/exa_classic.c534
-rw-r--r--xorg-server/exa/exa_migration_classic.c1490
-rw-r--r--xorg-server/exa/exa_mixed.c583
-rw-r--r--xorg-server/exa/exa_priv.h10
-rw-r--r--xorg-server/exa/exa_render.c2512
-rw-r--r--xorg-server/exa/exa_unaccel.c56
8 files changed, 2649 insertions, 2643 deletions
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, &region, &box, 1);
+ RegionInit(&region, &box, 1);
DamageRegionAppend(&pPix->drawable, &region);
DamageRegionProcessPending(&pPix->drawable);
- REGION_UNINIT(pScreen, &region);
+ RegionUninit(&region);
}
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 <dix-config.h>
-#endif
-
-#include <string.h>
-
-#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 <dix-config.h>
+#endif
+
+#include <string.h>
+
+#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 <eric@anholt.net>
- * Michel Dänzer <michel@tungstengraphics.com>
- *
- */
-
-#ifdef HAVE_DIX_CONFIG_H
-#include <dix-config.h>
-#endif
-
-#include <string.h>
-
-#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 <eric@anholt.net>
+ * Michel Dänzer <michel@tungstengraphics.com>
+ *
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <string.h>
+
+#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 <dix-config.h>
-#endif
-
-#include <string.h>
-
-#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 <dix-config.h>
+#endif
+
+#include <string.h>
+
+#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 <dix-config.h>
-#endif
-
-#include <stdlib.h>
-
-#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 (&region, 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, &region, 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, &region);
- 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 = &region;
- exaDoMigration(pixmaps, 1, TRUE);
- }
-
- if (!exaPixmapHasGpuCopy(pDstPix)) {
- REGION_UNINIT(pDst->pDrawable->pScreen, &region);
- return 0;
- }
-
- if (!(*pExaScr->info->PrepareSolid) (pDstPix, GXcopy, 0xffffffff, pixel))
- {
- REGION_UNINIT(pDst->pDrawable->pScreen, &region);
- return -1;
- }
-
- nbox = REGION_NUM_RECTS(&region);
- pbox = REGION_RECTS(&region);
-
- 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, &region);
- 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 (&region, pSrc, pMask, pDst,
- xSrc, ySrc, xMask, yMask, xDst, yDst,
- rects->width, rects->height))
- goto next_rect;
-
- REGION_TRANSLATE(pScreen, &region, dst_off_x, dst_off_y);
-
- nbox = REGION_NUM_RECTS(&region);
- pbox = REGION_RECTS(&region);
-
- 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, &region);
-
- 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, &region, &box, 1);
-
- DamageRegionAppend(pDst->pDrawable, &region);
-
- REGION_UNINIT(pScreen, &region);
- }
-
- /************************************************************/
-
- 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 (&region, 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, &region, 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 : &region;
- 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, &region);
- return 0;
- }
- }
-
- if (pMaskPix) {
- pMaskPix = exaGetOffscreenPixmap (pMask->pDrawable, &mask_off_x,
- &mask_off_y);
- if (!pMaskPix) {
- REGION_UNINIT(pDst->pDrawable->pScreen, &region);
- return 0;
- }
- }
-
- if (!exaPixmapHasGpuCopy(pDstPix)) {
- REGION_UNINIT(pDst->pDrawable->pScreen, &region);
- return 0;
- }
-
- if (!(*pExaScr->info->PrepareComposite) (op, pSrc, pMask, pDst, pSrcPix,
- pMaskPix, pDstPix))
- {
- REGION_UNINIT(pDst->pDrawable->pScreen, &region);
- return -1;
- }
-
- nbox = REGION_NUM_RECTS(&region);
- pbox = REGION_RECTS(&region);
-
- 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, &region);
- 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 (&region, pSrc, pMask, pDst,
- xSrc, ySrc, xMask, yMask, xDst,
- yDst, width, height))
- goto done;
-
- ret = exaHWCopyNtoN(pSrc->pDrawable, pDst->pDrawable, NULL,
- REGION_RECTS(&region), REGION_NUM_RECTS(&region),
- xSrc - xDst, ySrc - yDst, FALSE, FALSE);
- REGION_UNINIT(pDst->pDrawable->pScreen, &region);
-
- /* 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 (&region, 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, &region,
- (PixmapPtr)pSrc->pDrawable,
- &patOrg, FB_ALLONES, GXcopy, CT_NONE);
-
- REGION_UNINIT(pDst->pDrawable->pScreen, &region);
-
- 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 <dix-config.h>
+#endif
+
+#include <stdlib.h>
+
+#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 (&region, pSrc, NULL, pDst,
+ xSrc, ySrc, 0, 0, xDst, yDst,
+ width, height))
+ return 1;
+
+ exaGetDrawableDeltas (pDst->pDrawable, pDstPix, &dst_off_x, &dst_off_y);
+
+ RegionTranslate(&region, 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(&region);
+ 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 = &region;
+ exaDoMigration(pixmaps, 1, TRUE);
+ }
+
+ if (!exaPixmapHasGpuCopy(pDstPix)) {
+ RegionUninit(&region);
+ return 0;
+ }
+
+ if (!(*pExaScr->info->PrepareSolid) (pDstPix, GXcopy, 0xffffffff, pixel))
+ {
+ RegionUninit(&region);
+ return -1;
+ }
+
+ nbox = RegionNumRects(&region);
+ pbox = RegionRects(&region);
+
+ while (nbox--)
+ {
+ (*pExaScr->info->Solid) (pDstPix, pbox->x1, pbox->y1, pbox->x2, pbox->y2);
+ pbox++;
+ }
+
+ (*pExaScr->info->DoneSolid) (pDstPix);
+ exaMarkSync(pDst->pDrawable->pScreen);
+
+ RegionUninit(&region);
+ 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 (&region, pSrc, pMask, pDst,
+ xSrc, ySrc, xMask, yMask, xDst, yDst,
+ rects->width, rects->height))
+ goto next_rect;
+
+ RegionTranslate(&region, dst_off_x, dst_off_y);
+
+ nbox = RegionNumRects(&region);
+ pbox = RegionRects(&region);
+
+ 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(&region);
+
+ 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(&region, &box, 1);
+
+ DamageRegionAppend(pDst->pDrawable, &region);
+
+ RegionUninit(&region);
+ }
+
+ /************************************************************/
+
+ 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 (&region, pSrc, pMask, pDst,
+ xSrc, ySrc, xMask, yMask, xDst, yDst,
+ width, height))
+ return 1;
+
+ exaGetDrawableDeltas (pDst->pDrawable, pDstPix, &dst_off_x, &dst_off_y);
+
+ RegionTranslate(&region, 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 : &region;
+ 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(&region);
+ return 0;
+ }
+ }
+
+ if (pMaskPix) {
+ pMaskPix = exaGetOffscreenPixmap (pMask->pDrawable, &mask_off_x,
+ &mask_off_y);
+ if (!pMaskPix) {
+ RegionUninit(&region);
+ return 0;
+ }
+ }
+
+ if (!exaPixmapHasGpuCopy(pDstPix)) {
+ RegionUninit(&region);
+ return 0;
+ }
+
+ if (!(*pExaScr->info->PrepareComposite) (op, pSrc, pMask, pDst, pSrcPix,
+ pMaskPix, pDstPix))
+ {
+ RegionUninit(&region);
+ return -1;
+ }
+
+ nbox = RegionNumRects(&region);
+ pbox = RegionRects(&region);
+
+ 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(&region);
+ 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 (&region, pSrc, pMask, pDst,
+ xSrc, ySrc, xMask, yMask, xDst,
+ yDst, width, height))
+ goto done;
+
+ ret = exaHWCopyNtoN(pSrc->pDrawable, pDst->pDrawable, NULL,
+ RegionRects(&region), RegionNumRects(&region),
+ xSrc - xDst, ySrc - yDst, FALSE, FALSE);
+ RegionUninit(&region);
+
+ /* 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 (&region, 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, &region,
+ (PixmapPtr)pSrc->pDrawable,
+ &patOrg, FB_ALLONES, GXcopy, CT_NONE);
+
+ RegionUninit(&region);
+
+ 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, &reg, pbox, nbox);
- REGION_TRANSLATE(pScreen, &reg, xoff + dx, yoff + dy);
+ RegionInit(&reg, pbox, nbox);
+ RegionTranslate(&reg, xoff + dx, yoff + dy);
pExaScr->prepare_access_reg(pPixmap, EXA_PREPARE_SRC, &reg);
- REGION_UNINIT(pScreen, &reg);
+ RegionUninit(&reg);
} 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, &reg, pbox, nbox);
- REGION_TRANSLATE(pScreen, &reg, xoff, yoff);
+ RegionInit(&reg, pbox, nbox);
+ RegionTranslate(&reg, xoff, yoff);
pExaScr->prepare_access_reg(pPixmap, EXA_PREPARE_DEST, &reg);
- REGION_UNINIT(pScreen, &reg);
+ RegionUninit(&reg);
} 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, &reg, &box, 1);
+ RegionInit(&reg, &box, 1);
pExaScr->prepare_access_reg(pPixmap, index, &reg);
- REGION_UNINIT(pScreen, &reg);
+ RegionUninit(&reg);
} 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, &reg, &box, 1);
- REGION_UNION(pScreen, dst, dst, &reg);
- REGION_UNINIT(pScreen, &reg);
+ RegionInit(&reg, &box, 1);
+ RegionUnion(dst, dst, &reg);
+ RegionUninit(&reg);
if (pExaScr->SavedSourceValidate) {
swap(pExaScr, pScreen, SourceValidate);
@@ -495,30 +495,30 @@ ExaPrepareCompositeReg(ScreenPtr pScreen,
Bool ret;
- REGION_NULL(pScreen, &region);
+ RegionNull(&region);
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, &region, pDst->pDrawable->x + xoff,
+ RegionTranslate(&region, pDst->pDrawable->x + xoff,
pDst->pDrawable->y + yoff);
dstReg = &region;
}
@@ -598,7 +598,7 @@ ExaPrepareCompositeReg(ScreenPtr pScreen,
dstReg);
pExaScr->prepare_access_reg(pDstPix, EXA_PREPARE_DEST, dstReg);
- REGION_UNINIT(pScreen, &region);
+ RegionUninit(&region);
return TRUE;
}