aboutsummaryrefslogtreecommitdiff
path: root/xorg-server/exa
diff options
context:
space:
mode:
authormarha <marha@users.sourceforge.net>2011-07-04 14:26:33 +0200
committermarha <marha@users.sourceforge.net>2011-07-04 14:26:33 +0200
commit7cc339a490eac34596e97788c3b0092d58459cf6 (patch)
treebc9a29aff5729a5b7314022bc3fea8fdff721dc0 /xorg-server/exa
parent3bbcbc59b6d98f09b26f39d6208faec76cc6aa3e (diff)
parent5c671fd7f8198bed2fc32b33b81d1081f1486ed9 (diff)
downloadvcxsrv-7cc339a490eac34596e97788c3b0092d58459cf6.tar.gz
vcxsrv-7cc339a490eac34596e97788c3b0092d58459cf6.tar.bz2
vcxsrv-7cc339a490eac34596e97788c3b0092d58459cf6.zip
Merge remote-tracking branch 'origin/released'
Conflicts: mesalib/common.py mesalib/docs/GL3.txt mesalib/scons/custom.py mesalib/scons/gallium.py mesalib/src/SConscript xorg-server/Xext/xtest.c xorg-server/dix/getevents.c xorg-server/dix/window.c xorg-server/exa/exa_accel.c xorg-server/exa/exa_migration_classic.c xorg-server/exa/exa_unaccel.c xorg-server/hw/kdrive/ephyr/ephyr.c xorg-server/hw/kdrive/ephyr/ephyr.h xorg-server/hw/kdrive/ephyr/ephyrinit.c xorg-server/hw/kdrive/ephyr/hostx.c xorg-server/hw/kdrive/src/kdrive.h xorg-server/hw/kdrive/src/kinput.c xorg-server/hw/xfree86/common/xf86Init.c xorg-server/hw/xfree86/dri2/dri2.c xorg-server/hw/xnest/Init.c xorg-server/hw/xquartz/darwin.c xorg-server/hw/xquartz/darwinEvents.c xorg-server/hw/xquartz/darwinEvents.h xorg-server/hw/xquartz/darwinXinput.c xorg-server/hw/xwin/InitInput.c xorg-server/include/input.h xorg-server/include/window.h xorg-server/mi/mipointer.c xorg-server/test/Makefile.am xorg-server/test/xi2/protocol-eventconvert.c
Diffstat (limited to 'xorg-server/exa')
-rw-r--r--xorg-server/exa/exa.c4
-rw-r--r--xorg-server/exa/exa_accel.c2612
-rw-r--r--xorg-server/exa/exa_classic.c532
-rw-r--r--xorg-server/exa/exa_driver.c452
-rw-r--r--xorg-server/exa/exa_migration_classic.c1490
-rw-r--r--xorg-server/exa/exa_migration_mixed.c522
-rw-r--r--xorg-server/exa/exa_mixed.c580
-rw-r--r--xorg-server/exa/exa_unaccel.c2
8 files changed, 3097 insertions, 3097 deletions
diff --git a/xorg-server/exa/exa.c b/xorg-server/exa/exa.c
index a4e294a71..4ce983bc3 100644
--- a/xorg-server/exa/exa.c
+++ b/xorg-server/exa/exa.c
@@ -1,7 +1,7 @@
/*
- * Copyright © 2001 Keith Packard
+ * Copyright © 2001 Keith Packard
*
- * Partly based on code that is Copyright © The XFree86 Project Inc.
+ * 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
diff --git a/xorg-server/exa/exa_accel.c b/xorg-server/exa/exa_accel.c
index b81d843f9..3917621e1 100644
--- a/xorg-server/exa/exa_accel.c
+++ b/xorg-server/exa/exa_accel.c
@@ -1,1306 +1,1306 @@
-/*
- * 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.
- *
- * Authors:
- * Eric Anholt <eric@anholt.net>
- * Michel Dänzer <michel@tungstengraphics.com>
- *
- */
-
-#ifdef HAVE_DIX_CONFIG_H
-#include <dix-config.h>
-#endif
-#include "exa_priv.h"
-#include <X11/fonts/fontstruct.h>
-#include "dixfontstr.h"
-#include "exa.h"
-
-static void
-exaFillSpans(DrawablePtr pDrawable, GCPtr pGC, int n,
- DDXPointPtr ppt, int *pwidth, int fSorted)
-{
- ScreenPtr pScreen = pDrawable->pScreen;
- ExaScreenPriv (pScreen);
- RegionPtr pClip = fbGetCompositeClip(pGC);
- PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable);
- ExaPixmapPriv (pPixmap);
- BoxPtr pextent, pbox;
- int nbox;
- int extentX1, extentX2, extentY1, extentY2;
- int fullX1, fullX2, fullY1;
- int partX1, partX2;
- int off_x, off_y;
-
- if (pExaScr->fallback_counter ||
- pExaScr->swappedOut ||
- pGC->fillStyle != FillSolid ||
- pExaPixmap->accel_blocked)
- {
- ExaCheckFillSpans (pDrawable, pGC, n, ppt, pwidth, fSorted);
- return;
- }
-
- if (pExaScr->do_migration) {
- ExaMigrationRec pixmaps[1];
-
- pixmaps[0].as_dst = TRUE;
- pixmaps[0].as_src = FALSE;
- pixmaps[0].pPix = pPixmap;
- pixmaps[0].pReg = NULL;
-
- exaDoMigration (pixmaps, 1, TRUE);
- }
-
- if (!(pPixmap = exaGetOffscreenPixmap (pDrawable, &off_x, &off_y)) ||
- !(*pExaScr->info->PrepareSolid) (pPixmap,
- pGC->alu,
- pGC->planemask,
- pGC->fgPixel))
- {
- ExaCheckFillSpans (pDrawable, pGC, n, ppt, pwidth, fSorted);
- return;
- }
-
- pextent = RegionExtents(pClip);
- extentX1 = pextent->x1;
- extentY1 = pextent->y1;
- extentX2 = pextent->x2;
- extentY2 = pextent->y2;
- while (n--)
- {
- fullX1 = ppt->x;
- fullY1 = ppt->y;
- fullX2 = fullX1 + (int) *pwidth;
- ppt++;
- pwidth++;
-
- if (fullY1 < extentY1 || extentY2 <= fullY1)
- continue;
-
- if (fullX1 < extentX1)
- fullX1 = extentX1;
-
- if (fullX2 > extentX2)
- fullX2 = extentX2;
-
- if (fullX1 >= fullX2)
- continue;
-
- nbox = RegionNumRects (pClip);
- if (nbox == 1)
- {
- (*pExaScr->info->Solid) (pPixmap,
- fullX1 + off_x, fullY1 + off_y,
- fullX2 + off_x, fullY1 + 1 + off_y);
- }
- else
- {
- pbox = RegionRects(pClip);
- while(nbox--)
- {
- if (pbox->y1 <= fullY1 && fullY1 < pbox->y2)
- {
- partX1 = pbox->x1;
- if (partX1 < fullX1)
- partX1 = fullX1;
- partX2 = pbox->x2;
- if (partX2 > fullX2)
- partX2 = fullX2;
- if (partX2 > partX1) {
- (*pExaScr->info->Solid) (pPixmap,
- partX1 + off_x, fullY1 + off_y,
- partX2 + off_x, fullY1 + 1 + off_y);
- }
- }
- pbox++;
- }
- }
- }
- (*pExaScr->info->DoneSolid) (pPixmap);
- exaMarkSync(pScreen);
-}
-
-static Bool
-exaDoPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y,
- int w, int h, int format, char *bits, int src_stride)
-{
- ExaScreenPriv (pDrawable->pScreen);
- PixmapPtr pPix = exaGetDrawablePixmap (pDrawable);
- ExaPixmapPriv(pPix);
- RegionPtr pClip;
- BoxPtr pbox;
- int nbox;
- int xoff, yoff;
- int bpp = pDrawable->bitsPerPixel;
- Bool ret = TRUE;
-
- if (pExaScr->fallback_counter || pExaPixmap->accel_blocked || !pExaScr->info->UploadToScreen)
- return FALSE;
-
- /* If there's a system copy, we want to save the result there */
- if (pExaPixmap->pDamage)
- return FALSE;
-
- /* Don't bother with under 8bpp, XYPixmaps. */
- if (format != ZPixmap || bpp < 8)
- return FALSE;
-
- /* Only accelerate copies: no rop or planemask. */
- if (!EXA_PM_IS_SOLID(pDrawable, pGC->planemask) || pGC->alu != GXcopy)
- return FALSE;
-
- if (pExaScr->swappedOut)
- return FALSE;
-
- if (pExaScr->do_migration) {
- ExaMigrationRec pixmaps[1];
-
- pixmaps[0].as_dst = TRUE;
- pixmaps[0].as_src = FALSE;
- pixmaps[0].pPix = pPix;
- pixmaps[0].pReg = DamagePendingRegion(pExaPixmap->pDamage);
-
- exaDoMigration (pixmaps, 1, TRUE);
- }
-
- pPix = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff);
-
- if (!pPix)
- return FALSE;
-
- x += pDrawable->x;
- y += pDrawable->y;
-
- pClip = fbGetCompositeClip(pGC);
- for (nbox = RegionNumRects(pClip),
- pbox = RegionRects(pClip);
- nbox--;
- pbox++)
- {
- int x1 = x;
- int y1 = y;
- int x2 = x + w;
- int y2 = y + h;
- char *src;
- Bool ok;
-
- if (x1 < pbox->x1)
- x1 = pbox->x1;
- if (y1 < pbox->y1)
- y1 = pbox->y1;
- if (x2 > pbox->x2)
- x2 = pbox->x2;
- if (y2 > pbox->y2)
- y2 = pbox->y2;
- if (x1 >= x2 || y1 >= y2)
- continue;
-
- src = bits + (y1 - y) * src_stride + (x1 - x) * (bpp / 8);
- ok = pExaScr->info->UploadToScreen(pPix, x1 + xoff, y1 + yoff,
- x2 - x1, y2 - y1, src, src_stride);
- /* We have to fall back completely, and ignore what has already been completed.
- * Messing with the fb layer directly like we used to is completely unacceptable.
- */
- if (!ok) {
- ret = FALSE;
- break;
- }
- }
-
- if (ret)
- exaMarkSync(pDrawable->pScreen);
-
- return ret;
-}
-
-static void
-exaPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y,
- int w, int h, int leftPad, int format, char *bits)
-{
- if (!exaDoPutImage(pDrawable, pGC, depth, x, y, w, h, format, bits,
- PixmapBytePad(w, pDrawable->depth)))
- ExaCheckPutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format,
- bits);
-}
-
-static Bool __inline
-exaCopyNtoNTwoDir (DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable,
- GCPtr pGC, BoxPtr pbox, int nbox, int dx, int dy)
-{
- ExaScreenPriv (pDstDrawable->pScreen);
- PixmapPtr pSrcPixmap, pDstPixmap;
- int src_off_x, src_off_y, dst_off_x, dst_off_y;
- int dirsetup;
-
- /* Need to get both pixmaps to call the driver routines */
- pSrcPixmap = exaGetOffscreenPixmap (pSrcDrawable, &src_off_x, &src_off_y);
- pDstPixmap = exaGetOffscreenPixmap (pDstDrawable, &dst_off_x, &dst_off_y);
- if (!pSrcPixmap || !pDstPixmap)
- return FALSE;
-
- /*
- * Now the case of a chip that only supports xdir = ydir = 1 or
- * xdir = ydir = -1, but we have xdir != ydir.
- */
- dirsetup = 0; /* No direction set up yet. */
- for (; nbox; pbox++, nbox--) {
- if (dx >= 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) {
- /* Do a xdir = ydir = -1 blit instead. */
- if (dirsetup != -1) {
- if (dirsetup != 0)
- pExaScr->info->DoneCopy(pDstPixmap);
- dirsetup = -1;
- if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap,
- pDstPixmap,
- -1, -1,
- pGC ? pGC->alu : GXcopy,
- pGC ? pGC->planemask :
- FB_ALLONES))
- return FALSE;
- }
- (*pExaScr->info->Copy)(pDstPixmap,
- src_off_x + pbox->x1 + dx,
- src_off_y + pbox->y1 + dy,
- dst_off_x + pbox->x1,
- dst_off_y + pbox->y1,
- pbox->x2 - pbox->x1,
- pbox->y2 - pbox->y1);
- } else if (dx < 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) {
- /* Do a xdir = ydir = 1 blit instead. */
- if (dirsetup != 1) {
- if (dirsetup != 0)
- pExaScr->info->DoneCopy(pDstPixmap);
- dirsetup = 1;
- if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap,
- pDstPixmap,
- 1, 1,
- pGC ? pGC->alu : GXcopy,
- pGC ? pGC->planemask :
- FB_ALLONES))
- return FALSE;
- }
- (*pExaScr->info->Copy)(pDstPixmap,
- src_off_x + pbox->x1 + dx,
- src_off_y + pbox->y1 + dy,
- dst_off_x + pbox->x1,
- dst_off_y + pbox->y1,
- pbox->x2 - pbox->x1,
- pbox->y2 - pbox->y1);
- } else if (dx >= 0) {
- /*
- * xdir = 1, ydir = -1.
- * Perform line-by-line xdir = ydir = 1 blits, going up.
- */
- int i;
- if (dirsetup != 1) {
- if (dirsetup != 0)
- pExaScr->info->DoneCopy(pDstPixmap);
- dirsetup = 1;
- if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap,
- pDstPixmap,
- 1, 1,
- pGC ? pGC->alu : GXcopy,
- pGC ? pGC->planemask :
- FB_ALLONES))
- return FALSE;
- }
- for (i = pbox->y2 - pbox->y1 - 1; i >= 0; i--)
- (*pExaScr->info->Copy)(pDstPixmap,
- src_off_x + pbox->x1 + dx,
- src_off_y + pbox->y1 + dy + i,
- dst_off_x + pbox->x1,
- dst_off_y + pbox->y1 + i,
- pbox->x2 - pbox->x1, 1);
- } else {
- /*
- * xdir = -1, ydir = 1.
- * Perform line-by-line xdir = ydir = -1 blits, going down.
- */
- int i;
- if (dirsetup != -1) {
- if (dirsetup != 0)
- pExaScr->info->DoneCopy(pDstPixmap);
- dirsetup = -1;
- if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap,
- pDstPixmap,
- -1, -1,
- pGC ? pGC->alu : GXcopy,
- pGC ? pGC->planemask :
- FB_ALLONES))
- return FALSE;
- }
- for (i = 0; i < pbox->y2 - pbox->y1; i++)
- (*pExaScr->info->Copy)(pDstPixmap,
- src_off_x + pbox->x1 + dx,
- src_off_y + pbox->y1 + dy + i,
- dst_off_x + pbox->x1,
- dst_off_y + pbox->y1 + i,
- pbox->x2 - pbox->x1, 1);
- }
- }
- if (dirsetup != 0)
- pExaScr->info->DoneCopy(pDstPixmap);
- exaMarkSync(pDstDrawable->pScreen);
- return TRUE;
-}
-
-Bool
-exaHWCopyNtoN (DrawablePtr pSrcDrawable,
- DrawablePtr pDstDrawable,
- GCPtr pGC,
- BoxPtr pbox,
- int nbox,
- int dx,
- int dy,
- Bool reverse,
- Bool upsidedown)
-{
- ExaScreenPriv (pDstDrawable->pScreen);
- PixmapPtr pSrcPixmap, pDstPixmap;
- ExaPixmapPrivPtr pSrcExaPixmap, pDstExaPixmap;
- int src_off_x, src_off_y;
- int dst_off_x, dst_off_y;
- RegionPtr srcregion = NULL, dstregion = NULL;
- xRectangle *rects;
- Bool ret = TRUE;
-
- /* avoid doing copy operations if no boxes */
- if (nbox == 0)
- return TRUE;
-
- pSrcPixmap = exaGetDrawablePixmap (pSrcDrawable);
- pDstPixmap = exaGetDrawablePixmap (pDstDrawable);
-
- exaGetDrawableDeltas (pSrcDrawable, pSrcPixmap, &src_off_x, &src_off_y);
- exaGetDrawableDeltas (pDstDrawable, pDstPixmap, &dst_off_x, &dst_off_y);
-
- rects = malloc(nbox * sizeof(xRectangle));
-
- if (rects) {
- int i;
- int ordering;
-
- for (i = 0; i < nbox; i++) {
- rects[i].x = pbox[i].x1 + dx + src_off_x;
- rects[i].y = pbox[i].y1 + dy + src_off_y;
- rects[i].width = pbox[i].x2 - pbox[i].x1;
- rects[i].height = pbox[i].y2 - pbox[i].y1;
- }
-
- /* This must match the RegionCopy() logic for reversing rect order */
- if (nbox == 1 || (dx > 0 && dy > 0) ||
- (pDstDrawable != pSrcDrawable &&
- (pDstDrawable->type != DRAWABLE_WINDOW ||
- pSrcDrawable->type != DRAWABLE_WINDOW)))
- ordering = CT_YXBANDED;
- else
- ordering = CT_UNSORTED;
-
- srcregion = RegionFromRects(nbox, rects, ordering);
- free(rects);
-
- if (!pGC || !exaGCReadsDestination(pDstDrawable, pGC->planemask,
- pGC->fillStyle, pGC->alu,
- pGC->clientClipType)) {
- dstregion = RegionCreate(NullBox, 0);
- RegionCopy(dstregion, srcregion);
- RegionTranslate(dstregion, dst_off_x - dx - src_off_x,
- dst_off_y - dy - src_off_y);
- }
- }
-
-
- pSrcExaPixmap = ExaGetPixmapPriv (pSrcPixmap);
- pDstExaPixmap = ExaGetPixmapPriv (pDstPixmap);
-
- /* Check whether the accelerator can use this pixmap.
- * If the pitch of the pixmaps is out of range, there's nothing
- * we can do but fall back to software rendering.
- */
- if (pSrcExaPixmap->accel_blocked & EXA_RANGE_PITCH ||
- pDstExaPixmap->accel_blocked & EXA_RANGE_PITCH)
- goto fallback;
-
- /* If the width or the height of either of the pixmaps
- * is out of range, check whether the boxes are actually out of the
- * addressable range as well. If they aren't, we can still do
- * the copying in hardware.
- */
- if (pSrcExaPixmap->accel_blocked || pDstExaPixmap->accel_blocked) {
- int i;
-
- for (i = 0; i < nbox; i++) {
- /* src */
- if ((pbox[i].x2 + dx + src_off_x) >= pExaScr->info->maxX ||
- (pbox[i].y2 + dy + src_off_y) >= pExaScr->info->maxY)
- goto fallback;
-
- /* dst */
- if ((pbox[i].x2 + dst_off_x) >= pExaScr->info->maxX ||
- (pbox[i].y2 + dst_off_y) >= pExaScr->info->maxY)
- goto fallback;
- }
- }
-
- if (pExaScr->do_migration) {
- ExaMigrationRec pixmaps[2];
-
- pixmaps[0].as_dst = TRUE;
- pixmaps[0].as_src = FALSE;
- pixmaps[0].pPix = pDstPixmap;
- pixmaps[0].pReg = dstregion;
- pixmaps[1].as_dst = FALSE;
- pixmaps[1].as_src = TRUE;
- pixmaps[1].pPix = pSrcPixmap;
- pixmaps[1].pReg = srcregion;
-
- exaDoMigration (pixmaps, 2, TRUE);
- }
-
- /* Mixed directions must be handled specially if the card is lame */
- if ((pExaScr->info->flags & EXA_TWO_BITBLT_DIRECTIONS) &&
- reverse != upsidedown) {
- if (exaCopyNtoNTwoDir(pSrcDrawable, pDstDrawable, pGC, pbox, nbox,
- dx, dy))
- goto out;
- goto fallback;
- }
-
- if (exaPixmapHasGpuCopy(pDstPixmap)) {
- /* Normal blitting. */
- if (exaPixmapHasGpuCopy(pSrcPixmap)) {
- if (!(*pExaScr->info->PrepareCopy) (pSrcPixmap, pDstPixmap, reverse ? -1 : 1,
- upsidedown ? -1 : 1,
- pGC ? pGC->alu : GXcopy,
- pGC ? pGC->planemask : FB_ALLONES)) {
- goto fallback;
- }
-
- while (nbox--)
- {
- (*pExaScr->info->Copy) (pDstPixmap,
- pbox->x1 + dx + src_off_x,
- pbox->y1 + dy + src_off_y,
- pbox->x1 + dst_off_x, pbox->y1 + dst_off_y,
- pbox->x2 - pbox->x1, pbox->y2 - pbox->y1);
- pbox++;
- }
-
- (*pExaScr->info->DoneCopy) (pDstPixmap);
- exaMarkSync (pDstDrawable->pScreen);
- /* UTS: mainly for SHM PutImage's secondary path.
- *
- * Only taking this path for directly accessible pixmaps.
- */
- } else if (!pDstExaPixmap->pDamage && pSrcExaPixmap->sys_ptr) {
- int bpp = pSrcDrawable->bitsPerPixel;
- int src_stride = exaGetPixmapPitch(pSrcPixmap);
- CARD8 *src = NULL;
-
- if (!pExaScr->info->UploadToScreen)
- goto fallback;
-
- if (pSrcDrawable->bitsPerPixel != pDstDrawable->bitsPerPixel)
- goto fallback;
-
- if (pSrcDrawable->bitsPerPixel < 8)
- goto fallback;
-
- if (pGC && !(pGC->alu == GXcopy && EXA_PM_IS_SOLID(pSrcDrawable, pGC->planemask)))
- goto fallback;
-
- while (nbox--)
- {
- src = pSrcExaPixmap->sys_ptr + (pbox->y1 + dy + src_off_y) * src_stride + (pbox->x1 + dx + src_off_x) * (bpp / 8);
- if (!pExaScr->info->UploadToScreen(pDstPixmap, pbox->x1 + dst_off_x,
- pbox->y1 + dst_off_y, pbox->x2 - pbox->x1, pbox->y2 - pbox->y1,
- (char *) src, src_stride))
- goto fallback;
-
- pbox++;
- }
- } else
- goto fallback;
- } else
- goto fallback;
-
- goto out;
-
-fallback:
- ret = FALSE;
-
-out:
- if (dstregion) {
- RegionUninit(dstregion);
- RegionDestroy(dstregion);
- }
- if (srcregion) {
- RegionUninit(srcregion);
- RegionDestroy(srcregion);
- }
-
- return ret;
-}
-
-void
-exaCopyNtoN (DrawablePtr pSrcDrawable,
- DrawablePtr pDstDrawable,
- GCPtr pGC,
- BoxPtr pbox,
- int nbox,
- int dx,
- int dy,
- Bool reverse,
- Bool upsidedown,
- Pixel bitplane,
- void *closure)
-{
- ExaScreenPriv(pDstDrawable->pScreen);
-
- if (pExaScr->fallback_counter ||
- (pExaScr->fallback_flags & EXA_FALLBACK_COPYWINDOW))
- return;
-
- if (exaHWCopyNtoN(pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy, reverse, upsidedown))
- return;
-
- /* This is a CopyWindow, it's cleaner to fallback at the original call. */
- if (pExaScr->fallback_flags & EXA_ACCEL_COPYWINDOW) {
- pExaScr->fallback_flags |= EXA_FALLBACK_COPYWINDOW;
- return;
- }
-
- /* fallback */
- ExaCheckCopyNtoN(pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy, reverse, upsidedown, bitplane, closure);
-}
-
-RegionPtr
-exaCopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC,
- int srcx, int srcy, int width, int height, int dstx, int dsty)
-{
- ExaScreenPriv (pDstDrawable->pScreen);
-
- if (pExaScr->fallback_counter || pExaScr->swappedOut) {
- return ExaCheckCopyArea(pSrcDrawable, pDstDrawable, pGC,
- srcx, srcy, width, height, dstx, dsty);
- }
-
- return miDoCopy (pSrcDrawable, pDstDrawable, pGC,
- srcx, srcy, width, height,
- dstx, dsty, exaCopyNtoN, 0, NULL);
-}
-
-static void
-exaPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
- DDXPointPtr ppt)
-{
- ExaScreenPriv (pDrawable->pScreen);
- int i;
- xRectangle *prect;
-
- /* If we can't reuse the current GC as is, don't bother accelerating the
- * points.
- */
- if (pExaScr->fallback_counter || pGC->fillStyle != FillSolid) {
- ExaCheckPolyPoint(pDrawable, pGC, mode, npt, ppt);
- return;
- }
-
- prect = malloc(sizeof(xRectangle) * npt);
- for (i = 0; i < npt; i++) {
- prect[i].x = ppt[i].x;
- prect[i].y = ppt[i].y;
- if (i > 0 && mode == CoordModePrevious) {
- prect[i].x += prect[i - 1].x;
- prect[i].y += prect[i - 1].y;
- }
- prect[i].width = 1;
- prect[i].height = 1;
- }
- pGC->ops->PolyFillRect(pDrawable, pGC, npt, prect);
- free(prect);
-}
-
-/**
- * exaPolylines() checks if it can accelerate the lines as a group of
- * horizontal or vertical lines (rectangles), and uses existing rectangle fill
- * acceleration if so.
- */
-static void
-exaPolylines(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
- DDXPointPtr ppt)
-{
- ExaScreenPriv (pDrawable->pScreen);
- xRectangle *prect;
- int x1, x2, y1, y2;
- int i;
-
- if (pExaScr->fallback_counter) {
- ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt);
- return;
- }
-
- /* Don't try to do wide lines or non-solid fill style. */
- if (pGC->lineWidth != 0 || pGC->lineStyle != LineSolid ||
- pGC->fillStyle != FillSolid) {
- ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt);
- return;
- }
-
- prect = malloc(sizeof(xRectangle) * (npt - 1));
- x1 = ppt[0].x;
- y1 = ppt[0].y;
- /* If we have any non-horizontal/vertical, fall back. */
- for (i = 0; i < npt - 1; i++) {
- if (mode == CoordModePrevious) {
- x2 = x1 + ppt[i + 1].x;
- y2 = y1 + ppt[i + 1].y;
- } else {
- x2 = ppt[i + 1].x;
- y2 = ppt[i + 1].y;
- }
-
- if (x1 != x2 && y1 != y2) {
- free(prect);
- ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt);
- return;
- }
-
- if (x1 < x2) {
- prect[i].x = x1;
- prect[i].width = x2 - x1 + 1;
- } else {
- prect[i].x = x2;
- prect[i].width = x1 - x2 + 1;
- }
- if (y1 < y2) {
- prect[i].y = y1;
- prect[i].height = y2 - y1 + 1;
- } else {
- prect[i].y = y2;
- prect[i].height = y1 - y2 + 1;
- }
-
- x1 = x2;
- y1 = y2;
- }
- pGC->ops->PolyFillRect(pDrawable, pGC, npt - 1, prect);
- free(prect);
-}
-
-/**
- * exaPolySegment() checks if it can accelerate the lines as a group of
- * horizontal or vertical lines (rectangles), and uses existing rectangle fill
- * acceleration if so.
- */
-static void
-exaPolySegment (DrawablePtr pDrawable, GCPtr pGC, int nseg,
- xSegment *pSeg)
-{
- ExaScreenPriv (pDrawable->pScreen);
- xRectangle *prect;
- int i;
-
- /* Don't try to do wide lines or non-solid fill style. */
- if (pExaScr->fallback_counter || pGC->lineWidth != 0 ||
- pGC->lineStyle != LineSolid || pGC->fillStyle != FillSolid)
- {
- ExaCheckPolySegment(pDrawable, pGC, nseg, pSeg);
- return;
- }
-
- /* If we have any non-horizontal/vertical, fall back. */
- for (i = 0; i < nseg; i++) {
- if (pSeg[i].x1 != pSeg[i].x2 && pSeg[i].y1 != pSeg[i].y2) {
- ExaCheckPolySegment(pDrawable, pGC, nseg, pSeg);
- return;
- }
- }
-
- prect = malloc(sizeof(xRectangle) * nseg);
- for (i = 0; i < nseg; i++) {
- if (pSeg[i].x1 < pSeg[i].x2) {
- prect[i].x = pSeg[i].x1;
- prect[i].width = pSeg[i].x2 - pSeg[i].x1 + 1;
- } else {
- prect[i].x = pSeg[i].x2;
- prect[i].width = pSeg[i].x1 - pSeg[i].x2 + 1;
- }
- if (pSeg[i].y1 < pSeg[i].y2) {
- prect[i].y = pSeg[i].y1;
- prect[i].height = pSeg[i].y2 - pSeg[i].y1 + 1;
- } else {
- prect[i].y = pSeg[i].y2;
- prect[i].height = pSeg[i].y1 - pSeg[i].y2 + 1;
- }
-
- /* don't paint last pixel */
- if (pGC->capStyle == CapNotLast) {
- if (prect[i].width == 1)
- prect[i].height--;
- else
- prect[i].width--;
- }
- }
- pGC->ops->PolyFillRect(pDrawable, pGC, nseg, prect);
- free(prect);
-}
-
-static Bool exaFillRegionSolid (DrawablePtr pDrawable, RegionPtr pRegion,
- Pixel pixel, CARD32 planemask, CARD32 alu,
- unsigned int clientClipType);
-
-static void
-exaPolyFillRect(DrawablePtr pDrawable,
- GCPtr pGC,
- int nrect,
- xRectangle *prect)
-{
- ExaScreenPriv (pDrawable->pScreen);
- RegionPtr pClip = fbGetCompositeClip(pGC);
- PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable);
- ExaPixmapPriv (pPixmap);
- register BoxPtr pbox;
- BoxPtr pextent;
- int extentX1, extentX2, extentY1, extentY2;
- int fullX1, fullX2, fullY1, fullY2;
- int partX1, partX2, partY1, partY2;
- int xoff, yoff;
- int xorg, yorg;
- int n;
- RegionPtr pReg = RegionFromRects(nrect, prect, CT_UNSORTED);
-
- /* Compute intersection of rects and clip region */
- RegionTranslate(pReg, pDrawable->x, pDrawable->y);
- RegionIntersect(pReg, pClip, pReg);
-
- if (!RegionNumRects(pReg)) {
- goto out;
- }
-
- exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff);
-
- if (pExaScr->fallback_counter || pExaScr->swappedOut ||
- pExaPixmap->accel_blocked)
- {
- goto fallback;
- }
-
- /* For ROPs where overlaps don't matter, convert rectangles to region and
- * call exaFillRegion{Solid,Tiled}.
- */
- if ((pGC->fillStyle == FillSolid || pGC->fillStyle == FillTiled) &&
- (nrect == 1 || pGC->alu == GXcopy || pGC->alu == GXclear ||
- pGC->alu == GXnoop || pGC->alu == GXcopyInverted ||
- pGC->alu == GXset)) {
- if (((pGC->fillStyle == FillSolid || pGC->tileIsPixel) &&
- exaFillRegionSolid(pDrawable, pReg, pGC->fillStyle == FillSolid ?
- pGC->fgPixel : pGC->tile.pixel, pGC->planemask,
- pGC->alu, pGC->clientClipType)) ||
- (pGC->fillStyle == FillTiled && !pGC->tileIsPixel &&
- exaFillRegionTiled(pDrawable, pReg, pGC->tile.pixmap, &pGC->patOrg,
- pGC->planemask, pGC->alu,
- pGC->clientClipType))) {
- goto out;
- }
- }
-
- if (pGC->fillStyle != FillSolid &&
- !(pGC->tileIsPixel && pGC->fillStyle == FillTiled))
- {
- goto fallback;
- }
-
- if (pExaScr->do_migration) {
- ExaMigrationRec pixmaps[1];
-
- pixmaps[0].as_dst = TRUE;
- pixmaps[0].as_src = FALSE;
- pixmaps[0].pPix = pPixmap;
- pixmaps[0].pReg = NULL;
-
- exaDoMigration (pixmaps, 1, TRUE);
- }
-
- if (!exaPixmapHasGpuCopy (pPixmap) ||
- !(*pExaScr->info->PrepareSolid) (pPixmap,
- pGC->alu,
- pGC->planemask,
- pGC->fgPixel))
- {
-fallback:
- ExaCheckPolyFillRect (pDrawable, pGC, nrect, prect);
- goto out;
- }
-
- xorg = pDrawable->x;
- yorg = pDrawable->y;
-
- pextent = RegionExtents(pClip);
- extentX1 = pextent->x1;
- extentY1 = pextent->y1;
- extentX2 = pextent->x2;
- extentY2 = pextent->y2;
- while (nrect--)
- {
- fullX1 = prect->x + xorg;
- fullY1 = prect->y + yorg;
- fullX2 = fullX1 + (int) prect->width;
- fullY2 = fullY1 + (int) prect->height;
- prect++;
-
- if (fullX1 < extentX1)
- fullX1 = extentX1;
-
- if (fullY1 < extentY1)
- fullY1 = extentY1;
-
- if (fullX2 > extentX2)
- fullX2 = extentX2;
-
- if (fullY2 > extentY2)
- fullY2 = extentY2;
-
- if ((fullX1 >= fullX2) || (fullY1 >= fullY2))
- continue;
- n = RegionNumRects (pClip);
- if (n == 1)
- {
- (*pExaScr->info->Solid) (pPixmap,
- fullX1 + xoff, fullY1 + yoff,
- fullX2 + xoff, fullY2 + yoff);
- }
- else
- {
- pbox = RegionRects(pClip);
- /*
- * clip the rectangle to each box in the clip region
- * this is logically equivalent to calling Intersect(),
- * but rectangles may overlap each other here.
- */
- while(n--)
- {
- partX1 = pbox->x1;
- if (partX1 < fullX1)
- partX1 = fullX1;
- partY1 = pbox->y1;
- if (partY1 < fullY1)
- partY1 = fullY1;
- partX2 = pbox->x2;
- if (partX2 > fullX2)
- partX2 = fullX2;
- partY2 = pbox->y2;
- if (partY2 > fullY2)
- partY2 = fullY2;
-
- pbox++;
-
- if (partX1 < partX2 && partY1 < partY2) {
- (*pExaScr->info->Solid) (pPixmap,
- partX1 + xoff, partY1 + yoff,
- partX2 + xoff, partY2 + yoff);
- }
- }
- }
- }
- (*pExaScr->info->DoneSolid) (pPixmap);
- exaMarkSync(pDrawable->pScreen);
-
-out:
- RegionUninit(pReg);
- RegionDestroy(pReg);
-}
-
-const GCOps exaOps = {
- exaFillSpans,
- ExaCheckSetSpans,
- exaPutImage,
- exaCopyArea,
- ExaCheckCopyPlane,
- exaPolyPoint,
- exaPolylines,
- exaPolySegment,
- miPolyRectangle,
- ExaCheckPolyArc,
- miFillPolygon,
- exaPolyFillRect,
- miPolyFillArc,
- miPolyText8,
- miPolyText16,
- miImageText8,
- miImageText16,
- ExaCheckImageGlyphBlt,
- ExaCheckPolyGlyphBlt,
- ExaCheckPushPixels,
-};
-
-void
-exaCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
-{
- RegionRec rgnDst;
- int dx, dy;
- PixmapPtr pPixmap = (*pWin->drawable.pScreen->GetWindowPixmap) (pWin);
- ExaScreenPriv(pWin->drawable.pScreen);
-
- dx = ptOldOrg.x - pWin->drawable.x;
- dy = ptOldOrg.y - pWin->drawable.y;
- RegionTranslate(prgnSrc, -dx, -dy);
-
- RegionInit(&rgnDst, NullBox, 0);
-
- RegionIntersect(&rgnDst, &pWin->borderClip, prgnSrc);
-#ifdef COMPOSITE
- if (pPixmap->screen_x || pPixmap->screen_y)
- RegionTranslate(&rgnDst,
- -pPixmap->screen_x, -pPixmap->screen_y);
-#endif
-
- if (pExaScr->fallback_counter) {
- pExaScr->fallback_flags |= EXA_FALLBACK_COPYWINDOW;
- goto fallback;
- }
-
- pExaScr->fallback_flags |= EXA_ACCEL_COPYWINDOW;
- miCopyRegion (&pPixmap->drawable, &pPixmap->drawable,
- NULL,
- &rgnDst, dx, dy, exaCopyNtoN, 0, NULL);
- pExaScr->fallback_flags &= ~EXA_ACCEL_COPYWINDOW;
-
-fallback:
- RegionUninit(&rgnDst);
-
- if (pExaScr->fallback_flags & EXA_FALLBACK_COPYWINDOW) {
- pExaScr->fallback_flags &= ~EXA_FALLBACK_COPYWINDOW;
- RegionTranslate(prgnSrc, dx, dy);
- ExaCheckCopyWindow(pWin, ptOldOrg, prgnSrc);
- }
-}
-
-static Bool
-exaFillRegionSolid (DrawablePtr pDrawable, RegionPtr pRegion, Pixel pixel,
- CARD32 planemask, CARD32 alu, unsigned int clientClipType)
-{
- ExaScreenPriv(pDrawable->pScreen);
- PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable);
- ExaPixmapPriv (pPixmap);
- int xoff, yoff;
- Bool ret = FALSE;
-
- exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff);
- RegionTranslate(pRegion, xoff, yoff);
-
- if (pExaScr->fallback_counter || pExaPixmap->accel_blocked)
- goto out;
-
- if (pExaScr->do_migration) {
- ExaMigrationRec pixmaps[1];
-
- pixmaps[0].as_dst = TRUE;
- pixmaps[0].as_src = FALSE;
- pixmaps[0].pPix = pPixmap;
- pixmaps[0].pReg = exaGCReadsDestination(pDrawable, planemask, FillSolid,
- alu, clientClipType) ? NULL : pRegion;
-
- exaDoMigration (pixmaps, 1, TRUE);
- }
-
- if (exaPixmapHasGpuCopy (pPixmap) &&
- (*pExaScr->info->PrepareSolid) (pPixmap, alu, planemask, pixel))
- {
- int nbox;
- BoxPtr pBox;
-
- nbox = RegionNumRects (pRegion);
- pBox = RegionRects (pRegion);
-
- while (nbox--)
- {
- (*pExaScr->info->Solid) (pPixmap, pBox->x1, pBox->y1, pBox->x2,
- pBox->y2);
- pBox++;
- }
- (*pExaScr->info->DoneSolid) (pPixmap);
- exaMarkSync(pDrawable->pScreen);
-
- if (pExaPixmap->pDamage &&
- pExaPixmap->sys_ptr && pDrawable->type == DRAWABLE_PIXMAP &&
- pDrawable->width == 1 && pDrawable->height == 1 &&
- pDrawable->bitsPerPixel != 24) {
- ExaPixmapPriv(pPixmap);
- RegionPtr pending_damage = DamagePendingRegion(pExaPixmap->pDamage);
-
- switch (pDrawable->bitsPerPixel) {
- case 32:
- *(CARD32*)pExaPixmap->sys_ptr = pixel;
- break;
- case 16:
- *(CARD16*)pExaPixmap->sys_ptr = pixel;
- break;
- case 8:
- case 4:
- case 1:
- *(CARD8*)pExaPixmap->sys_ptr = pixel;
- }
-
- RegionUnion(&pExaPixmap->validSys, &pExaPixmap->validSys,
- pRegion);
- RegionUnion(&pExaPixmap->validFB, &pExaPixmap->validFB,
- pRegion);
- RegionSubtract(pending_damage, pending_damage, pRegion);
- }
-
- ret = TRUE;
- }
-
-out:
- RegionTranslate(pRegion, -xoff, -yoff);
-
- return ret;
-}
-
-/* Try to do an accelerated tile of the pTile into pRegion of pDrawable.
- * Based on fbFillRegionTiled(), fbTile().
- */
-Bool
-exaFillRegionTiled (DrawablePtr pDrawable, RegionPtr pRegion, PixmapPtr pTile,
- DDXPointPtr pPatOrg, CARD32 planemask, CARD32 alu,
- unsigned int clientClipType)
-{
- ExaScreenPriv(pDrawable->pScreen);
- PixmapPtr pPixmap;
- ExaPixmapPrivPtr pExaPixmap;
- ExaPixmapPrivPtr pTileExaPixmap = ExaGetPixmapPriv(pTile);
- int xoff, yoff;
- int tileWidth, tileHeight;
- int nbox = RegionNumRects (pRegion);
- BoxPtr pBox = RegionRects (pRegion);
- Bool ret = FALSE;
- int i;
-
- tileWidth = pTile->drawable.width;
- tileHeight = pTile->drawable.height;
-
- /* If we're filling with a solid color, grab it out and go to
- * FillRegionSolid, saving numerous copies.
- */
- if (tileWidth == 1 && tileHeight == 1)
- return exaFillRegionSolid(pDrawable, pRegion,
- exaGetPixmapFirstPixel (pTile), planemask,
- alu, clientClipType);
-
- pPixmap = exaGetDrawablePixmap (pDrawable);
- pExaPixmap = ExaGetPixmapPriv (pPixmap);
-
- if (pExaScr->fallback_counter || pExaPixmap->accel_blocked ||
- pTileExaPixmap->accel_blocked)
- return FALSE;
-
- if (pExaScr->do_migration) {
- ExaMigrationRec pixmaps[2];
-
- pixmaps[0].as_dst = TRUE;
- pixmaps[0].as_src = FALSE;
- pixmaps[0].pPix = pPixmap;
- pixmaps[0].pReg = exaGCReadsDestination(pDrawable, planemask, FillTiled,
- alu, clientClipType) ? NULL : pRegion;
- pixmaps[1].as_dst = FALSE;
- pixmaps[1].as_src = TRUE;
- pixmaps[1].pPix = pTile;
- pixmaps[1].pReg = NULL;
-
- exaDoMigration (pixmaps, 2, TRUE);
- }
-
- pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff);
-
- if (!pPixmap || !exaPixmapHasGpuCopy(pTile))
- return FALSE;
-
- if ((*pExaScr->info->PrepareCopy) (pTile, pPixmap, 1, 1, alu, planemask))
- {
- if (xoff || yoff)
- RegionTranslate(pRegion, xoff, yoff);
-
- for (i = 0; i < nbox; i++)
- {
- int height = pBox[i].y2 - pBox[i].y1;
- int dstY = pBox[i].y1;
- int tileY;
-
- if (alu == GXcopy)
- height = min(height, tileHeight);
-
- modulus(dstY - yoff - pDrawable->y - pPatOrg->y, tileHeight, tileY);
-
- while (height > 0) {
- int width = pBox[i].x2 - pBox[i].x1;
- int dstX = pBox[i].x1;
- int tileX;
- int h = tileHeight - tileY;
-
- if (alu == GXcopy)
- width = min(width, tileWidth);
-
- if (h > height)
- h = height;
- height -= h;
-
- modulus(dstX - xoff - pDrawable->x - pPatOrg->x, tileWidth,
- tileX);
-
- while (width > 0) {
- int w = tileWidth - tileX;
- if (w > width)
- w = width;
- width -= w;
-
- (*pExaScr->info->Copy) (pPixmap, tileX, tileY, dstX, dstY,
- w, h);
- dstX += w;
- tileX = 0;
- }
- dstY += h;
- tileY = 0;
- }
- }
- (*pExaScr->info->DoneCopy) (pPixmap);
-
- /* With GXcopy, we only need to do the basic algorithm up to the tile
- * size; then, we can just keep doubling the destination in each
- * direction until it fills the box. This way, the number of copy
- * operations is O(log(rx)) + O(log(ry)) instead of O(rx * ry), where
- * rx/ry is the ratio between box and tile width/height. This can make
- * a big difference if each driver copy incurs a significant constant
- * overhead.
- */
- if (alu != GXcopy)
- ret = TRUE;
- else {
- Bool more_copy = FALSE;
-
- for (i = 0; i < nbox; i++) {
- int dstX = pBox[i].x1 + tileWidth;
- int dstY = pBox[i].y1 + tileHeight;
-
- if ((dstX < pBox[i].x2) || (dstY < pBox[i].y2)) {
- more_copy = TRUE;
- break;
- }
- }
-
- if (more_copy == FALSE)
- ret = TRUE;
-
- if (more_copy && (*pExaScr->info->PrepareCopy) (pPixmap, pPixmap,
- 1, 1, alu, planemask)) {
- for (i = 0; i < nbox; i++)
- {
- int dstX = pBox[i].x1 + tileWidth;
- int dstY = pBox[i].y1 + tileHeight;
- int width = min(pBox[i].x2 - dstX, tileWidth);
- int height = min(pBox[i].y2 - pBox[i].y1, tileHeight);
-
- while (dstX < pBox[i].x2) {
- (*pExaScr->info->Copy) (pPixmap, pBox[i].x1, pBox[i].y1,
- dstX, pBox[i].y1, width, height);
- dstX += width;
- width = min(pBox[i].x2 - dstX, width * 2);
- }
-
- width = pBox[i].x2 - pBox[i].x1;
- height = min(pBox[i].y2 - dstY, tileHeight);
-
- while (dstY < pBox[i].y2) {
- (*pExaScr->info->Copy) (pPixmap, pBox[i].x1, pBox[i].y1,
- pBox[i].x1, dstY, width, height);
- dstY += height;
- height = min(pBox[i].y2 - dstY, height * 2);
- }
- }
-
- (*pExaScr->info->DoneCopy) (pPixmap);
-
- ret = TRUE;
- }
- }
-
- exaMarkSync(pDrawable->pScreen);
-
- if (xoff || yoff)
- RegionTranslate(pRegion, -xoff, -yoff);
- }
-
- return ret;
-}
-
-
-/**
- * Accelerates GetImage for solid ZPixmap downloads from framebuffer memory.
- *
- * This is probably the only case we actually care about. The rest fall through
- * to migration and fbGetImage, which hopefully will result in migration pushing
- * the pixmap out of framebuffer.
- */
-void
-exaGetImage (DrawablePtr pDrawable, int x, int y, int w, int h,
- unsigned int format, unsigned long planeMask, char *d)
-{
- ExaScreenPriv (pDrawable->pScreen);
- PixmapPtr pPix = exaGetDrawablePixmap (pDrawable);
- ExaPixmapPriv(pPix);
- int xoff, yoff;
- Bool ok;
-
- if (pExaScr->fallback_counter || pExaScr->swappedOut)
- goto fallback;
-
- /* If there's a system copy, we want to save the result there */
- if (pExaPixmap->pDamage)
- goto fallback;
-
- pPix = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff);
-
- if (pPix == NULL || pExaScr->info->DownloadFromScreen == NULL)
- goto fallback;
-
- /* Only cover the ZPixmap, solid copy case. */
- if (format != ZPixmap || !EXA_PM_IS_SOLID(pDrawable, planeMask))
- goto fallback;
-
- /* Only try to handle the 8bpp and up cases, since we don't want to think
- * about <8bpp.
- */
- if (pDrawable->bitsPerPixel < 8)
- goto fallback;
-
- ok = pExaScr->info->DownloadFromScreen(pPix, pDrawable->x + x + xoff,
- pDrawable->y + y + yoff, w, h, d,
- PixmapBytePad(w, pDrawable->depth));
- if (ok) {
- exaWaitSync(pDrawable->pScreen);
- return;
- }
-
-fallback:
- ExaCheckGetImage(pDrawable, x, y, w, h, format, planeMask, d);
-}
+/*
+ * 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.
+ *
+ * Authors:
+ * Eric Anholt <eric@anholt.net>
+ * Michel Dänzer <michel@tungstengraphics.com>
+ *
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+#include "exa_priv.h"
+#include <X11/fonts/fontstruct.h>
+#include "dixfontstr.h"
+#include "exa.h"
+
+static void
+exaFillSpans(DrawablePtr pDrawable, GCPtr pGC, int n,
+ DDXPointPtr ppt, int *pwidth, int fSorted)
+{
+ ScreenPtr pScreen = pDrawable->pScreen;
+ ExaScreenPriv (pScreen);
+ RegionPtr pClip = fbGetCompositeClip(pGC);
+ PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable);
+ ExaPixmapPriv (pPixmap);
+ BoxPtr pextent, pbox;
+ int nbox;
+ int extentX1, extentX2, extentY1, extentY2;
+ int fullX1, fullX2, fullY1;
+ int partX1, partX2;
+ int off_x, off_y;
+
+ if (pExaScr->fallback_counter ||
+ pExaScr->swappedOut ||
+ pGC->fillStyle != FillSolid ||
+ pExaPixmap->accel_blocked)
+ {
+ ExaCheckFillSpans (pDrawable, pGC, n, ppt, pwidth, fSorted);
+ return;
+ }
+
+ if (pExaScr->do_migration) {
+ ExaMigrationRec pixmaps[1];
+
+ pixmaps[0].as_dst = TRUE;
+ pixmaps[0].as_src = FALSE;
+ pixmaps[0].pPix = pPixmap;
+ pixmaps[0].pReg = NULL;
+
+ exaDoMigration (pixmaps, 1, TRUE);
+ }
+
+ if (!(pPixmap = exaGetOffscreenPixmap (pDrawable, &off_x, &off_y)) ||
+ !(*pExaScr->info->PrepareSolid) (pPixmap,
+ pGC->alu,
+ pGC->planemask,
+ pGC->fgPixel))
+ {
+ ExaCheckFillSpans (pDrawable, pGC, n, ppt, pwidth, fSorted);
+ return;
+ }
+
+ pextent = RegionExtents(pClip);
+ extentX1 = pextent->x1;
+ extentY1 = pextent->y1;
+ extentX2 = pextent->x2;
+ extentY2 = pextent->y2;
+ while (n--)
+ {
+ fullX1 = ppt->x;
+ fullY1 = ppt->y;
+ fullX2 = fullX1 + (int) *pwidth;
+ ppt++;
+ pwidth++;
+
+ if (fullY1 < extentY1 || extentY2 <= fullY1)
+ continue;
+
+ if (fullX1 < extentX1)
+ fullX1 = extentX1;
+
+ if (fullX2 > extentX2)
+ fullX2 = extentX2;
+
+ if (fullX1 >= fullX2)
+ continue;
+
+ nbox = RegionNumRects (pClip);
+ if (nbox == 1)
+ {
+ (*pExaScr->info->Solid) (pPixmap,
+ fullX1 + off_x, fullY1 + off_y,
+ fullX2 + off_x, fullY1 + 1 + off_y);
+ }
+ else
+ {
+ pbox = RegionRects(pClip);
+ while(nbox--)
+ {
+ if (pbox->y1 <= fullY1 && fullY1 < pbox->y2)
+ {
+ partX1 = pbox->x1;
+ if (partX1 < fullX1)
+ partX1 = fullX1;
+ partX2 = pbox->x2;
+ if (partX2 > fullX2)
+ partX2 = fullX2;
+ if (partX2 > partX1) {
+ (*pExaScr->info->Solid) (pPixmap,
+ partX1 + off_x, fullY1 + off_y,
+ partX2 + off_x, fullY1 + 1 + off_y);
+ }
+ }
+ pbox++;
+ }
+ }
+ }
+ (*pExaScr->info->DoneSolid) (pPixmap);
+ exaMarkSync(pScreen);
+}
+
+static Bool
+exaDoPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y,
+ int w, int h, int format, char *bits, int src_stride)
+{
+ ExaScreenPriv (pDrawable->pScreen);
+ PixmapPtr pPix = exaGetDrawablePixmap (pDrawable);
+ ExaPixmapPriv(pPix);
+ RegionPtr pClip;
+ BoxPtr pbox;
+ int nbox;
+ int xoff, yoff;
+ int bpp = pDrawable->bitsPerPixel;
+ Bool ret = TRUE;
+
+ if (pExaScr->fallback_counter || pExaPixmap->accel_blocked || !pExaScr->info->UploadToScreen)
+ return FALSE;
+
+ /* If there's a system copy, we want to save the result there */
+ if (pExaPixmap->pDamage)
+ return FALSE;
+
+ /* Don't bother with under 8bpp, XYPixmaps. */
+ if (format != ZPixmap || bpp < 8)
+ return FALSE;
+
+ /* Only accelerate copies: no rop or planemask. */
+ if (!EXA_PM_IS_SOLID(pDrawable, pGC->planemask) || pGC->alu != GXcopy)
+ return FALSE;
+
+ if (pExaScr->swappedOut)
+ return FALSE;
+
+ if (pExaScr->do_migration) {
+ ExaMigrationRec pixmaps[1];
+
+ pixmaps[0].as_dst = TRUE;
+ pixmaps[0].as_src = FALSE;
+ pixmaps[0].pPix = pPix;
+ pixmaps[0].pReg = DamagePendingRegion(pExaPixmap->pDamage);
+
+ exaDoMigration (pixmaps, 1, TRUE);
+ }
+
+ pPix = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff);
+
+ if (!pPix)
+ return FALSE;
+
+ x += pDrawable->x;
+ y += pDrawable->y;
+
+ pClip = fbGetCompositeClip(pGC);
+ for (nbox = RegionNumRects(pClip),
+ pbox = RegionRects(pClip);
+ nbox--;
+ pbox++)
+ {
+ int x1 = x;
+ int y1 = y;
+ int x2 = x + w;
+ int y2 = y + h;
+ char *src;
+ Bool ok;
+
+ if (x1 < pbox->x1)
+ x1 = pbox->x1;
+ if (y1 < pbox->y1)
+ y1 = pbox->y1;
+ if (x2 > pbox->x2)
+ x2 = pbox->x2;
+ if (y2 > pbox->y2)
+ y2 = pbox->y2;
+ if (x1 >= x2 || y1 >= y2)
+ continue;
+
+ src = bits + (y1 - y) * src_stride + (x1 - x) * (bpp / 8);
+ ok = pExaScr->info->UploadToScreen(pPix, x1 + xoff, y1 + yoff,
+ x2 - x1, y2 - y1, src, src_stride);
+ /* We have to fall back completely, and ignore what has already been completed.
+ * Messing with the fb layer directly like we used to is completely unacceptable.
+ */
+ if (!ok) {
+ ret = FALSE;
+ break;
+ }
+ }
+
+ if (ret)
+ exaMarkSync(pDrawable->pScreen);
+
+ return ret;
+}
+
+static void
+exaPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y,
+ int w, int h, int leftPad, int format, char *bits)
+{
+ if (!exaDoPutImage(pDrawable, pGC, depth, x, y, w, h, format, bits,
+ PixmapBytePad(w, pDrawable->depth)))
+ ExaCheckPutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format,
+ bits);
+}
+
+static Bool __inline
+exaCopyNtoNTwoDir (DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable,
+ GCPtr pGC, BoxPtr pbox, int nbox, int dx, int dy)
+{
+ ExaScreenPriv (pDstDrawable->pScreen);
+ PixmapPtr pSrcPixmap, pDstPixmap;
+ int src_off_x, src_off_y, dst_off_x, dst_off_y;
+ int dirsetup;
+
+ /* Need to get both pixmaps to call the driver routines */
+ pSrcPixmap = exaGetOffscreenPixmap (pSrcDrawable, &src_off_x, &src_off_y);
+ pDstPixmap = exaGetOffscreenPixmap (pDstDrawable, &dst_off_x, &dst_off_y);
+ if (!pSrcPixmap || !pDstPixmap)
+ return FALSE;
+
+ /*
+ * Now the case of a chip that only supports xdir = ydir = 1 or
+ * xdir = ydir = -1, but we have xdir != ydir.
+ */
+ dirsetup = 0; /* No direction set up yet. */
+ for (; nbox; pbox++, nbox--) {
+ if (dx >= 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) {
+ /* Do a xdir = ydir = -1 blit instead. */
+ if (dirsetup != -1) {
+ if (dirsetup != 0)
+ pExaScr->info->DoneCopy(pDstPixmap);
+ dirsetup = -1;
+ if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap,
+ pDstPixmap,
+ -1, -1,
+ pGC ? pGC->alu : GXcopy,
+ pGC ? pGC->planemask :
+ FB_ALLONES))
+ return FALSE;
+ }
+ (*pExaScr->info->Copy)(pDstPixmap,
+ src_off_x + pbox->x1 + dx,
+ src_off_y + pbox->y1 + dy,
+ dst_off_x + pbox->x1,
+ dst_off_y + pbox->y1,
+ pbox->x2 - pbox->x1,
+ pbox->y2 - pbox->y1);
+ } else if (dx < 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) {
+ /* Do a xdir = ydir = 1 blit instead. */
+ if (dirsetup != 1) {
+ if (dirsetup != 0)
+ pExaScr->info->DoneCopy(pDstPixmap);
+ dirsetup = 1;
+ if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap,
+ pDstPixmap,
+ 1, 1,
+ pGC ? pGC->alu : GXcopy,
+ pGC ? pGC->planemask :
+ FB_ALLONES))
+ return FALSE;
+ }
+ (*pExaScr->info->Copy)(pDstPixmap,
+ src_off_x + pbox->x1 + dx,
+ src_off_y + pbox->y1 + dy,
+ dst_off_x + pbox->x1,
+ dst_off_y + pbox->y1,
+ pbox->x2 - pbox->x1,
+ pbox->y2 - pbox->y1);
+ } else if (dx >= 0) {
+ /*
+ * xdir = 1, ydir = -1.
+ * Perform line-by-line xdir = ydir = 1 blits, going up.
+ */
+ int i;
+ if (dirsetup != 1) {
+ if (dirsetup != 0)
+ pExaScr->info->DoneCopy(pDstPixmap);
+ dirsetup = 1;
+ if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap,
+ pDstPixmap,
+ 1, 1,
+ pGC ? pGC->alu : GXcopy,
+ pGC ? pGC->planemask :
+ FB_ALLONES))
+ return FALSE;
+ }
+ for (i = pbox->y2 - pbox->y1 - 1; i >= 0; i--)
+ (*pExaScr->info->Copy)(pDstPixmap,
+ src_off_x + pbox->x1 + dx,
+ src_off_y + pbox->y1 + dy + i,
+ dst_off_x + pbox->x1,
+ dst_off_y + pbox->y1 + i,
+ pbox->x2 - pbox->x1, 1);
+ } else {
+ /*
+ * xdir = -1, ydir = 1.
+ * Perform line-by-line xdir = ydir = -1 blits, going down.
+ */
+ int i;
+ if (dirsetup != -1) {
+ if (dirsetup != 0)
+ pExaScr->info->DoneCopy(pDstPixmap);
+ dirsetup = -1;
+ if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap,
+ pDstPixmap,
+ -1, -1,
+ pGC ? pGC->alu : GXcopy,
+ pGC ? pGC->planemask :
+ FB_ALLONES))
+ return FALSE;
+ }
+ for (i = 0; i < pbox->y2 - pbox->y1; i++)
+ (*pExaScr->info->Copy)(pDstPixmap,
+ src_off_x + pbox->x1 + dx,
+ src_off_y + pbox->y1 + dy + i,
+ dst_off_x + pbox->x1,
+ dst_off_y + pbox->y1 + i,
+ pbox->x2 - pbox->x1, 1);
+ }
+ }
+ if (dirsetup != 0)
+ pExaScr->info->DoneCopy(pDstPixmap);
+ exaMarkSync(pDstDrawable->pScreen);
+ return TRUE;
+}
+
+Bool
+exaHWCopyNtoN (DrawablePtr pSrcDrawable,
+ DrawablePtr pDstDrawable,
+ GCPtr pGC,
+ BoxPtr pbox,
+ int nbox,
+ int dx,
+ int dy,
+ Bool reverse,
+ Bool upsidedown)
+{
+ ExaScreenPriv (pDstDrawable->pScreen);
+ PixmapPtr pSrcPixmap, pDstPixmap;
+ ExaPixmapPrivPtr pSrcExaPixmap, pDstExaPixmap;
+ int src_off_x, src_off_y;
+ int dst_off_x, dst_off_y;
+ RegionPtr srcregion = NULL, dstregion = NULL;
+ xRectangle *rects;
+ Bool ret = TRUE;
+
+ /* avoid doing copy operations if no boxes */
+ if (nbox == 0)
+ return TRUE;
+
+ pSrcPixmap = exaGetDrawablePixmap (pSrcDrawable);
+ pDstPixmap = exaGetDrawablePixmap (pDstDrawable);
+
+ exaGetDrawableDeltas (pSrcDrawable, pSrcPixmap, &src_off_x, &src_off_y);
+ exaGetDrawableDeltas (pDstDrawable, pDstPixmap, &dst_off_x, &dst_off_y);
+
+ rects = malloc(nbox * sizeof(xRectangle));
+
+ if (rects) {
+ int i;
+ int ordering;
+
+ for (i = 0; i < nbox; i++) {
+ rects[i].x = pbox[i].x1 + dx + src_off_x;
+ rects[i].y = pbox[i].y1 + dy + src_off_y;
+ rects[i].width = pbox[i].x2 - pbox[i].x1;
+ rects[i].height = pbox[i].y2 - pbox[i].y1;
+ }
+
+ /* This must match the RegionCopy() logic for reversing rect order */
+ if (nbox == 1 || (dx > 0 && dy > 0) ||
+ (pDstDrawable != pSrcDrawable &&
+ (pDstDrawable->type != DRAWABLE_WINDOW ||
+ pSrcDrawable->type != DRAWABLE_WINDOW)))
+ ordering = CT_YXBANDED;
+ else
+ ordering = CT_UNSORTED;
+
+ srcregion = RegionFromRects(nbox, rects, ordering);
+ free(rects);
+
+ if (!pGC || !exaGCReadsDestination(pDstDrawable, pGC->planemask,
+ pGC->fillStyle, pGC->alu,
+ pGC->clientClipType)) {
+ dstregion = RegionCreate(NullBox, 0);
+ RegionCopy(dstregion, srcregion);
+ RegionTranslate(dstregion, dst_off_x - dx - src_off_x,
+ dst_off_y - dy - src_off_y);
+ }
+ }
+
+
+ pSrcExaPixmap = ExaGetPixmapPriv (pSrcPixmap);
+ pDstExaPixmap = ExaGetPixmapPriv (pDstPixmap);
+
+ /* Check whether the accelerator can use this pixmap.
+ * If the pitch of the pixmaps is out of range, there's nothing
+ * we can do but fall back to software rendering.
+ */
+ if (pSrcExaPixmap->accel_blocked & EXA_RANGE_PITCH ||
+ pDstExaPixmap->accel_blocked & EXA_RANGE_PITCH)
+ goto fallback;
+
+ /* If the width or the height of either of the pixmaps
+ * is out of range, check whether the boxes are actually out of the
+ * addressable range as well. If they aren't, we can still do
+ * the copying in hardware.
+ */
+ if (pSrcExaPixmap->accel_blocked || pDstExaPixmap->accel_blocked) {
+ int i;
+
+ for (i = 0; i < nbox; i++) {
+ /* src */
+ if ((pbox[i].x2 + dx + src_off_x) >= pExaScr->info->maxX ||
+ (pbox[i].y2 + dy + src_off_y) >= pExaScr->info->maxY)
+ goto fallback;
+
+ /* dst */
+ if ((pbox[i].x2 + dst_off_x) >= pExaScr->info->maxX ||
+ (pbox[i].y2 + dst_off_y) >= pExaScr->info->maxY)
+ goto fallback;
+ }
+ }
+
+ if (pExaScr->do_migration) {
+ ExaMigrationRec pixmaps[2];
+
+ pixmaps[0].as_dst = TRUE;
+ pixmaps[0].as_src = FALSE;
+ pixmaps[0].pPix = pDstPixmap;
+ pixmaps[0].pReg = dstregion;
+ pixmaps[1].as_dst = FALSE;
+ pixmaps[1].as_src = TRUE;
+ pixmaps[1].pPix = pSrcPixmap;
+ pixmaps[1].pReg = srcregion;
+
+ exaDoMigration (pixmaps, 2, TRUE);
+ }
+
+ /* Mixed directions must be handled specially if the card is lame */
+ if ((pExaScr->info->flags & EXA_TWO_BITBLT_DIRECTIONS) &&
+ reverse != upsidedown) {
+ if (exaCopyNtoNTwoDir(pSrcDrawable, pDstDrawable, pGC, pbox, nbox,
+ dx, dy))
+ goto out;
+ goto fallback;
+ }
+
+ if (exaPixmapHasGpuCopy(pDstPixmap)) {
+ /* Normal blitting. */
+ if (exaPixmapHasGpuCopy(pSrcPixmap)) {
+ if (!(*pExaScr->info->PrepareCopy) (pSrcPixmap, pDstPixmap, reverse ? -1 : 1,
+ upsidedown ? -1 : 1,
+ pGC ? pGC->alu : GXcopy,
+ pGC ? pGC->planemask : FB_ALLONES)) {
+ goto fallback;
+ }
+
+ while (nbox--)
+ {
+ (*pExaScr->info->Copy) (pDstPixmap,
+ pbox->x1 + dx + src_off_x,
+ pbox->y1 + dy + src_off_y,
+ pbox->x1 + dst_off_x, pbox->y1 + dst_off_y,
+ pbox->x2 - pbox->x1, pbox->y2 - pbox->y1);
+ pbox++;
+ }
+
+ (*pExaScr->info->DoneCopy) (pDstPixmap);
+ exaMarkSync (pDstDrawable->pScreen);
+ /* UTS: mainly for SHM PutImage's secondary path.
+ *
+ * Only taking this path for directly accessible pixmaps.
+ */
+ } else if (!pDstExaPixmap->pDamage && pSrcExaPixmap->sys_ptr) {
+ int bpp = pSrcDrawable->bitsPerPixel;
+ int src_stride = exaGetPixmapPitch(pSrcPixmap);
+ CARD8 *src = NULL;
+
+ if (!pExaScr->info->UploadToScreen)
+ goto fallback;
+
+ if (pSrcDrawable->bitsPerPixel != pDstDrawable->bitsPerPixel)
+ goto fallback;
+
+ if (pSrcDrawable->bitsPerPixel < 8)
+ goto fallback;
+
+ if (pGC && !(pGC->alu == GXcopy && EXA_PM_IS_SOLID(pSrcDrawable, pGC->planemask)))
+ goto fallback;
+
+ while (nbox--)
+ {
+ src = pSrcExaPixmap->sys_ptr + (pbox->y1 + dy + src_off_y) * src_stride + (pbox->x1 + dx + src_off_x) * (bpp / 8);
+ if (!pExaScr->info->UploadToScreen(pDstPixmap, pbox->x1 + dst_off_x,
+ pbox->y1 + dst_off_y, pbox->x2 - pbox->x1, pbox->y2 - pbox->y1,
+ (char *) src, src_stride))
+ goto fallback;
+
+ pbox++;
+ }
+ } else
+ goto fallback;
+ } else
+ goto fallback;
+
+ goto out;
+
+fallback:
+ ret = FALSE;
+
+out:
+ if (dstregion) {
+ RegionUninit(dstregion);
+ RegionDestroy(dstregion);
+ }
+ if (srcregion) {
+ RegionUninit(srcregion);
+ RegionDestroy(srcregion);
+ }
+
+ return ret;
+}
+
+void
+exaCopyNtoN (DrawablePtr pSrcDrawable,
+ DrawablePtr pDstDrawable,
+ GCPtr pGC,
+ BoxPtr pbox,
+ int nbox,
+ int dx,
+ int dy,
+ Bool reverse,
+ Bool upsidedown,
+ Pixel bitplane,
+ void *closure)
+{
+ ExaScreenPriv(pDstDrawable->pScreen);
+
+ if (pExaScr->fallback_counter ||
+ (pExaScr->fallback_flags & EXA_FALLBACK_COPYWINDOW))
+ return;
+
+ if (exaHWCopyNtoN(pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy, reverse, upsidedown))
+ return;
+
+ /* This is a CopyWindow, it's cleaner to fallback at the original call. */
+ if (pExaScr->fallback_flags & EXA_ACCEL_COPYWINDOW) {
+ pExaScr->fallback_flags |= EXA_FALLBACK_COPYWINDOW;
+ return;
+ }
+
+ /* fallback */
+ ExaCheckCopyNtoN(pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy, reverse, upsidedown, bitplane, closure);
+}
+
+RegionPtr
+exaCopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC,
+ int srcx, int srcy, int width, int height, int dstx, int dsty)
+{
+ ExaScreenPriv (pDstDrawable->pScreen);
+
+ if (pExaScr->fallback_counter || pExaScr->swappedOut) {
+ return ExaCheckCopyArea(pSrcDrawable, pDstDrawable, pGC,
+ srcx, srcy, width, height, dstx, dsty);
+ }
+
+ return miDoCopy (pSrcDrawable, pDstDrawable, pGC,
+ srcx, srcy, width, height,
+ dstx, dsty, exaCopyNtoN, 0, NULL);
+}
+
+static void
+exaPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
+ DDXPointPtr ppt)
+{
+ ExaScreenPriv (pDrawable->pScreen);
+ int i;
+ xRectangle *prect;
+
+ /* If we can't reuse the current GC as is, don't bother accelerating the
+ * points.
+ */
+ if (pExaScr->fallback_counter || pGC->fillStyle != FillSolid) {
+ ExaCheckPolyPoint(pDrawable, pGC, mode, npt, ppt);
+ return;
+ }
+
+ prect = malloc(sizeof(xRectangle) * npt);
+ for (i = 0; i < npt; i++) {
+ prect[i].x = ppt[i].x;
+ prect[i].y = ppt[i].y;
+ if (i > 0 && mode == CoordModePrevious) {
+ prect[i].x += prect[i - 1].x;
+ prect[i].y += prect[i - 1].y;
+ }
+ prect[i].width = 1;
+ prect[i].height = 1;
+ }
+ pGC->ops->PolyFillRect(pDrawable, pGC, npt, prect);
+ free(prect);
+}
+
+/**
+ * exaPolylines() checks if it can accelerate the lines as a group of
+ * horizontal or vertical lines (rectangles), and uses existing rectangle fill
+ * acceleration if so.
+ */
+static void
+exaPolylines(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
+ DDXPointPtr ppt)
+{
+ ExaScreenPriv (pDrawable->pScreen);
+ xRectangle *prect;
+ int x1, x2, y1, y2;
+ int i;
+
+ if (pExaScr->fallback_counter) {
+ ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt);
+ return;
+ }
+
+ /* Don't try to do wide lines or non-solid fill style. */
+ if (pGC->lineWidth != 0 || pGC->lineStyle != LineSolid ||
+ pGC->fillStyle != FillSolid) {
+ ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt);
+ return;
+ }
+
+ prect = malloc(sizeof(xRectangle) * (npt - 1));
+ x1 = ppt[0].x;
+ y1 = ppt[0].y;
+ /* If we have any non-horizontal/vertical, fall back. */
+ for (i = 0; i < npt - 1; i++) {
+ if (mode == CoordModePrevious) {
+ x2 = x1 + ppt[i + 1].x;
+ y2 = y1 + ppt[i + 1].y;
+ } else {
+ x2 = ppt[i + 1].x;
+ y2 = ppt[i + 1].y;
+ }
+
+ if (x1 != x2 && y1 != y2) {
+ free(prect);
+ ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt);
+ return;
+ }
+
+ if (x1 < x2) {
+ prect[i].x = x1;
+ prect[i].width = x2 - x1 + 1;
+ } else {
+ prect[i].x = x2;
+ prect[i].width = x1 - x2 + 1;
+ }
+ if (y1 < y2) {
+ prect[i].y = y1;
+ prect[i].height = y2 - y1 + 1;
+ } else {
+ prect[i].y = y2;
+ prect[i].height = y1 - y2 + 1;
+ }
+
+ x1 = x2;
+ y1 = y2;
+ }
+ pGC->ops->PolyFillRect(pDrawable, pGC, npt - 1, prect);
+ free(prect);
+}
+
+/**
+ * exaPolySegment() checks if it can accelerate the lines as a group of
+ * horizontal or vertical lines (rectangles), and uses existing rectangle fill
+ * acceleration if so.
+ */
+static void
+exaPolySegment (DrawablePtr pDrawable, GCPtr pGC, int nseg,
+ xSegment *pSeg)
+{
+ ExaScreenPriv (pDrawable->pScreen);
+ xRectangle *prect;
+ int i;
+
+ /* Don't try to do wide lines or non-solid fill style. */
+ if (pExaScr->fallback_counter || pGC->lineWidth != 0 ||
+ pGC->lineStyle != LineSolid || pGC->fillStyle != FillSolid)
+ {
+ ExaCheckPolySegment(pDrawable, pGC, nseg, pSeg);
+ return;
+ }
+
+ /* If we have any non-horizontal/vertical, fall back. */
+ for (i = 0; i < nseg; i++) {
+ if (pSeg[i].x1 != pSeg[i].x2 && pSeg[i].y1 != pSeg[i].y2) {
+ ExaCheckPolySegment(pDrawable, pGC, nseg, pSeg);
+ return;
+ }
+ }
+
+ prect = malloc(sizeof(xRectangle) * nseg);
+ for (i = 0; i < nseg; i++) {
+ if (pSeg[i].x1 < pSeg[i].x2) {
+ prect[i].x = pSeg[i].x1;
+ prect[i].width = pSeg[i].x2 - pSeg[i].x1 + 1;
+ } else {
+ prect[i].x = pSeg[i].x2;
+ prect[i].width = pSeg[i].x1 - pSeg[i].x2 + 1;
+ }
+ if (pSeg[i].y1 < pSeg[i].y2) {
+ prect[i].y = pSeg[i].y1;
+ prect[i].height = pSeg[i].y2 - pSeg[i].y1 + 1;
+ } else {
+ prect[i].y = pSeg[i].y2;
+ prect[i].height = pSeg[i].y1 - pSeg[i].y2 + 1;
+ }
+
+ /* don't paint last pixel */
+ if (pGC->capStyle == CapNotLast) {
+ if (prect[i].width == 1)
+ prect[i].height--;
+ else
+ prect[i].width--;
+ }
+ }
+ pGC->ops->PolyFillRect(pDrawable, pGC, nseg, prect);
+ free(prect);
+}
+
+static Bool exaFillRegionSolid (DrawablePtr pDrawable, RegionPtr pRegion,
+ Pixel pixel, CARD32 planemask, CARD32 alu,
+ unsigned int clientClipType);
+
+static void
+exaPolyFillRect(DrawablePtr pDrawable,
+ GCPtr pGC,
+ int nrect,
+ xRectangle *prect)
+{
+ ExaScreenPriv (pDrawable->pScreen);
+ RegionPtr pClip = fbGetCompositeClip(pGC);
+ PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable);
+ ExaPixmapPriv (pPixmap);
+ register BoxPtr pbox;
+ BoxPtr pextent;
+ int extentX1, extentX2, extentY1, extentY2;
+ int fullX1, fullX2, fullY1, fullY2;
+ int partX1, partX2, partY1, partY2;
+ int xoff, yoff;
+ int xorg, yorg;
+ int n;
+ RegionPtr pReg = RegionFromRects(nrect, prect, CT_UNSORTED);
+
+ /* Compute intersection of rects and clip region */
+ RegionTranslate(pReg, pDrawable->x, pDrawable->y);
+ RegionIntersect(pReg, pClip, pReg);
+
+ if (!RegionNumRects(pReg)) {
+ goto out;
+ }
+
+ exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff);
+
+ if (pExaScr->fallback_counter || pExaScr->swappedOut ||
+ pExaPixmap->accel_blocked)
+ {
+ goto fallback;
+ }
+
+ /* For ROPs where overlaps don't matter, convert rectangles to region and
+ * call exaFillRegion{Solid,Tiled}.
+ */
+ if ((pGC->fillStyle == FillSolid || pGC->fillStyle == FillTiled) &&
+ (nrect == 1 || pGC->alu == GXcopy || pGC->alu == GXclear ||
+ pGC->alu == GXnoop || pGC->alu == GXcopyInverted ||
+ pGC->alu == GXset)) {
+ if (((pGC->fillStyle == FillSolid || pGC->tileIsPixel) &&
+ exaFillRegionSolid(pDrawable, pReg, pGC->fillStyle == FillSolid ?
+ pGC->fgPixel : pGC->tile.pixel, pGC->planemask,
+ pGC->alu, pGC->clientClipType)) ||
+ (pGC->fillStyle == FillTiled && !pGC->tileIsPixel &&
+ exaFillRegionTiled(pDrawable, pReg, pGC->tile.pixmap, &pGC->patOrg,
+ pGC->planemask, pGC->alu,
+ pGC->clientClipType))) {
+ goto out;
+ }
+ }
+
+ if (pGC->fillStyle != FillSolid &&
+ !(pGC->tileIsPixel && pGC->fillStyle == FillTiled))
+ {
+ goto fallback;
+ }
+
+ if (pExaScr->do_migration) {
+ ExaMigrationRec pixmaps[1];
+
+ pixmaps[0].as_dst = TRUE;
+ pixmaps[0].as_src = FALSE;
+ pixmaps[0].pPix = pPixmap;
+ pixmaps[0].pReg = NULL;
+
+ exaDoMigration (pixmaps, 1, TRUE);
+ }
+
+ if (!exaPixmapHasGpuCopy (pPixmap) ||
+ !(*pExaScr->info->PrepareSolid) (pPixmap,
+ pGC->alu,
+ pGC->planemask,
+ pGC->fgPixel))
+ {
+fallback:
+ ExaCheckPolyFillRect (pDrawable, pGC, nrect, prect);
+ goto out;
+ }
+
+ xorg = pDrawable->x;
+ yorg = pDrawable->y;
+
+ pextent = RegionExtents(pClip);
+ extentX1 = pextent->x1;
+ extentY1 = pextent->y1;
+ extentX2 = pextent->x2;
+ extentY2 = pextent->y2;
+ while (nrect--)
+ {
+ fullX1 = prect->x + xorg;
+ fullY1 = prect->y + yorg;
+ fullX2 = fullX1 + (int) prect->width;
+ fullY2 = fullY1 + (int) prect->height;
+ prect++;
+
+ if (fullX1 < extentX1)
+ fullX1 = extentX1;
+
+ if (fullY1 < extentY1)
+ fullY1 = extentY1;
+
+ if (fullX2 > extentX2)
+ fullX2 = extentX2;
+
+ if (fullY2 > extentY2)
+ fullY2 = extentY2;
+
+ if ((fullX1 >= fullX2) || (fullY1 >= fullY2))
+ continue;
+ n = RegionNumRects (pClip);
+ if (n == 1)
+ {
+ (*pExaScr->info->Solid) (pPixmap,
+ fullX1 + xoff, fullY1 + yoff,
+ fullX2 + xoff, fullY2 + yoff);
+ }
+ else
+ {
+ pbox = RegionRects(pClip);
+ /*
+ * clip the rectangle to each box in the clip region
+ * this is logically equivalent to calling Intersect(),
+ * but rectangles may overlap each other here.
+ */
+ while(n--)
+ {
+ partX1 = pbox->x1;
+ if (partX1 < fullX1)
+ partX1 = fullX1;
+ partY1 = pbox->y1;
+ if (partY1 < fullY1)
+ partY1 = fullY1;
+ partX2 = pbox->x2;
+ if (partX2 > fullX2)
+ partX2 = fullX2;
+ partY2 = pbox->y2;
+ if (partY2 > fullY2)
+ partY2 = fullY2;
+
+ pbox++;
+
+ if (partX1 < partX2 && partY1 < partY2) {
+ (*pExaScr->info->Solid) (pPixmap,
+ partX1 + xoff, partY1 + yoff,
+ partX2 + xoff, partY2 + yoff);
+ }
+ }
+ }
+ }
+ (*pExaScr->info->DoneSolid) (pPixmap);
+ exaMarkSync(pDrawable->pScreen);
+
+out:
+ RegionUninit(pReg);
+ RegionDestroy(pReg);
+}
+
+const GCOps exaOps = {
+ exaFillSpans,
+ ExaCheckSetSpans,
+ exaPutImage,
+ exaCopyArea,
+ ExaCheckCopyPlane,
+ exaPolyPoint,
+ exaPolylines,
+ exaPolySegment,
+ miPolyRectangle,
+ ExaCheckPolyArc,
+ miFillPolygon,
+ exaPolyFillRect,
+ miPolyFillArc,
+ miPolyText8,
+ miPolyText16,
+ miImageText8,
+ miImageText16,
+ ExaCheckImageGlyphBlt,
+ ExaCheckPolyGlyphBlt,
+ ExaCheckPushPixels,
+};
+
+void
+exaCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
+{
+ RegionRec rgnDst;
+ int dx, dy;
+ PixmapPtr pPixmap = (*pWin->drawable.pScreen->GetWindowPixmap) (pWin);
+ ExaScreenPriv(pWin->drawable.pScreen);
+
+ dx = ptOldOrg.x - pWin->drawable.x;
+ dy = ptOldOrg.y - pWin->drawable.y;
+ RegionTranslate(prgnSrc, -dx, -dy);
+
+ RegionInit(&rgnDst, NullBox, 0);
+
+ RegionIntersect(&rgnDst, &pWin->borderClip, prgnSrc);
+#ifdef COMPOSITE
+ if (pPixmap->screen_x || pPixmap->screen_y)
+ RegionTranslate(&rgnDst,
+ -pPixmap->screen_x, -pPixmap->screen_y);
+#endif
+
+ if (pExaScr->fallback_counter) {
+ pExaScr->fallback_flags |= EXA_FALLBACK_COPYWINDOW;
+ goto fallback;
+ }
+
+ pExaScr->fallback_flags |= EXA_ACCEL_COPYWINDOW;
+ miCopyRegion (&pPixmap->drawable, &pPixmap->drawable,
+ NULL,
+ &rgnDst, dx, dy, exaCopyNtoN, 0, NULL);
+ pExaScr->fallback_flags &= ~EXA_ACCEL_COPYWINDOW;
+
+fallback:
+ RegionUninit(&rgnDst);
+
+ if (pExaScr->fallback_flags & EXA_FALLBACK_COPYWINDOW) {
+ pExaScr->fallback_flags &= ~EXA_FALLBACK_COPYWINDOW;
+ RegionTranslate(prgnSrc, dx, dy);
+ ExaCheckCopyWindow(pWin, ptOldOrg, prgnSrc);
+ }
+}
+
+static Bool
+exaFillRegionSolid (DrawablePtr pDrawable, RegionPtr pRegion, Pixel pixel,
+ CARD32 planemask, CARD32 alu, unsigned int clientClipType)
+{
+ ExaScreenPriv(pDrawable->pScreen);
+ PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable);
+ ExaPixmapPriv (pPixmap);
+ int xoff, yoff;
+ Bool ret = FALSE;
+
+ exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff);
+ RegionTranslate(pRegion, xoff, yoff);
+
+ if (pExaScr->fallback_counter || pExaPixmap->accel_blocked)
+ goto out;
+
+ if (pExaScr->do_migration) {
+ ExaMigrationRec pixmaps[1];
+
+ pixmaps[0].as_dst = TRUE;
+ pixmaps[0].as_src = FALSE;
+ pixmaps[0].pPix = pPixmap;
+ pixmaps[0].pReg = exaGCReadsDestination(pDrawable, planemask, FillSolid,
+ alu, clientClipType) ? NULL : pRegion;
+
+ exaDoMigration (pixmaps, 1, TRUE);
+ }
+
+ if (exaPixmapHasGpuCopy (pPixmap) &&
+ (*pExaScr->info->PrepareSolid) (pPixmap, alu, planemask, pixel))
+ {
+ int nbox;
+ BoxPtr pBox;
+
+ nbox = RegionNumRects (pRegion);
+ pBox = RegionRects (pRegion);
+
+ while (nbox--)
+ {
+ (*pExaScr->info->Solid) (pPixmap, pBox->x1, pBox->y1, pBox->x2,
+ pBox->y2);
+ pBox++;
+ }
+ (*pExaScr->info->DoneSolid) (pPixmap);
+ exaMarkSync(pDrawable->pScreen);
+
+ if (pExaPixmap->pDamage &&
+ pExaPixmap->sys_ptr && pDrawable->type == DRAWABLE_PIXMAP &&
+ pDrawable->width == 1 && pDrawable->height == 1 &&
+ pDrawable->bitsPerPixel != 24) {
+ ExaPixmapPriv(pPixmap);
+ RegionPtr pending_damage = DamagePendingRegion(pExaPixmap->pDamage);
+
+ switch (pDrawable->bitsPerPixel) {
+ case 32:
+ *(CARD32*)pExaPixmap->sys_ptr = pixel;
+ break;
+ case 16:
+ *(CARD16*)pExaPixmap->sys_ptr = pixel;
+ break;
+ case 8:
+ case 4:
+ case 1:
+ *(CARD8*)pExaPixmap->sys_ptr = pixel;
+ }
+
+ RegionUnion(&pExaPixmap->validSys, &pExaPixmap->validSys,
+ pRegion);
+ RegionUnion(&pExaPixmap->validFB, &pExaPixmap->validFB,
+ pRegion);
+ RegionSubtract(pending_damage, pending_damage, pRegion);
+ }
+
+ ret = TRUE;
+ }
+
+out:
+ RegionTranslate(pRegion, -xoff, -yoff);
+
+ return ret;
+}
+
+/* Try to do an accelerated tile of the pTile into pRegion of pDrawable.
+ * Based on fbFillRegionTiled(), fbTile().
+ */
+Bool
+exaFillRegionTiled (DrawablePtr pDrawable, RegionPtr pRegion, PixmapPtr pTile,
+ DDXPointPtr pPatOrg, CARD32 planemask, CARD32 alu,
+ unsigned int clientClipType)
+{
+ ExaScreenPriv(pDrawable->pScreen);
+ PixmapPtr pPixmap;
+ ExaPixmapPrivPtr pExaPixmap;
+ ExaPixmapPrivPtr pTileExaPixmap = ExaGetPixmapPriv(pTile);
+ int xoff, yoff;
+ int tileWidth, tileHeight;
+ int nbox = RegionNumRects (pRegion);
+ BoxPtr pBox = RegionRects (pRegion);
+ Bool ret = FALSE;
+ int i;
+
+ tileWidth = pTile->drawable.width;
+ tileHeight = pTile->drawable.height;
+
+ /* If we're filling with a solid color, grab it out and go to
+ * FillRegionSolid, saving numerous copies.
+ */
+ if (tileWidth == 1 && tileHeight == 1)
+ return exaFillRegionSolid(pDrawable, pRegion,
+ exaGetPixmapFirstPixel (pTile), planemask,
+ alu, clientClipType);
+
+ pPixmap = exaGetDrawablePixmap (pDrawable);
+ pExaPixmap = ExaGetPixmapPriv (pPixmap);
+
+ if (pExaScr->fallback_counter || pExaPixmap->accel_blocked ||
+ pTileExaPixmap->accel_blocked)
+ return FALSE;
+
+ if (pExaScr->do_migration) {
+ ExaMigrationRec pixmaps[2];
+
+ pixmaps[0].as_dst = TRUE;
+ pixmaps[0].as_src = FALSE;
+ pixmaps[0].pPix = pPixmap;
+ pixmaps[0].pReg = exaGCReadsDestination(pDrawable, planemask, FillTiled,
+ alu, clientClipType) ? NULL : pRegion;
+ pixmaps[1].as_dst = FALSE;
+ pixmaps[1].as_src = TRUE;
+ pixmaps[1].pPix = pTile;
+ pixmaps[1].pReg = NULL;
+
+ exaDoMigration (pixmaps, 2, TRUE);
+ }
+
+ pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff);
+
+ if (!pPixmap || !exaPixmapHasGpuCopy(pTile))
+ return FALSE;
+
+ if ((*pExaScr->info->PrepareCopy) (pTile, pPixmap, 1, 1, alu, planemask))
+ {
+ if (xoff || yoff)
+ RegionTranslate(pRegion, xoff, yoff);
+
+ for (i = 0; i < nbox; i++)
+ {
+ int height = pBox[i].y2 - pBox[i].y1;
+ int dstY = pBox[i].y1;
+ int tileY;
+
+ if (alu == GXcopy)
+ height = min(height, tileHeight);
+
+ modulus(dstY - yoff - pDrawable->y - pPatOrg->y, tileHeight, tileY);
+
+ while (height > 0) {
+ int width = pBox[i].x2 - pBox[i].x1;
+ int dstX = pBox[i].x1;
+ int tileX;
+ int h = tileHeight - tileY;
+
+ if (alu == GXcopy)
+ width = min(width, tileWidth);
+
+ if (h > height)
+ h = height;
+ height -= h;
+
+ modulus(dstX - xoff - pDrawable->x - pPatOrg->x, tileWidth,
+ tileX);
+
+ while (width > 0) {
+ int w = tileWidth - tileX;
+ if (w > width)
+ w = width;
+ width -= w;
+
+ (*pExaScr->info->Copy) (pPixmap, tileX, tileY, dstX, dstY,
+ w, h);
+ dstX += w;
+ tileX = 0;
+ }
+ dstY += h;
+ tileY = 0;
+ }
+ }
+ (*pExaScr->info->DoneCopy) (pPixmap);
+
+ /* With GXcopy, we only need to do the basic algorithm up to the tile
+ * size; then, we can just keep doubling the destination in each
+ * direction until it fills the box. This way, the number of copy
+ * operations is O(log(rx)) + O(log(ry)) instead of O(rx * ry), where
+ * rx/ry is the ratio between box and tile width/height. This can make
+ * a big difference if each driver copy incurs a significant constant
+ * overhead.
+ */
+ if (alu != GXcopy)
+ ret = TRUE;
+ else {
+ Bool more_copy = FALSE;
+
+ for (i = 0; i < nbox; i++) {
+ int dstX = pBox[i].x1 + tileWidth;
+ int dstY = pBox[i].y1 + tileHeight;
+
+ if ((dstX < pBox[i].x2) || (dstY < pBox[i].y2)) {
+ more_copy = TRUE;
+ break;
+ }
+ }
+
+ if (more_copy == FALSE)
+ ret = TRUE;
+
+ if (more_copy && (*pExaScr->info->PrepareCopy) (pPixmap, pPixmap,
+ 1, 1, alu, planemask)) {
+ for (i = 0; i < nbox; i++)
+ {
+ int dstX = pBox[i].x1 + tileWidth;
+ int dstY = pBox[i].y1 + tileHeight;
+ int width = min(pBox[i].x2 - dstX, tileWidth);
+ int height = min(pBox[i].y2 - pBox[i].y1, tileHeight);
+
+ while (dstX < pBox[i].x2) {
+ (*pExaScr->info->Copy) (pPixmap, pBox[i].x1, pBox[i].y1,
+ dstX, pBox[i].y1, width, height);
+ dstX += width;
+ width = min(pBox[i].x2 - dstX, width * 2);
+ }
+
+ width = pBox[i].x2 - pBox[i].x1;
+ height = min(pBox[i].y2 - dstY, tileHeight);
+
+ while (dstY < pBox[i].y2) {
+ (*pExaScr->info->Copy) (pPixmap, pBox[i].x1, pBox[i].y1,
+ pBox[i].x1, dstY, width, height);
+ dstY += height;
+ height = min(pBox[i].y2 - dstY, height * 2);
+ }
+ }
+
+ (*pExaScr->info->DoneCopy) (pPixmap);
+
+ ret = TRUE;
+ }
+ }
+
+ exaMarkSync(pDrawable->pScreen);
+
+ if (xoff || yoff)
+ RegionTranslate(pRegion, -xoff, -yoff);
+ }
+
+ return ret;
+}
+
+
+/**
+ * Accelerates GetImage for solid ZPixmap downloads from framebuffer memory.
+ *
+ * This is probably the only case we actually care about. The rest fall through
+ * to migration and fbGetImage, which hopefully will result in migration pushing
+ * the pixmap out of framebuffer.
+ */
+void
+exaGetImage (DrawablePtr pDrawable, int x, int y, int w, int h,
+ unsigned int format, unsigned long planeMask, char *d)
+{
+ ExaScreenPriv (pDrawable->pScreen);
+ PixmapPtr pPix = exaGetDrawablePixmap (pDrawable);
+ ExaPixmapPriv(pPix);
+ int xoff, yoff;
+ Bool ok;
+
+ if (pExaScr->fallback_counter || pExaScr->swappedOut)
+ goto fallback;
+
+ /* If there's a system copy, we want to save the result there */
+ if (pExaPixmap->pDamage)
+ goto fallback;
+
+ pPix = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff);
+
+ if (pPix == NULL || pExaScr->info->DownloadFromScreen == NULL)
+ goto fallback;
+
+ /* Only cover the ZPixmap, solid copy case. */
+ if (format != ZPixmap || !EXA_PM_IS_SOLID(pDrawable, planeMask))
+ goto fallback;
+
+ /* Only try to handle the 8bpp and up cases, since we don't want to think
+ * about <8bpp.
+ */
+ if (pDrawable->bitsPerPixel < 8)
+ goto fallback;
+
+ ok = pExaScr->info->DownloadFromScreen(pPix, pDrawable->x + x + xoff,
+ pDrawable->y + y + yoff, w, h, d,
+ PixmapBytePad(w, pDrawable->depth));
+ if (ok) {
+ exaWaitSync(pDrawable->pScreen);
+ return;
+ }
+
+fallback:
+ ExaCheckGetImage(pDrawable, x, y, w, h, format, planeMask, d);
+}
diff --git a/xorg-server/exa/exa_classic.c b/xorg-server/exa/exa_classic.c
index 1a1467848..919b29df2 100644
--- a/xorg-server/exa/exa_classic.c
+++ b/xorg-server/exa/exa_classic.c
@@ -1,266 +1,266 @@
-/*
- * 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);
-
- exaDestroyPixmap(pPixmap);
-
- 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) {
- void* old_ptr = pPixmap->devPrivate.ptr;
- pPixmap->devPrivate.ptr = ExaGetPixmapAddress(pPixmap);
- ret = pExaScr->info->PixmapIsOffscreen(pPixmap);
- pPixmap->devPrivate.ptr = old_ptr;
- } 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);
+
+ exaDestroyPixmap(pPixmap);
+
+ 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) {
+ void* old_ptr = pPixmap->devPrivate.ptr;
+ pPixmap->devPrivate.ptr = ExaGetPixmapAddress(pPixmap);
+ ret = pExaScr->info->PixmapIsOffscreen(pPixmap);
+ pPixmap->devPrivate.ptr = old_ptr;
+ } else
+ ret = (pExaPixmap->use_gpu_copy && pExaPixmap->fb_ptr);
+
+ return ret;
+}
diff --git a/xorg-server/exa/exa_driver.c b/xorg-server/exa/exa_driver.c
index bfc89295f..795cb00cd 100644
--- a/xorg-server/exa/exa_driver.c
+++ b/xorg-server/exa/exa_driver.c
@@ -1,226 +1,226 @@
-/*
- * 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 specific implementation. */
-
-static _X_INLINE void*
-ExaGetPixmapAddress(PixmapPtr p)
-{
- ExaPixmapPriv(p);
-
- return pExaPixmap->sys_ptr;
-}
-
-/**
- * exaCreatePixmap() creates a new pixmap.
- *
- * Pixmaps are always marked as pinned, because exa has no control over them.
- */
-PixmapPtr
-exaCreatePixmap_driver(ScreenPtr pScreen, int w, int h, int depth,
- unsigned usage_hint)
-{
- PixmapPtr pPixmap;
- ExaPixmapPrivPtr pExaPixmap;
- int bpp;
- size_t paddedWidth, datasize;
- 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;
-
- /* Set this before driver hooks, to allow for driver pixmaps without gpu
- * memory to back it. These pixmaps have a valid pointer at all times.
- */
- pPixmap->devPrivate.ptr = NULL;
-
- if (pExaScr->info->CreatePixmap2) {
- int new_pitch = 0;
- pExaPixmap->driverPriv = pExaScr->info->CreatePixmap2(pScreen, w, h, depth, usage_hint, bpp, &new_pitch);
- paddedWidth = pExaPixmap->fb_pitch = new_pitch;
- }
- else {
- paddedWidth = ((w * bpp + FB_MASK) >> FB_SHIFT) * sizeof(FbBits);
- if (paddedWidth / 4 > 32767 || h > 32767)
- return NullPixmap;
-
- exaSetFbPitch(pExaScr, pExaPixmap, w, h, bpp);
-
- if (paddedWidth < pExaPixmap->fb_pitch)
- paddedWidth = pExaPixmap->fb_pitch;
- datasize = h * paddedWidth;
- pExaPixmap->driverPriv = pExaScr->info->CreatePixmap(pScreen, datasize, 0);
- }
-
- if (!pExaPixmap->driverPriv) {
- swap(pExaScr, pScreen, DestroyPixmap);
- pScreen->DestroyPixmap (pPixmap);
- swap(pExaScr, pScreen, DestroyPixmap);
- return NULL;
- }
-
- /* Allow ModifyPixmapHeader to set sys_ptr appropriately. */
- pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED;
- pExaPixmap->fb_ptr = NULL;
- pExaPixmap->pDamage = NULL;
- pExaPixmap->sys_ptr = NULL;
-
- (*pScreen->ModifyPixmapHeader)(pPixmap, w, h, 0, 0,
- paddedWidth, NULL);
-
- pExaPixmap->area = NULL;
-
- exaSetAccelBlock(pExaScr, pExaPixmap,
- w, h, bpp);
-
- pExaPixmap->use_gpu_copy = exaPixmapHasGpuCopy(pPixmap);
-
- /* During a fallback we must prepare access. */
- if (pExaScr->fallback_counter)
- exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_AUX_DEST);
-
- return pPixmap;
-}
-
-Bool
-exaModifyPixmapHeader_driver(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;
-
- if (width > 0 && height > 0 && bitsPerPixel > 0) {
- exaSetFbPitch(pExaScr, pExaPixmap,
- width, height, bitsPerPixel);
-
- exaSetAccelBlock(pExaScr, pExaPixmap,
- width, height, bitsPerPixel);
- }
- }
-
- if (pExaScr->info->ModifyPixmapHeader) {
- ret = pExaScr->info->ModifyPixmapHeader(pPixmap, width, height, depth,
- bitsPerPixel, devKind, pPixData);
- /* For EXA_HANDLES_PIXMAPS, we set pPixData to NULL.
- * If pPixmap->devPrivate.ptr is non-NULL, then we've got a
- * !has_gpu_copy pixmap. We need to store the pointer,
- * because PrepareAccess won't be called.
- */
- if (!pPixData && pPixmap->devPrivate.ptr && pPixmap->devKind) {
- pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr;
- pExaPixmap->sys_pitch = pPixmap->devKind;
- }
- if (ret == TRUE)
- goto out;
- }
-
- swap(pExaScr, pScreen, ModifyPixmapHeader);
- ret = pScreen->ModifyPixmapHeader(pPixmap, width, height, depth,
- bitsPerPixel, devKind, pPixData);
- swap(pExaScr, pScreen, ModifyPixmapHeader);
-
-out:
- /* Always NULL this, we don't want lingering pointers. */
- pPixmap->devPrivate.ptr = NULL;
-
- return ret;
-}
-
-Bool
-exaDestroyPixmap_driver (PixmapPtr pPixmap)
-{
- ScreenPtr pScreen = pPixmap->drawable.pScreen;
- ExaScreenPriv(pScreen);
- Bool ret;
-
- if (pPixmap->refcnt == 1)
- {
- ExaPixmapPriv (pPixmap);
-
- exaDestroyPixmap(pPixmap);
-
- if (pExaPixmap->driverPriv)
- pExaScr->info->DestroyPixmap(pScreen, pExaPixmap->driverPriv);
- pExaPixmap->driverPriv = NULL;
- }
-
- swap(pExaScr, pScreen, DestroyPixmap);
- ret = pScreen->DestroyPixmap (pPixmap);
- swap(pExaScr, pScreen, DestroyPixmap);
-
- return ret;
-}
-
-Bool
-exaPixmapHasGpuCopy_driver(PixmapPtr pPixmap)
-{
- ScreenPtr pScreen = pPixmap->drawable.pScreen;
- ExaScreenPriv(pScreen);
- pointer saved_ptr;
- Bool ret;
-
- 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 specific implementation. */
+
+static _X_INLINE void*
+ExaGetPixmapAddress(PixmapPtr p)
+{
+ ExaPixmapPriv(p);
+
+ return pExaPixmap->sys_ptr;
+}
+
+/**
+ * exaCreatePixmap() creates a new pixmap.
+ *
+ * Pixmaps are always marked as pinned, because exa has no control over them.
+ */
+PixmapPtr
+exaCreatePixmap_driver(ScreenPtr pScreen, int w, int h, int depth,
+ unsigned usage_hint)
+{
+ PixmapPtr pPixmap;
+ ExaPixmapPrivPtr pExaPixmap;
+ int bpp;
+ size_t paddedWidth, datasize;
+ 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;
+
+ /* Set this before driver hooks, to allow for driver pixmaps without gpu
+ * memory to back it. These pixmaps have a valid pointer at all times.
+ */
+ pPixmap->devPrivate.ptr = NULL;
+
+ if (pExaScr->info->CreatePixmap2) {
+ int new_pitch = 0;
+ pExaPixmap->driverPriv = pExaScr->info->CreatePixmap2(pScreen, w, h, depth, usage_hint, bpp, &new_pitch);
+ paddedWidth = pExaPixmap->fb_pitch = new_pitch;
+ }
+ else {
+ paddedWidth = ((w * bpp + FB_MASK) >> FB_SHIFT) * sizeof(FbBits);
+ if (paddedWidth / 4 > 32767 || h > 32767)
+ return NullPixmap;
+
+ exaSetFbPitch(pExaScr, pExaPixmap, w, h, bpp);
+
+ if (paddedWidth < pExaPixmap->fb_pitch)
+ paddedWidth = pExaPixmap->fb_pitch;
+ datasize = h * paddedWidth;
+ pExaPixmap->driverPriv = pExaScr->info->CreatePixmap(pScreen, datasize, 0);
+ }
+
+ if (!pExaPixmap->driverPriv) {
+ swap(pExaScr, pScreen, DestroyPixmap);
+ pScreen->DestroyPixmap (pPixmap);
+ swap(pExaScr, pScreen, DestroyPixmap);
+ return NULL;
+ }
+
+ /* Allow ModifyPixmapHeader to set sys_ptr appropriately. */
+ pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED;
+ pExaPixmap->fb_ptr = NULL;
+ pExaPixmap->pDamage = NULL;
+ pExaPixmap->sys_ptr = NULL;
+
+ (*pScreen->ModifyPixmapHeader)(pPixmap, w, h, 0, 0,
+ paddedWidth, NULL);
+
+ pExaPixmap->area = NULL;
+
+ exaSetAccelBlock(pExaScr, pExaPixmap,
+ w, h, bpp);
+
+ pExaPixmap->use_gpu_copy = exaPixmapHasGpuCopy(pPixmap);
+
+ /* During a fallback we must prepare access. */
+ if (pExaScr->fallback_counter)
+ exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_AUX_DEST);
+
+ return pPixmap;
+}
+
+Bool
+exaModifyPixmapHeader_driver(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;
+
+ if (width > 0 && height > 0 && bitsPerPixel > 0) {
+ exaSetFbPitch(pExaScr, pExaPixmap,
+ width, height, bitsPerPixel);
+
+ exaSetAccelBlock(pExaScr, pExaPixmap,
+ width, height, bitsPerPixel);
+ }
+ }
+
+ if (pExaScr->info->ModifyPixmapHeader) {
+ ret = pExaScr->info->ModifyPixmapHeader(pPixmap, width, height, depth,
+ bitsPerPixel, devKind, pPixData);
+ /* For EXA_HANDLES_PIXMAPS, we set pPixData to NULL.
+ * If pPixmap->devPrivate.ptr is non-NULL, then we've got a
+ * !has_gpu_copy pixmap. We need to store the pointer,
+ * because PrepareAccess won't be called.
+ */
+ if (!pPixData && pPixmap->devPrivate.ptr && pPixmap->devKind) {
+ pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr;
+ pExaPixmap->sys_pitch = pPixmap->devKind;
+ }
+ if (ret == TRUE)
+ goto out;
+ }
+
+ swap(pExaScr, pScreen, ModifyPixmapHeader);
+ ret = pScreen->ModifyPixmapHeader(pPixmap, width, height, depth,
+ bitsPerPixel, devKind, pPixData);
+ swap(pExaScr, pScreen, ModifyPixmapHeader);
+
+out:
+ /* Always NULL this, we don't want lingering pointers. */
+ pPixmap->devPrivate.ptr = NULL;
+
+ return ret;
+}
+
+Bool
+exaDestroyPixmap_driver (PixmapPtr pPixmap)
+{
+ ScreenPtr pScreen = pPixmap->drawable.pScreen;
+ ExaScreenPriv(pScreen);
+ Bool ret;
+
+ if (pPixmap->refcnt == 1)
+ {
+ ExaPixmapPriv (pPixmap);
+
+ exaDestroyPixmap(pPixmap);
+
+ if (pExaPixmap->driverPriv)
+ pExaScr->info->DestroyPixmap(pScreen, pExaPixmap->driverPriv);
+ pExaPixmap->driverPriv = NULL;
+ }
+
+ swap(pExaScr, pScreen, DestroyPixmap);
+ ret = pScreen->DestroyPixmap (pPixmap);
+ swap(pExaScr, pScreen, DestroyPixmap);
+
+ return ret;
+}
+
+Bool
+exaPixmapHasGpuCopy_driver(PixmapPtr pPixmap)
+{
+ ScreenPtr pScreen = pPixmap->drawable.pScreen;
+ ExaScreenPriv(pScreen);
+ pointer saved_ptr;
+ Bool ret;
+
+ 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_migration_classic.c b/xorg-server/exa/exa_migration_classic.c
index eb1081236..2f01f8d24 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 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 = { FALSE, TRUE,
- NULL, 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 = { FALSE, TRUE,
- NULL, 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", __FUNCTION__, 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 = { FALSE, TRUE,
+ NULL, 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 = { FALSE, TRUE,
+ NULL, 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", __FUNCTION__, 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_migration_mixed.c b/xorg-server/exa/exa_migration_mixed.c
index 9489b2927..4b2261943 100644
--- a/xorg-server/exa/exa_migration_mixed.c
+++ b/xorg-server/exa/exa_migration_mixed.c
@@ -1,261 +1,261 @@
-/*
- * 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"
-
-void
-exaCreateDriverPixmap_mixed(PixmapPtr pPixmap)
-{
- ScreenPtr pScreen = pPixmap->drawable.pScreen;
- ExaScreenPriv(pScreen);
- ExaPixmapPriv(pPixmap);
- int w = pPixmap->drawable.width, h = pPixmap->drawable.height;
- int depth = pPixmap->drawable.depth, bpp = pPixmap->drawable.bitsPerPixel;
- int usage_hint = pPixmap->usage_hint;
- int paddedWidth = pExaPixmap->sys_pitch;
-
- /* Already done. */
- if (pExaPixmap->driverPriv)
- return;
-
- if (exaPixmapIsPinned(pPixmap))
- return;
-
- /* Can't accel 1/4 bpp. */
- if (pExaPixmap->accel_blocked || bpp < 8)
- return;
-
- if (pExaScr->info->CreatePixmap2) {
- int new_pitch = 0;
- pExaPixmap->driverPriv = pExaScr->info->CreatePixmap2(pScreen, w, h, depth, usage_hint, bpp, &new_pitch);
- paddedWidth = pExaPixmap->fb_pitch = new_pitch;
- } else {
- if (paddedWidth < pExaPixmap->fb_pitch)
- paddedWidth = pExaPixmap->fb_pitch;
- pExaPixmap->driverPriv = pExaScr->info->CreatePixmap(pScreen, paddedWidth*h, 0);
- }
-
- if (!pExaPixmap->driverPriv)
- return;
-
- (*pScreen->ModifyPixmapHeader)(pPixmap, w, h, 0, 0,
- paddedWidth, NULL);
-}
-
-void
-exaDoMigration_mixed(ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel)
-{
- int 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))
- {
- can_accel = FALSE;
- break;
- }
- }
-
- /* We can do nothing. */
- if (!can_accel)
- return;
-
- for (i = 0; i < npixmaps; i++) {
- PixmapPtr pPixmap = pixmaps[i].pPix;
- ExaPixmapPriv(pPixmap);
-
- if (!pExaPixmap->driverPriv)
- exaCreateDriverPixmap_mixed(pPixmap);
-
- if (pExaPixmap->pDamage && exaPixmapHasGpuCopy(pPixmap)) {
- ExaScreenPriv(pPixmap->drawable.pScreen);
-
- /* This pitch is needed for proper acceleration. For some reason
- * there are pixmaps without pDamage and a bad fb_pitch value.
- * So setting devKind when only exaPixmapHasGpuCopy() is true
- * causes corruption. Pixmaps without pDamage are not migrated
- * and should have a valid devKind at all times, so that's why this
- * isn't causing problems. Pixmaps have their gpu pitch set the
- * first time in the MPH call from exaCreateDriverPixmap_mixed().
- */
- pPixmap->devKind = pExaPixmap->fb_pitch;
- exaCopyDirtyToFb(pixmaps + i);
-
- if (pExaScr->deferred_mixed_pixmap == pPixmap &&
- !pixmaps[i].as_dst && !pixmaps[i].pReg)
- pExaScr->deferred_mixed_pixmap = NULL;
- }
-
- pExaPixmap->use_gpu_copy = exaPixmapHasGpuCopy(pPixmap);
- }
-}
-
-void
-exaMoveInPixmap_mixed(PixmapPtr pPixmap)
-{
- ExaMigrationRec pixmaps[1];
-
- pixmaps[0].as_dst = FALSE;
- pixmaps[0].as_src = TRUE;
- pixmaps[0].pPix = pPixmap;
- pixmaps[0].pReg = NULL;
-
- exaDoMigration(pixmaps, 1, TRUE);
-}
-
-void
-exaDamageReport_mixed(DamagePtr pDamage, RegionPtr pRegion, void *closure)
-{
- PixmapPtr pPixmap = closure;
- ExaPixmapPriv(pPixmap);
-
- /* Move back results of software rendering on system memory copy of mixed driver
- * pixmap (see exaPrepareAccessReg_mixed).
- *
- * Defer moving the destination back into the driver pixmap, to try and save
- * overhead on multiple subsequent software fallbacks.
- */
- if (!pExaPixmap->use_gpu_copy && exaPixmapHasGpuCopy(pPixmap)) {
- ExaScreenPriv(pPixmap->drawable.pScreen);
-
- if (pExaScr->deferred_mixed_pixmap &&
- pExaScr->deferred_mixed_pixmap != pPixmap)
- exaMoveInPixmap_mixed(pExaScr->deferred_mixed_pixmap);
- pExaScr->deferred_mixed_pixmap = pPixmap;
- }
-}
-
-/* With mixed pixmaps, if we fail to get direct access to the driver pixmap, we
- * use the DownloadFromScreen hook to retrieve contents to a copy in system
- * memory, perform software rendering on that and move back the results with the
- * UploadToScreen hook (see exaDamageReport_mixed).
- */
-void
-exaPrepareAccessReg_mixed(PixmapPtr pPixmap, int index, RegionPtr pReg)
-{
- ExaPixmapPriv(pPixmap);
- Bool has_gpu_copy = exaPixmapHasGpuCopy(pPixmap);
- Bool success;
-
- success = ExaDoPrepareAccess(pPixmap, index);
-
- if (success && has_gpu_copy && pExaPixmap->pDamage) {
- /* You cannot do accelerated operations while a buffer is mapped. */
- exaFinishAccess(&pPixmap->drawable, index);
- /* Update the gpu view of both deferred destination pixmaps and of
- * source pixmaps that were migrated with a bounding region.
- */
- exaMoveInPixmap_mixed(pPixmap);
- success = ExaDoPrepareAccess(pPixmap, index);
-
- if (success) {
- /* We have a gpu pixmap that can be accessed, we don't need the cpu
- * copy anymore. Drivers that prefer DFS, should fail prepare
- * access.
- */
- DamageUnregister(&pPixmap->drawable, pExaPixmap->pDamage);
- DamageDestroy(pExaPixmap->pDamage);
- pExaPixmap->pDamage = NULL;
-
- free(pExaPixmap->sys_ptr);
- pExaPixmap->sys_ptr = NULL;
-
- return;
- }
- }
-
- if (!success) {
- ExaMigrationRec pixmaps[1];
-
- /* Do we need to allocate our system buffer? */
- if (!pExaPixmap->sys_ptr) {
- pExaPixmap->sys_ptr = malloc(pExaPixmap->sys_pitch *
- pPixmap->drawable.height);
- if (!pExaPixmap->sys_ptr)
- FatalError("EXA: malloc failed for size %d bytes\n",
- pExaPixmap->sys_pitch * pPixmap->drawable.height);
- }
-
- 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;
-
- if (!pExaPixmap->pDamage &&
- (has_gpu_copy || !exaPixmapIsPinned(pPixmap))) {
- Bool as_dst = pixmaps[0].as_dst;
-
- /* 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);
-
- if (has_gpu_copy) {
- exaPixmapDirty(pPixmap, 0, 0, pPixmap->drawable.width,
- pPixmap->drawable.height);
-
- /* We don't know which region of the destination will be damaged,
- * have to assume all of it
- */
- if (as_dst) {
- pixmaps[0].as_dst = FALSE;
- pixmaps[0].as_src = TRUE;
- pixmaps[0].pReg = NULL;
- }
- exaCopyDirtyToSys(pixmaps);
- }
-
- if (as_dst)
- exaPixmapDirty(pPixmap, 0, 0, pPixmap->drawable.width,
- pPixmap->drawable.height);
- } else if (has_gpu_copy)
- exaCopyDirtyToSys(pixmaps);
-
- pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
- pPixmap->devKind = pExaPixmap->sys_pitch;
- pExaPixmap->use_gpu_copy = FALSE;
- }
-}
-
+/*
+ * 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"
+
+void
+exaCreateDriverPixmap_mixed(PixmapPtr pPixmap)
+{
+ ScreenPtr pScreen = pPixmap->drawable.pScreen;
+ ExaScreenPriv(pScreen);
+ ExaPixmapPriv(pPixmap);
+ int w = pPixmap->drawable.width, h = pPixmap->drawable.height;
+ int depth = pPixmap->drawable.depth, bpp = pPixmap->drawable.bitsPerPixel;
+ int usage_hint = pPixmap->usage_hint;
+ int paddedWidth = pExaPixmap->sys_pitch;
+
+ /* Already done. */
+ if (pExaPixmap->driverPriv)
+ return;
+
+ if (exaPixmapIsPinned(pPixmap))
+ return;
+
+ /* Can't accel 1/4 bpp. */
+ if (pExaPixmap->accel_blocked || bpp < 8)
+ return;
+
+ if (pExaScr->info->CreatePixmap2) {
+ int new_pitch = 0;
+ pExaPixmap->driverPriv = pExaScr->info->CreatePixmap2(pScreen, w, h, depth, usage_hint, bpp, &new_pitch);
+ paddedWidth = pExaPixmap->fb_pitch = new_pitch;
+ } else {
+ if (paddedWidth < pExaPixmap->fb_pitch)
+ paddedWidth = pExaPixmap->fb_pitch;
+ pExaPixmap->driverPriv = pExaScr->info->CreatePixmap(pScreen, paddedWidth*h, 0);
+ }
+
+ if (!pExaPixmap->driverPriv)
+ return;
+
+ (*pScreen->ModifyPixmapHeader)(pPixmap, w, h, 0, 0,
+ paddedWidth, NULL);
+}
+
+void
+exaDoMigration_mixed(ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel)
+{
+ int 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))
+ {
+ can_accel = FALSE;
+ break;
+ }
+ }
+
+ /* We can do nothing. */
+ if (!can_accel)
+ return;
+
+ for (i = 0; i < npixmaps; i++) {
+ PixmapPtr pPixmap = pixmaps[i].pPix;
+ ExaPixmapPriv(pPixmap);
+
+ if (!pExaPixmap->driverPriv)
+ exaCreateDriverPixmap_mixed(pPixmap);
+
+ if (pExaPixmap->pDamage && exaPixmapHasGpuCopy(pPixmap)) {
+ ExaScreenPriv(pPixmap->drawable.pScreen);
+
+ /* This pitch is needed for proper acceleration. For some reason
+ * there are pixmaps without pDamage and a bad fb_pitch value.
+ * So setting devKind when only exaPixmapHasGpuCopy() is true
+ * causes corruption. Pixmaps without pDamage are not migrated
+ * and should have a valid devKind at all times, so that's why this
+ * isn't causing problems. Pixmaps have their gpu pitch set the
+ * first time in the MPH call from exaCreateDriverPixmap_mixed().
+ */
+ pPixmap->devKind = pExaPixmap->fb_pitch;
+ exaCopyDirtyToFb(pixmaps + i);
+
+ if (pExaScr->deferred_mixed_pixmap == pPixmap &&
+ !pixmaps[i].as_dst && !pixmaps[i].pReg)
+ pExaScr->deferred_mixed_pixmap = NULL;
+ }
+
+ pExaPixmap->use_gpu_copy = exaPixmapHasGpuCopy(pPixmap);
+ }
+}
+
+void
+exaMoveInPixmap_mixed(PixmapPtr pPixmap)
+{
+ ExaMigrationRec pixmaps[1];
+
+ pixmaps[0].as_dst = FALSE;
+ pixmaps[0].as_src = TRUE;
+ pixmaps[0].pPix = pPixmap;
+ pixmaps[0].pReg = NULL;
+
+ exaDoMigration(pixmaps, 1, TRUE);
+}
+
+void
+exaDamageReport_mixed(DamagePtr pDamage, RegionPtr pRegion, void *closure)
+{
+ PixmapPtr pPixmap = closure;
+ ExaPixmapPriv(pPixmap);
+
+ /* Move back results of software rendering on system memory copy of mixed driver
+ * pixmap (see exaPrepareAccessReg_mixed).
+ *
+ * Defer moving the destination back into the driver pixmap, to try and save
+ * overhead on multiple subsequent software fallbacks.
+ */
+ if (!pExaPixmap->use_gpu_copy && exaPixmapHasGpuCopy(pPixmap)) {
+ ExaScreenPriv(pPixmap->drawable.pScreen);
+
+ if (pExaScr->deferred_mixed_pixmap &&
+ pExaScr->deferred_mixed_pixmap != pPixmap)
+ exaMoveInPixmap_mixed(pExaScr->deferred_mixed_pixmap);
+ pExaScr->deferred_mixed_pixmap = pPixmap;
+ }
+}
+
+/* With mixed pixmaps, if we fail to get direct access to the driver pixmap, we
+ * use the DownloadFromScreen hook to retrieve contents to a copy in system
+ * memory, perform software rendering on that and move back the results with the
+ * UploadToScreen hook (see exaDamageReport_mixed).
+ */
+void
+exaPrepareAccessReg_mixed(PixmapPtr pPixmap, int index, RegionPtr pReg)
+{
+ ExaPixmapPriv(pPixmap);
+ Bool has_gpu_copy = exaPixmapHasGpuCopy(pPixmap);
+ Bool success;
+
+ success = ExaDoPrepareAccess(pPixmap, index);
+
+ if (success && has_gpu_copy && pExaPixmap->pDamage) {
+ /* You cannot do accelerated operations while a buffer is mapped. */
+ exaFinishAccess(&pPixmap->drawable, index);
+ /* Update the gpu view of both deferred destination pixmaps and of
+ * source pixmaps that were migrated with a bounding region.
+ */
+ exaMoveInPixmap_mixed(pPixmap);
+ success = ExaDoPrepareAccess(pPixmap, index);
+
+ if (success) {
+ /* We have a gpu pixmap that can be accessed, we don't need the cpu
+ * copy anymore. Drivers that prefer DFS, should fail prepare
+ * access.
+ */
+ DamageUnregister(&pPixmap->drawable, pExaPixmap->pDamage);
+ DamageDestroy(pExaPixmap->pDamage);
+ pExaPixmap->pDamage = NULL;
+
+ free(pExaPixmap->sys_ptr);
+ pExaPixmap->sys_ptr = NULL;
+
+ return;
+ }
+ }
+
+ if (!success) {
+ ExaMigrationRec pixmaps[1];
+
+ /* Do we need to allocate our system buffer? */
+ if (!pExaPixmap->sys_ptr) {
+ pExaPixmap->sys_ptr = malloc(pExaPixmap->sys_pitch *
+ pPixmap->drawable.height);
+ if (!pExaPixmap->sys_ptr)
+ FatalError("EXA: malloc failed for size %d bytes\n",
+ pExaPixmap->sys_pitch * pPixmap->drawable.height);
+ }
+
+ 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;
+
+ if (!pExaPixmap->pDamage &&
+ (has_gpu_copy || !exaPixmapIsPinned(pPixmap))) {
+ Bool as_dst = pixmaps[0].as_dst;
+
+ /* 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);
+
+ if (has_gpu_copy) {
+ exaPixmapDirty(pPixmap, 0, 0, pPixmap->drawable.width,
+ pPixmap->drawable.height);
+
+ /* We don't know which region of the destination will be damaged,
+ * have to assume all of it
+ */
+ if (as_dst) {
+ pixmaps[0].as_dst = FALSE;
+ pixmaps[0].as_src = TRUE;
+ pixmaps[0].pReg = NULL;
+ }
+ exaCopyDirtyToSys(pixmaps);
+ }
+
+ if (as_dst)
+ exaPixmapDirty(pPixmap, 0, 0, pPixmap->drawable.width,
+ pPixmap->drawable.height);
+ } else if (has_gpu_copy)
+ exaCopyDirtyToSys(pixmaps);
+
+ pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
+ pPixmap->devKind = pExaPixmap->sys_pitch;
+ pExaPixmap->use_gpu_copy = FALSE;
+ }
+}
+
diff --git a/xorg-server/exa/exa_mixed.c b/xorg-server/exa/exa_mixed.c
index 188a7e0a6..58645aea0 100644
--- a/xorg-server/exa/exa_mixed.c
+++ b/xorg-server/exa/exa_mixed.c
@@ -1,290 +1,290 @@
-/*
- * 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(paddedWidth);
-
- /* 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) {
- if (devKind > 0)
- pExaPixmap->fb_pitch = devKind;
- else
- 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 = 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);
-
- exaDestroyPixmap(pPixmap);
-
- 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;
-}
+/*
+ * 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(paddedWidth);
+
+ /* 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) {
+ if (devKind > 0)
+ pExaPixmap->fb_pitch = devKind;
+ else
+ 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 = 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);
+
+ exaDestroyPixmap(pPixmap);
+
+ 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_unaccel.c b/xorg-server/exa/exa_unaccel.c
index 634d1a893..fca46ac5e 100644
--- a/xorg-server/exa/exa_unaccel.c
+++ b/xorg-server/exa/exa_unaccel.c
@@ -1,6 +1,6 @@
/*
*
- * Copyright © 1999 Keith Packard
+ * Copyright © 1999 Keith Packard
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that